[
  {
    "path": ".github/workflows/static.yml",
    "content": "# Simple workflow for deploying static content to GitHub Pages\nname: Deploy static content to Pages\n\non:\n  # Runs on pushes targeting the default branch\n  push:\n    branches: [\"main\"]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  # Single deploy job since we're just deploying\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Pages\n        uses: actions/configure-pages@v5\n      - name: Create analytics file\n        run: echo \"${{ vars.CLOUDFLARE_ANALYTICS }}\" > public/analytics.template\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          # Deploy public folder only\n          path: './public'\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.pem\npublic/analytics.template\n"
  },
  {
    "path": ".hintrc",
    "content": "{\n  \"extends\": [\n    \"development\"\n  ],\n  \"hints\": {\n    \"compat-api/html\": [\n      \"default\",\n      {\n        \"ignore\": [\n          \"iframe[loading]\",\n          \"nav[popover]\",\n          \"button[popovertarget]\",\n          \"button[popovertargetaction]\"\n        ]\n      }\n    ],\n    \"no-inline-styles\": \"off\",\n    \"compat-api/css\": [\n      \"default\",\n      {\n        \"ignore\": [\n          \"view-transition-name\",\n          \"text-size-adjust\",\n          \"text-size-adjust: none\",\n          \"overscroll-behavior\",\n          \"overscroll-behavior: none\"\n        ]\n      }\n    ]\n  }\n}"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2024 Joeri Sebrechts\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Plain Vanilla\n\nA website demonstrating how to do web development using only vanilla techniques: no tools, no frameworks, just the browser and vanilla web code. The site itself is also built in this way.\n\n## Running\n\nRun the `public/` folder as a static website:\n\n- node: `npx http-server public -c-1`\n- php: `php -S localhost:8000 -t public`\n- python: `python3 -m http.server 8000 --directory public`\n\nOr use the VS Code Live Preview extension to show `public/index.html`.\n\n## Contributing\n\nIssues or PR's welcome!\n\n## Other resources\n\nThese are some other resources demonstrating #notools web development techniques.\n\n- [MDN Learn Web Development](https://developer.mozilla.org/en-US/docs/Learn): a vanilla web development learning path\n- [Odin Project Foundations](https://www.theodinproject.com/paths/foundations/courses/foundations): a vanilla web development course\n- [create-react-app-zero](https://github.com/jsebrech/create-react-app-zero): another project of mine, a no-tools version of create-react-app, to be able to use React without frills\n- [HEX: a No Framework Approach to Building Modern Web Apps](https://medium.com/@metapgmr/hex-a-no-framework-approach-to-building-modern-web-apps-e43f74190b9c): a React-like approach based on vanilla web development techniques\n- [plainJS](https://plainjs.com/): a collection of vanilla javascript functions and plugins to replace the use of jQuery\n- [Web Dev Toolkit](https://gomakethings.com/toolkit/): a collection of vanilla helper functions, boilerplates and libraries\n- [The Modern JavaScipt Tutorial](https://javascript.info/): a step-by-step tutorial to learn vanilla JavaScript\n\n## Attribution\n\nSoft ice icon by [Twemoji](https://github.com/jdecked/twemoji) is licensed under [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/).\n"
  },
  {
    "path": "eslint.config.cjs",
    "content": "/* eslint-disable no-undef */\nconst globals = require(\"globals\");\nconst js = require(\"@eslint/js\");\n\nmodule.exports = [\n    js.configs.recommended, \n    {\n        languageOptions: {\n            globals: {\n                ...globals.browser,\n                ...globals.mocha\n            },\n            ecmaVersion: 2022,\n            sourceType: \"module\",\n        }\n    },\n    {\n        ignores: [\n            \"public/blog/articles/\",\n            \"**/lib/\",\n            \"**/react/\",\n        ]\n    }\n];"
  },
  {
    "path": "public/blog/archive.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla Blog</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"A blog about vanilla web development.\">\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"../apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"./index.css\">\n</head>\n<body>\n    <noscript><strong>Please enable JavaScript to view this page correctly.</strong></noscript>\n    <header>\n        <h1>Plain Vanilla Blog</h1>\n        <nav aria-label=\"breadcrumb\">\n            <ol>\n                <li><a href=\"../index.html\">Plain Vanilla</a></li>\n                <li><a href=\"./index.html\">Blog</a></li>\n                <li><a href=\"#\" aria-current=\"page\">Archive</a></li>\n            </ol>\n        </nav>\n    </header>\n    <main>\n        <h2>Archive</h2>\n        <blog-archive><noscript>Please enable scripting to see the archives.</noscript></blog-archive>\n    </main>\n    <blog-footer></blog-footer>\n\n    <script type=\"module\" src=\"./index.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2024-08-17-lets-build-a-blog/card.html",
    "content": "<ul class=\"cards\">\n    <li class=\"card\">\n        <img src=\"./articles/2024-08-17-lets-build-a-blog/image.webp\" aria-hidden=\"true\" loading=\"lazy\" />\n        <h3><a href=\"./articles/2024-08-17-lets-build-a-blog/\">Let's build a blog, vanilla-style!</a></h3>\n        <p>Explaining how this vanilla web development blog was built, using nothing but vanilla web techniques.</p>\n        <small>\n            <time datetime=\"2024-08-17\">August 17, 2024</time>\n        </small>\n    </li>\n</ul>"
  },
  {
    "path": "public/blog/articles/2024-08-17-lets-build-a-blog/example.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>A spiffy title!</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"This is a spiffy article. You should read it.\">\n    <link rel=\"stylesheet\" href=\"index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-08-17\">\n        <img src=\"image.jpeg\" alt=\"Another AI image\" loading=\"lazy\" />\n        <h2>A spiffy title!</h2>\n        <p class=\"byline\" aria-label=\"author\">Malkovich</p>\n    </blog-header>\n    <main>\n        Article text goes here ...\n    </main>\n    <blog-footer mastodon-url=\"https://example.com/@jmalkovich/12345\"></blog-footer>\n    <script type=\"module\" src=\"index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-08-17-lets-build-a-blog/generator.js",
    "content": "customElements.define('blog-generator', class BlogGenerator extends HTMLElement {\n\n    // ...\n\n    async processArticle(article, path) {\n        const file = await article.getFile();\n        const html = await file.text();\n        const dom = (new DOMParser()).parseFromString(html, 'text/html');\n        // mandatory\n        const title = dom.querySelector('title').textContent;\n        const summary = dom.querySelector('meta[name=\"description\"]').getAttribute('content');\n        const published = dom.querySelector('blog-header').getAttribute('published');\n        const content = await this.processArticleContent(dom.querySelector('main'), path);\n        const slug = path.name;\n        // optional\n        const img = dom.querySelector('blog-header img');\n        const image = img && { src: img.getAttribute('src'), alt: img.getAttribute('alt') };\n        const updated = dom.querySelector('blog-header').getAttribute('updated') || undefined;\n\n        this.#articles.push({\n            slug, title, summary, content, published, updated, image\n        });\n    }\n\n    async processArticleContent(main, path) {\n        // inline code examples\n        await Promise.all([...main.querySelectorAll('x-code-viewer')].map(async (elem) => {\n            const text = await this.downloadFile(elem.getAttribute('src'), path);\n            const pre = document.createElement('pre');\n            pre.innerHTML = html`<code>${text}</code>`;\n            elem.replaceWith(pre);\n        }));\n\n        // convert img src to absolute url\n        [...main.querySelectorAll('img')].map((elem) => {\n            const src = elem.getAttribute('src');\n            if (src.indexOf('http') !== 0) {\n                elem.setAttribute('src', new URL(`articles/${path.name}/${src}`, BLOG_BASE_URL));\n            }\n        });\n\n        // replace iframes by links\n        [...main.querySelectorAll('iframe')].map((elem) => {\n            const src = elem.getAttribute('src');\n            const title = elem.getAttribute('title') || src;\n            const a = document.createElement('a');\n            a.textContent = title;\n            const p = document.createElement('p');\n            p.appendChild(a);\n            elem.replaceWith(p);\n            if (src.indexOf('http') !== 0) {\n                a.href = new URL(`articles/${path.name}/${src}`, BLOG_BASE_URL);\n            } else {\n                a.href = src;\n            }\n        });\n\n        return main.innerHTML;\n    }\n\n    // ...\n\n});"
  },
  {
    "path": "public/blog/articles/2024-08-17-lets-build-a-blog/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Let's build a blog, vanilla-style!</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"Explaining how this vanilla web development blog was built, using nothing but vanilla web techniques.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-08-17\" updated=\"2024-08-26\">\n        <img src=\"image.webp\" alt=\"Bricks being laid by hand\" loading=\"lazy\" />\n        <h2>Let's build a blog, vanilla-style!</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            As I write this paragraph it is my birthday, and it seemed like as good an opportunity as any to start a blog about vanilla web development.\n            This blog post will be a bit unusual, as I will be writing it while I'm making the blog's inner workings.\n            But before I get around to figuring out and then explaining how it was made, let me start with why.\n        </p>\n\n        <section>\n            <h3>Origin story</h3>\n            <p>\n                I have been building web sites since the late 90's, and over the years there were always two constants:\n                (1) browsers were terrible developer platforms, (2) new tools and frameworks built ever taller on top of them.\n                The tools were necessary, but their growing complexity frustrated me, and in that frustration lies the origin of this blog.\n            </p>\n            <p>\n                A few years ago something unexpected happened: Microsoft moved away from their (underfeatured) Trident browser engine.\n                Suddenly there was a new baseline of browsers, a capable baseline. Browsers got good!\n                I explored what modern browsers could do as a developer platform, and grew excited with the possibilities\n                to treat the browser itself as the framework, without a middleman. \n                That eventually led into making the <a href=\"https://plainvanillaweb.com\">Plain Vanilla website</a>, a framework tutorial for the web standards platform.\n            </p>\n            <p>\n                In building this website editorial choices had to be made.\n                Trying to explain too much would only confuse people, so the tutorial was trimmed of its fat.\n                There is however so much more to explore, and that is where this blog enters the picture.\n                Here I will talk about some of the things that didn't find a home in the Plain Vanilla tutorial,\n                and document the new things that do.\n            </p> \n        </section>\n\n        <section>\n            <h3>What is a blog anyway?</h3>\n\n            <p>\n                Of course, a blog about vanilla web development has to be built vanilla-style.\n                That means no build steps, no server-side logic, no frameworks or libraries.\n                Bottom line that means throwing up a bunch of HTML pages with an index page linking them together,\n                but that by itself isn't enough. The idea is to make a full-fat modern feeling blog,\n                something that has what people expect a blog to have. So off I went to look at popular blogs and build a list of features.\n            </p>\n            <p>A <em>modern</em> blog will have ...</p> \n            <ul>\n                <li>One page per article, easy for sharing as a link and discovery by Google.</li>\n                <li>A welcome page, with one or more hero cards leading to articles and a list of cards for recent articles.</li>\n                <li>An archive page, with the full history of articles linking to the article pages.</li>\n                <li>An RSS feed, for the 20 most recent articles, containing the full text.</li>\n                <li>Comments on every article. This is a big one.</li>\n                <li>Some colors and imagery, to spruce things up and please the readers.</li>\n                <li>Easy to author articles. This is also a big one.</li>\n            </ul>\n            <p>The challenge was: how to do all of that within the vanilla constraints that I set myself?</p>\n        </section>\n\n        <section>\n            <h3>Article-first design</h3>\n\n            <p>\n                The core of the blog experience is the article, so getting that right is key and that makes it the best place to start.\n                Lacking any kind of generator or server-side routing, each article has to be written as a discrete html page\n                in order to be discoverable by Google. Authoring those html pages should be straightforward,\n                with minimal boilerplate.\n            </p>\n\n            <p>After careful consideration we present to you, an article page blueprint...</p>\n            <x-code-viewer src=\"example.html\"></x-code-viewer>\n\n            <p>\n                This does several things for me. It keeps the &lt;head&gt; section as minimal as possible.\n                It also moves the navigation at the top and bottom into dedicated web components.\n                The header component accepts the article's image and title as child elements,\n                neatly leaving the main element containing just the article's content and nothing else,\n                making it easy to extract (but more on that later).\n            </p>\n            <p>\n                When users have scripting disabled they won't get the header navigation, \n                but thanks to this CSS they do get a warning:<br>\n                <code>@media (scripting: none) { blog-header::before { content: ' ... ' } }</code><br>\n                This approach frees me from thinking about noscript warnings while writing an article.\n            </p>\n            <p>\n                Finally, for comments I considered Disqus, but didn't want to include their embed.\n                So instead the footer accepts the URL to a mastodon toot about the article,\n                and will automatically generate a link that goes there. Given that the blog has a technical audience\n                I'm pretty sure they can figure out how to reply over there. This approach can be extended\n                to <a href=\"https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/\">show replies inline on the page</a>\n                by calling the Mastodon API, but I didn't tackle that yet. It's somewhat cumbersome to first post an article, \n                then toot about it, and then update the article with the toot's URL, but I'll survive.\n                Incidentally, I still giggle like a schoolgirl inside my head every time I type the word <em>toot</em>.\n            </p>\n        </section>\n\n        <section>\n            <h3>Organizing files</h3>\n\n            <p>\n                Next comes the question how to organize the article files into a coherent structure.\n                After thinking it over, this is what I landed on:\n            </p>\n            <ul>\n                <li><code>articles/</code>\n                    <ul>\n                        <li><code><em>YYYY-MM-DD</em>-some-blog-title/</code>\n                            <ul>\n                                <li><code>index.html</code></li>\n                                <li><code>image.jpeg</code></li>\n                                <li>other files used in the article ...</li>\n                            </ul>\n                        </li>\n                    </ul>\n                </li>\n                <li><code>components/</code>: the blog's shared web components</li>\n                <li><code>index.html</code>: the main landing page</li>\n                <li><code>archive.html</code>: the archives page</li>\n                <li><code>index.js/css</code>: shared resources</li>\n                <li><code>feed.xml</code>: the RSS feed</li>\n            </ul>\n            <p>\n                By wrapping every article and all its resources into a folder, each article can get as messy and complicated as it wants.\n                The shared index.js and index.css is separate from that of the main site\n                to keep the blog's resources out of the Plain Vanilla site's pages, and vice versa.\n            </p>\n        </section>\n\n        <section>\n            <h3>Building indexes</h3>\n\n            <p>\n                You wouldn't think a blog has a need for many indexes, but in fact this modest blog will have three:\n            </p>\n            <ol>\n                <li>The recent posts section on the main landing page</li>\n                <li>The recent posts in the RSS feed</li>\n                <li>The full list of articles in the archive page</li>\n            </ol>\n            <p>\n                Visually showing an index is not so difficult, as a web component built around a simple <code>&lt;li&gt;</code>-based\n                card design can be used to show both the recent posts and the archive page, and was straighforward to style with CSS.\n            </p>\n            <x-code-viewer src=\"card.html\"></x-code-viewer>\n            <p>\n                Getting that data in a convenient form however is another matter.\n                The RSS feed contains full text contents, so needs a separate step to build from the articles' HTML.\n                The recent posts section on the index page thankfully can be built by reading the RSS feed,\n                so was trivial to solve with a <code>&lt;blog-latest-posts&gt;</code> web component once the feed was set up.\n                The full list of articles however cannot, as the RSS feed would grow too large if it contained all posts.\n                So the archive page needs another separate step to build the full list of links from the folder of articles.\n            </p>\n            <p>\n                For these build steps I considered various options:\n            </p>\n            <dl>\n                <dt>❌ <del>Manually keeping the files in sync</del><dt>\n                <dd>\n                    It sounded like a lot of work, and error-prone, so a hard no on that one.\n                </dd>\n                <dt>❌ <del>A generator script, and a package.json</del></dt>\n                <dd>\n                    This is what I would normally go for, relying on a bunch of npm dependencies and a bunch of scripting\n                    to process the articles into the index files that are needed. \n                    It felt like cheating to bring in node and its ecosystem, so again this was a no.\n                </dd>\n                <dt>✅ A separate generator webpage</dt>\n                <dd>\n                    I've wanted to play around with the\n                    <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/File_System_API\">File System API</a>\n                    for a while, and this seemed a good opportunity.\n                    Turning the generator into a webpage also leaves options for actually running the web components\n                    and extracting their dynamically rendered content.\n                </dd>\n            </dl>\n\n            <p>\n                For the generator page I built a dedicated web component that allows opening or dropping the\n                local <code>blog/</code> folder with the newly written or updated articles,\n                and then will process those into a <code>feed.xml</code> and <code>index.json</code>.\n                The JSON file is used to load the contents of the archive page.\n                The RSS feed is particularly tricky, because there is a limited set of tags that it should contain.\n                By loading the article's HTML into a DOM parser, and replacing all unsupported tags (like the code viewer web component shown below)\n                the HTML can be transformed into something that can be used as RSS feed entry contents.\n            </p>\n            <p>The core logic of the generator extracts the article's metadata and transforms the HTML:</p>\n            <x-code-viewer src=\"generator.js\"></x-code-viewer>\n\n            <p>To give you an idea of what <a href=\"../../generator.html\">generator.html</a> looks like in use:</p>\n            <img src=\"generator.webp\" alt=\"generator page screenshot\" />\n\n            <p>\n                The generator JS ended up around 250 lines of code, so not too cumbersome to build or maintain.\n                If you're curious about the generator, check out the \n                <a href=\"https://github.com/jsebrech/plainvanilla/tree/main/public/blog/\">blog's code on Github</a>.\n                It can be found in <code>generator.html</code> and <code>generator.js</code>.\n            </p>\n\n            <p>The user experience of writing a blog post then boils down to this:</p>\n            <ol>\n                <li>Create an article folder and write the article as HTML</li>\n                <li>Open the generator page</a></li>\n                <li>Drop the blog folder on the generator, it will automatically process the articles</li>\n                <li>Copy the <code>feed.xml</code> and <code>index.json</code> text to their respective files</li>\n                <li>Commit and push the changes</li>\n                <li>Optionally: toot on mastodon, add the toot URL in the page, commit and push</li>\n            </ol>\n\n            <p>Not too shabby...</p>\n        </section>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113030045608088158\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2024-08-25-vanilla-entity-encoding/example1.js",
    "content": "class MyComponent extends HTMLElement {\n    connectedCallback() {\n        const btn = `<button>${this.getAttribute('foo')}</button>`;\n        this.innerHTML = `\n            <header><h1>${this.getAttribute('bar')}</h1></header>\n            <article>\n                <p class=\"${this.getAttribute('baz')}\">${this.getAttribute('xyzzy')}</p>\n                ${btn}\n            </article>\n        `;\n    }\n}\ncustomElements.define('my-component', MyComponent);"
  },
  {
    "path": "public/blog/articles/2024-08-25-vanilla-entity-encoding/example2.js",
    "content": "function htmlEncode(s) {\n    return s.replace(/[&<>'\"]/g,\n        tag => ({\n            '&': '&amp;',\n            '<': '&lt;',\n            '>': '&gt;',\n            \"'\": '&#39;',\n            '\"': '&quot;'\n        }[tag]))\n}\n\nclass MyComponent extends HTMLElement {\n    connectedCallback() {\n        const btn = `<button>${htmlEncode(this.getAttribute('foo'))}</button>`;\n        this.innerHTML = `\n            <header><h1>${htmlEncode(this.getAttribute('bar'))}</h1></header>\n            <article>\n                <p class=\"${htmlEncode(this.getAttribute('baz'))}\">${htmlEncode(this.getAttribute('xyzzy'))}</p>\n                ${btn}\n            </article>\n        `;\n    }\n}\ncustomElements.define('my-component', MyComponent);"
  },
  {
    "path": "public/blog/articles/2024-08-25-vanilla-entity-encoding/example3.js",
    "content": "import { html } from './html.js';\n\nclass MyComponent extends HTMLElement {\n    connectedCallback() {\n        const btn = html`<button>${this.getAttribute('foo')}</button>`;\n        this.innerHTML = html`\n            <header><h1>${this.getAttribute('bar')}</h1></header>\n            <article>\n                <p class=\"${this.getAttribute('baz')}\">${this.getAttribute('xyzzy')}</p>\n                ${btn}\n            </article>\n        `;\n    }\n}\ncustomElements.define('my-component', MyComponent);"
  },
  {
    "path": "public/blog/articles/2024-08-25-vanilla-entity-encoding/html.js",
    "content": "class Html extends String { }\n\n/** \n * tag a string as html not to be encoded\n * @param {string} str\n * @returns {string}\n */\nexport const htmlRaw = str => new Html(str);\n\n/** \n * entity encode a string as html\n * @param {*} value The value to encode\n * @returns {string}\n */\nexport const htmlEncode = (value) => {\n    // avoid double-encoding the same string\n    if (value instanceof Html) {\n        return value;\n    } else {\n        // https://stackoverflow.com/a/57448862/20980\n        return htmlRaw(\n            String(value).replace(/[&<>'\"]/g, \n                tag => ({\n                    '&': '&amp;',\n                    '<': '&lt;',\n                    '>': '&gt;',\n                    \"'\": '&#39;',\n                    '\"': '&quot;'\n                }[tag]))\n        );\n    }\n}\n\n/** \n * html tagged template literal, auto-encodes entities\n */\nexport const html = (strings, ...values) => \n    htmlRaw(String.raw({ raw: strings }, ...values.map(htmlEncode)));\n"
  },
  {
    "path": "public/blog/articles/2024-08-25-vanilla-entity-encoding/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Vanilla entity encoding</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"The first version of this site didn't use entity encoding in the examples. Now it does.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-08-25\">\n        <img src=\"image.webp\" alt=\"A man working a printing press printing HTML code\" loading=\"lazy\" />\n        <h2>Vanilla entity encoding</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <h3>Good enough</h3>\n        <p>\n            When I made the first version of the Plain Vanilla website, there were things that I would have liked\n            to spend more time on, but that I felt didn't belong in a Good Enough&trade; version of the site.\n            One of those things was defending against <a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\">Cross-Site Scripting</a> (XSS).\n        </p>\n        <p>\n            XSS is still in the <a href=\"https://owasp.org/www-project-top-ten/\">OWASP Top Ten</a> of security issues, \n            but it's no longer as prevalent as it used to be. Frameworks have built in a lot of defenses, \n            and when using their templating systems you have to go out of your way to inject code into the generated HTML.\n            When eschewing frameworks we're reduced to standard templating in our web components, and those offer no defense against XSS.\n        </p>\n        <p>\n            Because of this, in the original site the <a href=\"https://plainvanillaweb.com/pages/components.html#passing-data\">Passing Data example</a> \n            on the <em>Components</em> page had an undocumented XSS bug.\n            The <em>name</em> field could have scripts injected into it. I felt ambivalent about leaving that bug in.\n            On the one hand, the code was very compact and neat by leaving it in.\n            On the other hand it made that code a bad example that shouldn't be copied.\n            I ended up choosing to leave it as-is because an example doesn't have to be production-grade\n            and generating properly encoded HTML was not the point of that specific example.\n            It's time however to circle back to that XSS bug and figure out how it would have been solved in a clean and readable way,\n            if Santa really did want to bring his List application to production-level quality.\n        </p>\n\n        <h3>The problem</h3>\n        <p>\n            The basic problem we need to solve is that vanilla web components end up having a lot of code that looks like this:\n        </p>\n        <x-code-viewer src=\"example1.js\"></x-code-viewer>\n        <p>\n            If any of <code>foo</code>, <code>bar</code>, <code>baz</code> or <code>xyzzy</code> contain one of the dangerous HTML entities,\n            we risk seeing our component break, and worst-case risk seeing an attacker inject a malicious payload into the page.\n            Just as a reminder, those dangerous HTML entities are &lt;, &gt;, &amp;, ' and \".\n        </p>\n\n        <h3>The fix, take one</h3>\n        <p>\n            A naive fix is creating a html-encoding function and using it consistently:\n        </p>\n        <x-code-viewer src=\"example2.js\"></x-code-viewer>\n        <p>\n            While this does work to defend against XSS, it is verbose and ugly, not pleasant to type and not pleasant to read.\n            What really kills it though, is that it assumes attention to detail from us messy humans. We can never forget,\n            never ever, to put a <code>htmlEncode()</code> around each and every variable.\n            In the real world, that is somewhat unlikely.\n        </p>\n        <p>\n            What is needed is a solution that allows us to forget about entity encoding, by doing it automatically\n            when we're templating. I drew inspiration from templating libraries that work in-browser and are based on tagged templates, \n            like <a href=\"https://lit.dev/docs/api/templates/#html\">lit-html</a> \n            and <a href=\"https://github.com/developit/htm\">htm</a>. The quest was on to build the most minimalistic\n            html templating function that encoded entities automatically.\n        </p>\n\n        <h3>The fix, take two</h3>\n        <p>\n            Ideally, the fixed example should look more like this:\n        </p>\n        <x-code-viewer src=\"example3.js\"></x-code-viewer>\n        <p>\n            The <code>html``</code> <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates\">tagged template function</a> \n            would automatically encode entities, in a way that we don't even have to think about it.\n            Even when we nest generated HTML inside of another template, like with <code>${btn}</code>, it should just magically work.\n            It would be so minimal as to disappear in the background, barely impacting readability, maybe even improving it.\n            You may be thinking that doing that correctly would involve an impressive amount of code. I must disappoint.\n        </p>\n        <x-code-viewer src=\"html.js\"></x-code-viewer>\n        <p>\n            Those couple dozen lines of code are all that is needed. Let's go through it from top to bottom.\n        </p>\n        <dl>\n            <dt><code>class Html extends String { }</code></dt>\n            <dd>The Html class is used to mark strings as encoded, so that they won't be encoded again.</dd>\n            <dt><code>export const htmlRaw = str => new Html(str);</code></dt>\n            <dd>Case in point, the htmlRaw function does the marking.</dd>\n            <dt><code>export const htmlEncode = ...</code></dt>\n            <dd>The earlier htmlEncode function is still doing useful work, only this time it will mark the resulting string as HTML, and it won't double-encode.</dd>\n            <dt><code>export const html = ...</code></dt>\n            <dd>The tagged template function that binds it together.</dd>\n        </dl>\n\n        <p>\n            A nice upside of the html template function is that the <em>html-in-template-string</em> Visual Studio Code extension\n            can detect it automatically and will syntax highlight the templated HTML. This is what example 3 looked like after I made it:\n        </p>\n\n        <img src=\"syntax-highlighting.webp\" alt=\"example 3 with syntax highlighting\" />\n\n        <p>\n            Granted, there's still a bunch of boilerplate here, and that <code>getAttribute</code> gets unwieldy.\n            But with this syntax highlighting enabled sometimes when I'm working on vanilla web components I forget it's not React and JSX, but just HTML and JS.\n            It's surprising how nice of a development experience web standards can be if you embrace them.\n        </p>\n\n        <p>\n            I decided to leave the XSS bug in the <em>Passing Data</em> example, but now the <em>Applications</em> page\n            has an explanation about entity encoding documenting this html template function.\n            I can only hope people that work their way through the tutorial make it that far.\n            For your convenience I also put the HTML templating function in its own separate \n            <a href=\"https://github.com/jsebrech/html-literal\">html-literal repo on Github</a>.\n        </p>\n\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113030056958516573\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/adder.html",
    "content": "<!doctype html>\n<head>\n    <title>Adder example</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n</head>\n<body>\n    <style>\n        :root { margin: 0.5em; font-family: system-ui, sans-serif; }\n    </style>\n    <script type=\"module\" src=\"adder.js\"></script>\n    <x-adder></x-adder>\n</body>"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/adder.js",
    "content": "import { signal, computed } from './signals.js';\n\ncustomElements.define('x-adder', class extends HTMLElement {\n    a = signal(1);\n    b = signal(2);\n    result = computed((a, b) => `${a} + ${b} = ${+a + +b}`, [this.a, this.b]);\n\n    connectedCallback() {\n        if (this.querySelector('input')) return;\n\n        this.innerHTML = `\n            <input type=\"number\" name=\"a\" value=\"${this.a}\">\n            <input type=\"number\" name=\"b\" value=\"${this.b}\">\n            <p></p>\n        `;\n        this.result.effect(\n            () => this.querySelector('p').textContent = this.result);\n        this.addEventListener('input', \n            e => this[e.target.name].value = e.target.value);\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Poor man's signals</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"Signals are all the rage over in frameworkland, so let's bring them to vanilla JS.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-08-30\">\n        <img src=\"image.webp\" alt=\"Train signals with mountains in the distance\" loading=\"lazy\" />\n        <h2>Poor man's signals</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            Signals are all the rage right now. Everyone's doing them.\n            <a href=\"https://angular.dev/guide/signals\">Angular</a>,\n            and <a href=\"https://docs.solidjs.com/concepts/signals\">Solid</a>,\n            and <a href=\"https://preactjs.com/guide/v10/signals/\">Preact</a>,\n            and there are third party packages for just about every framework that doesn't already have them.\n            There's even a <a href=\"https://github.com/tc39/proposal-signals\">proposal</a>\n            to add them to the language, and if that passes it's just a \n            <a href=\"https://thenewstack.io/did-signals-just-land-in-react/\">matter of time</a> before all frameworks \n            have them built in.\n        </p>\n\n        <h3>Living under a rock</h3>\n        <p>\n            In case you've been living under a rock, here's the example from Preact's documentation \n            that neatly summarizes what signals do:\n        </p>\n        <x-code-viewer src=\"preact-example.js\" name=\"\"></x-code-viewer>\n        <p>\n            Simply put, signals wrap values and computations \n            in a way that allows us to easily respond to every change to those values and results in a targeted way,\n            without having to rerender the entire application in the way that we would do in React.\n            In short, signals are an efficient and targeted way to respond to changes without having to do state comparison and DOM-diffing.\n        </p>\n        <p>\n            OK, so, if signals are so great, why am I trying to sell you on them on a vanilla web development blog?\n            Don't worry! Vanilla web developers can have signals too.\n        </p>\n\n        <h3>Just a wrapper</h3>\n        <p>\n            Signals are at heart nothing more than a wrapper for a value that sends events when the value changes.\n            That's nothing that a little trickery with the not well known but very handy <code>EventTarget</code> base class can't fix for us.\n        </p>\n        <x-code-viewer src=\"signals1.js\" name=\"\"></x-code-viewer>\n        <p>\n            This gets us a very barebones signals experience:\n        </p>\n        <x-code-viewer src=\"signals1-use.js\" name=\"\"></x-code-viewer>\n        <p>\n            But that's kind of ugly. The <code>new</code> keyword went out of fashion a decade ago,\n            and that <code>addEventListener</code> sure is unwieldy.\n            So let's add a little syntactic sugar.\n        </p>\n        <x-code-viewer src=\"signals2.js\" name=\"\"></x-code-viewer>\n        <p>\n            Now our barebones example is a lot nicer to use:\n        </p>\n        <x-code-viewer src=\"signals2-use.js\" name=\"\"></x-code-viewer>\n        <p>\n            The <code>effect(fn)</code> method will call the specified function,\n            and also subscribe it to changes in the signal's value.\n        </p>\n        <p>\n            It also returns a dispose function that can be used to unregister the effect.\n            However, a nice side effect of using <code>EventTarget</code> and browser built-in events as the reactivity primitive\n            is that it makes the browser smart enough to garbage collect the signal and its effect when the signal goes out of scope.\n            This means less chance for memory leaks even if we never call the dispose function.\n        </p>\n        <p>\n            Finally, the <code>toString</code> and <code>valueOf</code> magic methods allow for dropping <code>.value</code> in most places\n            that the signal's value gets used. (But not in this example, because the console is far too clever for that.)\n        </p>\n\n        <h3>Does not compute</h3>\n        <p>\n            This signals implementation is already capable, but at some point it might be handy to have an effect based on more than one signal.\n            That means supporting computed values. Where the base signals are a wrapper around a value,\n            computed signals are a wrapper around a function.\n        </p>\n        <x-code-viewer src=\"signals3.js\" name=\"\"></x-code-viewer>\n        <p>\n            The computed signal calculates its value from a function.\n            It also depends on other signals, and when they change it will recompute its value.\n            It's a bit obnoxious to have to pass the signals that it depends on\n            as an additional parameter, but hey, I didn't title this article <em>Rich man's signals</em>.\n        </p>\n        <p>\n            This enables porting Preact's signals example to vanilla JS.\n        </p>\n        <x-code-viewer src=\"signals3-use.js\" name=\"\"></x-code-viewer>\n\n        <h3>Can you use it in a sentence?</h3>\n        <p>\n            You may be thinking, all these <code>console.log</code> examples are fine and dandy,\n            but how do you use this stuff in actual web development?\n            This simple adder demonstrates how signals can be combined with web components:\n        </p>\n        <x-code-viewer src=\"adder.js\"></x-code-viewer>\n        <p>\n            And here's a live demo:\n        </p>\n        <iframe src=\"adder.html\" name=\"Adder example\"></iframe>\n        <p>\n            In case you were wondering, the <code>if</code> is there to prevent adding the effect twice\n            if connectedCallback is called when the component is already rendered.\n        </p>\n        <p>\n            The full poor man's signals code in all its 36 line glory can be found in the <a href=\"https://github.com/jsebrech/tiny-signals/\">tiny-signals repo</a> on Github.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113051808087212046\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/preact-example.js",
    "content": "import { signal, computed, effect } from \"@preact/signals\";\n\nconst name = signal(\"Jane\");\nconst surname = signal(\"Doe\");\nconst fullName = computed(() => `${name.value} ${surname.value}`);\n\n// Logs name every time it changes:\neffect(() => console.log(fullName.value));\n// Logs: \"Jane Doe\"\n\n// Updating `name` updates `fullName`, which triggers the effect again:\nname.value = \"John\";\n// Logs: \"John Doe\"\n"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals.js",
    "content": "export class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n\n    effect(fn) {\n        fn();\n        this.addEventListener('change', fn);\n        return () => this.removeEventListener('change', fn);\n    }\n\n    valueOf () { return this.#value; }\n    toString () { return String(this.#value); }\n}\n\nexport class Computed extends Signal {\n    constructor (fn, deps) {\n        super(fn(...deps));\n        for (const dep of deps) {\n            if (dep instanceof Signal) \n                dep.addEventListener('change', () => this.value = fn(...deps));\n        }\n    }\n}\n\nexport const signal = _ => new Signal(_);\nexport const computed = (fn, deps) => new Computed(fn, deps);\n"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals1-use.js",
    "content": "const name = new Signal('Jane');\nname.addEventListener('change', () => console.log(name.value));\nname.value = 'John';\n// Logs: John"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals1.js",
    "content": "class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n}"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals2-use.js",
    "content": "const name = signal('Jane');\nname.effect(() => console.log(name.value));\n// Logs: Jane\nname.value = 'John';\n// Logs: John"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals2.js",
    "content": "class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n\n    effect(fn) {\n        fn();\n        this.addEventListener('change', fn);\n        return () => this.removeEventListener('change', fn);\n    }\n\n    valueOf () { return this.#value; }\n    toString () { return String(this.#value); }\n}\n\nconst signal = _ => new Signal(_);\n"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals3-use.js",
    "content": "const name = signal('Jane');\nconst surname = signal('Doe');\nconst fullName = computed(() => `${name} ${surname}`, [name, surname]);\n// Logs name every time it changes:\nfullName.effect(() => console.log(fullName.value));\n// -> Jane Doe\n\n// Updating `name` updates `fullName`, which triggers the effect again:\nname.value = 'John';\n// -> John Doe\n"
  },
  {
    "path": "public/blog/articles/2024-08-30-poor-mans-signals/signals3.js",
    "content": "class Computed extends Signal {\n    constructor (fn, deps) {\n        super(fn(...deps));\n        for (const dep of deps) {\n            if (dep instanceof Signal) \n                dep.addEventListener('change', () => this.value = fn(...deps));\n        }\n    }\n}\n\nconst computed = (fn, deps) => new Computed(fn, deps);\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/adder.svelte",
    "content": "<script>\n  export let a;\n  export let b;\n</script>\n\n<input type=\"number\" bind:value={a}>\n<input type=\"number\" bind:value={b}>\n\n<p>{a} + {b} = {a + b}</p>"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/bind.js",
    "content": "/**\n* Render a template (element or string) to an html fragment \n* while connecting it up to data using Vue-style shorthand binding syntax.\n*\n* - `@click=\"handleClick\"` -> `click` event and `target.handleClick` method\n* - `@change=\"mySignal\"` -> `change` event will set `target.mySignal.value` to e.target.value\n* - `@change=\"myProp\"` -> `change` event will set `target.myProp` to e.target.value\n* - `:textContent=\"text\"` -> elem `textContent` property is set to `this.text` property once\n*   (also supports special shorthand `:text` for textContent and `:html` for innerHTML)\n* - `:value=\"mySignal\"` -> elem `value` attribute is bound to the signal `target.mySignal`'s value\n*\n* @param {*} template The template to be bound to an object\n* @param {*} target The object being targeted for binding\n* @returns fragment\n*/\nexport const bind = (template, target) => {\n    if (!template.content) {\n        const text = template;\n        template = document.createElement('template');\n        template.innerHTML = text;\n    }\n    const fragment = template.content.cloneNode(true);\n    // iterate over all nodes in the fragment and bind them\n    // based on https://hawkticehurst.com/2024/05/bring-your-own-base-class/\n    const iterator = document.createNodeIterator(\n        fragment,\n        NodeFilter.SHOW_ELEMENT,\n        {\n            // Reject any node that is not an HTML element\n            acceptNode: (node) => {\n                if (!(node instanceof HTMLElement))\n                    return NodeFilter.FILTER_REJECT;\n                return NodeFilter.FILTER_ACCEPT;\n            },\n        }\n    );\n    let node;\n    while (node = iterator.nextNode()) {\n        if (!node) return;\n        const elem = node;\n        // list of all properties\n        // const properties = getAllProperties(elem);\n        // copy NamedNodeMap because we're about to change it\n        for (const attr of Array(...node.attributes)) {\n            // check for custom event listener attributes\n            if (attr.name.startsWith('@')) {\n                const event = attr.name.slice(1);\n                const property = attr.value;\n                let listener;\n                // if we're binding the event to a function, call it directly\n                if (typeof target[property] === 'function') {\n                    listener = target[property].bind(target);\n                // if we're binding to a signal, set the signal's value\n                } else if (typeof target[property] === 'object' && \n                           typeof target[property].value !== 'undefined') {\n                    listener = e => target[property].value = e.target.value;\n                // fallback: assume we're binding to a property, set the property's value\n                } else {\n                    listener = e => target[property] = e.target.value;\n                }\n                elem.addEventListener(event, listener);\n                // remove (non-standard) attribute from element\n                elem.removeAttributeNode(attr);\n            // check for custom property/attribute binding attributes\n            } else if (attr.name.startsWith(':')) {\n                // extract the name and value of the attribute/property\n                let name = attr.name.slice(1);\n                const property = getPropertyForAttribute(name, target); // properties.values().find(k => k.toLowerCase() === name.toLowerCase());\n                const setter = property ?\n                    () => elem[property] = target[attr.value] :\n                    () => elem.setAttribute(name, target[attr.value]);\n                setter();\n                // if we're binding to a signal, listen to updates\n                target[attr.value].effect?.(setter);\n                // remove (non-standard) attribute from element\n                elem.removeAttributeNode(attr);\n            }\n        }\n    }\n    return fragment;\n}\n\nfunction getPropertyForAttribute(name, obj) {\n    switch (name.toLowerCase()) {\n        case 'text': case 'textcontent':\n            return 'textContent';\n        case 'html': case 'innerhtml':\n            return 'innerHTML';\n        default:\n            for (let prop of Object.getOwnPropertyNames(obj)) {\n                if (prop.toLowerCase() === name.toLowerCase()) {\n                    return prop;\n                }\n            }   \n    }\n}"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/bind1.js",
    "content": "export const bind = (template) => {\n    const fragment = template.content.cloneNode(true);\n    // iterate over all nodes in the fragment\n    const iterator = document.createNodeIterator(\n        fragment,\n        NodeFilter.SHOW_ELEMENT,\n        {\n            // reject any node that is not an HTML element\n            acceptNode: (node) => {\n                if (!(node instanceof HTMLElement))\n                    return NodeFilter.FILTER_REJECT;\n                return NodeFilter.FILTER_ACCEPT;\n            },\n        }\n    );\n    let node;\n    while (node = iterator.nextNode()) {\n        if (!node) return;\n        const elem = node;\n        for (const attr of Array(...node.attributes)) {\n            // check for event binding directive\n            if (attr.name.startsWith('@')) {\n\n                // TODO: bind event ...\n                \n                elem.removeAttributeNode(attr);\n            // check for property/attribute binding directive\n            } else if (attr.name.startsWith(':')) {\n                \n                // TODO: bind data ...\n                \n                elem.removeAttributeNode(attr);\n            }\n        }\n    }\n    return fragment;\n}"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/bind2-partial.js",
    "content": "export const bind = (template, target) => {\n    if (!template.content) {\n        const text = template;\n        template = document.createElement('template');\n        template.innerHTML = text;\n    }\n    const fragment = template.content.cloneNode(true);\n// ...\n}"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/bind3-partial.js",
    "content": "// check for custom event listener attributes\nif (attr.name.startsWith('@')) {\n    const event = attr.name.slice(1);\n    const property = attr.value;\n    let listener;\n    // if we're binding the event to a function, call it directly\n    if (typeof target[property] === 'function') {\n        listener = target[property].bind(target);\n    // if we're binding to a signal, set the signal's value\n    } else if (typeof target[property] === 'object' && \n                typeof target[property].value !== 'undefined') {\n        listener = e => target[property].value = e.target.value;\n    // fallback: assume we're binding to a property, set the property's value\n    } else {\n        listener = e => target[property] = e.target.value;\n    }\n    elem.addEventListener(event, listener);\n    // remove (non-standard) attribute from element\n    elem.removeAttributeNode(attr);\n}"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/bind4-partial.js",
    "content": "// ...\n    if (attr.name.startsWith(':')) {\n        // extract the name and value of the attribute/property\n        let name = attr.name.slice(1);\n        const property = getPropertyForAttribute(name, target);\n        const setter = property ?\n            () => elem[property] = target[attr.value] :\n            () => elem.setAttribute(name, target[attr.value]);\n        setter();\n        // if we're binding to a signal, listen to updates\n        if (target[attr.value]?.effect) {\n            target[attr.value].effect(setter);\n        // if we're binding to a property, listen to the target's updates\n        } else if (target.addEventListener) {\n            target.addEventListener('change', setter);\n        }\n        // remove (non-standard) attribute from element\n        elem.removeAttributeNode(attr);\n    }\n// ...\n\nfunction getPropertyForAttribute(name, obj) {\n    switch (name.toLowerCase()) {\n        case 'text': case 'textcontent':\n            return 'textContent';\n        case 'html': case 'innerhtml':\n            return 'innerHTML';\n        default:\n            for (let prop of Object.getOwnPropertyNames(obj)) {\n                if (prop.toLowerCase() === name.toLowerCase()) {\n                    return prop;\n                }\n            }   \n    }\n}"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-bind3/bind.js",
    "content": "export const bind = (template, target) => {\n    if (!template.content) {\n        const text = template;\n        template = document.createElement('template');\n        template.innerHTML = text;\n    }\n    const fragment = template.content.cloneNode(true);\n    // iterate over all nodes in the fragment\n    const iterator = document.createNodeIterator(\n        fragment,\n        NodeFilter.SHOW_ELEMENT,\n        {\n            // reject any node that is not an HTML element\n            acceptNode: (node) => {\n                if (!(node instanceof HTMLElement))\n                    return NodeFilter.FILTER_REJECT;\n                return NodeFilter.FILTER_ACCEPT;\n            },\n        }\n    );\n    let node;\n    while (node = iterator.nextNode()) {\n        if (!node) return;\n        const elem = node;\n        for (const attr of Array(...node.attributes)) {\n            // check for event binding directive\n            if (attr.name.startsWith('@')) {\n                // check for custom event listener attributes\n                if (attr.name.startsWith('@')) {\n                    const event = attr.name.slice(1);\n                    const property = attr.value;\n                    let listener;\n                    // if we're binding the event to a function, call it directly\n                    if (typeof target[property] === 'function') {\n                        listener = target[property].bind(target);\n                    // if we're binding to a signal, set the signal's value\n                    } else if (typeof target[property] === 'object' && \n                                typeof target[property].value !== 'undefined') {\n                        listener = e => target[property].value = e.target.value;\n                    // fallback: assume we're binding to a property, set the property's value\n                    } else {\n                        listener = e => target[property] = e.target.value;\n                    }\n                    elem.addEventListener(event, listener);\n                    // remove (non-standard) attribute from element\n                    elem.removeAttributeNode(attr);\n                }\n            // check for property/attribute binding directive\n            } else if (attr.name.startsWith(':')) {\n\n                // TODO: bind data ...\n                \n                elem.removeAttributeNode(attr);\n            }\n        }\n    }\n    return fragment;\n}\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-bind3/example.html",
    "content": "<!doctype html>\n<head>\n    <title>Binding example</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n</head>\n<body>\n    <style>\n        :root { margin: 0.5em; font-family: system-ui, sans-serif; }\n        div { margin: 0.5em 0; }\n    </style>\n    <script type=\"module\" src=\"example.js\"></script>\n    <x-example></x-example>\n</body>"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-bind3/example.js",
    "content": "import { bind } from './bind.js';\nimport { signal } from './signals.js';\n\ncustomElements.define('x-example', class Example extends HTMLElement {\n\n    set a(value) { \n        this.setAttribute('a', value);\n        this.querySelector('label[for=a] span').textContent = value;\n    }\n    set b(value) {\n        this.setAttribute('b', value);\n        this.querySelector('label[for=b] span').textContent = value;\n    }\n    c = signal('');\n\n    connectedCallback() {\n        this.append(bind(`\n            <div>\n                <input id=\"a\" type=\"number\" @input=\"onInputA\">\n                <label for=\"a\">A = <span></span></label>\n            </div>\n            <div>\n                <input id=\"b\" type=\"number\" @input=\"b\">\n                <label for=\"b\">B = <span></span></label>\n            </div>\n            <div>\n                <input id=\"c\" type=\"number\" @input=\"c\">\n                <label for=\"c\">C = <span></span></label>\n            </div>\n            <button @click=\"onClick\">Add</button>\n            <div>Result: <span id=\"result\"></span></div>\n        `, this));\n        this.c.effect(() => \n            this.querySelector('label[for=c] span').textContent = this.c);\n    }\n\n    onInputA (e) {\n        this.a = e.target.value;\n    }\n\n    onClick() {\n        this.querySelector('#result').textContent =\n            +this.getAttribute('a') + +this.getAttribute('b') + +this.c;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-bind3/signals.js",
    "content": "export class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n\n    effect(fn) {\n        fn();\n        this.addEventListener('change', fn);\n        return () => this.removeEventListener('change', fn);\n    }\n\n    valueOf () { return this.#value; }\n    toString () { return String(this.#value); }\n}\n\nexport class Computed extends Signal {\n    constructor (fn, deps) {\n        super(fn(...deps));\n        for (const dep of deps) {\n            if (dep instanceof Signal) \n                dep.addEventListener('change', () => this.value = fn(...deps));\n        }\n    }\n}\n\nexport const signal = _ => new Signal(_);\nexport const computed = (fn, deps) => new Computed(fn, deps);\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-combined/adder.js",
    "content": "import { bind } from './bind.js';\nimport { signal, computed } from './signals.js';\nimport { html } from './html.js';\n\ncustomElements.define('x-adder', class Adder extends HTMLElement {\n    a = signal();\n    b = signal();\n    result = computed(() => \n        html`${+this.a} + ${+this.b} = ${+this.a + +this.b}`, [this.a, this.b]);\n\n    connectedCallback() {\n        this.a.value ??= this.getAttribute('a') || 0;\n        this.b.value ??= this.getAttribute('b') || 0;\n        this.append(bind(html`\n            <input type=\"number\" :value=\"a\" @input=\"a\" />\n            <input type=\"number\" :value=\"b\" @input=\"b\" />\n            <p :html=\"result\"></p>\n        `, this));\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-combined/bind.js",
    "content": "/**\n* Render a template (element or string) to an html fragment \n* while connecting it up to data using Vue-style shorthand binding syntax.\n*\n* - `@click=\"handleClick\"` -> `click` event and `target.handleClick` method\n* - `@change=\"mySignal\"` -> `change` event will set `target.mySignal.value` to e.target.value\n* - `@change=\"myProp\"` -> `change` event will set `target.myProp` to e.target.value\n* - `:textContent=\"text\"` -> elem `textContent` property is set to `this.text` property once\n*   (also supports special shorthand `:text` for textContent and `:html` for innerHTML)\n* - `:value=\"mySignal\"` -> elem `value` attribute is bound to the signal `target.mySignal`'s value\n*\n* @param {*} template The template to be bound to an object\n* @param {*} target The object being targeted for binding\n* @returns fragment\n* @license Unlicense\n*/\nexport const bind = (template, target) => {\n    if (!template.content) {\n        const text = template;\n        template = document.createElement('template');\n        template.innerHTML = text;\n    }\n    const fragment = template.content.cloneNode(true);\n    // iterate over all nodes in the fragment and bind them\n    // based on https://hawkticehurst.com/2024/05/bring-your-own-base-class/\n    const iterator = document.createNodeIterator(\n        fragment,\n        NodeFilter.SHOW_ELEMENT,\n        {\n            // Reject any node that is not an HTML element\n            acceptNode: (node) => {\n                if (!(node instanceof HTMLElement))\n                    return NodeFilter.FILTER_REJECT;\n                return NodeFilter.FILTER_ACCEPT;\n            },\n        }\n    );\n    let node;\n    while (node = iterator.nextNode()) {\n        if (!node) return;\n        const elem = node;\n        for (const attr of Array(...node.attributes)) {\n            // check for custom event listener attributes\n            if (attr.name.startsWith('@')) {\n                const event = attr.name.slice(1);\n                const property = attr.value;\n                let listener;\n                // if we're binding the event to a function, call it directly\n                if (typeof target[property] === 'function') {\n                    listener = target[property].bind(target);\n                // if we're binding to a signal, set the signal's value\n                } else if (typeof target[property] === 'object' && \n                           typeof target[property].value !== 'undefined') {\n                    listener = e => target[property].value = e.target.value;\n                // fallback: assume we're binding to a property, set the property's value\n                } else {\n                    listener = e => target[property] = e.target.value;\n                }\n                elem.addEventListener(event, listener);\n                // remove (non-standard) attribute from element\n                elem.removeAttributeNode(attr);\n            // check for custom property/attribute binding attributes\n            } else if (attr.name.startsWith(':')) {\n                // extract the name and value of the attribute/property\n                let name = attr.name.slice(1);\n                const property = getPropertyForAttribute(name, target);\n                const setter = property ?\n                    () => elem[property] = target[attr.value] :\n                    () => elem.setAttribute(name, target[attr.value]);\n                setter();\n                // if we're binding to a signal, listen to updates\n                target[attr.value].effect?.(setter);\n                // remove (non-standard) attribute from element\n                elem.removeAttributeNode(attr);\n            }\n        }\n    }\n    return fragment;\n}\n\nfunction getPropertyForAttribute(name, obj) {\n    switch (name.toLowerCase()) {\n        case 'text': case 'textcontent':\n            return 'textContent';\n        case 'html': case 'innerhtml':\n            return 'innerHTML';\n        default:\n            for (let prop of Object.getOwnPropertyNames(obj)) {\n                if (prop.toLowerCase() === name.toLowerCase()) {\n                    return prop;\n                }\n            }   \n    }\n}"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-combined/example.html",
    "content": "<!doctype html>\n<head>\n    <title>Binding example</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n</head>\n<body>\n    <style>\n        :root { margin: 0.5em; font-family: system-ui, sans-serif; }\n        div { margin: 0.5em 0; }\n    </style>\n    <script type=\"module\" src=\"adder.js\"></script>\n    <x-adder a=\"1\" b=\"2\"></x-adder>\n</body>"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-combined/html.js",
    "content": "class Html extends String { }\n\n/** \n * tag a string as html not to be encoded\n * @param {string} str\n * @returns {string}\n */\nexport const htmlRaw = str => new Html(str);\n\n/** \n * entity encode a string as html\n * @param {*} value The value to encode\n * @returns {string}\n */\nexport const htmlEncode = (value) => {\n    // avoid double-encoding the same string\n    if (value instanceof Html) {\n        return value;\n    } else {\n        // https://stackoverflow.com/a/57448862/20980\n        return htmlRaw(\n            String(value).replace(/[&<>'\"]/g, \n                tag => ({\n                    '&': '&amp;',\n                    '<': '&lt;',\n                    '>': '&gt;',\n                    \"'\": '&#39;',\n                    '\"': '&quot;'\n                }[tag]))\n        );\n    }\n}\n\n/** \n * html tagged template literal, auto-encodes entities\n */\nexport const html = (strings, ...values) => \n    htmlRaw(String.raw({ raw: strings }, ...values.map(htmlEncode)));\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/example-combined/signals.js",
    "content": "export class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n\n    effect(fn) {\n        fn();\n        this.addEventListener('change', fn);\n        return () => this.removeEventListener('change', fn);\n    }\n\n    valueOf () { return this.#value; }\n    toString () { return String(this.#value); }\n}\n\nexport class Computed extends Signal {\n    constructor (fn, deps) {\n        super(fn(...deps));\n        for (const dep of deps) {\n            if (dep instanceof Signal) \n                dep.addEventListener('change', () => this.value = fn(...deps));\n        }\n    }\n}\n\nexport const signal = _ => new Signal(_);\nexport const computed = (fn, deps) => new Computed(fn, deps);\n"
  },
  {
    "path": "public/blog/articles/2024-09-03-unix-philosophy/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>A unix philosophy for web development</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"Maybe all web components need to be a light-weight framework is the right set of helper functions.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-09-03\">\n        <img src=\"image.webp\" alt=\"A pattern of connected spheres\" loading=\"lazy\" />\n        <h2>A unix philosophy for web development</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            Web components have their malcontents. While frameworks have done their best to provide\n            a place for web components to fit into their architecture, the suit never fits quite right,\n            and framework authors have not been shy about expressing their disappointment.\n            Here's Ryan Carniato of SolidJS explaining what's wrong with web components:\n        </p>\n        <blockquote>\n            The collection of standards (Custom Elements, HTML Templates, Shadow DOM, and formerly HTML Imports) \n            put together to form Web Components on the surface seem like they could be used to replace \n            your favourite library or framework. But they are not an advanced templating solution. \n            They don't improve your ability to render or update the DOM. \n            They don't manage higher-level concerns for you like state management.\n        </blockquote>\n        <cite><a href=\"https://dev.to/ryansolid/maybe-web-components-are-not-the-future-hfh\">Ryan Carniato</a></cite>\n        <p>\n            While this criticism is true, perhaps it's besides the point.\n            Maybe web components were never meant to solve those problems anyway.\n            Maybe there are ways to solve those problems in a way that dovetails with web components as they exist.\n            In the main <a href=\"../../../pages/components.html\">components tutorial</a> I've already explained what they <em>can</em> do,\n            now let's see what can be done about the things that they <em>can't</em> do.\n        </p>\n\n        <h3>The Unix Philosophy</h3>\n\n        <p>\n            The Unix operating system carries with it a culture and philosophy of system design,\n            which carries over to the command lines of today's Unix-like systems like Linux and MacOS. \n            This philosophy can be summarized as follows:\n        </p>\n        <ul>\n            <li>Write programs that do one thing and do it well.</li>\n            <li>Write programs to work together.</li>\n            <li>Write programs to handle text streams, because that is a universal interface.</li>\n        </ul>\n        <p>\n            What if we look at the various technologies that comprise web components as just programs, \n            part of a Unix-like system of web development that we collectively call the browser platform?\n            In that system we can do better than text and use the DOM as the universal interface between programs, \n            and we can extend the system with a set of single purpose independent \"programs\" (functions) \n            that fully embrace the DOM by augmenting it instead of replacing it.\n        </p>\n        <p>\n            In a sense this is the most old-school way of building web projects, the one people who \"don't know any better\"\n            automatically gravitate to. What us old-school web developers did before Vue and Solid and Svelte, before Angular and React,\n            before Knockout and Ember and Backbone, before even jQuery, was have a bunch of functions in <code>utilities.js</code>\n            that we copied along from project to project.\n            But, you know, sometimes old things can become new again.\n        </p>\n        <p>\n            In previous posts I've already covered a <code>html()</code> function for <a href=\"../2024-08-25-vanilla-entity-encoding/\">vanilla entity encoding</a>,\n            and a <code>signal()</code> function that provides a <a href=\"../2024-08-30-poor-mans-signals/\">tiny signals</a> implementation \n            that can serve as a lightweight system for state management.\n            That still leaves a missing link between the state managed by the signals and the DOM that is rendered from safely entity-encoded HTML.\n            What we need is a <code>bind()</code> function that can bind data to DOM elements and bind DOM events back to data.\n        </p>\n\n        <h3>Finding inspiration</h3>\n\n        <p>\n            In order to bind a template to data, we need a way of describing that behavior in the HTML markup.\n            Well-trodden paths are often the best starting place to look for inspiration. I like <a href=\"https://vuejs.org/guide/essentials/template-syntax.html\">Vue's template syntax</a>,\n            because it is valid HTML but just augmented, and because it is proven. Vue's templates only pretend to be HTML\n            because they're actually compiled to JavaScript behind the scenes, but let's start there as an API.\n            This is what it looks like:\n        </p>\n        <dl>\n            <dt><code>&lt;img :src=\"imageSrc\" /&gt;</code></dt>\n            <dd>Bind <em>src</em> to track the value of the <em>imageSrc</em> property of the current component.\n                Vue is smart enough to set a property if one exists, and falls back to setting an attribute otherwise.\n                (If that confuses you, read about <a href=\"https://javascript.info/dom-attributes-and-properties\">attributes and properties</a> first.)</dd>\n            <dt><code>&lt;button @click=\"doThis\"&gt;&lt;/button&gt;</code></dt>\n            <dd>Bind the <em>click</em> event to the <em>doThis</em> method of the current component.</dd>\n        </dl>\n        <p>\n            By chance I came across this article about <a href=\"https://hawkticehurst.com/2024/05/bring-your-own-base-class/\">making a web component base class</a>.\n            In the section <em>Declarative interactivity</em> the author shows a way to do the Vue-like event binding syntax\n            on a vanilla web component. This is what inspired me to develop the concept into a generic binding function and write this article.\n        </p>\n\n        <h3>Just an iterator</h3>\n\n        <p>\n            The heart of the binding function is an HTML fragment iterator. \n            After all, before we can bind attributes we need to first find the ones that have binding directives.\n        </p>\n        <x-code-viewer src=\"bind1.js\" name=\"\"></x-code-viewer>\n        <p>\n            This code will take an <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template\">HTML template element</a>, \n            clone it to a <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment\">document fragment</a>, \n            and then iterate over all the nodes in the fragment, discovering their attributes. \n            Then for each attribute a check is made to see if it's a binding directive (@ or :). \n            The node is then bound to data according to the directive attribute (shown here as TODO's), \n            and the attribute is removed from the node. At the end the bound fragment is returned for inserting into the DOM.\n        </p>\n        <p>\n            The benefit of using a fragment is that it is disconnected from the main DOM, while still offering all of the DOM API's. \n            That means we can easily create a node iterator to walk over it and discover all the attributes \n            with binding directives, modify those nodes and attributes in-place, and still be sure we're not causing \n            DOM updates in the main page until the fragment is inserted there. This makes the bind function very fast.\n        </p>\n        <p>\n            If you're thinking \"woah dude, that's a lot of code and a lot of technobabble, I ain't reading all that,\"\n            then please, I implore you to read through the code line by line, and you'll see it will all make sense.\n        </p>\n        <p>\n            Of course, we also need to have something to bind <em>to</em>, so we need to add a second parameter.\n            At the same time, it would be nice to just be able to pass in a string and have it auto-converted into a template.\n            The beginning of our bind function then ends up looking like this:\n        </p>\n        <x-code-viewer src=\"bind2-partial.js\" name=\"\"></x-code-viewer>\n        <p>That just leaves us the TODO's. We can make those as simple or complicated as we want. I'll pick a middle ground.</p>\n\n        <h3>Binding to events</h3>\n\n        <p>This 20 line handler binds events to methods, signals or properties:</p>\n        <x-code-viewer src=\"bind3-partial.js\" name=\"\"></x-code-viewer>\n\n        <p>That probably doesn't explain much, so let me give an example of what this enables:</p>\n        <iframe src=\"example-bind3/example.html\" title=\"Binding to events example\" height=\"200\"></iframe>\n        <x-code-viewer src=\"./example-bind3/example.js\" name=\"\"></x-code-viewer>\n\n        <ul>\n            <li><code>input#a</code>'s input event is handled by calling the <code>onClickA()</code> method.</li>\n            <li><code>input#b</code>'s input event is handled by assigning <code>e.target.value</code> to the <code>b</code> property.</li>\n            <li><code>input#c</code>'s input event is handled by setting the value of the <code>c</code> signal.</li>\n        </ul>\n        <p>\n            If you're not familiar with the <code>signal()</code> function, check out the <a href=\"../2024-08-30-poor-mans-signals/\">tiny signals</a> \n            implementation in the previous post. For now you can also just roll with it.\n        </p>\n        <p>Not a bad result for 20 lines of code.</p>\n\n        <h3>Binding to data</h3>\n        <p>\n            Having established the pattern for events that automatically update properties, \n            we now reverse the polarity to make data values automatically set element properties or attributes.\n        </p>\n        <x-code-viewer src=\"bind4-partial.js\" name=\"\"></x-code-viewer>\n        <p>\n            The <code>getPropertyForAttribute</code> function is necessary because the attributes that contain the directives\n            will have names that are case-insensitive, and these must be mapped to property names that are case-sensitive.\n            Also, the <code>:text</code> and <code>:html</code> shorthand notations replace the role of <code>v-text</code>\n            and <code>v-html</code> in Vue's template syntax.\n        </p>\n        <p>\n            When the value of the target's observed property changes, we need to update the bound element's property or attribute.\n            This means a triggering <code>'change'</code> event is needed that is then subscribed to.\n            A framework's templating system will compare state across time, and detect the changed values automatically. \n            Lacking such a system we need a light-weight alternative.\n        </p>\n        <p>\n            When the property being bound to is a signal, this code registers an effect on the signal.\n            When the property is just a value, it registers an event listener on the target object,\n            making it the responsibility of that target object to dispatch the <code>'change'</code> event when values change.\n            This approach isn't going to get many points for style, but it does work.\n        </p>\n        <p>\n            Check out the <a href=\"example-combined/bind.js\">completed bind.js</a> code.\n        </p>\n\n        <h3>Bringing the band together</h3>\n\n        <p>\n            In the article <a href=\"https://dev.to/richharris/why-i-don-t-use-web-components-2cia\">Why I don't use web components</a> \n            Svelte's Rich Harris lays out the case against web components. He demonstrates how this simple 9 line Svelte component\n            <code>&lt;Adder a={1} b={2}/&gt;</code> becomes an incredible verbose 59 line monstrosity when ported to a vanilla web component.\n        </p>\n        <x-code-viewer src=\"adder.svelte\"></x-code-viewer>\n\n        <p>\n            Now that we have assembled our three helper functions <code>html()</code>, <code>signal()</code> and <code>bind()</code>\n            on top of the web components baseline, at a total budget of around 150 lines of code, how close can we get for a web component <code>&lt;x-adder a=\"1\" b=\"2\"&gt;&lt;/x-adder&gt;</code>?\n        </p>\n        <x-code-viewer src=\"example-combined/adder.js\"></x-code-viewer>\n        <iframe src=\"example-combined/example.html\" title=\"combined example\"></iframe>\n\n        <p>\n            To be fair, that's still twice the lines of code, but it describes clearly what it does, and really that is all you need. \n            And I'm just shooting in the wind here, trying stuff out.\n            Somewhere out there could be a minimal set of functions that transforms web components into something resembling a framework,\n            and the idea excites me! Who knows, maybe in a few years the web community will return to writing projects in \n            vanilla web code, dragging along the modern equivalent of <code>utilities.js</code> from project to project...\n        </p>\n        <br>\n        <p><em>What do you think?</em></p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113075285264597399\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-06-how-fast-are-web-components/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>How fast are web components?</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"Benchmarking the relative performance of different web component techniques.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <style>\n        table th:nth-of-type(1) {\n            text-align: left;\n            padding-right: 1em;\n        }\n        table td:nth-of-type(2) {\n            text-align: right;\n        }\n    </style>\n</head>\n<body>\n    <blog-header published=\"2024-09-06\" updated=\"2024-09-15\">\n        <img src=\"image.webp\" alt=\"A snail and a hare in a race\" loading=\"lazy\" />\n        <h2>How fast are web components?</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <aside>\n            <h3>Author's note</h3>\n            <p>\n                This article initially had somewhat different results and conclusions,\n                but deficiencies in the original benchmark were pointed out and addressed.\n                Where the conclusions were changed from the original article, this is pointed out in the text.\n            </p>\n        </aside>\n\n        <p>\n            It is often said that web components are slow.\n            This was also my experience when I first tried building web components a few years ago.\n            At the time I was using the Stencil framework, because I didn't feel confident that they could be built well without a framework.\n            Performance when putting hundreds of them on a page was so bad that I ended up going back to React.\n        </p>\n        <p>\n            But as I've gotten deeper into vanilla web development I started to realize that maybe I was just using it wrong.\n            Perhaps web components can be fast, if built in a light-weight way.\n            This article is an attempt to settle the question \"How fast are web components?\".\n        </p>\n\n        <h3>The lay of the land</h3>\n\n        <p>\n            What kinds of questions did I want answered?\n        </p>\n        <ul>\n            <li>How many web components can you render on the page in a millisecond?</li>\n            <li>Does the technique used to built the web component matter, which technique is fastest?</li>\n            <li>How do web component frameworks compare? I used Lit as the framework of choice as it is well-respected.</li>\n            <li>How does React compare?</li>\n            <li>What happens when you combine React with web components?</li>\n        </ul>\n\n        <p>\n            To figure out the answer I made a benchmark as a vanilla web page (of course),\n            that renders thousands of very simple components containing only <code>&lt;span&gt;.&lt;/span&gt;</code>\n            and measured the elapsed time. This benchmark was then run on multiple devices and multiple browsers\n            to figure out performance characteristics. The ultimate goal of this test is to figure out the absolute best performance\n            that can be extracted from the most minimal web component.\n        </p>\n\n        <p>To get a performance range I used two devices for testing:</p>\n        <ul>\n            <li>A <em>Macbook Air M1</em> running MacOS, to stand in as the \"fast\" device, comparable to a new high end iPhone.</li>\n            <li>An <em>Asus Chi T300 Core M</em> from 2015 running Linux Mint Cinnamon, to stand in as the \"slow\" device, comparable to an older low end Android.</li>\n        </ul>\n        <p>Between these devices is a 7x CPU performance gap.</p>\n\n        <h3>The test</h3>\n\n        <p>\n            The test is simple: render thousands of components using a specific technique, \n            call <code>requestAnimationFrame()</code> repeatedly until they actually render,\n            then measure elapsed time. This produces a <em>components per millisecond</em> number.\n        </p>\n        <p>The techniques being compared:</p>\n        <ul>\n            <li><strong>innerHTML:</strong> each web component renders its content by assigning to <code>this.innerHTML</code></li>\n            <li><strong>append:</strong> each web component creates the span using <code>document.createElement</code> and then appends it to itself</li>\n            <li><strong>append (buffered):</strong> same as the append method, except all web components are first buffered to a document fragment which is then appended to the DOM</li>\n            <li><strong>shadow + innerHTML:</strong> the same as innerHTML, except each component has a shadow DOM</li>\n            <li><strong>shadow + append:</strong> the same as append, except each component has a shadow DOM</li>\n            <li><strong>template + append:</strong> each web component renders its content by cloning a template and appending it</li>\n            <li><strong>textcontent:</strong> each web component directly sets its textContent property, instead of adding a span (making the component itself be the span)\n            <li><strong>direct:</strong> appends spans instead of custom elements, to be able to measure custom element overhead</li>\n            <li><strong>lit:</strong> each web component is rendered using the lit framework, in the way that its documentation recommends</li>\n            <li><strong>react pure:</strong> rendering in React as a standard React component, to have a baseline for comparison to mainstream web development</li>\n            <li><strong>react + wc:</strong> each React component wraps the append-style web component</li>\n            <li><strong>(norender):</strong> same as other strategies, except the component is only created but not added to the DOM, to separate out component construction cost</li>\n        </ul>\n        <p>\n            This test was run on M1 in Brave, Chrome, Edge, Firefox and Safari. And on Chi in Chrome and Firefox.\n            It was run for 10 iterations and a geometric mean was taken of the results.\n        </p>\n\n        <h3>The results</h3>\n\n        <p>First, let's compare techniques. The number here is components per millisecond, so <strong>higher is better</strong>.</p>\n        \n        <p><strong>Author's note:</strong> the numbers from the previous version of this article are <del>crossed out</del>.</p>\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">Chrome on M1</th></tr>\n                <tr><th>technique</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>innerHTML</td><td><del>143</del> 135</td></tr>\n                <tr><td>append</td><td><del>233</del> 239</td></tr>\n                <tr><td>append (buffered)</td><td><del>228</del> 239</td></tr>\n                <tr><td>shadow + innerHTML</td><td><del>132</del> 127</td></tr>\n                <tr><td>shadow + append</td><td><del>183</del> 203</td></tr>\n                <tr><td>template + append</td><td><del>181</del> 198</td></tr>\n                <tr><td>textcontent</td><td>345</td></tr>\n                <tr><td>direct</td><td>461</td></tr>\n                <tr><td>lit</td><td><del>133</del> 137</td></tr>\n                <tr><td>react pure</td><td><del>275</del> 338</td></tr>\n                <tr><td>react + wc</td><td><del>172</del> 212</td></tr>\n                <tr><td>append (norender)</td><td>1393</td></tr>\n                <tr><td>shadow (norender)</td><td>814</td></tr>\n                <tr><td>direct (norender)</td><td>4277</td></tr>\n                <tr><td>lit (norender)</td><td>880</td></tr>\n            </tbody>\n        </table>\n\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">Chrome on Chi, best of three</th></tr>\n                <tr><th>technique</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>innerHTML</td><td><del>25</del> 29</td></tr>\n                <tr><td>append</td><td><del>55</del> 55</td></tr>\n                <tr><td>append (buffered)</td><td><del>56</del> 59</td></tr>\n                <tr><td>shadow + innerHTML</td><td><del>24</del> 26</td></tr>\n                <tr><td>shadow + append</td><td><del>36</del> 47</td></tr>\n                <tr><td>template + append</td><td><del>45</del> 46</td></tr>\n                <tr><td>textcontent</td><td>81</td></tr>\n                <tr><td>direct</td><td>116</td></tr>\n                <tr><td>lit</td><td><del>30</del> 33</td></tr>\n                <tr><td>react pure</td><td><del>77</del> 87</td></tr>\n                <tr><td>react + wc</td><td><del>45</del> 52</td></tr>\n                <tr><td>append (norender)</td><td>434</td></tr>\n                <tr><td>shadow (norender)</td><td>231</td></tr>\n                <tr><td>direct (norender)</td><td>1290</td></tr>\n                <tr><td>lit (norender)</td><td>239</td></tr>\n            </tbody>\n        </table>\n\n        <p>\n            One relief right off the bat is that even the slowest implementation on the slow device renders 100.000 components in 4 seconds.\n            React is roughly in the same performance class as well-written web components.\n            That means for a typical web app performance is not a reason to avoid web components.\n        </p>\n        <aside>\n            <h3>Author's note</h3>\n            <p>\n                The previous version of this article said React was faster than web components,\n                but this only the case if we make the web components render a span. Unlike a React component a web component\n                is itself part of the DOM, and so is itself the equivalent of a span. The <em>textcontent</em> strategy exploits this advantage\n                to functionally do the same as the React code, and it matches its performance.\n            </p>\n        </aside>\n\n        <p>\n            As far as web component technique goes, the performance delta between the fastest and the slowest technique is around 2x,\n            so again for a typical web app that difference will not matter. Things that slow down web components\n            are shadow DOM and innerHTML. Appending directly created elements or cloned templates and avoiding shadow DOM is the right strategy\n            for a well-performing web component that needs to end up on the page thousands of times.\n        </p>\n\n        <p>\n            On the slow device the Lit framework is a weak performer, probably due to its use of shadow DOM and JS-heavy approaches.\n            Meanwhile, pure React is the best performer, because while it does more work in creating the virtual DOM and diffing it to the real DOM,\n            it benefits from not having to initialize the web component class instances.\n            Consequently, when wrapping web components inside React components we see React's performance advantage disappear, and that it adds a performance tax.\n            In the grand scheme of things however, the differences between React and optimized web components remains small.\n        </p>\n\n        <p>\n            The fast device is up to 5x faster than the slow device in Chrome, depending on the technique used,\n            so it is really worth testing applications on slow devices to get an idea of the range of performance.\n        </p>\n\n        <p>\n            Next, let's compare browsers:\n        </p>\n\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">M1, append, best of three</th></tr>\n                <tr><th>browser</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>Brave</td><td><del>146</del> 145</td></tr>\n                <tr><td>Chrome</td><td><del>233</del> 239</td></tr>\n                <tr><td>Edge</td><td><del>224</del> 237</td></tr>\n                <tr><td>Firefox</td><td><del>232</del> 299</td></tr>\n                <tr><td>Safari</td><td><del>260</del> 239</td></tr>\n            </tbody>\n        </table>\n\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">Chi, append, best of three</th></tr>\n                <tr><th>browser</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>Chrome</td><td><del>55</del> 55</td></tr>\n                <tr><td>Firefox</td><td><del>180</del> 77</td></tr>\n            </tbody>\n        </table>\n\n        <p>\n            Brave is really slow, probably because of its built-in ad blocking. Ad blocking extensions also slow down the other browsers by a lot.\n            Safari, Chrome and Edge end up in roughly the same performance bucket. Firefox is the best performer overall.\n            Using the \"wrong\" browser can halve the performance of a machine.\n        </p>\n        <p>\n            <strong>Author's note:</strong>\n            due to a measurement error in measuring elapsed time, the previous version of this article had Safari as fastest and Firefox as middle of the pack.\n        </p>\n        <p>\n            There is a large performance gap when you compare the slowest technique on the slowest browser on the slowest device,\n            with its fastest opposite combo. Specifically, there is a 16x performance gap:\n        </p>\n        <ul>\n            <li>textContent, Firefox on M1: 430 components/ms</li>\n            <li>Shadow DOM + innerHTML, Chrome on Chi: 26 components/ms</li>\n        </ul>\n        <p>\n            That means it becomes worthwhile to carefully consider technique when having to support a wide range of browsers and devices,\n            because a bad combination may lead to a meaningfully degraded user experience.\n            And of course, you should always test your web app on a slow device to make sure it still works ok.\n        </p>\n        \n        <h3>Bottom line</h3>\n\n        <p>\n            I feel confident now that web components can be fast enough for almost all use cases where someone might consider React instead.\n        </p>\n        <p>\n            However, it does matter how they are built. Shadow DOM should not be used for smaller often used web components,\n            and the contents of those smaller components should be built using append operations instead of innerHTML.\n            The use of web component frameworks might impact their performance significantly,\n            and given how easy it is to write vanilla web components I personally don't see the point behind Lit or Stencil. YMMV.\n        </p>\n\n        <p>\n            The full benchmark code and results can be <a href=\"https://github.com/jsebrech/vanilla-benchmarks\">found on Github</a>.\n        </p>\n\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113092382700063677\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/error-boundary-partial.html",
    "content": "<x-error-boundary>\n    <p slot=\"error\">Something went wrong</p>\n    <x-suspense>\n        <p slot=\"fallback\">Loading...</p>\n        <x-lazy><x-hello-world></x-hello-world></x-lazy>\n    </x-suspense>\n</x-error-boundary>"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/error-boundary.js",
    "content": "export class ErrorBoundary extends HTMLElement {\n\n    static showError(sender, error) {\n        if (!error) throw new Error('ErrorBoundary.showError: expected two arguments but got one');\n        const boundary = sender.closest('x-error-boundary');\n        if (boundary) {\n            boundary.error = error;\n        } else {\n            console.error('unable to find x-error-boundary to show error');\n            console.error(error);\n        }\n    }\n\n    #error;\n    #errorSlot;\n    #contentSlot;\n\n    get error() {\n        return this.#error;\n    }\n\n    set error(error) {\n        if (!this.#errorSlot) return;\n        this.#error = error;\n        this.#errorSlot.style.display = error ? 'contents' : 'none';\n        this.#contentSlot.style.display = !error ? 'contents' : 'none';\n        if (error) {\n            this.#errorSlot.assignedElements().forEach(element => {\n                if (Object.hasOwn(element, 'error')) {\n                    element.error = error;\n                } else {\n                    element.setAttribute('error', error?.message || error);\n                }\n            });\n            this.dispatchEvent(new CustomEvent('error', { detail: error }));\n        }\n    }\n\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n\n        this.#errorSlot = document.createElement('slot');\n        this.#errorSlot.style.display = 'none';\n        this.#errorSlot.name = 'error';\n        // default error message\n        this.#errorSlot.textContent = 'Something went wrong.';\n        this.#contentSlot = document.createElement('slot');\n        this.shadowRoot.append(this.#errorSlot, this.#contentSlot);\n    }\n\n    reset() {\n        this.error = null;\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n}\ncustomElements.define('x-error-boundary', ErrorBoundary);\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/components/error-boundary.js",
    "content": "/**\n * A vanilla version of react-error-boundary ( https://github.com/bvaughn/react-error-boundary )\n * \n * Usage:\n * \n * <x-error-boundary>\n *     <p slot=\"error\">Something went wrong</p>\n *     <x-suspense>\n *         Shows the error if loading fails:\n *         <x-lazy><x-load-on-demand></x-load-on-demand></x-lazy>\n *     </x-suspense>\n * </x-error-boundary>\n * \n * @license MIT\n */\nexport class ErrorBoundary extends HTMLElement {\n\n    /**\n     * Find the nearest error boundary to the sender element and make it show an error\n     * @param {*} sender The element that sends the error\n     * @param {*} error Error or string, the error to show\n     */\n    static showError(sender, error) {\n        if (!error) throw new Error('ErrorBoundary.showError: expected two arguments but got one');\n        const boundary = sender.closest('x-error-boundary');\n        if (boundary) {\n            boundary.error = error;\n        } else {\n            console.error('unable to find x-error-boundary to show error');\n            console.error(error);\n        }\n    }\n\n    #error;\n    #errorSlot;\n    #contentSlot;\n\n    get error() {\n        return this.#error;\n    }\n\n    set error(error) {\n        if (!this.#errorSlot) return;\n        this.#error = error;\n        this.#errorSlot.style.display = error ? 'contents' : 'none';\n        this.#contentSlot.style.display = !error ? 'contents' : 'none';\n        if (error) {\n            this.#errorSlot.assignedElements().forEach(element => {\n                if (Object.hasOwn(element, 'error')) {\n                    element.error = error;\n                } else {\n                    element.setAttribute('error', error?.message || error);\n                }\n            });\n            this.dispatchEvent(new CustomEvent('error', { detail: error }));\n        }\n    }\n\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n\n        this.#errorSlot = document.createElement('slot');\n        this.#errorSlot.style.display = 'none';\n        this.#errorSlot.name = 'error';\n        // default error message\n        this.#errorSlot.textContent = 'Something went wrong.';\n        this.#contentSlot = document.createElement('slot');\n        this.shadowRoot.append(this.#errorSlot, this.#contentSlot);\n    }\n\n    reset() {\n        this.error = null;\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n}\n\nexport const registerErrorBoundary = () => customElements.define('x-error-boundary', ErrorBoundary);\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/components/error-message.js",
    "content": "class ErrorMessage extends HTMLElement {\n    connectedCallback() {\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['error'];\n    }\n    \n    attributeChangedCallback() {\n        this.update();\n    }\n    \n    update() {\n        const errorMsg = this.getAttribute('error') || '';\n        this.textContent = errorMsg;\n    }\n}\n\nexport const registerErrorMessage = () => customElements.define('x-error-message', ErrorMessage);\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/components/hello-world/hello-world.js",
    "content": "import { Suspense } from '../suspense.js';\nimport { later } from './later.js';\n\nclass HelloWorldComponent extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            <p>Hello world!</p>\n            <button id=\"load\">Load</button>\n            <button id=\"error\">Load with error</button>\n        `;\n        const btnLoad = this.querySelector('button#load');\n        btnLoad.onclick = () => {\n            // simulate loading of data\n            Suspense.waitFor(this, later(1000));\n        };\n        const btnError = this.querySelector('button#error');\n        btnError.onclick = () => {\n            // simulate loading of data that ends in an error\n            Suspense.waitFor(this, later(1000).then(() => { throw new Error('An error, as expected.'); }));\n        }\n    }\n}\n\nexport default function register() {\n    customElements.define('x-hello-world', HelloWorldComponent);\n}\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/components/hello-world/later.js",
    "content": "export function later(delay) {\n    return new Promise(function(resolve) {\n        setTimeout(resolve, delay);\n    });\n}"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/components/lazy.js",
    "content": "import { Suspense } from './suspense.js';\n\n/**\n * A vanilla version of React's lazy() function\n * inspired by https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/\n * \n * Usage: <x-lazy><x-load-on-demand></x-load-on-demand></x-lazy>\n * \n * Will load default function from ./components/<load-on-demand>/<load-on-demand>.js and execute it.\n * Only direct children are lazy-loaded, and only on initial DOM insert.\n * \n * Pass the root attribute to modify the path to load relative to the current document.\n * <x-lazy root=\"./submodule/components/\"><x-load-on-demand></x-load-on-demand></x-lazy>\n * \n * Put the lazy-path attribute on a custom element to specify the path to the JS file to load.\n * \n * @license MIT\n */\nclass Lazy extends HTMLElement {\n    connectedCallback() {\n        this.style.display = 'contents';\n        this.#loadLazy();\n    }\n\n    /**\n     * Find direct child custom elements that need loading, then load them\n     */\n    #loadLazy() {\n        const elements = \n            [...this.children].filter(_ => _.localName.includes('-'));\n        const unregistered = \n            elements.filter(_ => !customElements.get(_.localName));\n        if (unregistered.length) {\n            Suspense.waitFor(this, \n                ...unregistered.map(_ => this.#loadElement(_))\n            );    \n        }\n    }\n\n    /**\n     * Load a custom element\n     * @param {*} element \n     * @returns {Promise} a promise that settles when loading completes or fails\n     */\n    #loadElement(element) {\n        // does the element advertise its own path?\n        let url = element.getAttribute('lazy-path');\n        if (!url) {\n            // strip leading x- off the name\n            const cleanName = element.localName.replace(/^x-/, '').toLowerCase();\n            // root directory to load from, relative to current document\n            const rootDir = this.getAttribute('root') || './components/';\n            // assume component is in its own folder\n            url = `${rootDir}${cleanName}/${cleanName}.js`;\n        }\n        // dynamically import, then register if not yet registered\n        return import(new URL(url, document.location)).then(module => \n            !customElements.get(element.localName) && module && module.default());\n    }\n}\n\nexport const registerLazy = () => customElements.define('x-lazy', Lazy);\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/components/suspense.js",
    "content": "import { ErrorBoundary } from './error-boundary.js';\n\n/**\n * A vanilla version of React's Suspense\n * \n * Usage:\n * \n * <x-suspense>\n *     <p slot=\"fallback\">Loading...</p>\n *     <p>\n *         While it loads it shows the fallback:\n *         <x-lazy><x-load-on-demand></x-load-on-demand></x-lazy>\n *     </p>\n * </x-suspense>\n * \n * @license MIT\n */\nexport class Suspense extends HTMLElement {\n\n    /**\n     * Find the nearest suspense to the sender element and make it wait for the promises to complete.\n     * @param {*} sender The element that sends the promise\n     * @param {...Promise} promises \n     */\n    static waitFor(sender, ...promises) {\n        const suspense = sender.closest('x-suspense');\n        if (suspense) suspense.addPromises(...promises);\n    }\n\n    #fallbackSlot;\n    #contentSlot;\n    #waitingForPromise;\n\n    set #loading(isLoading) {\n        if (!this.#fallbackSlot) return;\n        this.#fallbackSlot.style.display = isLoading ? 'contents' : 'none';\n        this.#contentSlot.style.display = !isLoading ? 'contents' : 'none';\n    }\n\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n\n        this.#fallbackSlot = document.createElement('slot');\n        this.#fallbackSlot.style.display = 'none';\n        this.#fallbackSlot.name = 'fallback';\n        this.#contentSlot = document.createElement('slot');\n        this.shadowRoot.append(this.#fallbackSlot, this.#contentSlot);\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n\n    /**\n     * Wait for one or more promises to settle, showing fallback content\n     * @param  {...Promise} promises \n     */\n    addPromises(...promises) {\n        if (!promises.length) return;\n        this.#loading = true;\n        // combine into previous promises if there are any\n        const newPromise = this.#waitingForPromise = \n            Promise.allSettled([...promises, this.#waitingForPromise]);\n        // wait for all promises to complete\n        newPromise.then(settled => {\n            // if no more promises were added, we're done\n            if (newPromise === this.#waitingForPromise) {\n                this.#loading = false;\n                // if a promise failed, show an error\n                const failed = settled.find(_ => _.status === 'rejected');\n                if (failed) ErrorBoundary.showError(this, failed.reason);\n            }\n        });\n    }\n}\n\nexport const registerSuspense = () => customElements.define('x-suspense', Suspense);\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <title>Lazy, Suspense and Error Boundary example</title>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n        <style>\n            body { font-family: system-ui, sans-serif; }\n            div { min-height: 2em; border: 1px dotted black; margin: 1em 0; padding: 1em; }\n            button { font-size: 90%; }\n        </style>\n    </head>\n    <body>\n        <x-demo></x-demo>\n        <script type=\"module\" src=\"index.js\"></script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/example/index.js",
    "content": "import { registerLazy } from './components/lazy.js';\nimport { registerSuspense } from './components/suspense.js';\nimport { registerErrorBoundary } from './components/error-boundary.js';\nimport { registerErrorMessage } from './components/error-message.js';\n\ncustomElements.define('x-demo', class extends HTMLElement {\n\n    constructor() {\n        super();\n        registerLazy();\n        registerSuspense();\n        registerErrorBoundary();\n        registerErrorMessage();\n    }\n\n    connectedCallback() {\n        this.innerHTML = `\n            <p>Lazy loading demo</p>\n            <button id=\"lazy-load\">Load lazy</button>\n            <button id=\"error-reset\" disabled>Reset error</button>\n            <div id=\"lazy-load-div\">\n                <p>Click to load..</p>\n            </div>\n        `;\n        const resetBtn = this.querySelector('button#error-reset')\n        resetBtn.onclick = () => {\n            this.querySelector('x-error-boundary').reset();\n            resetBtn.setAttribute('disabled', true);\n        };\n        const loadBtn = this.querySelector('button#lazy-load');\n        loadBtn.onclick = () => {\n            this.querySelector('div#lazy-load-div').innerHTML = `\n                <x-error-boundary>\n                    <x-error-message slot=\"error\"></x-error-message>\n                    <x-suspense>\n                        <p slot=\"fallback\">Loading...</p>\n                        <p><x-lazy><x-hello-world></x-hello-world></x-lazy></p>\n                    </x-suspense>\n                </x-error-boundary>\n            `\n            this.querySelector('x-error-boundary').addEventListener('error', _ => {\n                resetBtn.removeAttribute('disabled');\n            });\n            loadBtn.setAttribute('disabled', true);\n        };\n    }\n\n});\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Sweet Suspense</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"React-style lazy loading of web components.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-09-09\">\n        <img src=\"image.webp\" alt=\"A shadowed figure in a city square, waiting on a woman\" loading=\"lazy\" />\n        <h2>Sweet Suspense</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            I was reading Addy Osmani and Hassan Djirdeh's book <a href=\"https://largeapps.dev/\">Building Large Scale Web Apps</a>.\n            (Which, by the way, I can definitely recommend.) In it they cover all the ways to make a React app sing at scale.\n            The chapter on <em>Modularity</em> was especially interesting to me, because JavaScript modules\n            are a common approach to modularity in both React and vanilla web code.\n        </p>\n        <p>\n            In that chapter on <em>Modularity</em> there was one particular topic that caught my eye,\n            and it was the use of <code>lazy()</code> and <code>Suspense</code>, paired with an <code>ErrorBoundary</code>.\n            These are the primitives that React gives us to asynchronously load UI components and their data on-demand while showing a fallback UI,\n            and replace the UI with an error message when something goes wrong.\n            If you're not familiar, here's a good <a href=\"https://refine.dev/blog/react-lazy-loading/#catching-loading-errors\">overview page</a>.\n        </p>\n        <p>\n            It was at that time that I was visited by the imp of the perverse, which posed to me a simple challenge:\n            <em>can you bring React's lazy loading primitives to vanilla web components?</em>\n            To be clear, there are <a href=\"https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/\">many</a> \n            <a href=\"https://github.com/codewithkyle/lazy-loader\">ways</a> to \n            <a href=\"https://www.webcomponents.org/element/st-lazy\">load</a> web components \n            <a href=\"https://lamplightdev.com/blog/2020/03/20/lazy-loading-web-components-with-intersection-observer/\">lazily</a>. \n            This is well-trodden territory. What wasn't out there was a straight port of lazy, suspense and error boundary. \n            The idea would not let me go. So here goes nothing.\n        </p>\n\n        <h3>Lazy</h3>\n\n        <p>\n            The idea and execution of React's lazy is simple. Whenever you want to use a component in your code,\n            but you don't want to actually fetch its code yet until it needs to be rendered, wrap it using the <code>lazy()</code> function:<br>\n            <code>const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));</code><br>\n        </p>\n        <p>\n            React will automatically \"suspend\" rendering when it first bumps into this lazy component until the component has loaded, and then continue automatically.\n        </p>\n        <p>\n            This works in React because the markup of a component only looks like HTML, \n            but is actually JavaScript in disguise, better known as <em>JSX</em>.\n            With web components however, the markup that the component is used in is actually HTML,\n            where there is no <code>import()</code> and no calling of functions.\n            That means our vanilla <em>lazy</em> cannot be a JavaScript function, but instead it must be an HTML custom element:<br>\n            <code>&lt;x-lazy&gt;&lt;x-hello-world&gt;&lt;/x-hello-world&gt;&lt;/x-lazy&gt;</code>\n        </p>\n\n        <p>\n            The basic setup is simple, when the lazy component is added to the DOM,\n            we'll scan for children that have a '-' in the name and therefore are custom elements,\n            see if they're not yet defined, and load and define them if so.\n            By using <code>display: contents</code> we can avoid having the <code>&lt;x-lazy&gt;</code> impact layout.\n        </p>\n        <x-code-viewer src=\"./lazy1.js\" name=\"lazy.js\"></x-code-viewer>\n\n        <p>\n            To actually load the element, we'll have to first find the JS file to import, and then run its register function.\n            By having the function that calls <code>customElements.define</code> as the default export by convention the problem is reduced to finding the path to the JS file.\n            The following code uses a heuristic that assumes components are in a <code>./components/</code> subfolder of the current document\n            and follow a consistent file naming scheme:\n        </p>\n        <x-code-viewer src=\"./lazy2-partial.js\" name=\"lazy.js (continued)\"></x-code-viewer>\n\n        <p>\n            One could get a lot more creative however, and for example use an \n            <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap\">import map</a> \n            to map module names to files. This I leave as an exercise for the reader.\n        </p>\n\n        <h3>Suspense</h3>\n\n        <p>\n            While the lazy component is loading, we can't show it yet. This is true for custom elements just as much as for React.\n            That means we need a wrapper component that will show a fallback UI as long as any components in its subtree are loading,\n            the <code>&lt;x-suspense&gt;</code> component. This starts out as a tale of two slots. When the suspense element is loading it shows the fallback, otherwise the content.\n        </p>\n\n        <x-code-viewer src=\"./suspense1-partial.html\" name=\"example.html\"></x-code-viewer>\n        <x-code-viewer src=\"./suspense1.js\" name=\"suspense.js\"></x-code-viewer>\n\n        <p>\n            The trick now is, how to we get <code>loading = true</code> to happen?\n            In Plain Vanilla's applications page I showed how a React context can be simulated using the <code>element.closest()</code> API.\n            We can use the same mechanism to create a generic API that will let our suspense wait on a promise to complete.\n        </p>\n\n        <x-code-viewer src=\"./suspense2-partial.js\" name=\"suspense.js (continued)\"></x-code-viewer>\n\n        <p>\n            <code>Suspense.waitFor</code> will call the nearest ancestor <code>&lt;x-suspense&gt;</code>\n            to a given element, and give it a set of promises that it should wait on.\n            This API can then be called from our <code>&lt;x-lazy&gt;</code> component.\n            Note that <code>#loadElement</code> returns a promise that completes when the custom element is loaded or fails to load.\n        </p>\n        <x-code-viewer src=\"./lazy3-partial.js\" name=\"lazy.js (continued)\"></x-code-viewer>\n        <p>\n            The nice thing about the promise-based approach is that we can give it any promise, just like we would with React's suspense.\n            For example, when loading data in a custom element that is in the suspense's subtree, we can call the exact same API:<br>\n            <code>Suspense.waitFor(this, fetch(url).then(...))</code>\n        </p>\n\n        <h3>Error boundary</h3>\n\n        <p>\n            Up to this point, we've been assuming everything always works. This is <del>Sparta</del>software, it will never \"always work\".\n            What we need is a graceful way to intercept failed promises that are monitored by the suspense,\n            and show an error message instead. That is the role that React's error boundary plays.\n        </p>\n        <p>\n            The approach is similar to suspense:\n        </p>\n        <x-code-viewer src=\"./error-boundary-partial.html\" name=\"example.html\"></x-code-viewer>\n        <p>\n            And the code is also quite similar to suspense:\n        </p>\n        <x-code-viewer src=\"./error-boundary.js\"></x-code-viewer>\n\n        <p>\n            Similar to suspense, this has an API <code>ErrorBoundary.showError()</code> that can be called\n            from anywhere inside the error boundary's subtree to show an error that occurs.\n            The suspense component is then modified to call this API when it bumps into a rejected promise.\n            To hide the error, the <code>reset()</code> method can be called on the error boundary element.\n        </p>\n        <p>\n            Finally, the <code>error</code> setter will set the error as a property or attribute\n            on all children in the error slot, which enables customizing the error message's behavior based on the error object's properties\n            by creating a custom <code>&lt;x-error-message&gt;</code> component.\n        </p>\n\n        <h3>Conclusion</h3>\n\n        <p>\n            Finally, we can bring all of this together in a single example,\n            that combines lazy, suspense, error boundary, a customized error message, and a lazy-loaded hello-world component.\n        </p>\n\n        <x-code-viewer src=\"./example/index.js\" name=\"example/index.js\"></x-code-viewer>\n        <iframe src=\"example/index.html\" title=\"complete example\" height=\"250\"></iframe>\n\n        <p>\n            For the complete example's code, as well as the lazy, suspense and error-boundary components,\n            check out the <a href=\"https://github.com/jsebrech/sweet-suspense\">sweet-suspense repo on Github</a>.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113109291222822968\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/lazy1.js",
    "content": "customElements.define('x-lazy', class extends HTMLElement {\n    connectedCallback() {\n        this.style.display = 'contents';\n        this.#loadLazy();\n    }\n\n    #loadLazy() {\n        const elements = \n            [...this.children].filter(_ => _.localName.includes('-'));\n        const unregistered = \n            elements.filter(_ => !customElements.get(_.localName));\n        unregistered.forEach(_ => this.#loadElement(_));\n    }\n\n    #loadElement(element) {\n        // TODO: load the custom element\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/lazy2-partial.js",
    "content": "    #loadElement(element) {\n        // strip leading x- off the name\n        const cleanName = element.localName.replace(/^x-/, '').toLowerCase();\n        // assume component is in its own folder\n        const url = `./components/${cleanName}/${cleanName}.js`;\n        // dynamically import, then register if not yet registered\n        return import(new URL(url, document.location)).then(module => \n            !customElements.get(element.localName) && module && module.default());\n    }"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/lazy3-partial.js",
    "content": "    #loadLazy() {\n        const elements = \n            [...this.children].filter(_ => _.localName.includes('-'));\n        const unregistered = \n            elements.filter(_ => !customElements.get(_.localName));\n        if (unregistered.length) {\n            Suspense.waitFor(this, \n                ...unregistered.map(_ => this.#loadElement(_))\n            );\n        }\n    }"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/suspense1-partial.html",
    "content": "<x-suspense>\n    <p slot=\"fallback\">Loading...</p>\n    <x-lazy><x-hello-world></x-hello-world></x-lazy>\n</x-suspense>"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/suspense1.js",
    "content": "export class Suspense extends HTMLElement {\n    #fallbackSlot;\n    #contentSlot;\n\n    set loading(isLoading) {\n        if (!this.#fallbackSlot) return;\n        this.#fallbackSlot.style.display = isLoading ? 'contents' : 'none';\n        this.#contentSlot.style.display = !isLoading ? 'contents' : 'none';\n    }\n\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n\n        this.#fallbackSlot = document.createElement('slot');\n        this.#fallbackSlot.style.display = 'none';\n        this.#fallbackSlot.name = 'fallback';\n        this.#contentSlot = document.createElement('slot');\n        this.shadowRoot.append(this.#fallbackSlot, this.#contentSlot);\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n}\ncustomElements.define('x-suspense', Suspense);"
  },
  {
    "path": "public/blog/articles/2024-09-09-sweet-suspense/suspense2-partial.js",
    "content": "    static waitFor(sender, ...promises) {\n        const suspense = sender.closest('x-suspense');\n        if (suspense) suspense.addPromises(...promises);\n    }\n\n    addPromises(...promises) {\n        if (!promises.length) return;\n        this.loading = true;\n        // combine into previous promises if there are any\n        const newPromise = this.#waitingForPromise = \n            Promise.allSettled([...promises, this.#waitingForPromise]);\n        // wait for all promises to complete\n        newPromise.then(_ => {\n            // if no newer promises were added, we're done\n            if (newPromise === this.#waitingForPromise) {\n                this.loading = false;\n            }\n        });\n    }"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/defined/example.html",
    "content": "<!doctype html>\n<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n        <title>defining the custom element</title>\n        <style>\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-example {\n                background-color: lavender;\n            }\n            x-example:not(:defined)::after {\n                content: '{defined: false}'\n            }\n            x-example:defined::after {\n                content: '{defined: true, status: ' attr(status) '}'\n            }\n        </style>\n    </head>\n    <body>\n        <p>Custom element: <x-example></x-example></p>\n        <button onclick=\"define()\">Define</button>\n        <button onclick=\"location.reload()\">Reload</button>\n\n        <script>\n            function define() {\n                customElements.define('x-example', class extends HTMLElement {\n                    constructor() {\n                        super();\n                    }\n                    connectedCallback() {\n                        this.setAttribute('status', 'ready');\n                    }\n                });\n            }\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/defined2/example.html",
    "content": "<!doctype html>\n<html>\n    <head>\n        <title>defined custom elements</title>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n        <style>\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-container { display: block; border: 1px dotted gray; padding: 1em; }\n            x-controls { display: block; margin-top: 1em; }\n            #placeholder:empty::after { content: '-' }\n            #log { border: 1px dotted gray; padding: 1em; font-size: 80%; }\n\n            x-lifecycle { background: #ddd; padding: 0.1em; }\n            x-lifecycle:not(:defined)::after {\n                content: '{defined: false}';\n            }\n            x-lifecycle:defined::after {\n                content: \n                    '{defined: true, constructed: true'\n                    ', connected: ' attr(connected) \n                    ', source: ' attr(source) '}';\n            }\n        </style>\n    </head>\n    <body>\n        <x-container>\n            <p>Static element: <x-lifecycle source=\"static\"></x-lifecycle></p>\n            <p>Dynamic element: <span id=\"placeholder\"></span></p>\n        </x-container>\n\n        <x-controls state=\"initial\">\n            <button id=\"define\" onclick=\"define()\">Define</button>\n            <button id=\"create\" onclick=\"create()\">Create</button>\n            <button id=\"upgrade\" onclick=\"upgrade()\" disabled>Upgrade</button>\n            <button id=\"connect\" onclick=\"connect()\" disabled>Connect</button>\n            <button id=\"disconnect\" onclick=\"disconnect()\" disabled>Disconnect</button>\n            <button id=\"delete\" onclick=\"deleteElement()\" disabled>Delete</button>\n            <button onclick=\"location.reload()\">Reload</button>\n        </x-controls>\n\n        <div>\n            <h4>Dynamic element (in-memory)</h4>\n            <p><span id=\"element-status\"></span></p>\n        </div>\n\n        <div id=\"log\"><h4>Reactions:</h4></div>\n\n        <script>\n            let storage = { };\n\n            update();\n\n            function define() {\n                customElements.define('x-lifecycle', class extends HTMLElement {\n                    get status() {\n                        return 'defined: true, constructed: true' +\n                               ', connected: ' + (this.getAttribute('connected') || 'false') +\n                               ', source: ' + (this.getAttribute('source') || 'unknown');\n                    }\n\n                    constructor() {\n                        super();\n                        update();\n                        appendLog('constructed');\n                    }\n\n                    connectedCallback() {\n                        this.setAttribute('connected', true);\n                        update();\n                        appendLog('connected');\n                    }\n\n                    disconnectedCallback() {\n                        this.setAttribute('connected', false);\n                        update();\n                        appendLog('disconnected');\n                    }\n\n                    static observedAttributes = ['source'];\n                    attributeChangedCallback() {\n                        appendLog('attributes changed');\n                    }\n                });\n                update();\n            }\n\n            function create() {\n                storage.element = document.createElement('x-lifecycle');\n                storage.element.setAttribute('source', 'createElement');\n                update();\n            }\n\n            function upgrade() {\n                customElements.upgrade(storage.element);\n                update();\n            }\n\n            function connect() {\n                document.querySelector('#placeholder').append(storage.element);\n                update();\n            }\n\n            function disconnect() {\n                storage.element.remove();\n                update();\n            }\n\n            function deleteElement() {\n                delete storage.element;\n                update();\n            }\n\n            function update() {\n                // definition\n                const isDefined = !!customElements.get('x-lifecycle');\n                // dynamic element\n                const isCreated = !!storage.element;\n                const isConstructed = isCreated && !!storage.element.status;\n                const isConnected = !!document.querySelector('#placeholder x-lifecycle');\n                document.querySelector('#element-status').textContent = \n                    storage.element ? '{' + \n                        ( storage.element.status || \n                          (isDefined ? 'defined: true, constructed: false' : 'defined: false')) + \n                    '}' : 'null';\n                // controls\n                setButtonDisabled('define', isDefined);\n                setButtonDisabled('create', isCreated);\n                setButtonDisabled('connect', !isCreated || isConnected);\n                setButtonDisabled('disconnect', !storage.element || !isConnected);\n                setButtonDisabled('upgrade', !isDefined || !isCreated || isConstructed || isConnected);\n                setButtonDisabled('delete', !isCreated || isConnected);\n            }\n\n            function getButton(id) {\n                return document.querySelector('button#' + id);\n            }\n\n            function setButtonDisabled(id, disabled) {\n                const btn = getButton(id);\n                if (btn) {\n                    disabled ? btn.setAttribute('disabled', true) : btn.removeAttribute('disabled');\n                }\n            }\n\n            function appendLog(text) {\n                const p = document.createElement('p');\n                p.textContent = text;\n                document.querySelector('#log').append(p);\n            }\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>The life and times of a web component</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"The entire lifecycle of a web component, from original creation to when a shadow crosses.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-09-16\">\n        <img src=\"image.webp\" alt=\"A custom element at a house party\" loading=\"lazy\" />\n        <h2>The life and times of a web component</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            When first taught about the wave-particle duality of light most people's brains does a double take.\n            How can light be two different categories of things at the same time, both a wave and a particle? That's just weird.\n            The same thing happens with web components, confusing people when they first try to learn them and run into their Document-JavaScript duality.\n            The component systems in frameworks are typically JavaScript-first, only using the DOM as an outlet for their visual appearance.\n            Web components however &mdash; or custom elements to be precise &mdash; can start out in either JavaScript or the document, and are married to neither.\n        </p>\n\n        <h3>Just the DOM please</h3>\n\n        <p>\n            Do you want to see the minimal JavaScript code needed to set up an <code>&lt;x-example&gt;</code> custom element?\n            Here it is:\n        </p>\n        <p>&nbsp;</p>\n        <p>\n            No, that's not a typo. Custom elements can be used just fine without any JavaScript.\n            Consider this example of an <code>&lt;x-tooltip&gt;</code> custom element that is HTML and CSS only:\n        </p>\n        <iframe src=\"undefined/example.html\" name=\"undefined custom element\" height=\"75\"></iframe>\n        <x-code-viewer src=\"undefined/example.html\" name=\"example.html\"></x-code-viewer>\n        <p>\n            <small>For the curious, here is the <a href=\"undefined/example.css\">example.css</a>, but it is not important here.</small>\n        </p>\n        <p>\n            Such elements are called <em>undefined custom elements</em>.\n            Before custom elements are defined in the window by calling <code>customElements.define()</code> they always start out in this state.\n            There is no need to actually define the custom element if it can be solved in a pure CSS way.\n            In fact, many \"pure CSS\" components found online can be solved by such custom elements,\n            by styling the element itself and its <code>::before</code> and <code>::after</code> pseudo-elements.\n        </p>\n\n        <h3>A question of definition</h3>\n\n        <p>\n            The CSS-only representation of the custom element can be progressively enhanced by connecting it up to a JavaScript counterpart,\n            a custom element class. This is a class that inherits from <code>HTMLElement</code> and allows the custom element\n            to implement its own logic.\n        </p>\n        <iframe src=\"defined/example.html\" name=\"defining the custom element\" height=\"125\"></iframe>\n        <x-code-viewer src=\"defined/example.html\" name=\"example.html\"></x-code-viewer>\n        <p>\n            What happens to the elements already in the markup at the moment <code>customElements.define()</code>\n            is called is an <em>element upgrade</em>. The browser will take all custom elements already in the document,\n            and create an instance of the matching custom element class that it connects them to.\n            This class enables the element to control its own part of the DOM, but also allows it to react to what happens in the DOM.\n        </p>\n        <p>\n            Element upgrades occur for existing custom elements in the document when <code>customElements.define()</code> is called,\n            and for all new custom elements with that tag name created afterwards (e.g. using <code>document.createElement('x-example')</code>).\n            It does not occur automatically for detached custom elements (not part of the document) that were created before the element was defined.\n            Those can be upgraded retroactively by calling <code>customElements.upgrade()</code>.\n        </p>\n\n        <p>\n            So far, this is the part of the lifecycle we've seen:\n        </p>\n        <pre>\n&lt;undefined&gt; \n    -> define() -> &lt;defined&gt;\n    -> automatic upgrade() \n                -> constructor() \n                -> &lt;constructed&gt;\n        </pre>\n\n        <p>\n            The constructor as shown in the example above is optional, but if it is specified then it has a <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance\">number of gotcha's</a>:\n        </p>\n        <dl>\n            <dt>It must start with a call to <code>super()</code>.</dt>\n            <dt>It should not make DOM changes yet, as the element is not yet guaranteed to be connected to the DOM.</dt>\n            <dd>\n                This includes reading or modifying its own DOM properties, like its attributes.\n                The tricky part is that in the constructor the element might already be in the DOM,\n                so setting attributes might work. Or it might give an error. It's best to avoid DOM interaction altogether in the constructor.\n            </dd>\n            <dt>It should initialize its state, like class properties</dt>\n            <dd>\n                But work done in the constructor should be minimized and maximally postponed until <code>connectedCallback</code>.\n            </dd>\n        </dl>\n\n        <h3>Making connections</h3>\n\n        <p>\n            After being constructed, if the element was already in the document, its <code>connectedCallback()</code> handler is called.\n            This handler is normally called only when the element is inserted into the document, but for elements that are already in the document when they are defined it ends up being called as well.\n            In this handler DOM changes can be made, and in the example above the <code>status</code> attribute is set to demonstrate this.\n        </p>\n        <p>\n            The <em>connectedCallback()</em> handler is part of what is known in the HTML standard as <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions\">custom element reactions</a>:\n            These reactions allow the element to respond to various changes to the DOM:\n        </p>\n        <ul>\n            <li><code>connectedCallback()</code> is called when the element is inserted into the document, even if it was only moved from a different place in the same document.</li>\n            <li><code>disconnectedCallback()</code> is called when the element is removed from the document.</li>\n            <li><code>adoptedCallback()</code> is called when the element is moved to a new document. (You are unlikely to need this in practice.)</li>\n            <li><code>attributeChangedCallback()</code> is called when an attribute is changed, but only for the attributes listed in its <code>observedAttributes</code> property.</li>\n        </ul>\n        <p>\n            There are also special reactions for <a href=\"https://dev.to/stuffbreaker/custom-forms-with-web-components-and-elementinternals-4jaj\">form-associated custom elements</a>, \n            but those are a rabbit hole beyond the purview of this blog post.\n        </p>\n        <p>\n            There are more gotcha's to these reactions:\n        </p>\n        <dl>\n            <dt><code>connectedCallback()</code> and <code>disconnectedCallback()</code> can be called multiple times</dt>\n            <dd>\n                This can occur when the element is moved around in the document.\n                These handlers should be written in such a way that it is harmless to run them multiple times,\n                e.g. by doing an early exit when it is detected that <em>connectedCallback()</em> was already run.\n            </dd>\n            <dt><code>attributeChangedCallback()</code> can be called before <code>connectedCallback()</code></dt>\n            <dd>\n                For all attributes already set when the element in the document is upgraded,\n                the <em>attributeChangedCallback()</em> handler will be called first,\n                and only after this <em>connectedCallback()</em> is called.\n                The unpleasant consequence is that any <em>attributeChangedCallback</em> that tries to update DOM structures\n                created in <em>connectedCallback</em> can produce errors.\n            </dd>\n            <dt><code>attributeChangedCallback()</code> is only called for attribute changes, not property changes.</dt>\n            <dd>\n                Attribute changes can be done in Javascript by calling <code>element.setAttribute('name', 'value')</code>.\n                DOM attributes and class properties can have the same name, but are not automatically linked.\n                Generally for this reason it is better to avoid having attributes and properties with the same name.\n            </dd>\n        </dl>\n\n        <p>\n            The lifecycle covered up to this point for elements that start out in the initial document:\n        </p>\n        <pre>\n&lt;undefined&gt; \n    -> define() -> &lt;defined&gt;\n    -> automatic upgrade() \n                -> [element].constructor()\n                -> [element].attributeChangedCallback()\n                -> [element].connectedCallback() \n                -> &lt;connected&gt;\n        </pre>\n\n        <h3>Flip the script</h3>\n\n        <p>\n            So far we've covered one half of the Document-JavaScript duality, for custom elements starting out in the document,\n            and only after that becoming defined and gaining a JavaScript counterpart.\n            It is however also possible to reverse the flow, and start out from JavaScript.\n        </p>\n        <p>\n            This is the minimal code to create a custom element in JavaScript: <code>document.createElement('x-example')</code>.\n            The element does not need to be defined in order to run this code, although it can be, and the resulting node can be inserted into the document\n            as if it was part of the original HTML markup.\n        </p>\n        <p>\n            If it is inserted, and after insertion the element becomes defined, then it will behave as described above.\n            Things are however different if the element remains detached:\n        </p>\n        <dl>\n            <dt>The detached element will not be automatically upgraded when it is defined.</dt>\n            <dd>\n                The constructor or reactions will not be called. It will be automatically upgraded when it is inserted into the document.\n                It can also be upgraded explicitly by calling <code>customElements.upgrade()</code>.\n            </dd>\n            <dt>If the detached element is already defined when it is created, it will be upgraded automatically.</dt>\n            <dd>The <em>constructor()</em> and <em>attributeChangedCallback()</em> will be called. Because it is not yet part of the document <em>connectedCallback()</em> won't be.</dd>\n        </dl>\n        <p>\n            By now no doubt you are a bit confused. Here's an interactive playground that lets you test\n            what happens to elements as they go through their lifecycle, both for those in the initial document and those created dynamically.\n        </p>\n        <iframe src=\"defined2/example.html\" name=\"custom element lifecycle\" height=\"600\"></iframe>\n\n        <p>Here are some interesting things to try out:</p>\n        <ul>\n            <li><em>Create</em>, then <em>Define</em>, and you will see that the created element is not upgraded automatically because it is detached from the document.</li>\n            <li><em>Create</em>, then <em>Connect</em>, then <em>Define</em>, and you will see that the element is upgraded automatically because it is in the document.</li>\n            <li><em>Define</em>, then <em>Create</em>, and you will see that the element is upgraded as soon as it is created (<em>constructed</em> appears in the reactions).</li>\n        </ul>\n        <p>\n            I tried writing a flowchart of all possible paths through the lifecycle that can be seen in this example,\n            but it got so unwieldy that I think it's better to just play around with the example until a solid grasp develops.\n        </p>\n\n        <h3>In the shadows</h3>\n\n        <p>\n            Adding shadow DOM creates yet another wrinkle in the lifecycle.\n            At any point in the element's JavaScript half, including in its constructor, a shadow DOM can be attached to the element by calling <code>attachShadow()</code>.\n            Because the shadow DOM is immediately available for DOM operations, that makes it possible to do those DOM operations in the constructor.\n        </p>\n        <p>\n            In this next interactive example you can see what happens when the shadow DOM becomes attached.\n            The <em>x-shadowed</em> element will immediately attach a shadow DOM in its constructor,\n            which happens when the element is upgraded automatically after defining.\n            The <em>x-shadowed-later</em> element postpones adding a shadow DOM until a link is clicked,\n            so the element first starts out as a non-shadowed custom element, and adds a shadow DOM later.\n        </p>\n\n        <iframe src=\"shadowed/example.html\" name=\"shadowed custom elements\"></iframe>\n        <x-code-viewer src=\"shadowed/example.html\" name=\"example.html\"></x-code-viewer>\n\n        <p>\n            While adding a shadow DOM can be done at any point, it is a one-way operation.\n            Once added the shadow DOM will replace the element's original contents, and this cannot be undone.\n        </p>\n\n        <h3>Keeping an eye out</h3>\n\n        <p>\n            So far we've mostly been dealing with initial setup of the custom element,\n            but a major part of the lifecycle is responding to changes as they occur.\n            Here are some of the major ways that custom elements can respond to DOM changes:\n        </p>\n        <ul>\n            <li><em>connectedCallback</em> and <em>disconnectedCallback</em> to handle DOM insert and remove of the element itself.</li>\n            <li><em>attributeChangedCallback</em> to handle attribute changes of the element.</li>\n            <li>For shadowed custom elements, the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/slotchange_event\">slotchange</a> event can be used to detect when children are added and removed in a <code>&lt;slot&gt;</code>.</li>\n            <li>Saving the best for last, <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver\">MutationObserver</a> can be used to monitor DOM subtree changes, as well as attribute changes.</li>\n        </ul>\n        <p>\n            <em>MutationObserver</em> in particular is worth exploring, because it is a swiss army knife for monitoring the DOM.\n            Here's an example of a counter that automatically updates when new child elements are added:\n        </p>\n        <iframe src=\"observer/example.html\" name=\"custom element with observer\"></iframe>\n        <x-code-viewer src=\"observer/example.html\" name=\"example.html\"></x-code-viewer>\n\n        <p>\n            There is still more to tell, but already I can feel eyes glazing over and brains turning to mush,\n            so I will keep the rest for another day.\n        </p>\n\n        <hr />\n\n        <p>\n            Phew, that was a much longer story than I originally set out to write, but custom elements have surprising intricacy.\n            I hope you found it useful, and if not at least you got to see some code and click some buttons.\n            It's all about the clicking of the buttons.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113147980761074467\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/observer/example.html",
    "content": "<!doctype html>\n<html> \n    <head>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n        <title>custom element with observer</title>\n        <style>\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-wall { display: block; margin-bottom: 1em; }\n        </style>\n    </head>\n    <body>\n        <x-wall><x-bottle></x-bottle></x-wall>\n        <button onclick=\"add()\">Add one more</button>\n        <button onclick=\"location.reload()\">Reload</button>\n\n        <script>\n        customElements.define('x-wall', class extends HTMLElement {\n            connectedCallback() {\n                if (this.line) return; // prevent double initialization\n                this.line = document.createElement('p');\n                this.insertBefore(this.line, this.firstChild);\n                new MutationObserver(() => this.update()).observe(this, { childList: true });\n                this.update();\n            }\n            update() {\n                const count = this.querySelectorAll('x-bottle').length;\n                this.line.textContent = \n                    `${count} ${count === 1 ? 'bottle' : 'bottles'} of beer on the wall`;\n            }\n        });\n        customElements.define('x-bottle', class extends HTMLElement {\n            connectedCallback() { this.textContent = '🍺'; }\n        });\n        function add() {\n            document.querySelector('x-wall').append(\n                document.createElement('x-bottle'));\n        }\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/shadowed/example.html",
    "content": "<!doctype html>\n<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n        <title>shadowed custom element</title>\n        <style>\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-shadowed, x-shadowed-later { background-color: lightgray; }\n        </style>\n    </head>\n    <body>\n        <p>&lt;x-shadowed&gt;: <x-shadowed>undefined, not shadowed</x-shadowed></p>\n        <p>&lt;x-shadowed-later&gt;: <x-shadowed-later>undefined, not shadowed</x-shadowed-later></p>\n        <button id=\"define\" onclick=\"define()\">Define</button>\n        <button onclick=\"location.reload()\">Reload</button>\n\n        <script>\n        function define() {\n            customElements.define('x-shadowed', class extends HTMLElement {\n                constructor() {\n                    super();\n                    this.attachShadow({mode: 'open'});\n                    this.shadowRoot.innerHTML = `\n                        <span style=\"background-color: lightgreen\">\n                            shadowed\n                        </span>\n                    `;\n                }\n            });\n            customElements.define('x-shadowed-later', class extends HTMLElement {\n                connectedCallback() {\n                    this.innerHTML = 'constructed, <a href=\"#\">click to shadow</a>';\n                    this.querySelector('a').onclick = (e) => { e.preventDefault(); this.addShadow() };\n                }\n                addShadow() {\n                    this.attachShadow({mode: 'open'});\n                    this.shadowRoot.innerHTML = `\n                        <span style=\"background-color: lightgreen\">\n                            shadowed\n                        </span>\n                    `;\n                }\n            });\n            document.querySelector('button#define').setAttribute('disabled', true);\n        }\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/undefined/example.css",
    "content": "body { font-family: system-ui, sans-serif; margin: 1em; }\nbutton { user-select: none; }\n/* based on https://github.com/argyleink/gui-challenges/blob/main/tooltips/tool-tip.css */\nx-tooltip {\n    --color: lightgray;\n    --bg: hsl(0 0% 20%);\n\n    pointer-events: none;\n    user-select: none;\n    /* animate in on hover or focus of parent element */\n    z-index: 1;\n    opacity: 0;\n    transition: opacity .2s ease;\n    transition-delay: 200ms;\n    :is(:hover, :focus-visible, :active) > & {\n        opacity: 1;\n    }\n    /* vertically center and move to the right */\n    position:absolute;\n    top:50%;\n    transform:translateY(-50%);\n    left: calc(100% + 15px);\n    padding: 0.5em;\n    inline-size: max-content;\n    max-inline-size: 25ch;\n    /* color, backdrop and shadow */\n    color: var(--color);\n    filter: \n        drop-shadow(0 3px 3px hsl(0 0% 0% / 50%)) \n        drop-shadow(0 12px 12px hsl(0 0% 0% / 50%));\n    &::after {\n        content: \"\";\n        background: var(--bg);\n        position: absolute;\n        z-index: -1;\n        left: 0;\n        top: 50%;\n        transform:translateY(-50%);\n        width: 100%;\n        height: 100%;\n        border-radius: 5px;\n    }\n    /* fix drop shadow in safari */\n    will-change: filter;\n}\n\nbutton:has(> x-tooltip) {\n    position: relative;\n}"
  },
  {
    "path": "public/blog/articles/2024-09-16-life-and-times-of-a-custom-element/undefined/example.html",
    "content": "<!doctype html>\n<html>\n    <head>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n        <link rel=\"stylesheet\" href=\"example.css\">\n        <title>undefined custom element</title>\n    </head>\n    <body>\n        <button>\n            Hover me\n            <x-tooltip inert role=\"tooltip\">Thanks for hovering!</x-tooltip>\n        </button>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/AddTask.js",
    "content": "customElements.define('task-add', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            <input type=\"text\" placeholder=\"Add task\" />\n            <button>Add</button>\n        `;\n        this.querySelector('button').onclick = () => {\n            const input = this.querySelector('input');\n            this.closest('tasks-context').dispatch({\n                type: 'added',\n                id: nextId++,\n                text: input.value\n            });\n            input.value = '';\n        };\n    }\n})\n\nlet nextId = 3;\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/App.js",
    "content": "customElements.define('tasks-app', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            <tasks-context>\n                <h1>Day off in Kyoto</h1>\n                <task-add></task-add>\n                <task-list></task-list>\n            </tasks-context>\n        `;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/TaskList.js",
    "content": "customElements.define('task-list', class extends HTMLElement {\n    get context() { return this.closest('tasks-context'); }\n    \n    connectedCallback() {\n        this.context.addEventListener('change', () => this.update());\n        this.append(document.createElement('ul'));\n        this.update();\n    }\n\n    update() {\n        const ul = this.querySelector('ul');\n        let before = ul.firstChild;\n        this.context.tasks.forEach(task => {\n            let li = ul.querySelector(`:scope > [data-key=\"${task.id}\"]`);\n            if (!li) {\n                li = document.createElement('li');\n                li.dataset.key = task.id;\n                li.append(document.createElement('task-item'));\n            }\n            li.firstChild.task = task;\n            // move to the right position in the list if not there yet\n            if (li !== before) ul.insertBefore(li, before);\n            before = li.nextSibling;\n        });\n        // remove unknown nodes\n        while (before) {\n            const remove = before;\n            before = before.nextSibling;\n            ul.removeChild(remove);\n        }\n    }\n});\n\ncustomElements.define('task-item', class extends HTMLElement {\n    #isEditing = false;\n    #task;\n    set task(task) { this.#task = task; this.update(); }\n    get context() { return this.closest('tasks-context'); }\n\n    connectedCallback() {\n        if (this.querySelector('label')) return;\n        this.innerHTML = `\n            <label>\n                <input type=\"checkbox\" />\n                <input type=\"text\" />\n                <span></span>\n                <button id=\"edit\">Edit</button>\n                <button id=\"save\">Save</button>\n                <button id=\"delete\">Delete</button>\n            </label>\n        `;\n        this.querySelector('input[type=checkbox]').onchange = e => {\n            this.context.dispatch({\n                type: 'changed',\n                task: {\n                    ...this.#task,\n                    done: e.target.checked\n                }\n            });\n        };\n        this.querySelector('input[type=text]').onchange = e => {\n            this.context.dispatch({\n                type: 'changed',\n                task: {\n                    ...this.#task,\n                    text: e.target.value\n                }\n            });\n        };\n        this.querySelector('button#edit').onclick = () => {\n            this.#isEditing = true;\n            this.update();\n        };\n        this.querySelector('button#save').onclick = () => {\n            this.#isEditing = false;\n            this.update();\n        };\n        this.querySelector('button#delete').onclick = () => {\n            this.context.dispatch({\n                type: 'deleted',\n                id: this.#task.id\n            });\n        };\n        this.context.addEventListener('change', () => this.update());\n        this.update();\n    }\n\n    update() {\n        if (this.isConnected && this.#task) {\n            this.querySelector('input[type=checkbox]').checked = this.#task.done;\n            const inputEdit = this.querySelector('input[type=text]');\n            inputEdit.style.display = this.#isEditing ? 'inline' : 'none';\n            inputEdit.value = this.#task.text;\n            const span = this.querySelector('span');\n            span.style.display = this.#isEditing ? 'none' : 'inline';\n            span.textContent = this.#task.text;\n            this.querySelector('button#edit').style.display = this.#isEditing ? 'none' : 'inline';\n            this.querySelector('button#save').style.display = this.#isEditing ? 'inline' : 'none';\n        }\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/TasksContext.js",
    "content": "customElements.define('tasks-context', class extends HTMLElement {\n    #tasks = structuredClone(initialTasks);\n    get tasks() { return this.#tasks; }\n    set tasks(tasks) {\n        this.#tasks = tasks;\n        this.dispatchEvent(new Event('change'));\n    }\n\n    dispatch(action) {\n        this.tasks = tasksReducer(this.tasks, action);\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n});\n\nfunction tasksReducer(tasks, action) {\n    switch (action.type) {\n        case 'added': {\n            return [...tasks, {\n                id: action.id,\n                text: action.text,\n                done: false\n            }];\n        }\n        case 'changed': {\n            return tasks.map(t => {\n                if (t.id === action.task.id) {\n                    return action.task;\n                } else {\n                    return t;\n                }\n            });\n        }\n        case 'deleted': {\n            return tasks.filter(t => t.id !== action.id);\n        }\n        default: {\n            throw Error('Unknown action: ' + action.type);\n        }\n    }\n}\n\nconst initialTasks = [\n    { id: 0, text: 'Philosopher’s Path', done: true },\n    { id: 1, text: 'Visit the temple', done: false },\n    { id: 2, text: 'Drink matcha', done: false }\n];\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Document</title>\n    <link rel=\"stylesheet\" href=\"styles.css\">\n</head>\n<body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/index.js",
    "content": "import './App.js';\nimport './AddTask.js';\nimport './TaskList.js';\nimport './TasksContext.js';\n\nconst render = () => {\n    const root = document.getElementById('root');\n    root.append(document.createElement('tasks-app'));\n}\n\ndocument.addEventListener('DOMContentLoaded', render);\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/styles.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: sans-serif;\n  margin: 20px;\n  padding: 0;\n}\n\nh1 {\n  margin-top: 0;\n  font-size: 22px;\n}\n\nh2 {\n  margin-top: 0;\n  font-size: 20px;\n}\n\nh3 {\n  margin-top: 0;\n  font-size: 18px;\n}\n\nh4 {\n  margin-top: 0;\n  font-size: 16px;\n}\n\nh5 {\n  margin-top: 0;\n  font-size: 14px;\n}\n\nh6 {\n  margin-top: 0;\n  font-size: 12px;\n}\n\ncode {\n  font-size: 1.2em;\n}\n\nul {\n  padding-inline-start: 20px;\n}\n\nbutton { margin: 5px; }\nli { list-style-type: none; }\nul, li { margin: 0; padding: 0; }\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>The unreasonable effectiveness of vanilla JS</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"A case study in porting intricate React code to vanilla.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-09-28\">\n        <img src=\"image.webp\" alt=\"A female comic book hero bearing a vanilla sigil on her chest\" loading=\"lazy\" />\n        <h2>The unreasonable effectiveness of vanilla JS</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            I have a confession to make. At the end of the Plain Vanilla tutorial's <a href=\"../../../pages/applications.html\">Applications page</a>\n            a challenge was posed to the reader: port <a href=\"https://react.dev\">react.dev</a>'s final example \n            <a href=\"https://react.dev/learn/scaling-up-with-reducer-and-context\">Scaling Up with Reducer and Context</a> to vanilla web code.\n            Here's the confession: until today I had never actually ported over that example myself.\n        </p>\n        <p>\n            That example demonstrates a cornucopia of React's featureset.\n            Richly interactive UI showing a tasks application, making use of a context to lift the task state up,\n            and a reducer that the UI's controls dispatch to. React's DOM-diffing algorithm gets a real workout \n            because each task in the list can be edited independently from and concurrently with the other tasks. \n            It is an intricate and impressive demonstration. Here it is in its interactive glory:\n        </p>\n        <iframe src=\"./complete/index.html\" title=\"complete example\" height=\"250\"></iframe>\n        <p>\n            But I lied. That interactive example is actually the vanilla version and it is identical.\n            If you want to verify that it is in fact identical, check out the <a href=\"https://codesandbox.io/p/sandbox/react-dev-wy7lfd\">original React example</a>.\n            And with that out of the way, let's break apart the vanilla code.\n        </p>\n\n        <h3>Project setup</h3>\n\n        <p>The React version has these code files that we will need to port:</p>\n        <ul>\n            <li><strong>public/index.html</strong></li>\n            <li><strong>src/styles.css</strong></li>\n            <li><strong>src/index.js</strong>: imports the styles, bootstraps React and renders the App component</li>\n            <li><strong>src/App.js</strong>: renders the context's TasksProvider containing the AddTask and TaskList components</li>\n            <li><strong>src/AddTask.js</strong>: renders the simple form at the top to add a new task</li>\n            <li><strong>src/TaskList.js</strong>: renders the list of tasks</li>\n        </ul>\n        <p>\n            To make things fun, I chose the same set of files with the same filenames for the vanilla version.\n            Here's <strong>index.html</strong>:\n        </p>\n        <x-code-viewer src=\"./complete/index.html\" name=\"index.html\"></x-code-viewer>\n        <p>\n            The only real difference is that it links to <strong>index.js</strong> and <strong>styles.css</strong>.\n            The stylesheet was copied verbatim, but for the curious here's a link to <a href=\"./complete/styles.css\">styles.css</a>.\n        </p>\n        \n        <h3>Get to the code</h3>\n\n        <p>\n            <strong>index.js</strong> is where it starts to get interesting.\n            Compare the React version to the vanilla version:\n        </p>\n        <x-code-viewer src=\"./react/src/index.js\" name=\"index.js (React)\"></x-code-viewer>\n        <x-code-viewer src=\"./complete/index.js\" name=\"index.js (Vanilla)\"></x-code-viewer>\n        <p>\n            Bootstrapping is different but also similar. All of the web components are imported first to load them,\n            and then the <code>&lt;tasks-app&gt;</code> component is rendered to the page.\n        </p>\n        <p>\n            The <strong>App.js</strong> code also bears more than a striking resemblance:\n        </p>\n        <x-code-viewer src=\"./react/src/App.js\" name=\"App.js (React)\"></x-code-viewer>\n        <x-code-viewer src=\"./complete/App.js\" name=\"App.js (Vanilla)\"></x-code-viewer>\n\n        <p>\n            What I like about the code so far is that it <em>feels</em> React-like. I generally find programming against React's API pleasing,\n            but I don't like the tooling, page weight and overall complexity baggage that it comes with.\n        </p>\n\n        <h3>Adding context</h3>\n\n        <p>\n            The broad outline of how to bring a React-like context to a vanilla web application is\n            already explained in the <a href=\"https://plainvanillaweb.com/pages/applications.html#managing-state\">passing data deeply section</a> \n            of the main Plain Vanilla tutorial, so I won't cover that again here.\n            What adds spice in this specific case is that the React context uses a reducer,\n            a function that accepts the old tasks and an action to apply to them, and returns the new tasks to show throughout the application.\n        </p>\n        <p>\n            Thankfully, the React example's reducer function and initial state were already vanilla JS code,\n            so those come along for the ride unchanged and ultimately the vanilla context is a very straightforward custom element:\n        </p>\n\n        <x-code-viewer src=\"./complete/TasksContext.js\" name=\"TasksContext.js (Vanilla)\"></x-code-viewer>\n\n        <p>\n            The actual context component is very bare bones, as it only needs to store the tasks,\n            emit change events for the other components to subscribe to, and provide a dispatch method \n            for those components to call that will use the reducer function to update the tasks.\n        </p>\n\n        <h3>Adding tasks</h3>\n\n        <p>\n            The AddTask component ends up offering more of a challenge. It's a stateful component with event listeners that dispatches to the reducer:\n        </p>\n        <x-code-viewer src=\"./react/src/AddTask.js\" name=\"AddTask.js (React)\"></x-code-viewer>\n        <p>\n            The main wrinkle this adds for the vanilla web component is that the event listener on the button element\n            cannot be put inline with the markup. Luckily the handling of the input is much simplified\n            because we can rely on it keeping its state automatically, a convenience owed to not using a virtual DOM.\n            Thanks to the groundwork in the context component the actual dispatching of the action is easy:\n        </p>\n        <x-code-viewer src=\"./complete/AddTask.js\" name=\"AddTask.js (Vanilla)\"></x-code-viewer>\n        <p>\n            Fascinating to me is that <strong>index.js</strong>, <strong>App.js</strong>, <strong>TasksContext.js</strong> and <strong>AddTask.js</strong>\n            are all fewer lines of code in the vanilla version than their React counterpart while remaining functionally equivalent. \n        </p>\n\n        <h3>Hard mode</h3>\n        <p>\n            The TaskList component is where React starts really pulling its weight.\n            The React version is clean and straightforward and juggles a lot of state with a constantly updating task list UI.\n        </p>\n        <x-code-viewer src=\"./react/src/TaskList.js\" name=\"TaskList.js (React)\"></x-code-viewer>\n\n        <p>\n            This proved to be a real challenge to port. The vanilla version ended up being a lot more verbose\n            because it has to do all the same DOM-reconciliation in explicit logic managed by the <strong>update()</strong> methods\n            of <code>&lt;task-list&gt;</code> and <code>&lt;task-item&gt;</code>.\n        </p>\n        <x-code-viewer src=\"./complete/TaskList.js\" name=\"TaskList.js (Vanilla)\"></x-code-viewer>\n        <p>\n            Some interesting take-aways:\n        </p>\n        <ul>\n            <li>\n                The <code>&lt;task-list&gt;</code> component's <strong>update()</strong> method implements a poor man's version of React reconciliation,\n                merging the current state of the <strong>tasks</strong> array into the child nodes of the <code>&lt;ul&gt;</code>.\n                In order to do this, it has to store a key on each list item, just like React requires, and here it becomes obvious why that is.\n                Without the key we can't find the existing <code>&lt;li&gt;</code> nodes that match up to task items,\n                and so would have to recreate the entire list. By adding the key it becomes possible to update the list in-place,\n                modifying task items instead of recreating them so that they can keep their on-going edit state.\n            </li>\n            <li>\n                That reconciliation code is very generic however, and it is easy to imagine a fully generic <strong>repeat()</strong>\n                function that converts an array of data to markup on the page. In fact, the Lit framework <a href=\"https://lit.dev/docs/templates/lists/#the-repeat-directive\">contains exactly that</a>.\n                For brevity's sake this code doesn't go quite that far.\n            </li>\n            <li>\n                The <code>&lt;task-item&gt;</code> component cannot do what the React code does: create different markup depending on the current state.\n                Instead it creates the union of the markup across the various states, and then in the <strong>update()</strong>\n                shows the right subset of elements based on the current state.\n            </li>\n        </ul>\n        <p>\n            That wraps up the entire code. You can find the <a href=\"https://github.com/jsebrech/vanilla-context-and-reducer\">ported example on Github</a>.\n        </p>\n\n        <h3>Some thoughts</h3>\n        \n        <p>\n            A peculiar result of this porting challenge is that the vanilla version ends up being roughly \n            the same number of lines of code as the React version. The React code is still overall less verbose (all those querySelectors, oy!),\n            but it has its own share of boilerplate that disappears in the vanilla version.\n            This isn't a diss against React, it's more of a compliment to how capable browsers have gotten that vanilla web components\n            can carry us so far.\n        </p>\n        <p>\n            If I could have waved a magic wand, what would have made the vanilla version simpler?\n        </p>\n        <ul>\n            <li>\n                All of those <strong>querySelector</strong> calls get annoying. The alternatives are building the markup easily with innerHTML\n                and then fishing out references to the created elements using querySelector, or building the elements one by one verbosely using createElement,\n                but then easily having a reference to them. Either of those ends up very verbose. \n                An alternative templating approach that makes it easy to create elements <em>and</em> get a reference to them would be very welcome.\n            </li>\n            <li>\n                As long as we're dreaming, I'm jealous of how easy it is to add the event listeners in JSX.\n                A real expression language in HTML templates that supports data and event binding and data-conditional markup would be very neat\n                and would take away most of the reason to still find a framework's templating language more convenient.\n                Web components are a perfectly fine alternative to React components, they just lack an easy built-in templating mechanism.\n            </li>\n            <li>\n                Browsers could get a little smarter about how they handle DOM updates during event handling.\n                In the logic that sorts the <code>&lt;li&gt;</code> to the right order in the list, \n                the <em>if</em> condition before insertBefore proved necessary because the browser\n                didn't notice that the element was already placed where it needed to be inserted,\n                and click events would get lost as a consequence.\n                I've even noticed that assigning a textContent to a button mid-click will make Safari\n                lose track of that button's click event. All of that can be worked around with clever reconciliation logic,\n                but that's code that belongs in the browser, not in JavaScript.\n            </li>\n        </ul>\n        <p>\n            All in all though, I'm really impressed with vanilla JS. I call it unreasonably effective because it is\n            jarring just how capable the built-in abilities of browsers are, and just how many web developers despite that \n            still default to web frameworks for every new project. Maybe one day...\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113215359038426580\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/package.json",
    "content": "{\n  \"name\": \"react.dev\",\n  \"version\": \"0.0.0\",\n  \"main\": \"/src/index.js\",\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"dependencies\": {\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\",\n    \"react-scripts\": \"^5.0.0\"\n  },\n  \"devDependencies\": {}\n}"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Document</title>\n</head>\n<body>\n  <div id=\"root\"></div>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/src/AddTask.js",
    "content": "import { useState } from 'react';\nimport { useTasksDispatch } from './TasksContext.js';\n\nexport default function AddTask() {\n  const [text, setText] = useState('');\n  const dispatch = useTasksDispatch();\n  return (\n    <>\n      <input\n        placeholder=\"Add task\"\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n      <button onClick={() => {\n        setText('');\n        dispatch({\n          type: 'added',\n          id: nextId++,\n          text: text,\n        }); \n      }}>Add</button>\n    </>\n  );\n}\n\nlet nextId = 3;\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/src/App.js",
    "content": "import AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport { TasksProvider } from './TasksContext.js';\n\nexport default function TaskApp() {\n  return (\n    <TasksProvider>\n      <h1>Day off in Kyoto</h1>\n      <AddTask />\n      <TaskList />\n    </TasksProvider>\n  );\n}\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/src/TaskList.js",
    "content": "import { useState } from 'react';\nimport { useTasks, useTasksDispatch } from './TasksContext.js';\n\nexport default function TaskList() {\n  const tasks = useTasks();\n  return (\n    <ul>\n      {tasks.map(task => (\n        <li key={task.id}>\n          <Task task={task} />\n        </li>\n      ))}\n    </ul>\n  );\n}\n\nfunction Task({ task }) {\n  const [isEditing, setIsEditing] = useState(false);\n  const dispatch = useTasksDispatch();\n  let taskContent;\n  if (isEditing) {\n    taskContent = (\n      <>\n        <input\n          value={task.text}\n          onChange={e => {\n            dispatch({\n              type: 'changed',\n              task: {\n                ...task,\n                text: e.target.value\n              }\n            });\n          }} />\n        <button onClick={() => setIsEditing(false)}>\n          Save\n        </button>\n      </>\n    );\n  } else {\n    taskContent = (\n      <>\n        {task.text}\n        <button onClick={() => setIsEditing(true)}>\n          Edit\n        </button>\n      </>\n    );\n  }\n  return (\n    <label>\n      <input\n        type=\"checkbox\"\n        checked={task.done}\n        onChange={e => {\n          dispatch({\n            type: 'changed',\n            task: {\n              ...task,\n              done: e.target.checked\n            }\n          });\n        }}\n      />\n      {taskContent}\n      <button onClick={() => {\n        dispatch({\n          type: 'deleted',\n          id: task.id\n        });\n      }}>\n        Delete\n      </button>\n    </label>\n  );\n}\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/src/TasksContext.js",
    "content": "import { createContext, useContext, useReducer } from 'react';\n\nconst TasksContext = createContext(null);\n\nconst TasksDispatchContext = createContext(null);\n\nexport function TasksProvider({ children }) {\n  const [tasks, dispatch] = useReducer(\n    tasksReducer,\n    initialTasks\n  );\n\n  return (\n    <TasksContext.Provider value={tasks}>\n      <TasksDispatchContext.Provider value={dispatch}>\n        {children}\n      </TasksDispatchContext.Provider>\n    </TasksContext.Provider>\n  );\n}\n\nexport function useTasks() {\n  return useContext(TasksContext);\n}\n\nexport function useTasksDispatch() {\n  return useContext(TasksDispatchContext);\n}\n\nfunction tasksReducer(tasks, action) {\n  switch (action.type) {\n    case 'added': {\n      return [...tasks, {\n        id: action.id,\n        text: action.text,\n        done: false\n      }];\n    }\n    case 'changed': {\n      return tasks.map(t => {\n        if (t.id === action.task.id) {\n          return action.task;\n        } else {\n          return t;\n        }\n      });\n    }\n    case 'deleted': {\n      return tasks.filter(t => t.id !== action.id);\n    }\n    default: {\n      throw Error('Unknown action: ' + action.type);\n    }\n  }\n}\n\nconst initialTasks = [\n  { id: 0, text: 'Philosopher’s Path', done: true },\n  { id: 1, text: 'Visit the temple', done: false },\n  { id: 2, text: 'Drink matcha', done: false }\n];\n"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/src/index.js",
    "content": "import React, { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport \"./styles.css\";\n\nimport App from \"./App\";\n\nconst root = createRoot(document.getElementById(\"root\"));\nroot.render(\n  <StrictMode>\n    <App />\n  </StrictMode>\n);"
  },
  {
    "path": "public/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/react/src/styles.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: sans-serif;\n  margin: 20px;\n  padding: 0;\n}\n\nh1 {\n  margin-top: 0;\n  font-size: 22px;\n}\n\nh2 {\n  margin-top: 0;\n  font-size: 20px;\n}\n\nh3 {\n  margin-top: 0;\n  font-size: 18px;\n}\n\nh4 {\n  margin-top: 0;\n  font-size: 16px;\n}\n\nh5 {\n  margin-top: 0;\n  font-size: 14px;\n}\n\nh6 {\n  margin-top: 0;\n  font-size: 12px;\n}\n\ncode {\n  font-size: 1.2em;\n}\n\nul {\n  padding-inline-start: 20px;\n}\n\nbutton { margin: 5px; }\nli { list-style-type: none; }\nul, li { margin: 0; padding: 0; }\n"
  },
  {
    "path": "public/blog/articles/2024-09-30-lived-experience/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Lived experience</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"Thoughts on the past and future of frameworks, web components and web development.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-09-30\">\n        <img src=\"image.webp\" alt=\"An old man sitting astride a tall pile of books\" loading=\"lazy\" />\n        <h2>Lived experience</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            Ryan Carniato shared a hot take a few days ago, <a href=\"https://dev.to/ryansolid/web-components-are-not-the-future-48bh\">Web Components Are Not the Future</a>.\n            As hot takes tend to do, it got some responses, like Nolan Lawson's piece <a href=\"https://nolanlawson.com/2024/09/28/web-components-are-okay/\">Web components are okay</a>,\n            or Cory LaViska's <a href=\"https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/\">Web Components Are Not the Future &mdash; They're the Present</a>.\n            They do an excellent job of directly engaging Ryan's arguments, so I'm not going to do that here.\n            Instead I want to talk about my lived experience of web development, and where I hope it is headed in the future.\n            Take it in the spirit it is intended, one of optimism and possibility.\n        </p>\n\n        <h3>A galaxy far, far away</h3>\n        <p>\n            So I've been making web sites since a long time ago, since before CSS and HTML4.\n            I say this not to humblebrag, but to explain that I was here for all of it.\n            Every time when the definition of <em>modern web development</em> changed I would update my priors, following along.\n        </p>\n        <p>\n            For the longest time making web pages do anything except show text and images was an exercise in frustration.\n            Browsers were severely lacking in features, were wildly incompatible with web standards and each other,\n            and the tools that web developers needed to bring them to order were missing or lacking.\n            I built my share of vanilla JS components back in the IE6 days, and it made me dream of a better way.\n            When frameworks first started coming on the scene with that better way, adding missing features, abstracting away incompatibility,\n            and providing better tooling, I was ready for them. I was all-in.\n        </p>\n        <p>\n            I bought into ExtJS, loved it for a time, and then got a hundred thousand line codebase stuck on ExtJS 3 because version 4 changed things\n            so much that porting was too costly. I then bought into Backbone, loved that too, but had to move on when its principal developer did.\n            I joined a team that bought into AngularJS and got stuck painted into a corner when the Angular team went in a totally different direction for v2.\n            I helped rewrite a bunch of frontends in Angular v2 and React, \n            and found myself sucked into constant forced maintenance when their architecture and ecosystems churned.\n        </p>\n        <p>\n            Did I make bad choices? Even in hindsight I would say I picked the right choices for the time.\n            Time just moved on.\n        </p>\n\n        <h3>The cost of change</h3>\n        <p>\n            This lived experience taught me a strong awareness of rates of change in dependencies, and the costs they impose.\n            I imagine a web page as a thin old man sitting astride a tall pile of dependencies, each changing at their own pace.\n            Some dependencies are stable for decades, like HTML's core set of elements, or CSS 2's set of layout primitives. \n            They're so stable that we don't even consider them dependencies, they're just <em>the web</em>.\n        </p>\n        <p>\n            Other dependencies change every few years, like module systems, or new transpiled languages, \n            or the preferred build and bundling tool of the day, or what framework is in vogue.\n            Then there are the dependencies that change yearly, like major framework and OS releases.\n            Finally there are the dependencies that change constantly, like the many packages that contribute\n            to a typical web application built with a popular framework.\n        </p>\n        <p>\n            As a web developer who loves their user, taking on those dependencies creates a Solomon's choice.\n            Either you keep up with the churn, and spend a not insignificant amount of your day working and reworking code\n            that already works, instead of working on the things your user cares about. \n            Or, you stick it out for as long as you can on old versions, applying ever more workarounds to get \n            old framework releases and their outdated build and CLI tools to work in new OS and ecosystem environments,\n            slowly boiling a frog that will at some point force a deep rewrite, again at the expense of the user.\n        </p>\n        <p>\n            Which is not to say the frameworks don't add value. They absolutely do, and they keep getting better. \n            Writing new code on a new framework is a steadily rising tide of developer experience. \n            But let us not pretend these benefits don't come at a cost.\n            Wherever there is a codebase too complicated to understand and maintain yourself, wherever there is a set of build tools \n            that must be kept compatible with changes in operating systems and ecosystems,\n            there is a shelf life. Sooner or later the makers of every framework and of every tool will move on,\n            even if it's just to a new long-term supported release, and the web developers that they served will have to move with them.\n        </p>\n        <p>\n            I hold this truth to be self-evident: the larger the abstraction layer a web developer uses on top of web standards,\n            the shorter the shelf life of their codebase becomes, and the more they will feel the churn.\n        </p>\n\n        <h3>The rising tide</h3>\n        <p>\n            Why do modern web projects built with modern frameworks depend on so much <em>stuff</em>?\n            At first there was no other option. Interacting with the DOM was painful, \n            and web frameworks rightly made choices to keep component systems outside the DOM, minimizing and abstracting away those interactions\n            in increasingly clever DOM reconciliation strategies. Supporting the brittle browsers and slow devices of the day required many workarounds and polyfills,\n            and web frameworks rightly added intricate tools to build, bundle and minify the user's code.\n        </p>\n        <p>\n            They needed a way to bring dependencies into those build systems, and sanely settled on the convention of node modules\n            and the NPM ecosystem. It got easy to add more dependencies, and just as water always finds the easy way down,\n            dependencies found the easy way in. As the abstraction layer grew the load time cost imposed by it grew right along,\n            and so we got server-side rendering, client-side hydration, lazy loading, and many other load time reduction strategies.\n        </p>\n        <p>\n            DOM-diffing, synthetic event systems, functional components, JSX, reactive data layers, server-side rendering and streaming, bundlers, tree shaking, \n            transpilers and compilers, and all the other complications that you won't find in web standards but you will find in every major web framework &mdash;\n            they are the things invented to make the modern web possible, but they are not the web. The web is what ships to the browser.\n            And all of those things are downstream from the decision to abstract away the browser,\n            a decision once made in good faith and for good reasons. A decision which now needs revisiting.\n        </p>\n        <p>\n            Browsers were not standing still. They saw what web developers were doing in userland to compensate \n            for the deficiencies in browser API's, and they kept improving and growing the platform, a rising tide slowly catching up to what frameworks did.\n            When Microsoft bid IE <a href=\"https://blogs.windows.com/windowsexperience/2022/06/15/internet-explorer-11-has-retired-and-is-officially-out-of-support-what-you-need-to-know/\">a well-deserved farewell</a> on June 15, 2022 a tipping point was reached.\n            For the first time the browser platform was so capable that it felt to me like it didn't need so much abstracting away anymore.\n            It wasn't a great platform, not as cleanly designed or complete as the API's of the popular frameworks,\n            but it was <em>Good Enough&trade;</em> as a foundation, and that was all that mattered.\n        </p>\n\n        <h3>Holding my breath</h3>\n\n        <p>\n            I was very excited for what would happen in the framework ecosystem. There was a golden opportunity for frameworks \n            to tear down their abstraction layers, make something far simpler, far more closely aligned with the base web platform. \n            They could have a component system built on top of web components,\n            leveraging browser events and built-in DOM API's. All the frameworks could become cross-compatible, \n            easily plugging into each other's data layers and components while preserving what makes them unique.\n            The page weights would shrink by an order of magnitude with so much infrastructure code removed,\n            and that in combination with the move to HTTP/3 could make build tools optional.\n            It would do less, so inevitably be worse in some ways, but sometimes <a href=\"https://en.wikipedia.org/wiki/Worse_is_better\">worse is better</a>.\n        </p>\n        <p>\n            I gave a talk about how good the browser's platform had gotten, \n            showing off <a href=\"https://github.com/jsebrech/create-react-app-zero\">a version of Create React App</a> that didn't need any build tools\n            and was extremely light-weight, and the developer audience was just as excited as I was.\n            And I held my breath waiting on framework churn to for once go in the other direction, towards simplicity...\n        </p>\n        <p>\n            But nothing happened. In fact, the major frameworks kept building up their abstraction layers instead of building down.\n            We got React Server Components and React Compiler, exceedingly clever, utterly incomprehensible, \n            workarounds for self-imposed problems caused by overengineering.\n            Web developers don't seem to mind, but they struggle quietly with how to keep up with these tools and deliver good user experiences. \n            The bigger the abstraction layer gets, the more they feel the churn.\n        </p>\n        <p>\n            The irony is not lost on me that now the framework authors also feel the churn in their dependencies,\n            struggling to adapt to web components as foundational technology. React 19 is supposed to finally support web components\n            in a way that isn't incredibly painful, or so they say, we'll see. I confess to feeling some satisfaction\n            in their struggle. The shoe is on the other foot. Welcome to modern web development.\n        </p>\n        \n        <h3>The road ahead</h3>\n\n        <p>\n            What the frameworks are doing, that's fine for them, and they can keep doing it. \n            But I'm done with all that unless someone is paying me to do it.\n            They're on a fundamentally different path from where I want web development to go, from how I want to make web pages.\n            The web is what ships to the browser. Reducing the distance between what the developer writes and what ships to the browser\n            is valuable and necessary. This blog and this site are my own stake in the ground for this idea, \n            showing just how much you can get done without any framework code or build tools at all. \n            But let's be honest: web components are not a framework, no matter how hard I tried to explain them as one.\n        </p>\n\n        <blockquote>\n            <p>Comparing web components to React is like comparing a good bicycle with a cybertruck.</p>\n            <p>They do very different things, and they're used by different people with very, very different mindsets.</p>\n        </blockquote>\n        <cite><a href=\"https://adactio.com/notes/21455\">Jeremy Keith</a></cite>\n\n        <p>\n            I want a motorbike, not a cybertruck. I still want frameworks, only much lighter. \n            Frameworks less than 10 KB in size, that are a thin layer on top of web standards\n            but still solve the problems that frameworks solve. I call this idea the <em>interoperable web framework</em>:\n        </p>\n        <ul>\n            <li>Its components are just web components.</li>\n            <li>Its events are just DOM events.</li>\n            <li>Its templates are just HTML templates.</li>\n            <li>It doesn't need to own the DOM that its components take part in.</li>\n            <li>Its data and event binding works on all HTML elements, built-in or custom, made with the framework or with something else.</li>\n            <li>It can be easily mixed together on a page with other interoperable web frameworks, with older versions of itself, or with vanilla code.</li>\n            <li>It doesn't need its own build tools.</li>\n        </ul>\n        <p>\n            I just feel it on my bones such a thing can be built now. Maybe I'm wrong and Ryan Carniato is right.\n            After all, he knows a lot more about frameworks than I do. But the more vanilla code that I write the more certain that I feel on this.\n            Some existing solutions like Lit are close, but none are precisely what I am looking for. \n            I would love to see a community of vanilla developers come together to figure out what that could look like,\n            running experiments and iterating on the results. For now I will just keep holding my breath, waiting for the tide to come in.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113227558827641941\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/context-provider.js",
    "content": "export class ContextProvider extends EventTarget {\n    #value;\n    get value() { return this.#value }\n    set value(v) { this.#value = v; this.dispatchEvent(new Event('change')); }\n\n    #context;\n    get context() { return this.#context }\n\n    constructor(target, context, initialValue = undefined) {\n        super();\n        this.#context = context;\n        this.#value = initialValue;\n        this.handle = this.handle.bind(this);\n        if (target) this.attach(target);\n    }\n    \n    attach(target) {\n        target.addEventListener('context-request', this.handle);\n    }\n\n    detach(target) {\n        target.removeEventListener('context-request', this.handle);\n    }\n\n    /**\n     * Handle a context-request event\n     * @param {ContextRequestEvent} e \n     */\n    handle(e) {\n        if (e.context === this.context) {\n            if (e.subscribe) {\n                const unsubscribe = () => this.removeEventListener('change', update);\n                const update = () => e.callback(this.value, unsubscribe);\n                this.addEventListener('change', update);\n                update();\n            } else {\n                e.callback(this.value);\n            }\n            e.stopPropagation();\n        }\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/context-request.js",
    "content": "export class ContextRequestEvent extends Event {\n    constructor(context, callback, subscribe) {\n        super('context-request', {\n            bubbles: true,\n            composed: true,\n        });\n        this.context = context;\n        this.callback = callback;\n        this.subscribe = subscribe;\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/index.css",
    "content": "body {\n    margin: 1em;\n    font-family: system-ui, sans-serif;\n}\n\ntheme-panel {\n    display: block;\n    border: 1px dotted gray;\n    min-height: 2em;\n    max-width: 400px;\n    padding: 1em;\n    margin-bottom: 1em;\n}\n\n.panel-light {\n    color: #222;\n    background: #fff;\n}\n\n.panel-dark {\n    color: #fff;\n    background: rgb(23, 32, 42);\n}\n\ntheme-toggle button {\n    margin: 0;\n    padding: 5px;\n}\n\n.button-light,\n.button-dark {\n    border: 1px solid #777;\n}\n\n.button-dark {\n    background: #222;\n    color: #fff;\n}\n\n.button-light {\n    background: #fff;\n    color: #222;\n}"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title>tiny-context example</title>\n    <link rel=\"stylesheet\" href=\"index.css\">\n</head>\n<body>\n    <script type=\"module\" src=\"index.js\"></script>\n    <theme-demo></theme-demo>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/index.js",
    "content": "import { ContextRequestEvent } from \"./context-request.js\";\nimport \"./theme-provider.js\"; // global provider on body\nimport \"./theme-context.js\"; // element with local provider\n\ncustomElements.define('theme-demo', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            <theme-panel id=\"first\">\n                <theme-toggle></theme-toggle>\n            </theme-panel>\n            <theme-context>\n                <theme-panel id=\"second\">\n                </theme-panel>\n            </theme-context>\n            <button>Reparent toggle</button>\n        `;\n        this.querySelector('button').onclick = reparent;\n    }\n});\n\ncustomElements.define('theme-panel', class extends HTMLElement {\n    #unsubscribe;\n\n    connectedCallback() {\n        this.dispatchEvent(new ContextRequestEvent('theme', (theme, unsubscribe) => {\n            this.className = 'panel-' + theme;\n            this.#unsubscribe = unsubscribe;\n        }, true));\n    }\n\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n});\n\ncustomElements.define('theme-toggle', class extends HTMLElement {\n    #unsubscribe;\n\n    connectedCallback() {\n        this.innerHTML = '<button>Toggle</button>';\n        this.dispatchEvent(new ContextRequestEvent('theme-toggle', (toggle) => {\n            this.querySelector('button').onclick = toggle;\n        }));\n        this.dispatchEvent(new ContextRequestEvent('theme', (theme, unsubscribe) => {\n            this.querySelector('button').className = 'button-' + theme;\n            this.#unsubscribe = unsubscribe;\n        }, true));\n    }\n\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n});\n\nfunction reparent() {\n    const toggle = document.querySelector('theme-toggle');\n    const first = document.querySelector('theme-panel#first');\n    const second = document.querySelector('theme-panel#second');\n    if (toggle.parentNode === second) {\n        first.append(toggle);\n    } else {\n        second.append(toggle);\n    }\n}"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/theme-context.js",
    "content": "import { ContextProvider } from \"./context-provider.js\";\n\ncustomElements.define('theme-context', class extends HTMLElement {\n    themeProvider = new ContextProvider(this, 'theme', 'light');\n    toggleProvider = new ContextProvider(this, 'theme-toggle', () => {\n        this.themeProvider.value = this.themeProvider.value === 'light' ? 'dark' : 'light';\n    });\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/combined/theme-provider.js",
    "content": "// loaded with <script type=\"module\" src=\"theme-provider.js\"></script>\n\nimport { ContextProvider } from \"./context-provider.js\";\n\nconst themeProvider = new ContextProvider(document.body, 'theme', 'light');\nconst toggleProvider = new ContextProvider(document.body, 'theme-toggle', () => {\n    themeProvider.value = themeProvider.value === 'light' ? 'dark' : 'light';\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/context-provider.js",
    "content": "export class ContextProvider extends EventTarget {\n    #value;\n    get value() { return this.#value }\n    set value(v) { this.#value = v; this.dispatchEvent(new Event('change')); }\n\n    #context;\n    get context() { return this.#context }\n\n    constructor(target, context, initialValue = undefined) {\n        super();\n        this.#context = context;\n        this.#value = initialValue;\n        this.handle = this.handle.bind(this);\n        if (target) this.attach(target);\n    }\n    \n    attach(target) {\n        target.addEventListener('context-request', this.handle);\n    }\n\n    detach(target) {\n        target.removeEventListener('context-request', this.handle);\n    }\n\n    /**\n     * Handle a context-request event\n     * @param {ContextRequestEvent} e \n     */\n    handle(e) {\n        if (e.context === this.context) {\n            if (e.subscribe) {\n                const unsubscribe = () => this.removeEventListener('change', update);\n                const update = () => e.callback(this.value, unsubscribe);\n                this.addEventListener('change', update);\n                update();\n            } else {\n                e.callback(this.value);\n            }\n            e.stopPropagation();\n        }\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/context-request-1.js",
    "content": "class ContextRequestEvent extends Event {\n    constructor(context, callback, subscribe) {\n        super('context-request', {\n            bubbles: true,\n            composed: true,\n        });\n        this.context = context;\n        this.callback = callback;\n        this.subscribe = subscribe;\n    }\n}\n\ncustomElements.define('my-component', class extends HTMLElement {\n    connectedCallback() {\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', (theme) => {\n                // ...\n            })\n        );\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/context-request-2.js",
    "content": "customElements.define('my-component', class extends HTMLElement {\n    connectedCallback() {\n        let theme = 'light'; // default value\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', t => theme = t)\n        );\n        // do something with theme\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/context-request-3.js",
    "content": "customElements.define('my-component', class extends HTMLElement {\n    #unsubscribe;\n    connectedCallback() {\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', (theme, unsubscribe) => {\n                this.#unsubscribe = unsubscribe;\n                // do something with theme\n            }, true)\n        );\n    }\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/context-request-4.js",
    "content": "customElements.define('my-component', class extends HTMLElement {\n    connectedCallback() {\n        let theme = 'light';\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', (t, unsubscribe) => {\n                theme = t;\n                unsubscribe?.();\n            })\n        );\n        // do something with theme\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Needs more context</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <meta name=\"description\" content=\"A better way to do context for web components.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-10-07\">\n        <img src=\"image.webp\" alt=\"A comic book page showing a cowbell being rang\" loading=\"lazy\" />\n        <h2>Needs more context</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            In the earlier article <a href=\"../2024-09-28-unreasonable-effectiveness-of-vanilla-js/\">the unreasonable effectiveness of vanilla JS</a>\n            I explained a vanilla web version of the React tutorial example <em>Scaling up with Reducer and Context</em>.\n            That example used a technique for <em>context</em> based on <code>Element.closest()</code>.\n            While that way of obtaining a context is very simple, which definitely has its merits,\n            it also has some downsides:\n        </p>\n        <ul>\n            <li>It cannot be used from inside a shadow DOM to find a context that lives outside of it without <a href=\"https://stackoverflow.com/q/54520554/20980\">clumsy workarounds</a>.</li>\n            <li>It requires a custom element to be the context.</li>\n            <li>There has to be separate mechanism to subscribe to context updates.</li>\n        </ul>\n        <p>\n            There is in fact, or so I learned recently, a better and more standard way to solve this\n            known as the <a href=\"https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md\">context protocol</a>. \n            It's not a browser feature, but a protocol for how to implement a context in web components.\n        </p>\n        <p>\n            This is how it works: the consumer starts by dispatching a <code>context-request</code> event.\n        </p>\n        <x-code-viewer src=\"context-request-1.js\" name=\"\"></x-code-viewer>\n        <p>\n            The event will travel up the DOM tree (bubbles = true), piercing any shadow DOM boundaries (composed = true),\n            until it reaches a listener that responds to it. This listener is attached to the DOM by a context provider.\n            The context provider uses the <code>e.context</code> property to detect whether it should respond,\n            then calls <code>e.callback</code> with the appropriate context value.\n            Finally it calls <code>e.stopPropagation()</code> so the event will stop bubbling up the DOM tree.\n        </p>\n        <p>\n            This whole song and dance is guaranteed to happen synchronously, which enables this elegant pattern:\n        </p>\n        <x-code-viewer src=\"context-request-2.js\" name=\"\"></x-code-viewer>\n        <p>\n            If no provider is registered the event's callback is never called and the default value will be used instead.\n        </p>\n        <p>\n            Instead of doing a one-off request for a context's value it's also possible to subscribe to updates\n            by setting its subscribe property to true.\n            Every time the context's value changes the callback will be called again.\n            To ensure proper cleanup the subscribing element has to unsubscribe on disconnect.\n        </p>\n        <x-code-viewer src=\"context-request-3.js\" name=\"\"></x-code-viewer>\n        <p>\n            It is recommended, but not required, to listen for and call unsubscribe functions in one-off requests,\n            just in case a provider is overzealously creating subscriptions.\n            However, this is not necessary when using only spec-compliant providers.\n        </p>\n        <x-code-viewer src=\"context-request-4.js\" name=\"\"></x-code-viewer>\n        <p>\n            Providers are somewhat more involved to implement.\n            There are several spec-compliant libraries that implement them,\n            like <a href=\"https://lit.dev/docs/data/context/\">@lit/context</a> \n            and <a href=\"https://blikblum.github.io/wc-context/\">wc-context</a>.\n            A very minimal implementation is this one:\n        </p>\n        <x-code-viewer src=\"context-provider.js\"></x-code-viewer>\n        <p>\n            This minimal provider can then be used in a custom element like this:\n        </p>\n        <x-code-viewer src=\"theme-context.js\"></x-code-viewer>\n        <p>\n            Which would be used on a page like this, with <code>&lt;my-subscriber&gt;</code> requesting \n            the theme by dispatching a <code>context-request</code> event.\n        </p>\n        <x-code-viewer src=\"theme-context-fragment.html\" name=\"\"></x-code-viewer>\n        <p>\n            Notice in the above example that the <code>theme-toggle</code> context is providing a function.\n            This unlocks a capability for dependency injection where API's to control page behavior\n            are provided by a context to any subscribing custom element.\n        </p>\n        <p>\n            Don't let this example mislead you however. A provider doesn't actually need a dedicated custom element,\n            and can be attached to any DOM node, even the body element itself.\n            This means a context can be provided or consumed from anywhere on the page.\n        </p>\n        <x-code-viewer src=\"theme-provider.js\"></x-code-viewer>\n        <p>\n            And because there can be more than one event listener on a page,\n            there can be more than one provider providing the same context.\n            The first one to handle the event will win.\n        </p>\n        <p>\n            Here's an example that illustrates a combination of a global provider attached to the body (top panel),\n            and a local provider using a <code>&lt;theme-context&gt;</code> (bottom panel).\n            Every time the <code>&lt;theme-toggle&gt;</code> is reparented it resubscribes to the theme from the nearest provider.\n        </p>\n        <iframe src=\"combined/index.html\" title=\"combined example\" height=\"250\"></iframe>\n        <x-code-viewer src=\"combined/index.js\" name=\"index.js\"></x-code-viewer>\n\n        <p>\n            The full implementation of this protocol can be found in the <a href=\"https://github.com/jsebrech/tiny-context\">tiny-context repo</a> on Github.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113267665973403436\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/theme-context-fragment.html",
    "content": "<theme-context>\n    <div>\n        <my-subscriber></my-subscriber>\n    </div>\n</theme-context>\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/theme-context.js",
    "content": "customElements.define('theme-context', class extends HTMLElement {\n    themeProvider = new ContextProvider(this, 'theme', 'light');\n    toggleProvider = new ContextProvider(this, 'theme-toggle', () => {\n        this.themeProvider.value = this.themeProvider.value === 'light' ? 'dark' : 'light';\n    });\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-07-needs-more-context/theme-provider.js",
    "content": "// loaded with <script type=\"module\" src=\"theme-provider.js\"></script>\n\nimport { ContextProvider } from \"./context-provider.js\";\n\nconst themeProvider = new ContextProvider(document.body, 'theme', 'light');\nconst toggleProvider = new ContextProvider(document.body, 'theme-toggle', () => {\n    themeProvider.value = themeProvider.value === 'light' ? 'dark' : 'light';\n});\n"
  },
  {
    "path": "public/blog/articles/2024-10-20-editing-plain-vanilla/.hintrc",
    "content": "{\n  \"extends\": [\n    \"development\"\n  ],\n  \"hints\": {\n    \"compat-api/html\": [\n      \"default\",\n      {\n        \"ignore\": [\n          \"iframe[loading]\"\n        ]\n      }\n    ],\n    \"no-inline-styles\": \"off\"\n  }\n}"
  },
  {
    "path": "public/blog/articles/2024-10-20-editing-plain-vanilla/eslint.config.cjs",
    "content": "/* eslint-disable no-undef */\nconst globals = require(\"globals\");\nconst js = require(\"@eslint/js\");\n\nmodule.exports = [\n    js.configs.recommended, \n    {\n        languageOptions: {\n            globals: {\n                ...globals.browser,\n                ...globals.mocha\n            },\n            ecmaVersion: 2022,\n            sourceType: \"module\",\n        }\n    },\n    {\n        ignores: [\n            \"public/blog/articles/\",\n            \"**/lib/\",\n            \"**/react/\",\n        ]\n    }\n];"
  },
  {
    "path": "public/blog/articles/2024-10-20-editing-plain-vanilla/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Editing Plain Vanilla</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"How to set up VS Code for a vanilla web project.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-10-20\">\n        <img src=\"image.webp\" alt=\"Early 20th century, an editor laying out a newspaper by hand\" loading=\"lazy\" />\n        <h2>Editing Plain Vanilla</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            I'm typing this up in Visual Studio Code, after realizing I should probably explain how I use it to make this site.\n            But the whole idea behind Plain Vanilla is no build, no framework, no tools.\n            And VS Code is definitely a tool. So what gives?\n        </p>\n        <p>\n            There's a difference between tools that sit in between the code and a deployed site, and tools that only act in support of editing or deploying.\n            The first category, like npm or typescript, impose continued maintenance on the project because they form a direct dependency.\n            The second category, like VS Code or git, are easily replaced without impacting the project's ability to be edited.\n            There's a tension between the ability to get things done faster, and the burden created by additional dependencies.\n            For this project I draw the line in accepting the second category while rejecting the first.\n        </p>\n        <h3>Setting up a profile</h3>\n        <p>\n            I use VS Code for framework-based work projects as well as vanilla web development.\n            To keep those two realms neatly separated I've <a href=\"https://code.visualstudio.com/docs/editor/profiles\">set up a separate Vanilla profile</a>. \n            In that profile is a much leaner suite of extensions, configured for only vanilla web development.\n        </p>\n        <ul>\n            <li><strong>ESLint</strong>, to automatically lint the JS code while editing</li>\n            <li><strong>webhint</strong>, to lint the HTML and CSS code, and detect accessibility issues</li>\n            <li><strong>html-in-template-string</strong>, to syntax highlight HTML template strings</li>\n            <li><strong>Todo Tree</strong>, to keep track of TODO's while doing larger changes</li>\n            <li><strong>Live Preview</strong>, to get a live preview of the page that I'm working on</li>\n            <li><strong>VS Code Counter</strong>, for quick comparative line counts when porting framework code to vanilla</li>\n            <li><strong>Intellicode</strong>, for simple code completion</li>\n            <li><strong>Codeium</strong>, for AI-assisted code completion, works great for web component boilerplate</li>\n        </ul>\n        <p>\n            Modern web development can be very overburdened by tools, sometimes all but requiring the latest Macbook Pro with decadent amounts of RAM\n            just to edit a basic project. The combination of a no build plain vanilla codebase with a lean VS Code profile guarantees quick editing,\n            even on my oldest and slowest laptops.\n        </p>\n        <h3>Linting</h3>\n        <p>\n            Nobody's perfect, myself included, so something needs to be scanning the code for goofs.\n            The first linting tool that's set up is ESLint. The VS Code extension regrettably does not come bundled with an eslint installation,\n            so this has to be installed explicitly. By doing it once globally this can be reused across vanilla web projects.\n        </p>\n        <p><code>npm install -g eslint @eslint/js globals</code></p>\n        <p>\n            Because I use nvm to manage node versions the global eslint install was not automatically detectable.\n            This required setting a NODE_PATH in <code>.zshrc</code> that VS Code then picked up.\n        </p>\n        <p><code>export NODE_PATH=$(npm root -g)</code></p>\n        <p>\n            In addition, in order to lint successfully it needs a configuration file, located in the project's root.\n        </p>\n        <x-code-viewer src=\"./eslint.config.cjs\" name=\"/eslint.config.cjs\"></x-code-viewer>\n        <p>\n            Setting the <code>ecmaVersion</code> to 2022 ensures that I don't accidentally use newer and unsupported Javascript features,\n            like in this example trying to use ES2024's <a href=\"https://2ality.com/2024/06/ecmascript-2024.html#regular-expression-flag-%2Fv\">v flag</a> in regular expressions.\n            This version could be set to whatever browser compatibility a project requires.\n        </p>\n        <img src=\"eslinterror.png\" alt=\"ESLint error for ECMAScript 2024 feature\" loading=\"lazy\" width=\"561\" />\n        <p>\n            The <code>ignores</code> blocks excludes external libraries to placate my OCD that wants to see zero errors or warnings reported by eslint project-wide.\n            The article folders are excluded for a similar reason, because they contain a lot of incomplete and deliberately invalid example JS files.\n        </p>\n        <p>\n            The webhint extension is installed to do automatic linting on HTML and CSS.\n            Luckily it out of the box comes bundled with a webhint installation and applies the default <code>development</code> ruleset.\n            A nice thing about this extension is that it reports accessibility issues.\n        </p>\n        <img src=\"webhinterror.png\" alt=\"Webhint error for accessibility\" loading=\"lazy\" width=\"842\" />\n        <p>\n            Only a few tweaks were made to the webhint configuration to again get to that all-important zero warnings count.\n        </p>\n        <x-code-viewer src=\"./.hintrc\" name=\"/.hintrc\"></x-code-viewer>\n\n        <h3>html-in-template-string</h3>\n        <p>\n            I've mentioned it before in the <a href=\"../2024-08-25-vanilla-entity-encoding/\">entity encoding article</a>,\n            but this neat little extension formats HTML inside tagged template strings in web component JS code.\n        </p>\n        <img src=\"syntax-highlighting.webp\" loading=\"lazy\" alt=\"Syntax highlighting in template strings\" width=\"849\" />\n\n        <h3>Live Preview</h3>\n        <p>\n            The center piece for a smooth editing workflow is the Live Preview extension.\n            I can right-click on any HTML file in the project and select \"Show Preview\" to get a live preview of the page.\n            This preview automatically refreshes when files are saved. Because vanilla web pages always load instantly\n            this provides the hot-reloading workflow from framework projects, except even faster and with zero setup.\n            The only gotcha is that all paths in the site have to be relative paths so the previewed page can resolve them.\n        </p>\n        <img src=\"live-preview.webp\" alt=\"Live Preview of this article while editing\" loading=\"lazy\" />\n        <p>\n            The preview's URL can be pasted into a \"real browser\" to debug tricky javascript issues\n            and do compatibility testing. Very occasionally I'll need to spin up a \"real server\", \n            but most of the code in my vanilla projects is written with only a Live Preview tab open.\n        </p>\n        <p>\n            Previewing is also how I get a realtime view of unit tests while working on components or infrastructure code,\n            by opening the tests web page and selecting the right test suite to hot reload while editing.\n        </p>\n\n        <h3>Bonus: working offline</h3>\n        <p>\n            Because I live at the beach and work in the big city I regularly need to take long train rides with spotty internet connection.\n            Like many developers I cannot keep web API's in my head and have to look them up regularly while coding.\n            To have a complete offline vanilla web development setup with me at all times I use <a href=\"\">devdocs.io</a>.\n            All my projects folders are set up to sync automatically with <a href=\"https://syncthing.net/\">Syncthing</a>, \n            so whatever I was doing on the desktop can usually be smoothly continued offline on the laptop \n            without having to do any prep work to make that possible.\n        </p>\n        <img src=\"devdocs.webp\" alt=\"devdocs.io screenshot\" loading=\"lazy\" />\n\n        <p>\n            There, that's my lean vanilla web development setup.\n            What should I add to this, or do differently? Feel free to let me know.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113339907977265330\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-12-16-caching-vanilla-sites/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Caching vanilla sites</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"Strategies for cache invalidation on vanilla web sites.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2024-12-16\">\n        <img src=\"image.webp\" alt=\"Early 20th century, an editor laying out a newspaper by hand\" loading=\"lazy\" />\n        <h2>Caching vanilla sites</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            If you go to a typical website built with a framework, you'll see a lot of this:\n        </p>\n        <img src=\"vercel.webp\" width=\"865\" alt=\"browser devtools showing network requests for vercel.com\" loading=\"lazy\" />\n        <p>\n            Those long cryptic filenames are not meant to discourage casual snooping.\n            They're meant to ensure the filename is changed every time a single byte in that file changes,\n            because the site is using <em>far-future expire headers</em>, \n            a technique where the browser is told to cache files indefinitely, until the end of time.\n            On successive page loads those resources will then always be served from cache.\n            The only drawback is having to change the filename each time the file's contents change, \n            but a framework's build steps typically take care of that.\n        </p>\n        <p>\n            For vanilla web sites, this strategy doesn't work. By abandoning a build step there is no way to automatically generate filenames,\n            and unless nothing makes you happier than renaming all files manually every time you deploy a new version,\n            we have to look towards other strategies.\n        </p>\n\n        <h3>How caching works</h3>\n\n        <p>\n            Browser cache behavior is complicated, and a deep dive into the topic deserves <a href=\"https://web.dev/articles/http-cache\">its own article</a>.\n            However, very simply put, what you'll see is mostly these response headers:\n        </p>\n        <dl>\n            <dt>Cache-Control</dt>\n            <dd>\n                <p>\n                    The cache control response header determines whether the browser should cache the response, and how long it should serve the response from cache.\n                </p>\n                <p><code>Cache-Control: public, max-age: 604800</code></p>\n                <p>\n                    This will cache the resource and only check if there's a new version after one week.\n                </p>\n            </dd>\n            <dt>Age</dt>\n            <dd>\n                <p>\n                    The <code>max-age</code> directive does not measure age from the time that the response is received,\n                    but from the time that the response was originally served:\n                </p>\n                <p><code>Age: 10</code></p>\n                <p>\n                    This response header indicates the response was served on the origin server 10 seconds ago.\n                </p>\n            </dd>\n            <dt>Etag</dt>\n            <dd>\n                <p>\n                    The <code>Etag</code> header is a unique hash of the resource's contents, an identifier for that version of the resource.\n                </p>\n                <p><code>ETag: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"</code></p>\n                <p>\n                    When the browser requests that resource again from the server, knowing the Etag it can pass an <code>If-None-Match</code>\n                    header with the Etag's value. If the resource has not changed it will still have the same Etag value,\n                    and the server will respond with <code>304 Not Modified</code>. \n                </p>\n                <p><code>If-None-Match: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"</code></p>\n            </dd>\n            <dt>Last-Modified</dt>\n            <dd>\n                <p>\n                    The <code>Last-Modified</code> header works similarly to Etag, except instead of sending a hash of the contents,\n                    it sends a timestamp of when the resource was last changed. \n                    Like Etag's <code>If-None-Match</code> it is matched by the <code>If-Modified-Since</code> header when requesting the resource from the server again.\n                </p>\n            </dd>\n        </dl>\n\n        <p>\n            With that basic review of caching headers, let's look at some strategies for making good use of them in vanilla web projects.\n        </p>\n\n        <h3>Keeping it simple: GitHub Pages</h3>\n\n        <p>\n            The simplest strategy is what GitHub Pages does: cache files for 10 minutes.\n            Every file that's downloaded has <code>Cache-Control: max-age</code> headers that make it expire 10 minutes into the future.\n            After that if the file is loaded again it will be requested from the network.\n            The browser will add <code>If-None-Match</code> or <code>If-Modified-Since</code> headers\n            to allow the server to avoid sending the file if it hasn't been changed, saving bytes but not a roundtrip.\n        </p>\n        <p>\n            If you want to see it in action, just open the browser devtools and reload this page.\n        </p>\n        <img src=\"plainvanilla.webp\" width=\"660\" loading=\"lazy\" alt=\"browser devtools showing network requests for plainvanillaweb.com\" />  \n        <p>\n            Visitors never get a page that is more than 10 minutes out of date,\n            and as they navigate around the site they mostly get fast cache-served responses.\n            However, on repeat visits they will get a slow first-load experience.\n            Also, if the server updates in the middle of a page load then different resources may end up mismatched and belong to a different version of the site, causing unpredictable bugs.\n            Well, for 10 minutes at least.\n        </p>\n\n        <h3>Extending cache durations</h3>\n        <p>\n            While the 10 minute cache policy is ok for HTML content and small JS and CSS files,\n            it can be improved by increasing cache times on large resources like libraries and images.\n            By using a caching proxy that allows setting rules on specific types or folders of files we can increase the cache duration.\n            For sites <a href=\"https://blog.cloudflare.com/secure-and-fast-github-pages-with-cloudflare/\">proxied through Cloudflare</a>, \n            their <a href=\"https://developers.cloudflare.com/cache/concepts/customize-cache/\">cache customization settings</a> \n            can be used to set these resource-specific policies.\n        </p>\n        <p>\n            By setting longer cache durations on some resources, we can ensure they're served from local cache more often.\n            However, what to do if the resource changes? In those cases we need to modify the fetched URL of the resource every place that it is referred to.\n            For example, by appending a unique query parameter:\n        </p>\n        <p>\n            <code>&lt;img src=\"image.jpg?v=2\" alt=\"My cached image\" /&gt;</code>\n        </p>\n        <p>\n            The awkward aspect of having to change the referred URL in every place that a changed file is used\n            makes extending cache durations inconvenient for files that are changed often or are referred in many places.\n        </p>\n        <p>\n            Also, applying such policies to JavaScript or CSS becomes a minefield,\n            because a mismatched combination of JS or CSS files could end up in the browser cache indefinitely,\n            breaking the website for the user until URL's are changed or their browser cache is cleared.\n            For that reason, I don't think it's prudent to do this for anything but files that never change or that have some kind of version marker in their URL.\n        </p>\n\n        <h3>Complete control with service workers</h3>\n\n        <p>\n            A static web site can take complete control over its cache behavior by <a href=\"https://web.dev/learn/pwa/service-workers\">using a service worker</a>.\n            The service worker intercepts every network request and then decides whether to serve it from a local cache or from the network.\n            For example, here's a service worker that will cache all resources indefinitely, until its version is changed:\n        </p>\n        <x-code-viewer src=\"sw.js\"></x-code-viewer>\n        <p>\n            This recreates the <em>far-future expiration</em> strategy but does it client-side, inside the service worker.\n            Because only the version at the top of the <code>sw.js</code> file needs to be updated when the site's contents change,\n            this becomes practical to do without adding a build step. However, because the service worker intercepts network requests\n            to change their behavior there is a risk that bugs could lead to a broken site, so this strategy is only for the careful and well-versed.\n            (And no, the above service worker code hasn't been baked in production, so be careful when copying it to your own site.)\n        </p>\n        \n        <h3>Wrapping up</h3>\n        <p>\n            Setting sane cache policies meant to optimize page load performance is one of the things typically in the domain\n            of full-fat frameworks or application servers. But, abandoning build steps and server-side logic does not necessarily \n            have to mean having poor caching performance. There are multiple strategies with varying amounts of cache control,\n            and there is probably a suitable strategy for any plain vanilla site.\n        </p>\n        <p>\n            Last but not least, an even better way to speed up page loading is to keep the web page itself light.\n            Using a plain vanilla approach to pages with zero dependencies baked into the page weight\n            already puts you in pole position for good page load performance, before caching even enters the picture.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113664512755567750\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2024-12-16-caching-vanilla-sites/sw.js",
    "content": "let cacheName = 'cache-worker-v1';\n// these are automatically cached when the site is first loaded\nlet initialAssets = [\n    './',\n    'index.html',\n    'index.js',\n    'index.css',\n    'manifest.json',\n    'android-chrome-512x512.png',\n    'favicon.ico',\n    'apple-touch-icon.png',\n    'styles/reset.css',\n    // the rest will be auto-discovered\n];\n\n// initial bundle (on first load)\nself.addEventListener('install', (event) => {\n    event.waitUntil(\n        caches.open(cacheName).then((cache) => {\n            return cache.addAll(initialAssets);\n        })\n    );\n});\n\n// clear out stale caches after service worker update\nself.addEventListener('activate', (event) => {\n    event.waitUntil(\n        caches.keys().then((cacheNames) => {\n            return Promise.all(\n                cacheNames.map((cacheName) => {\n                    if (cacheName !== self.cacheName) {\n                        return caches.delete(cacheName);\n                    }\n                })\n            );\n        })\n    );\n});\n\n// default to fetching from cache, fallback to network\nself.addEventListener('fetch', (event) => {\n    const url = new URL(event.request.url);\n\n    // other origins bypass the cache\n    if (url.origin !== location.origin) {\n        networkOnly(event);\n    // default to fetching from cache, and updating asynchronously\n    } else {\n        staleWhileRevalidate(event);\n    }\n});\n\nconst networkOnly = (event) => {\n    event.respondWith(fetch(event.request));\n}\n\n// fetch events are serviced from cache if possible, but also updated behind the scenes\nconst staleWhileRevalidate = (event) => {\n    event.respondWith(\n        caches.match(event.request).then(cachedResponse => {\n            const networkUpdate = \n                fetch(event.request).then(networkResponse => {\n                    caches.open(cacheName).then(\n                        cache => cache.put(event.request, networkResponse));\n                    return networkResponse.clone();\n                }).catch(_ => /*ignore because we're probably offline*/_);\n            return cachedResponse || networkUpdate;\n        })\n    );\n}"
  },
  {
    "path": "public/blog/articles/2025-01-01-new-years-resolve/example-index.js",
    "content": "import { registerAvatarComponent } from './components/avatar.js';\nconst app = () => {\n    registerAvatarComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/blog/articles/2025-01-01-new-years-resolve/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>New year's resolve</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"import.meta.resolve and other ways to avoid bundling\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2025-01-01\">\n        <img src=\"image.webp\" alt=\"New year's fireworks\" loading=\"lazy\" />\n        <h2>New year's resolve</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            Today I was looking at what I want to write about in the coming year,\n            and while checking out custom element micro-frameworks came across <code>import.meta.resolve</code>\n            in the documentation for the <a href=\"https://github.com/jhuddle/ponys\">Ponys</a> micro-framework. \n            That one simple trick is part of the essential toolbox that allows skipping build-time bundling,\n            unlocking the vanilla web development achievement in the browser.\n        </p>\n        <p>\n            We need this toolbox because the build-time bundler does a lot of work for us:\n        </p>\n        <ul>\n            <li><em>Combining JS and CSS files</em> to avoid slow page loads.</li>\n            <li><em>Resolving paths to the JS and CSS dependencies</em> so we can have clean import statements.</li>\n            <li><em>Optimizing the bundled code</em>, by stripping out whitespace, and removing unused imports thanks to a tree shaking algorithm.</li>\n        </ul>\n        <p>\n            It is not immediately apparent how to get these benefits without using a bundler.\n        </p>\n\n        <h3>Combining JS and CSS files</h3>\n        <p>\n            A typical framework-based web project contains hundreds or thousands of files.\n            Having all those files loaded separately on a page load would be intolerably slow,\n            hence the need for a bundler to reduce the file count. Even by stripping away third party dependencies\n            we can still end up with dozens or hundreds of files constituting a vanilla web project.\n        </p>\n        <p>\n            When inspecting a page load in the browser's developer tools, we would then expect to see a lot of this:\n        </p>\n        <img src=\"http1.png\" alt=\"a waterfall of network requests in browser devtools over http1\" loading=\"lazy\" />\n        <p>\n            The browser would download 6 files at a time and the later requests would block until those files downloaded.\n            This limitation of HTTP/1 let to not just the solution of bundlers to reduce file count, but because the limitation of 6 parallel downloads\n            was per domain it also led to the popularity of CDN networks which allowed <em>cheating</em> and downloading 12 files at once instead of 6.\n        </p> \n        <p>\n            However. It's 2025. What you're likely to see in this modern era is more like this:\n        </p>\n        <img src=\"http2.png\" alt=\"parallel network requests in browser devtools over http2\" loading=\"lazy\" />\n        <p>\n            Because almost all web servers have shifted over to HTTP/2, which no longer has this limitation of only having 6 files in flight at a time,\n            we now see that all the files that are requested in parallel get downloaded in parallel.\n            There's still a small caveat on lossy connections called head-of-line-blocking, <a href=\"https://http3-explained.haxx.se/en/why-quic/why-tcphol\">fixed in HTTP/3</a>,\n            which is presently starting to roll out to web servers across the internet.\n        </p>\n        <p>\n            But the long and short of it is this: requesting a lot of files all at once just isn't that big of a problem anymore.\n            We don't need to bundle up the files in a vanilla web project until the file counts get ridiculous.\n        </p>\n\n        <h3>Resolving paths</h3>\n\n        <p>\n            Another thing that bundlers do is resolving relative paths pointing to imported JS and CSS files.\n            See, for example, the elegance of CSS modules for importing styles into a react component from a relative path:\n        </p>\n        <x-code-viewer src=\"layout.tsx\" name=\"layout.tsx (React)\"></x-code-viewer>\n        <p>\n            However. It's 2025. And our browsers now have a modern vanilla toolbox for importing.\n            When we bootstrap our JS with the magic incantation <code>&lt;script src=\"index.js\" type=\"module\"&gt;&lt;/script&gt;</code>\n            we unlock the magic ability to import JS files using <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_features_into_your_script\">ES module</a> import notation:\n        </p>\n        <x-code-viewer src=\"example-index.js\" name=\"index.js\"></x-code-viewer>\n        <p>\n            Inside of such files we also get access to <code>import.meta.url</code>, the URL of the current JS file,\n            and <code>import.meta.resolve()</code>, a function that resolves a path relative to the current file,\n            even a path to a CSS file:\n        </p>\n        <x-code-viewer src=\"layout.js\"></x-code-viewer>\n        <p>\n            While not quite the same as what the bundler does, it still enables accessing any file by its relative path,\n            and that in turn allows <a href=\"https://medium.com/@devwares/best-folder-structure-for-modern-web-application-3894e1238bd\">organizing projects in whatever way we want</a>, for example in a feature-based folder organization.\n            All without needing a build step.\n        </p>\n        <p>\n            This ability to do relative imports can be super-charged by <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap\">import maps</a>,\n            which decouple the name of what is imported from the path of the file it is imported from,\n            again all without involving a build step.\n        </p>\n\n        <h3>Optimizing bundled code</h3>\n\n        <p>\n            Another thing bundlers can do is optimizing the bundled code, by splitting the payload into things loaded initially,\n            and things loaded later on lazily. And also by minifying it, stripping away unnecessary whitespace and comments so it will load faster.\n        </p>\n        <p>\n            However. It's 2025. We can transparently enable gzip or brotli compression on the server,\n            and as it turns out that gets <a href=\"https://css-tricks.com/the-difference-between-minification-and-gzipping/\">almost all the benefit of minifying</a>. \n            While minifying is nice, gzipping is what we really want, and we can get that without a build step.\n        </p>\n        <p>\n            And lazy loading, that works fine using <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import\">dynamic import</a>, and with a bit due diligence we can put some of the code behind such an import statement.\n            I wrote before how React's <a href=\"../2024-09-09-sweet-suspense/\">lazy and suspense can be ported</a> easily to vanilla web components.\n        </p>\n\n        <h3>Happy new year!</h3>\n\n        <p>\n            Great news! It's 2025, and the browser landscape is looking better than ever. It gives us enough tools that for many web projects\n            we can drop the bundler and do just fine. You wouldn't believe it based on what the mainstream frameworks are doing though.\n            Maybe 2025 is the year we finally see a wide recognition of just how powerful the browser platform has gotten,\n            and a return to old school simplicity in web development practice, away from all those complicated build steps. \n            It's my new year's resolve to do my part in spreading the word.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/113755105021769804\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-01-01-new-years-resolve/layout.js",
    "content": "class Layout extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n        this.shadowRoot.innerHTML = `\n            <link rel=\"stylesheet\" href=\"${import.meta.resolve('styles.css')}\">\n            <section class=\"dashboard\"><slot></slot></section>\n        `;\n    }\n}\n\nexport const registerLayoutComponent = \n    () => customElements.define('x-layout', Layout);\n"
  },
  {
    "path": "public/blog/articles/2025-01-01-new-years-resolve/layout.tsx",
    "content": "import styles from './styles.module.css'\n \nexport default function Layout({\n  children,\n}: {\n  children: React.ReactNode\n}) {\n  return <section className={styles.dashboard}>{children}</section>\n}"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo1.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 1</title>\n        <link rel=\"stylesheet\" href=\"../../example-base.css\">\n    </head>\n    <body>\n        <p>Markup: <span id=\"rawhtml\"></span></p>\n        <p>Outputs: <my-hello value=\"world\"></my-hello></p>\n        <script>\n            const span = document.getElementById('rawhtml');\n            const myHello = document.querySelector('my-hello');\n            span.textContent = myHello.outerHTML;\n        </script>\n        <script src=\"demo1.js\"></script></script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo1.js",
    "content": "customElements.define('my-hello', class extends HTMLElement {\n    connectedCallback() {\n        this.textContent = `Hello, ${ this.value || 'null' }!`;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo2.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 2</title>\n        <link rel=\"stylesheet\" href=\"../../example-base.css\">\n    </head>\n    <body>\n        <p>Markup: <span id=\"rawhtml\"></span></p>\n        <p>Outputs: <my-hello value=\"world\"></my-hello></p>\n        <script>\n            const span = document.getElementById('rawhtml');\n            const myHello = document.querySelector('my-hello');\n            span.textContent = myHello.outerHTML;\n        </script>\n        <script src=\"demo2.js\"></script></script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo2.js",
    "content": "customElements.define('my-hello', class extends HTMLElement {\n    connectedCallback() {\n        this.textContent = `Hello, ${ this.getAttribute('value') || 'null' }!`;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo3.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 3</title>\n        <link rel=\"stylesheet\" href=\"../../example-base.css\">\n    </head>\n    <body>\n        <p>Markup: <span id=\"rawhtml\"></span></p>\n        <p>Outputs: <my-hello value=\"world\"></my-hello></p>\n\n        <button onclick=\"myHello.value = 42\">myHello.value = 42</button>\n        <button onclick=\"location.reload()\">Reload</button>\n\n        <script>\n            const span = document.getElementById('rawhtml');\n            const myHello = document.querySelector('my-hello');\n            const m = new MutationObserver(() => {\n                span.textContent = myHello.outerHTML.replace(/\\>.*\\<\\//g, '><');\n            });\n            m.observe(myHello, { attributes: true, childList: true });\n        </script>\n        <script src=\"demo3.js\"></script></script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo3.js",
    "content": "customElements.define('my-hello', class extends HTMLElement {\n    get value() {\n        return this.getAttribute('value');\n    }\n    set value(v) {\n        this.setAttribute('value', String(v));\n    }\n    \n    static observedAttributes = ['value'];\n    attributeChangedCallback() {\n        this.textContent = `Hello, ${ this.value || 'null' }!`;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo4.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 4</title>\n        <link rel=\"stylesheet\" href=\"../../example-base.css\">\n    </head>\n    <body>\n        <p>Markup: <span id=\"markup\"></span></p>\n        <p>Outputs: <my-hello value=\"world\"></my-hello></p>\n\n        <button onclick=\"myHello.glam = !myHello.glam\">toggle myHello.glam</button>\n\n        <script>\n            const span = document.getElementById('markup');\n            const myHello = document.querySelector('my-hello');\n            const m = new MutationObserver(() => {\n                span.textContent = myHello.outerHTML.replace(/\\>.*\\<\\//g, '><');\n            });\n            m.observe(myHello, { attributes: true, childList: true });\n        </script>\n        <script src=\"demo4.js\"></script></script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo4.js",
    "content": "customElements.define('my-hello', class extends HTMLElement {\n    get value() {\n        return this.getAttribute('value');\n    }\n    set value(v) {\n        this.setAttribute('value', String(v));\n    }\n\n    get glam() {\n        return this.hasAttribute('glam');\n    }\n    set glam(v) {\n        if (v) {\n            this.setAttribute('glam', 'true');\n        } else {\n            this.removeAttribute('glam');\n        }\n    }\n    \n    static observedAttributes = ['value', 'glam'];\n    attributeChangedCallback() {\n        this.textContent = \n            `Hello, ${ this.value || 'null' }!` +\n            (this.glam ? '!!@#!' : '');\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo5-before.js",
    "content": "// html:\n<my-hello value=\"world\"></my-hello>\n// js:\nconst myHello = document.querySelector('my-hello');\nmyHello.value = 42; // setter not called before define\ncustomElements.define('my-hello', /* ... */);\nconsole.log(myHello.getAttribute('value')); // -> \"world\"\n"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo5.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 5</title>\n        <link rel=\"stylesheet\" href=\"../../example-base.css\">\n    </head>\n    <body>\n        <p>Markup: <span id=\"markup\"></span></p>\n        <p>Outputs: <my-hello value=\"world\"></my-hello></p>\n\n        <button onclick=\"myHello.glam = !myHello.glam\">toggle myHello.glam</button>\n\n        <script>\n            const span = document.getElementById('markup');\n            const myHello = document.querySelector('my-hello');\n            const m = new MutationObserver(() => {\n                span.textContent = myHello.outerHTML.replace(/\\>.*\\<\\//g, '><');\n            });\n            m.observe(myHello, { attributes: true, childList: true });\n        </script>\n        <script src=\"demo5.js\"></script></script>\n    </body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/demo5.js",
    "content": "customElements.define('my-hello', class extends HTMLElement {\n    get value() {\n        return this.getAttribute('value');\n    }\n    set value(v) {\n        this.setAttribute('value', String(v));\n    }\n\n    get glam() {\n        return this.hasAttribute('glam');\n    }\n    set glam(v) {\n        if (v) {\n            this.setAttribute('glam', 'true');\n        } else {\n            this.removeAttribute('glam');\n        }\n    }\n    \n    static observedAttributes = ['value', 'glam'];\n    attributeChangedCallback() {\n        this.textContent = \n            `Hello, ${ this.value || 'null' }!` +\n            (this.glam ? '!!@#!' : '');\n    }\n\n    connectedCallback() {\n        this.#upgradeProperty('value');\n        this.#upgradeProperty('glam');\n    }\n\n    #upgradeProperty(prop) {\n        if (this.hasOwnProperty(prop)) {\n            let value = this[prop];\n            delete this[prop];\n            this[prop] = value;\n        }\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-04-21-attribute-property-duality/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>The attribute/property duality</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"How to work with attributes and properties in custom elements.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2025-04-21\">\n        <img src=\"image.webp\" alt=\"A cartoon angle bracket figure gladly sharing his opinions to a crowd of symbols.\" loading=\"lazy\" />\n        <h2>The attribute/property duality</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            Web components, a.k.a. custom elements, are HTML elements\n            that participate in HTML markup. As such they can have attributes:\n        </p>\n        <p><code>&lt;my-hello value=\"world\"&gt;&lt;/my-hello&gt;</code></p>\n        <p>\n            But, they are also JavaScript objects, and as such they can have object properties.\n        </p>\n        <p><code>let myHello = document.querySelector('my-hello'); myHello.value = 'foo';</code></p>\n        <p>\n            And here's the tricky part about that: <em>these are not the same thing!</em>\n            In fact, custom element attributes and properties by default have <em>zero</em> relationship between them,\n            even when they share a name. Here's a live proof of this fact:\n        </p>\n\n        <x-code-viewer src=\"demo1.js\"></x-code-viewer>\n        <iframe src=\"demo1.html\" title=\"Demo: no connection between attribute and property\" height=\"150\"></iframe>\n\n        <p>\n            Now, to be fair, we can get at the attribute value just fine from JavaScript:\n        </p>\n\n        <x-code-viewer src=\"demo2.js\"></x-code-viewer>\n        <iframe src=\"demo2.html\" title=\"Demo: displaying the attribute\" height=\"150\"></iframe>\n\n        <p>\n            But what if we would also like it to have a <code>value</code> <em>property</em>?\n            What should the relationship between attribute and property be like?\n        </p>\n        <ul>\n            <li>Does updating the attribute always update the property?</li>\n            <li>Does updating the property always update the attribute?</li>\n            <li>When updates can go either way, does the property read and update the value of the attribute, or do both attribute and property wrap around a private field on the custom element's class?</li>\n            <li>When updates can go either way, how to avoid loops where the property updates the attribute, which updates the property, which...</li>\n            <li>When is it fine to have just an attribute without a property, or a property without an attribute?</li>\n        </ul>\n\n        <p>\n            In framework-based code, we typically don't get a say in these things.\n            Frameworks generally like to pretend that attributes and properties are the same thing,\n            and they automatically create code to make sure this is the case.\n            In vanilla custom elements however, not only do we get to decide these things, we <em>must</em> decide them.\n        </p>\n\n        <h3>Going native</h3>\n\n        <p>\n            Seasoned developers will intuitively grasp what the sensible relationship between attributes and properties should be.\n            This is because built-in HTML elements all implement similar kinds of relationships between their attributes and their properties.\n            To explore that in depth, I recommend reading <a href=\"https://blog.ltgt.net/web-component-properties/\">Making Web Component properties behave closer to the platform</a>.\n            Without fully restating that article, here's a quick recap:\n        </p>\n        <ul>\n            <li>Properties can exist independent of an attribute, but an attribute will typically have a related property.</li>\n            <li>If changing the attribute updates the property, then updating the property will update the attribute.</li>\n            <li>Properties <em>reflect</em> either an internal value of an element, or the value of the corresponding attribute.</li>\n            <li>Assigning a value of an invalid type will coerce the value to the right type, instead of rejecting the change.</li>\n            <li>Change events are only dispatched for changes by user input, not from programmatic changes to attribute or property.</li>\n        </ul>\n\n        <p>An easy way to get much of this behavior is to make a property wrap around an attribute:</p>\n\n        <x-code-viewer src=\"demo3.js\"></x-code-viewer>\n        <iframe src=\"demo3.html\" title=\"Demo: property wraps attribute\" height=\"150\"></iframe>\n\n        <p>\n            Notice how updating the property will update the attribute in the HTML representation,\n            and how the property's assigned value is coerced into the attribute's string type.\n            Attributes are always strings.\n        </p>\n        \n        <h3>Into the weeds</h3>\n\n        <p>\n            Up to this point, things are looking straightforward. But this is web development,\n            things are never as straightforward as they seem.\n            For instance, what boolean attribute value should make a corresponding boolean property become true?\n            The surprising but <a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML\">standard behavior</a> on built-in elements is that \n            any attribute value will be interpreted as true, and only the absence of the attribute will be interpreted as false.\n        </p>\n        <p>\n            Time for another iteration of our element:\n        </p>\n\n        <x-code-viewer src=\"demo4.js\"></x-code-viewer>\n        <iframe src=\"demo4.html\" title=\"Demo: adding a boolean property\" height=\"150\"></iframe>\n\n        <p>\n            Which leaves us with the last bit of tricky trivia:\n            it's possible for the custom element's class to be instantiated and attached to the element\n            <em>after</em> the property is assigned. In that case the property's setter is never called,\n            and the attribute is not updated.\n        </p>\n        \n        <x-code-viewer src=\"demo5-before.js\" name=\"\"></x-code-viewer>\n\n        <p>\n            This can be avoided by reassigning any previously set properties when the element is connected:\n        </p>\n\n        <x-code-viewer src=\"demo5.js\"></x-code-viewer>\n\n        <h3>In conclusion</h3>\n\n        <p>\n            If that seems like a lot of work to do a very simple thing, that is because it is.\n            The good news is: we don't have to always do this work.\n        </p>\n        <p>\n            When we're using web components as framework components in a codebase that we control,\n            we don't have to follow any of these unwritten rules and can keep the web component code as simple as we like.\n            However, when using web components as custom elements to be used in HTML markup \n            then we do well to follow these best practices to avoid surprises, \n            especially when making web components that may be used by others. YMMV.\n        </p>\n        <p>\n            In <a href=\"../2025-05-09-form-control/\">the next article</a>, I'll be looking into custom elements that accept input, and how that adds twists to the plot.\n        </p>\n\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/114377418312879988\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo1/index-partial.txt",
    "content": "<form>\n    <p>\n        My favorite colors are <input-inline name=\"color1\" value=\"green\"></input-inline> \n        and <input-inline name=\"color2\" value=\"purple\"></input-inline>.\n    </p>\n    <button type=\"submit\">Submit</button>\n</form>"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo1/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 1</title>\n        <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n        <style>\n            input-inline {\n                background-color: lightcyan;\n            }\n            form {\n                max-width: 450px;\n            }\n        </style>\n    </head>\n    <body>\n        <form>\n            <p>\n                My favorite colors are <input-inline name=\"color1\" value=\"green\"></input-inline> \n                and <input-inline name=\"color2\" value=\"purple\"></input-inline>.\n            </p>\n            <button type=\"submit\">Submit</button>\n            <button type=\"button\" onclick=\"location.reload()\">Reload</button>\n        </form>\n        <br />\n        <p id=\"result\"></p>\n        <script src=\"input-inline.js\"></script>\n        <script>\n            document.querySelector('form').onsubmit = (e) => {\n                e.preventDefault();\n                const data = new FormData(e.target);\n                const obj = Object.fromEntries(data.entries());\n                document.getElementById('result').textContent = \n                    'Submitted: ' + JSON.stringify(obj);\n            }\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo1/input-inline.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    get value() {\n        return this.getAttribute('value') ?? '';\n    }\n    set value(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (this.textContent !== this.value) {\n            this.textContent = this.value;\n        }\n        this.contentEditable = true;\n    }\n});"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo2/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 2</title>\n        <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n        <style>\n            input-inline {\n                background-color: lightcyan;\n            }\n            form {\n                max-width: 450px;\n            }\n        </style>\n    </head>\n    <body>\n        <form>\n            <p>\n                My favorite colors are <input-inline name=\"color1\" value=\"green\"></input-inline> \n                and <input-inline name=\"color2\" value=\"purple\"></input-inline>.\n            </p>\n            <button type=\"submit\">Submit</button>\n            <button type=\"button\" onclick=\"location.reload()\">Reload</button>\n        </form>\n        <br />\n        <p id=\"result\"></p>\n        <script src=\"input-inline.js\"></script>\n        <script>\n            document.querySelector('form').onsubmit = (e) => {\n                e.preventDefault();\n                const data = new FormData(e.target);\n                const obj = Object.fromEntries(data.entries());\n                document.getElementById('result').textContent = \n                    'Submitted: ' + JSON.stringify(obj);\n            }\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo2/input-inline-partial.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    #internals;\n\n    /* ... */\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n    }\n    \n    /* ... */\n\n    #update() {\n        /* ... */\n        this.#internals.setFormValue(this.value);\n    }\n\n    static formAssociated = true;\n});"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo2/input-inline.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    #internals;\n\n    get value() {\n        return this.getAttribute('value') ?? '';\n    }\n    set value(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (this.textContent !== this.value) {\n            this.textContent = this.value;\n        }\n        this.contentEditable = true;\n        this.#internals.setFormValue(this.value);\n    }\n\n    static formAssociated = true;\n});"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo3/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 3</title>\n        <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n        <style>\n            input-inline {\n                background-color: lightcyan;\n            }\n            form {\n                max-width: 450px;\n            }\n        </style>\n    </head>\n    <body>\n        <form>\n            <p>\n                My favorite colors are <input-inline name=\"color1\" value=\"green\"></input-inline> \n                and <input-inline name=\"color2\" value=\"purple\"></input-inline>.\n            </p>\n            <button type=\"submit\">Submit</button>\n            <button type=\"reset\">Reset</button>\n        </form>\n        <br />\n        <p id=\"result\"></p>\n        <script src=\"input-inline.js\"></script>\n        <script>\n            document.querySelector('form').onsubmit = (e) => {\n                e.preventDefault();\n                const data = new FormData(e.target);\n                const obj = Object.fromEntries(data.entries());\n                document.getElementById('result').textContent = \n                    'Submitted: ' + JSON.stringify(obj);\n            }\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo3/input-inline-partial.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    #shouldFireChange = false;\n    \n    /* ... */\n\n    constructor() {\n        /* ... */\n        this.addEventListener('input', this);\n        this.addEventListener('keydown', this);\n        this.addEventListener('paste', this);\n        this.addEventListener('focusout', this);\n    }\n\n    handleEvent(e) {\n        switch (e.type) {\n            // respond to user input (typing, drag-and-drop, paste)\n            case 'input':\n                this.value = cleanTextContent(this.textContent);\n                this.#shouldFireChange = true;\n                break;\n            // enter key should submit form instead of adding a new line\n            case 'keydown':\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    this.#internals.form?.requestSubmit();\n                }\n                break;\n            // prevent pasting rich text (firefox), or newlines (all browsers)\n            case 'paste':\n                e.preventDefault();\n                const text = e.clipboardData.getData('text/plain')\n                    // replace newlines and tabs with spaces\n                    .replace(/[\\n\\r\\t]+/g, ' ')\n                    // limit length of pasted text to something reasonable\n                    .substring(0, 1000);\n                // shadowRoot.getSelection is non-standard, fallback to document in firefox\n                // https://stackoverflow.com/a/70523247\n                let selection = this.getRootNode()?.getSelection?.() || document.getSelection();\n                let range = selection.getRangeAt(0);\n                range.deleteContents();\n                range.insertNode(document.createTextNode(text));\n                // manually trigger input event to restore default behavior\n                this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n                break;\n            // fire change event on blur\n            case 'focusout':\n                if (this.#shouldFireChange) {\n                    this.#shouldFireChange = false;\n                    this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n                }\n                break;\n        }\n    }\n    \n    /* ... */\n});\n\nfunction cleanTextContent(text) {\n    return (text ?? '')\n        // replace newlines and tabs with spaces\n        .replace(/[\\n\\r\\t]+/g, ' ');\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo3/input-inline.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    #shouldFireChange = false;\n    #internals;\n\n    get value() {\n        return this.getAttribute('value') ?? '';\n    }\n    set value(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n        // add event listeners\n        this.addEventListener('input', this);\n        this.addEventListener('keydown', this);\n        this.addEventListener('paste', this);\n        this.addEventListener('focusout', this);\n    }\n\n    handleEvent(e) {\n        switch (e.type) {\n            // respond to user input (typing, drag-and-drop, paste)\n            case 'input':\n                this.value = cleanTextContent(this.textContent);\n                this.#shouldFireChange = true;\n                break;\n            // enter key should submit form instead of adding a new line\n            case 'keydown':\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    this.#internals.form?.requestSubmit();\n                }\n                break;\n            // prevent pasting rich text (firefox), or newlines (all browsers)\n            case 'paste':\n                e.preventDefault();\n                const text = e.clipboardData.getData('text/plain')\n                    // replace newlines and tabs with spaces\n                    .replace(/[\\n\\r\\t]+/g, ' ')\n                    // limit length of pasted text to something reasonable\n                    .substring(0, 1000);\n                // shadowRoot.getSelection is non-standard, fallback to document in firefox\n                // https://stackoverflow.com/a/70523247\n                let selection = this.getRootNode()?.getSelection?.() || document.getSelection();\n                let range = selection.getRangeAt(0);\n                range.deleteContents();\n                range.insertNode(document.createTextNode(text));\n                // manually trigger input event to restore default behavior\n                this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n                break;\n            // fire change event on blur\n            case 'focusout':\n                if (this.#shouldFireChange) {\n                    this.#shouldFireChange = false;\n                    this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n                }\n                break;\n        }\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (cleanTextContent(this.textContent) !== this.value) {\n            this.textContent = this.value;\n        }\n        this.contentEditable = true;\n        this.#internals.setFormValue(this.value);\n    }\n\n    static formAssociated = true;\n});\n\nfunction cleanTextContent(text) {\n    return (text ?? '')\n        // replace newlines and tabs with spaces\n        .replace(/[\\n\\r\\t]+/g, ' ')\n        // remove zero width spaces\n        .replace(/\\u200B/g, '');\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo4/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 4</title>\n        <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n        <style>\n            input-inline {\n                background-color: lightcyan;\n                color: black;\n            }\n            input-inline:disabled {\n                background-color: ghostwhite;\n                color: darkgray;\n                -webkit-user-select: none;\n                user-select: none;\n            }\n            form {\n                max-width: 450px;\n            }\n            fieldset {\n                margin-bottom: 1em;\n            }\n        </style>\n    </head>\n    <body>\n        <form>\n            <fieldset>\n                <p>\n                    My favorite colors are <input-inline name=\"color1\" value=\"green\"></input-inline> \n                    and <input-inline name=\"color2\" value=\"purple\"></input-inline>.\n                </p>\n                <button type=\"submit\">Submit</button>\n                <button type=\"reset\">Reset</button>\n            </fieldset>\n            <p>\n                Disabled:\n                <button type=\"button\" onclick=\"toggleDisabled('fieldset')\">Toggle fieldset</button>\n                <button type=\"button\" onclick=\"toggleDisabled('[name=color1]')\">Toggle control 1</button>\n                <button type=\"button\" onclick=\"toggleDisabled('[name=color2]')\">Toggle control 2</button>\n            </p>\n            <p>\n                Readonly:\n                <button type=\"button\" onclick=\"toggleReadOnly('[name=color1]')\">Toggle control 1</button>\n                <button type=\"button\" onclick=\"toggleReadOnly('[name=color2]')\">Toggle control 2</button>\n            </p>\n        </form>\n        <br />\n        <p id=\"result\"></p>\n        <script src=\"input-inline.js\"></script>\n        <script>\n            document.querySelector('form').onsubmit = (e) => {\n                e.preventDefault();\n                const data = new FormData(e.target);\n                const obj = Object.fromEntries(data.entries());\n                document.getElementById('result').textContent = \n                    'Submitted: ' + JSON.stringify(obj);\n            }\n\n            function toggleDisabled(selector) {\n                const elem = document.querySelector(selector);\n                elem.disabled = !elem.disabled;\n            }\n\n            function toggleReadOnly(selector) {\n                const elem = document.querySelector(selector);\n                elem.readOnly = !elem.readOnly;\n            }\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo4/input-inline-partial.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    /* ... */\n\n    #formDisabled = false;\n    #value;\n\n    set value(v) {\n        if (this.#value !== String(v)) {\n            this.#value = String(v);\n            this.#update();    \n        }\n    }\n    get value() {\n        return this.#value ?? this.defaultValue;\n    }\n\n    get defaultValue() {\n        return this.getAttribute('value') ?? '';\n    }\n    set defaultValue(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    set disabled(v) {\n        if (v) {\n            this.setAttribute('disabled', 'true');\n        } else {\n            this.removeAttribute('disabled');\n        }\n    }\n    get disabled() {\n        return this.hasAttribute('disabled');\n    }\n\n    set readOnly(v) {\n        if (v) {\n            this.setAttribute('readonly', 'true');\n        } else {\n            this.removeAttribute('readonly');\n        }\n    }\n    get readOnly() {\n        return this.hasAttribute('readonly');\n    }\n\n    /* ... */\n\n    static observedAttributes = ['value', 'disabled', 'readonly'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        this.textContent = this.value;\n        this.#internals.setFormValue(this.value);\n\n        const isDisabled = this.#formDisabled || this.disabled;\n        this.#internals.ariaDisabled = isDisabled;\n        this.#internals.ariaReadOnly = this.readOnly;\n        this.contentEditable = !this.readOnly && !isDisabled && 'plaintext-only';\n        this.tabIndex = isDisabled ? -1 : 0;\n    }\n\n    static formAssociated = true;\n\n    formResetCallback() {\n        this.#value = undefined;\n        this.#update();\n    }\n    \n    formDisabledCallback(disabled) {\n        this.#formDisabled = disabled;\n        this.#update();\n    }\n    \n    formStateRestoreCallback(state) {\n        this.#value = state ?? undefined;\n        this.#update();\n    }\n});\n\n/* ... */"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo4/input-inline.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    #shouldFireChange = false;\n    #internals;\n    #formDisabled = false;\n    #value;\n\n    set value(v) {\n        if (this.#value !== String(v)) {\n            this.#value = String(v);\n            this.#update();    \n        }\n    }\n    get value() {\n        return this.#value ?? this.defaultValue;\n    }\n\n    get defaultValue() {\n        return this.getAttribute('value') ?? '';\n    }\n    set defaultValue(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    set disabled(v) {\n        if (v) {\n            this.setAttribute('disabled', 'true');\n        } else {\n            this.removeAttribute('disabled');\n        }\n    }\n    get disabled() {\n        return this.hasAttribute('disabled');\n    }\n\n    set readOnly(v) {\n        if (v) {\n            this.setAttribute('readonly', 'true');\n        } else {\n            this.removeAttribute('readonly');\n        }\n    }\n    get readOnly() {\n        return this.hasAttribute('readonly');\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n        // add event listeners\n        this.addEventListener('input', this);\n        this.addEventListener('keydown', this);\n        this.addEventListener('paste', this);\n        this.addEventListener('focusout', this);\n    }\n\n    handleEvent(e) {\n        switch (e.type) {\n            // respond to user input (typing, drag-and-drop, paste)\n            case 'input':\n                this.value = cleanTextContent(this.textContent);\n                this.#shouldFireChange = true;\n                break;\n            // enter key should submit form instead of adding a new line\n            case 'keydown':\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    this.#internals.form?.requestSubmit();\n                }\n                break;\n            // prevent pasting rich text (firefox), or newlines (all browsers)\n            case 'paste':\n                e.preventDefault();\n                const text = e.clipboardData.getData('text/plain')\n                    // replace newlines and tabs with spaces\n                    .replace(/[\\n\\r\\t]+/g, ' ')\n                    // limit length of pasted text to something reasonable\n                    .substring(0, 1000);\n                // shadowRoot.getSelection is non-standard, fallback to document in firefox\n                // https://stackoverflow.com/a/70523247\n                let selection = this.getRootNode()?.getSelection?.() || document.getSelection();\n                let range = selection.getRangeAt(0);\n                range.deleteContents();\n                range.insertNode(document.createTextNode(text));\n                // manually trigger input event to restore default behavior\n                this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n                break;\n            // fire change event on blur\n            case 'focusout':\n                if (this.#shouldFireChange) {\n                    this.#shouldFireChange = false;\n                    this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n                }\n                break;\n        }\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value', 'disabled', 'readonly'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (cleanTextContent(this.textContent) !== this.value) {\n            this.textContent = this.value;\n        }\n        this.#internals.setFormValue(this.value);\n\n        const isDisabled = this.#formDisabled || this.disabled;\n        this.#internals.ariaDisabled = isDisabled;\n        this.#internals.ariaReadOnly = this.readOnly;\n        this.contentEditable = !this.readOnly && !isDisabled && 'plaintext-only';\n        this.tabIndex = isDisabled ? -1 : 0;\n    }\n\n    static formAssociated = true;\n\n    formResetCallback() {\n        this.#value = undefined;\n        this.#update();\n    }\n    \n    formDisabledCallback(disabled) {\n        this.#formDisabled = disabled;\n        this.#update();\n    }\n    \n    formStateRestoreCallback(state) {\n        this.#value = state ?? undefined;\n        this.#update();\n    }\n});\n\nfunction cleanTextContent(text) {\n    return (text ?? '')\n        // replace newlines and tabs with spaces\n        .replace(/[\\n\\r\\t]+/g, ' ')\n        // remove zero width spaces\n        .replace(/\\u200B/g, '');\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo5/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 5</title>\n        <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n        <link rel=\"stylesheet\" href=\"input-inline.css\">\n        <style>\n            form {\n                max-width: 450px;\n            }\n            fieldset {\n                margin-bottom: 1em;\n            }\n        </style>\n    </head>\n    <body>\n        <form>\n            <fieldset>\n                <p>\n                    My favorite colors are <input-inline name=\"color1\" value=\"green\"></input-inline> \n                    and <input-inline name=\"color2\" value=\"purple\"></input-inline>.\n                </p>\n                <button type=\"submit\">Submit</button>\n                <button type=\"reset\">Reset</button>\n            </fieldset>\n            <p>\n                Disabled:\n                <button type=\"button\" onclick=\"toggleDisabled('fieldset')\">Toggle fieldset</button>\n                <button type=\"button\" onclick=\"toggleDisabled('[name=color1]')\">Toggle control 1</button>\n                <button type=\"button\" onclick=\"toggleDisabled('[name=color2]')\">Toggle control 2</button>\n            </p>\n            <p>\n                Readonly:\n                <button type=\"button\" onclick=\"toggleReadOnly('[name=color1]')\">Toggle control 1</button>\n                <button type=\"button\" onclick=\"toggleReadOnly('[name=color2]')\">Toggle control 2</button>\n            </p>\n        </form>\n        <br />\n        <p id=\"result\"></p>\n        <script src=\"input-inline.js\"></script>\n        <script>\n            document.querySelector('form').onsubmit = (e) => {\n                e.preventDefault();\n                const data = new FormData(e.target);\n                const obj = Object.fromEntries(data.entries());\n                document.getElementById('result').textContent = \n                    'Submitted: ' + JSON.stringify(obj);\n            }\n\n            function toggleDisabled(selector) {\n                const elem = document.querySelector(selector);\n                elem.disabled = !elem.disabled;\n            }\n\n            function toggleReadOnly(selector) {\n                const elem = document.querySelector(selector);\n                elem.readOnly = !elem.readOnly;\n            }\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo5/input-inline.css",
    "content": "/* default styling has lowest priority */\n@layer {\n    :root {\n        --input-inline-border-color: light-dark(rgb(118, 118, 118), rgb(161, 161, 161));\n        --input-inline-border-color-hover: light-dark(rgb(78, 78, 78), rgb(200, 200, 200));\n        --input-inline-border-color-disabled: rgba(150, 150, 150, 0.5);\n        --input-inline-text-color: light-dark(fieldtext, rgb(240, 240, 240));\n        --input-inline-text-color-disabled: light-dark(rgb(84, 84, 84), rgb(170, 170, 170));\n        --input-inline-bg-color: inherit;\n        --input-inline-bg-color-disabled: inherit;\n        --input-inline-min-width: 4ch;\n    }\n\n    input-inline {\n        display: inline;\n        background-color: var(--input-inline-bg-color);\n        color: var(--input-inline-text-color);\n        border: 1px dotted var(--input-inline-border-color);\n        padding: 2px 3px;\n        margin-bottom: -2px;\n        border-radius: 3px;\n        /* minimum width */\n        padding-right: max(3px, calc(var(--input-inline-min-width) - var(--current-length)));\n\n        &:hover {\n            border-color: var(--input-inline-border-color-hover);\n        }\n    \n        &:disabled {\n            border-color: var(--input-inline-border-color-disabled);\n            background-color: var(--input-inline-bg-color-disabled);\n            color: var(--input-inline-text-color-disabled);\n            -webkit-user-select: none;\n            user-select: none;\n        }\n    \n        &:focus-visible {\n            border-color: transparent;\n            outline-offset: 0;\n            outline: 2px solid royalblue; /* firefox */\n            outline-color: -webkit-focus-ring-color; /* the rest */\n        }\n    }\n\n    @media screen and (-webkit-min-device-pixel-ratio:0) {\n        input-inline:empty::before {\n            /* fixes issue where empty input-inline shifts left in chromium browsers */\n            content: \" \";\n        }\n    }\n\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo5/input-inline.js",
    "content": "customElements.define('input-inline', class extends HTMLElement {\n    \n    #shouldFireChange = false;\n    #internals;\n    #formDisabled = false;\n    #value;\n\n    set value(v) {\n        if (this.#value !== String(v)) {\n            this.#value = String(v);\n            this.#update();    \n        }\n    }\n    get value() {\n        return this.#value ?? this.defaultValue;\n    }\n\n    get defaultValue() {\n        return this.getAttribute('value') ?? '';\n    }\n    set defaultValue(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    set disabled(v) {\n        if (v) {\n            this.setAttribute('disabled', 'true');\n        } else {\n            this.removeAttribute('disabled');\n        }\n    }\n    get disabled() {\n        return this.hasAttribute('disabled');\n    }\n\n    set readOnly(v) {\n        if (v) {\n            this.setAttribute('readonly', 'true');\n        } else {\n            this.removeAttribute('readonly');\n        }\n    }\n    get readOnly() {\n        return this.hasAttribute('readonly');\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n        // add event listeners\n        this.addEventListener('input', this);\n        this.addEventListener('keydown', this);\n        this.addEventListener('paste', this);\n        this.addEventListener('focusout', this);\n    }\n\n    handleEvent(e) {\n        switch (e.type) {\n            // respond to user input (typing, drag-and-drop, paste)\n            case 'input':\n                this.value = cleanTextContent(this.textContent);\n                this.#shouldFireChange = true;\n                break;\n            // enter key should submit form instead of adding a new line\n            case 'keydown':\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    this.#internals.form?.requestSubmit();\n                }\n                break;\n            // prevent pasting rich text (firefox), or newlines (all browsers)\n            case 'paste':\n                e.preventDefault();\n                const text = e.clipboardData.getData('text/plain')\n                    // replace newlines and tabs with spaces\n                    .replace(/[\\n\\r\\t]+/g, ' ')\n                    // limit length of pasted text to something reasonable\n                    .substring(0, 1000);\n                // shadowRoot.getSelection is non-standard, fallback to document in firefox\n                // https://stackoverflow.com/a/70523247\n                let selection = this.getRootNode()?.getSelection?.() || document.getSelection();\n                let range = selection.getRangeAt(0);\n                range.deleteContents();\n                range.insertNode(document.createTextNode(text));\n                // manually trigger input event to restore default behavior\n                this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n                break;\n            // fire change event on blur\n            case 'focusout':\n                if (this.#shouldFireChange) {\n                    this.#shouldFireChange = false;\n                    this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n                }\n                break;\n        }\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value', 'disabled', 'readonly'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (cleanTextContent(this.textContent) !== this.value) {\n            this.textContent = this.value;\n        }\n        this.#internals.setFormValue(this.value);\n\n        const isDisabled = this.#formDisabled || this.disabled;\n        this.#internals.ariaDisabled = isDisabled;\n        this.#internals.ariaReadOnly = this.readOnly;\n        this.contentEditable = !this.readOnly && !isDisabled && 'plaintext-only';\n        this.tabIndex = isDisabled ? -1 : 0;\n\n        const length = cleanTextContent(this.textContent).length || 0;\n        this.style.setProperty('--current-length', `${length}ch`);\n    }\n\n    static formAssociated = true;\n\n    formResetCallback() {\n        this.#value = undefined;\n        this.#update();\n    }\n    \n    formDisabledCallback(disabled) {\n        this.#formDisabled = disabled;\n        this.#update();\n    }\n    \n    formStateRestoreCallback(state) {\n        this.#value = state ?? undefined;\n        this.#update();\n    }\n});\n\nfunction cleanTextContent(text) {\n    return (text ?? '')\n        // replace newlines and tabs with spaces\n        .replace(/[\\n\\r\\t]+/g, ' ')\n        // remove zero width spaces\n        .replace(/\\u200B/g, '');\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo6/index-partial.txt",
    "content": "<form>\n    <p>\n        My favorite color is <input-inline name=\"color1\" value=\"green\" required></input-inline>.\n    </p>\n    <button type=\"submit\">Submit</button>\n    <button type=\"reset\">Reset</button>\n</form>"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo6/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\">\n        <title>demo 6</title>\n        <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n        <link rel=\"stylesheet\" href=\"input-inline.css\">\n        <style>\n            form {\n                max-width: 450px;\n            }\n            fieldset {\n                margin-bottom: 1em;\n            }\n            input-inline:invalid {\n                border-color: red;\n            }\n        </style>\n    </head>\n    <body>\n        <form>\n            <p>\n                My favorite color is <input-inline name=\"color1\" value=\"\" required></input-inline>.\n            </p>\n            <button type=\"submit\">Submit</button>\n            <button type=\"reset\">Reset</button>\n        </form>\n        <p style=\"margin: 0.5em 0;\">\n            <button type=\"button\" onclick=\"setInvalid('[name=color1]', 'Oops, wrong!')\">Set custom validity message</button> \n            <button type=\"button\" onclick=\"setInvalid('[name=color1]', '')\">Clear custom validity message</button>\n        </p>\n        <p id=\"result\"></p>\n        <script src=\"input-inline.js\"></script>\n        <script>\n            document.querySelector('form').onsubmit = (e) => {\n                e.preventDefault();\n                const data = new FormData(e.target);\n                const obj = Object.fromEntries(data.entries());\n                document.getElementById('result').textContent = \n                    'Submitted: ' + JSON.stringify(obj);\n            }\n            function setInvalid(selector, message) {\n                const elem = document.querySelector(selector);\n                elem.setCustomValidity(message);\n            }\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo6/input-inline-partial.js",
    "content": "let VALUE_MISSING_MESSAGE = 'Please fill out this field.';\n(() => {\n    const input = document.createElement('input');\n    input.required = true;\n    input.reportValidity();\n    VALUE_MISSING_MESSAGE = input.validationMessage;\n})();\n\nconst isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\ncustomElements.define('input-inline', class extends HTMLElement {\n    \n    /* ... */\n\n    #customValidityMessage = '';\n\n    /* ... */\n\n    set required(v) {\n        if (v) {\n            this.setAttribute('required', 'true');\n        } else {\n            this.removeAttribute('required');\n        }\n    }\n    get required() {\n        return this.hasAttribute('required');\n    }\n\n    /* ... */\n\n    static observedAttributes = ['value', 'disabled', 'readonly', 'required'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        /* ... */\n\n        this.#internals.ariaRequired = this.required;\n        this.#updateValidity();\n    }\n\n    /* ... */\n\n    #updateValidity() {\n        const state = {};\n        let message = '';\n\n        // custom validity message overrides all else\n        if (this.#customValidityMessage) {\n            state.customError = true;\n            message = this.#customValidityMessage;\n        } else {\n            if (this.required && !this.value) {\n                state.valueMissing = true;\n                message = VALUE_MISSING_MESSAGE;\n            }\n    \n            // add other checks here if needed (e.g., pattern, minLength)\n        }\n\n        // safari needs a focusable validation anchor to show the validation message on form submit\n        // and it must be a descendant of the input\n        let anchor = undefined;\n        if (isSafari) {\n            anchor = this.querySelector('span[aria-hidden]');\n            if (!anchor) {\n                anchor = document.createElement('span');\n                anchor.ariaHidden = true;\n                anchor.tabIndex = 0;\n                this.append(anchor);\n            }\n        }\n\n        this.#internals.setValidity(state, message, anchor);\n    }\n\n    checkValidity() {\n        this.#updateValidity();\n        return this.#internals.checkValidity();\n    }\n\n    reportValidity() {\n        this.#updateValidity();\n        return this.#internals.reportValidity();\n    }\n\n    setCustomValidity(message) {\n        this.#customValidityMessage = message ?? '';\n        this.#updateValidity();\n    }\n\n    get validity() {\n        return this.#internals.validity;\n    }\n\n    get validationMessage() {\n        return this.#internals.validationMessage;\n    }\n\n    get willValidate() {\n        return this.#internals.willValidate;\n    }\n});\n\n/* ... */"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo6/input-inline.css",
    "content": "/* default styling has lowest priority */\n@layer {\n    :root {\n        --input-inline-border-color: light-dark(rgb(118, 118, 118), rgb(161, 161, 161));\n        --input-inline-border-color-hover: light-dark(rgb(78, 78, 78), rgb(200, 200, 200));\n        --input-inline-border-color-disabled: rgba(150, 150, 150, 0.5);\n        --input-inline-text-color: light-dark(fieldtext, rgb(240, 240, 240));\n        --input-inline-text-color-disabled: light-dark(rgb(84, 84, 84), rgb(170, 170, 170));\n        --input-inline-bg-color: inherit;\n        --input-inline-bg-color-disabled: inherit;\n        --input-inline-min-width: 4ch;\n    }\n\n    input-inline {\n        display: inline;\n        background-color: var(--input-inline-bg-color);\n        color: var(--input-inline-text-color);\n        border: 1px dotted var(--input-inline-border-color);\n        padding: 2px 3px;\n        margin-bottom: -2px;\n        border-radius: 3px;\n        /* minimum width */\n        padding-right: max(3px, calc(var(--input-inline-min-width) - var(--current-length)));\n\n        &:hover {\n            border-color: var(--input-inline-border-color-hover);\n        }\n    \n        &:disabled {\n            border-color: var(--input-inline-border-color-disabled);\n            background-color: var(--input-inline-bg-color-disabled);\n            color: var(--input-inline-text-color-disabled);\n            -webkit-user-select: none;\n            user-select: none;\n        }\n    \n        &:focus-visible {\n            border-color: transparent;\n            outline-offset: 0;\n            outline: 2px solid royalblue; /* firefox */\n            outline-color: -webkit-focus-ring-color; /* the rest */\n        }\n    }\n\n    @media screen and (-webkit-min-device-pixel-ratio:0) {\n        input-inline:empty::before {\n            /* fixes issue where empty input-inline shifts left in chromium browsers */\n            content: \" \";\n        }\n    }\n\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/demo6/input-inline.js",
    "content": "let VALUE_MISSING_MESSAGE = 'Please fill out this field.';\n(() => {\n    const input = document.createElement('input');\n    input.required = true;\n    input.reportValidity();\n    VALUE_MISSING_MESSAGE = input.validationMessage;\n})();\n\nconst isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\ncustomElements.define('input-inline', class extends HTMLElement {\n    \n    #shouldFireChange = false;\n    #internals;\n    #formDisabled = false;\n    #value;\n    #customValidityMessage = '';\n\n    set value(v) {\n        if (this.#value !== String(v)) {\n            this.#value = String(v);\n            this.#update();    \n        }\n    }\n    get value() {\n        return this.#value ?? this.defaultValue;\n    }\n\n    get defaultValue() {\n        return this.getAttribute('value') ?? '';\n    }\n    set defaultValue(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    set disabled(v) {\n        if (v) {\n            this.setAttribute('disabled', 'true');\n        } else {\n            this.removeAttribute('disabled');\n        }\n    }\n    get disabled() {\n        return this.hasAttribute('disabled');\n    }\n\n    set readOnly(v) {\n        if (v) {\n            this.setAttribute('readonly', 'true');\n        } else {\n            this.removeAttribute('readonly');\n        }\n    }\n    get readOnly() {\n        return this.hasAttribute('readonly');\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n\n    set required(v) {\n        if (v) {\n            this.setAttribute('required', 'true');\n        } else {\n            this.removeAttribute('required');\n        }\n    }\n    get required() {\n        return this.hasAttribute('required');\n    }\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n        // add event listeners\n        this.addEventListener('input', this);\n        this.addEventListener('keydown', this);\n        this.addEventListener('paste', this);\n        this.addEventListener('focusout', this);\n    }\n\n    handleEvent(e) {\n        switch (e.type) {\n            // respond to user input (typing, drag-and-drop, paste)\n            case 'input':\n                this.value = cleanTextContent(this.textContent);\n                this.#shouldFireChange = true;\n                break;\n            // enter key should submit form instead of adding a new line\n            case 'keydown':\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    this.#internals.form?.requestSubmit();\n                }\n                break;\n            // prevent pasting rich text (firefox), or newlines (all browsers)\n            case 'paste':\n                e.preventDefault();\n                const text = e.clipboardData.getData('text/plain')\n                    // replace newlines and tabs with spaces\n                    .replace(/[\\n\\r\\t]+/g, ' ')\n                    // limit length of pasted text to something reasonable\n                    .substring(0, 1000);\n                // shadowRoot.getSelection is non-standard, fallback to document in firefox\n                // https://stackoverflow.com/a/70523247\n                let selection = this.getRootNode()?.getSelection?.() || document.getSelection();\n                let range = selection.getRangeAt(0);\n                range.deleteContents();\n                range.insertNode(document.createTextNode(text));\n                // manually trigger input event to restore default behavior\n                this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n                break;\n            // fire change event on blur\n            case 'focusout':\n                if (this.#shouldFireChange) {\n                    this.#shouldFireChange = false;\n                    this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n                }\n                break;\n        }\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value', 'disabled', 'readonly', 'required'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (cleanTextContent(this.textContent) !== this.value) {\n            this.textContent = this.value;\n        }\n        this.#internals.setFormValue(this.value);\n\n        const isDisabled = this.#formDisabled || this.disabled;\n        this.#internals.ariaDisabled = isDisabled;\n        this.#internals.ariaReadOnly = this.readOnly;\n        this.contentEditable = !this.readOnly && !isDisabled && 'plaintext-only';\n        this.tabIndex = isDisabled ? -1 : 0;\n\n        const length = cleanTextContent(this.textContent).length || 0;\n        this.style.setProperty('--current-length', `${length}ch`);\n\n        this.#internals.ariaRequired = this.required;\n        this.#updateValidity();\n    }\n\n    static formAssociated = true;\n\n    formResetCallback() {\n        this.#value = undefined;\n        this.#update();\n    }\n    \n    formDisabledCallback(disabled) {\n        this.#formDisabled = disabled;\n        this.#update();\n    }\n    \n    formStateRestoreCallback(state) {\n        this.#value = state ?? undefined;\n        this.#update();\n    }\n\n    #updateValidity() {\n        const state = {};\n        let message = '';\n\n        // custom validity message overrides all else\n        if (this.#customValidityMessage) {\n            state.customError = true;\n            message = this.#customValidityMessage;\n        } else {\n            if (this.required && !this.value) {\n                state.valueMissing = true;\n                message = VALUE_MISSING_MESSAGE;\n            }\n    \n            // add other checks here if needed (e.g., pattern, minLength)\n        }\n\n        // safari needs a focusable validation anchor to show the validation message on form submit\n        // and it must be a descendant of the input\n        let anchor = undefined;\n        if (isSafari) {\n            anchor = this.querySelector('span[aria-hidden]');\n            if (!anchor) {\n                anchor = document.createElement('span');\n                anchor.ariaHidden = true;\n                anchor.tabIndex = 0;\n                this.append(anchor);\n            }\n        }\n\n        this.#internals.setValidity(state, message, anchor);\n    }\n\n    checkValidity() {\n        this.#updateValidity();\n        return this.#internals.checkValidity();\n    }\n\n    reportValidity() {\n        this.#updateValidity();\n        return this.#internals.reportValidity();\n    }\n\n    setCustomValidity(message) {\n        this.#customValidityMessage = message ?? '';\n        this.#updateValidity();\n    }\n\n    get validity() {\n        return this.#internals.validity;\n    }\n\n    get validationMessage() {\n        return this.#internals.validationMessage;\n    }\n\n    get willValidate() {\n        return this.#internals.willValidate;\n    }\n});\n\nfunction cleanTextContent(text) {\n    return (text ?? '')\n        // replace newlines and tabs with spaces\n        .replace(/[\\n\\r\\t]+/g, ' ')\n        // remove zero width spaces\n        .replace(/\\u200B/g, '');\n}\n"
  },
  {
    "path": "public/blog/articles/2025-05-09-form-control/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Making a new form control</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"Building a form control as a custom element.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n</head>\n<body>\n    <blog-header published=\"2025-05-09\">\n        <img src=\"image.webp\" alt=\"A MAD magazine cover of people working hard at a gym.\" loading=\"lazy\" />\n        <h2>Making a new form control</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            There are some things that a web developer <em>knows</em> they shouldn't attempt.\n            Making clever use of contenteditable. Building custom form controls. Making complicated custom elements without a framework.\n            But do we really know what we think we know? Why not try to do all three, just for fun? Could it really be that bad?\n        </p>\n        <p><em>Narrator: it would indeed be that bad.</em></p>\n        <p>\n            This article is building on the previous one on proper <a href=\"../2025-04-21-attribute-property-duality/\">attribute/property relations</a> in custom elements.\n            Read that first if you haven't yet. In this piece we're taking it a step further to build a custom element that handles input.\n            The mission is simple: implement a basic version of <code>&lt;input type=\"text\" /&gt;</code> but with <code>display: inline</code> layout.\n        </p>\n\n        <h3>A simple element</h3>\n        \n        <p>\n            Let's start by just throwing something against the wall and playing around with it.\n        </p>\n        <x-code-viewer src=\"demo1/input-inline.js\"></x-code-viewer>\n        <p>\n            And here's how we use it:<br>\n        </p>\n        <x-code-viewer src=\"demo1/index-partial.txt\" name=\"\"></x-code-viewer>\n        <iframe src=\"demo1/index.html\" title=\"demo1\"></iframe>\n\n        <p>\n            This is simple, clean, and horribly broken. For one, the form cannot see these controls at all and submits the empty object.\n        </p>\n\n        <h3>Form-associated elements</h3>\n\n        <p>\n            To fix that, we have to make a <a href=\"https://html.spec.whatwg.org/dev/custom-elements.html#custom-elements-face-example\">form-associated custom element</a>.\n            This is done through the magic of the <code>formAssociated</code> property and <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals\">ElementInternals</a>.\n        </p>\n\n        <x-code-viewer src=\"demo2/input-inline-partial.js\" name=\"input-inline.js\"></x-code-viewer>\n        <iframe src=\"demo2/index.html\" title=\"demo2\"></iframe>\n\n        <p>\n            <code>ElementInternals</code> offers a control surface for setting the behavior of our custom element as part of a form.\n            The <code>this.#internals.role = 'textbox'</code> assignment sets a default role that can be overridden by the element's user through the <code>role</code> attribute or property, just like for built-in form controls.\n            By calling <code>this.#internals.setFormValue</code> every time the control's value changes the form will know what value to submit.\n            But ... while the form does submit the values for our controls now, it does not see the changes we make. That's because we aren't responding to input yet.\n        </p>\n\n        <h3>Looking for input</h3>\n\n        <p>\n            Ostensibly responding to input is just adding a few event listeners in <code>connectedCallback</code> and removing them again in <code>disconnectedCallback</code>.\n            But doing it that way quickly gets verbose. An easy alternative is to instead rely on some of the built-in event logic magic,\n            namely that events bubble and that <a href=\"https://gregdaynes.com/note/2024/07/29/web-components.html\">objects can be listeners too</a>.\n        </p>\n\n        <x-code-viewer src=\"demo3/input-inline-partial.js\" name=\"input-inline.js\"></x-code-viewer>\n        <iframe src=\"demo3/index.html\" title=\"demo3\"></iframe>\n\n        <p>\n            I prefer this pattern because it simplifies the code a lot compared to having separate handler functions.\n            Attaching event listeners in the constructor instead of attaching and detaching them in the lifecycle callbacks is another simplification. \n            It may seem like blasphemy to never clean up the event listeners, but DOM event listeners\n            are weakly bound and garbage collection of the element can still occur with them attached. So this is fine.\n        </p>\n        <p>\n            In the event handler logic there's some verbosity to deal with the fallout of working with contenteditable.\n            As this code is not the focus of this article, I won't dally on it except to remark that contenteditable is still just as annoying as you thought it was.\n        </p>\n        <p>\n            With these changes our element will now also emit <code>input</code> and <code>change</code> events just like a built-in HTML form control.\n            But, you may have noticed another issue has cropped up. The standard form reset button does not actually reset the form.\n        </p>\n\n        <h3>Read the instructions</h3>\n\n        <p>\n            You see, when we said <code>static formAssociated = true</code> we entered into a contract to faithfully implement the expected behavior of a form control.\n            That means we have a bunch of extra work to do.\n        </p>\n\n        <x-code-viewer src=\"demo4/input-inline-partial.js\" name=\"input-inline.js\"></x-code-viewer>\n        <iframe src=\"demo4/index.html\" title=\"demo4\" height=\"250\"></iframe>\n\n        <p>\n            There's a LOT going on there. It's too much to explain, so let me sum up.\n        </p>\n        <ul>\n            <li>The <code>value</code> attribute now corresponds to a <code>defaultValue</code> property, which is the value shown until changed and also the value that the form will reset the field to.</li>\n            <li>The <code>value</code> property contains only the modified value and does not correspond to an attribute.</li>\n            <li>The control can be marked disabled or read-only through attribute or property.</li>\n            <li>The form callbacks are implemented, so the control can be reset to its default value, will restore its last value after back-navigation, and will disable itself when it is in a disabled fieldset.</li>\n        </ul>\n\n        <h3>With some style</h3>\n\n        <p>\n            Up to this point we've been using some stand-in styling.\n            However, it would be nice to have some default styling that can be bundled with our custom form control.\n            Something like this:\n        </p>\n\n        <x-code-viewer src=\"demo5/input-inline.css\"></x-code-viewer>\n        <iframe src=\"demo5/index.html\" title=\"demo5\" height=\"250\"></iframe>\n\n        <p>\n            The styles are isolated by scoping them to the name of our custom element, \n            and the use of @layer puts them at the lowest priority, so that any user style will override the default style,\n            just like for the built-in form controls. The use of variables offers an additional way to quickly restyle the control.\n        </p>\n        <p>\n            In the styling we also see the importance of properly thinking out disabled and focused state behavior.\n            The upside and downside of building a custom form control is that we get to implement all the behavior that's normally built-in to the browser.\n        </p>\n        <p>\n            We're now past the 150 lines mark, just to get to the low bar of implementing the browser's mandatory form control behavior.\n            So, are we done? Well, not quite. There's still one thing that form controls do, and although it's optional it's also kind of required.\n        </p>\n\n        <h3>Validation</h3>\n\n        <p>\n            Built-in form controls come with a validity API. To get an idea of what it means to implement it \n            in a custom form control, let's add one validation attribute: <code>required</code>.\n            It doesn't seem like it should take a lot of work, right?\n        </p>\n\n        <x-code-viewer src=\"demo6/input-inline-partial.js\" name=\"input-inline.js\"></x-code-viewer>\n        <iframe src=\"demo6/index.html\" title=\"demo6\" height=\"200\"></iframe>\n        <p>\n            The code for the example is exactly like it would be for built-in controls:\n        </p>\n        <x-code-viewer src=\"demo6/index-partial.txt\" name=\"\"></x-code-viewer>\n\n        <p>\n            The <code>ElementInternals</code> interface is doing a lot of the work here, but we still have to proxy its methods and properties.\n            You can tell however that by this point we're deep in the weeds of custom elements, because of the rough edges.\n        </p>\n        <ul>\n            <li>The example is using the <code>input-inline:invalid</code> style instead of <code>:user-invalid</code> because\n            <a href=\"https://github.com/whatwg/html/issues/9639\">:user-invalid is not supported</a> on custom elements yet.</li>\n            <li>An ugly hack is needed to get the properly localized message for a required field that matches that of built-in controls.</li>\n            <li>Safari flat-out won't show validation messages on non-shadowed form-associated custom elements if we don't give it an anchor to set them to, requiring another ugly hack.</li>\n        </ul>\n\n        <h3>In conclusion</h3>\n\n        <p>\n            We've established by now that it is indeed feasible to build a custom form control and have it take part in regular HTML forms,\n            but also that it is a path surrounded by peril as well as laborious to travel.\n            Whether it is worth doing is in the eye of the beholder.\n        </p>\n        <p>\n            Along that path we also learned some lessons on how to handle input in custom elements, and have proven yet again that <code>contenteditable</code>,\n            while less painful than it once was, is an attribute that can only be used in anger.\n        </p>\n        <p>\n            Regardless, the full source code of the <code>input-inline</code> form control <a href=\"https://github.com/jsebrech/input-inline\">is on GitHub</a>.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/114479668425959461\"></blog-footer>\n    <script type=\"module\" src=\"../../index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example1/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 1</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <style>\n        @import \"../../../../styles/reset.css\";\n        ::view-transition-old(root),\n        ::view-transition-new(root) {\n            animation-duration: 0.5s;\n        }\n        body {\n            margin: 1em;\n        }\n        button {\n            -webkit-user-select: none;\n            user-select: none;\n            margin-bottom: 1em;\n        }\n        .square {\n            width: 100px;\n            height: 100px;\n        }\n    </style>\n    <link rel=\"stylesheet\" href=\"transitions.css\">\n</head>\n<body>\n    <button onclick=\"transition()\">Transition</button>\n    <div id=\"square1\" class=\"square\"></div>\n    <script src=\"index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example1/index.js",
    "content": "function transition() {\n    const square1 = document.getElementById('square1');\n    if (document.startViewTransition) {\n        document.startViewTransition(() => {\n            square1.classList.toggle('toggled');\n        });\n    } else {\n        square1.classList.toggle('toggled');\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example1/transitions.css",
    "content": "#square1 {\n    background-color: orange;\n}\n#square1.toggled {\n    background-color: blue;\n}"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example2/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 2</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <style>\n        @import \"../../../../styles/reset.css\";\n        ::view-transition-old(root),\n        ::view-transition-new(root) {\n            animation-duration: 0.5s;\n        }\n        body {\n            margin: 1em;\n        }\n        div {\n            display: inline-block;\n        }\n        button {\n            -webkit-user-select: none;\n            user-select: none;\n            margin-bottom: 1em;\n        }\n        .square {\n            width: 100px;\n            height: 100px;\n        }\n        #square1 {\n            background-color: orange;\n        }\n        #square1.toggled {\n            background-color: blue;\n        }\n    </style>\n    <link rel=\"stylesheet\" href=\"transitions.css\">\n</head>\n<body>\n    <p>\n        <button onclick=\"transition()\">Transition</button>\n    </p>\n    <div id=\"square1\" class=\"square\"></div>\n    <div id=\"square2\" class=\"square\"></div>\n    <script src=\"index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example2/index.js",
    "content": "function transition() {\n    const square1 = document.getElementById('square1');\n    const square2 = document.getElementById('square2');\n    if (document.startViewTransition) {\n        document.startViewTransition(() => {\n            square1.classList.toggle('toggled');\n            square2.classList.toggle('toggled');\n        });\n    } else {\n        square1.classList.toggle('toggled');\n        square2.classList.toggle('toggled');\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example2/transitions.css",
    "content": "#square2 {\n    background-color: green;\n    view-transition-name: slide;\n    display: none;\n}\n#square2.toggled {\n    display: inline-block;\n}\n::view-transition-new(slide):only-child {\n    animation: 400ms ease-in both slide-in;\n}\n@keyframes slide-in {\n    from { transform: translateY(-200px); }\n    to { transform: translateY(0); }\n}"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example3/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 3</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <style>\n        @import \"../../../../styles/reset.css\";\n        ::view-transition-old(root),\n        ::view-transition-new(root) {\n            animation-duration: 0.5s;\n        }\n        body {\n            margin: 1em;\n        }\n        div {\n            display: inline-block;\n        }\n        view-transition {\n            display: inline-block !important;\n        }\n        button {\n            -webkit-user-select: none;\n            user-select: none;\n            margin-bottom: 1em;\n        }\n        .square {\n            width: 100px;\n            height: 100px;\n        }\n        #square1 {\n            background-color: orange;\n        }\n        #square1.toggled {\n            background-color: blue;\n        }\n    </style>\n    <link rel=\"stylesheet\" href=\"transitions.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n        import { transition } from './index.js';\n\n        document.addEventListener('DOMContentLoaded', () => {\n            const root = document.getElementById('root');\n            root.innerHTML = `\n                <p><button>Transition</button></p>\n                <div id=\"square1\" class=\"square\"></div>\n                <div id=\"square2\" class=\"square\"></div>\n            `;\n            root.querySelector('button').onclick = transition;\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example3/index.js",
    "content": "import { startTransition } from './view-transition.js';\n\nexport function transition() {\n    startTransition(() => {\n        document.getElementById('square1').classList.toggle('toggled');\n        document.getElementById('square2').classList.toggle('toggled');\n    });\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example3/transitions.css",
    "content": "#square2 {\n    background-color: green;\n    view-transition-name: slide;\n    display: none;\n}\n#square2.toggled {\n    display: inline-block;\n}\n::view-transition-new(slide):only-child {\n    animation: 400ms ease-in both slide-in;\n}\n@keyframes slide-in {\n    from { transform: translateY(-200px); }\n    to { transform: translateY(0); }\n}"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example3/view-transition.js",
    "content": "export const startTransition = (updateCallback) => {\n    if (document.startViewTransition) {\n        document.startViewTransition(updateCallback);\n    } else {\n        const done = Promise.try(updateCallback);\n        return {\n            updateCallbackDone: done,\n            ready: done,\n            finished: done,\n            skipTransition: () => {}\n        };\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example4/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 4</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <style>\n        @import \"../../../../styles/reset.css\";\n        ::view-transition-old(root),\n        ::view-transition-new(root) {\n            animation-duration: 0.5s;\n        }\n        body {\n            margin: 1em;\n        }\n        div {\n            display: inline-block;\n        }\n        view-transition {\n            display: inline-block !important;\n        }\n        button {\n            -webkit-user-select: none;\n            user-select: none;\n            margin-bottom: 1em;\n        }\n        .route {\n            width: 100px;\n            height: 100px;\n        }\n        .route {\n            font-family: sans-serif;\n            font-size: 16px;\n            text-align: center;\n            padding: 1em;\n        }\n        #route1 {\n            background-color: blue;\n        }\n        #route2 {\n            background-color: limegreen;\n        }\n        #route2.loading {\n            background-color: green;\n        }\n    </style>\n    <link rel=\"stylesheet\" href=\"transitions.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n        import { navigate } from './index.js';\n\n        document.addEventListener('DOMContentLoaded', () => {\n            const root = document.getElementById('root');\n            root.innerHTML = `\n                <p><button>Navigate</button></p>\n                <div id=\"route1\" class=\"route\"></div>\n                <div id=\"route2\" class=\"route\"></div>\n            `;\n            root.querySelector('button').onclick = navigate;\n            navigate();\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example4/index.js",
    "content": "import { startTransition } from './view-transition.js';\n\nlet currentRoute = '';\n\nexport function navigate() {\n    currentRoute = currentRoute === 'route2' ? 'route1' : 'route2';\n    updateRoute1();\n    updateRoute2();\n}\n\nfunction updateRoute1() {\n    startTransition(() => {\n        if (currentRoute === 'route1') {\n            document.getElementById('route1').classList.add('active');\n        } else {\n            document.getElementById('route1').classList.remove('active');\n        }\n    });\n}\n\nfunction updateRoute2() {\n    startTransition(() => {\n        const route2 = document.getElementById('route2');\n        if (currentRoute === 'route2') {\n            route2.classList.add('active', 'loading');\n            route2.textContent = '...';\n            load().then((data) => startTransition(() => {\n                route2.textContent = data;\n                route2.classList.remove('loading');\n            }));\n        } else {\n            document.getElementById('route2').classList.remove('active');\n        }\n    });\n}\n\nfunction load() {\n    return new Promise((resolve) => {\n        setTimeout(() => {\n            resolve('Hi!');\n        }, 250);\n    });\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example4/transitions.css",
    "content": ".route {\n    display: none;\n}\n.route.active {\n    display: inline-block;\n}\n.route#route2 {\n    view-transition-name: slide;\n}\n::view-transition-new(slide):only-child {\n    animation: 400ms ease-in both slide-in;\n}\n@keyframes slide-in {\n    from { transform: translateY(-200px); }\n    to { transform: translateY(0); }\n}"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example4/view-transition.js",
    "content": "export const startTransition = (updateCallback) => {\n    if (document.startViewTransition) {\n        document.startViewTransition(updateCallback);\n    } else {\n        const done = Promise.try(updateCallback);\n        return {\n            updateCallbackDone: done,\n            ready: done,\n            finished: done,\n            skipTransition: () => {}\n        };\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example5/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 5</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <style>\n        @import \"../../../../styles/reset.css\";\n        ::view-transition-old(root),\n        ::view-transition-new(root) {\n            animation-duration: 0.5s;\n        }\n        body {\n            margin: 1em;\n        }\n        div {\n            display: inline-block;\n        }\n        view-transition {\n            display: inline-block !important;\n        }\n        button {\n            -webkit-user-select: none;\n            user-select: none;\n            margin-bottom: 1em;\n        }\n        .route {\n            width: 100px;\n            height: 100px;\n        }\n        .route {\n            font-family: sans-serif;\n            font-size: 16px;\n            text-align: center;\n            padding: 1em;\n        }\n        #route1 {\n            background-color: blue;\n        }\n        #route2 {\n            background-color: limegreen;\n        }\n        #route2.loading {\n            background-color: green;\n        }\n    </style>\n    <link rel=\"stylesheet\" href=\"transitions.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <div id=\"root\"></div>\n    <script type=\"module\">\n        import { navigate } from './index.js';\n\n        document.addEventListener('DOMContentLoaded', () => {\n            const root = document.getElementById('root');\n            root.innerHTML = `\n                <p><button>Navigate</button></p>\n                <div id=\"route1\" class=\"route\"></div>\n                <div id=\"route2\" class=\"route\"></div>\n            `;\n            root.querySelector('button').onclick = navigate;\n            navigate();\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example5/index.js",
    "content": "import { startTransition } from './view-transition.js';\n\nlet currentRoute = '';\n\nexport function navigate() {\n    currentRoute = currentRoute === 'route2' ? 'route1' : 'route2';\n    updateRoute1();\n    updateRoute2();\n}\n\nfunction updateRoute1() {\n    startTransition(() => {\n        if (currentRoute === 'route1') {\n            document.getElementById('route1').classList.add('active');\n        } else {\n            document.getElementById('route1').classList.remove('active');\n        }\n    });\n}\n\nfunction updateRoute2() {\n    startTransition(() => {\n        const route2 = document.getElementById('route2');\n        if (currentRoute === 'route2') {\n            route2.classList.add('active', 'loading');\n            route2.textContent = '...';\n            load().then((data) => startTransition(() => {\n                route2.textContent = data;\n                route2.classList.remove('loading');\n            }));\n        } else {\n            document.getElementById('route2').classList.remove('active');\n        }\n    });\n}\n\nfunction load() {\n    return new Promise((resolve) => {\n        setTimeout(() => {\n            resolve('Hi!');\n        }, 250);\n    });\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example5/transitions.css",
    "content": ".route {\n    display: none;\n}\n.route.active {\n    display: inline-block;\n}\n.route#route2 {\n    view-transition-name: slide;\n}\n::view-transition-new(slide):only-child {\n    animation: 400ms ease-in both slide-in;\n}\n@keyframes slide-in {\n    from { transform: translateY(-200px); }\n    to { transform: translateY(0); }\n}"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example5/view-transition-part.js",
    "content": "// the currently animating view transition\nlet currentTransition = null;\n// the next transition to run (after currentTransition completes)\nlet nextTransition = null;\n\n/** start a view transition or queue it for later if one is already animating */\nexport const startTransition = (updateCallback) => {\n    if (!updateCallback) updateCallback = () => {};\n    // a transition is active\n    if (currentTransition && !currentTransition.isFinished) {\n        // it is running callbacks, but not yet animating\n        if (!currentTransition.isReady) {\n            currentTransition.addCallback(updateCallback);\n            return currentTransition;\n        // it is already animating, queue callback in the next transition\n        } else {\n            if (!nextTransition) {\n                nextTransition = new QueueingViewTransition();\n            }\n            return nextTransition.addCallback(updateCallback);\n        }\n    // if no transition is active, start animating the new transition\n    } else {\n        currentTransition = new QueueingViewTransition();\n        currentTransition.addCallback(updateCallback);\n        currentTransition.run();\n        // after it's done, execute any queued transition\n        const doNext = () => {\n            if (nextTransition) {\n                currentTransition = nextTransition;\n                nextTransition = null;\n                currentTransition.run();\n                currentTransition.finished.finally(doNext);\n            } else {\n                currentTransition = null;\n            }\n        }\n        currentTransition.finished.finally(doNext);\n        return currentTransition;\n    }\n}\n\n// ..."
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example5/view-transition.js",
    "content": "// the currently animating view transition\nlet currentTransition = null;\n// the next transition to run (after currentTransition completes)\nlet nextTransition = null;\n\n/** start a view transition or queue it for later if one is already animating */\nexport const startTransition = (updateCallback) => {\n    if (!updateCallback) updateCallback = () => {};\n    // a transition is active\n    if (currentTransition && !currentTransition.isFinished) {\n        // it is running callbacks, but not yet animating\n        if (!currentTransition.isReady) {\n            currentTransition.addCallback(updateCallback);\n            return currentTransition;\n        // it is already animating, queue callback in the next transition\n        } else {\n            if (!nextTransition) {\n                nextTransition = new QueueingViewTransition();\n            }\n            return nextTransition.addCallback(updateCallback);\n        }\n    // if no transition is active, start animating the new transition\n    } else {\n        currentTransition = new QueueingViewTransition();\n        currentTransition.addCallback(updateCallback);\n        currentTransition.run();\n        // after it's done, execute any queued transition\n        const doNext = () => {\n            if (nextTransition) {\n                currentTransition = nextTransition;\n                nextTransition = null;\n                currentTransition.run();\n                currentTransition.finished.finally(doNext);\n            } else {\n                currentTransition = null;\n            }\n        }\n        currentTransition.finished.finally(doNext);\n        return currentTransition;\n    }\n}\n\nconst doViewTransition = (updateCallback) => {\n    let transition;\n    if (document.startViewTransition) {\n        transition = document.startViewTransition(updateCallback);\n    } else {\n        // fake view transition in firefox\n        const done = promiseTry(updateCallback);\n        transition = {\n            updateCallbackDone: done,\n            ready: done,\n            finished: done,\n            skipTransition: () => {}\n        };\n    }\n    return transition;\n}\n\nlet nextQueueId = 0;\n\nclass QueueingViewTransition {\n    #id = nextQueueId++;\n    #updateCallbackDone = Promise.withResolvers();\n    #ready = Promise.withResolvers();\n    #finished = Promise.withResolvers();\n    #callbacks = [];\n    #activeViewTransition = null;\n\n    get id() { return this.#id; }\n\n    // transition is running\n    isRunning = false;\n    // callbacks are complete, animation will start\n    isReady = false;\n    // animation is complete\n    isFinished = false;\n\n    constructor() {\n        this.ready.finally(() => this.isReady = true);\n        this.finished.finally(() => {\n            this.isFinished = true;\n        });\n    }\n\n    addCallback(updateCallback) {\n        if (typeof updateCallback !== 'function') throw new Error('updateCallback must be a function');\n        if (this.isReady) throw new Error('view transition already started');\n        this.#callbacks.push(updateCallback);\n        return this;\n    }\n\n    run(skipTransition = false) {\n        // already running\n        if (this.isRunning) return;\n        this.isRunning = true;\n\n        // execute callbacks in order in case later ones depend on DOM changes of earlier ones\n        // but do it async to allow callbacks to be added until animation starts\n        const doNext = () => {\n            if (this.#callbacks.length) {\n                const callback = this.#callbacks.shift();\n                return promiseTry(callback).then(doNext);\n            }\n        };\n\n        const callback = () => {\n            return doNext().then(this.#updateCallbackDone.resolve, this.#updateCallbackDone.reject);\n        };\n\n        // jump to the end\n        if (skipTransition) {\n            callback()\n                .then(this.#ready.resolve, this.#ready.reject)\n                .then(this.#finished.resolve, this.#finished.reject);\n        // start animating\n        } else {\n            this.#activeViewTransition = doViewTransition(callback);\n            this.#activeViewTransition.ready.then(this.#ready.resolve, this.#ready.reject);\n            this.#activeViewTransition.finished.then(this.#finished.resolve, this.#finished.reject);\n        }\n    }\n\n    // callbacks have fulfilled their promise\n    get updateCallbackDone() { return this.#updateCallbackDone.promise }\n    // animation is about to start\n    get ready() { return this.#ready.promise }\n    // animation has completed\n    get finished() { return this.#finished.promise }\n\n    skipTransition() {\n        if (this.#activeViewTransition) {\n            this.#activeViewTransition.skipTransition();\n        } else {\n            this.run(true);\n        }\n    }\n}\n\n// polyfill\nfunction promiseTry(fn) {\n    if (Promise.try) return Promise.try(fn);\n\treturn new Promise(function(resolve) {\n\t\tresolve(fn());\n\t});\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <title>Example 6</title>\n    <link rel=\"stylesheet\" href=\"src/styles.css\">\n    <link rel=\"stylesheet\" href=\"src/animations.css\">\n    <script type=\"module\" src=\"src/index.js\" defer></script>\n</head>\n\n<body>\n    <noscript>Please enable JavaScript to run this app.</noscript>\n    \n    <div id=\"root\"></div>\n</body>\n\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/lib/html.js",
    "content": "class Html extends String { }\n\n/** \n * tag a string as html not to be encoded\n * @param {string} str\n * @returns {string}\n */\nexport const htmlRaw = str => new Html(str);\n\n/** \n * entity encode a string as html\n * @param {*} value The value to encode\n * @returns {string}\n */\nexport const htmlEncode = (value) => {\n    // avoid double-encoding the same string\n    if (value instanceof Html) {\n        return value;\n    } else {\n        // https://stackoverflow.com/a/57448862/20980\n        return htmlRaw(\n            String(value).replace(/[&<>'\"]/g, \n                tag => ({\n                    '&': '&amp;',\n                    '<': '&lt;',\n                    '>': '&gt;',\n                    \"'\": '&#39;',\n                    '\"': '&quot;'\n                }[tag]))\n        );\n    }\n}\n\n/** \n * html tagged template literal, auto-encodes entities\n */\nexport const html = (strings, ...values) => \n    htmlRaw(String.raw({ raw: strings }, ...values.map(htmlEncode)));\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/lib/view-route.js",
    "content": "export const routerEvents = new EventTarget();\n\n// update routes on popstate (browser back/forward)\nexport const handlePopState = (e) => {\n    routerEvents.dispatchEvent(new PopStateEvent('popstate', { state: e.state }));\n}\nwindow.addEventListener('popstate', handlePopState);\n\nconst baseURL = new URL(window.originalHref || document.URL);\nconst basePath = baseURL.pathname.slice(0, baseURL.pathname.lastIndexOf('/'));\n\n/**\n * Usage:\n * <view-route path=\"/(?:index.html)?\" exact><p>hello</p><view-route> = only match / or /index.html and show the text \"hello\"\n * <view-route path=\"/\"> = match every route below / (e.g. for site navigation)\n * <view-route path=\"/todos/([\\w]+)\"> = match #/todos/:id\n * <view-route path=\"*\"> = match if no other route matches within the same parent node\n * \n * routechange event contains detail.matches, the array of matched parts of the regex\n */\ncustomElements.define('view-route', class extends HTMLElement {\n\n    #matches = [];\n\n    /** is this route currently active */\n    get isActive() {\n        return !!this.#matches?.length;\n    }\n\n    /** array of matched parts of the regex */\n    get matches() {\n        return this.#matches;\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n        routerEvents.addEventListener('popstate', this);\n        this.update();\n    }\n\n    disconnectedCallback() {\n        routerEvents.removeEventListener('popstate', this);\n    }\n\n    handleEvent(e) {\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['path', 'exact'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        let path = this.getAttribute('path') || '/';\n        // prepend absolute paths with the base path of the document (SPA behavior)\n        if (path.startsWith('/')) path = basePath + path;\n        const exact = this.hasAttribute('exact');\n        this.setMatches(this.matchesRoute(path, exact) || []);\n        if (this.isActive) {\n            this.dispatchEvent(new CustomEvent('routechange', { detail: this.matches, bubbles: true }));\n        }\n    }\n\n    setMatches(matches) {\n        this.#matches = matches;\n        this.style.display = this.isActive ? 'contents' : 'none';\n    }\n\n    matchesRoute(path, exact) {\n        let matches;\n        // '*' triggers fallback route if no other route matches\n        if (path === '*') {\n            const activeRoutes = Array.from(\n                this.parentNode.getElementsByTagName('view-route')\n                ).filter(_ => _.isActive);\n            if (!activeRoutes.length) matches = ['*'];\n        // normal routes\n        } else {\n            const regex = new RegExp(`^${path.replaceAll('/', '\\\\/')}${exact ? '$' : ''}`, 'gi');\n            const relativeUrl = location.pathname + location.search + location.hash;\n            matches = regex.exec(relativeUrl);\n        }\n        return matches;\n    }\n});\n\nconst handleLinkClick = (e) => {\n    const a = e.target.closest('a');\n    if (a && a.href) {\n        e.preventDefault();\n        const anchorUrl = new URL(a.href);\n        const pageUrl = basePath + anchorUrl.pathname + anchorUrl.search + anchorUrl.hash;\n        routerEvents.dispatchEvent(new CustomEvent('navigate', { detail: { url: pageUrl, a }}));\n    }\n}\n\nconst handleNavigate = (e) => {\n    pushState(null, null, e.detail.url);\n}\n\n/** \n * intercept link navigation for all links inside root, \n * and do single-page navigation using pushState instead.\n * @param {HTMLElement} root\n */\nexport const interceptNavigation = (root) => {\n    root.addEventListener('click', handleLinkClick);\n    // by default, navigate events cause pushState() calls\n    // add capturing listener to routerEvents before interceptNavigation() to prevent\n    routerEvents.addEventListener('navigate', handleNavigate);\n}\n\n/**\n * Navigate to a new state and update routes\n * @param {*} state \n * @param {*} unused \n * @param {*} url \n */\nexport const pushState = (state, unused, url) => {\n    history.pushState(state, unused, url);\n    routerEvents.dispatchEvent(new PopStateEvent('popstate', { state }));\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/lib/view-transition.js",
    "content": "let nextVTId = 0;\n\ncustomElements.define('view-transition', class extends HTMLElement {\n    #defaultName = 'VT_' + nextVTId++;\n\n    get name() { return this.getAttribute('name') }\n    set name(v) { this.setAttribute('name', v); }\n\n    static get observedAttributes() { return ['name'] }\n    attributeChangedCallback() { this.update(); }\n\n    connectedCallback() { this.update(); }\n\n    disconnectedCallback() { this.updateShadowRule(false); }\n\n    update() {\n        this.style.display = 'block';\n        this.style.viewTransitionName = this.name || this.#defaultName;\n        this.updateShadowRule();\n    }\n\n    updateShadowRule(insert = true) {\n        // if this is inside a shadow dom, make it visible to light dom view transitions\n        // by setting view-transition-name on a shadow part from a light dom stylesheet\n        if (this.getRootNode() instanceof ShadowRoot) {\n            if (!this.hasAttribute('part')) {\n                this.setAttribute('part', this.#defaultName);\n            }\n            const stylesheet = getTransitionStyleSheet();\n            const localName = this.getRootNode().host.localName;\n\n            // delete the old rule\n            const oldIndex = [...stylesheet.cssRules].findIndex(r => {\n                const match = /^([^:]+)::part\\(([^)]+)\\)/.exec(r.selectorText);\n                if (match && match[1] === localName && match[2] === this.getAttribute('part')) return true;\n            });\n            if (oldIndex >= 0) stylesheet.deleteRule(oldIndex);\n                \n            // add the new rule\n            if (insert) {\n                stylesheet.insertRule(\n                    `${localName}::part(${this.getAttribute('part')}) { \n                        view-transition-name: ${this.style.viewTransitionName};\n                    }`);\n            }\n        }\n    }\n});\n\nconst getTransitionStyleSheet = () => {\n    const adoptedStyleSheets = document.adoptedStyleSheets;\n    let stylesheet = adoptedStyleSheets.find(s => s.id === 'view-transition');\n    if (!stylesheet) {\n        stylesheet = new CSSStyleSheet();\n        stylesheet.id = 'view-transition';\n        adoptedStyleSheets.push(stylesheet);\n    }\n    return stylesheet;\n}\n\nexport const transitionEvents = new EventTarget();\n\n// the currently animating view transition\nlet currentTransition = null;\n// the next transition to run (after currentTransition completes)\nlet nextTransition = null;\n\n/** start a view transition or queue it for later if one is already animating */\nexport const startTransition = (updateCallback, transitionType) => {\n    log('startTransition', { updateCallback, transitionType });\n    if (!updateCallback) updateCallback = () => {};\n    // a transition is active\n    if (currentTransition && !currentTransition.isFinished) {\n        // it is running callbacks, but not yet animating\n        if (!currentTransition.isReady) {\n            currentTransition.addCallback(updateCallback);\n            return currentTransition;\n        // it is already animating, queue callback in the next transition\n        } else {\n            if (!nextTransition) {\n                nextTransition = new QueueingViewTransition(transitionType);\n            }\n            return nextTransition.addCallback(updateCallback);\n        }\n    // if no transition is active, start animating the new transition\n    } else {\n        currentTransition = new QueueingViewTransition(transitionType);\n        currentTransition.addCallback(updateCallback);\n        currentTransition.run();\n        // after it's done, execute any queued transition\n        const doNext = () => {\n            if (nextTransition) {\n                currentTransition = nextTransition;\n                nextTransition = null;\n                currentTransition.run();\n                currentTransition.finished.finally(doNext);\n            } else {\n                currentTransition = null;\n            }\n        }\n        currentTransition.finished.finally(doNext);\n        return currentTransition;\n    }\n}\n\nconst doViewTransition = (updateCallback, transitionType) => {\n    transitionEvents.dispatchEvent(new CustomEvent('transitionstart', { detail: { transitionType } }));\n    let transition;\n    if (document.startViewTransition) {\n        transition = document.startViewTransition(updateCallback);\n    } else {\n        // fake view transition in firefox\n        const done = promiseTry(updateCallback);\n        transition = {\n            updateCallbackDone: done,\n            ready: done,\n            finished: done,\n            skipTransition: () => {}\n        };\n    }\n    transition.finished.finally(() => {\n        transitionEvents.dispatchEvent(new CustomEvent('transitionend', { detail: { transitionType } }));  \n    });\n    return transition;\n}\n\nlet nextQueueId = 0;\n\nclass QueueingViewTransition {\n    #id = nextQueueId++;\n    #updateCallbackDone = Promise.withResolvers();\n    #ready = Promise.withResolvers();\n    #finished = Promise.withResolvers();\n    #callbacks = [];\n    #activeViewTransition = null;\n    #transitionType;\n\n    get id() { return this.#id; }\n\n    // transition is running\n    isRunning = false;\n    // callbacks are complete, animation will start\n    isReady = false;\n    // animation is complete\n    isFinished = false;\n\n    constructor(transitionType) {\n        log('new QueueingViewTransition', { id: this.id, obj: this });\n        this.#transitionType = transitionType;\n        this.ready.finally(() => this.isReady = true);\n        this.finished.finally(() => {\n            this.isFinished = true;\n            log('QVT.finished', { \n                id: this.id, obj: this,\n                names: [...document.querySelectorAll('view-transition')]\n                    .filter(v => v.checkVisibility())\n                    .map(v => v.style.viewTransitionName)\n            });\n        });\n    }\n\n    addCallback(updateCallback) {\n        log('QVT.addCallback', { id: this.id, updateCallback, obj: this });\n        if (typeof updateCallback !== 'function') throw new Error('updateCallback must be a function');\n        if (this.isReady) throw new Error('view transition already started');\n        this.#callbacks.push(updateCallback);\n        return this;\n    }\n\n    run(skipTransition = false) {\n        log('QVT.run', { id: this.id, obj: this });\n        // already running\n        if (this.isRunning) return;\n        this.isRunning = true;\n\n        // execute callbacks in order in case later ones depend on DOM changes of earlier ones\n        // but do it async to allow callbacks to be added until animation starts\n        const doNext = () => {\n            if (this.#callbacks.length) {\n                const callback = this.#callbacks.shift();\n                log('QVT.run > callback', { id: this.id, obj: this, callback });\n                return promiseTry(callback).then(doNext);\n            }\n        };\n\n        const callback = () => {\n            return doNext().then(this.#updateCallbackDone.resolve, this.#updateCallbackDone.reject);\n        };\n\n        // jump to the end\n        if (skipTransition) {\n            callback()\n                .then(this.#ready.resolve, this.#ready.reject)\n                .then(this.#finished.resolve, this.#finished.reject);\n        // start animating\n        } else {\n            log('QVT.run > document.startViewTransition', \n                { id: this.id, obj: this, callbacks: this.#callbacks.slice(), \n                  names: [...document.querySelectorAll('view-transition')]\n                    .filter(v => v.checkVisibility())\n                    .map(v => v.style.viewTransitionName)\n            });\n            this.#activeViewTransition = doViewTransition(callback, this.#transitionType);\n            this.#activeViewTransition.ready.then(this.#ready.resolve, this.#ready.reject);\n            this.#activeViewTransition.finished.then(this.#finished.resolve, this.#finished.reject);\n        }\n    }\n\n    // callbacks have fulfilled their promise\n    get updateCallbackDone() { return this.#updateCallbackDone.promise }\n    // animation is about to start\n    get ready() { return this.#ready.promise }\n    // animation has completed\n    get finished() { return this.#finished.promise }\n\n    skipTransition() {\n        if (this.#activeViewTransition) {\n            this.#activeViewTransition.skipTransition();\n        } else {\n            this.run(true);\n        }\n    }\n}\n\n// polyfill\nfunction promiseTry(fn) {\n    if (Promise.try) return Promise.try(fn);\n\treturn new Promise(function(resolve) {\n\t\tresolve(fn());\n\t});\n}\n\nfunction log(...args) {\n    console.debug(...args);\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/App.js",
    "content": "import '../lib/view-transition.js';\nimport './Home.js';\nimport './Details.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n        <view-route path=\"/(?:index.html)?\" exact>\n            <demo-home></demo-home>\n        </view-route>\n        <view-route path=\"/video\">\n            <demo-details></demo-details>\n        </view-route>\n        `;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/Details.js",
    "content": "import { startTransition } from '../lib/view-transition.js';\nimport { html } from '../lib/html.js';\nimport { ChevronLeft } from './Icons.js';\nimport { fetchVideo, fetchVideoDetails } from './data.js';\nimport './Layout.js';\n\ncustomElements.define('demo-details', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            <view-route path=\"/video/(?<id>[\\\\w]+)\">\n                <demo-page>\n                    <div slot=\"heading\">\n                        <a class=\"link fit back\" href=\"/\">\n                            ${ChevronLeft()} Back\n                        </a>\n                    </div>\n                    <div class=\"details\">\n                        <demo-video></demo-video>\n                        <demo-video-details></demo-video-details>\n                    </div>\n                </demo-page>\n            </view-route>\n        `;\n        const id = this.querySelector('view-route').matches?.groups?.id ?? null;\n        this.update(id);\n        this.addEventListener('routechange', this);\n    }\n    \n    handleEvent(e) { \n        if (e.type === 'routechange') {\n            this.update(e.detail?.groups?.id);\n        }\n    }\n\n    update(id) {\n        const videoElem = this.querySelector('demo-video');\n        videoElem.innerHTML = '';\n        if (id) {\n            startTransition(() => fetchVideo(id).then(video => {\n                videoElem.innerHTML = html`\n                    <div\n                        aria-hidden=\"true\"\n                        style=\"view-transition-name: video-${video.id}\"\n                        class=\"thumbnail ${video.image}\">\n                        <demo-video-controls></demo-video-controls>\n                    </div>\n                `;\n            }));\n            this.querySelector('demo-video-details').update(id);\n        }\n    }\n});\n\ncustomElements.define('demo-video-details', class extends HTMLElement {\n    async update(id) {\n        if (id) {\n            const load = fetchVideoDetails(id);\n            const wait = new Promise((resolve) => { setTimeout(resolve, 10, null); });\n            let video = await Promise.race([load, wait]);\n            if (video) {\n                this.innerHTML = videoInfo(video);\n            } else {\n                this.innerHTML = videoInfoFallback();\n                video = await load;\n                // animate content in and fallback out\n                startTransition(() => {\n                    this.innerHTML = videoInfo(video);\n                });\n            }\n        } else this.innerHTML = '';\n    }\n});\n\nconst videoInfoFallback = () => `\n    <div style=\"view-transition-name: details-fallback\">\n        <div class=\"fallback title\"></div>\n        <div class=\"fallback description\"></div>\n    </div>\n`;\n\nconst videoInfo = (details) => html`\n    <div style=\"view-transition-name: details-content\">\n        <p class=\"info-title\">${details.title}</p>\n        <p class=\"info-description\">${details.description}</p>\n    </div>\n`;"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/Home.js",
    "content": "import { routerEvents } from \"../lib/view-route.js\";\nimport { startTransition } from \"../lib/view-transition.js\";\nimport './Layout.js';\nimport './Videos.js';\nimport { IconSearch } from \"./Icons.js\";\nimport { fetchVideos } from \"./data.js\";\n\ncustomElements.define('demo-home', class extends HTMLElement {\n    videos = [];\n    searchInput = null;\n    searchList = null;\n\n    connectedCallback() {\n        this.innerHTML = `\n            <demo-page>\n                <div class=\"fit\" slot=\"heading\"></div>\n                <demo-search-input></demo-search-input>\n                <demo-search-list>Loading...</demo-search-list>\n            </demo-page>\n        `;\n        this.searchInput = this.querySelector('demo-search-input');\n        this.searchInput.addEventListener('change', this.update.bind(this));\n        this.searchList = this.querySelector('demo-search-list');\n        fetchVideos().then(videos => {\n            this.videos = videos;\n            this.querySelector('div[slot=heading]').textContent = `${videos.length} Videos`;\n            this.update();\n        });\n        // rerender after back navigation\n        routerEvents.addEventListener('popstate', this);\n    }\n\n    handleEvent(e) { this.update(); }\n\n    update() {\n        const filteredVideos = filterVideos(this.videos, this.searchInput.text);\n        this.searchList.update(filteredVideos, this.searchInput.text);\n    }\n});\n\ncustomElements.define('demo-search-input', class extends HTMLElement {\n    #text = '';\n    get text() { return this.#text }\n    set text(v) { if (this.#text !== v) { this.#text = v; this.update(); } }\n\n    connectedCallback() {\n        this.innerHTML = `\n            <form class=\"search\">\n                <label for=\"search\" class=\"sr-only\">\n                    Search\n                </label>\n                <div class=\"search-input\">\n                    <div class=\"search-icon\">\n                        ${IconSearch()}\n                    </div>\n                    <input id=\"search\" type=\"text\" placeholder=\"Search\" />\n                </div>\n            </form>\n        `;\n        this.querySelector('input').addEventListener('input', e => {\n            this.#text = e.target.value;\n            this.dispatchEvent(new CustomEvent('change', { detail: e.target.value }));\n        });\n        this.querySelector('form').addEventListener('submit', e => {\n            e.preventDefault();\n        });\n        this.update();\n    }\n    update() {\n        this.querySelector('input').value = this.text;\n    }\n});\n\ncustomElements.define('demo-search-list', class extends HTMLElement {\n    update(videos, text) {\n        const filteredVideos = filterVideos(videos, text);\n        startTransition(() => {\n            this.innerHTML = `\n                <div class=\"video-list\">\n                    <div class=\"videos\"></div>\n                    ${!filteredVideos.length ? (\n                        `<div class=\"no-results\">No results</div>`\n                    ) : ''}\n                </div>\n            `;\n            if (filteredVideos.length) {\n                this.querySelector('.videos').replaceChildren(...filteredVideos.map(v => {\n                    const transition = document.createElement('view-transition');\n                    transition.name = `list-video-${v.id}`;\n                    transition.append(document.createElement('demo-video'));\n                    transition.firstChild.update(v);\n                    return transition;\n                }));\n            }\n        });\n    }\n});\n\nfunction filterVideos(videos, query) {\n  const keywords = query\n    .toLowerCase()\n    .split(\" \")\n    .filter((s) => s !== \"\");\n  if (keywords.length === 0) {\n    return videos;\n  }\n  return videos.filter((video) => {\n    const words = (video.title + \" \" + video.description)\n      .toLowerCase()\n      .split(\" \");\n    return keywords.every((kw) => words.some((w) => w.includes(kw)));\n  });\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/Icons.js",
    "content": "export function ChevronLeft() {\n  return (`\n    <svg\n      class=\"chevron-left\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      width=\"20\"\n      height=\"20\"\n      viewBox=\"0 0 20 20\">\n      <g fill=\"none\" fillRule=\"evenodd\" transform=\"translate(-446 -398)\">\n        <path\n          fill=\"currentColor\"\n          fill-rule=\"nonzero\"\n          d=\"M95.8838835,240.366117 C95.3957281,239.877961 94.6042719,239.877961 94.1161165,240.366117 C93.6279612,240.854272 93.6279612,241.645728 94.1161165,242.133883 L98.6161165,246.633883 C99.1042719,247.122039 99.8957281,247.122039 100.383883,246.633883 L104.883883,242.133883 C105.372039,241.645728 105.372039,240.854272 104.883883,240.366117 C104.395728,239.877961 103.604272,239.877961 103.116117,240.366117 L99.5,243.982233 L95.8838835,240.366117 Z\"\n          transform=\"translate(356.5 164.5)\"\n        />\n        <polygon points=\"446 418 466 418 466 398 446 398\" />\n      </g>\n    </svg>\n  `);\n}\n\nexport function PauseIcon() {\n  return (`\n    <svg\n      class=\"control-icon\"\n      style=\"padding: 4px\"\n      width=\"100\"\n      height=\"100\"\n      viewBox=\"0 0 512 512\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        fill-rule=\"evenodd\"\n        clip-rule=\"evenodd\"\n        d=\"M256 0C114.617 0 0 114.615 0 256s114.617 256 256 256 256-114.615 256-256S397.383 0 256 0zm-32 320c0 8.836-7.164 16-16 16h-32c-8.836 0-16-7.164-16-16V192c0-8.836 7.164-16 16-16h32c8.836 0 16 7.164 16 16v128zm128 0c0 8.836-7.164 16-16 16h-32c-8.836 0-16-7.164-16-16V192c0-8.836 7.164-16 16-16h32c8.836 0 16 7.164 16 16v128z\"\n        fill=\"currentColor\"\n      />\n    </svg>\n  `);\n}\n\nexport function PlayIcon() {\n  return (`\n    <svg\n      class=\"control-icon\"\n      width=\"100\"\n      height=\"100\"\n      viewBox=\"0 0 72 72\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        fill-rule=\"evenodd\"\n        clip-rule=\"evenodd\"\n        d=\"M36 69C54.2254 69 69 54.2254 69 36C69 17.7746 54.2254 3 36 3C17.7746 3 3 17.7746 3 36C3 54.2254 17.7746 69 36 69ZM52.1716 38.6337L28.4366 51.5801C26.4374 52.6705 24 51.2235 24 48.9464V23.0536C24 20.7764 26.4374 19.3295 28.4366 20.4199L52.1716 33.3663C54.2562 34.5034 54.2562 37.4966 52.1716 38.6337Z\"\n        fill=\"currentColor\"\n      />\n    </svg>\n  `);\n}\n\nexport function Heart({liked, animate}) {\n  return (`\n    <svg\n      class=\"absolute overflow-visible\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\">\n      <circle\n        class=\"circle ${liked ? 'liked' : ''} ${animate ? 'animate' : ''}\"\n        cx=\"12\"\n        cy=\"12\"\n        r=\"11.5\"\n        fill=\"transparent\"\n        stroke-width=\"0\"\n        stroke=\"currentColor\"\n      />\n    </svg>\n    <svg\n      class=\"heart ${liked ? 'liked' : ''} ${animate ? 'animate' : ''}\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\">\n      ${liked ? `\n        <path\n          d=\"M12 23a.496.496 0 0 1-.26-.074C7.023 19.973 0 13.743 0 8.68c0-4.12 2.322-6.677 6.058-6.677 2.572 0 5.108 2.387 5.134 2.41l.808.771.808-.771C12.834 4.387 15.367 2 17.935 2 21.678 2 24 4.558 24 8.677c0 5.06-7.022 11.293-11.74 14.246a.496.496 0 0 1-.26.074V23z\"\n          fill=\"currentColor\"\n        />\n      ` : `\n        <path\n          fill-rule=\"evenodd\"\n          clip-rule=\"evenodd\"\n          d=\"m12 5.184-.808-.771-.004-.004C11.065 4.299 8.522 2.003 6 2.003c-3.736 0-6 2.558-6 6.677 0 4.47 5.471 9.848 10 13.079.602.43 1.187.82 1.74 1.167A.497.497 0 0 0 12 23v-.003c.09 0 .182-.026.26-.074C16.977 19.97 24 13.737 24 8.677 24 4.557 21.743 2 18 2c-2.569 0-5.166 2.387-5.192 2.413L12 5.184zm-.002 15.525c2.071-1.388 4.477-3.342 6.427-5.47C20.72 12.733 22 10.401 22 8.677c0-1.708-.466-2.855-1.087-3.55C20.316 4.459 19.392 4 18 4c-.726 0-1.63.364-2.5.9-.67.412-1.148.82-1.266.92-.03.025-.037.031-.019.014l-.013.013L12 7.949 9.832 5.88a10.08 10.08 0 0 0-1.33-.977C7.633 4.367 6.728 4.003 6 4.003c-1.388 0-2.312.459-2.91 1.128C2.466 5.826 2 6.974 2 8.68c0 1.726 1.28 4.058 3.575 6.563 1.948 2.127 4.352 4.078 6.423 5.466z\"\n          fill=\"currentColor\"\n        />\n      `}\n    </svg>\n  `);\n}\n\nexport function IconSearch() {\n  return (`\n    <svg width=\"1em\" height=\"1em\" viewBox=\"0 0 20 20\">\n      <path\n        d=\"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z\"\n        stroke=\"currentColor\"\n        fill=\"none\"\n        stroke-width=\"2\"\n        fill-rule=\"evenodd\"\n        stroke-linecap=\"round\"\n        stroke-linejoin=\"round\"></path>\n    </svg>\n  `);\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/Layout.js",
    "content": "import { transitionEvents } from \"../lib/view-transition.js\";\n\ncustomElements.define('demo-page', class extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n        this.shadowRoot.innerHTML = `\n            <link rel=\"stylesheet\" href=\"${import.meta.resolve('./styles.css')}\">\n            <div class=\"page\">\n                <div class=\"top\">\n                    <div class=\"top-nav\">\n                        <view-transition name=\"nav\">\n                            <slot name=\"heading\"></slot>\n                        </view-transition>\n                    </div>\n                </div>\n                <div class=\"bottom\">\n                    <div class=\"content\"><slot></slot></div>\n                </div>\n            </div>\n        `;\n        const viewTransition = this.shadowRoot.querySelector('view-transition');\n        transitionEvents.addEventListener('transitionstart', e => {\n            const transitionType = e.detail?.transitionType;\n            switch (transitionType) {\n                case 'nav-back':\n                case 'nav-forward':\n                    viewTransition.name = transitionType;\n                    break;\n            }\n        });\n        transitionEvents.addEventListener('transitionend', e => {\n            viewTransition.name = 'nav';\n        });\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/LikeButton.js",
    "content": "import { Heart } from './Icons.js';\n\n// A hack since we don't actually have a backend.\n// Unlike local state, this survives videos being filtered.\nconst likedVideos = new Set();\n\ncustomElements.define('demo-video-like', class extends HTMLElement {\n    animate = false;\n    connectedCallback() {\n        this.replaceChildren(document.createElement('button'));\n        this.update();\n    };\n    update() {\n        const id = this.getAttribute('id');\n        const liked = likedVideos.has(id);\n        const button = this.querySelector('button');\n        button.className = 'like-button ' + (liked ? 'liked' : '');\n        button.ariaLabel = liked ? 'Unsave' : 'Save';\n        button.innerHTML = Heart({liked, animate: this.animate});\n        button.onclick = () => {\n            this.animate = true;\n            likedVideos[liked ? 'delete' : 'add'](id);\n            this.update();\n            this.animate = false;\n        };\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/Videos.js",
    "content": "import { startTransition } from '../lib/view-transition.js';\nimport { PlayIcon, PauseIcon } from './Icons.js';\nimport './LikeButton.js';\n\ncustomElements.define('demo-video', class extends HTMLElement {\n    update(video) {\n        this.innerHTML = `\n            <div class=\"video\">\n                <a class=\"link\" href=\"/video/${video.id}\">\n                    <div\n                        aria-hidden=\"true\"\n                        tabIndex=\"-1\"\n                        style=\"view-transition-name: video-${video.id}\"\n                        class=\"thumbnail ${video.image}\">\n                    </div>\n\n                    <div class=\"info\">\n                        <div class=\"video-title\">${video.title}</div>\n                        <div class=\"video-description\">${video.description}</div>\n                    </div>\n                </a>\n                <demo-video-like id=\"${video.id}\"></demo-video-like>\n            </div>\n        `;\n    }\n});\n\ncustomElements.define('demo-video-controls', class extends HTMLElement {\n    isPlaying = false;\n    connectedCallback() {\n        this.innerHTML = `\n            <span class=\"controls\">\n                ${PlayIcon()}\n            </span>\n        `;\n        this.addEventListener('click', this);\n        this.update();\n    }\n    handleEvent(e) {\n        startTransition(async () => {\n            this.isPlaying = !this.isPlaying;\n            this.update();\n        });\n    }\n    update() {\n        this.querySelector('span').innerHTML = this.isPlaying ? PauseIcon() : PlayIcon();\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/animations.css",
    "content": "/* Slide animations for details content */\n::view-transition-old(details-fallback):only-child {\n    animation: 150ms ease-out both fade-out, 150ms ease-out both slide-down;\n}\n\n::view-transition-new(details-content):only-child,\n::view-transition-new(details-fallback):only-child {\n    animation: 210ms ease-in 150ms both fade-in, 400ms ease-in both slide-up;\n}\n\n/* Animations for view transition classed added by transition type */\n::view-transition-old(nav-forward) {\n    /* when sliding forward, the \"old\" page should slide out to left. */\n    animation: 150ms cubic-bezier(0.4, 0, 1, 1) both fade-out,\n    400ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;\n}\n\n::view-transition-new(nav-forward) {\n    /* when sliding forward, the \"new\" page should slide in from right. */\n    animation: 210ms cubic-bezier(0, 0, 0.2, 1) 150ms both fade-in,\n    400ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;\n}\n\n::view-transition-old(nav-back) {\n    /* when sliding back, the \"old\" page should slide out to right. */\n    animation: 150ms cubic-bezier(0.4, 0, 1, 1) both fade-out,\n    400ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-right;\n}\n\n::view-transition-new(nav-back) {\n    /* when sliding back, the \"new\" page should slide in from left. */\n    animation: 210ms cubic-bezier(0, 0, 0.2, 1) 150ms both fade-in,\n    400ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-left;\n}\n\n/* Keyframes to support our animations above. */\n@keyframes slide-up {\n    from {\n        transform: translateY(10px);\n    }\n    to {\n        transform: translateY(0);\n    }\n}\n\n@keyframes slide-down {\n    from {\n        transform: translateY(0);\n    }\n    to {\n        transform: translateY(10px);\n    }\n}\n\n@keyframes fade-in {\n    from {\n        opacity: 0;\n    }\n}\n\n@keyframes fade-out {\n    to {\n        opacity: 0;\n    }\n}\n\n@keyframes slide-to-right {\n    to {\n        transform: translateX(50px);\n    }\n}\n\n@keyframes slide-from-right {\n    from {\n        transform: translateX(50px);\n    }\n    to {\n        transform: translateX(0);\n    }\n}\n\n@keyframes slide-to-left {\n    to {\n        transform: translateX(-50px);\n    }\n}\n\n@keyframes slide-from-left {\n    from {\n        transform: translateX(-50px);\n    }\n    to {\n        transform: translateX(0);\n    }\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/data.js",
    "content": "const videos = [\n  {\n    id: '1',\n    title: 'First video',\n    description: 'Video description',\n    image: 'blue',\n  },\n  {\n    id: '2',\n    title: 'Second video',\n    description: 'Video description',\n    image: 'red',\n  },\n  {\n    id: '3',\n    title: 'Third video',\n    description: 'Video description',\n    image: 'green',\n  },\n  {\n    id: '4',\n    title: 'Fourth video',\n    description: 'Video description',\n    image: 'purple',\n  },\n  {\n    id: '5',\n    title: 'Fifth video',\n    description: 'Video description',\n    image: 'yellow',\n  },\n  {\n    id: '6',\n    title: 'Sixth video',\n    description: 'Video description',\n    image: 'gray',\n  },\n];\n\nlet videosCache = new Map();\nlet videoCache = new Map();\nlet videoDetailsCache = new Map();\nconst VIDEO_DELAY = 1;\nconst VIDEO_DETAILS_DELAY = 1000;\nexport function fetchVideos() {\n  if (videosCache.has(0)) {\n    return videosCache.get(0);\n  }\n  const promise = new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(videos);\n    }, VIDEO_DELAY);\n  });\n  videosCache.set(0, promise);\n  return promise;\n}\n\nexport function fetchVideo(id) {\n  if (videoCache.has(id)) {\n    return videoCache.get(id);\n  }\n  const promise = new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(videos.find((video) => video.id === id));\n    }, VIDEO_DELAY);\n  });\n  videoCache.set(id, promise);\n  return promise;\n}\n\nexport function fetchVideoDetails(id) {\n  if (videoDetailsCache.has(id)) {\n    return videoDetailsCache.get(id);\n  }\n  const promise = new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(videos.find((video) => video.id === id));\n    }, VIDEO_DETAILS_DELAY);\n  });\n  videoDetailsCache.set(id, promise);\n  return promise;\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/index.js",
    "content": "import { interceptNavigation, routerEvents, handlePopState, pushState } from '../lib/view-route.js';\nimport { startTransition } from '../lib/view-transition.js';\nimport './App.js';\n\nconst app = () => {\n    // intercept default router behavior to make it animate view transitions\n    routerEvents.addEventListener('navigate', (e) => {\n        e.stopImmediatePropagation();\n        const { url, a } = e.detail;\n        const isBackNav = a?.classList?.contains('back');\n        const transitionType = isBackNav ? 'nav-back' : 'nav-forward';\n        startTransition(\n            () => {\n                pushState(transitionType, null, url);\n                // give routes time to render before snapshotting\n                return new Promise(resolve => setTimeout(resolve, 10));\n            }, \n            transitionType);\n    }, { capture: true });\n    // intercept popstate to animate back/forward page navigation\n    window.removeEventListener('popstate', handlePopState);\n    window.addEventListener('popstate', (e) => {\n        startTransition(() => handlePopState(e), e.state);\n    });\n\n    const root = document.getElementById('root');\n    root.innerHTML = `<demo-app></demo-app>`;\n    interceptNavigation(root);\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/example6/src/styles.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: sans-serif;\n  margin: 20px;\n  padding: 0;\n}\n\nh1 {\n  margin-top: 0;\n  font-size: 22px;\n}\n\nh2 {\n  margin-top: 0;\n  font-size: 20px;\n}\n\nh3 {\n  margin-top: 0;\n  font-size: 18px;\n}\n\nh4 {\n  margin-top: 0;\n  font-size: 16px;\n}\n\nh5 {\n  margin-top: 0;\n  font-size: 14px;\n}\n\nh6 {\n  margin-top: 0;\n  font-size: 12px;\n}\n\ncode {\n  font-size: 1.2em;\n}\n\nul {\n  padding-inline-start: 20px;\n}\n\n@font-face {\n  font-family: Optimistic Text;\n  src: url(https://react.dev/fonts/Optimistic_Text_W_Rg.woff2) format(\"woff2\");\n  font-weight: 400;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: Optimistic Text;\n  src: url(https://react.dev/fonts/Optimistic_Text_W_Md.woff2) format(\"woff2\");\n  font-weight: 500;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: Optimistic Text;\n  src: url(https://react.dev/fonts/Optimistic_Text_W_Bd.woff2) format(\"woff2\");\n  font-weight: 600;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: Optimistic Text;\n  src: url(https://react.dev/fonts/Optimistic_Text_W_Bd.woff2) format(\"woff2\");\n  font-weight: 700;\n  font-style: normal;\n  font-display: swap;\n}\n\n* {\n  box-sizing: border-box;\n}\n\nhtml {\n  background-image: url(https://react.dev/images/meta-gradient-dark.png);\n  background-size: 100%;\n  background-position: -100%;\n  background-color: rgb(64 71 86);\n  background-repeat: no-repeat;\n  height: 100%;\n  width: 100%;\n}\n\nbody {\n  font-family: Optimistic Text, -apple-system, ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;\n  padding: 10px 0 10px 0;\n  margin: 0;\n  display: flex;\n  justify-content: center;\n}\n\n#root {\n  flex: 1 1;\n  height: auto;\n  background-color: #fff;\n  border-radius: 10px;\n  max-width: 450px;\n  min-height: 600px;\n  padding-bottom: 10px;\n}\n\nh1 {\n  margin-top: 0;\n  font-size: 22px;\n}\n\nh2 {\n  margin-top: 0;\n  font-size: 20px;\n}\n\nh3 {\n  margin-top: 0;\n  font-size: 18px;\n}\n\nh4 {\n  margin-top: 0;\n  font-size: 16px;\n}\n\nh5 {\n  margin-top: 0;\n  font-size: 14px;\n}\n\nh6 {\n  margin-top: 0;\n  font-size: 12px;\n}\n\ncode {\n  font-size: 1.2em;\n}\n\nul {\n  padding-inline-start: 20px;\n}\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border-width: 0;\n}\n\n.absolute {\n  position: absolute;\n}\n\n.overflow-visible {\n  overflow: visible;\n}\n\n.visible {\n  overflow: visible;\n}\n\n.fit {\n  width: fit-content;\n}\n\n\n/* Layout */\n.page {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n}\n\n.top-hero {\n  height: 200px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  background-image: conic-gradient(\n      from 90deg at -10% 100%,\n      #2b303b 0deg,\n      #2b303b 90deg,\n      #16181d 1turn\n  );\n}\n\n.bottom {\n  flex: 1;\n  overflow: auto;\n}\n\n.top-nav {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  margin-bottom: 0;\n  padding: 0 12px;\n  top: 0;\n  width: 100%;\n  height: 44px;\n  color: #23272f;\n  font-weight: 700;\n  font-size: 20px;\n  z-index: 100;\n  cursor: default;\n}\n\n.content {\n  padding: 0 12px;\n  margin-top: 4px;\n}\n\n\n.loader {\n  color: #23272f;\n  font-size: 3px;\n  width: 1em;\n  margin-right: 18px;\n  height: 1em;\n  border-radius: 50%;\n  position: relative;\n  text-indent: -9999em;\n  animation: loading-spinner 1.3s infinite linear;\n  animation-delay: 200ms;\n  transform: translateZ(0);\n}\n\n@keyframes loading-spinner {\n  0%,\n  100% {\n    box-shadow: 0 -3em 0 0.2em,\n    2em -2em 0 0em, 3em 0 0 -1em,\n    2em 2em 0 -1em, 0 3em 0 -1em,\n    -2em 2em 0 -1em, -3em 0 0 -1em,\n    -2em -2em 0 0;\n  }\n  12.5% {\n    box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em,\n    3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em,\n    -2em 2em 0 -1em, -3em 0 0 -1em,\n    -2em -2em 0 -1em;\n  }\n  25% {\n    box-shadow: 0 -3em 0 -0.5em,\n    2em -2em 0 0, 3em 0 0 0.2em,\n    2em 2em 0 0, 0 3em 0 -1em,\n    -2em 2em 0 -1em, -3em 0 0 -1em,\n    -2em -2em 0 -1em;\n  }\n  37.5% {\n    box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,\n    3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em,\n    -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;\n  }\n  50% {\n    box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,\n    3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em,\n    -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;\n  }\n  62.5% {\n    box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,\n    3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0,\n    -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;\n  }\n  75% {\n    box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em,\n    3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em,\n    -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;\n  }\n  87.5% {\n    box-shadow: 0em -3em 0 0, 2em -2em 0 -1em,\n    3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em,\n    -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;\n  }\n}\n\n/* LikeButton */\n.like-button {\n  outline-offset: 2px;\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 2.5rem;\n  height: 2.5rem;\n  cursor: pointer;\n  border-radius: 9999px;\n  border: none;\n  outline: none 2px;\n  color: #5e687e;\n  background: none;\n}\n\n.like-button:focus {\n  color: #a6423a;\n  background-color: rgba(166, 66, 58, .05);\n}\n\n.like-button:active {\n  color: #a6423a;\n  background-color: rgba(166, 66, 58, .05);\n  transform: scaleX(0.95) scaleY(0.95);\n}\n\n.like-button:hover {\n  background-color: #f6f7f9;\n}\n\n.like-button.liked {\n  color: #a6423a;\n}\n\n/* Icons */\n@keyframes circle {\n  0% {\n    transform: scale(0);\n    stroke-width: 16px;\n  }\n\n  50% {\n    transform: scale(.5);\n    stroke-width: 16px;\n  }\n\n  to {\n    transform: scale(1);\n    stroke-width: 0;\n  }\n}\n\n.circle {\n  color: rgba(166, 66, 58, .5);\n  transform-origin: center;\n  transition-property: all;\n  transition-duration: .15s;\n  transition-timing-function: cubic-bezier(.4,0,.2,1);\n}\n\n.circle.liked.animate {\n  animation: circle .3s forwards;\n}\n\n.heart {\n  width: 1.5rem;\n  height: 1.5rem;\n}\n\n.heart.liked {\n  transform-origin: center;\n  transition-property: all;\n  transition-duration: .15s;\n  transition-timing-function: cubic-bezier(.4, 0, .2, 1);\n}\n\n.heart.liked.animate {\n  animation: scale .35s ease-in-out forwards;\n}\n\n.control-icon {\n  color: hsla(0, 0%, 100%, .5);\n  filter:  drop-shadow(0 20px 13px rgba(0, 0, 0, .03)) drop-shadow(0 8px 5px rgba(0, 0, 0, .08));\n}\n\n.chevron-left {\n  margin-top: 2px;\n  rotate: 90deg;\n}\n\n\n/* Video */\n.thumbnail {\n  position: relative;\n  aspect-ratio: 16 / 9;\n  display: flex;\n  overflow: hidden;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  border-radius: 0.5rem;\n  outline-offset: 2px;\n  width: 8rem;\n  vertical-align: middle;\n  background-color: #ffffff;\n  background-size: cover;\n  -webkit-user-select: none;\n  user-select: none;\n}\n\n.thumbnail.blue {\n  background-image: conic-gradient(at top right, #c76a15, #087ea4, #2b3491);\n}\n\n.thumbnail.red {\n  background-image: conic-gradient(at top right, #c76a15, #a6423a, #2b3491);\n}\n\n.thumbnail.green {\n  background-image: conic-gradient(at top right, #c76a15, #388f7f, #2b3491);\n}\n\n.thumbnail.purple {\n  background-image: conic-gradient(at top right, #c76a15, #575fb7, #2b3491);\n}\n\n.thumbnail.yellow {\n  background-image: conic-gradient(at top right, #c76a15, #FABD62, #2b3491);\n}\n\n.thumbnail.gray {\n  background-image: conic-gradient(at top right, #c76a15, #4E5769, #2b3491);\n}\n\n.video {\n  display: flex;\n  flex-direction: row;\n  gap: 0.75rem;\n  align-items: center;\n}\n\n.video .link {\n  display: flex;\n  flex-direction: row;\n  flex: 1 1 0;\n  gap: 0.125rem;\n  outline-offset: 4px;\n  cursor: pointer;\n}\n\n.video .info {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  margin-left: 8px;\n  gap: 0.125rem;\n}\n\n.video .info:hover {\n  text-decoration: underline;\n}\n\n.video-title {\n  font-size: 15px;\n  line-height: 1.25;\n  font-weight: 700;\n  color: #23272f;\n}\n\n.video-description {\n  color: #5e687e;\n  font-size: 13px;\n}\n\n/* Details */\n.details .thumbnail {\n  position: relative;\n  aspect-ratio: 16 / 9;\n  display: flex;\n  overflow: hidden;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  border-radius: 0.5rem;\n  outline-offset: 2px;\n  width: 100%;\n  vertical-align: middle;\n  background-color: #ffffff;\n  background-size: cover;\n  -webkit-user-select: none;\n  user-select: none;\n}\n\n.video-details-title {\n  margin-top: 8px;\n}\n\n.video-details-speaker {\n  display: flex;\n  gap: 8px;\n  margin-top: 10px\n}\n\n.back {\n  display: flex;\n  align-items: center;\n  margin-left: -5px;\n  cursor: pointer;\n}\n\n.back:hover {\n  text-decoration: underline;\n}\n\n.info-title {\n  font-size: 1.5rem;\n  font-weight: 700;\n  line-height: 1.25;\n  margin: 8px 0 0 0 ;\n}\n\n.info-description {\n  margin: 8px 0 0 0;\n}\n\n.controls {\n  cursor: pointer;\n}\n\n.fallback {\n  background: #f6f7f8 linear-gradient(to right, #e6e6e6 5%, #cccccc 25%, #e6e6e6 35%) no-repeat;\n  background-size: 800px 104px;\n  display: block;\n  line-height: 1.25;\n  margin: 8px 0 0 0;\n  border-radius: 5px;\n  overflow: hidden;\n\n  animation: 1s linear 1s infinite shimmer;\n  animation-delay: 300ms;\n  animation-duration: 1s;\n  animation-fill-mode: forwards;\n  animation-iteration-count: infinite;\n  animation-name: shimmer;\n  animation-timing-function: linear;\n}\n\n\n.fallback.title {\n  width: 130px;\n  height: 30px;\n\n}\n\n.fallback.description {\n  width: 150px;\n  height: 21px;\n}\n\n@keyframes shimmer {\n  0% {\n    background-position: -468px 0;\n  }\n\n  100% {\n    background-position: 468px 0;\n  }\n}\n\n.search {\n  margin-bottom: 10px;\n}\n.search-input {\n  width: 100%;\n  position: relative;\n}\n\n.search-icon {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  inset-inline-start: 0;\n  display: flex;\n  align-items: center;\n  padding-inline-start: 1rem;\n  pointer-events: none;\n  color: #99a1b3;\n}\n\n.search-input input {\n  display: flex;\n  padding-inline-start: 2.75rem;\n  padding-top: 10px;\n  padding-bottom: 10px;\n  width: 100%;\n  text-align: start;\n  background-color: rgb(235 236 240);\n  outline: 2px solid transparent;\n  cursor: pointer;\n  border: none;\n  align-items: center;\n  color: rgb(35 39 47);\n  border-radius: 9999px;\n  vertical-align: middle;\n  font-size: 15px;\n}\n\n.search-input input:hover, .search-input input:active {\n  background-color: rgb(235 236 240/ 0.8);\n  color: rgb(35 39 47/ 0.8);\n}\n\n/* Home */\n.video-list {\n  position: relative;\n}\n\n.video-list .videos {\n  display: flex;\n  flex-direction: column;\n  gap: 1rem;\n  overflow-y: auto;\n  height: 100%;\n}\n\n/* extra styles: */\n\n/* make this class work for actual <a> elements */\n.link {\n  text-decoration: none;\n  color: inherit;\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-12-view-transitions/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Bringing React's &lt;ViewTransition&gt; to vanilla JS</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"Bringing React's declarative view transitions API to vanilla as a custom element.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <script type=\"module\" src=\"../../index.js\" defer></script>\n</head>\n<body>\n    <blog-header published=\"2025-06-12\">\n        <img src=\"image.webp\" alt=\"A vanilla superhero girl breaking through comic cell walls.\" loading=\"lazy\" />\n        <h2>Bringing React's &lt;ViewTransition&gt; to vanilla JS</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            I like React. I really do. It is the default answer for modern web development, and it is that answer for a reason.\n            Generally when React adds a feature it is well thought through, within the React system of thinking.\n            My one criticism is that React by its nature overthinks things, that dumber and simpler solutions would often be \n            on the whole ... better. Less magic, more predictable.\n        </p>\n        <p>\n            So when I port framework features to vanilla JS, don't take this as a slight of that framework.\n            It is meant as an exploration of what dumber and simpler solutions might look like, when built  \n            on the ground floor of the web's platform instead of the lofty altitudes of big frameworks. \n            It is a great way to learn.\n        </p>\n        <p>\n            Which brings me of course to today's topic: view transitions, and how to implement them.\n        </p>\n\n        <h3>View Transitions 101</h3>\n\n        <p>\n            Let's start with the basics: what is a view transition?\n        </p>\n\n        <iframe src=\"./example1/index.html\" title=\"example 1\" height=\"200\"></iframe>\n\n        <p>\n            In a supporting browser, what you'll see when you click is a square smoothly transitioning\n            between blue and orange on every button click. By supported browser I mean Chrome, Edge or Safari,\n            but sadly not yet Firefox, although <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1823896\">they're working on it</a>!\n            In Firefox you'll see the change, but applied immediately without the animation.\n        </p>\n        <p>\n            At the code level, it looks something like this:\n        </p>\n\n        <x-code-viewer src=\"./example1/index.js\" name=\"example.js\"></x-code-viewer>\n        <x-code-viewer src=\"./example1/transitions.css\" name=\"transitions.css\"></x-code-viewer>\n\n        <p>\n            How this works is that the browser takes a snapshot of the page when we call <code>document.startViewTransition()</code>,\n            takes another snapshot after the callback passed to it is done (or the promise it returns fulfills),\n            and then figures out how to smoothly animate between the two snapshots, using a fade by default.\n        </p>\n        <p>\n            A very nice thing is that by putting a <code>view-transition-name</code> style on an element we can \n            make it transition independently from the rest of the page, and we can control that transition through CSS.\n        </p>\n        <x-code-viewer src=\"./example2/index.js\" name=\"example.js\"></x-code-viewer>\n        <x-code-viewer src=\"./example2/transitions.css\" name=\"transitions.css\"></x-code-viewer>\n        <p>\n            Now we can see a second square sliding in on the first click, and fading out on the second.\n        </p>\n        <iframe src=\"./example2/index.html\" title=\"example 2\" height=\"200\"></iframe>\n\n        <p>\n            That's enough view transition basics for now. If you're curious for more, \n            you can learn the rest in the <a href=\"https://developer.chrome.com/docs/web-platform/view-transitions\">chrome developer documentation</a>.\n        </p>\n\n        <h3>Here comes trouble</h3>\n\n        <p>\n            Up to this point, we've gotten the fair weather version of view transitions, but there are paper cuts.\n        </p>\n        <ul>\n            <li>Firefox doesn't support view transitions at all, so we have to feature-detect.</li>\n            <li>There is only one actual current View Transitions standard, level 1, but most of the online tutorials talk about the unfinalized level 2.</li> \n            <li>If there are duplicate values of <code>view-transition-name</code> anywhere on the page, the animations disappear in a puff of duplicate element error smoke.</li>\n            <li>As always, there's a thing about shadow DOM, but more on that later.</li>\n            <li>Starting a new view transition when one is already running skips to the end of the previous one, bringing the smooth user experience to a jarring end.</li>\n            <li>User input is blocked while the view is transitioning, causing frustration when clicks are ignored.</li>\n            <li>The <code>document.startViewTransition()</code> function only accepts a single callback that returns a single promise.</li>\n        </ul>\n        <p>\n            It is the last one that really spells trouble. In a larger single-page web application we'll typically\n            find a central routing layer that triggers a number of asynchronous updates every time the route changes.\n            Wrapping those asynchronous updates into a single promise can be a challenge,\n            as is finding the right place to \"slot in\" a call to <code>document.startViewTransition()</code>.\n        </p>\n        <p>\n            Also, we probably don't even <em>want</em> to wait for all of the asynchronous updates to complete.\n            Leaving the application in an interactive state in between two smaller view transitions is better\n            than bundling it all together into one ponderous picture perfect transition animation.\n        </p>\n\n        <h3>What React did</h3>\n\n        <p>\n            React being React they solve those problems through magic, through exceeding cleverness.\n            You can read up on <a href=\"https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#view-transitions\">their approach to view transitions</a>, \n            but distilling it down it becomes this:\n        </p>\n        <ul>\n            <li>Anything that should take part separately in a view transition is wrapped in a <code>&lt;ViewTransition&gt;</code> component.</li>\n            <li>React will choose unique <code>view-transition-name</code> style values, which DOM elements to set them on, and when to set them.\n                This can be controlled through the <code>&lt;ViewTransition&gt;</code> <code>name</code> and <code>key</code> props.</li>\n            <li>Any updates that should become part of a view transition are wrapped in a <code>startTransition()</code> call.</li>\n            <li>React automatically figures out when to call <code>document.startViewTransition()</code>, and what updates to put inside the callback.\n                It also cleverly avoids starting new transitions when one is already running, so <code>startTransition()</code> can be called from multiple places safely.\n                Oh, and by the way, it feature detects, obviously.\n            </li>\n        </ul>\n        <p>\n            When you do all of that, you get <a href=\"https://codesandbox.io/p/sandbox/njn4yc\">magic</a>.\n        </p>\n        <img src=\"react-demo.gif\" alt=\"A React view transition demo\" loading=\"lazy\" width=\"240\" />\n        <p>\n            Good luck figuring out <a href=\"https://react.dev/reference/react/ViewTransition#how-does-viewtransition-work\">how it works</a>, \n            or how to troubleshoot when the magic loses its shine.\n            But that is the bar, that is the lofty goal of user experience to reach with a dumber and simpler reimagining as vanilla JS.\n            So let's get cooking.\n        </p>\n\n        <h3>A fresh start</h3>\n\n        <p>\n            Our starting point is a barebones implementation of a <code>startTransition()</code>\n            function to replace what React's <code>startTransition()</code> does.\n            It will fall back to non-animated transitions if our browser doesn't support <code>document.startViewTransition</code>.\n        </p>\n\n        <x-code-viewer src=\"example3/view-transition.js\"></x-code-viewer>\n        <x-code-viewer src=\"example3/index.js\" name=\"example.js\"></x-code-viewer>\n\n        <iframe src=\"./example3/index.html\" title=\"example 3\" height=\"200\"></iframe>\n\n        <p>\n            While that takes care of feature-detecting, we can still run into timing issues.\n            For example, let's say that instead of toggling we were switching routes,\n            and the second route needs to load data prior to animating in.\n        </p>\n        <p>\n            So with HTML like this:\n        </p>\n\n        <pre><code>\n    &lt;p&gt;&lt;button&gt;Navigate&lt;/button&gt;&lt;/p&gt;\n    &lt;div id=\"route1\" class=\"route\"&gt;&lt;/div&gt;\n    &lt;div id=\"route2\" class=\"route\"&gt;&lt;/div&gt;\n        </code></pre>\n\n        <p>\n            We might intuitively choose to do something like this:\n        </p>\n\n        <x-code-viewer src=\"example4/index.js\" name=\"example.js\"></x-code-viewer>\n        <iframe src=\"./example4/index.html\" title=\"example 4\" height=\"200\"></iframe>\n\n        <p>\n            But, as you see when trying it out, it doesn't work. Because the <code>startTransition()</code>\n            calls end up overlapping each other, the animation is interrupted, and we get a jarring experience.\n            While this toy example can be made to work by tuning delays, in the real world those same delays are network-based, so there's no timing-based solution.\n            We also can't solve this by bundling everything into one single big view transition, because that would imply\n            blocking user input while a network request completes, which would be a bad user experience.\n        </p>\n        <p>\n            React solves all of this in the typical React way. It will smartly choose how to batch work\n            into successive calls to <code>document.startViewTransition()</code>. It will take into account where something loads lazily,\n            as in the previous example, and batch the work of animating in the content for the fallback in a separate view transition.\n        </p>\n        \n        <h3>Taking a queue</h3>\n\n        <p>\n            Distilling that approach to its essence, the really useful part of React's solution is the queueing and batching of work. \n            Any call to <code>startTransition()</code> that occurs while a view transition is running should be queued until after the transition completes,\n            and nested calls should have all their updates batched together.\n        </p>\n\n        <x-code-viewer src=\"example5/view-transition-part.js\" name=\"view-transition.js\"></x-code-viewer>\n\n        <p>\n            The <code>QueueingViewTransition</code> implementation is a straightforward batching of callbacks,\n            and a single call to <code>document.startViewTransition()</code> that executes them in order.\n            It is not included in the text of this article for brevity's sake, but linked at the bottom instead.\n        </p>\n        <p>\n            Applying that queueing solution on top of the previous example's unchanged code, \n            we suddenly see the magic of clean view transitions between dynamically loading routes.\n        </p>\n\n        <iframe src=\"./example5/index.html\" title=\"example 5\" height=\"200\"></iframe>\n\n        <h3>Back to the top</h3>\n\n        <p>\n             So as I was saying at the top, I like porting framework features to vanilla JS as a way of learning and exploring dumber and simpler solutions.\n             Which brings me to the playground for that learning, a full port of React's tour-de-force <code>&lt;ViewTransition&gt;</code> example to vanilla web code.\n        </p>\n\n        <iframe src=\"./example6/index.html\" title=\"example 6\" height=\"500\" scrolling=\"always\"></iframe>\n\n        <p>\n            The full code of this example is <a href=\"https://github.com/jsebrech/view-transition-element\">on GitHub</a>.\n            Arguably the 300 lines of code in the <code>lib/</code> folder of that example constitute a mini-framework,\n            but fascinating to me is that you can get so much mileage out of such a small amount of library code,\n            with the resulting single-page application being more or less the same number of lines as the React original.\n        </p>\n        <p>\n            That example also shows how to do a purely client-side router with clean URLs using <code>pushState()</code>.\n            This blog post has however gone too long already, so I'll leave that for another time.\n        </p>\n\n        <h3>One more thing</h3>\n\n        <p>\n            Oh yeah, I promised to talk about the thing with shadow DOM, and I promised a custom element.\n            Here is the thing with shadow DOM: when <code>document.startViewTransition()</code> is called from the light DOM,\n            it cannot see elements inside the shadow DOM that need to transition independently, \n            unless those elements are exposed as DOM parts and a <code>view-transition-name</code> style is set on them in the light DOM.\n        </p>\n        <p>\n            If the solution to that intrigues you, it's in the GitHub example repo as well as a &lt;view-transition&gt; custom element.\n            If that sounds like a bunch of mumbo jumbo instead, join the club.\n            Just one more reason to avoid shadow DOM.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/114668723520713225\"></blog-footer>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example1/app.js",
    "content": "import { routerEvents, interceptNavigation } from './view-route.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n\n    #route = '/';\n\n    constructor() {\n        super();\n        interceptNavigation(document.body);\n        routerEvents.addEventListener('navigate', (e) => {\n            this.#route = e.detail.url;\n            this.update();\n        });\n    }\n\n    connectedCallback() {\n        this.update();\n    }\n\n    update() {\n        if (this.#route === '/') {\n            this.innerHTML = 'This is the homepage. <a href=\"/details\">Go to the details page</a>.';\n        } else if (this.#route === '/details') {\n            this.innerHTML = 'This is the details page. <a href=\"/\">Go to the home page</a>.';\n        } else {\n            this.innerHTML = `The page ${this.#route} does not exist. <a href=\"/\">Go to the home page</a>.`;\n        }\n        this.innerHTML += `<br>Current route: ${this.#route}`;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example1/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 1</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n    <script src=\"app.js\" type=\"module\" defer></script>\n</head>\n<body>\n    <demo-app></demo-app>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example1/view-route.js",
    "content": "export const routerEvents = new EventTarget();\n\nexport const interceptNavigation = (root) => {\n    // convert link clicks to navigate events\n    root.addEventListener('click', handleLinkClick);\n    // convert navigate events to pushState() calls\n    routerEvents.addEventListener('navigate', handleNavigate);\n}\n\nconst handleLinkClick = (e) => {\n    const a = e.target.closest('a');\n    if (a && a.href) {\n        e.preventDefault();\n        const anchorUrl = new URL(a.href);\n        const pageUrl = anchorUrl.pathname + anchorUrl.search + anchorUrl.hash;\n        routerEvents.dispatchEvent(new CustomEvent('navigate', { detail: { url: pageUrl, a }}));\n    }\n}\n\nconst handleNavigate = (e) => {\n    history.pushState(null, null, e.detail.url);\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example2/app.js",
    "content": "import { routerEvents, interceptNavigation, matchesRoute } from './view-route.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n\n    #route = '/';\n\n    constructor() {\n        super();\n        interceptNavigation(document.body);\n        routerEvents.addEventListener('popstate', (e) => {\n            const matches =\n                matchesRoute('/details') || \n                matchesRoute('/');\n            this.#route = matches?.[1];\n            this.update();\n        });\n    }\n\n    connectedCallback() {\n        this.update();\n    }\n\n    update() {\n        if (this.#route === '/') {\n            this.innerHTML = 'This is the homepage. <a href=\"/details\">Go to the details page</a>.';\n        } else if (this.#route === '/details') {\n            this.innerHTML = 'This is the details page. <a href=\"/\">Go to the home page</a>.';\n        } else {\n            this.innerHTML = `The page ${this.#route} does not exist. <a href=\"/\">Go to the home page</a>.`;\n        }\n        this.innerHTML += `<br>Current route: ${this.#route}`;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example2/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 2</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n    <script src=\"app.js\" type=\"module\" defer></script>\n</head>\n<body>\n    <demo-app></demo-app>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example2/view-route-partial.js",
    "content": "const handleNavigate = (e) => {\n    history.pushState(null, null, e.detail.url);\n    routerEvents.dispatchEvent(new PopStateEvent('popstate'));\n}\n\n// update routes on popstate (browser back/forward)\nexport const handlePopState = (e) => {\n    routerEvents.dispatchEvent(new PopStateEvent('popstate', { state: e.state }));\n}\nwindow.addEventListener('popstate', handlePopState);\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example2/view-route-partial2.js",
    "content": "// ...\n\n// all routes will be relative to the document's base path\nconst baseURL = new URL(window.originalHref || document.URL);\nconst basePath = baseURL.pathname.slice(0, baseURL.pathname.lastIndexOf('/'));\n\n// returns an array of regex matches for matched routes, or null\nexport const matchesRoute = (path) => {\n    const fullPath = basePath + '(' + path + ')';\n    const regex = new RegExp(`^${fullPath.replaceAll('/', '\\\\/')}`, 'gi');\n    const relativeUrl = location.pathname;\n    return regex.exec(relativeUrl);\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example2/view-route.js",
    "content": "export const routerEvents = new EventTarget();\n\n// all routes will be relative to the document's base path\nconst baseURL = new URL(window.originalHref || document.URL);\nconst basePath = baseURL.pathname.slice(0, baseURL.pathname.lastIndexOf('/'));\n\nexport const interceptNavigation = (root) => {\n    // convert link clicks to navigate events\n    root.addEventListener('click', handleLinkClick);\n    // convert navigate events to pushState() calls\n    routerEvents.addEventListener('navigate', handleNavigate);\n}\n\nconst handleLinkClick = (e) => {\n    const a = e.target.closest('a');\n    if (a && a.href) {\n        e.preventDefault();\n        const anchorUrl = new URL(a.href);\n        const pageUrl = basePath + anchorUrl.pathname + anchorUrl.search + anchorUrl.hash;\n        routerEvents.dispatchEvent(new CustomEvent('navigate', { detail: { url: pageUrl, a }}));\n    }\n}\n\nconst handleNavigate = (e) => {\n    history.pushState(null, null, e.detail.url);\n    routerEvents.dispatchEvent(new PopStateEvent('popstate'));\n}\n\n// update routes on popstate (browser back/forward)\nexport const handlePopState = (e) => {\n    routerEvents.dispatchEvent(new PopStateEvent('popstate', { state: e.state }));\n}\nwindow.addEventListener('popstate', handlePopState);\n\n// returns an array of regex matches for matched routes, or null\nexport const matchesRoute = (path) => {\n    const fullPath = path.startsWith('/') ? basePath + '(' + path + ')' : '(' + path + ')';\n    const regex = new RegExp(`^${fullPath.replaceAll('/', '\\\\/')}`, 'gi');\n    const relativeUrl = location.pathname;\n    return regex.exec(relativeUrl);\n}\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example3/app.js",
    "content": "import { interceptNavigation } from './view-route.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n\n    constructor() {\n        super();\n        interceptNavigation(document.body);\n    }\n\n    connectedCallback() {\n        this.innerHTML = `\n        <view-route path=\"/(?:index.html)?$\">\n            This is the homepage. <a href=\"/details\">Go to the details page</a>, or\n            travel a <a href=\"/unknown\">path of mystery</a>.\n        </view-route>\n        <view-route path=\"/details\">\n            This is the details page. <a href=\"/\">Go to the home page</a>.\n        </view-route>\n        <view-route path=\"*\">\n            The page does not exist. <a href=\"/\">Go to the home page</a>.\n        </view-route>\n        `\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example3/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 3</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n    <script src=\"app.js\" type=\"module\" defer></script>\n</head>\n<body>\n    <demo-app></demo-app>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example3/view-route-partial.js",
    "content": "// ...\n\ncustomElements.define('view-route', class extends HTMLElement {\n\n    #matches = [];\n\n    get isActive() {\n        return !!this.#matches?.length;\n    }\n\n    get matches() {\n        return this.#matches;\n    }\n\n    set matches(v) {\n        this.#matches = v;\n        this.style.display = this.isActive ? 'contents' : 'none';\n        if (this.isActive) {\n            this.dispatchEvent(new CustomEvent('routechange', { detail: v, bubbles: true }));\n        }\n    }\n\n    connectedCallback() {\n        routerEvents.addEventListener('popstate', this);\n        this.update();\n    }\n\n    disconnectedCallback() {\n        routerEvents.removeEventListener('popstate', this);\n    }\n\n    handleEvent(e) {\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['path'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const path = this.getAttribute('path') || '/';\n        this.matches = this.matchesRoute(path) || [];\n    }\n\n    matchesRoute(path) {\n        // '*' triggers fallback route if no other route on the same DOM level matches\n        if (path === '*') {\n            const activeRoutes = \n                Array.from(this.parentNode.getElementsByTagName('view-route')).filter(_ => _.isActive);\n            if (!activeRoutes.length) return [location.pathname, '*'];\n        // normal routes\n        } else {\n            return matchesRoute(path);\n        }\n        return null;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example3/view-route.js",
    "content": "export const routerEvents = new EventTarget();\n\n// all routes will be relative to the document's base path\nconst baseURL = new URL(window.originalHref || document.URL);\nconst basePath = baseURL.pathname.slice(0, baseURL.pathname.lastIndexOf('/'));\n\nexport const interceptNavigation = (root) => {\n    // convert link clicks to navigate events\n    root.addEventListener('click', handleLinkClick);\n    // convert navigate events to pushState() calls\n    routerEvents.addEventListener('navigate', handleNavigate);\n}\n\nconst handleLinkClick = (e) => {\n    const a = e.target.closest('a');\n    if (a && a.href) {\n        e.preventDefault();\n        const anchorUrl = new URL(a.href);\n        const pageUrl = basePath + anchorUrl.pathname + anchorUrl.search + anchorUrl.hash;\n        routerEvents.dispatchEvent(new CustomEvent('navigate', { detail: { url: pageUrl, a }}));\n    }\n}\n\nconst handleNavigate = (e) => {\n    history.pushState(null, null, e.detail.url);\n    routerEvents.dispatchEvent(new PopStateEvent('popstate'));\n}\n\n// update routes on popstate (browser back/forward)\nexport const handlePopState = (e) => {\n    routerEvents.dispatchEvent(new PopStateEvent('popstate', { state: e.state }));\n}\nwindow.addEventListener('popstate', handlePopState);\n\n// returns an array of regex matches for matched routes, or null\nexport const matchesRoute = (path) => {\n    const fullPath = path.startsWith('/') ? basePath + '(' + path + ')' : '(' + path + ')';\n    const regex = new RegExp(`^${fullPath.replaceAll('/', '\\\\/')}`, 'gi');\n    const relativeUrl = location.pathname;\n    return regex.exec(relativeUrl);\n}\n\ncustomElements.define('view-route', class extends HTMLElement {\n\n    #matches = [];\n\n    get isActive() {\n        return !!this.#matches?.length;\n    }\n\n    get matches() {\n        return this.#matches;\n    }\n\n    set matches(v) {\n        this.#matches = v;\n        this.style.display = this.isActive ? 'contents' : 'none';\n        if (this.isActive) {\n            this.dispatchEvent(new CustomEvent('routechange', { detail: v, bubbles: true }));\n        }\n    }\n\n    connectedCallback() {\n        routerEvents.addEventListener('popstate', this);\n        this.update();\n    }\n\n    disconnectedCallback() {\n        routerEvents.removeEventListener('popstate', this);\n    }\n\n    handleEvent(e) {\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['path'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const path = this.getAttribute('path') || '/';\n        this.matches = this.matchesRoute(path) || [];\n    }\n\n    matchesRoute(path) {\n        // '*' triggers fallback route if no other route on the same DOM level matches\n        if (path === '*') {\n            const activeRoutes = \n                Array.from(this.parentNode.getElementsByTagName('view-route')).filter(_ => _.isActive);\n            if (!activeRoutes.length) return [location.pathname, '*'];\n        // normal routes\n        } else {\n            return matchesRoute(path);\n        }\n        return null;\n    }\n});\n"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example4/404.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <script>\n        var pathSegmentsToKeep = window.location.hostname === 'localhost' ? 0 : 1;\n\n        var l = window.location;\n        l.replace(\n            l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +\n            l.pathname.split('/').slice(0, 1 + pathSegmentsToKeep).join('/') + '/?/' +\n            l.pathname.slice(1).split('/').slice(pathSegmentsToKeep).join('/').replace(/&/g, '~and~') +\n            (l.search ? '&' + l.search.slice(1).replace(/&/g, '~and~') : '') +\n            l.hash\n        );\n    </script>\n</head>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/example4/index-partial.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <!-- ... -->\n</head>\n<body>\n    <script type=\"text/javascript\">\n        // preserve route\n        window.originalHref = window.location.href;\n        // decode from parameter passed by 404.html\n        (function (l) {\n            if (l.search[1] === '/') {\n                var decoded = l.search.slice(1).split('&').map(function (s) {\n                    return s.replace(/~and~/g, '&')\n                }).join('?');\n                window.history.replaceState(null, null,\n                    l.pathname.slice(0, -1) + decoded + l.hash\n                );\n            }\n        }(window.location))\n    </script>\n    \n    <!-- ... -->\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-06-25-routing/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Clean client-side routing</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"Finding a nice way of doing single-page app routing without a library.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <script type=\"module\" src=\"../../index.js\" defer></script>\n</head>\n<body>\n    <blog-header published=\"2025-06-25\">\n        <img src=\"image.webp\" alt=\"A twisty maze of stairways.\" loading=\"lazy\" />\n        <h2>Clean Client-side Routing</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            The main Plain Vanilla tutorial explains two ways of doing client-side routing.\n            Both use old school anchor tags for route navigation.\n            First is the traditional multi-page approach described on the Sites page as one HTML file per route,\n            great for content sites, not so great for web applications.\n            Second is the hash-based routing approach decribed on the Applications page, one custom element per route,\n            better for web applications, but not for having clean URLs or having Google index your content.\n        </p>\n        <p>\n            In this article I will describe a third way, single-file and single-page but with clean URLs using the <code>pushState</code> API,\n            and still using anchor tags for route navigation.\n            The conceit of this technique will be that it needs more code, and the tiniest bit of server cooperation.\n        </p>\n        <h3>Intercepting anchor clicks</h3>\n        <p>\n            To get a true single-page experience the first thing we have to do is intercept link tag navigation and redirect them to in-page events.\n            Our SPA can then respond to these events by updating its routes.\n        <p>\n\n        <x-code-viewer src=\"./example1/view-route.js\"></x-code-viewer>\n\n        <p>\n            In an example HTML page we can leverage this to implement routing in a <code>&lt;demo-app&gt;&lt;/demo-app&gt;</code> element.\n        </p>\n        <x-code-viewer src=\"./example1/app.js\"></x-code-viewer>\n        <iframe src=\"./example1/index.html\" title=\"example 1\"></iframe>\n        <p data-rss-exclude=\"true\">\n            <small><a href=\"./example1/index.html\" target=\"_blank\">open example 1 in a separate tab</a></small>\n        </p>\n\n        <p>\n            The first thing we're doing in <code>view-route.js</code> is the <code>interceptNavigation()</code> function.\n            It adds an event handler at the top of the DOM that traps bubbling link clicks and turns them into a <code>navigate</code> event instead of the default action of browser page navigation.\n            Then it also adds a <code>navigate</code> event listener that will update the browser's URL by calling <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/History/pushState\">pushState</a>.\n        </p>\n        <p>\n            In <code>app.js</code> we can listen to the same <code>navigate</code> event to actually update the routes.\n            Suddenly we've implemented a very basic in-page routing, but there are still a bunch of missing pieces.\n        </p>\n\n        <h3>There and back again</h3>\n\n        <p>\n            For one, browser back and forward buttons don't actually work.\n            We can click and see the URL update in the browser, but the page does not respond.\n            In order to do this, we need to start listening to <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event\">popstate</a> events.\n        </p>\n        <p>\n            However, this risks creating diverging code paths for route navigation, one for the <code>navigate</code> event and one for the <code>popstate</code> event.\n            Ideally a single event listener responds to both types of navigation.\n            A simplistic way of providing a single event to listen can look like this:\n        </p>\n        <x-code-viewer src=\"./example2/view-route-partial.js\" name=\"view-route.js (partial)\"></x-code-viewer>\n        <p>\n            Now our views can respond to <code>popstate</code> events and update based on the current route.\n            A second question then becomes: what is the current route? The <code>popstate</code> event does not carry that info.\n            The <code>window.location</code> value does have that, and it is always updated as we navigate, but because it has the full URL it is cumbersome to parse.\n            What is needed is a way of easily parsing it, something like this:\n        </p>\n        <x-code-viewer src=\"./example2/view-route-partial2.js\" name=\"view-route.js (continued)\"></x-code-viewer>\n        <p>\n            The <code>matchesRoute()</code> function accepts a regex to match as the route,\n            and will wrap it so it is interpreted relative to the current document's URL,\n            making all routes relative to our single page.\n            Now we can clean up the application code leveraging these new generic routing features:\n        </p>\n        <x-code-viewer src=\"./example2/app.js\"></x-code-viewer>\n        <iframe src=\"./example2/index.html\" title=\"example 2\"></iframe>\n        <p data-rss-exclude=\"true\">\n            <small><a href=\"./example2/index.html\" target=\"_blank\">open example 2 in a separate tab</a></small>\n        </p>\n        <p>\n            Opening that in a separate tab we can see that the absolute URL neatly updates with the routes,\n            that browser back/forwards navigation updates the view, and that inside the view the route is\n            relative to the document.\n        </p>\n        <p>\n            Because <code>matchesRoute()</code> accepts a regex,\n            it can be used to capture route components that are used inside of the view.\n            Something like <code>matchesRoute('/details/(?&lt;id&gt;[\\\\w]+)')</code> would\n            put the ID in <code>matches.groups.id</code>. It's simple, but it gets the job done.\n        </p>\n\n        <h3>Can you use it in a sentence?</h3>\n\n        <p>\n            While this rudimentary way of detecting routes works, adding more routes quickly becomes unwieldy.\n            It would be nice to instead have a declarative way of wrapping parts of views inside routes.\n            Enter: a custom element to wrap each route in the page's markup.\n        </p>\n        <x-code-viewer src=\"./example3/view-route-partial.js\" name=\"view-route.js (partial)\"></x-code-viewer>\n        <p>\n            Now we can rewrite our app to be a lot more declarative, while preserving the behavior.\n        </p>\n        <x-code-viewer src=\"./example3/app.js\"></x-code-viewer>\n        <iframe src=\"./example3/index.html\" title=\"example 3\"></iframe>\n        <p data-rss-exclude=\"true\">\n            <small><a href=\"./example3/index.html\" target=\"_blank\">open example 3 in a separate tab</a></small>\n        </p>\n\n        <h3>404 not found</h3>\n\n        <p>\n            While things now look like they work perfectly, the illusion is shattered upon reloading the page when it is on the details route.\n            To get rid of the 404 error we need a handler that will redirect to the main index page.\n            This is typically something that requires server-side logic, locking us out from simple static hosting like GitHub Pages,\n            but thanks to the kindness of internet strangers, <a href=\"https://github.com/rafgraph/spa-github-pages\">there is a solution</a>.\n        </p>\n        <p>\n            It involves creating a <code>404.html</code> file that GitHub will load for any 404 error (the tiny bit of server cooperation).\n            In this file the route is encoded as a query parameter, the page redirects to <code>index.html</code>,\n            and inside that index page the route is restored.\n        </p>\n        <x-code-viewer src=\"example4/404.html\"></x-code-viewer>\n        <x-code-viewer src=\"example4/index-partial.html\" name=\"index.html\"></x-code-viewer>\n\n        <p>\n            Adding this last piece to what we already had gets us a complete routing solution for vanilla single page applications\n            that are hosted on GitHub Pages. Here's a live example hosted from there:\n        </p>\n        <iframe src=\"https://sebrechts.net/view-route/\" title=\"example 4\" height=\"300\"></iframe>\n\n        <p>\n            To full code of <code>view-route.js</code> and of this example <a href=\"https://github.com/jsebrech/view-route\">is on GitHub</a>.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/114745575673419397\"></blog-footer>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-07-13-history-architecture/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>The history of web application architecture</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"The many different ways of building for the web, and their many frustrations.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <script type=\"module\" src=\"../../index.js\" defer></script>\n</head>\n<body>\n    <blog-header published=\"2025-07-13\">\n        <img src=\"image.webp\" alt=\"a colorful office building viewed at an angle, with the sky behind\" />\n        <h2>The history of web application architecture</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            I'm old enough to remember what it was like. I first got online in 1994, but by then I was using computers for a few years already.\n            That means I was there for the whole ride, the entire history of web application architecture, \n            from the before times to the present day.\n            So this post will be an overview of the various ways to make a web app, past and present, \n            and their relative trade-offs as I experienced them.\n        </p>\n        <p>\n            Just to set expectations right: this will cover architectures targeted primarily at proper applications, \n            of the sort that work with user data, and where most screens have to be made unique based on that user data.\n            Web sites where the different visitors are presented with identical pages are a different beast.\n            Although many of these architectures overlap with that use case, it will not be the focus here.\n        </p>\n        <p>\n            Also, while I will be mentioning some frameworks, they are equally not the focus.\n            Where you see a framework, you can slot in vanilla web development with a bespoke solution.\n        </p>\n        <p>\n            This will be a long one, so grab a snack, take some time, and let's get going.\n        </p>\n\n        <h3>Before time began</h3>\n        <p>\n            Back when people first went online, the ruling architecture was <em>offline-first</em>.\n            It looked sort of like this:\n        </p>\n        <img src=\"architectures/old-school-desktop.webp\" alt=\"architecture diagram of user sending a local file via e-mail\" />\n        <p>\n            Our user would have a proper desktop application, written in C or C++ most likely,\n            and that would work with local files on their local file system, all perfectly functional when offline.\n            When they wanted to \"go online\" and share their work, they would dial in to the internet,\n            start their e-mail client and patiently send an e-mail to their friend or colleague containing \n            a copy of their file as an attachment.\n        </p>\n        <p>\n            This architecture was very simple, and it worked well in the absence of a reliable and fast internet connection.\n            This was a good thing because at the time most people <em>never had</em> a reliable and fast internet connection.\n            There were problems though. For one, the bootstrapping problem: how do you get everyone to have the application \n            installed so they can open and edit the file they received via e-mail?\n            Also, the syncing problem: how are changes kept in sync between multiple devices and users?\n            Merging edits from different files that could have <em>weeks</em> of incompatible edits was always \n            somewhere between frustrating and impossible.\n        </p>\n\n        <h3>Traditional server-side rendering</h3>\n        <p>\n            Web applications promised they would solve both problems. At first we built them like this:\n        </p>\n        <img src=\"architectures/traditional-ssr.webp\" alt=\"architecture diagram of a traditional server-side rendered web application\" width=\"1586\" height=\"1324\" loading=\"lazy\" />\n        <p>\n            The first thing we did was move all of the stuff from all of the users into a central database somewhere online.\n            Because this database was shared between the users, it became a lot more easy to keep their changes in sync.\n            If one user made an edit to something, everyone else would see it on the next refresh.\n        </p>\n        <p>\n            To allow users to actually get at this database we had to give them an application to do it.\n            This new-fangled thing called a <em>web application</em> running on a <em>web application server</em> would take http requests\n            coming from the user's browser, SQL query the database for the right set of stuff, \n            and send back an entire web page. Every click, every submit, it would generate a whole new page.\n        </p>\n        <p>\n            Deployment of those early web applications was often suspiciously simple:\n            someone would connect via FTP to a server, and copy over the files from their local machine.\n            There often weren't even any build steps. There was no step 3.\n        </p>\n        <p>\n            On the one hand this architecture was convenient. It solved the bootstrapping problem \n            by only demanding that each user have a web browser and an internet connection.\n            It also moved all of the application logic over to the server, keeping it neatly in one place.\n            Crucially it kept the browser's task minimal, important in an era where browsers were much less capable\n            and PC's were orders of magnitude slower than today. If done well, it could even be used to make\n            web applications that still worked with JavaScript disabled. My first mobile web app was like that,\n            sneakily using HTML forms with multiple submit actions and hidden input fields\n            to present interactive navigation through a CRUD interface.\n        </p>\n        <p>\n            On the other hand, it had many problems, especially early on. HTML wasn't very good, CSS was in its infancy,\n            and early JavaScript was mostly useless. It was hard going building <em>anything at all</em> on the early web.\n            On top of that, web developers were a new breed, and they had to relearn many of the architecture lessons their desktop developer\n            colleagues had already learned through bitter experience. For example, everyone has heard of the adage\n            \"If you don't choose a framework, you'll end up building a worse one yourself.\" That is because for the first few years\n            building your own terrible framework as you went was the norm, until everyone wisened up and started preaching this wisdom. \n            For sure, my own first experiments in web application development in PHP 3 and 4 were all \n            without the benefit of a proper framework.\n        </p>\n        <p>\n            Web developers also had to learn lessons that their desktop counterparts never had to contend with.\n            Moving the application to the server was convenient, but it exposed it to hackers from all across the world,\n            and the early web application landscape was riddled with embarrassing hacks.\n            Because the threat level on the internet keeps rising this remains a major headache to this day.\n        </p>\n        <p>\n            Another novel problem was having to care a whole lot about connectivity and server uptime.\n            Because users literally couldn't do anything at all if they didn't have a connection to a working web server,\n            making sure that connection was always there became a pervasive headache.\n            Going to a site and seeing an error 500 message was unsurprisingly common in those early years.\n        </p>\n        <p>\n            The biggest problems however were throughput, bandwidth and latency. Because almost every click had to reload the whole page,\n            doing anything at all in those early web applications was <em>slow</em>, like <em>really, really slow</em>.\n            At the time, servers were slow to render the page, networks slow to transport it, and PC's and browsers slow to render.\n            That couldn't stand, so something had to change. It was at this point that we saw a fork in the road,\n            and the web developer community split up into two schools of thought that each went their own way.\n            Although, as you will see, they are drawing closer again.\n        </p>\n\n        <h3>Modern server-side rendering</h3>\n\n        <p>\n            One branch of the web development tree doubled down on server-side rendering,\n            building further on top of the existing server-side frameworks.\n        </p>\n        <img src=\"architectures/liveview.webp\" alt=\"architecture diagram of a server-side rendered application with liveview templates\" width=\"1588\" height=\"1324\" loading=\"lazy\" />\n        <p>\n            They tackled the problems imposed by throughput and latency by\n            moving over to a model of partial page updates, where small bits of user-activated JavaScript\n            (originally mostly built with jQuery) would update parts of the page with HTML partials\n            that they fetched from the server.\n        </p>\n        <p>\n            The evolution of this architecture are so called <em>LiveViews</em>.\n            This is a design first popularized by the Phoenix framework for the obscure Elixir programming language,\n            but quickly <a href=\"https://github.com/liveviews/liveviews\">adopted in many places</a>.\n        </p>\n        <p>\n            It uses framework logic to automatically wire up server-side generated templates with bits of JavaScript\n            that will automatically call the server to fetch partial page updates when necessary.\n            The developer has the convenience of not thinking about client-side scripting, \n            while the users get an interactive user experience similar to a JavaScript-rich frontend.\n            Typically the client keeps an open websocket connection to the server,\n            so that server-side changes are quickly and automatically streamed into the page as soon as they occur.\n        </p>\n        <p>\n            This architecture is conceptually simple to work with as all the logic remains on the server.\n            It also doesn't ask much from the browser, good for slow devices and bandwidth-constrained environments.\n            As a consequence it finds a sweet spot in mostly static content-driven web sites.\n        </p>\n        <p>\n            But nothing is without trade-offs. This design hits the server on almost every interaction and has no path to offline functionality.\n            Network latency and reliability are its UX killer, and especially on mobile phones &ndash; the main way people interact with web apps these days &ndash;\n            those can still be a challenge. While this can be mitigated somewhat through browser caching, the limitation is always there.\n            After all, the more that page content is dictated by realtime user input, the more necessary it becomes to push logic to the client.\n            In cases where the network is good however, it can seem like magic even for highly interactive applications, \n            and for that reason it has its diehard fans.\n        </p>\n\n        <h3>Client-side rendering</h3>\n        <p>\n            There was another branch of web development practice, let's say the ones who were fonder\n            of clever architecture, who had a crazy thought: what if we moved rendering data to HTML from the server to the browser?\n            They built new frameworks, in JavaScript, designed to run in the browser\n            so that the application could be shipped as a whole as part of the initial page load, \n            and every navigation would only need to fetch data for the new route.\n            In theory this allowed for smaller and less frequent roundtrips to the server,\n            and therefore an improvement to the user experience.\n            Thanks to a blooming cottage industry of industry insiders advertising its benefits, it became the dominant architecture for new web applications,\n            with React as the framework of choice to run inside the browser.\n        </p>\n        <p>\n            This method taken to its modern best practice extreme looks like this:\n        </p>\n        <img src=\"architectures/modern-SPA.webp\" alt=\"Architecture diagram of a client-side rendered single-page application\" width=\"1830\" height=\"1444\" loading=\"lazy\" />\n        <p>\n            It starts out by moving the application, its framework, and its other dependencies over to the browser.\n            When the page is loaded the entire bundle gets loaded, and then pages can be rendered as routes inside of the single-page application.\n            Every time a new route needs to be rendered the data gets fetched from the server, not the HTML.\n        </p>\n        <p>\n            The web application server's job is now just providing the application bundle as a single HTML page,\n            and providing API endpoints for loading JSON data for every route. \n            Because those API endpoints naturally end up mirroring the frontend's routes this part usually gets called the <em>backend-for-frontend</em>.\n            This job was so different from the old web server's role that a new generation of frameworks sprung up to be a better fit. \n            Express on node became a very popular choice, as it allowed a great deal of similarity between browser and server codebases,\n            although in practice there's usually not much actual code in common.\n        </p>\n        <p>\n            For security reasons &ndash; after all, the web application servers are on the increasingly dangerous public internet &ndash;\n            the best practice became to host backends-for-frontend in a DMZ, a demilitarized zone\n            where the assumption has to be that security is temporary and hostile interlopers could arrive at any time.\n            In addition, if an organization has multiple frontends (and if they have a mobile app they probably have at least two),\n            then this DMZ will contain multiple backends for frontend.\n        </p>\n        <p>\n            Because there is only a single database to share between those different BFFs, \n            and because of the security risks of connecting to the database from the dangerous DMZ,\n            a best practice became to keep the backend-for-frontend focused on just the part of serving the frontend,\n            and to wrap the database in a separate thing. This separate <em>microservice</em>\n            is an application whose sole job is publishing an API that gatekeeps access to the database.\n            This API is usually in a separate network segment, shielded by firewalls or API gateways,\n            and it is often built in yet another framework better tailored for building APIs, \n            or even in a different programming language like Go or C#.\n        </p>\n        <p>\n            Of course, having only one microservice is kind of a lonely affair, \n            so even organizations of moderate size would often end up having their backends-for-frontend each talking to multiple microservices.\n        </p>\n        <p>\n            That's just too many servers to manage, too many network connections to configure, too many builds to run, \n            so people by and large stopped managing their own servers, either for running builds or for runtime hosting.\n            Instead they moved to the cloud, where someone else manages the server, and hosted their backends\n            as docker containers or serverless functions deployed by git-powered CI/CD pipelines.\n            This made some people fabulously wealthy. After all, 74% of Amazon's profit is made from AWS,\n            and over a third of Microsoft's from Azure.\n            It is no accident that there is a persistent drumbeat that everyone should move everything to the cloud.\n            Those margins aren't going to pad themselves.\n        </p>\n        <p>\n            Incidentally, microservices as database intermediary are also a thing in the world of server-side rendered applications,\n            but in my personal observation those teams seem to choose this strategy less often.\n            Equally incidentally, the word <em>serverless</em> in the context of serverless functions was and is highly amusing to me, \n            since it requires just as many servers, if not more. (I know why it's called that way, that doesn't make it any less funny.)\n        </p>\n        <p>\n            On paper this client-side rendered architecture has many positive qualities. It is highly modular,\n            which makes the work easy to split up across developers or teams. It pushes page rendering logic into\n            the browser, creating the potential to have a low latency and high quality user experience.\n            The layered nature of the backend and limited scope of the internet-facing backend-for-frontend forms\n            a solid defensive moat against cyberattacks. And the cloud-hosted infrastructure is low effort to manage and easy to scale.\n            A design like this is every architecture astronomer's dream, and I was for a while very enamored with it myself.\n        </p>\n        <p>\n            In practice though, it just doesn't work very well. It's just too <em>complicated</em>.\n            For larger experienced teams in large organizations it can kind of sort of make sense,\n            and it is no surprise that big tech is a heavy proponent of this architecture.\n            But step away from web-scale for just a second and there's too many parts to build and deploy and keep track of,\n            too many technologies to learn, too many hops a data request has to travel through. \n        </p>\n        <p>\n            The application's logic gets smeared out across three or more independent codebases,\n            and a lot of overhead is created in keeping all of those in sync.\n            Adding a single data field to a type can suddenly become a whole project. For one application I was working on\n            I once counted in how many places a particular type was explicitly defined, and the tally reached lucky number 7.\n            It is no accident that right around the time that this architecture peaked the use of monorepo tools \n            to bundle multiple projects into a single repository peaked as well.\n        </p>\n        <p>\n            Go talk to some people just starting out with web development\n            and see how lost they get in trying to figure out all of this <em>stuff</em>, \n            learning all the technologies comprising the Rube Goldberg machine that produces a webpage at the end.\n            See just how little time they have left to dedicate to learning vanilla HTML, CSS and JS, \n            arguably the key things a beginner should be focusing on.\n        </p>\n        <p>\n            Moreover, the promise that moving the application entirely to the browser would improve the user experience mostly <a href=\"https://gitnation.com/contents/project-fugu-bringing-hardware-capabilities-to-the-web-safely\">did not pan out</a>.\n            As applications built with client-side frameworks like React or Angular grew, the bundle to be shipped in a page load ballooned to <em>megabytes</em> in size.\n            The slowest quintile of devices and network connections struggled mightily with these heavy JavaScript payloads.\n            It was hoped that Moore's law would solve this problem, but the dynamics of how (mobile) device and internet provider markets work\n            mean that it hasn't been, and that it won't be any time soon. It's not impossible to build a great user experience \n            with this architecture, but you're starting from behind. Well, at least for public-facing web applications.\n        </p>\n\n        <h3>Client-side rendering with server offload</h3>\n        <p>\n            The designers of client-side frameworks were not wholly insensitive to the frustrations of developers \n            trying to make client-side rendered single-page applications work well on devices and connections \n            that weren't up to the job. They started to offload more and more of the rendering work back to the server.\n            In situations where the content of a page is fixed, <em>static site generation</em> can execute\n            the client-side framework at build time to pre-render pages to HTML.\n            And for situations where content has a dynamic character, <em>server-side rendering</em> was reintroduced \n            back into the mix to offload some of the rendering work back to the server.\n        </p>\n        <p>\n            The current evolution of these trends is the streaming single-page application:\n        </p>\n        <img src=\"architectures/streaming-SPA.webp\" alt=\"architecture diagram of a streaming single-page application\" width=\"1830\" height=\"1544\"loading=\"lazy\" />\n\n        <p>\n            In this architecture the framework runs the show in both backend-for-frontend and in the browser.\n            It decides where the rendering happens, and only pushes the work to the browser that must run there.\n            When possible the page is shipped prerendered to the browser and the code for the prerendered parts \n            is not needed in the client bundle.\n            Because some parts of the page are more dynamic than others, they can be rendered on-demand in the server \n            and <em>streamed</em> to the browser where they are slotted into the prerendered page.\n            The bundle that is shipped to the browser can be kept light-weight because it mostly just needs \n            to respond to user input by streaming the necessary page updates from the server over an open websocket connection.\n        </p>\n        <p>\n            If that sounds suspiciously like the architecture for modern server-side rendering that I described before,\n            that is because it basically is. While a Next.JS codebase is likely to have some\n            client-rendered components still, the extreme of a best practice Astro codebase would \n            see every last component rendered on the server. \n            In doing that they arrive at something functionally no different from LiveView architecture,\n            and with a similar set of trade-offs. These architectures are simpler to work with, but they \n            perform poorly for dynamic applications on low reliability or high latency connections,\n            and they cannot work offline.\n        </p>\n        <p>\n            Another major simplication of the architecture is getting rid of the database middleman.\n            Microservices and serverless functions are not as hyped as they were, \n            people are happy to build so-called <em>monoliths</em> again, \n            and frameworks are happy to recommend they do so.\n            The meta-frameworks now suggest that the API can be merged into the web application frontend, \n            and the framework will know that those parts are only meant to be run on the server.\n            This radically simplifies the codebase, we're back to a single codebase for the entire application\n            managed by a single framework.\n        </p>\n        <p>\n            However, <a href=\"https://en.wikipedia.org/wiki/No_such_thing_as_a_free_lunch\">TANSTAAFL</a>. This simplification comes at the expense of other things. The Next.JS documentation may claim\n            <em>\"Since Server Components are rendered on the server, you can safely make database queries using an ORM or database client.\"</em>\n            but that doesn't mean that it's actually safe to allow the part that faces the internet to have a direct line to the database.\n            Defense in depth was a good idea, and we're back to trading security for simplicity.\n            There were other reasons that monoliths once fell out of favor. It's like we're now forgetting lessons that were already learned.\n        </p>\n\n        <h3>Where does that leave us?</h3>\n\n        <p>\n            So, which architecture should you pick? I wish I could tell you,\n            but you should have understood by now that the answer was always going to be <em>it depends</em>.\n            Riffing on the work of Tolstoy: all web architectures are alike in that they are unhappy in their own unique way.\n        </p>\n        <p>\n            In a sense, all of these architectures are also unhappy in the same way:\n            there's a whole internet in between the user and their data.\n            There's a golden rule in software architecture: you can't beat physics with code.\n            We draw the internet on diagrams as a cute little cloud, pretending it is not a physical thing.\n            But the internet is wires, and antennas, and satellites, and data centers, and all kinds of physical things and places.\n            Sending a signal through all those physical things and places will always be somewhat unreliable and somewhat slow.\n            We cannot reliably deliver on the promise of a great user experience as long as we put a cute little cloud \n            in between the user and their stuff.\n        </p>\n        <p>\n            In the next article I'll be exploring an obscure but very different architecture,\n            a crazy thought similar to that of client-side rendering:\n            what happens when we move the user's data from the server back into the client?\n            What is <a href=\"../2025-07-16-local-first-architecture/\">local-first web application architecture</a>?\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/114846883855698259\"></blog-footer>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-07-16-local-first-architecture/example1.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Latency simulator</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <style>\n        @import \"../../../../styles/reset.css\";\n        body {\n            font-family: system-ui, sans-serif;\n            margin: 1em;\n        }\n    </style>\n</head>\n<body>\n    <p>\n        <label for=\"latency\">Round-trip latency:</label>\n        <input id=\"latency\" type=\"range\" min=\"50\" max=\"1000\" step=\"50\" value=\"100\" />\n    </p>\n    <p id=\"display\"></p>\n    <p id=\"frame\" style=\"text-align: center; padding: 0.5em;\">\n        <button id=\"btn1\">Blue</button>\n        <button id=\"btn2\">Yellow</button>\n    </p>\n    <script>\n        const latency = document.getElementById('latency');\n        const display = document.getElementById('display');\n        const frame = document.getElementById('frame');\n        const btn1 = document.getElementById('btn1');\n        const btn2 = document.getElementById('btn2');\n\n        function updateDisplay() {\n            display.textContent = `${latency.value} ms`;\n        }\n\n        function updateFrameColor(color) {\n            btn1.disabled = true;\n            btn2.disabled = true;\n            setTimeout(() => {\n                frame.style.backgroundColor = color;\n                btn1.disabled = false;\n                btn2.disabled = false;\n            }, latency.value);\n        }\n\n        btn1.onclick = () => updateFrameColor('cornflowerblue');\n        btn2.onclick = () => updateFrameColor('gold');\n\n        latency.addEventListener('input', updateDisplay);\n        updateDisplay();\n    </script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2025-07-16-local-first-architecture/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Local-first web application architecture</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"Maybe we just need to dig a little deeper (into the client).\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <script type=\"module\" src=\"../../index.js\" defer></script>\n</head>\n<body>\n    <blog-header published=\"2025-07-16\">\n        <img src=\"image.webp\" alt=\"a low view of a beach, grains of sand sharply in focus, a pier blurry in the distance\" />\n        <h2>Local-first web application architecture</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            Previously in <a href=\"../2025-07-13-history-architecture/\">the history of web application architecture</a> \n            I covered the different ways that people have tried to build web applications, and how all of them came with \n            their own unique set of drawbacks.\n            Also mentioned was how there is one drawback that they all share: \n            there is a whole internet between a user and their data,\n            and this makes it hard to deliver a top notch user experience.\n        </p>\n\n        <h3>Tail latency matters</h3>\n        <p>\n            On the surface, it doesn't seem like this should be the case. Networks are fast, right?\n            But the truth is, they're only fast for some of the people some of the time.\n        </p>\n        <p>\n            Look at the page load numbers (LCP) of this website for the last week (gathered anonymously):\n        </p>\n        <ul>\n            <li>P50: 650 ms</li>\n            <li>P75: 1200 ms</li>\n            <li>P90: 2148 ms</li>\n            <li>P99: 10,636 ms</li>\n        </ul>\n        <p>\n            While half of the visits see page load times well below a second,\n            many see times that are much, much higher. Part of this is due to geography.\n            Going through <a href=\"https://learn.microsoft.com/en-us/azure/networking/azure-network-latency?tabs=Europe%2CWesternEurope\">Azure's P50 roundtrip latency times</a> we can see that\n            some remote connections, like France to Australia, are in the 250 ms range, data center to data center.\n            Azure doesn't disclose P99 latency, but one may assume it is a multiple of the P50 latency.\n        </p>\n        <p>\n            But our user isn't sitting in a data center, they're probably on a mobile phone,\n            connecting through a slow network. Looking at <a href=\"https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Understanding_latency\">mozilla's minimum latency numbers</a> \n            we can see that it's not unusual to see another 100 ms of roundtrip latency added by the mobile network,\n            and in reality owing to packet loss and TCP retries it can be a lot more. My own experience taking the train into the office,\n            and trying to get some work done, is that the web can slow to a crawl as I pass through dead zones.\n            This is in a densely populated area in a rich country on the most expensive cell service provider. \n            Most people do not have these same luxuries.\n        </p>\n        <p>\n            So it's not unusual to see latencies climb far above the threshold of 100 ms,\n            commonly regarded as the threshold for an <em>immediate</em> response.\n            For an unlucky minority of users latencies can even climb above half a second.\n            This matters because if we have to hit the server to do something with the user's data \n            on every click, we will have noticeable and frustrating delay in the interaction.\n            To get a feel of this delay, here's a simulator where you can try out roundtrip latencies\n            from 50 ms to one second:\n        </p>\n        <iframe src=\"example1.html\" title=\"roundtrip latency simulator\" height=\"200\" loading=\"lazy\"></iframe>\n        <p>\n            Can you tell how much nicer 100 ms and below feel?\n            How the buttons actually <em>feel</em> lighter to press?\n            By contrast, 500 ms and above of roundtrip latency are just a slog, painful to use.\n            The buttons are heavy and cumbersome. This is human psychology at work,\n            and these lessons were learned in the desktop era but forgotten and never quite relearned for the web.\n            If we put over 100 ms of latency in between a user's click and the resulting effect\n            they will feel some degree of frustration, and we know that the internet cannot deliver below 100 ms of roundtrip latency\n            except in the luckiest of cases.\n        </p>\n        \n        <h3>Solutions</h3>\n\n        <p>\n            We can use some kind of closer-to-the-user cache,\n            in the form of a CDN or a browser cache or a service worker. This allows the content that needs to be loaded \n            based on the user's click to be fetched from something that has a better shot at being below that magic 100 ms\n            of latency. But this only works if what we need to load can be cached,\n            and if we can afford to cache it. For a web application that works with user data, this is typically not the case.\n        </p>\n        <p>\n            We can host the application in a georedundant way, have application servers\n            across the world and use a georedundant database like Google Spanner or Azure Cosmos DB. \n            This quickly gets complicated and expensive, and can only be achieved \n            through a great amount of vendor lock-in. Crucially, it probably does not get us past the 100 ms barrier anyway.\n        </p>\n        <p>\n            We can render client-side, using JavaScript to create and update the HTML page,\n            so that an update on the screen can happen immediately after the user's click.\n            But this only works if what the user is doing is not updating a piece of server-side data.\n            Otherwise we have to show some kind of loading or saving indicator until the server responds, \n            and then we're back to roundtrip latency.\n        </p>\n        <p>\n            Bottom line, and once again: the basic problem is that the internet is in between the user and their data.\n            So what if we moved the data to the user?\n        </p>\n\n        <h3>Local-first</h3>\n\n        <p>\n            This concept has been around for a while and it is known as a <a href=\"https://www.inkandswitch.com/essay/local-first/\">local-first application</a>.\n            To apply it to the web, let's start from the basic design of a client-side rendered web application\n            as covered in the previous article:\n        </p>\n        <img src=\"architectures/modern-SPA.webp\" alt=\"architecture diagram of a client-side rendered web application\" width=\"1830\" height=\"1444\" loading=\"lazy\" />\n        <p>\n            This design does not need the server for rendering, so it has the theoretical potential to hit 100 ms.\n            But because the user's interactions have to fetch data from the remote database and update it as well &ndash; \n            a database sitting multiple network hops away &ndash;\n            in practice we rarely actually hit that low latency.\n            We can <em>move the data to the user</em> by doing something like this:\n        </p>\n        <img src=\"architectures/local-first-partial.webp\" alt=\"architecture diagram of a local-first application with server-side sync\" width=\"1806\" height=\"1502\" loading=\"lazy\" />\n        <p>\n            The user's data gets duplicated into a local IndexedDB. More than duplicated actually as\n            this becomes the only copy of the data that the user will interact with directly.\n            The <em>backend-for-frontend</em> and API that used to gatekeep access to this data similarly get moved into the client,\n            as part of a service worker. This worker code can be very similar to what the server-side version would be, \n            it can even reuse express (although it probably shouldn't).\n            Because the service worker's API for all intents and purposes looks like a server-side API to the frontend codebase,\n            that frontend can be built in all the usual ways, \n            except now with the guarantee that every server roundtrip completes in milliseconds.\n        </p>\n        <p>\n            To avoid slow page loads each time the web application is opened\n            it also needs to be cached locally as part of the service worker.\n            By packaging this as a <em>progressive web app</em> installs become possible onto the user's home screen,\n            giving an experience not that unlike installing a native mobile app.\n            The application server's job is now reduced to only providing that initial application install,\n            and it can become a simple (and free) static web host.\n        </p>\n        \n        <h3>Here comes trouble</h3>\n        <p>\n            Both the application and the data are now running locally,\n            meaning the user doesn't need the network <em>at all</em> to get things done.\n            This isn't just local-first, it is offline-first.\n            But like all things in software architecture, we are trading one set of problems for another.\n        </p>\n        <p>\n            There still needs to be a way to get data onto other devices, or to other users,\n            or simply backed up into the cloud. That means the service worker also gets the job of\n            (asynchronously) uploading changes to a server API which will store it in a database,\n            as well as pulling server-side changes back down. The server-side version acts as the master copy,\n            and the server-side API gets the thankless job of merging client-side changes with it.\n        </p>\n        <p>\n            Not so fast though. Our user might be editing offline for a considerably long time,\n            and the data on the server may have been changed in the meanwhile from another device or by another user.\n            The job of merging those changes can be ... <em>complicated</em>.\n            A good strategy is needed for merging. A possible path is to use CRDT algorithms from a library like \n            <a href=\"https://github.com/automerge/automerge\">automerge</a>, as suggested by the local-first article linked above.\n            However, for many cases a simpler bespoke algorithm that is aware of the specific data types being merged probably works well enough,\n            as I discovered when making an offline-capable work orders web application that used this strategy.\n        </p>\n        <p>\n            As the local-first application is now directly talking to this API,\n            it needs a way to authenticate. This can be a reason to still have a minimal \n            <em>backend-for-frontend</em> on the server. An alternative is to use a separate \n            OpenID Connect identity provider with a PKCE authorization flow to obtain an access token.\n            <a href=\"https://blog.postman.com/what-is-pkce/\">PKCE</a> is an authorization flow developed for use by mobile apps but also usable by web apps \n            that enables secretless API authentication.\n        </p>\n        <p>\n            Another major caveat is that the entire codebase needs to be on the client,\n            which necessitates keeping it under a tight performance and size budget.\n            Careful curation of dependencies is key, and a javascript footprint that runs in the megabytes is verboten.\n            Vanilla web development can be a solution here, with its emphasis on using the platform to its limits\n            without bringing in dependencies. A lightweight framework like Lit or Preact will do as well.\n        </p>\n        <p>\n            This isn't just a theoretical exercise. The team at <a href=\"https://superhuman.com/\">Superhuman</a> built their better gmail than gmail \n            more or less as described here, using React as the framework, and the thing that sets their web app apart is its blistering speed.\n            You can go read how they did it on their blog (<a href=\"https://blog.superhuman.com/architecting-a-web-app-to-just-work-offline-part-1/\">part 1</a>, \n            <a href=\"https://blog.superhuman.com/building-reliable-apps-on-unreliable-networks/\">part 2</a>) or listen to the retelling on the \n            <a href=\"https://syntax.fm/show/918/extreme-native-perf-on-the-web-with-superhuman\">Syntax podcast</a>.\n        </p>\n\n        <h3>Loco-first</h3>\n\n        <p>\n            But we can push it even further, in theory at least. In the previous iteration of the architecture we still have\n            the application-specific database and syncing logic on the server,\n            but what if we instead did away with every last piece of server-side application logic?\n        </p>\n        <img src=\"architectures/local-first-full.webp\" alt=\"architecture diagram of a local-first application without server-side logic\" width=\"1768\" height=\"1372\" loading=\"lazy\" />\n        <p>\n            The syncing engine now gets moved in the client, and what it uploads to the server are just files.\n            That means all we need is a generic cloud drive, like Dropbox or Onedrive.\n            These cloud drive services often support cross-origin API access with OpenID Connect authentication using PKCE.\n            That means the service worker in the client doesn't need any application servers to upload its data\n            to the cloud storage.\n        </p>\n        <p>\n            The onboarding experience becomes a choice screen where the user picks their cloud drive option.\n            The application will redirect the user to the Dropbox or Onedrive or &lt;insert vendor here&gt; login page,\n            and obtains an access token using PKCE authorization flow that is persisted locally.\n            This token is used to connect to the user's cloud drive from inside the service worker.\n            The application will bootstrap itself from whatever files are already in the drive,\n            and will regularly synchronize with the current contents of the drive using its service worker logic.\n        </p>\n        <p>\n            Instead of a cloud drive, another option is the use of the <a href=\"https://wicg.github.io/file-system-access/\">File System Access API</a> to get a handle to a <em>local folder</em>.\n            The user can set up this folder as cloud-synced, or they can back it up and copy it to other devices using a method of their choice.\n            This solution allows the app to have complete privacy, as the user's data never leaves their device\n            or network. The caveat is <a href=\"https://caniuse.com/native-filesystem-api\">incomplete browser support</a>.\n            Come on Safari and Firefox, do your bit, for privacy!\n        </p>\n        <p>\n            In a single user scenario, each of their devices uploads its own copy of the data, either as a history of actions or as the latest state.\n            When a device's service worker wants to sync, it checks all of the files of the other devices to see if they have been modified.\n            If they are, it downloads updates and merges them into the local IndexedDB.\n            This is the same work as the previous architecture iteration did in its server-side syncing API, only now in reverse: instead of every device going to the server \n            and presenting its copy to merge, it is the service worker going to each device's copy and checking if it needs merging.\n        </p>\n        <p>\n            There is no longer a <em>master copy</em> of the data, only one copy per device, all on equal footing,\n            with an eventual consistency arising out of the devices merging from each other's copies.\n            This is the same philosophy as CRDTs, or of the <em>Operational Transformation</em> algorithm that underpins Google Docs.\n            No matter though, when you get deep enough into consistency models (I recommend <a href=\"https://jepsen.io/consistency\">Aphyr's writings</a>\n            or <a href=\"https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/\">Martin Kleppmann's book</a>), \n            you'll realize that there is <em>never</em> such as a thing as a reliable master copy in a distributed system, \n            even in cases where there is a central database.\n        </p>\n        <p>\n            A multi-user scenario can be realized by our user subscribing to someone else's shared cloud drive folder,\n            where the other user shares their copy of the data as read-only. When Alice shares her folder with Bob,\n            Bob shares his with Alice, and they both subscribe to each other's updates, \n            then they can work on a shared document without ever having given each other direct write access.\n        </p>\n        <p>\n            As this application has no servers outside of the lightly loaded static web host, which in 2025 is free to host even at scale,\n            the hosting cost drops to zero almost regardless of the number of users. The cloud drive costs are carried by each user individually,\n            only responsible for their own share of storage. The only hosting cost to the application's owner would be the domain name.\n            The climate footprint is minimal.\n        </p>\n        <p>\n            By eliminating the central database and its adjoining server-side logic it also eliminates the main target for hackers.\n            Because compromises can only occur one user at a time they lack a sufficient reward for hacking the application.\n            On top of that, the only servers are the static web host and the major cloud drive vendors,\n            both practically impossible to hack. This web app would be highly secure and remain secure with barely any maintenance.\n        </p>\n        <p>\n            This architecture would be a cloud vendor's worst nightmare if it ever became popular,\n            as they cannot earn a dime from it (aside from the basic cloud drive pennies).\n            Thankfully for them, it is impossible to monetize for the company that builds such a web app as well.\n            No server == no revenue opportunity. For now this is just a crazy theoretical exercise, \n            far removed from where the leading frontend architecture voices are driving us, \n            but the possibility fascinates me.\n        </p>        \n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/114863693149366857\"></blog-footer>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-01-redesigning-plain-vanilla/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Redesigning Plain Vanilla</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"Stepping out of my comfort zone.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <script type=\"module\" src=\"../../index.js\" defer></script>\n</head>\n<body>\n    <blog-header published=\"2026-03-01\">\n        <img src=\"image.webp\" alt=\"the index page of an old nuclear disaster prevention manual, designed in Swiss style\" />\n        <h2>Redesigning Plain Vanilla</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            <em>Design</em> has never been the part of building for the web that I felt comfortable with.\n            I would hide behind the shorthand \"I'm not a designer\" and just use someone else's design,\n            or throw something together that I wasn't happy with.\n            The original design of Plain Vanilla was shipped very much in that not-happy-with-it mindset.\n        </p>\n        <p>\n            So when I decided to finally take a web design course, settling on <a href=\"https://designacademy.io/\">DesignAcademy.io</a>\n            and had to pick a project to apply the course's learnings to, turning this site's design into something I liked was top of mind. \n            This article documents how and why the new design came about.\n        </p>\n        <p>\n            The course starts out by making you really think about the content that you want to apply a design to.\n            They challenge you to make your web page work as a google doc, so I did precisely that.\n            In revisiting the landing page and thinking through its text, about half of the characters were cut,\n            without losing any of the meaning.\n        </p>\n        <p>\n            <strong>Lesson 1</strong>: less is more.\n        </p>\n        <p>\n            The next challenge the course throws at you is to decide on a style and to gather inspiration for your design.\n            What I wanted the design of Plain Vanilla to communicate was a sort of timelessness,\n            like a manual from an earlier time, that at the same time feels simple and fresh.\n            In looking for inspiration I settled on <a href=\"https://en.wikipedia.org/wiki/Swiss_Style_(design)\">Swiss style</a>,\n            the 1950's minimalist style that manages to feel modern and old at the same time.\n            I absolutely adore the old manuals from the 50's, as in the image at the top of this page,\n            where minimalist design relying heavily on typography and spacing brings the content to the foreground.\n        </p>\n        <p>\n            With this style and many googled-together examples of it as inspiration in hand, I took on the next challenge:\n            make a first sketch of the design by simply copy pasting together elements of web sites and imagery\n            that inspired you into a rough first outline. The second half of the challenge:\n            take that design and layer your content over it. The result of this exercise was the initial redesign.\n            Notice how the left half is literally copy pasted together bits of screenshots.\n        </p>\n        <img src=\"sketch-1.webp\" alt=\"initial redesign sketch\" style=\"border: 1px solid gray;\" />\n        <p>\n            <strong>Lesson 2</strong>: taking ideas from everywhere is a quick way to get started.\n        </p>\n        <p>\n            The rest of the course was a series of design exercises on top of that initial draft, \n            to choose fonts, colors, imagery, to apply a grid system and figure out spacing, and to sort out the finer aspects.\n            Some elements of the initial redesign survived this process, others didn't, and what I ended up with\n            in the final Affinity Designer file is pretty close to the shipping redesign.\n        </p>\n        <img src=\"sketch-2.webp\" alt=\"final redesign sketch\" style=\"width: 400px; border: 1px solid gray;\" />\n        <p>\n            <strong>Lesson 3</strong>: design doesn't have to be intimidating if you have the right process.\n        </p>\n        <p>\n            The actual work of translating of the design to code wasn't all that complicated.\n            There was already a good baseline of semantic markup, so the redesign ended up mostly constrained\n            to central CSS changes. Most of the time was taken up by responsiveness, something absent from the design mockup.\n            Many of the final decisions on the exact behavior were made to favor code simplicity.\n            This is for example why I decided not to add animations.\n        </p>\n        <p>\n            This is also why I chose the popover API as the strategy for having a responsive hamburger menu on small screens.\n            While the popover API presently only has 87% support on caniuse.com, I felt that for the audience of this site\n            support should be sufficient, and the dramatic code simplification it allowed was undeniable.\n            The nav menu works without <em>any</em> JavaScript. It presents as a toggled menu by default,\n            and uses CSS to become permanently visible on larger screens.\n        </p>\n        <x-code-viewer src=\"./nav-menu.html\"></x-code-viewer>\n        <p>\n            This was also a good opportunity to revisit the website's content.\n            As it turns out, not a lot needed to change. Web standards don't actually change that often.\n            I did update some parts where evolving baseline support took away caveats \n            (for example, CSS nesting is now safe to use), and added some links to newly baseline \n            features like popover, dialog and mutually-exclusive details.\n        </p>\n        <p>\n            <strong>Lesson 4</strong>: when you build on top of web standards, you don't need to do a lot of maintenance.\n        </p>\n        <p>\n            In the end, I'm finally happy with the design of Plain Vanilla.\n            I still haven't gotten around to adding a dark mode, but it's on the todo list.\n            There may be some hiccups with the new design, so if you see any please let me know by making an issue on GitHub.\n            Do you like the new design, do you hate it? Please let me know.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/116155703022655713\"></blog-footer>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-01-redesigning-plain-vanilla/nav-menu.html",
    "content": "<nav id=\"menu-nav\" popover aria-label=\"main\">\n    <ol>\n        <li><a href=\"#\" aria-current=\"page\">Welcome</a></li>\n        <li><a href=\"pages/components.html\">Components</a></li>\n        <li><a href=\"pages/styling.html\">Styling</a></li>\n        <li><a href=\"pages/sites.html\">Sites</a></li>\n        <li><a href=\"pages/applications.html\">Applications</a></li>\n        <li class=\"nav-right\"><a href=\"blog/\">Blog</a></li>\n    </ol>\n</nav>\n<button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n    &mldr;\n</button>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example1/index-partial.html",
    "content": "<details>\n    <summary>A summary</summary>\n    Some details to further explain the summary.\n</details>\n"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example1/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 1</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n</head>\n<body>\n    <details>\n        <summary>A summary</summary>\n        Some details to further explain the summary.\n    </details>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example2/index-partial.html",
    "content": "<style>\n    details {\n        summary {\n            list-style: none;\n        }\n        summary::before {\n            content: \"\\1F512\";\n            margin: 0 0.3em 0 -0.1em;\n        }\n        &[open] summary::before {\n            content: \"\\1F513\";\n        }\n    }\n</style>\n<details>\n    <summary>A summary</summary>\n    Some details to further explain the summary.\n</details>\n"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example2/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 2</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n</head>\n<body>\n    <style>\n        details {\n            summary {\n                list-style: none;\n            }\n            summary::before {\n                content: \"\\1F512\";\n                margin: 0 0.3em 0 -0.1em;\n            }\n            &[open] summary::before {\n                content: \"\\1F513\";\n            }\n        }\n    </style>\n    <details>\n        <summary>A summary</summary>\n        Some details to further explain the summary.\n    </details>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example3/index-partial.html",
    "content": "<style>\n    details {\n        summary {\n            list-style: none;\n            user-select: none;\n            svg {\n                display: inline-block;\n                vertical-align: bottom;\n                color: gray;\n                rotate: 0;\n                transition: rotate 0.3s ease-out;\n            }\n        }\n        &[open] summary {\n            svg {\n                rotate: 180deg;\n            }\n        }\n    }\n</style>\n<details>\n    <summary>\n        A summary\n        <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n            <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n        </svg>\n    </summary>\n    Some details to further explain the summary.\n</details>\n"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example3/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 3</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n</head>\n<body>\n    <style>\n        details {\n            summary {\n                list-style: none;\n                user-select: none;\n                svg {\n                    display: inline-block;\n                    vertical-align: bottom;\n                    color: gray;\n                    rotate: 0;\n                    transition: rotate 0.3s ease-out;\n                }\n            }\n            &[open] summary {\n                svg {\n                    rotate: 180deg;\n                }\n            }\n        }\n    </style>\n    <details>\n        <summary>\n            A summary\n            <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n                <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n            </svg>\n        </summary>\n        Some details to further explain the summary.\n    </details>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example4/index-partial.html",
    "content": "<style>\n    details {\n        border: 1px solid gray;\n        max-width: 20em;\n\n        summary {\n            position: relative;\n            list-style: none;\n            padding: 0.2em 0.4em;\n            user-select: none;\n            svg {\n                position: absolute;\n                right: 0.2em;\n                top: 0.3em;\n                color: gray;\n                rotate: 0;\n                transition: rotate 0.3s ease-out;\n            }\n        }\n\n        &[open] {\n            summary {\n                font-weight: bold;\n                svg {\n                    rotate: 180deg;\n                }\n            }\n\n            &::details-content {\n                border-top: 1px solid gray;\n                padding: 0.2em 0.4em;        \n            }\n        }\n    }\n</style>\n<details>\n    <summary>\n        A summary\n        <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n            <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n        </svg>\n    </summary>\n    Some details to further explain the summary.\n    And this is another sentence that spends a great deal of time saying nothing.\n</details>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example4/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 4</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n</head>\n<body>\n    <style>\n        details {\n            border: 1px solid gray;\n            max-width: 20em;\n            \n            summary {\n                position: relative;\n                list-style: none;\n                padding: 0.2em 0.4em;\n                user-select: none;\n                svg {\n                    position: absolute;\n                    right: 0.2em;\n                    top: 0.3em;\n                    color: gray;\n                    rotate: 0;\n                    transition: rotate 0.3s ease-out;\n                }\n            }\n\n            &[open] {\n                summary {\n                    font-weight: bold;\n                    svg {\n                        rotate: 180deg;\n                    }\n                }\n\n                &::details-content {\n                    border-top: 1px solid gray;\n                    padding: 0.2em 0.4em;        \n                }\n            }\n        }\n    </style>\n    <details>\n        <summary>\n            A summary\n            <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n                <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n            </svg>\n        </summary>\n        Some details to further explain the summary.\n        And this is another sentence that spends a great deal of time saying nothing.\n    </details>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example5/index-partial.html",
    "content": "<style>\n    /* ... details styles repeated from previous example ... */\n\n    details + details {\n        border-top: none;\n    }\n\n    @supports (interpolate-size: allow-keywords) {\n        :root {\n            interpolate-size: allow-keywords;\n        }\n\n        details::details-content {\n            /* allow discrete transitions for the details content (animating to height auto) */\n            transition:\n                height 0.3s ease,\n                content-visibility 0.3s ease allow-discrete;\n            /* hide the details content by default */\n            height: 0;\n            overflow: clip;\n        }\n\n        /* show the details content when the details is open */\n        details[open]::details-content {\n            height: auto;\n        }\n    }\n</style>\n<details name=\"accordion\">\n    ...\n</details>\n<details name=\"accordion\">\n    ...\n</details>\n<details name=\"accordion\">\n    ...\n</details>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/example5/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Example 4</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <link rel=\"stylesheet\" href=\"../../../example-base.css\">\n</head>\n<body>\n    <style>\n        details {\n            border: 1px solid gray;\n            max-width: 20em;\n            \n            summary {\n                position: relative;\n                list-style: none;\n                padding: 0.2em 0.4em;\n                user-select: none;\n                svg {\n                    position: absolute;\n                    right: 0.2em;\n                    top: 0.3em;\n                    color: gray;\n                    rotate: 0;\n                    transition: rotate 0.3s ease-out;\n                }\n            }\n\n            &[open] {\n                summary {\n                    font-weight: bold;\n                    svg {\n                        rotate: 180deg;\n                    }\n                }\n\n                &::details-content {\n                    border-top: 1px solid gray;\n                    padding: 0.2em 0.4em;        \n                }\n            }\n        }\n\n        details + details {\n            border-top: none;\n        }\n\n        @supports (interpolate-size: allow-keywords) {\n            :root {\n                interpolate-size: allow-keywords;\n            }\n\n            details::details-content {\n                /* allow discrete transitions for the details content (animating to height auto) */\n                transition:\n                    height 0.3s ease,\n                    content-visibility 0.3s ease allow-discrete;\n                /* hide the details content by default */\n                height: 0;\n                overflow: clip;\n            }\n\n            /* show the details content when the details is open */\n            details[open]::details-content {\n                height: auto;\n            }\n        }\n    </style>\n    <details name=\"accordion\">\n        <summary>\n            Item 1\n            <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n                <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n            </svg>\n        </summary>\n        This is the first item.\n    </details>\n    <details name=\"accordion\">\n        <summary>\n            Item 2\n            <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n                <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n            </svg>\n        </summary>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.\n    </details>\n    <details name=\"accordion\">\n        <summary>\n            Item 3\n            <svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\">\n                <path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" />\n            </svg>\n        </summary>\n        Aha, and yet another item.\n    </details>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/2026-03-09-details-matters/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>&lt;details&gt; matters</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"An oddball element set to take the main stage.\">\n    <link rel=\"stylesheet\" href=\"../../index.css\">\n    <script type=\"module\" src=\"../../index.js\" defer></script>\n</head>\n<body>\n    <blog-header published=\"2026-03-09\">\n        <img src=\"image.webp\" alt=\"detail of a London street crossing showing the words look right\" />\n        <h2>&lt;details&gt; matters</h2>\n        <p class=\"byline\" aria-label=\"author\">Joeri Sebrechts</p>\n    </blog-header>\n    <main>\n        <p>\n            The richness of HTML continues to be a delightful surprise.\n        </p>\n        <p>\n            For example, take an unassuming element like &lt;details&gt;.\n            We've all seen it before. Here it is in its pure form:\n        </p>\n        <x-code-viewer src=\"example1/index-partial.html\" name=\"\"></x-code-viewer>\n        <iframe src=\"example1/index.html\" title=\"undecorated details\"></iframe>\n        \n        <p>\n            We can merrily click the summary to open and close the details to our heart's content.\n            But this is kind of plain-looking. Can we change that triangle into something else?\n        </p>\n        <iframe src=\"example2/index.html\" title=\"replacing the marker\"></iframe>\n        <p>\n            In a just world, this would work by neatly styling the <code>::marker</code> pseudo-element,\n            but like so often <a href=\"https://caniuse.com/css-marker-pseudo\">Safari is being annoying</a>. \n            Thankfully we can instead replace the marker by removing it with <code>list-style: none;</code> and adding a new summary marker\n            on the <code>::before</code> or <code>::after</code> pseudo-elements.\n        </p>\n        <x-code-viewer src=\"example2/index-partial.html\" name=\"\"></x-code-viewer>\n        <p>\n            And really, the <code>summary</code> element can contain anything at all, inviting our creativity.\n            Here's a fancier example that replaces the marker by an animated svg icon.\n        </p>\n        <iframe src=\"example3/index.html\" title=\"replacing the marker, but more fancy\"></iframe>\n        <x-code-viewer src=\"example3/index-partial.html\" name=\"\"></x-code-viewer>\n        \n        <p>\n            There's no reason to stop at decorating the marker though.\n            We can make the details element look like anything we want,\n            all it takes is the right CSS. If we wanted, we could make it look like a card.\n        </p>\n        <iframe src=\"example4/index.html\" height=\"250\" title=\"card-like appearance\"></iframe>\n        <x-code-viewer src=\"example4/index-partial.html\" name=\"\"></x-code-viewer>\n        <p>\n            One caveat with this example is the <code>::details-content</code> pseudo-element used to select\n            the expanded content area. This is baseline 2025 so still pretty new. For older browsers you can wrap the content \n            in a div and style that instead.\n        </p>\n\n        <p>\n            But wait, there's more! In baseline 2024 <code>&lt;details&gt;</code> picked up a neat trick\n            where all the elements with the same <code>name</code> attribute are mutually exclusive,\n            meaning only one can be open at the same time. All we have to do is stack them\n            to magically get an accordion.\n        </p>\n        <iframe src=\"example5/index.html\" height=\"350\" title=\"card-like appearance\"></iframe>\n        <x-code-viewer src=\"example5/index-partial.html\" name=\"\"></x-code-viewer>\n        <p>\n            There's no magic code here to make the accordion work aside from the <code>name</code> attributes. \n            HTML is doing the magic for us, which means this also happens to be fully keyboard-navigable and accessible.\n            The only tricky bit is animating the expanding and collapsing of the cards.\n            In this example that is implemented using <code>interpolate-size: allow-keywords</code>,\n            which is a <a href=\"https://css-tricks.com/almanac/properties/i/interpolate-size/\">Chromium-only trick</a> hopefully coming to other browsers near you.\n            Thankfully in those other browsers this is still perfectly functional, just not as smoothly animating.\n        </p>\n        <p>\n            By the way, the mutually exclusive &lt;details&gt; elements do not even need to share a parent element.\n            These accordion cards could be wrapped in custom elements, or <code>&lt;fieldset&gt;</code> or <code>&lt;form&gt;</code> elements,\n            and they would work just fine in all browsers, today. But you'll have to take my word for it.\n            After all, I have to leave some exercises up to the reader. &#x1F609;\n        </p>\n\n        <p>\n            Like I said, the richness of HTML continues to be a delightful surprise.\n            If you ask me then <code>&lt;details&gt;</code> has a bright future ahead of it.\n        </p>\n        <p>\n            No JavaScript was harmed in the making of this blog post.\n        </p>\n    </main>\n    <blog-footer mastodon-url=\"https://mstdn.social/@joeri_s/116201477581872111\"></blog-footer>\n</body>\n</html>"
  },
  {
    "path": "public/blog/articles/index.json",
    "content": "[\n    {\n        \"slug\": \"2026-03-09-details-matters\",\n        \"title\": \"<details> matters\",\n        \"summary\": \"An oddball element set to take the main stage.\",\n        \"published\": \"2026-03-09\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2026-03-01-redesigning-plain-vanilla\",\n        \"title\": \"Redesigning Plain Vanilla\",\n        \"summary\": \"Stepping out of my comfort zone.\",\n        \"published\": \"2026-03-01\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-07-16-local-first-architecture\",\n        \"title\": \"Local-first web application architecture\",\n        \"summary\": \"Maybe we just need to dig a little deeper (into the client).\",\n        \"published\": \"2025-07-16\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-07-13-history-architecture\",\n        \"title\": \"The history of web application architecture\",\n        \"summary\": \"The many different ways of building for the web, and their many frustrations.\",\n        \"published\": \"2025-07-13\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-06-25-routing\",\n        \"title\": \"Clean client-side routing\",\n        \"summary\": \"Finding a nice way of doing single-page app routing without a library.\",\n        \"published\": \"2025-06-25\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-06-12-view-transitions\",\n        \"title\": \"Bringing React's <ViewTransition> to vanilla JS\",\n        \"summary\": \"Bringing React's declarative view transitions API to vanilla as a custom element.\",\n        \"published\": \"2025-06-12\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-05-09-form-control\",\n        \"title\": \"Making a new form control\",\n        \"summary\": \"Building a form control as a custom element.\",\n        \"published\": \"2025-05-09\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-04-21-attribute-property-duality\",\n        \"title\": \"The attribute/property duality\",\n        \"summary\": \"How to work with attributes and properties in custom elements.\",\n        \"published\": \"2025-04-21\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2025-01-01-new-years-resolve\",\n        \"title\": \"New year's resolve\",\n        \"summary\": \"import.meta.resolve and other ways to avoid bundling\",\n        \"published\": \"2025-01-01\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-12-16-caching-vanilla-sites\",\n        \"title\": \"Caching vanilla sites\",\n        \"summary\": \"Strategies for cache invalidation on vanilla web sites.\",\n        \"published\": \"2024-12-16\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-10-20-editing-plain-vanilla\",\n        \"title\": \"Editing Plain Vanilla\",\n        \"summary\": \"How to set up VS Code for a vanilla web project.\",\n        \"published\": \"2024-10-20\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-10-07-needs-more-context\",\n        \"title\": \"Needs more context\",\n        \"summary\": \"A better way to do context for web components.\",\n        \"published\": \"2024-10-07\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-09-30-lived-experience\",\n        \"title\": \"Lived experience\",\n        \"summary\": \"Thoughts on the past and future of frameworks, web components and web development.\",\n        \"published\": \"2024-09-30\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-09-28-unreasonable-effectiveness-of-vanilla-js\",\n        \"title\": \"The unreasonable effectiveness of vanilla JS\",\n        \"summary\": \"A case study in porting intricate React code to vanilla.\",\n        \"published\": \"2024-09-28\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-09-16-life-and-times-of-a-custom-element\",\n        \"title\": \"The life and times of a web component\",\n        \"summary\": \"The entire lifecycle of a web component, from original creation to when a shadow crosses.\",\n        \"published\": \"2024-09-16\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-09-09-sweet-suspense\",\n        \"title\": \"Sweet Suspense\",\n        \"summary\": \"React-style lazy loading of web components.\",\n        \"published\": \"2024-09-09\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-09-06-how-fast-are-web-components\",\n        \"title\": \"How fast are web components?\",\n        \"summary\": \"Benchmarking the relative performance of different web component techniques.\",\n        \"published\": \"2024-09-06\",\n        \"updated\": \"2024-09-15\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-09-03-unix-philosophy\",\n        \"title\": \"A unix philosophy for web development\",\n        \"summary\": \"Maybe all web components need to be a light-weight framework is the right set of helper functions.\",\n        \"published\": \"2024-09-03\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-08-30-poor-mans-signals\",\n        \"title\": \"Poor man's signals\",\n        \"summary\": \"Signals are all the rage over in frameworkland, so let's bring them to vanilla JS.\",\n        \"published\": \"2024-08-30\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-08-25-vanilla-entity-encoding\",\n        \"title\": \"Vanilla entity encoding\",\n        \"summary\": \"The first version of this site didn't use entity encoding in the examples. Now it does.\",\n        \"published\": \"2024-08-25\",\n        \"author\": \"Joeri Sebrechts\"\n    },\n    {\n        \"slug\": \"2024-08-17-lets-build-a-blog\",\n        \"title\": \"Let's build a blog, vanilla-style!\",\n        \"summary\": \"Explaining how this vanilla web development blog was built, using nothing but vanilla web techniques.\",\n        \"published\": \"2024-08-17\",\n        \"updated\": \"2024-08-26\",\n        \"author\": \"Joeri Sebrechts\"\n    }\n]"
  },
  {
    "path": "public/blog/components/blog-archive.js",
    "content": "import { html } from '../../lib/html.js';\n\nclass BlogArchive extends HTMLElement {\n    connectedCallback() {\n        this.textContent = 'Loading...';\n        fetch(import.meta.resolve('../articles/index.json'))\n            .then(response => response.json())\n            .then(articles => {\n                // sort articles by published descending\n                articles.sort((a, b) => {\n                    return -a.published.localeCompare(b.published);\n                });\n                this.innerHTML = '<ul class=\"cards\">' +\n                    articles.map(item => html`\n                        <li class=\"card\">\n                            <h3><a href=\"${import.meta.resolve(`../articles/${item.slug}/`)}\">${item.title}</a></h3>\n                            <p>${item.summary}</p>\n                            <small>\n                                <time datetime=\"${item.published}\">\n                                    ${new Date(item.published).toLocaleDateString('en-US', { dateStyle: 'long' })}\n                                </time>\n                            </small>\n                        </li>\n                    `).join('\\n') +\n                '</ul>';\n            })\n            .catch(e => { \n                this.textContent = e.message;\n            });\n    }\n}\n\nexport const registerBlogArchive = \n    () => customElements.define('blog-archive', BlogArchive);\n"
  },
  {
    "path": "public/blog/components/blog-footer.js",
    "content": "import { html } from '../../lib/html.js';\n\nclass BlogFooter extends HTMLElement {\n    connectedCallback() {\n        const mastodonUrl = this.getAttribute('mastodon-url');\n        this.innerHTML = html`\n            <footer>                \n                ${mastodonUrl ? \n                    html`<p style=\"text-align: center\"><a href=\"${mastodonUrl}\">Discuss on Mastodon</a></p>` : ''}\n                <div class=\"contact\">\n                    <a href=\"https://sebrechts.net/\">Contact</a>\n                    <a href=\"https://github.com/jsebrech/plainvanilla\">GitHub</a>\n                </div>\n                <p class=\"top-link\">\n                    <a href=\"#top\">Back to top</a>\n                </p>\n                <x-analytics></x-analytics>\n            </footer>\n        `;\n    }\n}\n\nexport const registerBlogFooter = () => customElements.define('blog-footer', BlogFooter);\n"
  },
  {
    "path": "public/blog/components/blog-header.js",
    "content": "import { html } from '../../lib/html.js';\n\nclass BlogHeader extends HTMLElement {\n    connectedCallback() {\n        this.role = 'banner';\n        const title = this.getAttribute('title') || 'Plain Vanilla Blog';\n        const published = this.getAttribute('published');\n        const updated = this.getAttribute('updated');\n        const template = document.createElement('template');\n        template.innerHTML = html`\n            <h1>${title}</h1>\n            <p>A blog about vanilla web development &mdash; no frameworks, just standards.</p>\n            <nav aria-label=\"breadcrumb\" id=\"menu-nav\" popover>\n                <ol>\n                    <li><a href=\"${import.meta.resolve('../../index.html')}\">Plain Vanilla</a></li>\n                    <li><a href=\"${import.meta.resolve('../index.html')}\">Blog</a></li>\n                    <li><a href=\"#\" aria-current=\"page\">\n                        <time datetime=\"${published}\">\n                            ${new Date(published).toLocaleDateString('en-US', { dateStyle: 'long' })}\n                        </time>\n                    </a></li>\n                </ol>\n                ${updated ? html`\n                    <small>\n                        Last updated:\n                        <time datetime=\"${updated}\">\n                            ${new Date(updated).toLocaleDateString('en-US', { dateStyle: 'long' })}\n                        </time>\n                    </small>\n                ` : ''}\n            </nav>\n            <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n                &mldr;\n            </button>\n        `;\n        this.insertBefore(template.content, this.firstChild);\n    }\n}\n\nexport const registerBlogHeader = () => customElements.define('blog-header', BlogHeader);\n"
  },
  {
    "path": "public/blog/components/blog-latest-posts.js",
    "content": "import { html } from '../../lib/html.js';\n\nconst pathify = (url) => url && new URL(url).pathname.replace('/blog/', './');\n\nclass LatestPosts extends HTMLElement {\n    connectedCallback() {\n        this.textContent = \"Loading...\";\n        // show the most recent items from the RSS feed\n        fetch(import.meta.resolve('../feed.xml'))\n            .then(response => response.text())\n            .then(text => new DOMParser().parseFromString(text, \"text/xml\"))\n            .then(data => {\n                const parserError = data.querySelector('parsererror div');\n                if (parserError) {\n                    throw new Error(parserError.textContent);\n                }\n                // only the 6 most recent entries\n                const feedItems = \n                    [...data.querySelectorAll('entry')].slice(0, 6)\n                    .map(item => ({\n                        title: item.querySelector('title')?.textContent,\n                        link: pathify(item.querySelector('id')?.textContent),\n                        published: item.querySelector('published')?.textContent,\n                        updated: item.querySelector('updated')?.textContent,\n                        summary: item.querySelector('summary')?.textContent,\n                        image: pathify(item.querySelector('content')?.getAttribute('url'))\n                    }))\n                    // sanity check\n                    .filter(item => item.link && item.title);\n                if (feedItems.length) {\n                    this.innerHTML = '<ul class=\"cards\">' +\n                        feedItems.map(item => html`\n                            <li class=\"card\">\n                                ${item.image ? html`<img src=\"${item.image}\" aria-hidden=\"true\" loading=\"lazy\" />` : ''}\n                                <h3><a href=\"${item.link}\">${item.title}</a></h3>\n                                <p>${item.summary}</p>\n                                <small>\n                                    <time datetime=\"${item.published}\">\n                                        ${new Date(item.published).toLocaleDateString('en-US', { dateStyle: 'long' })}\n                                    </time>\n                                </small>\n                            </li>\n                        `).join('\\n') +\n                        '</ul>';\n                } else {\n                    this.innerHTML = 'Something went wrong...';\n                }\n            })\n            .catch(e => this.textContent = e.message);\n    }\n}\n\nexport const registerBlogLatestPosts = () => customElements.define('blog-latest-posts', LatestPosts);\n"
  },
  {
    "path": "public/blog/example-base.css",
    "content": "/* base CSS used for examples in blog articles */\n\n@import \"../styles/reset.css\";\n@import \"../styles/variables.css\";\n\nhtml {\n    margin:    0 auto;\n    max-width: 800px;\n    background-color: var(--background-color);\n    color: var(--text-color);\n}\n\nbody {\n    font-family: var(--font-system);\n    font-weight: normal;\n    margin: 1.5em;\n}\n\na, a:hover {\n    color: var(--link-color);\n}\n"
  },
  {
    "path": "public/blog/feed.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\">\n    <title>Plain Vanilla Blog</title>\n    <id>https://plainvanillaweb.com/blog/</id>\n    <icon>https://plainvanillaweb.com/favicon.ico</icon>\n    <logo>https://plainvanillaweb.com/android-chrome-512x512.png</logo>\n    <link rel=\"alternate\" href=\"https://plainvanillaweb.com/blog/\"/>\n    <link rel=\"self\" href=\"https://plainvanillaweb.com/blog/feed.xml\"/>\n    <updated>2026-03-09T12:00:00.000Z</updated>\n    <author>\n        <name>Joeri Sebrechts</name>\n    </author>\n    <entry>\n        <title><![CDATA[<details> matters]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/</id>\n        <published>2026-03-09T12:00:00.000Z</published>\n        <updated>2026-03-09T12:00:00.000Z</updated>\n        <summary><![CDATA[An oddball element set to take the main stage.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            The richness of HTML continues to be a delightful surprise.\n        </p>\n        <p>\n            For example, take an unassuming element like &lt;details&gt;.\n            We've all seen it before. Here it is in its pure form:\n        </p>\n        <div><pre><code>&lt;details&gt;\n    &lt;summary&gt;A summary&lt;/summary&gt;\n    Some details to further explain the summary.\n&lt;/details&gt;\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/example1/index.html\">undecorated details</a></p>\n        \n        <p>\n            We can merrily click the summary to open and close the details to our heart's content.\n            But this is kind of plain-looking. Can we change that triangle into something else?\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/example2/index.html\">replacing the marker</a></p>\n        <p>\n            In a just world, this would work by neatly styling the <code>::marker</code> pseudo-element,\n            but like so often <a href=\"https://caniuse.com/css-marker-pseudo\">Safari is being annoying</a>. \n            Thankfully we can instead replace the marker by removing it with <code>list-style: none;</code> and adding a new summary marker\n            on the <code>::before</code> or <code>::after</code> pseudo-elements.\n        </p>\n        <div><pre><code>&lt;style&gt;\n    details {\n        summary {\n            list-style: none;\n        }\n        summary::before {\n            content: \"\\1F512\";\n            margin: 0 0.3em 0 -0.1em;\n        }\n        &amp;[open] summary::before {\n            content: \"\\1F513\";\n        }\n    }\n&lt;/style&gt;\n&lt;details&gt;\n    &lt;summary&gt;A summary&lt;/summary&gt;\n    Some details to further explain the summary.\n&lt;/details&gt;\n</code></pre></div>\n        <p>\n            And really, the <code>summary</code> element can contain anything at all, inviting our creativity.\n            Here's a fancier example that replaces the marker by an animated svg icon.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/example3/index.html\">replacing the marker, but more fancy</a></p>\n        <div><pre><code>&lt;style&gt;\n    details {\n        summary {\n            list-style: none;\n            user-select: none;\n            svg {\n                display: inline-block;\n                vertical-align: bottom;\n                color: gray;\n                rotate: 0;\n                transition: rotate 0.3s ease-out;\n            }\n        }\n        &amp;[open] summary {\n            svg {\n                rotate: 180deg;\n            }\n        }\n    }\n&lt;/style&gt;\n&lt;details&gt;\n    &lt;summary&gt;\n        A summary\n        &lt;svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\"&gt;\n            &lt;path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" /&gt;\n        &lt;/svg&gt;\n    &lt;/summary&gt;\n    Some details to further explain the summary.\n&lt;/details&gt;\n</code></pre></div>\n        \n        <p>\n            There's no reason to stop at decorating the marker though.\n            We can make the details element look like anything we want,\n            all it takes is the right CSS. If we wanted, we could make it look like a card.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/example4/index.html\">card-like appearance</a></p>\n        <div><pre><code>&lt;style&gt;\n    details {\n        border: 1px solid gray;\n        max-width: 20em;\n\n        summary {\n            position: relative;\n            list-style: none;\n            padding: 0.2em 0.4em;\n            user-select: none;\n            svg {\n                position: absolute;\n                right: 0.2em;\n                top: 0.3em;\n                color: gray;\n                rotate: 0;\n                transition: rotate 0.3s ease-out;\n            }\n        }\n\n        &amp;[open] {\n            summary {\n                font-weight: bold;\n                svg {\n                    rotate: 180deg;\n                }\n            }\n\n            &amp;::details-content {\n                border-top: 1px solid gray;\n                padding: 0.2em 0.4em;        \n            }\n        }\n    }\n&lt;/style&gt;\n&lt;details&gt;\n    &lt;summary&gt;\n        A summary\n        &lt;svg focusable=\"false\" width=\"24\" height=\"24\" aria-hidden=\"true\"&gt;\n            &lt;path d=\"M6.34317 7.75732L4.92896 9.17154L12 16.2426L19.0711 9.17157L17.6569 7.75735L12 13.4142L6.34317 7.75732Z\" fill=\"currentColor\" /&gt;\n        &lt;/svg&gt;\n    &lt;/summary&gt;\n    Some details to further explain the summary.\n    And this is another sentence that spends a great deal of time saying nothing.\n&lt;/details&gt;</code></pre></div>\n        <p>\n            One caveat with this example is the <code>::details-content</code> pseudo-element used to select\n            the expanded content area. This is baseline 2025 so still pretty new. For older browsers you can wrap the content \n            in a div and style that instead.\n        </p>\n\n        <p>\n            But wait, there's more! In baseline 2024 <code>&lt;details&gt;</code> picked up a neat trick\n            where all the elements with the same <code>name</code> attribute are mutually exclusive,\n            meaning only one can be open at the same time. All we have to do is stack them\n            to magically get an accordion.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/example5/index.html\">card-like appearance</a></p>\n        <div><pre><code>&lt;style&gt;\n    /* ... details styles repeated from previous example ... */\n\n    details + details {\n        border-top: none;\n    }\n\n    @supports (interpolate-size: allow-keywords) {\n        :root {\n            interpolate-size: allow-keywords;\n        }\n\n        details::details-content {\n            /* allow discrete transitions for the details content (animating to height auto) */\n            transition:\n                height 0.3s ease,\n                content-visibility 0.3s ease allow-discrete;\n            /* hide the details content by default */\n            height: 0;\n            overflow: clip;\n        }\n\n        /* show the details content when the details is open */\n        details[open]::details-content {\n            height: auto;\n        }\n    }\n&lt;/style&gt;\n&lt;details name=\"accordion\"&gt;\n    ...\n&lt;/details&gt;\n&lt;details name=\"accordion\"&gt;\n    ...\n&lt;/details&gt;\n&lt;details name=\"accordion\"&gt;\n    ...\n&lt;/details&gt;</code></pre></div>\n        <p>\n            There's no magic code here to make the accordion work aside from the <code>name</code> attributes. \n            HTML is doing the magic for us, which means this also happens to be fully keyboard-navigable and accessible.\n            The only tricky bit is animating the expanding and collapsing of the cards.\n            In this example that is implemented using <code>interpolate-size: allow-keywords</code>,\n            which is a <a href=\"https://css-tricks.com/almanac/properties/i/interpolate-size/\">Chromium-only trick</a> hopefully coming to other browsers near you.\n            Thankfully in those other browsers this is still perfectly functional, just not as smoothly animating.\n        </p>\n        <p>\n            By the way, the mutually exclusive &lt;details&gt; elements do not even need to share a parent element.\n            These accordion cards could be wrapped in custom elements, or <code>&lt;fieldset&gt;</code> or <code>&lt;form&gt;</code> elements,\n            and they would work just fine in all browsers, today. But you'll have to take my word for it.\n            After all, I have to leave some exercises up to the reader. 😉\n        </p>\n\n        <p>\n            Like I said, the richness of HTML continues to be a delightful surprise.\n            If you ask me then <code>&lt;details&gt;</code> has a bright future ahead of it.\n        </p>\n        <p>\n            No JavaScript was harmed in the making of this blog post.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Redesigning Plain Vanilla]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2026-03-01-redesigning-plain-vanilla/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2026-03-01-redesigning-plain-vanilla/</id>\n        <published>2026-03-01T12:00:00.000Z</published>\n        <updated>2026-03-01T12:00:00.000Z</updated>\n        <summary><![CDATA[Stepping out of my comfort zone.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2026-03-01-redesigning-plain-vanilla/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            <em>Design</em> has never been the part of building for the web that I felt comfortable with.\n            I would hide behind the shorthand \"I'm not a designer\" and just use someone else's design,\n            or throw something together that I wasn't happy with.\n            The original design of Plain Vanilla was shipped very much in that not-happy-with-it mindset.\n        </p>\n        <p>\n            So when I decided to finally take a web design course, settling on <a href=\"https://designacademy.io/\">DesignAcademy.io</a>\n            and had to pick a project to apply the course's learnings to, turning this site's design into something I liked was top of mind. \n            This article documents how and why the new design came about.\n        </p>\n        <p>\n            The course starts out by making you really think about the content that you want to apply a design to.\n            They challenge you to make your web page work as a google doc, so I did precisely that.\n            In revisiting the landing page and thinking through its text, about half of the characters were cut,\n            without losing any of the meaning.\n        </p>\n        <p>\n            <strong>Lesson 1</strong>: less is more.\n        </p>\n        <p>\n            The next challenge the course throws at you is to decide on a style and to gather inspiration for your design.\n            What I wanted the design of Plain Vanilla to communicate was a sort of timelessness,\n            like a manual from an earlier time, that at the same time feels simple and fresh.\n            In looking for inspiration I settled on <a href=\"https://en.wikipedia.org/wiki/Swiss_Style_(design)\">Swiss style</a>,\n            the 1950's minimalist style that manages to feel modern and old at the same time.\n            I absolutely adore the old manuals from the 50's, as in the image at the top of this page,\n            where minimalist design relying heavily on typography and spacing brings the content to the foreground.\n        </p>\n        <p>\n            With this style and many googled-together examples of it as inspiration in hand, I took on the next challenge:\n            make a first sketch of the design by simply copy pasting together elements of web sites and imagery\n            that inspired you into a rough first outline. The second half of the challenge:\n            take that design and layer your content over it. The result of this exercise was the initial redesign.\n            Notice how the left half is literally copy pasted together bits of screenshots.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2026-03-01-redesigning-plain-vanilla/sketch-1.webp\" alt=\"initial redesign sketch\" style=\"border: 1px solid gray;\">\n        <p>\n            <strong>Lesson 2</strong>: taking ideas from everywhere is a quick way to get started.\n        </p>\n        <p>\n            The rest of the course was a series of design exercises on top of that initial draft, \n            to choose fonts, colors, imagery, to apply a grid system and figure out spacing, and to sort out the finer aspects.\n            Some elements of the initial redesign survived this process, others didn't, and what I ended up with\n            in the final Affinity Designer file is pretty close to the shipping redesign.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2026-03-01-redesigning-plain-vanilla/sketch-2.webp\" alt=\"final redesign sketch\" style=\"width: 400px; border: 1px solid gray;\">\n        <p>\n            <strong>Lesson 3</strong>: design doesn't have to be intimidating if you have the right process.\n        </p>\n        <p>\n            The actual work of translating of the design to code wasn't all that complicated.\n            There was already a good baseline of semantic markup, so the redesign ended up mostly constrained\n            to central CSS changes. Most of the time was taken up by responsiveness, something absent from the design mockup.\n            Many of the final decisions on the exact behavior were made to favor code simplicity.\n            This is for example why I decided not to add animations.\n        </p>\n        <p>\n            This is also why I chose the popover API as the strategy for having a responsive hamburger menu on small screens.\n            While the popover API presently only has 87% support on caniuse.com, I felt that for the audience of this site\n            support should be sufficient, and the dramatic code simplification it allowed was undeniable.\n            The nav menu works without <em>any</em> JavaScript. It presents as a toggled menu by default,\n            and uses CSS to become permanently visible on larger screens.\n        </p>\n        <div><pre><code>&lt;nav id=\"menu-nav\" popover aria-label=\"main\"&gt;\n    &lt;ol&gt;\n        &lt;li&gt;&lt;a href=\"#\" aria-current=\"page\"&gt;Welcome&lt;/a&gt;&lt;/li&gt;\n        &lt;li&gt;&lt;a href=\"pages/components.html\"&gt;Components&lt;/a&gt;&lt;/li&gt;\n        &lt;li&gt;&lt;a href=\"pages/styling.html\"&gt;Styling&lt;/a&gt;&lt;/li&gt;\n        &lt;li&gt;&lt;a href=\"pages/sites.html\"&gt;Sites&lt;/a&gt;&lt;/li&gt;\n        &lt;li&gt;&lt;a href=\"pages/applications.html\"&gt;Applications&lt;/a&gt;&lt;/li&gt;\n        &lt;li class=\"nav-right\"&gt;&lt;a href=\"blog/\"&gt;Blog&lt;/a&gt;&lt;/li&gt;\n    &lt;/ol&gt;\n&lt;/nav&gt;\n&lt;button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\"&gt;\n    &amp;mldr;\n&lt;/button&gt;</code></pre></div>\n        <p>\n            This was also a good opportunity to revisit the website's content.\n            As it turns out, not a lot needed to change. Web standards don't actually change that often.\n            I did update some parts where evolving baseline support took away caveats \n            (for example, CSS nesting is now safe to use), and added some links to newly baseline \n            features like popover, dialog and mutually-exclusive details.\n        </p>\n        <p>\n            <strong>Lesson 4</strong>: when you build on top of web standards, you don't need to do a lot of maintenance.\n        </p>\n        <p>\n            In the end, I'm finally happy with the design of Plain Vanilla.\n            I still haven't gotten around to adding a dark mode, but it's on the todo list.\n            There may be some hiccups with the new design, so if you see any please let me know by making an issue on GitHub.\n            Do you like the new design, do you hate it? Please let me know.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Local-first web application architecture]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/</id>\n        <published>2025-07-16T12:00:00.000Z</published>\n        <updated>2025-07-16T12:00:00.000Z</updated>\n        <summary><![CDATA[Maybe we just need to dig a little deeper (into the client).]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            Previously in <a href=\"../2025-07-13-history-architecture/\">the history of web application architecture</a> \n            I covered the different ways that people have tried to build web applications, and how all of them came with \n            their own unique set of drawbacks.\n            Also mentioned was how there is one drawback that they all share: \n            there is a whole internet between a user and their data,\n            and this makes it hard to deliver a top notch user experience.\n        </p>\n\n        <h3>Tail latency matters</h3>\n        <p>\n            On the surface, it doesn't seem like this should be the case. Networks are fast, right?\n            But the truth is, they're only fast for some of the people some of the time.\n        </p>\n        <p>\n            Look at the page load numbers (LCP) of this website for the last week (gathered anonymously):\n        </p>\n        <ul>\n            <li>P50: 650 ms</li>\n            <li>P75: 1200 ms</li>\n            <li>P90: 2148 ms</li>\n            <li>P99: 10,636 ms</li>\n        </ul>\n        <p>\n            While half of the visits see page load times well below a second,\n            many see times that are much, much higher. Part of this is due to geography.\n            Going through <a href=\"https://learn.microsoft.com/en-us/azure/networking/azure-network-latency?tabs=Europe%2CWesternEurope\">Azure's P50 roundtrip latency times</a> we can see that\n            some remote connections, like France to Australia, are in the 250 ms range, data center to data center.\n            Azure doesn't disclose P99 latency, but one may assume it is a multiple of the P50 latency.\n        </p>\n        <p>\n            But our user isn't sitting in a data center, they're probably on a mobile phone,\n            connecting through a slow network. Looking at <a href=\"https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Understanding_latency\">mozilla's minimum latency numbers</a> \n            we can see that it's not unusual to see another 100 ms of roundtrip latency added by the mobile network,\n            and in reality owing to packet loss and TCP retries it can be a lot more. My own experience taking the train into the office,\n            and trying to get some work done, is that the web can slow to a crawl as I pass through dead zones.\n            This is in a densely populated area in a rich country on the most expensive cell service provider. \n            Most people do not have these same luxuries.\n        </p>\n        <p>\n            So it's not unusual to see latencies climb far above the threshold of 100 ms,\n            commonly regarded as the threshold for an <em>immediate</em> response.\n            For an unlucky minority of users latencies can even climb above half a second.\n            This matters because if we have to hit the server to do something with the user's data \n            on every click, we will have noticeable and frustrating delay in the interaction.\n            To get a feel of this delay, here's a simulator where you can try out roundtrip latencies\n            from 50 ms to one second:\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/example1.html\">roundtrip latency simulator</a></p>\n        <p>\n            Can you tell how much nicer 100 ms and below feel?\n            How the buttons actually <em>feel</em> lighter to press?\n            By contrast, 500 ms and above of roundtrip latency are just a slog, painful to use.\n            The buttons are heavy and cumbersome. This is human psychology at work,\n            and these lessons were learned in the desktop era but forgotten and never quite relearned for the web.\n            If we put over 100 ms of latency in between a user's click and the resulting effect\n            they will feel some degree of frustration, and we know that the internet cannot deliver below 100 ms of roundtrip latency\n            except in the luckiest of cases.\n        </p>\n        \n        <h3>Solutions</h3>\n\n        <p>\n            We can use some kind of closer-to-the-user cache,\n            in the form of a CDN or a browser cache or a service worker. This allows the content that needs to be loaded \n            based on the user's click to be fetched from something that has a better shot at being below that magic 100 ms\n            of latency. But this only works if what we need to load can be cached,\n            and if we can afford to cache it. For a web application that works with user data, this is typically not the case.\n        </p>\n        <p>\n            We can host the application in a georedundant way, have application servers\n            across the world and use a georedundant database like Google Spanner or Azure Cosmos DB. \n            This quickly gets complicated and expensive, and can only be achieved \n            through a great amount of vendor lock-in. Crucially, it probably does not get us past the 100 ms barrier anyway.\n        </p>\n        <p>\n            We can render client-side, using JavaScript to create and update the HTML page,\n            so that an update on the screen can happen immediately after the user's click.\n            But this only works if what the user is doing is not updating a piece of server-side data.\n            Otherwise we have to show some kind of loading or saving indicator until the server responds, \n            and then we're back to roundtrip latency.\n        </p>\n        <p>\n            Bottom line, and once again: the basic problem is that the internet is in between the user and their data.\n            So what if we moved the data to the user?\n        </p>\n\n        <h3>Local-first</h3>\n\n        <p>\n            This concept has been around for a while and it is known as a <a href=\"https://www.inkandswitch.com/essay/local-first/\">local-first application</a>.\n            To apply it to the web, let's start from the basic design of a client-side rendered web application\n            as covered in the previous article:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/architectures/modern-SPA.webp\" alt=\"architecture diagram of a client-side rendered web application\" width=\"1830\" height=\"1444\" loading=\"lazy\">\n        <p>\n            This design does not need the server for rendering, so it has the theoretical potential to hit 100 ms.\n            But because the user's interactions have to fetch data from the remote database and update it as well – \n            a database sitting multiple network hops away –\n            in practice we rarely actually hit that low latency.\n            We can <em>move the data to the user</em> by doing something like this:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/architectures/local-first-partial.webp\" alt=\"architecture diagram of a local-first application with server-side sync\" width=\"1806\" height=\"1502\" loading=\"lazy\">\n        <p>\n            The user's data gets duplicated into a local IndexedDB. More than duplicated actually as\n            this becomes the only copy of the data that the user will interact with directly.\n            The <em>backend-for-frontend</em> and API that used to gatekeep access to this data similarly get moved into the client,\n            as part of a service worker. This worker code can be very similar to what the server-side version would be, \n            it can even reuse express (although it probably shouldn't).\n            Because the service worker's API for all intents and purposes looks like a server-side API to the frontend codebase,\n            that frontend can be built in all the usual ways, \n            except now with the guarantee that every server roundtrip completes in milliseconds.\n        </p>\n        <p>\n            To avoid slow page loads each time the web application is opened\n            it also needs to be cached locally as part of the service worker.\n            By packaging this as a <em>progressive web app</em> installs become possible onto the user's home screen,\n            giving an experience not that unlike installing a native mobile app.\n            The application server's job is now reduced to only providing that initial application install,\n            and it can become a simple (and free) static web host.\n        </p>\n        \n        <h3>Here comes trouble</h3>\n        <p>\n            Both the application and the data are now running locally,\n            meaning the user doesn't need the network <em>at all</em> to get things done.\n            This isn't just local-first, it is offline-first.\n            But like all things in software architecture, we are trading one set of problems for another.\n        </p>\n        <p>\n            There still needs to be a way to get data onto other devices, or to other users,\n            or simply backed up into the cloud. That means the service worker also gets the job of\n            (asynchronously) uploading changes to a server API which will store it in a database,\n            as well as pulling server-side changes back down. The server-side version acts as the master copy,\n            and the server-side API gets the thankless job of merging client-side changes with it.\n        </p>\n        <p>\n            Not so fast though. Our user might be editing offline for a considerably long time,\n            and the data on the server may have been changed in the meanwhile from another device or by another user.\n            The job of merging those changes can be ... <em>complicated</em>.\n            A good strategy is needed for merging. A possible path is to use CRDT algorithms from a library like \n            <a href=\"https://github.com/automerge/automerge\">automerge</a>, as suggested by the local-first article linked above.\n            However, for many cases a simpler bespoke algorithm that is aware of the specific data types being merged probably works well enough,\n            as I discovered when making an offline-capable work orders web application that used this strategy.\n        </p>\n        <p>\n            As the local-first application is now directly talking to this API,\n            it needs a way to authenticate. This can be a reason to still have a minimal \n            <em>backend-for-frontend</em> on the server. An alternative is to use a separate \n            OpenID Connect identity provider with a PKCE authorization flow to obtain an access token.\n            <a href=\"https://blog.postman.com/what-is-pkce/\">PKCE</a> is an authorization flow developed for use by mobile apps but also usable by web apps \n            that enables secretless API authentication.\n        </p>\n        <p>\n            Another major caveat is that the entire codebase needs to be on the client,\n            which necessitates keeping it under a tight performance and size budget.\n            Careful curation of dependencies is key, and a javascript footprint that runs in the megabytes is verboten.\n            Vanilla web development can be a solution here, with its emphasis on using the platform to its limits\n            without bringing in dependencies. A lightweight framework like Lit or Preact will do as well.\n        </p>\n        <p>\n            This isn't just a theoretical exercise. The team at <a href=\"https://superhuman.com/\">Superhuman</a> built their better gmail than gmail \n            more or less as described here, using React as the framework, and the thing that sets their web app apart is its blistering speed.\n            You can go read how they did it on their blog (<a href=\"https://blog.superhuman.com/architecting-a-web-app-to-just-work-offline-part-1/\">part 1</a>, \n            <a href=\"https://blog.superhuman.com/building-reliable-apps-on-unreliable-networks/\">part 2</a>) or listen to the retelling on the \n            <a href=\"https://syntax.fm/show/918/extreme-native-perf-on-the-web-with-superhuman\">Syntax podcast</a>.\n        </p>\n\n        <h3>Loco-first</h3>\n\n        <p>\n            But we can push it even further, in theory at least. In the previous iteration of the architecture we still have\n            the application-specific database and syncing logic on the server,\n            but what if we instead did away with every last piece of server-side application logic?\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/architectures/local-first-full.webp\" alt=\"architecture diagram of a local-first application without server-side logic\" width=\"1768\" height=\"1372\" loading=\"lazy\">\n        <p>\n            The syncing engine now gets moved in the client, and what it uploads to the server are just files.\n            That means all we need is a generic cloud drive, like Dropbox or Onedrive.\n            These cloud drive services often support cross-origin API access with OpenID Connect authentication using PKCE.\n            That means the service worker in the client doesn't need any application servers to upload its data\n            to the cloud storage.\n        </p>\n        <p>\n            The onboarding experience becomes a choice screen where the user picks their cloud drive option.\n            The application will redirect the user to the Dropbox or Onedrive or &lt;insert vendor here&gt; login page,\n            and obtains an access token using PKCE authorization flow that is persisted locally.\n            This token is used to connect to the user's cloud drive from inside the service worker.\n            The application will bootstrap itself from whatever files are already in the drive,\n            and will regularly synchronize with the current contents of the drive using its service worker logic.\n        </p>\n        <p>\n            Instead of a cloud drive, another option is the use of the <a href=\"https://wicg.github.io/file-system-access/\">File System Access API</a> to get a handle to a <em>local folder</em>.\n            The user can set up this folder as cloud-synced, or they can back it up and copy it to other devices using a method of their choice.\n            This solution allows the app to have complete privacy, as the user's data never leaves their device\n            or network. The caveat is <a href=\"https://caniuse.com/native-filesystem-api\">incomplete browser support</a>.\n            Come on Safari and Firefox, do your bit, for privacy!\n        </p>\n        <p>\n            In a single user scenario, each of their devices uploads its own copy of the data, either as a history of actions or as the latest state.\n            When a device's service worker wants to sync, it checks all of the files of the other devices to see if they have been modified.\n            If they are, it downloads updates and merges them into the local IndexedDB.\n            This is the same work as the previous architecture iteration did in its server-side syncing API, only now in reverse: instead of every device going to the server \n            and presenting its copy to merge, it is the service worker going to each device's copy and checking if it needs merging.\n        </p>\n        <p>\n            There is no longer a <em>master copy</em> of the data, only one copy per device, all on equal footing,\n            with an eventual consistency arising out of the devices merging from each other's copies.\n            This is the same philosophy as CRDTs, or of the <em>Operational Transformation</em> algorithm that underpins Google Docs.\n            No matter though, when you get deep enough into consistency models (I recommend <a href=\"https://jepsen.io/consistency\">Aphyr's writings</a>\n            or <a href=\"https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/\">Martin Kleppmann's book</a>), \n            you'll realize that there is <em>never</em> such as a thing as a reliable master copy in a distributed system, \n            even in cases where there is a central database.\n        </p>\n        <p>\n            A multi-user scenario can be realized by our user subscribing to someone else's shared cloud drive folder,\n            where the other user shares their copy of the data as read-only. When Alice shares her folder with Bob,\n            Bob shares his with Alice, and they both subscribe to each other's updates, \n            then they can work on a shared document without ever having given each other direct write access.\n        </p>\n        <p>\n            As this application has no servers outside of the lightly loaded static web host, which in 2025 is free to host even at scale,\n            the hosting cost drops to zero almost regardless of the number of users. The cloud drive costs are carried by each user individually,\n            only responsible for their own share of storage. The only hosting cost to the application's owner would be the domain name.\n            The climate footprint is minimal.\n        </p>\n        <p>\n            By eliminating the central database and its adjoining server-side logic it also eliminates the main target for hackers.\n            Because compromises can only occur one user at a time they lack a sufficient reward for hacking the application.\n            On top of that, the only servers are the static web host and the major cloud drive vendors,\n            both practically impossible to hack. This web app would be highly secure and remain secure with barely any maintenance.\n        </p>\n        <p>\n            This architecture would be a cloud vendor's worst nightmare if it ever became popular,\n            as they cannot earn a dime from it (aside from the basic cloud drive pennies).\n            Thankfully for them, it is impossible to monetize for the company that builds such a web app as well.\n            No server == no revenue opportunity. For now this is just a crazy theoretical exercise, \n            far removed from where the leading frontend architecture voices are driving us, \n            but the possibility fascinates me.\n        </p>        \n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[The history of web application architecture]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/</id>\n        <published>2025-07-13T12:00:00.000Z</published>\n        <updated>2025-07-13T12:00:00.000Z</updated>\n        <summary><![CDATA[The many different ways of building for the web, and their many frustrations.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            I'm old enough to remember what it was like. I first got online in 1994, but by then I was using computers for a few years already.\n            That means I was there for the whole ride, the entire history of web application architecture, \n            from the before times to the present day.\n            So this post will be an overview of the various ways to make a web app, past and present, \n            and their relative trade-offs as I experienced them.\n        </p>\n        <p>\n            Just to set expectations right: this will cover architectures targeted primarily at proper applications, \n            of the sort that work with user data, and where most screens have to be made unique based on that user data.\n            Web sites where the different visitors are presented with identical pages are a different beast.\n            Although many of these architectures overlap with that use case, it will not be the focus here.\n        </p>\n        <p>\n            Also, while I will be mentioning some frameworks, they are equally not the focus.\n            Where you see a framework, you can slot in vanilla web development with a bespoke solution.\n        </p>\n        <p>\n            This will be a long one, so grab a snack, take some time, and let's get going.\n        </p>\n\n        <h3>Before time began</h3>\n        <p>\n            Back when people first went online, the ruling architecture was <em>offline-first</em>.\n            It looked sort of like this:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/architectures/old-school-desktop.webp\" alt=\"architecture diagram of user sending a local file via e-mail\">\n        <p>\n            Our user would have a proper desktop application, written in C or C++ most likely,\n            and that would work with local files on their local file system, all perfectly functional when offline.\n            When they wanted to \"go online\" and share their work, they would dial in to the internet,\n            start their e-mail client and patiently send an e-mail to their friend or colleague containing \n            a copy of their file as an attachment.\n        </p>\n        <p>\n            This architecture was very simple, and it worked well in the absence of a reliable and fast internet connection.\n            This was a good thing because at the time most people <em>never had</em> a reliable and fast internet connection.\n            There were problems though. For one, the bootstrapping problem: how do you get everyone to have the application \n            installed so they can open and edit the file they received via e-mail?\n            Also, the syncing problem: how are changes kept in sync between multiple devices and users?\n            Merging edits from different files that could have <em>weeks</em> of incompatible edits was always \n            somewhere between frustrating and impossible.\n        </p>\n\n        <h3>Traditional server-side rendering</h3>\n        <p>\n            Web applications promised they would solve both problems. At first we built them like this:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/architectures/traditional-ssr.webp\" alt=\"architecture diagram of a traditional server-side rendered web application\" width=\"1586\" height=\"1324\" loading=\"lazy\">\n        <p>\n            The first thing we did was move all of the stuff from all of the users into a central database somewhere online.\n            Because this database was shared between the users, it became a lot more easy to keep their changes in sync.\n            If one user made an edit to something, everyone else would see it on the next refresh.\n        </p>\n        <p>\n            To allow users to actually get at this database we had to give them an application to do it.\n            This new-fangled thing called a <em>web application</em> running on a <em>web application server</em> would take http requests\n            coming from the user's browser, SQL query the database for the right set of stuff, \n            and send back an entire web page. Every click, every submit, it would generate a whole new page.\n        </p>\n        <p>\n            Deployment of those early web applications was often suspiciously simple:\n            someone would connect via FTP to a server, and copy over the files from their local machine.\n            There often weren't even any build steps. There was no step 3.\n        </p>\n        <p>\n            On the one hand this architecture was convenient. It solved the bootstrapping problem \n            by only demanding that each user have a web browser and an internet connection.\n            It also moved all of the application logic over to the server, keeping it neatly in one place.\n            Crucially it kept the browser's task minimal, important in an era where browsers were much less capable\n            and PC's were orders of magnitude slower than today. If done well, it could even be used to make\n            web applications that still worked with JavaScript disabled. My first mobile web app was like that,\n            sneakily using HTML forms with multiple submit actions and hidden input fields\n            to present interactive navigation through a CRUD interface.\n        </p>\n        <p>\n            On the other hand, it had many problems, especially early on. HTML wasn't very good, CSS was in its infancy,\n            and early JavaScript was mostly useless. It was hard going building <em>anything at all</em> on the early web.\n            On top of that, web developers were a new breed, and they had to relearn many of the architecture lessons their desktop developer\n            colleagues had already learned through bitter experience. For example, everyone has heard of the adage\n            \"If you don't choose a framework, you'll end up building a worse one yourself.\" That is because for the first few years\n            building your own terrible framework as you went was the norm, until everyone wisened up and started preaching this wisdom. \n            For sure, my own first experiments in web application development in PHP 3 and 4 were all \n            without the benefit of a proper framework.\n        </p>\n        <p>\n            Web developers also had to learn lessons that their desktop counterparts never had to contend with.\n            Moving the application to the server was convenient, but it exposed it to hackers from all across the world,\n            and the early web application landscape was riddled with embarrassing hacks.\n            Because the threat level on the internet keeps rising this remains a major headache to this day.\n        </p>\n        <p>\n            Another novel problem was having to care a whole lot about connectivity and server uptime.\n            Because users literally couldn't do anything at all if they didn't have a connection to a working web server,\n            making sure that connection was always there became a pervasive headache.\n            Going to a site and seeing an error 500 message was unsurprisingly common in those early years.\n        </p>\n        <p>\n            The biggest problems however were throughput, bandwidth and latency. Because almost every click had to reload the whole page,\n            doing anything at all in those early web applications was <em>slow</em>, like <em>really, really slow</em>.\n            At the time, servers were slow to render the page, networks slow to transport it, and PC's and browsers slow to render.\n            That couldn't stand, so something had to change. It was at this point that we saw a fork in the road,\n            and the web developer community split up into two schools of thought that each went their own way.\n            Although, as you will see, they are drawing closer again.\n        </p>\n\n        <h3>Modern server-side rendering</h3>\n\n        <p>\n            One branch of the web development tree doubled down on server-side rendering,\n            building further on top of the existing server-side frameworks.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/architectures/liveview.webp\" alt=\"architecture diagram of a server-side rendered application with liveview templates\" width=\"1588\" height=\"1324\" loading=\"lazy\">\n        <p>\n            They tackled the problems imposed by throughput and latency by\n            moving over to a model of partial page updates, where small bits of user-activated JavaScript\n            (originally mostly built with jQuery) would update parts of the page with HTML partials\n            that they fetched from the server.\n        </p>\n        <p>\n            The evolution of this architecture are so called <em>LiveViews</em>.\n            This is a design first popularized by the Phoenix framework for the obscure Elixir programming language,\n            but quickly <a href=\"https://github.com/liveviews/liveviews\">adopted in many places</a>.\n        </p>\n        <p>\n            It uses framework logic to automatically wire up server-side generated templates with bits of JavaScript\n            that will automatically call the server to fetch partial page updates when necessary.\n            The developer has the convenience of not thinking about client-side scripting, \n            while the users get an interactive user experience similar to a JavaScript-rich frontend.\n            Typically the client keeps an open websocket connection to the server,\n            so that server-side changes are quickly and automatically streamed into the page as soon as they occur.\n        </p>\n        <p>\n            This architecture is conceptually simple to work with as all the logic remains on the server.\n            It also doesn't ask much from the browser, good for slow devices and bandwidth-constrained environments.\n            As a consequence it finds a sweet spot in mostly static content-driven web sites.\n        </p>\n        <p>\n            But nothing is without trade-offs. This design hits the server on almost every interaction and has no path to offline functionality.\n            Network latency and reliability are its UX killer, and especially on mobile phones – the main way people interact with web apps these days –\n            those can still be a challenge. While this can be mitigated somewhat through browser caching, the limitation is always there.\n            After all, the more that page content is dictated by realtime user input, the more necessary it becomes to push logic to the client.\n            In cases where the network is good however, it can seem like magic even for highly interactive applications, \n            and for that reason it has its diehard fans.\n        </p>\n\n        <h3>Client-side rendering</h3>\n        <p>\n            There was another branch of web development practice, let's say the ones who were fonder\n            of clever architecture, who had a crazy thought: what if we moved rendering data to HTML from the server to the browser?\n            They built new frameworks, in JavaScript, designed to run in the browser\n            so that the application could be shipped as a whole as part of the initial page load, \n            and every navigation would only need to fetch data for the new route.\n            In theory this allowed for smaller and less frequent roundtrips to the server,\n            and therefore an improvement to the user experience.\n            Thanks to a blooming cottage industry of industry insiders advertising its benefits, it became the dominant architecture for new web applications,\n            with React as the framework of choice to run inside the browser.\n        </p>\n        <p>\n            This method taken to its modern best practice extreme looks like this:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/architectures/modern-SPA.webp\" alt=\"Architecture diagram of a client-side rendered single-page application\" width=\"1830\" height=\"1444\" loading=\"lazy\">\n        <p>\n            It starts out by moving the application, its framework, and its other dependencies over to the browser.\n            When the page is loaded the entire bundle gets loaded, and then pages can be rendered as routes inside of the single-page application.\n            Every time a new route needs to be rendered the data gets fetched from the server, not the HTML.\n        </p>\n        <p>\n            The web application server's job is now just providing the application bundle as a single HTML page,\n            and providing API endpoints for loading JSON data for every route. \n            Because those API endpoints naturally end up mirroring the frontend's routes this part usually gets called the <em>backend-for-frontend</em>.\n            This job was so different from the old web server's role that a new generation of frameworks sprung up to be a better fit. \n            Express on node became a very popular choice, as it allowed a great deal of similarity between browser and server codebases,\n            although in practice there's usually not much actual code in common.\n        </p>\n        <p>\n            For security reasons – after all, the web application servers are on the increasingly dangerous public internet –\n            the best practice became to host backends-for-frontend in a DMZ, a demilitarized zone\n            where the assumption has to be that security is temporary and hostile interlopers could arrive at any time.\n            In addition, if an organization has multiple frontends (and if they have a mobile app they probably have at least two),\n            then this DMZ will contain multiple backends for frontend.\n        </p>\n        <p>\n            Because there is only a single database to share between those different BFFs, \n            and because of the security risks of connecting to the database from the dangerous DMZ,\n            a best practice became to keep the backend-for-frontend focused on just the part of serving the frontend,\n            and to wrap the database in a separate thing. This separate <em>microservice</em>\n            is an application whose sole job is publishing an API that gatekeeps access to the database.\n            This API is usually in a separate network segment, shielded by firewalls or API gateways,\n            and it is often built in yet another framework better tailored for building APIs, \n            or even in a different programming language like Go or C#.\n        </p>\n        <p>\n            Of course, having only one microservice is kind of a lonely affair, \n            so even organizations of moderate size would often end up having their backends-for-frontend each talking to multiple microservices.\n        </p>\n        <p>\n            That's just too many servers to manage, too many network connections to configure, too many builds to run, \n            so people by and large stopped managing their own servers, either for running builds or for runtime hosting.\n            Instead they moved to the cloud, where someone else manages the server, and hosted their backends\n            as docker containers or serverless functions deployed by git-powered CI/CD pipelines.\n            This made some people fabulously wealthy. After all, 74% of Amazon's profit is made from AWS,\n            and over a third of Microsoft's from Azure.\n            It is no accident that there is a persistent drumbeat that everyone should move everything to the cloud.\n            Those margins aren't going to pad themselves.\n        </p>\n        <p>\n            Incidentally, microservices as database intermediary are also a thing in the world of server-side rendered applications,\n            but in my personal observation those teams seem to choose this strategy less often.\n            Equally incidentally, the word <em>serverless</em> in the context of serverless functions was and is highly amusing to me, \n            since it requires just as many servers, if not more. (I know why it's called that way, that doesn't make it any less funny.)\n        </p>\n        <p>\n            On paper this client-side rendered architecture has many positive qualities. It is highly modular,\n            which makes the work easy to split up across developers or teams. It pushes page rendering logic into\n            the browser, creating the potential to have a low latency and high quality user experience.\n            The layered nature of the backend and limited scope of the internet-facing backend-for-frontend forms\n            a solid defensive moat against cyberattacks. And the cloud-hosted infrastructure is low effort to manage and easy to scale.\n            A design like this is every architecture astronomer's dream, and I was for a while very enamored with it myself.\n        </p>\n        <p>\n            In practice though, it just doesn't work very well. It's just too <em>complicated</em>.\n            For larger experienced teams in large organizations it can kind of sort of make sense,\n            and it is no surprise that big tech is a heavy proponent of this architecture.\n            But step away from web-scale for just a second and there's too many parts to build and deploy and keep track of,\n            too many technologies to learn, too many hops a data request has to travel through. \n        </p>\n        <p>\n            The application's logic gets smeared out across three or more independent codebases,\n            and a lot of overhead is created in keeping all of those in sync.\n            Adding a single data field to a type can suddenly become a whole project. For one application I was working on\n            I once counted in how many places a particular type was explicitly defined, and the tally reached lucky number 7.\n            It is no accident that right around the time that this architecture peaked the use of monorepo tools \n            to bundle multiple projects into a single repository peaked as well.\n        </p>\n        <p>\n            Go talk to some people just starting out with web development\n            and see how lost they get in trying to figure out all of this <em>stuff</em>, \n            learning all the technologies comprising the Rube Goldberg machine that produces a webpage at the end.\n            See just how little time they have left to dedicate to learning vanilla HTML, CSS and JS, \n            arguably the key things a beginner should be focusing on.\n        </p>\n        <p>\n            Moreover, the promise that moving the application entirely to the browser would improve the user experience mostly <a href=\"https://gitnation.com/contents/project-fugu-bringing-hardware-capabilities-to-the-web-safely\">did not pan out</a>.\n            As applications built with client-side frameworks like React or Angular grew, the bundle to be shipped in a page load ballooned to <em>megabytes</em> in size.\n            The slowest quintile of devices and network connections struggled mightily with these heavy JavaScript payloads.\n            It was hoped that Moore's law would solve this problem, but the dynamics of how (mobile) device and internet provider markets work\n            mean that it hasn't been, and that it won't be any time soon. It's not impossible to build a great user experience \n            with this architecture, but you're starting from behind. Well, at least for public-facing web applications.\n        </p>\n\n        <h3>Client-side rendering with server offload</h3>\n        <p>\n            The designers of client-side frameworks were not wholly insensitive to the frustrations of developers \n            trying to make client-side rendered single-page applications work well on devices and connections \n            that weren't up to the job. They started to offload more and more of the rendering work back to the server.\n            In situations where the content of a page is fixed, <em>static site generation</em> can execute\n            the client-side framework at build time to pre-render pages to HTML.\n            And for situations where content has a dynamic character, <em>server-side rendering</em> was reintroduced \n            back into the mix to offload some of the rendering work back to the server.\n        </p>\n        <p>\n            The current evolution of these trends is the streaming single-page application:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/architectures/streaming-SPA.webp\" alt=\"architecture diagram of a streaming single-page application\" width=\"1830\" height=\"1544\" loading=\"lazy\">\n\n        <p>\n            In this architecture the framework runs the show in both backend-for-frontend and in the browser.\n            It decides where the rendering happens, and only pushes the work to the browser that must run there.\n            When possible the page is shipped prerendered to the browser and the code for the prerendered parts \n            is not needed in the client bundle.\n            Because some parts of the page are more dynamic than others, they can be rendered on-demand in the server \n            and <em>streamed</em> to the browser where they are slotted into the prerendered page.\n            The bundle that is shipped to the browser can be kept light-weight because it mostly just needs \n            to respond to user input by streaming the necessary page updates from the server over an open websocket connection.\n        </p>\n        <p>\n            If that sounds suspiciously like the architecture for modern server-side rendering that I described before,\n            that is because it basically is. While a Next.JS codebase is likely to have some\n            client-rendered components still, the extreme of a best practice Astro codebase would \n            see every last component rendered on the server. \n            In doing that they arrive at something functionally no different from LiveView architecture,\n            and with a similar set of trade-offs. These architectures are simpler to work with, but they \n            perform poorly for dynamic applications on low reliability or high latency connections,\n            and they cannot work offline.\n        </p>\n        <p>\n            Another major simplication of the architecture is getting rid of the database middleman.\n            Microservices and serverless functions are not as hyped as they were, \n            people are happy to build so-called <em>monoliths</em> again, \n            and frameworks are happy to recommend they do so.\n            The meta-frameworks now suggest that the API can be merged into the web application frontend, \n            and the framework will know that those parts are only meant to be run on the server.\n            This radically simplifies the codebase, we're back to a single codebase for the entire application\n            managed by a single framework.\n        </p>\n        <p>\n            However, <a href=\"https://en.wikipedia.org/wiki/No_such_thing_as_a_free_lunch\">TANSTAAFL</a>. This simplification comes at the expense of other things. The Next.JS documentation may claim\n            <em>\"Since Server Components are rendered on the server, you can safely make database queries using an ORM or database client.\"</em>\n            but that doesn't mean that it's actually safe to allow the part that faces the internet to have a direct line to the database.\n            Defense in depth was a good idea, and we're back to trading security for simplicity.\n            There were other reasons that monoliths once fell out of favor. It's like we're now forgetting lessons that were already learned.\n        </p>\n\n        <h3>Where does that leave us?</h3>\n\n        <p>\n            So, which architecture should you pick? I wish I could tell you,\n            but you should have understood by now that the answer was always going to be <em>it depends</em>.\n            Riffing on the work of Tolstoy: all web architectures are alike in that they are unhappy in their own unique way.\n        </p>\n        <p>\n            In a sense, all of these architectures are also unhappy in the same way:\n            there's a whole internet in between the user and their data.\n            There's a golden rule in software architecture: you can't beat physics with code.\n            We draw the internet on diagrams as a cute little cloud, pretending it is not a physical thing.\n            But the internet is wires, and antennas, and satellites, and data centers, and all kinds of physical things and places.\n            Sending a signal through all those physical things and places will always be somewhat unreliable and somewhat slow.\n            We cannot reliably deliver on the promise of a great user experience as long as we put a cute little cloud \n            in between the user and their stuff.\n        </p>\n        <p>\n            In the next article I'll be exploring an obscure but very different architecture,\n            a crazy thought similar to that of client-side rendering:\n            what happens when we move the user's data from the server back into the client?\n            What is <a href=\"../2025-07-16-local-first-architecture/\">local-first web application architecture</a>?\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Clean client-side routing]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-06-25-routing/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-06-25-routing/</id>\n        <published>2025-06-25T12:00:00.000Z</published>\n        <updated>2025-06-25T12:00:00.000Z</updated>\n        <summary><![CDATA[Finding a nice way of doing single-page app routing without a library.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-06-25-routing/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            The main Plain Vanilla tutorial explains two ways of doing client-side routing.\n            Both use old school anchor tags for route navigation.\n            First is the traditional multi-page approach described on the Sites page as one HTML file per route,\n            great for content sites, not so great for web applications.\n            Second is the hash-based routing approach decribed on the Applications page, one custom element per route,\n            better for web applications, but not for having clean URLs or having Google index your content.\n        </p>\n        <p>\n            In this article I will describe a third way, single-file and single-page but with clean URLs using the <code>pushState</code> API,\n            and still using anchor tags for route navigation.\n            The conceit of this technique will be that it needs more code, and the tiniest bit of server cooperation.\n        </p>\n        <h3>Intercepting anchor clicks</h3>\n        <p>\n            To get a true single-page experience the first thing we have to do is intercept link tag navigation and redirect them to in-page events.\n            Our SPA can then respond to these events by updating its routes.\n        </p><p>\n\n        <div><pre><code>export const routerEvents = new EventTarget();\n\nexport const interceptNavigation = (root) =&gt; {\n    // convert link clicks to navigate events\n    root.addEventListener('click', handleLinkClick);\n    // convert navigate events to pushState() calls\n    routerEvents.addEventListener('navigate', handleNavigate);\n}\n\nconst handleLinkClick = (e) =&gt; {\n    const a = e.target.closest('a');\n    if (a &amp;&amp; a.href) {\n        e.preventDefault();\n        const anchorUrl = new URL(a.href);\n        const pageUrl = anchorUrl.pathname + anchorUrl.search + anchorUrl.hash;\n        routerEvents.dispatchEvent(new CustomEvent('navigate', { detail: { url: pageUrl, a }}));\n    }\n}\n\nconst handleNavigate = (e) =&gt; {\n    history.pushState(null, null, e.detail.url);\n}\n</code></pre></div>\n\n        </p><p>\n            In an example HTML page we can leverage this to implement routing in a <code>&lt;demo-app&gt;&lt;/demo-app&gt;</code> element.\n        </p>\n        <div><pre><code>import { routerEvents, interceptNavigation } from './view-route.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n\n    #route = '/';\n\n    constructor() {\n        super();\n        interceptNavigation(document.body);\n        routerEvents.addEventListener('navigate', (e) =&gt; {\n            this.#route = e.detail.url;\n            this.update();\n        });\n    }\n\n    connectedCallback() {\n        this.update();\n    }\n\n    update() {\n        if (this.#route === '/') {\n            this.innerHTML = 'This is the homepage. &lt;a href=\"/details\"&gt;Go to the details page&lt;/a&gt;.';\n        } else if (this.#route === '/details') {\n            this.innerHTML = 'This is the details page. &lt;a href=\"/\"&gt;Go to the home page&lt;/a&gt;.';\n        } else {\n            this.innerHTML = `The page ${this.#route} does not exist. &lt;a href=\"/\"&gt;Go to the home page&lt;/a&gt;.`;\n        }\n        this.innerHTML += `&lt;br&gt;Current route: ${this.#route}`;\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-25-routing/example1/index.html\">example 1</a></p>\n        \n\n        <p>\n            The first thing we're doing in <code>view-route.js</code> is the <code>interceptNavigation()</code> function.\n            It adds an event handler at the top of the DOM that traps bubbling link clicks and turns them into a <code>navigate</code> event instead of the default action of browser page navigation.\n            Then it also adds a <code>navigate</code> event listener that will update the browser's URL by calling <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/History/pushState\">pushState</a>.\n        </p>\n        <p>\n            In <code>app.js</code> we can listen to the same <code>navigate</code> event to actually update the routes.\n            Suddenly we've implemented a very basic in-page routing, but there are still a bunch of missing pieces.\n        </p>\n\n        <h3>There and back again</h3>\n\n        <p>\n            For one, browser back and forward buttons don't actually work.\n            We can click and see the URL update in the browser, but the page does not respond.\n            In order to do this, we need to start listening to <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event\">popstate</a> events.\n        </p>\n        <p>\n            However, this risks creating diverging code paths for route navigation, one for the <code>navigate</code> event and one for the <code>popstate</code> event.\n            Ideally a single event listener responds to both types of navigation.\n            A simplistic way of providing a single event to listen can look like this:\n        </p>\n        <div><p><em>view-route.js (partial):</em></p><pre><code>const handleNavigate = (e) =&gt; {\n    history.pushState(null, null, e.detail.url);\n    routerEvents.dispatchEvent(new PopStateEvent('popstate'));\n}\n\n// update routes on popstate (browser back/forward)\nexport const handlePopState = (e) =&gt; {\n    routerEvents.dispatchEvent(new PopStateEvent('popstate', { state: e.state }));\n}\nwindow.addEventListener('popstate', handlePopState);\n</code></pre></div>\n        <p>\n            Now our views can respond to <code>popstate</code> events and update based on the current route.\n            A second question then becomes: what is the current route? The <code>popstate</code> event does not carry that info.\n            The <code>window.location</code> value does have that, and it is always updated as we navigate, but because it has the full URL it is cumbersome to parse.\n            What is needed is a way of easily parsing it, something like this:\n        </p>\n        <div><p><em>view-route.js (continued):</em></p><pre><code>// ...\n\n// all routes will be relative to the document's base path\nconst baseURL = new URL(window.originalHref || document.URL);\nconst basePath = baseURL.pathname.slice(0, baseURL.pathname.lastIndexOf('/'));\n\n// returns an array of regex matches for matched routes, or null\nexport const matchesRoute = (path) =&gt; {\n    const fullPath = basePath + '(' + path + ')';\n    const regex = new RegExp(`^${fullPath.replaceAll('/', '\\\\/')}`, 'gi');\n    const relativeUrl = location.pathname;\n    return regex.exec(relativeUrl);\n}\n</code></pre></div>\n        <p>\n            The <code>matchesRoute()</code> function accepts a regex to match as the route,\n            and will wrap it so it is interpreted relative to the current document's URL,\n            making all routes relative to our single page.\n            Now we can clean up the application code leveraging these new generic routing features:\n        </p>\n        <div><pre><code>import { routerEvents, interceptNavigation, matchesRoute } from './view-route.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n\n    #route = '/';\n\n    constructor() {\n        super();\n        interceptNavigation(document.body);\n        routerEvents.addEventListener('popstate', (e) =&gt; {\n            const matches =\n                matchesRoute('/details') || \n                matchesRoute('/');\n            this.#route = matches?.[1];\n            this.update();\n        });\n    }\n\n    connectedCallback() {\n        this.update();\n    }\n\n    update() {\n        if (this.#route === '/') {\n            this.innerHTML = 'This is the homepage. &lt;a href=\"/details\"&gt;Go to the details page&lt;/a&gt;.';\n        } else if (this.#route === '/details') {\n            this.innerHTML = 'This is the details page. &lt;a href=\"/\"&gt;Go to the home page&lt;/a&gt;.';\n        } else {\n            this.innerHTML = `The page ${this.#route} does not exist. &lt;a href=\"/\"&gt;Go to the home page&lt;/a&gt;.`;\n        }\n        this.innerHTML += `&lt;br&gt;Current route: ${this.#route}`;\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-25-routing/example2/index.html\">example 2</a></p>\n        \n        <p>\n            Opening that in a separate tab we can see that the absolute URL neatly updates with the routes,\n            that browser back/forwards navigation updates the view, and that inside the view the route is\n            relative to the document.\n        </p>\n        <p>\n            Because <code>matchesRoute()</code> accepts a regex,\n            it can be used to capture route components that are used inside of the view.\n            Something like <code>matchesRoute('/details/(?&lt;id&gt;[\\\\w]+)')</code> would\n            put the ID in <code>matches.groups.id</code>. It's simple, but it gets the job done.\n        </p>\n\n        <h3>Can you use it in a sentence?</h3>\n\n        <p>\n            While this rudimentary way of detecting routes works, adding more routes quickly becomes unwieldy.\n            It would be nice to instead have a declarative way of wrapping parts of views inside routes.\n            Enter: a custom element to wrap each route in the page's markup.\n        </p>\n        <div><p><em>view-route.js (partial):</em></p><pre><code>// ...\n\ncustomElements.define('view-route', class extends HTMLElement {\n\n    #matches = [];\n\n    get isActive() {\n        return !!this.#matches?.length;\n    }\n\n    get matches() {\n        return this.#matches;\n    }\n\n    set matches(v) {\n        this.#matches = v;\n        this.style.display = this.isActive ? 'contents' : 'none';\n        if (this.isActive) {\n            this.dispatchEvent(new CustomEvent('routechange', { detail: v, bubbles: true }));\n        }\n    }\n\n    connectedCallback() {\n        routerEvents.addEventListener('popstate', this);\n        this.update();\n    }\n\n    disconnectedCallback() {\n        routerEvents.removeEventListener('popstate', this);\n    }\n\n    handleEvent(e) {\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['path'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const path = this.getAttribute('path') || '/';\n        this.matches = this.matchesRoute(path) || [];\n    }\n\n    matchesRoute(path) {\n        // '*' triggers fallback route if no other route on the same DOM level matches\n        if (path === '*') {\n            const activeRoutes = \n                Array.from(this.parentNode.getElementsByTagName('view-route')).filter(_ =&gt; _.isActive);\n            if (!activeRoutes.length) return [location.pathname, '*'];\n        // normal routes\n        } else {\n            return matchesRoute(path);\n        }\n        return null;\n    }\n});\n</code></pre></div>\n        <p>\n            Now we can rewrite our app to be a lot more declarative, while preserving the behavior.\n        </p>\n        <div><pre><code>import { interceptNavigation } from './view-route.js';\n\ncustomElements.define('demo-app', class extends HTMLElement {\n\n    constructor() {\n        super();\n        interceptNavigation(document.body);\n    }\n\n    connectedCallback() {\n        this.innerHTML = `\n        &lt;view-route path=\"/(?:index.html)?$\"&gt;\n            This is the homepage. &lt;a href=\"/details\"&gt;Go to the details page&lt;/a&gt;, or\n            travel a &lt;a href=\"/unknown\"&gt;path of mystery&lt;/a&gt;.\n        &lt;/view-route&gt;\n        &lt;view-route path=\"/details\"&gt;\n            This is the details page. &lt;a href=\"/\"&gt;Go to the home page&lt;/a&gt;.\n        &lt;/view-route&gt;\n        &lt;view-route path=\"*\"&gt;\n            The page does not exist. &lt;a href=\"/\"&gt;Go to the home page&lt;/a&gt;.\n        &lt;/view-route&gt;\n        `\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-25-routing/example3/index.html\">example 3</a></p>\n        \n\n        <h3>404 not found</h3>\n\n        <p>\n            While things now look like they work perfectly, the illusion is shattered upon reloading the page when it is on the details route.\n            To get rid of the 404 error we need a handler that will redirect to the main index page.\n            This is typically something that requires server-side logic, locking us out from simple static hosting like GitHub Pages,\n            but thanks to the kindness of internet strangers, <a href=\"https://github.com/rafgraph/spa-github-pages\">there is a solution</a>.\n        </p>\n        <p>\n            It involves creating a <code>404.html</code> file that GitHub will load for any 404 error (the tiny bit of server cooperation).\n            In this file the route is encoded as a query parameter, the page redirects to <code>index.html</code>,\n            and inside that index page the route is restored.\n        </p>\n        <div><pre><code>&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n    &lt;script&gt;\n        var pathSegmentsToKeep = window.location.hostname === 'localhost' ? 0 : 1;\n\n        var l = window.location;\n        l.replace(\n            l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +\n            l.pathname.split('/').slice(0, 1 + pathSegmentsToKeep).join('/') + '/?/' +\n            l.pathname.slice(1).split('/').slice(pathSegmentsToKeep).join('/').replace(/&amp;/g, '~and~') +\n            (l.search ? '&amp;' + l.search.slice(1).replace(/&amp;/g, '~and~') : '') +\n            l.hash\n        );\n    &lt;/script&gt;\n&lt;/head&gt;\n&lt;/html&gt;</code></pre></div>\n        <div><p><em>index.html:</em></p><pre><code>&lt;!doctype html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n    &lt;!-- ... --&gt;\n&lt;/head&gt;\n&lt;body&gt;\n    &lt;script type=\"text/javascript\"&gt;\n        // preserve route\n        window.originalHref = window.location.href;\n        // decode from parameter passed by 404.html\n        (function (l) {\n            if (l.search[1] === '/') {\n                var decoded = l.search.slice(1).split('&amp;').map(function (s) {\n                    return s.replace(/~and~/g, '&amp;')\n                }).join('?');\n                window.history.replaceState(null, null,\n                    l.pathname.slice(0, -1) + decoded + l.hash\n                );\n            }\n        }(window.location))\n    &lt;/script&gt;\n    \n    &lt;!-- ... --&gt;\n&lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n\n        <p>\n            Adding this last piece to what we already had gets us a complete routing solution for vanilla single page applications\n            that are hosted on GitHub Pages. Here's a live example hosted from there:\n        </p>\n        <p><a href=\"https://sebrechts.net/view-route/\">example 4</a></p>\n\n        <p>\n            To full code of <code>view-route.js</code> and of this example <a href=\"https://github.com/jsebrech/view-route\">is on GitHub</a>.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Bringing React's <ViewTransition> to vanilla JS]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/</id>\n        <published>2025-06-12T12:00:00.000Z</published>\n        <updated>2025-06-12T12:00:00.000Z</updated>\n        <summary><![CDATA[Bringing React's declarative view transitions API to vanilla as a custom element.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            I like React. I really do. It is the default answer for modern web development, and it is that answer for a reason.\n            Generally when React adds a feature it is well thought through, within the React system of thinking.\n            My one criticism is that React by its nature overthinks things, that dumber and simpler solutions would often be \n            on the whole ... better. Less magic, more predictable.\n        </p>\n        <p>\n            So when I port framework features to vanilla JS, don't take this as a slight of that framework.\n            It is meant as an exploration of what dumber and simpler solutions might look like, when built  \n            on the ground floor of the web's platform instead of the lofty altitudes of big frameworks. \n            It is a great way to learn.\n        </p>\n        <p>\n            Which brings me of course to today's topic: view transitions, and how to implement them.\n        </p>\n\n        <h3>View Transitions 101</h3>\n\n        <p>\n            Let's start with the basics: what is a view transition?\n        </p>\n\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/example1/index.html\">example 1</a></p>\n\n        <p>\n            In a supporting browser, what you'll see when you click is a square smoothly transitioning\n            between blue and orange on every button click. By supported browser I mean Chrome, Edge or Safari,\n            but sadly not yet Firefox, although <a href=\"https://bugzilla.mozilla.org/show_bug.cgi?id=1823896\">they're working on it</a>!\n            In Firefox you'll see the change, but applied immediately without the animation.\n        </p>\n        <p>\n            At the code level, it looks something like this:\n        </p>\n\n        <div><p><em>example.js:</em></p><pre><code>function transition() {\n    const square1 = document.getElementById('square1');\n    if (document.startViewTransition) {\n        document.startViewTransition(() =&gt; {\n            square1.classList.toggle('toggled');\n        });\n    } else {\n        square1.classList.toggle('toggled');\n    }\n}\n</code></pre></div>\n        <div><p><em>transitions.css:</em></p><pre><code>#square1 {\n    background-color: orange;\n}\n#square1.toggled {\n    background-color: blue;\n}</code></pre></div>\n\n        <p>\n            How this works is that the browser takes a snapshot of the page when we call <code>document.startViewTransition()</code>,\n            takes another snapshot after the callback passed to it is done (or the promise it returns fulfills),\n            and then figures out how to smoothly animate between the two snapshots, using a fade by default.\n        </p>\n        <p>\n            A very nice thing is that by putting a <code>view-transition-name</code> style on an element we can \n            make it transition independently from the rest of the page, and we can control that transition through CSS.\n        </p>\n        <div><p><em>example.js:</em></p><pre><code>function transition() {\n    const square1 = document.getElementById('square1');\n    const square2 = document.getElementById('square2');\n    if (document.startViewTransition) {\n        document.startViewTransition(() =&gt; {\n            square1.classList.toggle('toggled');\n            square2.classList.toggle('toggled');\n        });\n    } else {\n        square1.classList.toggle('toggled');\n        square2.classList.toggle('toggled');\n    }\n}\n</code></pre></div>\n        <div><p><em>transitions.css:</em></p><pre><code>#square2 {\n    background-color: green;\n    view-transition-name: slide;\n    display: none;\n}\n#square2.toggled {\n    display: inline-block;\n}\n::view-transition-new(slide):only-child {\n    animation: 400ms ease-in both slide-in;\n}\n@keyframes slide-in {\n    from { transform: translateY(-200px); }\n    to { transform: translateY(0); }\n}</code></pre></div>\n        <p>\n            Now we can see a second square sliding in on the first click, and fading out on the second.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/example2/index.html\">example 2</a></p>\n\n        <p>\n            That's enough view transition basics for now. If you're curious for more, \n            you can learn the rest in the <a href=\"https://developer.chrome.com/docs/web-platform/view-transitions\">chrome developer documentation</a>.\n        </p>\n\n        <h3>Here comes trouble</h3>\n\n        <p>\n            Up to this point, we've gotten the fair weather version of view transitions, but there are paper cuts.\n        </p>\n        <ul>\n            <li>Firefox doesn't support view transitions at all, so we have to feature-detect.</li>\n            <li>There is only one actual current View Transitions standard, level 1, but most of the online tutorials talk about the unfinalized level 2.</li> \n            <li>If there are duplicate values of <code>view-transition-name</code> anywhere on the page, the animations disappear in a puff of duplicate element error smoke.</li>\n            <li>As always, there's a thing about shadow DOM, but more on that later.</li>\n            <li>Starting a new view transition when one is already running skips to the end of the previous one, bringing the smooth user experience to a jarring end.</li>\n            <li>User input is blocked while the view is transitioning, causing frustration when clicks are ignored.</li>\n            <li>The <code>document.startViewTransition()</code> function only accepts a single callback that returns a single promise.</li>\n        </ul>\n        <p>\n            It is the last one that really spells trouble. In a larger single-page web application we'll typically\n            find a central routing layer that triggers a number of asynchronous updates every time the route changes.\n            Wrapping those asynchronous updates into a single promise can be a challenge,\n            as is finding the right place to \"slot in\" a call to <code>document.startViewTransition()</code>.\n        </p>\n        <p>\n            Also, we probably don't even <em>want</em> to wait for all of the asynchronous updates to complete.\n            Leaving the application in an interactive state in between two smaller view transitions is better\n            than bundling it all together into one ponderous picture perfect transition animation.\n        </p>\n\n        <h3>What React did</h3>\n\n        <p>\n            React being React they solve those problems through magic, through exceeding cleverness.\n            You can read up on <a href=\"https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#view-transitions\">their approach to view transitions</a>, \n            but distilling it down it becomes this:\n        </p>\n        <ul>\n            <li>Anything that should take part separately in a view transition is wrapped in a <code>&lt;ViewTransition&gt;</code> component.</li>\n            <li>React will choose unique <code>view-transition-name</code> style values, which DOM elements to set them on, and when to set them.\n                This can be controlled through the <code>&lt;ViewTransition&gt;</code> <code>name</code> and <code>key</code> props.</li>\n            <li>Any updates that should become part of a view transition are wrapped in a <code>startTransition()</code> call.</li>\n            <li>React automatically figures out when to call <code>document.startViewTransition()</code>, and what updates to put inside the callback.\n                It also cleverly avoids starting new transitions when one is already running, so <code>startTransition()</code> can be called from multiple places safely.\n                Oh, and by the way, it feature detects, obviously.\n            </li>\n        </ul>\n        <p>\n            When you do all of that, you get <a href=\"https://codesandbox.io/p/sandbox/njn4yc\">magic</a>.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/react-demo.gif\" alt=\"A React view transition demo\" loading=\"lazy\" width=\"240\">\n        <p>\n            Good luck figuring out <a href=\"https://react.dev/reference/react/ViewTransition#how-does-viewtransition-work\">how it works</a>, \n            or how to troubleshoot when the magic loses its shine.\n            But that is the bar, that is the lofty goal of user experience to reach with a dumber and simpler reimagining as vanilla JS.\n            So let's get cooking.\n        </p>\n\n        <h3>A fresh start</h3>\n\n        <p>\n            Our starting point is a barebones implementation of a <code>startTransition()</code>\n            function to replace what React's <code>startTransition()</code> does.\n            It will fall back to non-animated transitions if our browser doesn't support <code>document.startViewTransition</code>.\n        </p>\n\n        <div><pre><code>export const startTransition = (updateCallback) =&gt; {\n    if (document.startViewTransition) {\n        document.startViewTransition(updateCallback);\n    } else {\n        const done = Promise.try(updateCallback);\n        return {\n            updateCallbackDone: done,\n            ready: done,\n            finished: done,\n            skipTransition: () =&gt; {}\n        };\n    }\n}\n</code></pre></div>\n        <div><p><em>example.js:</em></p><pre><code>import { startTransition } from './view-transition.js';\n\nexport function transition() {\n    startTransition(() =&gt; {\n        document.getElementById('square1').classList.toggle('toggled');\n        document.getElementById('square2').classList.toggle('toggled');\n    });\n}\n</code></pre></div>\n\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/example3/index.html\">example 3</a></p>\n\n        <p>\n            While that takes care of feature-detecting, we can still run into timing issues.\n            For example, let's say that instead of toggling we were switching routes,\n            and the second route needs to load data prior to animating in.\n        </p>\n        <p>\n            So with HTML like this:\n        </p>\n\n        <pre><code>\n    &lt;p&gt;&lt;button&gt;Navigate&lt;/button&gt;&lt;/p&gt;\n    &lt;div id=\"route1\" class=\"route\"&gt;&lt;/div&gt;\n    &lt;div id=\"route2\" class=\"route\"&gt;&lt;/div&gt;\n        </code></pre>\n\n        <p>\n            We might intuitively choose to do something like this:\n        </p>\n\n        <div><p><em>example.js:</em></p><pre><code>import { startTransition } from './view-transition.js';\n\nlet currentRoute = '';\n\nexport function navigate() {\n    currentRoute = currentRoute === 'route2' ? 'route1' : 'route2';\n    updateRoute1();\n    updateRoute2();\n}\n\nfunction updateRoute1() {\n    startTransition(() =&gt; {\n        if (currentRoute === 'route1') {\n            document.getElementById('route1').classList.add('active');\n        } else {\n            document.getElementById('route1').classList.remove('active');\n        }\n    });\n}\n\nfunction updateRoute2() {\n    startTransition(() =&gt; {\n        const route2 = document.getElementById('route2');\n        if (currentRoute === 'route2') {\n            route2.classList.add('active', 'loading');\n            route2.textContent = '...';\n            load().then((data) =&gt; startTransition(() =&gt; {\n                route2.textContent = data;\n                route2.classList.remove('loading');\n            }));\n        } else {\n            document.getElementById('route2').classList.remove('active');\n        }\n    });\n}\n\nfunction load() {\n    return new Promise((resolve) =&gt; {\n        setTimeout(() =&gt; {\n            resolve('Hi!');\n        }, 250);\n    });\n}\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/example4/index.html\">example 4</a></p>\n\n        <p>\n            But, as you see when trying it out, it doesn't work. Because the <code>startTransition()</code>\n            calls end up overlapping each other, the animation is interrupted, and we get a jarring experience.\n            While this toy example can be made to work by tuning delays, in the real world those same delays are network-based, so there's no timing-based solution.\n            We also can't solve this by bundling everything into one single big view transition, because that would imply\n            blocking user input while a network request completes, which would be a bad user experience.\n        </p>\n        <p>\n            React solves all of this in the typical React way. It will smartly choose how to batch work\n            into successive calls to <code>document.startViewTransition()</code>. It will take into account where something loads lazily,\n            as in the previous example, and batch the work of animating in the content for the fallback in a separate view transition.\n        </p>\n        \n        <h3>Taking a queue</h3>\n\n        <p>\n            Distilling that approach to its essence, the really useful part of React's solution is the queueing and batching of work. \n            Any call to <code>startTransition()</code> that occurs while a view transition is running should be queued until after the transition completes,\n            and nested calls should have all their updates batched together.\n        </p>\n\n        <div><p><em>view-transition.js:</em></p><pre><code>// the currently animating view transition\nlet currentTransition = null;\n// the next transition to run (after currentTransition completes)\nlet nextTransition = null;\n\n/** start a view transition or queue it for later if one is already animating */\nexport const startTransition = (updateCallback) =&gt; {\n    if (!updateCallback) updateCallback = () =&gt; {};\n    // a transition is active\n    if (currentTransition &amp;&amp; !currentTransition.isFinished) {\n        // it is running callbacks, but not yet animating\n        if (!currentTransition.isReady) {\n            currentTransition.addCallback(updateCallback);\n            return currentTransition;\n        // it is already animating, queue callback in the next transition\n        } else {\n            if (!nextTransition) {\n                nextTransition = new QueueingViewTransition();\n            }\n            return nextTransition.addCallback(updateCallback);\n        }\n    // if no transition is active, start animating the new transition\n    } else {\n        currentTransition = new QueueingViewTransition();\n        currentTransition.addCallback(updateCallback);\n        currentTransition.run();\n        // after it's done, execute any queued transition\n        const doNext = () =&gt; {\n            if (nextTransition) {\n                currentTransition = nextTransition;\n                nextTransition = null;\n                currentTransition.run();\n                currentTransition.finished.finally(doNext);\n            } else {\n                currentTransition = null;\n            }\n        }\n        currentTransition.finished.finally(doNext);\n        return currentTransition;\n    }\n}\n\n// ...</code></pre></div>\n\n        <p>\n            The <code>QueueingViewTransition</code> implementation is a straightforward batching of callbacks,\n            and a single call to <code>document.startViewTransition()</code> that executes them in order.\n            It is not included in the text of this article for brevity's sake, but linked at the bottom instead.\n        </p>\n        <p>\n            Applying that queueing solution on top of the previous example's unchanged code, \n            we suddenly see the magic of clean view transitions between dynamically loading routes.\n        </p>\n\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/example5/index.html\">example 5</a></p>\n\n        <h3>Back to the top</h3>\n\n        <p>\n             So as I was saying at the top, I like porting framework features to vanilla JS as a way of learning and exploring dumber and simpler solutions.\n             Which brings me to the playground for that learning, a full port of React's tour-de-force <code>&lt;ViewTransition&gt;</code> example to vanilla web code.\n        </p>\n\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/example6/index.html\">example 6</a></p>\n\n        <p>\n            The full code of this example is <a href=\"https://github.com/jsebrech/view-transition-element\">on GitHub</a>.\n            Arguably the 300 lines of code in the <code>lib/</code> folder of that example constitute a mini-framework,\n            but fascinating to me is that you can get so much mileage out of such a small amount of library code,\n            with the resulting single-page application being more or less the same number of lines as the React original.\n        </p>\n        <p>\n            That example also shows how to do a purely client-side router with clean URLs using <code>pushState()</code>.\n            This blog post has however gone too long already, so I'll leave that for another time.\n        </p>\n\n        <h3>One more thing</h3>\n\n        <p>\n            Oh yeah, I promised to talk about the thing with shadow DOM, and I promised a custom element.\n            Here is the thing with shadow DOM: when <code>document.startViewTransition()</code> is called from the light DOM,\n            it cannot see elements inside the shadow DOM that need to transition independently, \n            unless those elements are exposed as DOM parts and a <code>view-transition-name</code> style is set on them in the light DOM.\n        </p>\n        <p>\n            If the solution to that intrigues you, it's in the GitHub example repo as well as a &lt;view-transition&gt; custom element.\n            If that sounds like a bunch of mumbo jumbo instead, join the club.\n            Just one more reason to avoid shadow DOM.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Making a new form control]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/</id>\n        <published>2025-05-09T12:00:00.000Z</published>\n        <updated>2025-05-09T12:00:00.000Z</updated>\n        <summary><![CDATA[Building a form control as a custom element.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            There are some things that a web developer <em>knows</em> they shouldn't attempt.\n            Making clever use of contenteditable. Building custom form controls. Making complicated custom elements without a framework.\n            But do we really know what we think we know? Why not try to do all three, just for fun? Could it really be that bad?\n        </p>\n        <p><em>Narrator: it would indeed be that bad.</em></p>\n        <p>\n            This article is building on the previous one on proper <a href=\"../2025-04-21-attribute-property-duality/\">attribute/property relations</a> in custom elements.\n            Read that first if you haven't yet. In this piece we're taking it a step further to build a custom element that handles input.\n            The mission is simple: implement a basic version of <code>&lt;input type=\"text\" /&gt;</code> but with <code>display: inline</code> layout.\n        </p>\n\n        <h3>A simple element</h3>\n        \n        <p>\n            Let's start by just throwing something against the wall and playing around with it.\n        </p>\n        <div><pre><code>customElements.define('input-inline', class extends HTMLElement {\n    \n    get value() {\n        return this.getAttribute('value') ?? '';\n    }\n    set value(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    get name() {\n        return this.getAttribute('name') ?? '';\n    }\n    set name(v) {\n        this.setAttribute('name', String(v));\n    }\n    \n    connectedCallback() {\n        this.#update();\n    }\n\n    static observedAttributes = ['value'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        if (this.textContent !== this.value) {\n            this.textContent = this.value;\n        }\n        this.contentEditable = true;\n    }\n});</code></pre></div>\n        <p>\n            And here's how we use it:<br>\n        </p>\n        <div><pre><code>&lt;form&gt;\n    &lt;p&gt;\n        My favorite colors are &lt;input-inline name=\"color1\" value=\"green\"&gt;&lt;/input-inline&gt; \n        and &lt;input-inline name=\"color2\" value=\"purple\"&gt;&lt;/input-inline&gt;.\n    &lt;/p&gt;\n    &lt;button type=\"submit\"&gt;Submit&lt;/button&gt;\n&lt;/form&gt;</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/demo1/index.html\">demo1</a></p>\n\n        <p>\n            This is simple, clean, and horribly broken. For one, the form cannot see these controls at all and submits the empty object.\n        </p>\n\n        <h3>Form-associated elements</h3>\n\n        <p>\n            To fix that, we have to make a <a href=\"https://html.spec.whatwg.org/dev/custom-elements.html#custom-elements-face-example\">form-associated custom element</a>.\n            This is done through the magic of the <code>formAssociated</code> property and <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals\">ElementInternals</a>.\n        </p>\n\n        <div><p><em>input-inline.js:</em></p><pre><code>customElements.define('input-inline', class extends HTMLElement {\n    \n    #internals;\n\n    /* ... */\n\n    constructor() {\n        super();\n        this.#internals = this.attachInternals();\n        this.#internals.role = 'textbox';\n    }\n    \n    /* ... */\n\n    #update() {\n        /* ... */\n        this.#internals.setFormValue(this.value);\n    }\n\n    static formAssociated = true;\n});</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/demo2/index.html\">demo2</a></p>\n\n        <p>\n            <code>ElementInternals</code> offers a control surface for setting the behavior of our custom element as part of a form.\n            The <code>this.#internals.role = 'textbox'</code> assignment sets a default role that can be overridden by the element's user through the <code>role</code> attribute or property, just like for built-in form controls.\n            By calling <code>this.#internals.setFormValue</code> every time the control's value changes the form will know what value to submit.\n            But ... while the form does submit the values for our controls now, it does not see the changes we make. That's because we aren't responding to input yet.\n        </p>\n\n        <h3>Looking for input</h3>\n\n        <p>\n            Ostensibly responding to input is just adding a few event listeners in <code>connectedCallback</code> and removing them again in <code>disconnectedCallback</code>.\n            But doing it that way quickly gets verbose. An easy alternative is to instead rely on some of the built-in event logic magic,\n            namely that events bubble and that <a href=\"https://gregdaynes.com/note/2024/07/29/web-components.html\">objects can be listeners too</a>.\n        </p>\n\n        <div><p><em>input-inline.js:</em></p><pre><code>customElements.define('input-inline', class extends HTMLElement {\n    \n    #shouldFireChange = false;\n    \n    /* ... */\n\n    constructor() {\n        /* ... */\n        this.addEventListener('input', this);\n        this.addEventListener('keydown', this);\n        this.addEventListener('paste', this);\n        this.addEventListener('focusout', this);\n    }\n\n    handleEvent(e) {\n        switch (e.type) {\n            // respond to user input (typing, drag-and-drop, paste)\n            case 'input':\n                this.value = cleanTextContent(this.textContent);\n                this.#shouldFireChange = true;\n                break;\n            // enter key should submit form instead of adding a new line\n            case 'keydown':\n                if (e.key === 'Enter') {\n                    e.preventDefault();\n                    this.#internals.form?.requestSubmit();\n                }\n                break;\n            // prevent pasting rich text (firefox), or newlines (all browsers)\n            case 'paste':\n                e.preventDefault();\n                const text = e.clipboardData.getData('text/plain')\n                    // replace newlines and tabs with spaces\n                    .replace(/[\\n\\r\\t]+/g, ' ')\n                    // limit length of pasted text to something reasonable\n                    .substring(0, 1000);\n                // shadowRoot.getSelection is non-standard, fallback to document in firefox\n                // https://stackoverflow.com/a/70523247\n                let selection = this.getRootNode()?.getSelection?.() || document.getSelection();\n                let range = selection.getRangeAt(0);\n                range.deleteContents();\n                range.insertNode(document.createTextNode(text));\n                // manually trigger input event to restore default behavior\n                this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n                break;\n            // fire change event on blur\n            case 'focusout':\n                if (this.#shouldFireChange) {\n                    this.#shouldFireChange = false;\n                    this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n                }\n                break;\n        }\n    }\n    \n    /* ... */\n});\n\nfunction cleanTextContent(text) {\n    return (text ?? '')\n        // replace newlines and tabs with spaces\n        .replace(/[\\n\\r\\t]+/g, ' ');\n}\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/demo3/index.html\">demo3</a></p>\n\n        <p>\n            I prefer this pattern because it simplifies the code a lot compared to having separate handler functions.\n            Attaching event listeners in the constructor instead of attaching and detaching them in the lifecycle callbacks is another simplification. \n            It may seem like blasphemy to never clean up the event listeners, but DOM event listeners\n            are weakly bound and garbage collection of the element can still occur with them attached. So this is fine.\n        </p>\n        <p>\n            In the event handler logic there's some verbosity to deal with the fallout of working with contenteditable.\n            As this code is not the focus of this article, I won't dally on it except to remark that contenteditable is still just as annoying as you thought it was.\n        </p>\n        <p>\n            With these changes our element will now also emit <code>input</code> and <code>change</code> events just like a built-in HTML form control.\n            But, you may have noticed another issue has cropped up. The standard form reset button does not actually reset the form.\n        </p>\n\n        <h3>Read the instructions</h3>\n\n        <p>\n            You see, when we said <code>static formAssociated = true</code> we entered into a contract to faithfully implement the expected behavior of a form control.\n            That means we have a bunch of extra work to do.\n        </p>\n\n        <div><p><em>input-inline.js:</em></p><pre><code>customElements.define('input-inline', class extends HTMLElement {\n    \n    /* ... */\n\n    #formDisabled = false;\n    #value;\n\n    set value(v) {\n        if (this.#value !== String(v)) {\n            this.#value = String(v);\n            this.#update();    \n        }\n    }\n    get value() {\n        return this.#value ?? this.defaultValue;\n    }\n\n    get defaultValue() {\n        return this.getAttribute('value') ?? '';\n    }\n    set defaultValue(value) {\n        this.setAttribute('value', String(value));\n    }\n\n    set disabled(v) {\n        if (v) {\n            this.setAttribute('disabled', 'true');\n        } else {\n            this.removeAttribute('disabled');\n        }\n    }\n    get disabled() {\n        return this.hasAttribute('disabled');\n    }\n\n    set readOnly(v) {\n        if (v) {\n            this.setAttribute('readonly', 'true');\n        } else {\n            this.removeAttribute('readonly');\n        }\n    }\n    get readOnly() {\n        return this.hasAttribute('readonly');\n    }\n\n    /* ... */\n\n    static observedAttributes = ['value', 'disabled', 'readonly'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        this.style.display = 'inline';\n        this.textContent = this.value;\n        this.#internals.setFormValue(this.value);\n\n        const isDisabled = this.#formDisabled || this.disabled;\n        this.#internals.ariaDisabled = isDisabled;\n        this.#internals.ariaReadOnly = this.readOnly;\n        this.contentEditable = !this.readOnly &amp;&amp; !isDisabled &amp;&amp; 'plaintext-only';\n        this.tabIndex = isDisabled ? -1 : 0;\n    }\n\n    static formAssociated = true;\n\n    formResetCallback() {\n        this.#value = undefined;\n        this.#update();\n    }\n    \n    formDisabledCallback(disabled) {\n        this.#formDisabled = disabled;\n        this.#update();\n    }\n    \n    formStateRestoreCallback(state) {\n        this.#value = state ?? undefined;\n        this.#update();\n    }\n});\n\n/* ... */</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/demo4/index.html\">demo4</a></p>\n\n        <p>\n            There's a LOT going on there. It's too much to explain, so let me sum up.\n        </p>\n        <ul>\n            <li>The <code>value</code> attribute now corresponds to a <code>defaultValue</code> property, which is the value shown until changed and also the value that the form will reset the field to.</li>\n            <li>The <code>value</code> property contains only the modified value and does not correspond to an attribute.</li>\n            <li>The control can be marked disabled or read-only through attribute or property.</li>\n            <li>The form callbacks are implemented, so the control can be reset to its default value, will restore its last value after back-navigation, and will disable itself when it is in a disabled fieldset.</li>\n        </ul>\n\n        <h3>With some style</h3>\n\n        <p>\n            Up to this point we've been using some stand-in styling.\n            However, it would be nice to have some default styling that can be bundled with our custom form control.\n            Something like this:\n        </p>\n\n        <div><pre><code>/* default styling has lowest priority */\n@layer {\n    :root {\n        --input-inline-border-color: light-dark(rgb(118, 118, 118), rgb(161, 161, 161));\n        --input-inline-border-color-hover: light-dark(rgb(78, 78, 78), rgb(200, 200, 200));\n        --input-inline-border-color-disabled: rgba(150, 150, 150, 0.5);\n        --input-inline-text-color: light-dark(fieldtext, rgb(240, 240, 240));\n        --input-inline-text-color-disabled: light-dark(rgb(84, 84, 84), rgb(170, 170, 170));\n        --input-inline-bg-color: inherit;\n        --input-inline-bg-color-disabled: inherit;\n        --input-inline-min-width: 4ch;\n    }\n\n    input-inline {\n        display: inline;\n        background-color: var(--input-inline-bg-color);\n        color: var(--input-inline-text-color);\n        border: 1px dotted var(--input-inline-border-color);\n        padding: 2px 3px;\n        margin-bottom: -2px;\n        border-radius: 3px;\n        /* minimum width */\n        padding-right: max(3px, calc(var(--input-inline-min-width) - var(--current-length)));\n\n        &amp;:hover {\n            border-color: var(--input-inline-border-color-hover);\n        }\n    \n        &amp;:disabled {\n            border-color: var(--input-inline-border-color-disabled);\n            background-color: var(--input-inline-bg-color-disabled);\n            color: var(--input-inline-text-color-disabled);\n            -webkit-user-select: none;\n            user-select: none;\n        }\n    \n        &amp;:focus-visible {\n            border-color: transparent;\n            outline-offset: 0;\n            outline: 2px solid royalblue; /* firefox */\n            outline-color: -webkit-focus-ring-color; /* the rest */\n        }\n    }\n\n    @media screen and (-webkit-min-device-pixel-ratio:0) {\n        input-inline:empty::before {\n            /* fixes issue where empty input-inline shifts left in chromium browsers */\n            content: \" \";\n        }\n    }\n\n}\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/demo5/index.html\">demo5</a></p>\n\n        <p>\n            The styles are isolated by scoping them to the name of our custom element, \n            and the use of @layer puts them at the lowest priority, so that any user style will override the default style,\n            just like for the built-in form controls. The use of variables offers an additional way to quickly restyle the control.\n        </p>\n        <p>\n            In the styling we also see the importance of properly thinking out disabled and focused state behavior.\n            The upside and downside of building a custom form control is that we get to implement all the behavior that's normally built-in to the browser.\n        </p>\n        <p>\n            We're now past the 150 lines mark, just to get to the low bar of implementing the browser's mandatory form control behavior.\n            So, are we done? Well, not quite. There's still one thing that form controls do, and although it's optional it's also kind of required.\n        </p>\n\n        <h3>Validation</h3>\n\n        <p>\n            Built-in form controls come with a validity API. To get an idea of what it means to implement it \n            in a custom form control, let's add one validation attribute: <code>required</code>.\n            It doesn't seem like it should take a lot of work, right?\n        </p>\n\n        <div><p><em>input-inline.js:</em></p><pre><code>let VALUE_MISSING_MESSAGE = 'Please fill out this field.';\n(() =&gt; {\n    const input = document.createElement('input');\n    input.required = true;\n    input.reportValidity();\n    VALUE_MISSING_MESSAGE = input.validationMessage;\n})();\n\nconst isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\ncustomElements.define('input-inline', class extends HTMLElement {\n    \n    /* ... */\n\n    #customValidityMessage = '';\n\n    /* ... */\n\n    set required(v) {\n        if (v) {\n            this.setAttribute('required', 'true');\n        } else {\n            this.removeAttribute('required');\n        }\n    }\n    get required() {\n        return this.hasAttribute('required');\n    }\n\n    /* ... */\n\n    static observedAttributes = ['value', 'disabled', 'readonly', 'required'];\n    attributeChangedCallback() {\n        this.#update();\n    }\n\n    #update() {\n        /* ... */\n\n        this.#internals.ariaRequired = this.required;\n        this.#updateValidity();\n    }\n\n    /* ... */\n\n    #updateValidity() {\n        const state = {};\n        let message = '';\n\n        // custom validity message overrides all else\n        if (this.#customValidityMessage) {\n            state.customError = true;\n            message = this.#customValidityMessage;\n        } else {\n            if (this.required &amp;&amp; !this.value) {\n                state.valueMissing = true;\n                message = VALUE_MISSING_MESSAGE;\n            }\n    \n            // add other checks here if needed (e.g., pattern, minLength)\n        }\n\n        // safari needs a focusable validation anchor to show the validation message on form submit\n        // and it must be a descendant of the input\n        let anchor = undefined;\n        if (isSafari) {\n            anchor = this.querySelector('span[aria-hidden]');\n            if (!anchor) {\n                anchor = document.createElement('span');\n                anchor.ariaHidden = true;\n                anchor.tabIndex = 0;\n                this.append(anchor);\n            }\n        }\n\n        this.#internals.setValidity(state, message, anchor);\n    }\n\n    checkValidity() {\n        this.#updateValidity();\n        return this.#internals.checkValidity();\n    }\n\n    reportValidity() {\n        this.#updateValidity();\n        return this.#internals.reportValidity();\n    }\n\n    setCustomValidity(message) {\n        this.#customValidityMessage = message ?? '';\n        this.#updateValidity();\n    }\n\n    get validity() {\n        return this.#internals.validity;\n    }\n\n    get validationMessage() {\n        return this.#internals.validationMessage;\n    }\n\n    get willValidate() {\n        return this.#internals.willValidate;\n    }\n});\n\n/* ... */</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-05-09-form-control/demo6/index.html\">demo6</a></p>\n        <p>\n            The code for the example is exactly like it would be for built-in controls:\n        </p>\n        <div><pre><code>&lt;form&gt;\n    &lt;p&gt;\n        My favorite color is &lt;input-inline name=\"color1\" value=\"green\" required&gt;&lt;/input-inline&gt;.\n    &lt;/p&gt;\n    &lt;button type=\"submit\"&gt;Submit&lt;/button&gt;\n    &lt;button type=\"reset\"&gt;Reset&lt;/button&gt;\n&lt;/form&gt;</code></pre></div>\n\n        <p>\n            The <code>ElementInternals</code> interface is doing a lot of the work here, but we still have to proxy its methods and properties.\n            You can tell however that by this point we're deep in the weeds of custom elements, because of the rough edges.\n        </p>\n        <ul>\n            <li>The example is using the <code>input-inline:invalid</code> style instead of <code>:user-invalid</code> because\n            <a href=\"https://github.com/whatwg/html/issues/9639\">:user-invalid is not supported</a> on custom elements yet.</li>\n            <li>An ugly hack is needed to get the properly localized message for a required field that matches that of built-in controls.</li>\n            <li>Safari flat-out won't show validation messages on non-shadowed form-associated custom elements if we don't give it an anchor to set them to, requiring another ugly hack.</li>\n        </ul>\n\n        <h3>In conclusion</h3>\n\n        <p>\n            We've established by now that it is indeed feasible to build a custom form control and have it take part in regular HTML forms,\n            but also that it is a path surrounded by peril as well as laborious to travel.\n            Whether it is worth doing is in the eye of the beholder.\n        </p>\n        <p>\n            Along that path we also learned some lessons on how to handle input in custom elements, and have proven yet again that <code>contenteditable</code>,\n            while less painful than it once was, is an attribute that can only be used in anger.\n        </p>\n        <p>\n            Regardless, the full source code of the <code>input-inline</code> form control <a href=\"https://github.com/jsebrech/input-inline\">is on GitHub</a>.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[The attribute/property duality]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/</id>\n        <published>2025-04-21T12:00:00.000Z</published>\n        <updated>2025-04-21T12:00:00.000Z</updated>\n        <summary><![CDATA[How to work with attributes and properties in custom elements.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            Web components, a.k.a. custom elements, are HTML elements\n            that participate in HTML markup. As such they can have attributes:\n        </p>\n        <p><code>&lt;my-hello value=\"world\"&gt;&lt;/my-hello&gt;</code></p>\n        <p>\n            But, they are also JavaScript objects, and as such they can have object properties.\n        </p>\n        <p><code>let myHello = document.querySelector('my-hello'); myHello.value = 'foo';</code></p>\n        <p>\n            And here's the tricky part about that: <em>these are not the same thing!</em>\n            In fact, custom element attributes and properties by default have <em>zero</em> relationship between them,\n            even when they share a name. Here's a live proof of this fact:\n        </p>\n\n        <div><pre><code>customElements.define('my-hello', class extends HTMLElement {\n    connectedCallback() {\n        this.textContent = `Hello, ${ this.value || 'null' }!`;\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/demo1.html\">Demo: no connection between attribute and property</a></p>\n\n        <p>\n            Now, to be fair, we can get at the attribute value just fine from JavaScript:\n        </p>\n\n        <div><pre><code>customElements.define('my-hello', class extends HTMLElement {\n    connectedCallback() {\n        this.textContent = `Hello, ${ this.getAttribute('value') || 'null' }!`;\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/demo2.html\">Demo: displaying the attribute</a></p>\n\n        <p>\n            But what if we would also like it to have a <code>value</code> <em>property</em>?\n            What should the relationship between attribute and property be like?\n        </p>\n        <ul>\n            <li>Does updating the attribute always update the property?</li>\n            <li>Does updating the property always update the attribute?</li>\n            <li>When updates can go either way, does the property read and update the value of the attribute, or do both attribute and property wrap around a private field on the custom element's class?</li>\n            <li>When updates can go either way, how to avoid loops where the property updates the attribute, which updates the property, which...</li>\n            <li>When is it fine to have just an attribute without a property, or a property without an attribute?</li>\n        </ul>\n\n        <p>\n            In framework-based code, we typically don't get a say in these things.\n            Frameworks generally like to pretend that attributes and properties are the same thing,\n            and they automatically create code to make sure this is the case.\n            In vanilla custom elements however, not only do we get to decide these things, we <em>must</em> decide them.\n        </p>\n\n        <h3>Going native</h3>\n\n        <p>\n            Seasoned developers will intuitively grasp what the sensible relationship between attributes and properties should be.\n            This is because built-in HTML elements all implement similar kinds of relationships between their attributes and their properties.\n            To explore that in depth, I recommend reading <a href=\"https://blog.ltgt.net/web-component-properties/\">Making Web Component properties behave closer to the platform</a>.\n            Without fully restating that article, here's a quick recap:\n        </p>\n        <ul>\n            <li>Properties can exist independent of an attribute, but an attribute will typically have a related property.</li>\n            <li>If changing the attribute updates the property, then updating the property will update the attribute.</li>\n            <li>Properties <em>reflect</em> either an internal value of an element, or the value of the corresponding attribute.</li>\n            <li>Assigning a value of an invalid type will coerce the value to the right type, instead of rejecting the change.</li>\n            <li>Change events are only dispatched for changes by user input, not from programmatic changes to attribute or property.</li>\n        </ul>\n\n        <p>An easy way to get much of this behavior is to make a property wrap around an attribute:</p>\n\n        <div><pre><code>customElements.define('my-hello', class extends HTMLElement {\n    get value() {\n        return this.getAttribute('value');\n    }\n    set value(v) {\n        this.setAttribute('value', String(v));\n    }\n    \n    static observedAttributes = ['value'];\n    attributeChangedCallback() {\n        this.textContent = `Hello, ${ this.value || 'null' }!`;\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/demo3.html\">Demo: property wraps attribute</a></p>\n\n        <p>\n            Notice how updating the property will update the attribute in the HTML representation,\n            and how the property's assigned value is coerced into the attribute's string type.\n            Attributes are always strings.\n        </p>\n        \n        <h3>Into the weeds</h3>\n\n        <p>\n            Up to this point, things are looking straightforward. But this is web development,\n            things are never as straightforward as they seem.\n            For instance, what boolean attribute value should make a corresponding boolean property become true?\n            The surprising but <a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML\">standard behavior</a> on built-in elements is that \n            any attribute value will be interpreted as true, and only the absence of the attribute will be interpreted as false.\n        </p>\n        <p>\n            Time for another iteration of our element:\n        </p>\n\n        <div><pre><code>customElements.define('my-hello', class extends HTMLElement {\n    get value() {\n        return this.getAttribute('value');\n    }\n    set value(v) {\n        this.setAttribute('value', String(v));\n    }\n\n    get glam() {\n        return this.hasAttribute('glam');\n    }\n    set glam(v) {\n        if (v) {\n            this.setAttribute('glam', 'true');\n        } else {\n            this.removeAttribute('glam');\n        }\n    }\n    \n    static observedAttributes = ['value', 'glam'];\n    attributeChangedCallback() {\n        this.textContent = \n            `Hello, ${ this.value || 'null' }!` +\n            (this.glam ? '!!@#!' : '');\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/demo4.html\">Demo: adding a boolean property</a></p>\n\n        <p>\n            Which leaves us with the last bit of tricky trivia:\n            it's possible for the custom element's class to be instantiated and attached to the element\n            <em>after</em> the property is assigned. In that case the property's setter is never called,\n            and the attribute is not updated.\n        </p>\n        \n        <div><pre><code>// html:\n&lt;my-hello value=\"world\"&gt;&lt;/my-hello&gt;\n// js:\nconst myHello = document.querySelector('my-hello');\nmyHello.value = 42; // setter not called before define\ncustomElements.define('my-hello', /* ... */);\nconsole.log(myHello.getAttribute('value')); // -&gt; \"world\"\n</code></pre></div>\n\n        <p>\n            This can be avoided by reassigning any previously set properties when the element is connected:\n        </p>\n\n        <div><pre><code>customElements.define('my-hello', class extends HTMLElement {\n    get value() {\n        return this.getAttribute('value');\n    }\n    set value(v) {\n        this.setAttribute('value', String(v));\n    }\n\n    get glam() {\n        return this.hasAttribute('glam');\n    }\n    set glam(v) {\n        if (v) {\n            this.setAttribute('glam', 'true');\n        } else {\n            this.removeAttribute('glam');\n        }\n    }\n    \n    static observedAttributes = ['value', 'glam'];\n    attributeChangedCallback() {\n        this.textContent = \n            `Hello, ${ this.value || 'null' }!` +\n            (this.glam ? '!!@#!' : '');\n    }\n\n    connectedCallback() {\n        this.#upgradeProperty('value');\n        this.#upgradeProperty('glam');\n    }\n\n    #upgradeProperty(prop) {\n        if (this.hasOwnProperty(prop)) {\n            let value = this[prop];\n            delete this[prop];\n            this[prop] = value;\n        }\n    }\n});\n</code></pre></div>\n\n        <h3>In conclusion</h3>\n\n        <p>\n            If that seems like a lot of work to do a very simple thing, that is because it is.\n            The good news is: we don't have to always do this work.\n        </p>\n        <p>\n            When we're using web components as framework components in a codebase that we control,\n            we don't have to follow any of these unwritten rules and can keep the web component code as simple as we like.\n            However, when using web components as custom elements to be used in HTML markup \n            then we do well to follow these best practices to avoid surprises, \n            especially when making web components that may be used by others. YMMV.\n        </p>\n        <p>\n            In <a href=\"../2025-05-09-form-control/\">the next article</a>, I'll be looking into custom elements that accept input, and how that adds twists to the plot.\n        </p>\n\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[New year's resolve]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2025-01-01-new-years-resolve/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2025-01-01-new-years-resolve/</id>\n        <published>2025-01-01T12:00:00.000Z</published>\n        <updated>2025-01-01T12:00:00.000Z</updated>\n        <summary><![CDATA[import.meta.resolve and other ways to avoid bundling]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2025-01-01-new-years-resolve/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            Today I was looking at what I want to write about in the coming year,\n            and while checking out custom element micro-frameworks came across <code>import.meta.resolve</code>\n            in the documentation for the <a href=\"https://github.com/jhuddle/ponys\">Ponys</a> micro-framework. \n            That one simple trick is part of the essential toolbox that allows skipping build-time bundling,\n            unlocking the vanilla web development achievement in the browser.\n        </p>\n        <p>\n            We need this toolbox because the build-time bundler does a lot of work for us:\n        </p>\n        <ul>\n            <li><em>Combining JS and CSS files</em> to avoid slow page loads.</li>\n            <li><em>Resolving paths to the JS and CSS dependencies</em> so we can have clean import statements.</li>\n            <li><em>Optimizing the bundled code</em>, by stripping out whitespace, and removing unused imports thanks to a tree shaking algorithm.</li>\n        </ul>\n        <p>\n            It is not immediately apparent how to get these benefits without using a bundler.\n        </p>\n\n        <h3>Combining JS and CSS files</h3>\n        <p>\n            A typical framework-based web project contains hundreds or thousands of files.\n            Having all those files loaded separately on a page load would be intolerably slow,\n            hence the need for a bundler to reduce the file count. Even by stripping away third party dependencies\n            we can still end up with dozens or hundreds of files constituting a vanilla web project.\n        </p>\n        <p>\n            When inspecting a page load in the browser's developer tools, we would then expect to see a lot of this:\n        </p>\n        <img src=\"http1.png\" alt=\"a waterfall of network requests in browser devtools over http1\" loading=\"lazy\">\n        <p>\n            The browser would download 6 files at a time and the later requests would block until those files downloaded.\n            This limitation of HTTP/1 let to not just the solution of bundlers to reduce file count, but because the limitation of 6 parallel downloads\n            was per domain it also led to the popularity of CDN networks which allowed <em>cheating</em> and downloading 12 files at once instead of 6.\n        </p> \n        <p>\n            However. It's 2025. What you're likely to see in this modern era is more like this:\n        </p>\n        <img src=\"http2.png\" alt=\"parallel network requests in browser devtools over http2\" loading=\"lazy\">\n        <p>\n            Because almost all web servers have shifted over to HTTP/2, which no longer has this limitation of only having 6 files in flight at a time,\n            we now see that all the files that are requested in parallel get downloaded in parallel.\n            There's still a small caveat on lossy connections called head-of-line-blocking, <a href=\"https://http3-explained.haxx.se/en/why-quic/why-tcphol\">fixed in HTTP/3</a>,\n            which is presently starting to roll out to web servers across the internet.\n        </p>\n        <p>\n            But the long and short of it is this: requesting a lot of files all at once just isn't that big of a problem anymore.\n            We don't need to bundle up the files in a vanilla web project until the file counts get ridiculous.\n        </p>\n\n        <h3>Resolving paths</h3>\n\n        <p>\n            Another thing that bundlers do is resolving relative paths pointing to imported JS and CSS files.\n            See, for example, the elegance of CSS modules for importing styles into a react component from a relative path:\n        </p>\n        <div><p><em>layout.tsx (React):</em></p><pre><code>import styles from './styles.module.css'\n \nexport default function Layout({\n  children,\n}: {\n  children: React.ReactNode\n}) {\n  return &lt;section className={styles.dashboard}&gt;{children}&lt;/section&gt;\n}</code></pre></div>\n        <p>\n            However. It's 2025. And our browsers now have a modern vanilla toolbox for importing.\n            When we bootstrap our JS with the magic incantation <code>&lt;script src=\"index.js\" type=\"module\"&gt;&lt;/script&gt;</code>\n            we unlock the magic ability to import JS files using <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_features_into_your_script\">ES module</a> import notation:\n        </p>\n        <div><p><em>index.js:</em></p><pre><code>import { registerAvatarComponent } from './components/avatar.js';\nconst app = () =&gt; {\n    registerAvatarComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n</code></pre></div>\n        <p>\n            Inside of such files we also get access to <code>import.meta.url</code>, the URL of the current JS file,\n            and <code>import.meta.resolve()</code>, a function that resolves a path relative to the current file,\n            even a path to a CSS file:\n        </p>\n        <div><pre><code>class Layout extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n        this.shadowRoot.innerHTML = `\n            &lt;link rel=\"stylesheet\" href=\"${import.meta.resolve('styles.css')}\"&gt;\n            &lt;section class=\"dashboard\"&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/section&gt;\n        `;\n    }\n}\n\nexport const registerLayoutComponent = \n    () =&gt; customElements.define('x-layout', Layout);\n</code></pre></div>\n        <p>\n            While not quite the same as what the bundler does, it still enables accessing any file by its relative path,\n            and that in turn allows <a href=\"https://medium.com/@devwares/best-folder-structure-for-modern-web-application-3894e1238bd\">organizing projects in whatever way we want</a>, for example in a feature-based folder organization.\n            All without needing a build step.\n        </p>\n        <p>\n            This ability to do relative imports can be super-charged by <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap\">import maps</a>,\n            which decouple the name of what is imported from the path of the file it is imported from,\n            again all without involving a build step.\n        </p>\n\n        <h3>Optimizing bundled code</h3>\n\n        <p>\n            Another thing bundlers can do is optimizing the bundled code, by splitting the payload into things loaded initially,\n            and things loaded later on lazily. And also by minifying it, stripping away unnecessary whitespace and comments so it will load faster.\n        </p>\n        <p>\n            However. It's 2025. We can transparently enable gzip or brotli compression on the server,\n            and as it turns out that gets <a href=\"https://css-tricks.com/the-difference-between-minification-and-gzipping/\">almost all the benefit of minifying</a>. \n            While minifying is nice, gzipping is what we really want, and we can get that without a build step.\n        </p>\n        <p>\n            And lazy loading, that works fine using <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import\">dynamic import</a>, and with a bit due diligence we can put some of the code behind such an import statement.\n            I wrote before how React's <a href=\"../2024-09-09-sweet-suspense/\">lazy and suspense can be ported</a> easily to vanilla web components.\n        </p>\n\n        <h3>Happy new year!</h3>\n\n        <p>\n            Great news! It's 2025, and the browser landscape is looking better than ever. It gives us enough tools that for many web projects\n            we can drop the bundler and do just fine. You wouldn't believe it based on what the mainstream frameworks are doing though.\n            Maybe 2025 is the year we finally see a wide recognition of just how powerful the browser platform has gotten,\n            and a return to old school simplicity in web development practice, away from all those complicated build steps. \n            It's my new year's resolve to do my part in spreading the word.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Caching vanilla sites]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-12-16-caching-vanilla-sites/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-12-16-caching-vanilla-sites/</id>\n        <published>2024-12-16T12:00:00.000Z</published>\n        <updated>2024-12-16T12:00:00.000Z</updated>\n        <summary><![CDATA[Strategies for cache invalidation on vanilla web sites.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-12-16-caching-vanilla-sites/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            If you go to a typical website built with a framework, you'll see a lot of this:\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-12-16-caching-vanilla-sites/vercel.webp\" width=\"865\" alt=\"browser devtools showing network requests for vercel.com\" loading=\"lazy\">\n        <p>\n            Those long cryptic filenames are not meant to discourage casual snooping.\n            They're meant to ensure the filename is changed every time a single byte in that file changes,\n            because the site is using <em>far-future expire headers</em>, \n            a technique where the browser is told to cache files indefinitely, until the end of time.\n            On successive page loads those resources will then always be served from cache.\n            The only drawback is having to change the filename each time the file's contents change, \n            but a framework's build steps typically take care of that.\n        </p>\n        <p>\n            For vanilla web sites, this strategy doesn't work. By abandoning a build step there is no way to automatically generate filenames,\n            and unless nothing makes you happier than renaming all files manually every time you deploy a new version,\n            we have to look towards other strategies.\n        </p>\n\n        <h3>How caching works</h3>\n\n        <p>\n            Browser cache behavior is complicated, and a deep dive into the topic deserves <a href=\"https://web.dev/articles/http-cache\">its own article</a>.\n            However, very simply put, what you'll see is mostly these response headers:\n        </p>\n        <dl>\n            <dt>Cache-Control</dt>\n            <dd>\n                <p>\n                    The cache control response header determines whether the browser should cache the response, and how long it should serve the response from cache.\n                </p>\n                <p><code>Cache-Control: public, max-age: 604800</code></p>\n                <p>\n                    This will cache the resource and only check if there's a new version after one week.\n                </p>\n            </dd>\n            <dt>Age</dt>\n            <dd>\n                <p>\n                    The <code>max-age</code> directive does not measure age from the time that the response is received,\n                    but from the time that the response was originally served:\n                </p>\n                <p><code>Age: 10</code></p>\n                <p>\n                    This response header indicates the response was served on the origin server 10 seconds ago.\n                </p>\n            </dd>\n            <dt>Etag</dt>\n            <dd>\n                <p>\n                    The <code>Etag</code> header is a unique hash of the resource's contents, an identifier for that version of the resource.\n                </p>\n                <p><code>ETag: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"</code></p>\n                <p>\n                    When the browser requests that resource again from the server, knowing the Etag it can pass an <code>If-None-Match</code>\n                    header with the Etag's value. If the resource has not changed it will still have the same Etag value,\n                    and the server will respond with <code>304 Not Modified</code>. \n                </p>\n                <p><code>If-None-Match: \"33a64df551425fcc55e4d42a148795d9f25f89d4\"</code></p>\n            </dd>\n            <dt>Last-Modified</dt>\n            <dd>\n                <p>\n                    The <code>Last-Modified</code> header works similarly to Etag, except instead of sending a hash of the contents,\n                    it sends a timestamp of when the resource was last changed. \n                    Like Etag's <code>If-None-Match</code> it is matched by the <code>If-Modified-Since</code> header when requesting the resource from the server again.\n                </p>\n            </dd>\n        </dl>\n\n        <p>\n            With that basic review of caching headers, let's look at some strategies for making good use of them in vanilla web projects.\n        </p>\n\n        <h3>Keeping it simple: GitHub Pages</h3>\n\n        <p>\n            The simplest strategy is what GitHub Pages does: cache files for 10 minutes.\n            Every file that's downloaded has <code>Cache-Control: max-age</code> headers that make it expire 10 minutes into the future.\n            After that if the file is loaded again it will be requested from the network.\n            The browser will add <code>If-None-Match</code> or <code>If-Modified-Since</code> headers\n            to allow the server to avoid sending the file if it hasn't been changed, saving bytes but not a roundtrip.\n        </p>\n        <p>\n            If you want to see it in action, just open the browser devtools and reload this page.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-12-16-caching-vanilla-sites/plainvanilla.webp\" width=\"660\" loading=\"lazy\" alt=\"browser devtools showing network requests for plainvanillaweb.com\">  \n        <p>\n            Visitors never get a page that is more than 10 minutes out of date,\n            and as they navigate around the site they mostly get fast cache-served responses.\n            However, on repeat visits they will get a slow first-load experience.\n            Also, if the server updates in the middle of a page load then different resources may end up mismatched and belong to a different version of the site, causing unpredictable bugs.\n            Well, for 10 minutes at least.\n        </p>\n\n        <h3>Extending cache durations</h3>\n        <p>\n            While the 10 minute cache policy is ok for HTML content and small JS and CSS files,\n            it can be improved by increasing cache times on large resources like libraries and images.\n            By using a caching proxy that allows setting rules on specific types or folders of files we can increase the cache duration.\n            For sites <a href=\"https://blog.cloudflare.com/secure-and-fast-github-pages-with-cloudflare/\">proxied through Cloudflare</a>, \n            their <a href=\"https://developers.cloudflare.com/cache/concepts/customize-cache/\">cache customization settings</a> \n            can be used to set these resource-specific policies.\n        </p>\n        <p>\n            By setting longer cache durations on some resources, we can ensure they're served from local cache more often.\n            However, what to do if the resource changes? In those cases we need to modify the fetched URL of the resource every place that it is referred to.\n            For example, by appending a unique query parameter:\n        </p>\n        <p>\n            <code>&lt;img src=\"image.jpg?v=2\" alt=\"My cached image\" /&gt;</code>\n        </p>\n        <p>\n            The awkward aspect of having to change the referred URL in every place that a changed file is used\n            makes extending cache durations inconvenient for files that are changed often or are referred in many places.\n        </p>\n        <p>\n            Also, applying such policies to JavaScript or CSS becomes a minefield,\n            because a mismatched combination of JS or CSS files could end up in the browser cache indefinitely,\n            breaking the website for the user until URL's are changed or their browser cache is cleared.\n            For that reason, I don't think it's prudent to do this for anything but files that never change or that have some kind of version marker in their URL.\n        </p>\n\n        <h3>Complete control with service workers</h3>\n\n        <p>\n            A static web site can take complete control over its cache behavior by <a href=\"https://web.dev/learn/pwa/service-workers\">using a service worker</a>.\n            The service worker intercepts every network request and then decides whether to serve it from a local cache or from the network.\n            For example, here's a service worker that will cache all resources indefinitely, until its version is changed:\n        </p>\n        <div><pre><code>let cacheName = 'cache-worker-v1';\n// these are automatically cached when the site is first loaded\nlet initialAssets = [\n    './',\n    'index.html',\n    'index.js',\n    'index.css',\n    'manifest.json',\n    'android-chrome-512x512.png',\n    'favicon.ico',\n    'apple-touch-icon.png',\n    'styles/reset.css',\n    // the rest will be auto-discovered\n];\n\n// initial bundle (on first load)\nself.addEventListener('install', (event) =&gt; {\n    event.waitUntil(\n        caches.open(cacheName).then((cache) =&gt; {\n            return cache.addAll(initialAssets);\n        })\n    );\n});\n\n// clear out stale caches after service worker update\nself.addEventListener('activate', (event) =&gt; {\n    event.waitUntil(\n        caches.keys().then((cacheNames) =&gt; {\n            return Promise.all(\n                cacheNames.map((cacheName) =&gt; {\n                    if (cacheName !== self.cacheName) {\n                        return caches.delete(cacheName);\n                    }\n                })\n            );\n        })\n    );\n});\n\n// default to fetching from cache, fallback to network\nself.addEventListener('fetch', (event) =&gt; {\n    const url = new URL(event.request.url);\n\n    // other origins bypass the cache\n    if (url.origin !== location.origin) {\n        networkOnly(event);\n    // default to fetching from cache, and updating asynchronously\n    } else {\n        staleWhileRevalidate(event);\n    }\n});\n\nconst networkOnly = (event) =&gt; {\n    event.respondWith(fetch(event.request));\n}\n\n// fetch events are serviced from cache if possible, but also updated behind the scenes\nconst staleWhileRevalidate = (event) =&gt; {\n    event.respondWith(\n        caches.match(event.request).then(cachedResponse =&gt; {\n            const networkUpdate = \n                fetch(event.request).then(networkResponse =&gt; {\n                    caches.open(cacheName).then(\n                        cache =&gt; cache.put(event.request, networkResponse));\n                    return networkResponse.clone();\n                }).catch(_ =&gt; /*ignore because we're probably offline*/_);\n            return cachedResponse || networkUpdate;\n        })\n    );\n}</code></pre></div>\n        <p>\n            This recreates the <em>far-future expiration</em> strategy but does it client-side, inside the service worker.\n            Because only the version at the top of the <code>sw.js</code> file needs to be updated when the site's contents change,\n            this becomes practical to do without adding a build step. However, because the service worker intercepts network requests\n            to change their behavior there is a risk that bugs could lead to a broken site, so this strategy is only for the careful and well-versed.\n            (And no, the above service worker code hasn't been baked in production, so be careful when copying it to your own site.)\n        </p>\n        \n        <h3>Wrapping up</h3>\n        <p>\n            Setting sane cache policies meant to optimize page load performance is one of the things typically in the domain\n            of full-fat frameworks or application servers. But, abandoning build steps and server-side logic does not necessarily \n            have to mean having poor caching performance. There are multiple strategies with varying amounts of cache control,\n            and there is probably a suitable strategy for any plain vanilla site.\n        </p>\n        <p>\n            Last but not least, an even better way to speed up page loading is to keep the web page itself light.\n            Using a plain vanilla approach to pages with zero dependencies baked into the page weight\n            already puts you in pole position for good page load performance, before caching even enters the picture.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Editing Plain Vanilla]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/</id>\n        <published>2024-10-20T12:00:00.000Z</published>\n        <updated>2024-10-20T12:00:00.000Z</updated>\n        <summary><![CDATA[How to set up VS Code for a vanilla web project.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            I'm typing this up in Visual Studio Code, after realizing I should probably explain how I use it to make this site.\n            But the whole idea behind Plain Vanilla is no build, no framework, no tools.\n            And VS Code is definitely a tool. So what gives?\n        </p>\n        <p>\n            There's a difference between tools that sit in between the code and a deployed site, and tools that only act in support of editing or deploying.\n            The first category, like npm or typescript, impose continued maintenance on the project because they form a direct dependency.\n            The second category, like VS Code or git, are easily replaced without impacting the project's ability to be edited.\n            There's a tension between the ability to get things done faster, and the burden created by additional dependencies.\n            For this project I draw the line in accepting the second category while rejecting the first.\n        </p>\n        <h3>Setting up a profile</h3>\n        <p>\n            I use VS Code for framework-based work projects as well as vanilla web development.\n            To keep those two realms neatly separated I've <a href=\"https://code.visualstudio.com/docs/editor/profiles\">set up a separate Vanilla profile</a>. \n            In that profile is a much leaner suite of extensions, configured for only vanilla web development.\n        </p>\n        <ul>\n            <li><strong>ESLint</strong>, to automatically lint the JS code while editing</li>\n            <li><strong>webhint</strong>, to lint the HTML and CSS code, and detect accessibility issues</li>\n            <li><strong>html-in-template-string</strong>, to syntax highlight HTML template strings</li>\n            <li><strong>Todo Tree</strong>, to keep track of TODO's while doing larger changes</li>\n            <li><strong>Live Preview</strong>, to get a live preview of the page that I'm working on</li>\n            <li><strong>VS Code Counter</strong>, for quick comparative line counts when porting framework code to vanilla</li>\n            <li><strong>Intellicode</strong>, for simple code completion</li>\n            <li><strong>Codeium</strong>, for AI-assisted code completion, works great for web component boilerplate</li>\n        </ul>\n        <p>\n            Modern web development can be very overburdened by tools, sometimes all but requiring the latest Macbook Pro with decadent amounts of RAM\n            just to edit a basic project. The combination of a no build plain vanilla codebase with a lean VS Code profile guarantees quick editing,\n            even on my oldest and slowest laptops.\n        </p>\n        <h3>Linting</h3>\n        <p>\n            Nobody's perfect, myself included, so something needs to be scanning the code for goofs.\n            The first linting tool that's set up is ESLint. The VS Code extension regrettably does not come bundled with an eslint installation,\n            so this has to be installed explicitly. By doing it once globally this can be reused across vanilla web projects.\n        </p>\n        <p><code>npm install -g eslint @eslint/js globals</code></p>\n        <p>\n            Because I use nvm to manage node versions the global eslint install was not automatically detectable.\n            This required setting a NODE_PATH in <code>.zshrc</code> that VS Code then picked up.\n        </p>\n        <p><code>export NODE_PATH=$(npm root -g)</code></p>\n        <p>\n            In addition, in order to lint successfully it needs a configuration file, located in the project's root.\n        </p>\n        <div><p><em>/eslint.config.cjs:</em></p><pre><code>/* eslint-disable no-undef */\nconst globals = require(\"globals\");\nconst js = require(\"@eslint/js\");\n\nmodule.exports = [\n    js.configs.recommended, \n    {\n        languageOptions: {\n            globals: {\n                ...globals.browser,\n                ...globals.mocha\n            },\n            ecmaVersion: 2022,\n            sourceType: \"module\",\n        }\n    },\n    {\n        ignores: [\n            \"public/blog/articles/\",\n            \"**/lib/\",\n            \"**/react/\",\n        ]\n    }\n];</code></pre></div>\n        <p>\n            Setting the <code>ecmaVersion</code> to 2022 ensures that I don't accidentally use newer and unsupported Javascript features,\n            like in this example trying to use ES2024's <a href=\"https://2ality.com/2024/06/ecmascript-2024.html#regular-expression-flag-%2Fv\">v flag</a> in regular expressions.\n            This version could be set to whatever browser compatibility a project requires.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/eslinterror.png\" alt=\"ESLint error for ECMAScript 2024 feature\" loading=\"lazy\" width=\"561\">\n        <p>\n            The <code>ignores</code> blocks excludes external libraries to placate my OCD that wants to see zero errors or warnings reported by eslint project-wide.\n            The article folders are excluded for a similar reason, because they contain a lot of incomplete and deliberately invalid example JS files.\n        </p>\n        <p>\n            The webhint extension is installed to do automatic linting on HTML and CSS.\n            Luckily it out of the box comes bundled with a webhint installation and applies the default <code>development</code> ruleset.\n            A nice thing about this extension is that it reports accessibility issues.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/webhinterror.png\" alt=\"Webhint error for accessibility\" loading=\"lazy\" width=\"842\">\n        <p>\n            Only a few tweaks were made to the webhint configuration to again get to that all-important zero warnings count.\n        </p>\n        <div><p><em>/.hintrc:</em></p><pre><code>{\n  \"extends\": [\n    \"development\"\n  ],\n  \"hints\": {\n    \"compat-api/html\": [\n      \"default\",\n      {\n        \"ignore\": [\n          \"iframe[loading]\"\n        ]\n      }\n    ],\n    \"no-inline-styles\": \"off\"\n  }\n}</code></pre></div>\n\n        <h3>html-in-template-string</h3>\n        <p>\n            I've mentioned it before in the <a href=\"../2024-08-25-vanilla-entity-encoding/\">entity encoding article</a>,\n            but this neat little extension formats HTML inside tagged template strings in web component JS code.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/syntax-highlighting.webp\" loading=\"lazy\" alt=\"Syntax highlighting in template strings\" width=\"849\">\n\n        <h3>Live Preview</h3>\n        <p>\n            The center piece for a smooth editing workflow is the Live Preview extension.\n            I can right-click on any HTML file in the project and select \"Show Preview\" to get a live preview of the page.\n            This preview automatically refreshes when files are saved. Because vanilla web pages always load instantly\n            this provides the hot-reloading workflow from framework projects, except even faster and with zero setup.\n            The only gotcha is that all paths in the site have to be relative paths so the previewed page can resolve them.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/live-preview.webp\" alt=\"Live Preview of this article while editing\" loading=\"lazy\">\n        <p>\n            The preview's URL can be pasted into a \"real browser\" to debug tricky javascript issues\n            and do compatibility testing. Very occasionally I'll need to spin up a \"real server\", \n            but most of the code in my vanilla projects is written with only a Live Preview tab open.\n        </p>\n        <p>\n            Previewing is also how I get a realtime view of unit tests while working on components or infrastructure code,\n            by opening the tests web page and selecting the right test suite to hot reload while editing.\n        </p>\n\n        <h3>Bonus: working offline</h3>\n        <p>\n            Because I live at the beach and work in the big city I regularly need to take long train rides with spotty internet connection.\n            Like many developers I cannot keep web API's in my head and have to look them up regularly while coding.\n            To have a complete offline vanilla web development setup with me at all times I use <a href=\"\">devdocs.io</a>.\n            All my projects folders are set up to sync automatically with <a href=\"https://syncthing.net/\">Syncthing</a>, \n            so whatever I was doing on the desktop can usually be smoothly continued offline on the laptop \n            without having to do any prep work to make that possible.\n        </p>\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/devdocs.webp\" alt=\"devdocs.io screenshot\" loading=\"lazy\">\n\n        <p>\n            There, that's my lean vanilla web development setup.\n            What should I add to this, or do differently? Feel free to let me know.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Needs more context]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-10-07-needs-more-context/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-10-07-needs-more-context/</id>\n        <published>2024-10-07T12:00:00.000Z</published>\n        <updated>2024-10-07T12:00:00.000Z</updated>\n        <summary><![CDATA[A better way to do context for web components.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-10-07-needs-more-context/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            In the earlier article <a href=\"../2024-09-28-unreasonable-effectiveness-of-vanilla-js/\">the unreasonable effectiveness of vanilla JS</a>\n            I explained a vanilla web version of the React tutorial example <em>Scaling up with Reducer and Context</em>.\n            That example used a technique for <em>context</em> based on <code>Element.closest()</code>.\n            While that way of obtaining a context is very simple, which definitely has its merits,\n            it also has some downsides:\n        </p>\n        <ul>\n            <li>It cannot be used from inside a shadow DOM to find a context that lives outside of it without <a href=\"https://stackoverflow.com/q/54520554/20980\">clumsy workarounds</a>.</li>\n            <li>It requires a custom element to be the context.</li>\n            <li>There has to be separate mechanism to subscribe to context updates.</li>\n        </ul>\n        <p>\n            There is in fact, or so I learned recently, a better and more standard way to solve this\n            known as the <a href=\"https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md\">context protocol</a>. \n            It's not a browser feature, but a protocol for how to implement a context in web components.\n        </p>\n        <p>\n            This is how it works: the consumer starts by dispatching a <code>context-request</code> event.\n        </p>\n        <div><pre><code>class ContextRequestEvent extends Event {\n    constructor(context, callback, subscribe) {\n        super('context-request', {\n            bubbles: true,\n            composed: true,\n        });\n        this.context = context;\n        this.callback = callback;\n        this.subscribe = subscribe;\n    }\n}\n\ncustomElements.define('my-component', class extends HTMLElement {\n    connectedCallback() {\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', (theme) =&gt; {\n                // ...\n            })\n        );\n    }\n});\n</code></pre></div>\n        <p>\n            The event will travel up the DOM tree (bubbles = true), piercing any shadow DOM boundaries (composed = true),\n            until it reaches a listener that responds to it. This listener is attached to the DOM by a context provider.\n            The context provider uses the <code>e.context</code> property to detect whether it should respond,\n            then calls <code>e.callback</code> with the appropriate context value.\n            Finally it calls <code>e.stopPropagation()</code> so the event will stop bubbling up the DOM tree.\n        </p>\n        <p>\n            This whole song and dance is guaranteed to happen synchronously, which enables this elegant pattern:\n        </p>\n        <div><pre><code>customElements.define('my-component', class extends HTMLElement {\n    connectedCallback() {\n        let theme = 'light'; // default value\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', t =&gt; theme = t)\n        );\n        // do something with theme\n    }\n});\n</code></pre></div>\n        <p>\n            If no provider is registered the event's callback is never called and the default value will be used instead.\n        </p>\n        <p>\n            Instead of doing a one-off request for a context's value it's also possible to subscribe to updates\n            by setting its subscribe property to true.\n            Every time the context's value changes the callback will be called again.\n            To ensure proper cleanup the subscribing element has to unsubscribe on disconnect.\n        </p>\n        <div><pre><code>customElements.define('my-component', class extends HTMLElement {\n    #unsubscribe;\n    connectedCallback() {\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', (theme, unsubscribe) =&gt; {\n                this.#unsubscribe = unsubscribe;\n                // do something with theme\n            }, true)\n        );\n    }\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n});\n</code></pre></div>\n        <p>\n            It is recommended, but not required, to listen for and call unsubscribe functions in one-off requests,\n            just in case a provider is overzealously creating subscriptions.\n            However, this is not necessary when using only spec-compliant providers.\n        </p>\n        <div><pre><code>customElements.define('my-component', class extends HTMLElement {\n    connectedCallback() {\n        let theme = 'light';\n        this.dispatchEvent(\n            new ContextRequestEvent('theme', (t, unsubscribe) =&gt; {\n                theme = t;\n                unsubscribe?.();\n            })\n        );\n        // do something with theme\n    }\n});\n</code></pre></div>\n        <p>\n            Providers are somewhat more involved to implement.\n            There are several spec-compliant libraries that implement them,\n            like <a href=\"https://lit.dev/docs/data/context/\">@lit/context</a> \n            and <a href=\"https://blikblum.github.io/wc-context/\">wc-context</a>.\n            A very minimal implementation is this one:\n        </p>\n        <div><pre><code>export class ContextProvider extends EventTarget {\n    #value;\n    get value() { return this.#value }\n    set value(v) { this.#value = v; this.dispatchEvent(new Event('change')); }\n\n    #context;\n    get context() { return this.#context }\n\n    constructor(target, context, initialValue = undefined) {\n        super();\n        this.#context = context;\n        this.#value = initialValue;\n        this.handle = this.handle.bind(this);\n        if (target) this.attach(target);\n    }\n    \n    attach(target) {\n        target.addEventListener('context-request', this.handle);\n    }\n\n    detach(target) {\n        target.removeEventListener('context-request', this.handle);\n    }\n\n    /**\n     * Handle a context-request event\n     * @param {ContextRequestEvent} e \n     */\n    handle(e) {\n        if (e.context === this.context) {\n            if (e.subscribe) {\n                const unsubscribe = () =&gt; this.removeEventListener('change', update);\n                const update = () =&gt; e.callback(this.value, unsubscribe);\n                this.addEventListener('change', update);\n                update();\n            } else {\n                e.callback(this.value);\n            }\n            e.stopPropagation();\n        }\n    }\n}\n</code></pre></div>\n        <p>\n            This minimal provider can then be used in a custom element like this:\n        </p>\n        <div><pre><code>customElements.define('theme-context', class extends HTMLElement {\n    themeProvider = new ContextProvider(this, 'theme', 'light');\n    toggleProvider = new ContextProvider(this, 'theme-toggle', () =&gt; {\n        this.themeProvider.value = this.themeProvider.value === 'light' ? 'dark' : 'light';\n    });\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n});\n</code></pre></div>\n        <p>\n            Which would be used on a page like this, with <code>&lt;my-subscriber&gt;</code> requesting \n            the theme by dispatching a <code>context-request</code> event.\n        </p>\n        <div><pre><code>&lt;theme-context&gt;\n    &lt;div&gt;\n        &lt;my-subscriber&gt;&lt;/my-subscriber&gt;\n    &lt;/div&gt;\n&lt;/theme-context&gt;\n</code></pre></div>\n        <p>\n            Notice in the above example that the <code>theme-toggle</code> context is providing a function.\n            This unlocks a capability for dependency injection where API's to control page behavior\n            are provided by a context to any subscribing custom element.\n        </p>\n        <p>\n            Don't let this example mislead you however. A provider doesn't actually need a dedicated custom element,\n            and can be attached to any DOM node, even the body element itself.\n            This means a context can be provided or consumed from anywhere on the page.\n        </p>\n        <div><pre><code>// loaded with &lt;script type=\"module\" src=\"theme-provider.js\"&gt;&lt;/script&gt;\n\nimport { ContextProvider } from \"./context-provider.js\";\n\nconst themeProvider = new ContextProvider(document.body, 'theme', 'light');\nconst toggleProvider = new ContextProvider(document.body, 'theme-toggle', () =&gt; {\n    themeProvider.value = themeProvider.value === 'light' ? 'dark' : 'light';\n});\n</code></pre></div>\n        <p>\n            And because there can be more than one event listener on a page,\n            there can be more than one provider providing the same context.\n            The first one to handle the event will win.\n        </p>\n        <p>\n            Here's an example that illustrates a combination of a global provider attached to the body (top panel),\n            and a local provider using a <code>&lt;theme-context&gt;</code> (bottom panel).\n            Every time the <code>&lt;theme-toggle&gt;</code> is reparented it resubscribes to the theme from the nearest provider.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-10-07-needs-more-context/combined/index.html\">combined example</a></p>\n        <div><p><em>index.js:</em></p><pre><code>import { ContextRequestEvent } from \"./context-request.js\";\nimport \"./theme-provider.js\"; // global provider on body\nimport \"./theme-context.js\"; // element with local provider\n\ncustomElements.define('theme-demo', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            &lt;theme-panel id=\"first\"&gt;\n                &lt;theme-toggle&gt;&lt;/theme-toggle&gt;\n            &lt;/theme-panel&gt;\n            &lt;theme-context&gt;\n                &lt;theme-panel id=\"second\"&gt;\n                &lt;/theme-panel&gt;\n            &lt;/theme-context&gt;\n            &lt;button&gt;Reparent toggle&lt;/button&gt;\n        `;\n        this.querySelector('button').onclick = reparent;\n    }\n});\n\ncustomElements.define('theme-panel', class extends HTMLElement {\n    #unsubscribe;\n\n    connectedCallback() {\n        this.dispatchEvent(new ContextRequestEvent('theme', (theme, unsubscribe) =&gt; {\n            this.className = 'panel-' + theme;\n            this.#unsubscribe = unsubscribe;\n        }, true));\n    }\n\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n});\n\ncustomElements.define('theme-toggle', class extends HTMLElement {\n    #unsubscribe;\n\n    connectedCallback() {\n        this.innerHTML = '&lt;button&gt;Toggle&lt;/button&gt;';\n        this.dispatchEvent(new ContextRequestEvent('theme-toggle', (toggle) =&gt; {\n            this.querySelector('button').onclick = toggle;\n        }));\n        this.dispatchEvent(new ContextRequestEvent('theme', (theme, unsubscribe) =&gt; {\n            this.querySelector('button').className = 'button-' + theme;\n            this.#unsubscribe = unsubscribe;\n        }, true));\n    }\n\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n});\n\nfunction reparent() {\n    const toggle = document.querySelector('theme-toggle');\n    const first = document.querySelector('theme-panel#first');\n    const second = document.querySelector('theme-panel#second');\n    if (toggle.parentNode === second) {\n        first.append(toggle);\n    } else {\n        second.append(toggle);\n    }\n}</code></pre></div>\n\n        <p>\n            The full implementation of this protocol can be found in the <a href=\"https://github.com/jsebrech/tiny-context\">tiny-context repo</a> on Github.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Lived experience]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-09-30-lived-experience/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-09-30-lived-experience/</id>\n        <published>2024-09-30T12:00:00.000Z</published>\n        <updated>2024-09-30T12:00:00.000Z</updated>\n        <summary><![CDATA[Thoughts on the past and future of frameworks, web components and web development.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-09-30-lived-experience/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            Ryan Carniato shared a hot take a few days ago, <a href=\"https://dev.to/ryansolid/web-components-are-not-the-future-48bh\">Web Components Are Not the Future</a>.\n            As hot takes tend to do, it got some responses, like Nolan Lawson's piece <a href=\"https://nolanlawson.com/2024/09/28/web-components-are-okay/\">Web components are okay</a>,\n            or Cory LaViska's <a href=\"https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/\">Web Components Are Not the Future — They're the Present</a>.\n            They do an excellent job of directly engaging Ryan's arguments, so I'm not going to do that here.\n            Instead I want to talk about my lived experience of web development, and where I hope it is headed in the future.\n            Take it in the spirit it is intended, one of optimism and possibility.\n        </p>\n\n        <h3>A galaxy far, far away</h3>\n        <p>\n            So I've been making web sites since a long time ago, since before CSS and HTML4.\n            I say this not to humblebrag, but to explain that I was here for all of it.\n            Every time when the definition of <em>modern web development</em> changed I would update my priors, following along.\n        </p>\n        <p>\n            For the longest time making web pages do anything except show text and images was an exercise in frustration.\n            Browsers were severely lacking in features, were wildly incompatible with web standards and each other,\n            and the tools that web developers needed to bring them to order were missing or lacking.\n            I built my share of vanilla JS components back in the IE6 days, and it made me dream of a better way.\n            When frameworks first started coming on the scene with that better way, adding missing features, abstracting away incompatibility,\n            and providing better tooling, I was ready for them. I was all-in.\n        </p>\n        <p>\n            I bought into ExtJS, loved it for a time, and then got a hundred thousand line codebase stuck on ExtJS 3 because version 4 changed things\n            so much that porting was too costly. I then bought into Backbone, loved that too, but had to move on when its principal developer did.\n            I joined a team that bought into AngularJS and got stuck painted into a corner when the Angular team went in a totally different direction for v2.\n            I helped rewrite a bunch of frontends in Angular v2 and React, \n            and found myself sucked into constant forced maintenance when their architecture and ecosystems churned.\n        </p>\n        <p>\n            Did I make bad choices? Even in hindsight I would say I picked the right choices for the time.\n            Time just moved on.\n        </p>\n\n        <h3>The cost of change</h3>\n        <p>\n            This lived experience taught me a strong awareness of rates of change in dependencies, and the costs they impose.\n            I imagine a web page as a thin old man sitting astride a tall pile of dependencies, each changing at their own pace.\n            Some dependencies are stable for decades, like HTML's core set of elements, or CSS 2's set of layout primitives. \n            They're so stable that we don't even consider them dependencies, they're just <em>the web</em>.\n        </p>\n        <p>\n            Other dependencies change every few years, like module systems, or new transpiled languages, \n            or the preferred build and bundling tool of the day, or what framework is in vogue.\n            Then there are the dependencies that change yearly, like major framework and OS releases.\n            Finally there are the dependencies that change constantly, like the many packages that contribute\n            to a typical web application built with a popular framework.\n        </p>\n        <p>\n            As a web developer who loves their user, taking on those dependencies creates a Solomon's choice.\n            Either you keep up with the churn, and spend a not insignificant amount of your day working and reworking code\n            that already works, instead of working on the things your user cares about. \n            Or, you stick it out for as long as you can on old versions, applying ever more workarounds to get \n            old framework releases and their outdated build and CLI tools to work in new OS and ecosystem environments,\n            slowly boiling a frog that will at some point force a deep rewrite, again at the expense of the user.\n        </p>\n        <p>\n            Which is not to say the frameworks don't add value. They absolutely do, and they keep getting better. \n            Writing new code on a new framework is a steadily rising tide of developer experience. \n            But let us not pretend these benefits don't come at a cost.\n            Wherever there is a codebase too complicated to understand and maintain yourself, wherever there is a set of build tools \n            that must be kept compatible with changes in operating systems and ecosystems,\n            there is a shelf life. Sooner or later the makers of every framework and of every tool will move on,\n            even if it's just to a new long-term supported release, and the web developers that they served will have to move with them.\n        </p>\n        <p>\n            I hold this truth to be self-evident: the larger the abstraction layer a web developer uses on top of web standards,\n            the shorter the shelf life of their codebase becomes, and the more they will feel the churn.\n        </p>\n\n        <h3>The rising tide</h3>\n        <p>\n            Why do modern web projects built with modern frameworks depend on so much <em>stuff</em>?\n            At first there was no other option. Interacting with the DOM was painful, \n            and web frameworks rightly made choices to keep component systems outside the DOM, minimizing and abstracting away those interactions\n            in increasingly clever DOM reconciliation strategies. Supporting the brittle browsers and slow devices of the day required many workarounds and polyfills,\n            and web frameworks rightly added intricate tools to build, bundle and minify the user's code.\n        </p>\n        <p>\n            They needed a way to bring dependencies into those build systems, and sanely settled on the convention of node modules\n            and the NPM ecosystem. It got easy to add more dependencies, and just as water always finds the easy way down,\n            dependencies found the easy way in. As the abstraction layer grew the load time cost imposed by it grew right along,\n            and so we got server-side rendering, client-side hydration, lazy loading, and many other load time reduction strategies.\n        </p>\n        <p>\n            DOM-diffing, synthetic event systems, functional components, JSX, reactive data layers, server-side rendering and streaming, bundlers, tree shaking, \n            transpilers and compilers, and all the other complications that you won't find in web standards but you will find in every major web framework —\n            they are the things invented to make the modern web possible, but they are not the web. The web is what ships to the browser.\n            And all of those things are downstream from the decision to abstract away the browser,\n            a decision once made in good faith and for good reasons. A decision which now needs revisiting.\n        </p>\n        <p>\n            Browsers were not standing still. They saw what web developers were doing in userland to compensate \n            for the deficiencies in browser API's, and they kept improving and growing the platform, a rising tide slowly catching up to what frameworks did.\n            When Microsoft bid IE <a href=\"https://blogs.windows.com/windowsexperience/2022/06/15/internet-explorer-11-has-retired-and-is-officially-out-of-support-what-you-need-to-know/\">a well-deserved farewell</a> on June 15, 2022 a tipping point was reached.\n            For the first time the browser platform was so capable that it felt to me like it didn't need so much abstracting away anymore.\n            It wasn't a great platform, not as cleanly designed or complete as the API's of the popular frameworks,\n            but it was <em>Good Enough™</em> as a foundation, and that was all that mattered.\n        </p>\n\n        <h3>Holding my breath</h3>\n\n        <p>\n            I was very excited for what would happen in the framework ecosystem. There was a golden opportunity for frameworks \n            to tear down their abstraction layers, make something far simpler, far more closely aligned with the base web platform. \n            They could have a component system built on top of web components,\n            leveraging browser events and built-in DOM API's. All the frameworks could become cross-compatible, \n            easily plugging into each other's data layers and components while preserving what makes them unique.\n            The page weights would shrink by an order of magnitude with so much infrastructure code removed,\n            and that in combination with the move to HTTP/3 could make build tools optional.\n            It would do less, so inevitably be worse in some ways, but sometimes <a href=\"https://en.wikipedia.org/wiki/Worse_is_better\">worse is better</a>.\n        </p>\n        <p>\n            I gave a talk about how good the browser's platform had gotten, \n            showing off <a href=\"https://github.com/jsebrech/create-react-app-zero\">a version of Create React App</a> that didn't need any build tools\n            and was extremely light-weight, and the developer audience was just as excited as I was.\n            And I held my breath waiting on framework churn to for once go in the other direction, towards simplicity...\n        </p>\n        <p>\n            But nothing happened. In fact, the major frameworks kept building up their abstraction layers instead of building down.\n            We got React Server Components and React Compiler, exceedingly clever, utterly incomprehensible, \n            workarounds for self-imposed problems caused by overengineering.\n            Web developers don't seem to mind, but they struggle quietly with how to keep up with these tools and deliver good user experiences. \n            The bigger the abstraction layer gets, the more they feel the churn.\n        </p>\n        <p>\n            The irony is not lost on me that now the framework authors also feel the churn in their dependencies,\n            struggling to adapt to web components as foundational technology. React 19 is supposed to finally support web components\n            in a way that isn't incredibly painful, or so they say, we'll see. I confess to feeling some satisfaction\n            in their struggle. The shoe is on the other foot. Welcome to modern web development.\n        </p>\n        \n        <h3>The road ahead</h3>\n\n        <p>\n            What the frameworks are doing, that's fine for them, and they can keep doing it. \n            But I'm done with all that unless someone is paying me to do it.\n            They're on a fundamentally different path from where I want web development to go, from how I want to make web pages.\n            The web is what ships to the browser. Reducing the distance between what the developer writes and what ships to the browser\n            is valuable and necessary. This blog and this site are my own stake in the ground for this idea, \n            showing just how much you can get done without any framework code or build tools at all. \n            But let's be honest: web components are not a framework, no matter how hard I tried to explain them as one.\n        </p>\n\n        <blockquote>\n            <p>Comparing web components to React is like comparing a good bicycle with a cybertruck.</p>\n            <p>They do very different things, and they're used by different people with very, very different mindsets.</p>\n        </blockquote>\n        <cite><a href=\"https://adactio.com/notes/21455\">Jeremy Keith</a></cite>\n\n        <p>\n            I want a motorbike, not a cybertruck. I still want frameworks, only much lighter. \n            Frameworks less than 10 KB in size, that are a thin layer on top of web standards\n            but still solve the problems that frameworks solve. I call this idea the <em>interoperable web framework</em>:\n        </p>\n        <ul>\n            <li>Its components are just web components.</li>\n            <li>Its events are just DOM events.</li>\n            <li>Its templates are just HTML templates.</li>\n            <li>It doesn't need to own the DOM that its components take part in.</li>\n            <li>Its data and event binding works on all HTML elements, built-in or custom, made with the framework or with something else.</li>\n            <li>It can be easily mixed together on a page with other interoperable web frameworks, with older versions of itself, or with vanilla code.</li>\n            <li>It doesn't need its own build tools.</li>\n        </ul>\n        <p>\n            I just feel it on my bones such a thing can be built now. Maybe I'm wrong and Ryan Carniato is right.\n            After all, he knows a lot more about frameworks than I do. But the more vanilla code that I write the more certain that I feel on this.\n            Some existing solutions like Lit are close, but none are precisely what I am looking for. \n            I would love to see a community of vanilla developers come together to figure out what that could look like,\n            running experiments and iterating on the results. For now I will just keep holding my breath, waiting for the tide to come in.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[The unreasonable effectiveness of vanilla JS]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/</id>\n        <published>2024-09-28T12:00:00.000Z</published>\n        <updated>2024-09-28T12:00:00.000Z</updated>\n        <summary><![CDATA[A case study in porting intricate React code to vanilla.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            I have a confession to make. At the end of the Plain Vanilla tutorial's <a href=\"../../../pages/applications.html\">Applications page</a>\n            a challenge was posed to the reader: port <a href=\"https://react.dev\">react.dev</a>'s final example \n            <a href=\"https://react.dev/learn/scaling-up-with-reducer-and-context\">Scaling Up with Reducer and Context</a> to vanilla web code.\n            Here's the confession: until today I had never actually ported over that example myself.\n        </p>\n        <p>\n            That example demonstrates a cornucopia of React's featureset.\n            Richly interactive UI showing a tasks application, making use of a context to lift the task state up,\n            and a reducer that the UI's controls dispatch to. React's DOM-diffing algorithm gets a real workout \n            because each task in the list can be edited independently from and concurrently with the other tasks. \n            It is an intricate and impressive demonstration. Here it is in its interactive glory:\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/complete/index.html\">complete example</a></p>\n        <p>\n            But I lied. That interactive example is actually the vanilla version and it is identical.\n            If you want to verify that it is in fact identical, check out the <a href=\"https://codesandbox.io/p/sandbox/react-dev-wy7lfd\">original React example</a>.\n            And with that out of the way, let's break apart the vanilla code.\n        </p>\n\n        <h3>Project setup</h3>\n\n        <p>The React version has these code files that we will need to port:</p>\n        <ul>\n            <li><strong>public/index.html</strong></li>\n            <li><strong>src/styles.css</strong></li>\n            <li><strong>src/index.js</strong>: imports the styles, bootstraps React and renders the App component</li>\n            <li><strong>src/App.js</strong>: renders the context's TasksProvider containing the AddTask and TaskList components</li>\n            <li><strong>src/AddTask.js</strong>: renders the simple form at the top to add a new task</li>\n            <li><strong>src/TaskList.js</strong>: renders the list of tasks</li>\n        </ul>\n        <p>\n            To make things fun, I chose the same set of files with the same filenames for the vanilla version.\n            Here's <strong>index.html</strong>:\n        </p>\n        <div><p><em>index.html:</em></p><pre><code>&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"UTF-8\"&gt;\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n    &lt;title&gt;Document&lt;/title&gt;\n    &lt;link rel=\"stylesheet\" href=\"styles.css\"&gt;\n&lt;/head&gt;\n&lt;body&gt;\n    &lt;div id=\"root\"&gt;&lt;/div&gt;\n    &lt;script type=\"module\" src=\"index.js\"&gt;&lt;/script&gt;\n&lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n        <p>\n            The only real difference is that it links to <strong>index.js</strong> and <strong>styles.css</strong>.\n            The stylesheet was copied verbatim, but for the curious here's a link to <a href=\"./complete/styles.css\">styles.css</a>.\n        </p>\n        \n        <h3>Get to the code</h3>\n\n        <p>\n            <strong>index.js</strong> is where it starts to get interesting.\n            Compare the React version to the vanilla version:\n        </p>\n        <div><p><em>index.js (React):</em></p><pre><code>import React, { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport \"./styles.css\";\n\nimport App from \"./App\";\n\nconst root = createRoot(document.getElementById(\"root\"));\nroot.render(\n  &lt;StrictMode&gt;\n    &lt;App /&gt;\n  &lt;/StrictMode&gt;\n);</code></pre></div>\n        <div><p><em>index.js (Vanilla):</em></p><pre><code>import './App.js';\nimport './AddTask.js';\nimport './TaskList.js';\nimport './TasksContext.js';\n\nconst render = () =&gt; {\n    const root = document.getElementById('root');\n    root.append(document.createElement('tasks-app'));\n}\n\ndocument.addEventListener('DOMContentLoaded', render);\n</code></pre></div>\n        <p>\n            Bootstrapping is different but also similar. All of the web components are imported first to load them,\n            and then the <code>&lt;tasks-app&gt;</code> component is rendered to the page.\n        </p>\n        <p>\n            The <strong>App.js</strong> code also bears more than a striking resemblance:\n        </p>\n        <div><p><em>App.js (React):</em></p><pre><code>import AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport { TasksProvider } from './TasksContext.js';\n\nexport default function TaskApp() {\n  return (\n    &lt;TasksProvider&gt;\n      &lt;h1&gt;Day off in Kyoto&lt;/h1&gt;\n      &lt;AddTask /&gt;\n      &lt;TaskList /&gt;\n    &lt;/TasksProvider&gt;\n  );\n}\n</code></pre></div>\n        <div><p><em>App.js (Vanilla):</em></p><pre><code>customElements.define('tasks-app', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            &lt;tasks-context&gt;\n                &lt;h1&gt;Day off in Kyoto&lt;/h1&gt;\n                &lt;task-add&gt;&lt;/task-add&gt;\n                &lt;task-list&gt;&lt;/task-list&gt;\n            &lt;/tasks-context&gt;\n        `;\n    }\n});\n</code></pre></div>\n\n        <p>\n            What I like about the code so far is that it <em>feels</em> React-like. I generally find programming against React's API pleasing,\n            but I don't like the tooling, page weight and overall complexity baggage that it comes with.\n        </p>\n\n        <h3>Adding context</h3>\n\n        <p>\n            The broad outline of how to bring a React-like context to a vanilla web application is\n            already explained in the <a href=\"https://plainvanillaweb.com/pages/applications.html#managing-state\">passing data deeply section</a> \n            of the main Plain Vanilla tutorial, so I won't cover that again here.\n            What adds spice in this specific case is that the React context uses a reducer,\n            a function that accepts the old tasks and an action to apply to them, and returns the new tasks to show throughout the application.\n        </p>\n        <p>\n            Thankfully, the React example's reducer function and initial state were already vanilla JS code,\n            so those come along for the ride unchanged and ultimately the vanilla context is a very straightforward custom element:\n        </p>\n\n        <div><p><em>TasksContext.js (Vanilla):</em></p><pre><code>customElements.define('tasks-context', class extends HTMLElement {\n    #tasks = structuredClone(initialTasks);\n    get tasks() { return this.#tasks; }\n    set tasks(tasks) {\n        this.#tasks = tasks;\n        this.dispatchEvent(new Event('change'));\n    }\n\n    dispatch(action) {\n        this.tasks = tasksReducer(this.tasks, action);\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n});\n\nfunction tasksReducer(tasks, action) {\n    switch (action.type) {\n        case 'added': {\n            return [...tasks, {\n                id: action.id,\n                text: action.text,\n                done: false\n            }];\n        }\n        case 'changed': {\n            return tasks.map(t =&gt; {\n                if (t.id === action.task.id) {\n                    return action.task;\n                } else {\n                    return t;\n                }\n            });\n        }\n        case 'deleted': {\n            return tasks.filter(t =&gt; t.id !== action.id);\n        }\n        default: {\n            throw Error('Unknown action: ' + action.type);\n        }\n    }\n}\n\nconst initialTasks = [\n    { id: 0, text: 'Philosopher’s Path', done: true },\n    { id: 1, text: 'Visit the temple', done: false },\n    { id: 2, text: 'Drink matcha', done: false }\n];\n</code></pre></div>\n\n        <p>\n            The actual context component is very bare bones, as it only needs to store the tasks,\n            emit change events for the other components to subscribe to, and provide a dispatch method \n            for those components to call that will use the reducer function to update the tasks.\n        </p>\n\n        <h3>Adding tasks</h3>\n\n        <p>\n            The AddTask component ends up offering more of a challenge. It's a stateful component with event listeners that dispatches to the reducer:\n        </p>\n        <div><p><em>AddTask.js (React):</em></p><pre><code>import { useState } from 'react';\nimport { useTasksDispatch } from './TasksContext.js';\n\nexport default function AddTask() {\n  const [text, setText] = useState('');\n  const dispatch = useTasksDispatch();\n  return (\n    &lt;&gt;\n      &lt;input\n        placeholder=\"Add task\"\n        value={text}\n        onChange={e =&gt; setText(e.target.value)}\n      /&gt;\n      &lt;button onClick={() =&gt; {\n        setText('');\n        dispatch({\n          type: 'added',\n          id: nextId++,\n          text: text,\n        }); \n      }}&gt;Add&lt;/button&gt;\n    &lt;/&gt;\n  );\n}\n\nlet nextId = 3;\n</code></pre></div>\n        <p>\n            The main wrinkle this adds for the vanilla web component is that the event listener on the button element\n            cannot be put inline with the markup. Luckily the handling of the input is much simplified\n            because we can rely on it keeping its state automatically, a convenience owed to not using a virtual DOM.\n            Thanks to the groundwork in the context component the actual dispatching of the action is easy:\n        </p>\n        <div><p><em>AddTask.js (Vanilla):</em></p><pre><code>customElements.define('task-add', class extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            &lt;input type=\"text\" placeholder=\"Add task\" /&gt;\n            &lt;button&gt;Add&lt;/button&gt;\n        `;\n        this.querySelector('button').onclick = () =&gt; {\n            const input = this.querySelector('input');\n            this.closest('tasks-context').dispatch({\n                type: 'added',\n                id: nextId++,\n                text: input.value\n            });\n            input.value = '';\n        };\n    }\n})\n\nlet nextId = 3;\n</code></pre></div>\n        <p>\n            Fascinating to me is that <strong>index.js</strong>, <strong>App.js</strong>, <strong>TasksContext.js</strong> and <strong>AddTask.js</strong>\n            are all fewer lines of code in the vanilla version than their React counterpart while remaining functionally equivalent. \n        </p>\n\n        <h3>Hard mode</h3>\n        <p>\n            The TaskList component is where React starts really pulling its weight.\n            The React version is clean and straightforward and juggles a lot of state with a constantly updating task list UI.\n        </p>\n        <div><p><em>TaskList.js (React):</em></p><pre><code>import { useState } from 'react';\nimport { useTasks, useTasksDispatch } from './TasksContext.js';\n\nexport default function TaskList() {\n  const tasks = useTasks();\n  return (\n    &lt;ul&gt;\n      {tasks.map(task =&gt; (\n        &lt;li key={task.id}&gt;\n          &lt;Task task={task} /&gt;\n        &lt;/li&gt;\n      ))}\n    &lt;/ul&gt;\n  );\n}\n\nfunction Task({ task }) {\n  const [isEditing, setIsEditing] = useState(false);\n  const dispatch = useTasksDispatch();\n  let taskContent;\n  if (isEditing) {\n    taskContent = (\n      &lt;&gt;\n        &lt;input\n          value={task.text}\n          onChange={e =&gt; {\n            dispatch({\n              type: 'changed',\n              task: {\n                ...task,\n                text: e.target.value\n              }\n            });\n          }} /&gt;\n        &lt;button onClick={() =&gt; setIsEditing(false)}&gt;\n          Save\n        &lt;/button&gt;\n      &lt;/&gt;\n    );\n  } else {\n    taskContent = (\n      &lt;&gt;\n        {task.text}\n        &lt;button onClick={() =&gt; setIsEditing(true)}&gt;\n          Edit\n        &lt;/button&gt;\n      &lt;/&gt;\n    );\n  }\n  return (\n    &lt;label&gt;\n      &lt;input\n        type=\"checkbox\"\n        checked={task.done}\n        onChange={e =&gt; {\n          dispatch({\n            type: 'changed',\n            task: {\n              ...task,\n              done: e.target.checked\n            }\n          });\n        }}\n      /&gt;\n      {taskContent}\n      &lt;button onClick={() =&gt; {\n        dispatch({\n          type: 'deleted',\n          id: task.id\n        });\n      }}&gt;\n        Delete\n      &lt;/button&gt;\n    &lt;/label&gt;\n  );\n}\n</code></pre></div>\n\n        <p>\n            This proved to be a real challenge to port. The vanilla version ended up being a lot more verbose\n            because it has to do all the same DOM-reconciliation in explicit logic managed by the <strong>update()</strong> methods\n            of <code>&lt;task-list&gt;</code> and <code>&lt;task-item&gt;</code>.\n        </p>\n        <div><p><em>TaskList.js (Vanilla):</em></p><pre><code>customElements.define('task-list', class extends HTMLElement {\n    get context() { return this.closest('tasks-context'); }\n    \n    connectedCallback() {\n        this.context.addEventListener('change', () =&gt; this.update());\n        this.append(document.createElement('ul'));\n        this.update();\n    }\n\n    update() {\n        const ul = this.querySelector('ul');\n        let before = ul.firstChild;\n        this.context.tasks.forEach(task =&gt; {\n            let li = ul.querySelector(`:scope &gt; [data-key=\"${task.id}\"]`);\n            if (!li) {\n                li = document.createElement('li');\n                li.dataset.key = task.id;\n                li.append(document.createElement('task-item'));\n            }\n            li.firstChild.task = task;\n            // move to the right position in the list if not there yet\n            if (li !== before) ul.insertBefore(li, before);\n            before = li.nextSibling;\n        });\n        // remove unknown nodes\n        while (before) {\n            const remove = before;\n            before = before.nextSibling;\n            ul.removeChild(remove);\n        }\n    }\n});\n\ncustomElements.define('task-item', class extends HTMLElement {\n    #isEditing = false;\n    #task;\n    set task(task) { this.#task = task; this.update(); }\n    get context() { return this.closest('tasks-context'); }\n\n    connectedCallback() {\n        if (this.querySelector('label')) return;\n        this.innerHTML = `\n            &lt;label&gt;\n                &lt;input type=\"checkbox\" /&gt;\n                &lt;input type=\"text\" /&gt;\n                &lt;span&gt;&lt;/span&gt;\n                &lt;button id=\"edit\"&gt;Edit&lt;/button&gt;\n                &lt;button id=\"save\"&gt;Save&lt;/button&gt;\n                &lt;button id=\"delete\"&gt;Delete&lt;/button&gt;\n            &lt;/label&gt;\n        `;\n        this.querySelector('input[type=checkbox]').onchange = e =&gt; {\n            this.context.dispatch({\n                type: 'changed',\n                task: {\n                    ...this.#task,\n                    done: e.target.checked\n                }\n            });\n        };\n        this.querySelector('input[type=text]').onchange = e =&gt; {\n            this.context.dispatch({\n                type: 'changed',\n                task: {\n                    ...this.#task,\n                    text: e.target.value\n                }\n            });\n        };\n        this.querySelector('button#edit').onclick = () =&gt; {\n            this.#isEditing = true;\n            this.update();\n        };\n        this.querySelector('button#save').onclick = () =&gt; {\n            this.#isEditing = false;\n            this.update();\n        };\n        this.querySelector('button#delete').onclick = () =&gt; {\n            this.context.dispatch({\n                type: 'deleted',\n                id: this.#task.id\n            });\n        };\n        this.context.addEventListener('change', () =&gt; this.update());\n        this.update();\n    }\n\n    update() {\n        if (this.isConnected &amp;&amp; this.#task) {\n            this.querySelector('input[type=checkbox]').checked = this.#task.done;\n            const inputEdit = this.querySelector('input[type=text]');\n            inputEdit.style.display = this.#isEditing ? 'inline' : 'none';\n            inputEdit.value = this.#task.text;\n            const span = this.querySelector('span');\n            span.style.display = this.#isEditing ? 'none' : 'inline';\n            span.textContent = this.#task.text;\n            this.querySelector('button#edit').style.display = this.#isEditing ? 'none' : 'inline';\n            this.querySelector('button#save').style.display = this.#isEditing ? 'inline' : 'none';\n        }\n    }\n});\n</code></pre></div>\n        <p>\n            Some interesting take-aways:\n        </p>\n        <ul>\n            <li>\n                The <code>&lt;task-list&gt;</code> component's <strong>update()</strong> method implements a poor man's version of React reconciliation,\n                merging the current state of the <strong>tasks</strong> array into the child nodes of the <code>&lt;ul&gt;</code>.\n                In order to do this, it has to store a key on each list item, just like React requires, and here it becomes obvious why that is.\n                Without the key we can't find the existing <code>&lt;li&gt;</code> nodes that match up to task items,\n                and so would have to recreate the entire list. By adding the key it becomes possible to update the list in-place,\n                modifying task items instead of recreating them so that they can keep their on-going edit state.\n            </li>\n            <li>\n                That reconciliation code is very generic however, and it is easy to imagine a fully generic <strong>repeat()</strong>\n                function that converts an array of data to markup on the page. In fact, the Lit framework <a href=\"https://lit.dev/docs/templates/lists/#the-repeat-directive\">contains exactly that</a>.\n                For brevity's sake this code doesn't go quite that far.\n            </li>\n            <li>\n                The <code>&lt;task-item&gt;</code> component cannot do what the React code does: create different markup depending on the current state.\n                Instead it creates the union of the markup across the various states, and then in the <strong>update()</strong>\n                shows the right subset of elements based on the current state.\n            </li>\n        </ul>\n        <p>\n            That wraps up the entire code. You can find the <a href=\"https://github.com/jsebrech/vanilla-context-and-reducer\">ported example on Github</a>.\n        </p>\n\n        <h3>Some thoughts</h3>\n        \n        <p>\n            A peculiar result of this porting challenge is that the vanilla version ends up being roughly \n            the same number of lines of code as the React version. The React code is still overall less verbose (all those querySelectors, oy!),\n            but it has its own share of boilerplate that disappears in the vanilla version.\n            This isn't a diss against React, it's more of a compliment to how capable browsers have gotten that vanilla web components\n            can carry us so far.\n        </p>\n        <p>\n            If I could have waved a magic wand, what would have made the vanilla version simpler?\n        </p>\n        <ul>\n            <li>\n                All of those <strong>querySelector</strong> calls get annoying. The alternatives are building the markup easily with innerHTML\n                and then fishing out references to the created elements using querySelector, or building the elements one by one verbosely using createElement,\n                but then easily having a reference to them. Either of those ends up very verbose. \n                An alternative templating approach that makes it easy to create elements <em>and</em> get a reference to them would be very welcome.\n            </li>\n            <li>\n                As long as we're dreaming, I'm jealous of how easy it is to add the event listeners in JSX.\n                A real expression language in HTML templates that supports data and event binding and data-conditional markup would be very neat\n                and would take away most of the reason to still find a framework's templating language more convenient.\n                Web components are a perfectly fine alternative to React components, they just lack an easy built-in templating mechanism.\n            </li>\n            <li>\n                Browsers could get a little smarter about how they handle DOM updates during event handling.\n                In the logic that sorts the <code>&lt;li&gt;</code> to the right order in the list, \n                the <em>if</em> condition before insertBefore proved necessary because the browser\n                didn't notice that the element was already placed where it needed to be inserted,\n                and click events would get lost as a consequence.\n                I've even noticed that assigning a textContent to a button mid-click will make Safari\n                lose track of that button's click event. All of that can be worked around with clever reconciliation logic,\n                but that's code that belongs in the browser, not in JavaScript.\n            </li>\n        </ul>\n        <p>\n            All in all though, I'm really impressed with vanilla JS. I call it unreasonably effective because it is\n            jarring just how capable the built-in abilities of browsers are, and just how many web developers despite that \n            still default to web frameworks for every new project. Maybe one day...\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[The life and times of a web component]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/</id>\n        <published>2024-09-16T12:00:00.000Z</published>\n        <updated>2024-09-16T12:00:00.000Z</updated>\n        <summary><![CDATA[The entire lifecycle of a web component, from original creation to when a shadow crosses.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            When first taught about the wave-particle duality of light most people's brains does a double take.\n            How can light be two different categories of things at the same time, both a wave and a particle? That's just weird.\n            The same thing happens with web components, confusing people when they first try to learn them and run into their Document-JavaScript duality.\n            The component systems in frameworks are typically JavaScript-first, only using the DOM as an outlet for their visual appearance.\n            Web components however — or custom elements to be precise — can start out in either JavaScript or the document, and are married to neither.\n        </p>\n\n        <h3>Just the DOM please</h3>\n\n        <p>\n            Do you want to see the minimal JavaScript code needed to set up an <code>&lt;x-example&gt;</code> custom element?\n            Here it is:\n        </p>\n        <p>&nbsp;</p>\n        <p>\n            No, that's not a typo. Custom elements can be used just fine without any JavaScript.\n            Consider this example of an <code>&lt;x-tooltip&gt;</code> custom element that is HTML and CSS only:\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/undefined/example.html\">undefined/example.html</a></p>\n        <div><p><em>example.html:</em></p><pre><code>&lt;!doctype html&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" /&gt;\n        &lt;link rel=\"stylesheet\" href=\"example.css\"&gt;\n        &lt;title&gt;undefined custom element&lt;/title&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;button&gt;\n            Hover me\n            &lt;x-tooltip inert role=\"tooltip\"&gt;Thanks for hovering!&lt;/x-tooltip&gt;\n        &lt;/button&gt;\n    &lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n        <p>\n            <small>For the curious, here is the <a href=\"undefined/example.css\">example.css</a>, but it is not important here.</small>\n        </p>\n        <p>\n            Such elements are called <em>undefined custom elements</em>.\n            Before custom elements are defined in the window by calling <code>customElements.define()</code> they always start out in this state.\n            There is no need to actually define the custom element if it can be solved in a pure CSS way.\n            In fact, many \"pure CSS\" components found online can be solved by such custom elements,\n            by styling the element itself and its <code>::before</code> and <code>::after</code> pseudo-elements.\n        </p>\n\n        <h3>A question of definition</h3>\n\n        <p>\n            The CSS-only representation of the custom element can be progressively enhanced by connecting it up to a JavaScript counterpart,\n            a custom element class. This is a class that inherits from <code>HTMLElement</code> and allows the custom element\n            to implement its own logic.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/defined/example.html\">defined/example.html</a></p>\n        <div><p><em>example.html:</em></p><pre><code>&lt;!doctype html&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" /&gt;\n        &lt;title&gt;defining the custom element&lt;/title&gt;\n        &lt;style&gt;\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-example {\n                background-color: lavender;\n            }\n            x-example:not(:defined)::after {\n                content: '{defined: false}'\n            }\n            x-example:defined::after {\n                content: '{defined: true, status: ' attr(status) '}'\n            }\n        &lt;/style&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;p&gt;Custom element: &lt;x-example&gt;&lt;/x-example&gt;&lt;/p&gt;\n        &lt;button onclick=\"define()\"&gt;Define&lt;/button&gt;\n        &lt;button onclick=\"location.reload()\"&gt;Reload&lt;/button&gt;\n\n        &lt;script&gt;\n            function define() {\n                customElements.define('x-example', class extends HTMLElement {\n                    constructor() {\n                        super();\n                    }\n                    connectedCallback() {\n                        this.setAttribute('status', 'ready');\n                    }\n                });\n            }\n        &lt;/script&gt;\n    &lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n        <p>\n            What happens to the elements already in the markup at the moment <code>customElements.define()</code>\n            is called is an <em>element upgrade</em>. The browser will take all custom elements already in the document,\n            and create an instance of the matching custom element class that it connects them to.\n            This class enables the element to control its own part of the DOM, but also allows it to react to what happens in the DOM.\n        </p>\n        <p>\n            Element upgrades occur for existing custom elements in the document when <code>customElements.define()</code> is called,\n            and for all new custom elements with that tag name created afterwards (e.g. using <code>document.createElement('x-example')</code>).\n            It does not occur automatically for detached custom elements (not part of the document) that were created before the element was defined.\n            Those can be upgraded retroactively by calling <code>customElements.upgrade()</code>.\n        </p>\n\n        <p>\n            So far, this is the part of the lifecycle we've seen:\n        </p>\n        <pre>&lt;undefined&gt; \n    -&gt; define() -&gt; &lt;defined&gt;\n    -&gt; automatic upgrade() \n                -&gt; constructor() \n                -&gt; &lt;constructed&gt;\n        </pre>\n\n        <p>\n            The constructor as shown in the example above is optional, but if it is specified then it has a <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance\">number of gotcha's</a>:\n        </p>\n        <dl>\n            <dt>It must start with a call to <code>super()</code>.</dt>\n            <dt>It should not make DOM changes yet, as the element is not yet guaranteed to be connected to the DOM.</dt>\n            <dd>\n                This includes reading or modifying its own DOM properties, like its attributes.\n                The tricky part is that in the constructor the element might already be in the DOM,\n                so setting attributes might work. Or it might give an error. It's best to avoid DOM interaction altogether in the constructor.\n            </dd>\n            <dt>It should initialize its state, like class properties</dt>\n            <dd>\n                But work done in the constructor should be minimized and maximally postponed until <code>connectedCallback</code>.\n            </dd>\n        </dl>\n\n        <h3>Making connections</h3>\n\n        <p>\n            After being constructed, if the element was already in the document, its <code>connectedCallback()</code> handler is called.\n            This handler is normally called only when the element is inserted into the document, but for elements that are already in the document when they are defined it ends up being called as well.\n            In this handler DOM changes can be made, and in the example above the <code>status</code> attribute is set to demonstrate this.\n        </p>\n        <p>\n            The <em>connectedCallback()</em> handler is part of what is known in the HTML standard as <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions\">custom element reactions</a>:\n            These reactions allow the element to respond to various changes to the DOM:\n        </p>\n        <ul>\n            <li><code>connectedCallback()</code> is called when the element is inserted into the document, even if it was only moved from a different place in the same document.</li>\n            <li><code>disconnectedCallback()</code> is called when the element is removed from the document.</li>\n            <li><code>adoptedCallback()</code> is called when the element is moved to a new document. (You are unlikely to need this in practice.)</li>\n            <li><code>attributeChangedCallback()</code> is called when an attribute is changed, but only for the attributes listed in its <code>observedAttributes</code> property.</li>\n        </ul>\n        <p>\n            There are also special reactions for <a href=\"https://dev.to/stuffbreaker/custom-forms-with-web-components-and-elementinternals-4jaj\">form-associated custom elements</a>, \n            but those are a rabbit hole beyond the purview of this blog post.\n        </p>\n        <p>\n            There are more gotcha's to these reactions:\n        </p>\n        <dl>\n            <dt><code>connectedCallback()</code> and <code>disconnectedCallback()</code> can be called multiple times</dt>\n            <dd>\n                This can occur when the element is moved around in the document.\n                These handlers should be written in such a way that it is harmless to run them multiple times,\n                e.g. by doing an early exit when it is detected that <em>connectedCallback()</em> was already run.\n            </dd>\n            <dt><code>attributeChangedCallback()</code> can be called before <code>connectedCallback()</code></dt>\n            <dd>\n                For all attributes already set when the element in the document is upgraded,\n                the <em>attributeChangedCallback()</em> handler will be called first,\n                and only after this <em>connectedCallback()</em> is called.\n                The unpleasant consequence is that any <em>attributeChangedCallback</em> that tries to update DOM structures\n                created in <em>connectedCallback</em> can produce errors.\n            </dd>\n            <dt><code>attributeChangedCallback()</code> is only called for attribute changes, not property changes.</dt>\n            <dd>\n                Attribute changes can be done in Javascript by calling <code>element.setAttribute('name', 'value')</code>.\n                DOM attributes and class properties can have the same name, but are not automatically linked.\n                Generally for this reason it is better to avoid having attributes and properties with the same name.\n            </dd>\n        </dl>\n\n        <p>\n            The lifecycle covered up to this point for elements that start out in the initial document:\n        </p>\n        <pre>&lt;undefined&gt; \n    -&gt; define() -&gt; &lt;defined&gt;\n    -&gt; automatic upgrade() \n                -&gt; [element].constructor()\n                -&gt; [element].attributeChangedCallback()\n                -&gt; [element].connectedCallback() \n                -&gt; &lt;connected&gt;\n        </pre>\n\n        <h3>Flip the script</h3>\n\n        <p>\n            So far we've covered one half of the Document-JavaScript duality, for custom elements starting out in the document,\n            and only after that becoming defined and gaining a JavaScript counterpart.\n            It is however also possible to reverse the flow, and start out from JavaScript.\n        </p>\n        <p>\n            This is the minimal code to create a custom element in JavaScript: <code>document.createElement('x-example')</code>.\n            The element does not need to be defined in order to run this code, although it can be, and the resulting node can be inserted into the document\n            as if it was part of the original HTML markup.\n        </p>\n        <p>\n            If it is inserted, and after insertion the element becomes defined, then it will behave as described above.\n            Things are however different if the element remains detached:\n        </p>\n        <dl>\n            <dt>The detached element will not be automatically upgraded when it is defined.</dt>\n            <dd>\n                The constructor or reactions will not be called. It will be automatically upgraded when it is inserted into the document.\n                It can also be upgraded explicitly by calling <code>customElements.upgrade()</code>.\n            </dd>\n            <dt>If the detached element is already defined when it is created, it will be upgraded automatically.</dt>\n            <dd>The <em>constructor()</em> and <em>attributeChangedCallback()</em> will be called. Because it is not yet part of the document <em>connectedCallback()</em> won't be.</dd>\n        </dl>\n        <p>\n            By now no doubt you are a bit confused. Here's an interactive playground that lets you test\n            what happens to elements as they go through their lifecycle, both for those in the initial document and those created dynamically.\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/defined2/example.html\">defined2/example.html</a></p>\n\n        <p>Here are some interesting things to try out:</p>\n        <ul>\n            <li><em>Create</em>, then <em>Define</em>, and you will see that the created element is not upgraded automatically because it is detached from the document.</li>\n            <li><em>Create</em>, then <em>Connect</em>, then <em>Define</em>, and you will see that the element is upgraded automatically because it is in the document.</li>\n            <li><em>Define</em>, then <em>Create</em>, and you will see that the element is upgraded as soon as it is created (<em>constructed</em> appears in the reactions).</li>\n        </ul>\n        <p>\n            I tried writing a flowchart of all possible paths through the lifecycle that can be seen in this example,\n            but it got so unwieldy that I think it's better to just play around with the example until a solid grasp develops.\n        </p>\n\n        <h3>In the shadows</h3>\n\n        <p>\n            Adding shadow DOM creates yet another wrinkle in the lifecycle.\n            At any point in the element's JavaScript half, including in its constructor, a shadow DOM can be attached to the element by calling <code>attachShadow()</code>.\n            Because the shadow DOM is immediately available for DOM operations, that makes it possible to do those DOM operations in the constructor.\n        </p>\n        <p>\n            In this next interactive example you can see what happens when the shadow DOM becomes attached.\n            The <em>x-shadowed</em> element will immediately attach a shadow DOM in its constructor,\n            which happens when the element is upgraded automatically after defining.\n            The <em>x-shadowed-later</em> element postpones adding a shadow DOM until a link is clicked,\n            so the element first starts out as a non-shadowed custom element, and adds a shadow DOM later.\n        </p>\n\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/shadowed/example.html\">shadowed/example.html</a></p>\n        <div><p><em>example.html:</em></p><pre><code>&lt;!doctype html&gt;\n&lt;html&gt;\n    &lt;head&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" /&gt;\n        &lt;title&gt;shadowed custom element&lt;/title&gt;\n        &lt;style&gt;\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-shadowed, x-shadowed-later { background-color: lightgray; }\n        &lt;/style&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;p&gt;&amp;lt;x-shadowed&amp;gt;: &lt;x-shadowed&gt;undefined, not shadowed&lt;/x-shadowed&gt;&lt;/p&gt;\n        &lt;p&gt;&amp;lt;x-shadowed-later&amp;gt;: &lt;x-shadowed-later&gt;undefined, not shadowed&lt;/x-shadowed-later&gt;&lt;/p&gt;\n        &lt;button id=\"define\" onclick=\"define()\"&gt;Define&lt;/button&gt;\n        &lt;button onclick=\"location.reload()\"&gt;Reload&lt;/button&gt;\n\n        &lt;script&gt;\n        function define() {\n            customElements.define('x-shadowed', class extends HTMLElement {\n                constructor() {\n                    super();\n                    this.attachShadow({mode: 'open'});\n                    this.shadowRoot.innerHTML = `\n                        &lt;span style=\"background-color: lightgreen\"&gt;\n                            shadowed\n                        &lt;/span&gt;\n                    `;\n                }\n            });\n            customElements.define('x-shadowed-later', class extends HTMLElement {\n                connectedCallback() {\n                    this.innerHTML = 'constructed, &lt;a href=\"#\"&gt;click to shadow&lt;/a&gt;';\n                    this.querySelector('a').onclick = (e) =&gt; { e.preventDefault(); this.addShadow() };\n                }\n                addShadow() {\n                    this.attachShadow({mode: 'open'});\n                    this.shadowRoot.innerHTML = `\n                        &lt;span style=\"background-color: lightgreen\"&gt;\n                            shadowed\n                        &lt;/span&gt;\n                    `;\n                }\n            });\n            document.querySelector('button#define').setAttribute('disabled', true);\n        }\n        &lt;/script&gt;\n    &lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n\n        <p>\n            While adding a shadow DOM can be done at any point, it is a one-way operation.\n            Once added the shadow DOM will replace the element's original contents, and this cannot be undone.\n        </p>\n\n        <h3>Keeping an eye out</h3>\n\n        <p>\n            So far we've mostly been dealing with initial setup of the custom element,\n            but a major part of the lifecycle is responding to changes as they occur.\n            Here are some of the major ways that custom elements can respond to DOM changes:\n        </p>\n        <ul>\n            <li><em>connectedCallback</em> and <em>disconnectedCallback</em> to handle DOM insert and remove of the element itself.</li>\n            <li><em>attributeChangedCallback</em> to handle attribute changes of the element.</li>\n            <li>For shadowed custom elements, the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/slotchange_event\">slotchange</a> event can be used to detect when children are added and removed in a <code>&lt;slot&gt;</code>.</li>\n            <li>Saving the best for last, <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver\">MutationObserver</a> can be used to monitor DOM subtree changes, as well as attribute changes.</li>\n        </ul>\n        <p>\n            <em>MutationObserver</em> in particular is worth exploring, because it is a swiss army knife for monitoring the DOM.\n            Here's an example of a counter that automatically updates when new child elements are added:\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/observer/example.html\">observer/example.html</a></p>\n        <div><p><em>example.html:</em></p><pre><code>&lt;!doctype html&gt;\n&lt;html&gt; \n    &lt;head&gt;\n        &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" /&gt;\n        &lt;title&gt;custom element with observer&lt;/title&gt;\n        &lt;style&gt;\n            body { font-family: system-ui, sans-serif; margin: 1em; }\n            x-wall { display: block; margin-bottom: 1em; }\n        &lt;/style&gt;\n    &lt;/head&gt;\n    &lt;body&gt;\n        &lt;x-wall&gt;&lt;x-bottle&gt;&lt;/x-bottle&gt;&lt;/x-wall&gt;\n        &lt;button onclick=\"add()\"&gt;Add one more&lt;/button&gt;\n        &lt;button onclick=\"location.reload()\"&gt;Reload&lt;/button&gt;\n\n        &lt;script&gt;\n        customElements.define('x-wall', class extends HTMLElement {\n            connectedCallback() {\n                if (this.line) return; // prevent double initialization\n                this.line = document.createElement('p');\n                this.insertBefore(this.line, this.firstChild);\n                new MutationObserver(() =&gt; this.update()).observe(this, { childList: true });\n                this.update();\n            }\n            update() {\n                const count = this.querySelectorAll('x-bottle').length;\n                this.line.textContent = \n                    `${count} ${count === 1 ? 'bottle' : 'bottles'} of beer on the wall`;\n            }\n        });\n        customElements.define('x-bottle', class extends HTMLElement {\n            connectedCallback() { this.textContent = '🍺'; }\n        });\n        function add() {\n            document.querySelector('x-wall').append(\n                document.createElement('x-bottle'));\n        }\n        &lt;/script&gt;\n    &lt;/body&gt;\n&lt;/html&gt;</code></pre></div>\n\n        <p>\n            There is still more to tell, but already I can feel eyes glazing over and brains turning to mush,\n            so I will keep the rest for another day.\n        </p>\n\n        <hr>\n\n        <p>\n            Phew, that was a much longer story than I originally set out to write, but custom elements have surprising intricacy.\n            I hope you found it useful, and if not at least you got to see some code and click some buttons.\n            It's all about the clicking of the buttons.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Sweet Suspense]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-09-09-sweet-suspense/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-09-09-sweet-suspense/</id>\n        <published>2024-09-09T12:00:00.000Z</published>\n        <updated>2024-09-09T12:00:00.000Z</updated>\n        <summary><![CDATA[React-style lazy loading of web components.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-09-09-sweet-suspense/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            I was reading Addy Osmani and Hassan Djirdeh's book <a href=\"https://largeapps.dev/\">Building Large Scale Web Apps</a>.\n            (Which, by the way, I can definitely recommend.) In it they cover all the ways to make a React app sing at scale.\n            The chapter on <em>Modularity</em> was especially interesting to me, because JavaScript modules\n            are a common approach to modularity in both React and vanilla web code.\n        </p>\n        <p>\n            In that chapter on <em>Modularity</em> there was one particular topic that caught my eye,\n            and it was the use of <code>lazy()</code> and <code>Suspense</code>, paired with an <code>ErrorBoundary</code>.\n            These are the primitives that React gives us to asynchronously load UI components and their data on-demand while showing a fallback UI,\n            and replace the UI with an error message when something goes wrong.\n            If you're not familiar, here's a good <a href=\"https://refine.dev/blog/react-lazy-loading/#catching-loading-errors\">overview page</a>.\n        </p>\n        <p>\n            It was at that time that I was visited by the imp of the perverse, which posed to me a simple challenge:\n            <em>can you bring React's lazy loading primitives to vanilla web components?</em>\n            To be clear, there are <a href=\"https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/\">many</a> \n            <a href=\"https://github.com/codewithkyle/lazy-loader\">ways</a> to \n            <a href=\"https://www.webcomponents.org/element/st-lazy\">load</a> web components \n            <a href=\"https://lamplightdev.com/blog/2020/03/20/lazy-loading-web-components-with-intersection-observer/\">lazily</a>. \n            This is well-trodden territory. What wasn't out there was a straight port of lazy, suspense and error boundary. \n            The idea would not let me go. So here goes nothing.\n        </p>\n\n        <h3>Lazy</h3>\n\n        <p>\n            The idea and execution of React's lazy is simple. Whenever you want to use a component in your code,\n            but you don't want to actually fetch its code yet until it needs to be rendered, wrap it using the <code>lazy()</code> function:<br>\n            <code>const MarkdownPreview = lazy(() =&gt; import('./MarkdownPreview.js'));</code><br>\n        </p>\n        <p>\n            React will automatically \"suspend\" rendering when it first bumps into this lazy component until the component has loaded, and then continue automatically.\n        </p>\n        <p>\n            This works in React because the markup of a component only looks like HTML, \n            but is actually JavaScript in disguise, better known as <em>JSX</em>.\n            With web components however, the markup that the component is used in is actually HTML,\n            where there is no <code>import()</code> and no calling of functions.\n            That means our vanilla <em>lazy</em> cannot be a JavaScript function, but instead it must be an HTML custom element:<br>\n            <code>&lt;x-lazy&gt;&lt;x-hello-world&gt;&lt;/x-hello-world&gt;&lt;/x-lazy&gt;</code>\n        </p>\n\n        <p>\n            The basic setup is simple, when the lazy component is added to the DOM,\n            we'll scan for children that have a '-' in the name and therefore are custom elements,\n            see if they're not yet defined, and load and define them if so.\n            By using <code>display: contents</code> we can avoid having the <code>&lt;x-lazy&gt;</code> impact layout.\n        </p>\n        <div><p><em>lazy.js:</em></p><pre><code>customElements.define('x-lazy', class extends HTMLElement {\n    connectedCallback() {\n        this.style.display = 'contents';\n        this.#loadLazy();\n    }\n\n    #loadLazy() {\n        const elements = \n            [...this.children].filter(_ =&gt; _.localName.includes('-'));\n        const unregistered = \n            elements.filter(_ =&gt; !customElements.get(_.localName));\n        unregistered.forEach(_ =&gt; this.#loadElement(_));\n    }\n\n    #loadElement(element) {\n        // TODO: load the custom element\n    }\n});\n</code></pre></div>\n\n        <p>\n            To actually load the element, we'll have to first find the JS file to import, and then run its register function.\n            By having the function that calls <code>customElements.define</code> as the default export by convention the problem is reduced to finding the path to the JS file.\n            The following code uses a heuristic that assumes components are in a <code>./components/</code> subfolder of the current document\n            and follow a consistent file naming scheme:\n        </p>\n        <div><p><em>lazy.js (continued):</em></p><pre><code>    #loadElement(element) {\n        // strip leading x- off the name\n        const cleanName = element.localName.replace(/^x-/, '').toLowerCase();\n        // assume component is in its own folder\n        const url = `./components/${cleanName}/${cleanName}.js`;\n        // dynamically import, then register if not yet registered\n        return import(new URL(url, document.location)).then(module =&gt; \n            !customElements.get(element.localName) &amp;&amp; module &amp;&amp; module.default());\n    }</code></pre></div>\n\n        <p>\n            One could get a lot more creative however, and for example use an \n            <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap\">import map</a> \n            to map module names to files. This I leave as an exercise for the reader.\n        </p>\n\n        <h3>Suspense</h3>\n\n        <p>\n            While the lazy component is loading, we can't show it yet. This is true for custom elements just as much as for React.\n            That means we need a wrapper component that will show a fallback UI as long as any components in its subtree are loading,\n            the <code>&lt;x-suspense&gt;</code> component. This starts out as a tale of two slots. When the suspense element is loading it shows the fallback, otherwise the content.\n        </p>\n\n        <div><p><em>example.html:</em></p><pre><code>&lt;x-suspense&gt;\n    &lt;p slot=\"fallback\"&gt;Loading...&lt;/p&gt;\n    &lt;x-lazy&gt;&lt;x-hello-world&gt;&lt;/x-hello-world&gt;&lt;/x-lazy&gt;\n&lt;/x-suspense&gt;</code></pre></div>\n        <div><p><em>suspense.js:</em></p><pre><code>export class Suspense extends HTMLElement {\n    #fallbackSlot;\n    #contentSlot;\n\n    set loading(isLoading) {\n        if (!this.#fallbackSlot) return;\n        this.#fallbackSlot.style.display = isLoading ? 'contents' : 'none';\n        this.#contentSlot.style.display = !isLoading ? 'contents' : 'none';\n    }\n\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n\n        this.#fallbackSlot = document.createElement('slot');\n        this.#fallbackSlot.style.display = 'none';\n        this.#fallbackSlot.name = 'fallback';\n        this.#contentSlot = document.createElement('slot');\n        this.shadowRoot.append(this.#fallbackSlot, this.#contentSlot);\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n}\ncustomElements.define('x-suspense', Suspense);</code></pre></div>\n\n        <p>\n            The trick now is, how to we get <code>loading = true</code> to happen?\n            In Plain Vanilla's applications page I showed how a React context can be simulated using the <code>element.closest()</code> API.\n            We can use the same mechanism to create a generic API that will let our suspense wait on a promise to complete.\n        </p>\n\n        <div><p><em>suspense.js (continued):</em></p><pre><code>    static waitFor(sender, ...promises) {\n        const suspense = sender.closest('x-suspense');\n        if (suspense) suspense.addPromises(...promises);\n    }\n\n    addPromises(...promises) {\n        if (!promises.length) return;\n        this.loading = true;\n        // combine into previous promises if there are any\n        const newPromise = this.#waitingForPromise = \n            Promise.allSettled([...promises, this.#waitingForPromise]);\n        // wait for all promises to complete\n        newPromise.then(_ =&gt; {\n            // if no newer promises were added, we're done\n            if (newPromise === this.#waitingForPromise) {\n                this.loading = false;\n            }\n        });\n    }</code></pre></div>\n\n        <p>\n            <code>Suspense.waitFor</code> will call the nearest ancestor <code>&lt;x-suspense&gt;</code>\n            to a given element, and give it a set of promises that it should wait on.\n            This API can then be called from our <code>&lt;x-lazy&gt;</code> component.\n            Note that <code>#loadElement</code> returns a promise that completes when the custom element is loaded or fails to load.\n        </p>\n        <div><p><em>lazy.js (continued):</em></p><pre><code>    #loadLazy() {\n        const elements = \n            [...this.children].filter(_ =&gt; _.localName.includes('-'));\n        const unregistered = \n            elements.filter(_ =&gt; !customElements.get(_.localName));\n        if (unregistered.length) {\n            Suspense.waitFor(this, \n                ...unregistered.map(_ =&gt; this.#loadElement(_))\n            );\n        }\n    }</code></pre></div>\n        <p>\n            The nice thing about the promise-based approach is that we can give it any promise, just like we would with React's suspense.\n            For example, when loading data in a custom element that is in the suspense's subtree, we can call the exact same API:<br>\n            <code>Suspense.waitFor(this, fetch(url).then(...))</code>\n        </p>\n\n        <h3>Error boundary</h3>\n\n        <p>\n            Up to this point, we've been assuming everything always works. This is <del>Sparta</del>software, it will never \"always work\".\n            What we need is a graceful way to intercept failed promises that are monitored by the suspense,\n            and show an error message instead. That is the role that React's error boundary plays.\n        </p>\n        <p>\n            The approach is similar to suspense:\n        </p>\n        <div><p><em>example.html:</em></p><pre><code>&lt;x-error-boundary&gt;\n    &lt;p slot=\"error\"&gt;Something went wrong&lt;/p&gt;\n    &lt;x-suspense&gt;\n        &lt;p slot=\"fallback\"&gt;Loading...&lt;/p&gt;\n        &lt;x-lazy&gt;&lt;x-hello-world&gt;&lt;/x-hello-world&gt;&lt;/x-lazy&gt;\n    &lt;/x-suspense&gt;\n&lt;/x-error-boundary&gt;</code></pre></div>\n        <p>\n            And the code is also quite similar to suspense:\n        </p>\n        <div><pre><code>export class ErrorBoundary extends HTMLElement {\n\n    static showError(sender, error) {\n        if (!error) throw new Error('ErrorBoundary.showError: expected two arguments but got one');\n        const boundary = sender.closest('x-error-boundary');\n        if (boundary) {\n            boundary.error = error;\n        } else {\n            console.error('unable to find x-error-boundary to show error');\n            console.error(error);\n        }\n    }\n\n    #error;\n    #errorSlot;\n    #contentSlot;\n\n    get error() {\n        return this.#error;\n    }\n\n    set error(error) {\n        if (!this.#errorSlot) return;\n        this.#error = error;\n        this.#errorSlot.style.display = error ? 'contents' : 'none';\n        this.#contentSlot.style.display = !error ? 'contents' : 'none';\n        if (error) {\n            this.#errorSlot.assignedElements().forEach(element =&gt; {\n                if (Object.hasOwn(element, 'error')) {\n                    element.error = error;\n                } else {\n                    element.setAttribute('error', error?.message || error);\n                }\n            });\n            this.dispatchEvent(new CustomEvent('error', { detail: error }));\n        }\n    }\n\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n\n        this.#errorSlot = document.createElement('slot');\n        this.#errorSlot.style.display = 'none';\n        this.#errorSlot.name = 'error';\n        // default error message\n        this.#errorSlot.textContent = 'Something went wrong.';\n        this.#contentSlot = document.createElement('slot');\n        this.shadowRoot.append(this.#errorSlot, this.#contentSlot);\n    }\n\n    reset() {\n        this.error = null;\n    }\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n}\ncustomElements.define('x-error-boundary', ErrorBoundary);\n</code></pre></div>\n\n        <p>\n            Similar to suspense, this has an API <code>ErrorBoundary.showError()</code> that can be called\n            from anywhere inside the error boundary's subtree to show an error that occurs.\n            The suspense component is then modified to call this API when it bumps into a rejected promise.\n            To hide the error, the <code>reset()</code> method can be called on the error boundary element.\n        </p>\n        <p>\n            Finally, the <code>error</code> setter will set the error as a property or attribute\n            on all children in the error slot, which enables customizing the error message's behavior based on the error object's properties\n            by creating a custom <code>&lt;x-error-message&gt;</code> component.\n        </p>\n\n        <h3>Conclusion</h3>\n\n        <p>\n            Finally, we can bring all of this together in a single example,\n            that combines lazy, suspense, error boundary, a customized error message, and a lazy-loaded hello-world component.\n        </p>\n\n        <div><p><em>example/index.js:</em></p><pre><code>import { registerLazy } from './components/lazy.js';\nimport { registerSuspense } from './components/suspense.js';\nimport { registerErrorBoundary } from './components/error-boundary.js';\nimport { registerErrorMessage } from './components/error-message.js';\n\ncustomElements.define('x-demo', class extends HTMLElement {\n\n    constructor() {\n        super();\n        registerLazy();\n        registerSuspense();\n        registerErrorBoundary();\n        registerErrorMessage();\n    }\n\n    connectedCallback() {\n        this.innerHTML = `\n            &lt;p&gt;Lazy loading demo&lt;/p&gt;\n            &lt;button id=\"lazy-load\"&gt;Load lazy&lt;/button&gt;\n            &lt;button id=\"error-reset\" disabled&gt;Reset error&lt;/button&gt;\n            &lt;div id=\"lazy-load-div\"&gt;\n                &lt;p&gt;Click to load..&lt;/p&gt;\n            &lt;/div&gt;\n        `;\n        const resetBtn = this.querySelector('button#error-reset')\n        resetBtn.onclick = () =&gt; {\n            this.querySelector('x-error-boundary').reset();\n            resetBtn.setAttribute('disabled', true);\n        };\n        const loadBtn = this.querySelector('button#lazy-load');\n        loadBtn.onclick = () =&gt; {\n            this.querySelector('div#lazy-load-div').innerHTML = `\n                &lt;x-error-boundary&gt;\n                    &lt;x-error-message slot=\"error\"&gt;&lt;/x-error-message&gt;\n                    &lt;x-suspense&gt;\n                        &lt;p slot=\"fallback\"&gt;Loading...&lt;/p&gt;\n                        &lt;p&gt;&lt;x-lazy&gt;&lt;x-hello-world&gt;&lt;/x-hello-world&gt;&lt;/x-lazy&gt;&lt;/p&gt;\n                    &lt;/x-suspense&gt;\n                &lt;/x-error-boundary&gt;\n            `\n            this.querySelector('x-error-boundary').addEventListener('error', _ =&gt; {\n                resetBtn.removeAttribute('disabled');\n            });\n            loadBtn.setAttribute('disabled', true);\n        };\n    }\n\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-09-sweet-suspense/example/index.html\">complete example</a></p>\n\n        <p>\n            For the complete example's code, as well as the lazy, suspense and error-boundary components,\n            check out the <a href=\"https://github.com/jsebrech/sweet-suspense\">sweet-suspense repo on Github</a>.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[How fast are web components?]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-09-06-how-fast-are-web-components/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-09-06-how-fast-are-web-components/</id>\n        <published>2024-09-06T12:00:00.000Z</published>\n        <updated>2024-09-15T12:00:00.000Z</updated>\n        <summary><![CDATA[Benchmarking the relative performance of different web component techniques.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-09-06-how-fast-are-web-components/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <aside>\n            <h3>Author's note</h3>\n            <p>\n                This article initially had somewhat different results and conclusions,\n                but deficiencies in the original benchmark were pointed out and addressed.\n                Where the conclusions were changed from the original article, this is pointed out in the text.\n            </p>\n        </aside>\n\n        <p>\n            It is often said that web components are slow.\n            This was also my experience when I first tried building web components a few years ago.\n            At the time I was using the Stencil framework, because I didn't feel confident that they could be built well without a framework.\n            Performance when putting hundreds of them on a page was so bad that I ended up going back to React.\n        </p>\n        <p>\n            But as I've gotten deeper into vanilla web development I started to realize that maybe I was just using it wrong.\n            Perhaps web components can be fast, if built in a light-weight way.\n            This article is an attempt to settle the question \"How fast are web components?\".\n        </p>\n\n        <h3>The lay of the land</h3>\n\n        <p>\n            What kinds of questions did I want answered?\n        </p>\n        <ul>\n            <li>How many web components can you render on the page in a millisecond?</li>\n            <li>Does the technique used to built the web component matter, which technique is fastest?</li>\n            <li>How do web component frameworks compare? I used Lit as the framework of choice as it is well-respected.</li>\n            <li>How does React compare?</li>\n            <li>What happens when you combine React with web components?</li>\n        </ul>\n\n        <p>\n            To figure out the answer I made a benchmark as a vanilla web page (of course),\n            that renders thousands of very simple components containing only <code>&lt;span&gt;.&lt;/span&gt;</code>\n            and measured the elapsed time. This benchmark was then run on multiple devices and multiple browsers\n            to figure out performance characteristics. The ultimate goal of this test is to figure out the absolute best performance\n            that can be extracted from the most minimal web component.\n        </p>\n\n        <p>To get a performance range I used two devices for testing:</p>\n        <ul>\n            <li>A <em>Macbook Air M1</em> running MacOS, to stand in as the \"fast\" device, comparable to a new high end iPhone.</li>\n            <li>An <em>Asus Chi T300 Core M</em> from 2015 running Linux Mint Cinnamon, to stand in as the \"slow\" device, comparable to an older low end Android.</li>\n        </ul>\n        <p>Between these devices is a 7x CPU performance gap.</p>\n\n        <h3>The test</h3>\n\n        <p>\n            The test is simple: render thousands of components using a specific technique, \n            call <code>requestAnimationFrame()</code> repeatedly until they actually render,\n            then measure elapsed time. This produces a <em>components per millisecond</em> number.\n        </p>\n        <p>The techniques being compared:</p>\n        <ul>\n            <li><strong>innerHTML:</strong> each web component renders its content by assigning to <code>this.innerHTML</code></li>\n            <li><strong>append:</strong> each web component creates the span using <code>document.createElement</code> and then appends it to itself</li>\n            <li><strong>append (buffered):</strong> same as the append method, except all web components are first buffered to a document fragment which is then appended to the DOM</li>\n            <li><strong>shadow + innerHTML:</strong> the same as innerHTML, except each component has a shadow DOM</li>\n            <li><strong>shadow + append:</strong> the same as append, except each component has a shadow DOM</li>\n            <li><strong>template + append:</strong> each web component renders its content by cloning a template and appending it</li>\n            <li><strong>textcontent:</strong> each web component directly sets its textContent property, instead of adding a span (making the component itself be the span)\n            </li><li><strong>direct:</strong> appends spans instead of custom elements, to be able to measure custom element overhead</li>\n            <li><strong>lit:</strong> each web component is rendered using the lit framework, in the way that its documentation recommends</li>\n            <li><strong>react pure:</strong> rendering in React as a standard React component, to have a baseline for comparison to mainstream web development</li>\n            <li><strong>react + wc:</strong> each React component wraps the append-style web component</li>\n            <li><strong>(norender):</strong> same as other strategies, except the component is only created but not added to the DOM, to separate out component construction cost</li>\n        </ul>\n        <p>\n            This test was run on M1 in Brave, Chrome, Edge, Firefox and Safari. And on Chi in Chrome and Firefox.\n            It was run for 10 iterations and a geometric mean was taken of the results.\n        </p>\n\n        <h3>The results</h3>\n\n        <p>First, let's compare techniques. The number here is components per millisecond, so <strong>higher is better</strong>.</p>\n        \n        <p><strong>Author's note:</strong> the numbers from the previous version of this article are <del>crossed out</del>.</p>\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">Chrome on M1</th></tr>\n                <tr><th>technique</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>innerHTML</td><td><del>143</del> 135</td></tr>\n                <tr><td>append</td><td><del>233</del> 239</td></tr>\n                <tr><td>append (buffered)</td><td><del>228</del> 239</td></tr>\n                <tr><td>shadow + innerHTML</td><td><del>132</del> 127</td></tr>\n                <tr><td>shadow + append</td><td><del>183</del> 203</td></tr>\n                <tr><td>template + append</td><td><del>181</del> 198</td></tr>\n                <tr><td>textcontent</td><td>345</td></tr>\n                <tr><td>direct</td><td>461</td></tr>\n                <tr><td>lit</td><td><del>133</del> 137</td></tr>\n                <tr><td>react pure</td><td><del>275</del> 338</td></tr>\n                <tr><td>react + wc</td><td><del>172</del> 212</td></tr>\n                <tr><td>append (norender)</td><td>1393</td></tr>\n                <tr><td>shadow (norender)</td><td>814</td></tr>\n                <tr><td>direct (norender)</td><td>4277</td></tr>\n                <tr><td>lit (norender)</td><td>880</td></tr>\n            </tbody>\n        </table>\n\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">Chrome on Chi, best of three</th></tr>\n                <tr><th>technique</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>innerHTML</td><td><del>25</del> 29</td></tr>\n                <tr><td>append</td><td><del>55</del> 55</td></tr>\n                <tr><td>append (buffered)</td><td><del>56</del> 59</td></tr>\n                <tr><td>shadow + innerHTML</td><td><del>24</del> 26</td></tr>\n                <tr><td>shadow + append</td><td><del>36</del> 47</td></tr>\n                <tr><td>template + append</td><td><del>45</del> 46</td></tr>\n                <tr><td>textcontent</td><td>81</td></tr>\n                <tr><td>direct</td><td>116</td></tr>\n                <tr><td>lit</td><td><del>30</del> 33</td></tr>\n                <tr><td>react pure</td><td><del>77</del> 87</td></tr>\n                <tr><td>react + wc</td><td><del>45</del> 52</td></tr>\n                <tr><td>append (norender)</td><td>434</td></tr>\n                <tr><td>shadow (norender)</td><td>231</td></tr>\n                <tr><td>direct (norender)</td><td>1290</td></tr>\n                <tr><td>lit (norender)</td><td>239</td></tr>\n            </tbody>\n        </table>\n\n        <p>\n            One relief right off the bat is that even the slowest implementation on the slow device renders 100.000 components in 4 seconds.\n            React is roughly in the same performance class as well-written web components.\n            That means for a typical web app performance is not a reason to avoid web components.\n        </p>\n        <aside>\n            <h3>Author's note</h3>\n            <p>\n                The previous version of this article said React was faster than web components,\n                but this only the case if we make the web components render a span. Unlike a React component a web component\n                is itself part of the DOM, and so is itself the equivalent of a span. The <em>textcontent</em> strategy exploits this advantage\n                to functionally do the same as the React code, and it matches its performance.\n            </p>\n        </aside>\n\n        <p>\n            As far as web component technique goes, the performance delta between the fastest and the slowest technique is around 2x,\n            so again for a typical web app that difference will not matter. Things that slow down web components\n            are shadow DOM and innerHTML. Appending directly created elements or cloned templates and avoiding shadow DOM is the right strategy\n            for a well-performing web component that needs to end up on the page thousands of times.\n        </p>\n\n        <p>\n            On the slow device the Lit framework is a weak performer, probably due to its use of shadow DOM and JS-heavy approaches.\n            Meanwhile, pure React is the best performer, because while it does more work in creating the virtual DOM and diffing it to the real DOM,\n            it benefits from not having to initialize the web component class instances.\n            Consequently, when wrapping web components inside React components we see React's performance advantage disappear, and that it adds a performance tax.\n            In the grand scheme of things however, the differences between React and optimized web components remains small.\n        </p>\n\n        <p>\n            The fast device is up to 5x faster than the slow device in Chrome, depending on the technique used,\n            so it is really worth testing applications on slow devices to get an idea of the range of performance.\n        </p>\n\n        <p>\n            Next, let's compare browsers:\n        </p>\n\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">M1, append, best of three</th></tr>\n                <tr><th>browser</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>Brave</td><td><del>146</del> 145</td></tr>\n                <tr><td>Chrome</td><td><del>233</del> 239</td></tr>\n                <tr><td>Edge</td><td><del>224</del> 237</td></tr>\n                <tr><td>Firefox</td><td><del>232</del> 299</td></tr>\n                <tr><td>Safari</td><td><del>260</del> 239</td></tr>\n            </tbody>\n        </table>\n\n        <table>\n            <thead>\n                <tr><th colspan=\"2\">Chi, append, best of three</th></tr>\n                <tr><th>browser</th><th>components/ms</th></tr>\n            </thead>\n            <tbody>\n                <tr><td>Chrome</td><td><del>55</del> 55</td></tr>\n                <tr><td>Firefox</td><td><del>180</del> 77</td></tr>\n            </tbody>\n        </table>\n\n        <p>\n            Brave is really slow, probably because of its built-in ad blocking. Ad blocking extensions also slow down the other browsers by a lot.\n            Safari, Chrome and Edge end up in roughly the same performance bucket. Firefox is the best performer overall.\n            Using the \"wrong\" browser can halve the performance of a machine.\n        </p>\n        <p>\n            <strong>Author's note:</strong>\n            due to a measurement error in measuring elapsed time, the previous version of this article had Safari as fastest and Firefox as middle of the pack.\n        </p>\n        <p>\n            There is a large performance gap when you compare the slowest technique on the slowest browser on the slowest device,\n            with its fastest opposite combo. Specifically, there is a 16x performance gap:\n        </p>\n        <ul>\n            <li>textContent, Firefox on M1: 430 components/ms</li>\n            <li>Shadow DOM + innerHTML, Chrome on Chi: 26 components/ms</li>\n        </ul>\n        <p>\n            That means it becomes worthwhile to carefully consider technique when having to support a wide range of browsers and devices,\n            because a bad combination may lead to a meaningfully degraded user experience.\n            And of course, you should always test your web app on a slow device to make sure it still works ok.\n        </p>\n        \n        <h3>Bottom line</h3>\n\n        <p>\n            I feel confident now that web components can be fast enough for almost all use cases where someone might consider React instead.\n        </p>\n        <p>\n            However, it does matter how they are built. Shadow DOM should not be used for smaller often used web components,\n            and the contents of those smaller components should be built using append operations instead of innerHTML.\n            The use of web component frameworks might impact their performance significantly,\n            and given how easy it is to write vanilla web components I personally don't see the point behind Lit or Stencil. YMMV.\n        </p>\n\n        <p>\n            The full benchmark code and results can be <a href=\"https://github.com/jsebrech/vanilla-benchmarks\">found on Github</a>.\n        </p>\n\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[A unix philosophy for web development]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-09-03-unix-philosophy/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-09-03-unix-philosophy/</id>\n        <published>2024-09-03T12:00:00.000Z</published>\n        <updated>2024-09-03T12:00:00.000Z</updated>\n        <summary><![CDATA[Maybe all web components need to be a light-weight framework is the right set of helper functions.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-09-03-unix-philosophy/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            Web components have their malcontents. While frameworks have done their best to provide\n            a place for web components to fit into their architecture, the suit never fits quite right,\n            and framework authors have not been shy about expressing their disappointment.\n            Here's Ryan Carniato of SolidJS explaining what's wrong with web components:\n        </p>\n        <blockquote>\n            The collection of standards (Custom Elements, HTML Templates, Shadow DOM, and formerly HTML Imports) \n            put together to form Web Components on the surface seem like they could be used to replace \n            your favourite library or framework. But they are not an advanced templating solution. \n            They don't improve your ability to render or update the DOM. \n            They don't manage higher-level concerns for you like state management.\n        </blockquote>\n        <cite><a href=\"https://dev.to/ryansolid/maybe-web-components-are-not-the-future-hfh\">Ryan Carniato</a></cite>\n        <p>\n            While this criticism is true, perhaps it's besides the point.\n            Maybe web components were never meant to solve those problems anyway.\n            Maybe there are ways to solve those problems in a way that dovetails with web components as they exist.\n            In the main <a href=\"../../../pages/components.html\">components tutorial</a> I've already explained what they <em>can</em> do,\n            now let's see what can be done about the things that they <em>can't</em> do.\n        </p>\n\n        <h3>The Unix Philosophy</h3>\n\n        <p>\n            The Unix operating system carries with it a culture and philosophy of system design,\n            which carries over to the command lines of today's Unix-like systems like Linux and MacOS. \n            This philosophy can be summarized as follows:\n        </p>\n        <ul>\n            <li>Write programs that do one thing and do it well.</li>\n            <li>Write programs to work together.</li>\n            <li>Write programs to handle text streams, because that is a universal interface.</li>\n        </ul>\n        <p>\n            What if we look at the various technologies that comprise web components as just programs, \n            part of a Unix-like system of web development that we collectively call the browser platform?\n            In that system we can do better than text and use the DOM as the universal interface between programs, \n            and we can extend the system with a set of single purpose independent \"programs\" (functions) \n            that fully embrace the DOM by augmenting it instead of replacing it.\n        </p>\n        <p>\n            In a sense this is the most old-school way of building web projects, the one people who \"don't know any better\"\n            automatically gravitate to. What us old-school web developers did before Vue and Solid and Svelte, before Angular and React,\n            before Knockout and Ember and Backbone, before even jQuery, was have a bunch of functions in <code>utilities.js</code>\n            that we copied along from project to project.\n            But, you know, sometimes old things can become new again.\n        </p>\n        <p>\n            In previous posts I've already covered a <code>html()</code> function for <a href=\"../2024-08-25-vanilla-entity-encoding/\">vanilla entity encoding</a>,\n            and a <code>signal()</code> function that provides a <a href=\"../2024-08-30-poor-mans-signals/\">tiny signals</a> implementation \n            that can serve as a lightweight system for state management.\n            That still leaves a missing link between the state managed by the signals and the DOM that is rendered from safely entity-encoded HTML.\n            What we need is a <code>bind()</code> function that can bind data to DOM elements and bind DOM events back to data.\n        </p>\n\n        <h3>Finding inspiration</h3>\n\n        <p>\n            In order to bind a template to data, we need a way of describing that behavior in the HTML markup.\n            Well-trodden paths are often the best starting place to look for inspiration. I like <a href=\"https://vuejs.org/guide/essentials/template-syntax.html\">Vue's template syntax</a>,\n            because it is valid HTML but just augmented, and because it is proven. Vue's templates only pretend to be HTML\n            because they're actually compiled to JavaScript behind the scenes, but let's start there as an API.\n            This is what it looks like:\n        </p>\n        <dl>\n            <dt><code>&lt;img :src=\"imageSrc\" /&gt;</code></dt>\n            <dd>Bind <em>src</em> to track the value of the <em>imageSrc</em> property of the current component.\n                Vue is smart enough to set a property if one exists, and falls back to setting an attribute otherwise.\n                (If that confuses you, read about <a href=\"https://javascript.info/dom-attributes-and-properties\">attributes and properties</a> first.)</dd>\n            <dt><code>&lt;button @click=\"doThis\"&gt;&lt;/button&gt;</code></dt>\n            <dd>Bind the <em>click</em> event to the <em>doThis</em> method of the current component.</dd>\n        </dl>\n        <p>\n            By chance I came across this article about <a href=\"https://hawkticehurst.com/2024/05/bring-your-own-base-class/\">making a web component base class</a>.\n            In the section <em>Declarative interactivity</em> the author shows a way to do the Vue-like event binding syntax\n            on a vanilla web component. This is what inspired me to develop the concept into a generic binding function and write this article.\n        </p>\n\n        <h3>Just an iterator</h3>\n\n        <p>\n            The heart of the binding function is an HTML fragment iterator. \n            After all, before we can bind attributes we need to first find the ones that have binding directives.\n        </p>\n        <div><pre><code>export const bind = (template) =&gt; {\n    const fragment = template.content.cloneNode(true);\n    // iterate over all nodes in the fragment\n    const iterator = document.createNodeIterator(\n        fragment,\n        NodeFilter.SHOW_ELEMENT,\n        {\n            // reject any node that is not an HTML element\n            acceptNode: (node) =&gt; {\n                if (!(node instanceof HTMLElement))\n                    return NodeFilter.FILTER_REJECT;\n                return NodeFilter.FILTER_ACCEPT;\n            },\n        }\n    );\n    let node;\n    while (node = iterator.nextNode()) {\n        if (!node) return;\n        const elem = node;\n        for (const attr of Array(...node.attributes)) {\n            // check for event binding directive\n            if (attr.name.startsWith('@')) {\n\n                // TODO: bind event ...\n                \n                elem.removeAttributeNode(attr);\n            // check for property/attribute binding directive\n            } else if (attr.name.startsWith(':')) {\n                \n                // TODO: bind data ...\n                \n                elem.removeAttributeNode(attr);\n            }\n        }\n    }\n    return fragment;\n}</code></pre></div>\n        <p>\n            This code will take an <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template\">HTML template element</a>, \n            clone it to a <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment\">document fragment</a>, \n            and then iterate over all the nodes in the fragment, discovering their attributes. \n            Then for each attribute a check is made to see if it's a binding directive (@ or :). \n            The node is then bound to data according to the directive attribute (shown here as TODO's), \n            and the attribute is removed from the node. At the end the bound fragment is returned for inserting into the DOM.\n        </p>\n        <p>\n            The benefit of using a fragment is that it is disconnected from the main DOM, while still offering all of the DOM API's. \n            That means we can easily create a node iterator to walk over it and discover all the attributes \n            with binding directives, modify those nodes and attributes in-place, and still be sure we're not causing \n            DOM updates in the main page until the fragment is inserted there. This makes the bind function very fast.\n        </p>\n        <p>\n            If you're thinking \"woah dude, that's a lot of code and a lot of technobabble, I ain't reading all that,\"\n            then please, I implore you to read through the code line by line, and you'll see it will all make sense.\n        </p>\n        <p>\n            Of course, we also need to have something to bind <em>to</em>, so we need to add a second parameter.\n            At the same time, it would be nice to just be able to pass in a string and have it auto-converted into a template.\n            The beginning of our bind function then ends up looking like this:\n        </p>\n        <div><pre><code>export const bind = (template, target) =&gt; {\n    if (!template.content) {\n        const text = template;\n        template = document.createElement('template');\n        template.innerHTML = text;\n    }\n    const fragment = template.content.cloneNode(true);\n// ...\n}</code></pre></div>\n        <p>That just leaves us the TODO's. We can make those as simple or complicated as we want. I'll pick a middle ground.</p>\n\n        <h3>Binding to events</h3>\n\n        <p>This 20 line handler binds events to methods, signals or properties:</p>\n        <div><pre><code>// check for custom event listener attributes\nif (attr.name.startsWith('@')) {\n    const event = attr.name.slice(1);\n    const property = attr.value;\n    let listener;\n    // if we're binding the event to a function, call it directly\n    if (typeof target[property] === 'function') {\n        listener = target[property].bind(target);\n    // if we're binding to a signal, set the signal's value\n    } else if (typeof target[property] === 'object' &amp;&amp; \n                typeof target[property].value !== 'undefined') {\n        listener = e =&gt; target[property].value = e.target.value;\n    // fallback: assume we're binding to a property, set the property's value\n    } else {\n        listener = e =&gt; target[property] = e.target.value;\n    }\n    elem.addEventListener(event, listener);\n    // remove (non-standard) attribute from element\n    elem.removeAttributeNode(attr);\n}</code></pre></div>\n\n        <p>That probably doesn't explain much, so let me give an example of what this enables:</p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-03-unix-philosophy/example-bind3/example.html\">Binding to events example</a></p>\n        <div><pre><code>import { bind } from './bind.js';\nimport { signal } from './signals.js';\n\ncustomElements.define('x-example', class Example extends HTMLElement {\n\n    set a(value) { \n        this.setAttribute('a', value);\n        this.querySelector('label[for=a] span').textContent = value;\n    }\n    set b(value) {\n        this.setAttribute('b', value);\n        this.querySelector('label[for=b] span').textContent = value;\n    }\n    c = signal('');\n\n    connectedCallback() {\n        this.append(bind(`\n            &lt;div&gt;\n                &lt;input id=\"a\" type=\"number\" @input=\"onInputA\"&gt;\n                &lt;label for=\"a\"&gt;A = &lt;span&gt;&lt;/span&gt;&lt;/label&gt;\n            &lt;/div&gt;\n            &lt;div&gt;\n                &lt;input id=\"b\" type=\"number\" @input=\"b\"&gt;\n                &lt;label for=\"b\"&gt;B = &lt;span&gt;&lt;/span&gt;&lt;/label&gt;\n            &lt;/div&gt;\n            &lt;div&gt;\n                &lt;input id=\"c\" type=\"number\" @input=\"c\"&gt;\n                &lt;label for=\"c\"&gt;C = &lt;span&gt;&lt;/span&gt;&lt;/label&gt;\n            &lt;/div&gt;\n            &lt;button @click=\"onClick\"&gt;Add&lt;/button&gt;\n            &lt;div&gt;Result: &lt;span id=\"result\"&gt;&lt;/span&gt;&lt;/div&gt;\n        `, this));\n        this.c.effect(() =&gt; \n            this.querySelector('label[for=c] span').textContent = this.c);\n    }\n\n    onInputA (e) {\n        this.a = e.target.value;\n    }\n\n    onClick() {\n        this.querySelector('#result').textContent =\n            +this.getAttribute('a') + +this.getAttribute('b') + +this.c;\n    }\n});\n</code></pre></div>\n\n        <ul>\n            <li><code>input#a</code>'s input event is handled by calling the <code>onClickA()</code> method.</li>\n            <li><code>input#b</code>'s input event is handled by assigning <code>e.target.value</code> to the <code>b</code> property.</li>\n            <li><code>input#c</code>'s input event is handled by setting the value of the <code>c</code> signal.</li>\n        </ul>\n        <p>\n            If you're not familiar with the <code>signal()</code> function, check out the <a href=\"../2024-08-30-poor-mans-signals/\">tiny signals</a> \n            implementation in the previous post. For now you can also just roll with it.\n        </p>\n        <p>Not a bad result for 20 lines of code.</p>\n\n        <h3>Binding to data</h3>\n        <p>\n            Having established the pattern for events that automatically update properties, \n            we now reverse the polarity to make data values automatically set element properties or attributes.\n        </p>\n        <div><pre><code>// ...\n    if (attr.name.startsWith(':')) {\n        // extract the name and value of the attribute/property\n        let name = attr.name.slice(1);\n        const property = getPropertyForAttribute(name, target);\n        const setter = property ?\n            () =&gt; elem[property] = target[attr.value] :\n            () =&gt; elem.setAttribute(name, target[attr.value]);\n        setter();\n        // if we're binding to a signal, listen to updates\n        if (target[attr.value]?.effect) {\n            target[attr.value].effect(setter);\n        // if we're binding to a property, listen to the target's updates\n        } else if (target.addEventListener) {\n            target.addEventListener('change', setter);\n        }\n        // remove (non-standard) attribute from element\n        elem.removeAttributeNode(attr);\n    }\n// ...\n\nfunction getPropertyForAttribute(name, obj) {\n    switch (name.toLowerCase()) {\n        case 'text': case 'textcontent':\n            return 'textContent';\n        case 'html': case 'innerhtml':\n            return 'innerHTML';\n        default:\n            for (let prop of Object.getOwnPropertyNames(obj)) {\n                if (prop.toLowerCase() === name.toLowerCase()) {\n                    return prop;\n                }\n            }   \n    }\n}</code></pre></div>\n        <p>\n            The <code>getPropertyForAttribute</code> function is necessary because the attributes that contain the directives\n            will have names that are case-insensitive, and these must be mapped to property names that are case-sensitive.\n            Also, the <code>:text</code> and <code>:html</code> shorthand notations replace the role of <code>v-text</code>\n            and <code>v-html</code> in Vue's template syntax.\n        </p>\n        <p>\n            When the value of the target's observed property changes, we need to update the bound element's property or attribute.\n            This means a triggering <code>'change'</code> event is needed that is then subscribed to.\n            A framework's templating system will compare state across time, and detect the changed values automatically. \n            Lacking such a system we need a light-weight alternative.\n        </p>\n        <p>\n            When the property being bound to is a signal, this code registers an effect on the signal.\n            When the property is just a value, it registers an event listener on the target object,\n            making it the responsibility of that target object to dispatch the <code>'change'</code> event when values change.\n            This approach isn't going to get many points for style, but it does work.\n        </p>\n        <p>\n            Check out the <a href=\"example-combined/bind.js\">completed bind.js</a> code.\n        </p>\n\n        <h3>Bringing the band together</h3>\n\n        <p>\n            In the article <a href=\"https://dev.to/richharris/why-i-don-t-use-web-components-2cia\">Why I don't use web components</a> \n            Svelte's Rich Harris lays out the case against web components. He demonstrates how this simple 9 line Svelte component\n            <code>&lt;Adder a={1} b={2}/&gt;</code> becomes an incredible verbose 59 line monstrosity when ported to a vanilla web component.\n        </p>\n        <div><pre><code>&lt;script&gt;\n  export let a;\n  export let b;\n&lt;/script&gt;\n\n&lt;input type=\"number\" bind:value={a}&gt;\n&lt;input type=\"number\" bind:value={b}&gt;\n\n&lt;p&gt;{a} + {b} = {a + b}&lt;/p&gt;</code></pre></div>\n\n        <p>\n            Now that we have assembled our three helper functions <code>html()</code>, <code>signal()</code> and <code>bind()</code>\n            on top of the web components baseline, at a total budget of around 150 lines of code, how close can we get for a web component <code>&lt;x-adder a=\"1\" b=\"2\"&gt;&lt;/x-adder&gt;</code>?\n        </p>\n        <div><pre><code>import { bind } from './bind.js';\nimport { signal, computed } from './signals.js';\nimport { html } from './html.js';\n\ncustomElements.define('x-adder', class Adder extends HTMLElement {\n    a = signal();\n    b = signal();\n    result = computed(() =&gt; \n        html`${+this.a} + ${+this.b} = ${+this.a + +this.b}`, [this.a, this.b]);\n\n    connectedCallback() {\n        this.a.value ??= this.getAttribute('a') || 0;\n        this.b.value ??= this.getAttribute('b') || 0;\n        this.append(bind(html`\n            &lt;input type=\"number\" :value=\"a\" @input=\"a\" /&gt;\n            &lt;input type=\"number\" :value=\"b\" @input=\"b\" /&gt;\n            &lt;p :html=\"result\"&gt;&lt;/p&gt;\n        `, this));\n    }\n});\n</code></pre></div>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-09-03-unix-philosophy/example-combined/example.html\">combined example</a></p>\n\n        <p>\n            To be fair, that's still twice the lines of code, but it describes clearly what it does, and really that is all you need. \n            And I'm just shooting in the wind here, trying stuff out.\n            Somewhere out there could be a minimal set of functions that transforms web components into something resembling a framework,\n            and the idea excites me! Who knows, maybe in a few years the web community will return to writing projects in \n            vanilla web code, dragging along the modern equivalent of <code>utilities.js</code> from project to project...\n        </p>\n        <br>\n        <p><em>What do you think?</em></p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Poor man's signals]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-08-30-poor-mans-signals/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-08-30-poor-mans-signals/</id>\n        <published>2024-08-30T12:00:00.000Z</published>\n        <updated>2024-08-30T12:00:00.000Z</updated>\n        <summary><![CDATA[Signals are all the rage over in frameworkland, so let's bring them to vanilla JS.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-08-30-poor-mans-signals/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <p>\n            Signals are all the rage right now. Everyone's doing them.\n            <a href=\"https://angular.dev/guide/signals\">Angular</a>,\n            and <a href=\"https://docs.solidjs.com/concepts/signals\">Solid</a>,\n            and <a href=\"https://preactjs.com/guide/v10/signals/\">Preact</a>,\n            and there are third party packages for just about every framework that doesn't already have them.\n            There's even a <a href=\"https://github.com/tc39/proposal-signals\">proposal</a>\n            to add them to the language, and if that passes it's just a \n            <a href=\"https://thenewstack.io/did-signals-just-land-in-react/\">matter of time</a> before all frameworks \n            have them built in.\n        </p>\n\n        <h3>Living under a rock</h3>\n        <p>\n            In case you've been living under a rock, here's the example from Preact's documentation \n            that neatly summarizes what signals do:\n        </p>\n        <div><pre><code>import { signal, computed, effect } from \"@preact/signals\";\n\nconst name = signal(\"Jane\");\nconst surname = signal(\"Doe\");\nconst fullName = computed(() =&gt; `${name.value} ${surname.value}`);\n\n// Logs name every time it changes:\neffect(() =&gt; console.log(fullName.value));\n// Logs: \"Jane Doe\"\n\n// Updating `name` updates `fullName`, which triggers the effect again:\nname.value = \"John\";\n// Logs: \"John Doe\"\n</code></pre></div>\n        <p>\n            Simply put, signals wrap values and computations \n            in a way that allows us to easily respond to every change to those values and results in a targeted way,\n            without having to rerender the entire application in the way that we would do in React.\n            In short, signals are an efficient and targeted way to respond to changes without having to do state comparison and DOM-diffing.\n        </p>\n        <p>\n            OK, so, if signals are so great, why am I trying to sell you on them on a vanilla web development blog?\n            Don't worry! Vanilla web developers can have signals too.\n        </p>\n\n        <h3>Just a wrapper</h3>\n        <p>\n            Signals are at heart nothing more than a wrapper for a value that sends events when the value changes.\n            That's nothing that a little trickery with the not well known but very handy <code>EventTarget</code> base class can't fix for us.\n        </p>\n        <div><pre><code>class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n}</code></pre></div>\n        <p>\n            This gets us a very barebones signals experience:\n        </p>\n        <div><pre><code>const name = new Signal('Jane');\nname.addEventListener('change', () =&gt; console.log(name.value));\nname.value = 'John';\n// Logs: John</code></pre></div>\n        <p>\n            But that's kind of ugly. The <code>new</code> keyword went out of fashion a decade ago,\n            and that <code>addEventListener</code> sure is unwieldy.\n            So let's add a little syntactic sugar.\n        </p>\n        <div><pre><code>class Signal extends EventTarget {\n    #value;\n    get value () { return this.#value; }\n    set value (value) {\n        if (this.#value === value) return;\n        this.#value = value;\n        this.dispatchEvent(new CustomEvent('change')); \n    }\n\n    constructor (value) {\n        super();\n        this.#value = value;\n    }\n\n    effect(fn) {\n        fn();\n        this.addEventListener('change', fn);\n        return () =&gt; this.removeEventListener('change', fn);\n    }\n\n    valueOf () { return this.#value; }\n    toString () { return String(this.#value); }\n}\n\nconst signal = _ =&gt; new Signal(_);\n</code></pre></div>\n        <p>\n            Now our barebones example is a lot nicer to use:\n        </p>\n        <div><pre><code>const name = signal('Jane');\nname.effect(() =&gt; console.log(name.value));\n// Logs: Jane\nname.value = 'John';\n// Logs: John</code></pre></div>\n        <p>\n            The <code>effect(fn)</code> method will call the specified function,\n            and also subscribe it to changes in the signal's value.\n        </p>\n        <p>\n            It also returns a dispose function that can be used to unregister the effect.\n            However, a nice side effect of using <code>EventTarget</code> and browser built-in events as the reactivity primitive\n            is that it makes the browser smart enough to garbage collect the signal and its effect when the signal goes out of scope.\n            This means less chance for memory leaks even if we never call the dispose function.\n        </p>\n        <p>\n            Finally, the <code>toString</code> and <code>valueOf</code> magic methods allow for dropping <code>.value</code> in most places\n            that the signal's value gets used. (But not in this example, because the console is far too clever for that.)\n        </p>\n\n        <h3>Does not compute</h3>\n        <p>\n            This signals implementation is already capable, but at some point it might be handy to have an effect based on more than one signal.\n            That means supporting computed values. Where the base signals are a wrapper around a value,\n            computed signals are a wrapper around a function.\n        </p>\n        <div><pre><code>class Computed extends Signal {\n    constructor (fn, deps) {\n        super(fn(...deps));\n        for (const dep of deps) {\n            if (dep instanceof Signal) \n                dep.addEventListener('change', () =&gt; this.value = fn(...deps));\n        }\n    }\n}\n\nconst computed = (fn, deps) =&gt; new Computed(fn, deps);\n</code></pre></div>\n        <p>\n            The computed signal calculates its value from a function.\n            It also depends on other signals, and when they change it will recompute its value.\n            It's a bit obnoxious to have to pass the signals that it depends on\n            as an additional parameter, but hey, I didn't title this article <em>Rich man's signals</em>.\n        </p>\n        <p>\n            This enables porting Preact's signals example to vanilla JS.\n        </p>\n        <div><pre><code>const name = signal('Jane');\nconst surname = signal('Doe');\nconst fullName = computed(() =&gt; `${name} ${surname}`, [name, surname]);\n// Logs name every time it changes:\nfullName.effect(() =&gt; console.log(fullName.value));\n// -&gt; Jane Doe\n\n// Updating `name` updates `fullName`, which triggers the effect again:\nname.value = 'John';\n// -&gt; John Doe\n</code></pre></div>\n\n        <h3>Can you use it in a sentence?</h3>\n        <p>\n            You may be thinking, all these <code>console.log</code> examples are fine and dandy,\n            but how do you use this stuff in actual web development?\n            This simple adder demonstrates how signals can be combined with web components:\n        </p>\n        <div><pre><code>import { signal, computed } from './signals.js';\n\ncustomElements.define('x-adder', class extends HTMLElement {\n    a = signal(1);\n    b = signal(2);\n    result = computed((a, b) =&gt; `${a} + ${b} = ${+a + +b}`, [this.a, this.b]);\n\n    connectedCallback() {\n        if (this.querySelector('input')) return;\n\n        this.innerHTML = `\n            &lt;input type=\"number\" name=\"a\" value=\"${this.a}\"&gt;\n            &lt;input type=\"number\" name=\"b\" value=\"${this.b}\"&gt;\n            &lt;p&gt;&lt;/p&gt;\n        `;\n        this.result.effect(\n            () =&gt; this.querySelector('p').textContent = this.result);\n        this.addEventListener('input', \n            e =&gt; this[e.target.name].value = e.target.value);\n    }\n});\n</code></pre></div>\n        <p>\n            And here's a live demo:\n        </p>\n        <p><a href=\"https://plainvanillaweb.com/blog/articles/2024-08-30-poor-mans-signals/adder.html\">adder.html</a></p>\n        <p>\n            In case you were wondering, the <code>if</code> is there to prevent adding the effect twice\n            if connectedCallback is called when the component is already rendered.\n        </p>\n        <p>\n            The full poor man's signals code in all its 36 line glory can be found in the <a href=\"https://github.com/jsebrech/tiny-signals/\">tiny-signals repo</a> on Github.\n        </p>\n    ]]></content>\n    </entry>\n    <entry>\n        <title><![CDATA[Vanilla entity encoding]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"https://plainvanillaweb.com/blog/articles/2024-08-25-vanilla-entity-encoding/\"/>\n        <id>https://plainvanillaweb.com/blog/articles/2024-08-25-vanilla-entity-encoding/</id>\n        <published>2024-08-25T12:00:00.000Z</published>\n        <updated>2024-08-25T12:00:00.000Z</updated>\n        <summary><![CDATA[The first version of this site didn't use entity encoding in the examples. Now it does.]]></summary>\n        <media:content url=\"https://plainvanillaweb.com/blog/articles/2024-08-25-vanilla-entity-encoding/image.webp\" type=\"image/webp\" medium=\"image\" />\n        <author><name><![CDATA[Joeri Sebrechts]]></name></author>\n        <content type=\"html\"><![CDATA[\n        <h3>Good enough</h3>\n        <p>\n            When I made the first version of the Plain Vanilla website, there were things that I would have liked\n            to spend more time on, but that I felt didn't belong in a Good Enough™ version of the site.\n            One of those things was defending against <a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\">Cross-Site Scripting</a> (XSS).\n        </p>\n        <p>\n            XSS is still in the <a href=\"https://owasp.org/www-project-top-ten/\">OWASP Top Ten</a> of security issues, \n            but it's no longer as prevalent as it used to be. Frameworks have built in a lot of defenses, \n            and when using their templating systems you have to go out of your way to inject code into the generated HTML.\n            When eschewing frameworks we're reduced to standard templating in our web components, and those offer no defense against XSS.\n        </p>\n        <p>\n            Because of this, in the original site the <a href=\"https://plainvanillaweb.com/pages/components.html#passing-data\">Passing Data example</a> \n            on the <em>Components</em> page had an undocumented XSS bug.\n            The <em>name</em> field could have scripts injected into it. I felt ambivalent about leaving that bug in.\n            On the one hand, the code was very compact and neat by leaving it in.\n            On the other hand it made that code a bad example that shouldn't be copied.\n            I ended up choosing to leave it as-is because an example doesn't have to be production-grade\n            and generating properly encoded HTML was not the point of that specific example.\n            It's time however to circle back to that XSS bug and figure out how it would have been solved in a clean and readable way,\n            if Santa really did want to bring his List application to production-level quality.\n        </p>\n\n        <h3>The problem</h3>\n        <p>\n            The basic problem we need to solve is that vanilla web components end up having a lot of code that looks like this:\n        </p>\n        <div><pre><code>class MyComponent extends HTMLElement {\n    connectedCallback() {\n        const btn = `&lt;button&gt;${this.getAttribute('foo')}&lt;/button&gt;`;\n        this.innerHTML = `\n            &lt;header&gt;&lt;h1&gt;${this.getAttribute('bar')}&lt;/h1&gt;&lt;/header&gt;\n            &lt;article&gt;\n                &lt;p class=\"${this.getAttribute('baz')}\"&gt;${this.getAttribute('xyzzy')}&lt;/p&gt;\n                ${btn}\n            &lt;/article&gt;\n        `;\n    }\n}\ncustomElements.define('my-component', MyComponent);</code></pre></div>\n        <p>\n            If any of <code>foo</code>, <code>bar</code>, <code>baz</code> or <code>xyzzy</code> contain one of the dangerous HTML entities,\n            we risk seeing our component break, and worst-case risk seeing an attacker inject a malicious payload into the page.\n            Just as a reminder, those dangerous HTML entities are &lt;, &gt;, &amp;, ' and \".\n        </p>\n\n        <h3>The fix, take one</h3>\n        <p>\n            A naive fix is creating a html-encoding function and using it consistently:\n        </p>\n        <div><pre><code>function htmlEncode(s) {\n    return s.replace(/[&amp;&lt;&gt;'\"]/g,\n        tag =&gt; ({\n            '&amp;': '&amp;amp;',\n            '&lt;': '&amp;lt;',\n            '&gt;': '&amp;gt;',\n            \"'\": '&amp;#39;',\n            '\"': '&amp;quot;'\n        }[tag]))\n}\n\nclass MyComponent extends HTMLElement {\n    connectedCallback() {\n        const btn = `&lt;button&gt;${htmlEncode(this.getAttribute('foo'))}&lt;/button&gt;`;\n        this.innerHTML = `\n            &lt;header&gt;&lt;h1&gt;${htmlEncode(this.getAttribute('bar'))}&lt;/h1&gt;&lt;/header&gt;\n            &lt;article&gt;\n                &lt;p class=\"${htmlEncode(this.getAttribute('baz'))}\"&gt;${htmlEncode(this.getAttribute('xyzzy'))}&lt;/p&gt;\n                ${btn}\n            &lt;/article&gt;\n        `;\n    }\n}\ncustomElements.define('my-component', MyComponent);</code></pre></div>\n        <p>\n            While this does work to defend against XSS, it is verbose and ugly, not pleasant to type and not pleasant to read.\n            What really kills it though, is that it assumes attention to detail from us messy humans. We can never forget,\n            never ever, to put a <code>htmlEncode()</code> around each and every variable.\n            In the real world, that is somewhat unlikely.\n        </p>\n        <p>\n            What is needed is a solution that allows us to forget about entity encoding, by doing it automatically\n            when we're templating. I drew inspiration from templating libraries that work in-browser and are based on tagged templates, \n            like <a href=\"https://lit.dev/docs/api/templates/#html\">lit-html</a> \n            and <a href=\"https://github.com/developit/htm\">htm</a>. The quest was on to build the most minimalistic\n            html templating function that encoded entities automatically.\n        </p>\n\n        <h3>The fix, take two</h3>\n        <p>\n            Ideally, the fixed example should look more like this:\n        </p>\n        <div><pre><code>import { html } from './html.js';\n\nclass MyComponent extends HTMLElement {\n    connectedCallback() {\n        const btn = html`&lt;button&gt;${this.getAttribute('foo')}&lt;/button&gt;`;\n        this.innerHTML = html`\n            &lt;header&gt;&lt;h1&gt;${this.getAttribute('bar')}&lt;/h1&gt;&lt;/header&gt;\n            &lt;article&gt;\n                &lt;p class=\"${this.getAttribute('baz')}\"&gt;${this.getAttribute('xyzzy')}&lt;/p&gt;\n                ${btn}\n            &lt;/article&gt;\n        `;\n    }\n}\ncustomElements.define('my-component', MyComponent);</code></pre></div>\n        <p>\n            The <code>html``</code> <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates\">tagged template function</a> \n            would automatically encode entities, in a way that we don't even have to think about it.\n            Even when we nest generated HTML inside of another template, like with <code>${btn}</code>, it should just magically work.\n            It would be so minimal as to disappear in the background, barely impacting readability, maybe even improving it.\n            You may be thinking that doing that correctly would involve an impressive amount of code. I must disappoint.\n        </p>\n        <div><pre><code>class Html extends String { }\n\n/** \n * tag a string as html not to be encoded\n * @param {string} str\n * @returns {string}\n */\nexport const htmlRaw = str =&gt; new Html(str);\n\n/** \n * entity encode a string as html\n * @param {*} value The value to encode\n * @returns {string}\n */\nexport const htmlEncode = (value) =&gt; {\n    // avoid double-encoding the same string\n    if (value instanceof Html) {\n        return value;\n    } else {\n        // https://stackoverflow.com/a/57448862/20980\n        return htmlRaw(\n            String(value).replace(/[&amp;&lt;&gt;'\"]/g, \n                tag =&gt; ({\n                    '&amp;': '&amp;amp;',\n                    '&lt;': '&amp;lt;',\n                    '&gt;': '&amp;gt;',\n                    \"'\": '&amp;#39;',\n                    '\"': '&amp;quot;'\n                }[tag]))\n        );\n    }\n}\n\n/** \n * html tagged template literal, auto-encodes entities\n */\nexport const html = (strings, ...values) =&gt; \n    htmlRaw(String.raw({ raw: strings }, ...values.map(htmlEncode)));\n</code></pre></div>\n        <p>\n            Those couple dozen lines of code are all that is needed. Let's go through it from top to bottom.\n        </p>\n        <dl>\n            <dt><code>class Html extends String { }</code></dt>\n            <dd>The Html class is used to mark strings as encoded, so that they won't be encoded again.</dd>\n            <dt><code>export const htmlRaw = str =&gt; new Html(str);</code></dt>\n            <dd>Case in point, the htmlRaw function does the marking.</dd>\n            <dt><code>export const htmlEncode = ...</code></dt>\n            <dd>The earlier htmlEncode function is still doing useful work, only this time it will mark the resulting string as HTML, and it won't double-encode.</dd>\n            <dt><code>export const html = ...</code></dt>\n            <dd>The tagged template function that binds it together.</dd>\n        </dl>\n\n        <p>\n            A nice upside of the html template function is that the <em>html-in-template-string</em> Visual Studio Code extension\n            can detect it automatically and will syntax highlight the templated HTML. This is what example 3 looked like after I made it:\n        </p>\n\n        <img src=\"https://plainvanillaweb.com/blog/articles/2024-08-25-vanilla-entity-encoding/syntax-highlighting.webp\" alt=\"example 3 with syntax highlighting\">\n\n        <p>\n            Granted, there's still a bunch of boilerplate here, and that <code>getAttribute</code> gets unwieldy.\n            But with this syntax highlighting enabled sometimes when I'm working on vanilla web components I forget it's not React and JSX, but just HTML and JS.\n            It's surprising how nice of a development experience web standards can be if you embrace them.\n        </p>\n\n        <p>\n            I decided to leave the XSS bug in the <em>Passing Data</em> example, but now the <em>Applications</em> page\n            has an explanation about entity encoding documenting this html template function.\n            I can only hope people that work their way through the tutorial make it that far.\n            For your convenience I also put the HTML templating function in its own separate \n            <a href=\"https://github.com/jsebrech/html-literal\">html-literal repo on Github</a>.\n        </p>\n\n    ]]></content>\n    </entry>\n</feed>"
  },
  {
    "path": "public/blog/generator.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla Generator</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <link rel=\"stylesheet\" href=\"./index.css\">\n    <style>\n        blog-generator {\n            display: block;\n            border: 1px dashed gray;\n            padding: 1em;\n            min-height: 5em;\n            max-height: 90vh;\n            overflow: auto;\n            margin-bottom: 1em;\n        }\n\n        blog-generator pre {\n            border: 1px solid gray;\n            padding: 1em;\n            max-height: 30vh;\n            overflow: auto;\n        }\n\n        blog-generator button {\n            margin-bottom: 0.5em;\n        }\n\n        .warning { color: purple; }\n    </style>\n</head>\n<body>\n    <section>\n        <h1>Generator</h1>\n        <blog-generator></blog-generator>\n        <button onclick=\"document.querySelector('blog-generator').reset()\">Reset</button>\n    </section>\n\n    <section>\n        <h3>Browser support</h3>\n        <ul>\n            <li>Chrome: supported</li>\n            <li>Edge: supported</li>\n            <li>Safari: not supported</li>\n            <li>Firefox: not supported</li>\n            <li>Brave: supported, but first enable File System Access in brave://flags</li>\n            <li>Copy to clipboard: only over HTTPS</li>\n        </ul>\n    </section>\n\n    <script type=\"module\" src=\"./index.js\"></script>\n    <script type=\"module\" src=\"./generator.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "public/blog/generator.js",
    "content": "import { html } from '../lib/html.js';\n\nconst BLOG_BASE_URL = 'https://plainvanillaweb.com/blog/';\n\nconst ATOM_FEED_XML = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\">\n    <title>Plain Vanilla Blog</title>\n    <id>https://plainvanillaweb.com/blog/</id>\n    <icon>https://plainvanillaweb.com/favicon.ico</icon>\n    <logo>https://plainvanillaweb.com/android-chrome-512x512.png</logo>\n    <link rel=\"alternate\" href=\"https://plainvanillaweb.com/blog/\"/>\n    <link rel=\"self\" href=\"https://plainvanillaweb.com/blog/feed.xml\"/>\n    <updated>%UPDATED%</updated>\n    <author>\n        <name>Joeri Sebrechts</name>\n    </author>\n%ENTRIES%\n</feed>`;\n\nconst ATOM_FEED_LENGTH = 20;\n\ncustomElements.define('blog-generator', class BlogGenerator extends HTMLElement {\n\n    #blogFolder;\n    #articles; // [{ slug, title, summary, content, published, image: { src, alt } }]\n\n    reset() {\n        this.#blogFolder = null;\n        this.#articles = [];\n        this.textContent = 'To start: drag the blog folder here, or click to open it with a picker.';\n    }\n\n    showError(text) {\n        this.textContent = '';\n        this.addMessage(text, 'warning');\n    }\n\n    connectedCallback() {\n        this.reset();\n        this.addDragListeners();\n        this.addClickListener();\n    }\n\n    addClickListener() {\n        this.addEventListener('click', () => {\n            if (this.#blogFolder) return;\n            if (!window.showDirectoryPicker) {\n                this.showError('Opening folders with a picker is not supported in your browser.');\n            } else {\n                window.showDirectoryPicker({ \n                    id: 'plain-vanilla-generator', \n                    mode: 'read',\n                    startIn: 'documents'\n                }).then(async (entry) => {\n                    await this.startProcessing(entry);\n                }).catch((e) => {\n                    this.showError(e.message);\n                });\n            }\n        });\n    }\n\n    addDragListeners() {\n        this.addEventListener('dragover', (e) => {\n            // Prevent navigation.\n            e.preventDefault();\n        });\n\n        this.addEventListener('drop', async (e) => {\n            try {\n                // Prevent navigation.\n                e.preventDefault();\n                // Process all of the items.\n                const item = e.dataTransfer.items[0];\n                // Careful: `kind` will be 'file' for both file _and_ directory entries.\n                if (item.kind === 'file') {\n                    if (!item.getAsFileSystemHandle) {\n                        throw new Error('Dropping files is not supported in your browser.');\n                    }\n                    await this.startProcessing(item.getAsFileSystemHandle());\n                }\n            } catch (e) {\n                this.showError(e.message);\n            }\n        });\n    }\n\n    async startProcessing(blogFolder) {\n        this.#blogFolder = await blogFolder;\n        if (this.#blogFolder.kind !== 'directory' || this.#blogFolder.name !== 'blog') {\n            this.#blogFolder = null;\n            throw new Error('That folder is not the blog directory.');\n        }\n\n        this.#articles = [];\n        this.innerHTML = '';\n        this.addMessage('Processing...');\n        const articlesFolder = await this.#blogFolder.getDirectoryHandle('articles');\n        for await (const [key, value] of articlesFolder.entries()) {\n            if (value.kind === 'directory') {\n                this.addMessage(`Parsing ${key}/`);\n                try {\n                    const article = await value.getFileHandle('index.html');\n                    await this.processArticle(article, value);\n                } catch (e) {\n                    if (e.name === 'NotFoundError') {\n                        this.addMessage(`Folder ${key}/ does not have an index.html file, skipping.`, 'warning');\n                        continue;\n                    }\n                    throw new Error('Error processing ' + value.name + ': ' + e.message);\n                }\n            }\n        }\n        \n        // sort articles by published descending\n        this.#articles.sort((a, b) => {\n            return -a.published.localeCompare(b.published);\n        });\n\n        this.addFeedBlock();\n        this.addIndexJsonBlock();\n        this.addSitemapBlock();\n    }\n\n    async processArticle(article, path) {\n        const file = await article.getFile();\n        const html = await file.text();\n        const dom = (new DOMParser()).parseFromString(html, 'text/html');\n        // mandatory\n        const title = dom.querySelector('title').textContent;\n        const summary = dom.querySelector('meta[name=\"description\"]').getAttribute('content');\n        const published = dom.querySelector('blog-header').getAttribute('published');\n        const content = await this.processArticleContent(dom.querySelector('main'), path);\n        const slug = path.name;\n        // optional\n        const img = dom.querySelector('blog-header img');\n        const image = img && { src: img.getAttribute('src'), alt: img.getAttribute('alt') };\n        const updated = dom.querySelector('blog-header').getAttribute('updated') || undefined;\n        const author = dom.querySelector('blog-header p[aria-label=\"author\"]').textContent || undefined;\n\n        this.#articles.push({\n            slug, title, summary, content, published, updated, image, author\n        });\n    }\n\n    async processArticleContent(main, path) {\n        // inline code examples\n        await Promise.all([...main.querySelectorAll('x-code-viewer')].map(async (elem) => {\n            const text = await this.downloadFile(elem.getAttribute('src'), path);\n            const div = document.createElement('div');\n            const name = elem.getAttribute('name');\n            const label = name ? html`<p><em>${name}:</em></p>` : '';\n            div.innerHTML = html`${label}<pre><code>${text}</code></pre>`;\n            elem.replaceWith(div);\n        }));\n\n        // convert img src to absolute url\n        [...main.querySelectorAll('img')].map((elem) => {\n            const src = elem.getAttribute('src');\n            if (src.indexOf('http') !== 0) {\n                elem.setAttribute('src', new URL(`articles/${path.name}/${src}`, BLOG_BASE_URL));\n            }\n        });\n\n        // replace iframes by links\n        [...main.querySelectorAll('iframe')].map((elem) => {\n            const src = elem.getAttribute('src');\n            const title = elem.getAttribute('title') || src;\n            const a = document.createElement('a');\n            a.textContent = title;\n            const p = document.createElement('p');\n            p.appendChild(a);\n            elem.replaceWith(p);\n            if (src.indexOf('http') !== 0) {\n                a.href = new URL(`articles/${path.name}/${src}`, BLOG_BASE_URL);\n            } else {\n                a.href = src;\n            }\n        });\n\n        // strip out unwanted elements\n        [...main.querySelectorAll('[data-rss-exclude]')].map((elem) => elem.remove());\n\n        return main.innerHTML;\n    }\n\n    async downloadFile(file, path) {\n        const parts = await this.#blogFolder.resolve(path);\n        parts.push(file);\n        const url = new URL(parts.join('/'), import.meta.url);\n        return fetch(url).then(res => res.text());\n    }\n\n    addMessage(text, className) {\n        const message = document.createElement('p');\n        message.textContent = text;\n        message.className = className;\n        this.appendChild(message);\n    }\n\n    addFeedBlock() {\n        const lastUpdated = this.#articles.map(a => a.updated || a.published).sort().pop();\n        const xml = ATOM_FEED_XML\n            .replace('%UPDATED%', toISODate(lastUpdated))\n            .replace('%ENTRIES%', this.#articles.slice(0, ATOM_FEED_LENGTH).map(a => {\n                const url = `${BLOG_BASE_URL}articles/${a.slug}/`;\n                const media = a.image ? `<media:content url=\"${new URL(a.image.src, url)}\" type=\"image/${a.image.src.split('.').pop()}\" medium=\"image\" />` : '';\n                const author = a.author ? `<author><name><![CDATA[${a.author}]]></name></author>` : '';\n                return `    <entry>\n        <title><![CDATA[${a.title}]]></title>\n        <link rel=\"alternate\" type=\"text/html\" href=\"${url}\"/>\n        <id>${url}</id>\n        <published>${toISODate(a.published)}</published>\n        <updated>${toISODate(a.updated || a.published)}</updated>\n        <summary><![CDATA[${a.summary}]]></summary>\n        ${media}\n        ${author}\n        <content type=\"html\"><![CDATA[${a.content}]]></content>\n    </entry>`;\n            }).join('\\n'));\n\n        this.addMessage('feed.xml:');\n        const pre = document.createElement('pre');\n        pre.textContent = xml;\n        this.appendChild(pre);\n        pre.scrollIntoView();\n        const button = document.createElement('button');\n        button.onclick = () => navigator.clipboard.writeText(xml);\n        button.textContent = 'Copy feed.xml to clipboard';\n        this.appendChild(button);\n        this.addMessage(' ');\n    }\n\n    addIndexJsonBlock() {\n        const text = JSON.stringify(this.#articles.map(obj => ({ \n            ...obj, \n            content: undefined,\n            image: undefined\n        })), null, 4);\n\n        this.addMessage('articles/index.json:');\n        const pre = document.createElement('pre');\n        pre.textContent = text;\n        this.appendChild(pre);\n        pre.scrollIntoView();\n        const button = document.createElement('button');\n        button.onclick = () => navigator.clipboard.writeText(text);\n        button.textContent = 'Copy index.json to clipboard';\n        this.appendChild(button);\n    }\n\n    addSitemapBlock() {\n        const sitemap = this.#articles.map(a => `${BLOG_BASE_URL}articles/${a.slug}/index.html`).sort().join('\\n');\n        this.addMessage('sitemap.txt:');\n        const pre = document.createElement('pre');\n        pre.textContent = sitemap;\n        this.appendChild(pre);\n        const button = document.createElement('button');\n        button.onclick = () => navigator.clipboard.writeText(sitemap);\n        button.textContent = 'Copy sitemap.txt to clipboard';\n        this.appendChild(button);\n    }\n});\n\nfunction toISODate(date) {\n    if (typeof date === 'string') {\n        // default to publishing at noon UTC\n        if (date.indexOf('T') === -1) {\n            date = date + 'T12:00:00.000Z';\n        }\n        return new Date(date).toISOString();\n    }\n    return date;\n}"
  },
  {
    "path": "public/blog/index.css",
    "content": "@import \"../index.css\";\n\n.cards { \n    padding: 0;\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n    grid-gap: 2em;\n    row-gap: 0;\n    grid-auto-flow: row;\n    grid-auto-rows: minmax(100px, auto);\n}\n\n.card {\n    display: block;\n    position: relative;\n    list-style: none;\n    padding: 1em;\n    margin: 0 -1em;\n    font-size: 0.9em;\n    border-radius: 5px;\n    container-type: inline-size;\n    container-name: card;\n}\n\n.card img {\n    width: 100%;\n    height: 120px;\n    object-fit: cover;\n    margin-bottom: 0.5em;\n}\n\n.card h3 {\n    margin-top: 0;\n    margin-bottom: 0.5em;\n}\n\n.card a {\n    text-decoration: none;\n    color: inherit;\n}\n\n/* make the whole card focusable */\n.card:focus-within {\n    box-shadow: 0 0 0 0.25rem;\n}\n\n.card:focus-within a:focus {\n    text-decoration: none;\n}\n\n/* turn the whole card into the clickable area */\n.card h3 a::after {\n    display: block;\n    position: absolute;\n    content: \"\";\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n}\n\n/* make byline links clickable */\n.card small {\n    position: relative;\n    z-index: 10;\n    color: var(--text-color-mute);\n}\n\n.card small a {\n    text-decoration: underline;\n}\n\n.card small a:hover {\n    color: var(--text-color);\n}\n\n/* for hero cards (full width), move the image to the left */\n@container card ( min-width: 500px ) {\n    .card img {\n        float: left;\n        width: calc(50% - 1em);\n        height: 200px;\n        margin-right: 2em;\n        margin-bottom: 0;\n    }\n}\n\n.archive {\n    text-align: center;\n    color: var(--text-color-mute);\n\n    a:not(:hover) {\n        color: inherit;\n    }\n}\n\n.byline {\n    color: var(--text-color-mute);\n    font-size: 0.8em;\n    margin-bottom: 1.5em;\n}\n\n\nmain img {\n    margin: 0.5em 0;\n}\n\n.comments {\n    margin-top: 2em;\n    text-align: center;\n}\n\n/* header section */\n\nblog-header {\n    display: block;\n    margin-bottom: 1.5em;\n    text-align: left;\n}\n\nblog-header nav {\n    margin-bottom: 2em;\n}\n\nblog-header img {\n    margin-top: 0.5em;\n}\n\n@media screen and (max-width: 600px) {\n    h1 {\n        font-size: 2.2em;\n    }\n}\n\n@media (scripting: none) {\n    blog-header::before {\n        content: 'Please enable scripting to view the navigation'\n    }\n}\n"
  },
  {
    "path": "public/blog/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <title>Plain Vanilla Blog</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"A blog about vanilla web development.\">\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"../apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"./index.css\">\n    <link rel=\"alternate\" type=\"application/rss+xml\" href=\"https://plainvanillaweb.com/blog/feed.xml\">\n</head>\n<body>\n    <header>\n        <h1>Plain Vanilla Blog</h1>\n        <p class=\"hero-text\">A blog about vanilla web development&nbsp;&mdash; no frameworks, just standards.</p>\n        <nav aria-label=\"breadcrumb\" id=\"menu-nav\" popover>\n            <ol>\n                <li><a href=\"../index.html\">Plain Vanilla</a></li>\n                <li><a href=\"#\" aria-current=\"page\">Blog</a></li>\n            </ol>\n        </nav>\n        <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n            &mldr;\n        </button>\n    </header>\n    <main>\n        <h2>Featured</h2>\n        <ul class=\"cards\">\n            <li class=\"card\">\n                <img src=\"./articles/2026-03-09-details-matters/image.webp\" aria-hidden=\"true\" loading=\"lazy\" />\n                <h3><a href=\"./articles/2026-03-09-details-matters/\">&lt;details&gt; matters</a></h3>\n                <p>An oddball element set to take the main stage.</p>\n                <small>\n                    <time datetime=\"2026-03-09\">March 9, 2026</time>\n                </small>\n            </li>\n        </ul>\n\n        <h2>Latest Posts</h2>\n        <blog-latest-posts>\n            <noscript>Please enable scripting to view.</noscript>\n        </blog-latest-posts>\n\n        <p class=\"archive\">\n            <a href=\"archive.html\">Archive</a>\n            |\n            <a href=\"feed.xml\">RSS</a>\n        </p>\n    </main>\n    <blog-footer></blog-footer>\n    <script type=\"module\" src=\"./index.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "public/blog/index.js",
    "content": "import { registerBlogFooter } from \"./components/blog-footer.js\";\nimport { registerBlogHeader } from \"./components/blog-header.js\";\nimport { registerBlogLatestPosts } from \"./components/blog-latest-posts.js\";\nimport { registerBlogArchive } from \"./components/blog-archive.js\";\nimport { registerCodeViewerComponent } from \"../components/code-viewer/code-viewer.js\";\n\nconst app = async () => {\n    registerBlogLatestPosts();\n    registerBlogHeader();\n    registerBlogFooter();\n    registerBlogArchive();\n    registerCodeViewerComponent();\n    const { registerAnalyticsComponent } = await import(\"../components/analytics/analytics.js\");\n    registerAnalyticsComponent();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/components/analytics/analytics.js",
    "content": "class AnalyticsComponent extends HTMLElement {\n\n    #template;\n\n    constructor() {\n        super();\n        fetch(import.meta.resolve('../../analytics.template'))\n            .then(res => res.ok && res.text())\n            .then(template => {\n                this.#template = template;\n                this.update();\n            })\n            .catch(e => console.error(e));\n    }\n\n    connectedCallback() {\n        this.update();\n    }\n\n    update() {\n        if (this.isConnected && this.#template) {\n            this.innerHTML = this.#template;\n            // replace scripts by executable versions\n            const scripts = this.getElementsByTagName('script');\n            for (const script of scripts) {\n                const newScript = document.createElement('script');\n                for (const attr of script.attributes) {\n                    newScript.setAttribute(attr.name, attr.value);\n                }\n                newScript.innerHTML = script.innerHTML;\n                script.replaceWith(newScript);\n            }\n        }\n    }\n}\n\nexport const registerAnalyticsComponent = () => {\n    customElements.define('x-analytics', AnalyticsComponent);\n}"
  },
  {
    "path": "public/components/code-viewer/code-viewer.css",
    "content": "@import \"../../lib/speed-highlight/themes/github-dark.css\";\n\nx-code-viewer {\n    display: block;\n    display: flex;\n    flex-direction: column;\n}\n\nx-code-viewer label, \nx-code-viewer code {\n    display: block;\n    font-family: var(--font-system-code);\n    font-size: var(--font-system-code-size);\n    white-space: pre;\n    padding: 1em;\n}\n\nx-code-viewer label {\n    flex: 0 0 auto;\n    border-bottom: 1px dotted var(--border-color);\n}\n\nx-code-viewer label:empty {\n    display: none;\n}\n\nx-code-viewer code {\n    position: relative;\n    flex: 1 1 auto;\n    overflow: auto;\n    min-height: 8em;\n}\n\nx-code-viewer.loading code::after {\n    content: '';\n    box-sizing: border-box;\n    width: 30px;\n    height: 30px;\n    position: absolute;\n    top: calc(50% - 15px);\n    left: calc(50% - 15px);\n    border-radius: 50%;\n    border-top: 4px solid ghostwhite;\n    border-left: 4px solid ghostwhite;\n    border-right: 4px solid ghostwhite;\n    animation: code-viewer-spinner .6s linear infinite;\n}\n\n@keyframes code-viewer-spinner {\n    to {transform: rotate(360deg);}\n}\n\n@media (scripting: none) {\n    x-code-viewer::before { content: 'Enable scripting to view ' attr(src) }\n}\n"
  },
  {
    "path": "public/components/code-viewer/code-viewer.js",
    "content": "import { highlightElement } from \"../../lib/speed-highlight/index.js\";\n\n/**\n * Code Viewer component\n * \n * Usage:\n * <x-code-viewer src=\"path/to/code.js\"></x-code-viewer> - show code with label \"code.js\"\n * <x-code-viewer src=\"path/to/code.js\" name=\"My Code\"></x-code-viewer> - show code with label \"My Code\"\n */\nclass CodeViewer extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n            <label></label>\n            <code></code>\n        `;\n        // load code (and name) from src attribute\n        const src = this.getAttribute('src');\n        if (src) {\n            if (!this.hasAttribute('name')) {\n                this.setAttribute('name', src.split('/').pop());\n            }\n            this.classList.add('loading');\n            fetch(src).then(res => res.text()).then(text => {\n                this.setAttribute('code', text);\n            }).catch((e) => this.setAttribute('code', e.message))\n              .finally(() => this.classList.remove('loading'));\n        }\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['code', 'name'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const label = this.querySelector('label');\n        const code = this.querySelector('code');\n        if (label && code) {\n            label.textContent = this.getAttribute('name');\n            code.textContent = this.getAttribute('code');\n            // should we syntax highlight?\n            const src = this.getAttribute('src') || '';\n            const lang = src.split('.').pop();\n            if (['html', 'js', 'css'].includes(lang)) {\n                code.className = 'shj-lang-' + lang;\n            } else {\n                code.className = 'shj-lang-plain';\n            }\n            highlightElement(code);\n        }\n    }\n}\n\nexport const registerCodeViewerComponent = \n    () => customElements.define('x-code-viewer', CodeViewer);\n"
  },
  {
    "path": "public/components/tab-panel/tab-panel.css",
    "content": "x-tab-panel {\n    display: block;\n    border: 1px solid var(--border-color);\n}\n\nx-tab-panel div[role=tablist] {\n    display: block;\n    border-bottom: 1px dotted var(--border-color);\n}\n\nx-tab-panel div[role=tablist] button[role=tab] {\n    font-family: var(--font-system);\n    font-size: 100%;\n    color: inherit;\n    background-color: transparent;\n    background-image: none;\n    border: none;\n    padding: 0.5em;\n    padding-top: 0.6em;\n    margin-left: 0.5em;\n    border-bottom: 2px solid transparent;\n}\n\nx-tab-panel div[role=tablist] button[role=tab][aria-selected=true] {\n    font-weight: bold;\n    border-bottom: 2px solid var(--border-color);\n}\n\nx-tab-panel > x-tab {\n    display: none;\n}\n\nx-tab-panel > x-tab[active] {\n    display: block !important;\n}\n"
  },
  {
    "path": "public/components/tab-panel/tab-panel.js",
    "content": "/**\n * Tabbed panel component\n * \n * Usage:\n * <x-tab-panel>\n *     <x-tab title=\"Tab 1\" active>\n *         <p>Tab 1 content</p> \n *     </x-tab>\n *     <x-tab title=\"Tab 2\">\n *         <p>Tab 2 content</p>\n *     </x-tab>\n * </x-tab-panel>\n * \n * See: https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n */\nclass TabPanel extends HTMLElement {\n\n    #tablist;\n    #observer;\n    \n    get tablist() { return this.#tablist; }\n    get tabpanels() { return this.querySelectorAll('x-tab'); }\n\n    constructor() {\n        super();\n        this.#observer = new MutationObserver(this.onMutation.bind(this));\n        this.#observer.observe(this, { childList: true });\n    }\n\n    connectedCallback() {\n        this.#tablist = document.createElement('div');\n        this.#tablist.setAttribute('role', 'tablist');\n        this.insertBefore(this.#tablist, this.firstChild);\n    }\n\n    onMutation(m) {\n        if (m.filter(_ => _.type === 'childList').length) {\n            this.tablist.innerHTML = '';\n            this.tabpanels.forEach(tabPanel => {\n                if (tabPanel.role !== 'tabpanel') {\n                    tabPanel.style.display = 'none';\n                } else {\n                    const tab = document.createElement('button');\n                    tab.setAttribute('role', 'tab');\n                    tab.setAttribute('aria-controls', tabPanel.id);\n                    tab.textContent = tabPanel.title;\n                    tab.onclick = () => this.activatePanel(tabPanel.id);\n                    this.tablist.appendChild(tab);\n                }\n            });                \n        }\n        this.update();\n    }\n\n    activatePanel(id) {\n        this.tabpanels.forEach(tabPanel => {\n            if (tabPanel.id === id) {\n                tabPanel.setAttribute('active', 'true');\n            } else {\n                tabPanel.removeAttribute('active');\n            }\n        });\n        this.update();\n    }\n\n    update() {\n        this.tabpanels.forEach(tabPanel => {\n            const tab = this.tablist.querySelector(`[aria-controls=\"${tabPanel.id}\"]`);\n            if (tab) tab.setAttribute('aria-selected', tabPanel.hasAttribute('active'));\n        })\n    }\n}\n\nclass Tab extends HTMLElement {\n\n    static #nextId = 0;\n\n    connectedCallback() {\n        this.role = 'tabpanel';\n        this.id = 'tab-panel-' + Tab.#nextId++;\n    }\n}\n\nexport const registerTabPanelComponent = \n    () => {\n        customElements.define('x-tab-panel', TabPanel);\n        customElements.define('x-tab', Tab);\n    }\n"
  },
  {
    "path": "public/index.css",
    "content": "@import \"./styles/reset.css\";\n@import \"./styles/variables.css\";\n@import \"./styles/global.css\";\n@import \"./components/code-viewer/code-viewer.css\";\n@import \"./components/tab-panel/tab-panel.css\";\n"
  },
  {
    "path": "public/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <meta name=\"description\" content=\"An explainer for web development using only vanilla techniques. No tools, no frameworks &mdash; just HTML, CSS, and JavaScript.\">\n    <link rel=\"icon\" href=\"favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <link rel=\"canonical\" href=\"https://plainvanillaweb.com/index.html\" />\n    <style type=\"text/css\">\n\n        h1 {\n            margin-bottom: 0.4em;\n        }\n\n        dl {\n            margin-left: -1em;\n        }\n\n        #text-and-logo {\n\n            display: flex;\n            align-items: flex-start;\n            gap: 2rem;\n\n            > div {\n                flex: 1 1 auto;\n            }\n\n            > svg {\n                margin-top: 1em;\n                flex: 0 0 auto;\n                height: 19em;\n                width: auto;\n            }\n        }\n\n        @media screen and (max-width: 800px) {\n            #text-and-logo > svg {\n                height: 12em;\n            }\n            .hero-text br, #text-and-logo dl br {\n                display: none;\n            }\n        }\n\n        @media screen and (max-width: 600px) {\n            #text-and-logo > svg {\n                display: none;\n            }\n        }\n\n    </style>\n</head>\n<body>\n    <a href=\"#main-content\" class=\"skip-to-content\">Skip to main content</a>\n    <header>\n        <h1>Plain Vanilla</h1>\n        <p class=\"hero-text\">\n            An explainer for web development using only vanilla techniques.<br>\n            No tools, no frameworks &mdash; just HTML, CSS, and JavaScript.\n        </p>\n        <nav id=\"menu-nav\" popover aria-label=\"main\">\n            <ol>\n                <li><a href=\"#\" aria-current=\"page\">Welcome</a></li>\n                <li><a href=\"pages/components.html\">Components</a></li>\n                <li><a href=\"pages/styling.html\">Styling</a></li>\n                <li><a href=\"pages/sites.html\">Sites</a></li>\n                <li><a href=\"pages/applications.html\">Applications</a></li>\n                <li class=\"nav-right\"><a href=\"blog/\">Blog</a></li>\n            </ol>\n        </nav>\n        <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n            &mldr;\n        </button>\n    </header>\n\n    <main id=\"main-content\">\n        <section id=\"text-and-logo\">\n            <div>\n                <p class=\"hero-text\">\n                    Learn how to make web sites and web applications without build tools or frameworks,\n                    with just an editor, a browser, and web standards.\n                </p>\n                <dl>\n                    <dt><strong><a href=\"pages/components.html\">Components</a></strong></dt>\n                    <dd>Use web components to make higher-level primitives<br>\n                        out of plain HTML, JavaScript, and CSS.</dd>\n                    <dt><strong><a href=\"pages/styling.html\">Styling</a></strong></dt>\n                    <dd>Leverage modern CSS to replace the conveniences<br>\n                        of CSS Modules, PostCSS, or SASS.</dd>\n                    <dt><strong><a href=\"pages/sites.html\">Sites</a></strong></dt>\n                    <dd>Make a vanilla web site and get it online without<br>\n                        build tools, frameworks or server-side logic.</dd>\n                    <dt><strong><a href=\"pages/applications.html\">Applications</a></strong></dt>\n                    <dd>Craft single-page applications with vanilla strategies<br>\n                        for client-side routing and managing state.</dd>\n                </dl>\n            </div>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 36 36\">\n                <path fill=\"#FFCC4D\" d=\"M17.182 23H9.818s1.353 6.5 2.351 9.752C13.167 36.006 16.773 36 17.591 36c1.635 0 4.424.006 5.422-3.248C24.01 29.5 26.183 23 26.183 23h-9.001z\"/>\n                <path fill=\"#FFAC33\" d=\"M18 28c3.46 0 5.831-.751 7.097-1.725.349-1.06.653-1.977.85-2.569-.15-.25-.373-.487-.67-.706H10.723c-.341.252-.585.526-.732.817.109.508.262 1.214.447 2.037C11.527 27.024 14.055 28 18 28z\"/>\n                <path fill=\"#FFCC4D\" d=\"M9 20v3c0 1.657 4.03 3 9 3s9-1.343 9-3v-3H9z\"/>\n                <path fill=\"#F4900C\" d=\"M26.183 20.5c0 1.381-3.664 2.5-8.183 2.5s-8.182-1.119-8.182-2.5S13.481 18 18 18s8.183 1.119 8.183 2.5z\"/>\n                <path fill=\"#FFE8B6\" d=\"M26.902 13.908c.218-.939.159-1.941-.258-2.942-.404-.969-1.106-1.726-1.956-2.239.19-.709.154-1.469-.179-2.228-.501-1.145-1.589-1.903-2.814-2.113.152-.341.214-.76.039-1.288-.595-1.782-2.97-.584-4.751-2.959-1.476.885-1.777 2.208-1.707 3.315-1.352.241-2.132.532-2.132.532v.001c-.808.327-1.379 1.119-1.379 2.044 0 .49.165.939.436 1.305l-.48.179.001.002c-1.384.517-2.36 1.767-2.36 3.229 0 .622.191 1.197.5 1.702C8.176 13.198 7 14.838 7 16.754c0 2.495 1.989 4.518 4.508 4.712 2.663.826 7.99.6 12.076-.091 2.371-.4 4.791-1.82 4.791-4.225 0-1.295-.576-2.445-1.473-3.242z\"/><path d=\"M14.75 18.212c-2.24.634-5.602.796-7.39.314.725 1.744 2.478 2.977 4.535 2.977 6.145 0 12.417-4.183 12.417-4.183 1.969-1.226 2.972-3.16 2.649-5.188-2.042 2.888-9.869 5.417-12.211 6.08zm-1.615-3.981c4.739 0 9.575-3.069 9.575-3.069 1.583-.937 2.372-2.438 2.02-3.994-6.026 3.918-11.564 5.07-14.918 5.198.633 1.104 1.876 1.865 3.323 1.865zm-1.302-7.676c.236.964 1.1 1.681 2.136 1.681.655 0 1.312-.111 1.936-.277.384-.116.764-.24 1.143-.375 1.456-.565 2.517-1.291 2.517-1.291 1.056-.677 2.143-1.873 2.143-1.873s.369-.831-.25-1.319c-1.745 1.748-7.313 3.478-9.625 3.454z\" fill=\"#FFD983\"/>\n            </svg>\n        </section>\n        <section>\n            <aside>\n                <h2>Why go plain vanilla?</h2>\n                <p>\n                    Modern web development frameworks offer rich functionality,\n                    but this comes at the cost of framework and tooling complexity.\n                    The plain vanilla style of web development takes a different path,\n                    trading off short term comforts for long term benefits like simplicity \n                    and being effectively zero-maintenance.\n                </p>\n            </aside>\n        </section>\n        <section>\n            <aside class=\"aside-mirror\">\n                <h2>Who is this for?</h2>\n                <p>\n                    This tutorial is meant for those who already know their way around HTML, CSS, and JavaScript,\n                    and are looking to press the eject button on tooling complexity.\n                </p>\n                <p>\n                    If you're just starting out learning web development then this is not the site for you yet. \n                    You can get started at <a href=\"https://htmlforpeople.com/\">HTML for People</a> \n                    or <a href=\"https://www.theodinproject.com/paths/foundations/courses/foundations\">The Odin Project Foundations Course</a>.\n                </p>\n            </aside>\n        </section>\n        <section>\n            <h2>Up next</h2>\n            <hr />\n            <p>Learn how to use Web Components to compose content, style and behavior.</p>\n            <p><a href=\"pages/components.html\" class=\"button\">Get Started</a></p>\n        </section>\n    </main>\n\n    <footer>\n        <div class=\"contact\">\n            <a href=\"https://sebrechts.net/\">Contact</a>\n            <a href=\"https://github.com/jsebrech/plainvanilla\">GitHub</a>\n        </div>\n        <p class=\"top-link\">\n            <a href=\"#top\">Back to top</a>\n        </p>\n        <x-analytics></x-analytics>\n    </footer>\n\n    <script>\n        document.addEventListener('DOMContentLoaded', async () => {\n            const { registerAnalyticsComponent } = await import(\"./components/analytics/analytics.js\");\n            registerAnalyticsComponent();\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "public/index.js",
    "content": "import { registerCodeViewerComponent } from \"./components/code-viewer/code-viewer.js\";\nimport { registerTabPanelComponent } from \"./components/tab-panel/tab-panel.js\";\n\nconst app = async () => {\n    registerCodeViewerComponent();\n    registerTabPanelComponent();\n    const { registerAnalyticsComponent } = await import(\"./components/analytics/analytics.js\");\n    registerAnalyticsComponent();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/lib/html.js",
    "content": "class Html extends String { }\n\n/** \n * tag a string as html not to be encoded\n * @param {string} str\n * @returns {string}\n */\nexport const htmlRaw = str => new Html(str);\n\n/** \n * entity encode a string as html\n * @param {*} value The value to encode\n * @returns {string}\n */\nexport const htmlEncode = (value) => {\n    // avoid double-encoding the same string\n    if (value instanceof Html) {\n        return value;\n    } else {\n        // https://stackoverflow.com/a/57448862/20980\n        return htmlRaw(\n            String(value).replace(/[&<>'\"]/g, \n                tag => ({\n                    '&': '&amp;',\n                    '<': '&lt;',\n                    '>': '&gt;',\n                    \"'\": '&#39;',\n                    '\"': '&quot;'\n                }[tag]))\n        );\n    }\n}\n\n/** \n * html tagged template literal, auto-encodes entities\n */\nexport const html = (strings, ...values) => \n    htmlRaw(String.raw({ raw: strings }, ...values.map(htmlEncode)));\n"
  },
  {
    "path": "public/lib/speed-highlight/LICENSE",
    "content": "Creative Commons Legal Code\n\nCC0 1.0 Universal\n\n    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE\n    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN\n    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS\n    INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES\n    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS\n    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM\n    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED\n    HEREUNDER.\n\nStatement of Purpose\n\nThe laws of most jurisdictions throughout the world automatically confer\nexclusive Copyright and Related Rights (defined below) upon the creator\nand subsequent owner(s) (each and all, an \"owner\") of an original work of\nauthorship and/or a database (each, a \"Work\").\n\nCertain owners wish to permanently relinquish those rights to a Work for\nthe purpose of contributing to a commons of creative, cultural and\nscientific works (\"Commons\") that the public can reliably and without fear\nof later claims of infringement build upon, modify, incorporate in other\nworks, reuse and redistribute as freely as possible in any form whatsoever\nand for any purposes, including without limitation commercial purposes.\nThese owners may contribute to the Commons to promote the ideal of a free\nculture and the further production of creative, cultural and scientific\nworks, or to gain reputation or greater distribution for their Work in\npart through the use and efforts of others.\n\nFor these and/or other purposes and motivations, and without any\nexpectation of additional consideration or compensation, the person\nassociating CC0 with a Work (the \"Affirmer\"), to the extent that he or she\nis an owner of Copyright and Related Rights in the Work, voluntarily\nelects to apply CC0 to the Work and publicly distribute the Work under its\nterms, with knowledge of his or her Copyright and Related Rights in the\nWork and the meaning and intended legal effect of CC0 on those rights.\n\n1. Copyright and Related Rights. A Work made available under CC0 may be\nprotected by copyright and related or neighboring rights (\"Copyright and\nRelated Rights\"). Copyright and Related Rights include, but are not\nlimited to, the following:\n\n  i. the right to reproduce, adapt, distribute, perform, display,\n     communicate, and translate a Work;\n ii. moral rights retained by the original author(s) and/or performer(s);\niii. publicity and privacy rights pertaining to a person's image or\n     likeness depicted in a Work;\n iv. rights protecting against unfair competition in regards to a Work,\n     subject to the limitations in paragraph 4(a), below;\n  v. rights protecting the extraction, dissemination, use and reuse of data\n     in a Work;\n vi. database rights (such as those arising under Directive 96/9/EC of the\n     European Parliament and of the Council of 11 March 1996 on the legal\n     protection of databases, and under any national implementation\n     thereof, including any amended or successor version of such\n     directive); and\nvii. other similar, equivalent or corresponding rights throughout the\n     world based on applicable law or treaty, and any national\n     implementations thereof.\n\n2. Waiver. To the greatest extent permitted by, but not in contravention\nof, applicable law, Affirmer hereby overtly, fully, permanently,\nirrevocably and unconditionally waives, abandons, and surrenders all of\nAffirmer's Copyright and Related Rights and associated claims and causes\nof action, whether now known or unknown (including existing as well as\nfuture claims and causes of action), in the Work (i) in all territories\nworldwide, (ii) for the maximum duration provided by applicable law or\ntreaty (including future time extensions), (iii) in any current or future\nmedium and for any number of copies, and (iv) for any purpose whatsoever,\nincluding without limitation commercial, advertising or promotional\npurposes (the \"Waiver\"). Affirmer makes the Waiver for the benefit of each\nmember of the public at large and to the detriment of Affirmer's heirs and\nsuccessors, fully intending that such Waiver shall not be subject to\nrevocation, rescission, cancellation, termination, or any other legal or\nequitable action to disrupt the quiet enjoyment of the Work by the public\nas contemplated by Affirmer's express Statement of Purpose.\n\n3. Public License Fallback. Should any part of the Waiver for any reason\nbe judged legally invalid or ineffective under applicable law, then the\nWaiver shall be preserved to the maximum extent permitted taking into\naccount Affirmer's express Statement of Purpose. In addition, to the\nextent the Waiver is so judged Affirmer hereby grants to each affected\nperson a royalty-free, non transferable, non sublicensable, non exclusive,\nirrevocable and unconditional license to exercise Affirmer's Copyright and\nRelated Rights in the Work (i) in all territories worldwide, (ii) for the\nmaximum duration provided by applicable law or treaty (including future\ntime extensions), (iii) in any current or future medium and for any number\nof copies, and (iv) for any purpose whatsoever, including without\nlimitation commercial, advertising or promotional purposes (the\n\"License\"). The License shall be deemed effective as of the date CC0 was\napplied by Affirmer to the Work. Should any part of the License for any\nreason be judged legally invalid or ineffective under applicable law, such\npartial invalidity or ineffectiveness shall not invalidate the remainder\nof the License, and in such case Affirmer hereby affirms that he or she\nwill not (i) exercise any of his or her remaining Copyright and Related\nRights in the Work or (ii) assert any associated claims and causes of\naction with respect to the Work, in either case contrary to Affirmer's\nexpress Statement of Purpose.\n\n4. Limitations and Disclaimers.\n\n a. No trademark or patent rights held by Affirmer are waived, abandoned,\n    surrendered, licensed or otherwise affected by this document.\n b. Affirmer offers the Work as-is and makes no representations or\n    warranties of any kind concerning the Work, express, implied,\n    statutory or otherwise, including without limitation warranties of\n    title, merchantability, fitness for a particular purpose, non\n    infringement, or the absence of latent or other defects, accuracy, or\n    the present or absence of errors, whether or not discoverable, all to\n    the greatest extent permissible under applicable law.\n c. Affirmer disclaims responsibility for clearing rights of other persons\n    that may apply to the Work or any use thereof, including without\n    limitation any person's Copyright and Related Rights in the Work.\n    Further, Affirmer disclaims responsibility for obtaining any necessary\n    consents, permissions or other rights required for any use of the\n    Work.\n d. Affirmer understands and acknowledges that Creative Commons is not a\n    party to this document and has no duty or obligation with respect to\n    this CC0 or use of the Work.\n"
  },
  {
    "path": "public/lib/speed-highlight/common.js",
    "content": "/**\n * Commonly used match pattern\n*/\n\nexport default {\n\tnum: {\n\t\ttype: 'num',\n\t\tmatch: /(\\.e?|\\b)\\d(e-|[\\d.oxa-fA-F_])*(\\.|\\b)/g\n\t},\n\tstr: {\n\t\ttype: 'str',\n\t\tmatch: /([\"'])(\\\\[^]|(?!\\1)[^\\r\\n\\\\])*\\1?/g\n\t},\n\tstrDouble: {\n\t\ttype: 'str',\n\t\tmatch: /\"((?!\")[^\\r\\n\\\\]|\\\\[^])*\"?/g\n\t}\n}\n"
  },
  {
    "path": "public/lib/speed-highlight/index.js",
    "content": "/**\n * @module index\n * (Base script)\n*/\n\n/**\n * Default languages supported\n * @typedef {('asm'|'bash'|'bf'|'c'|'css'|'csv'|'diff'|'docker'|'git'|'go'|'html'|'http'|'ini'|'java'|'js'|'jsdoc'|'json'|'leanpub-md'|'log'|'lua'|'make'|'md'|'pl'|'plain'|'py'|'regex'|'rs'|'sql'|'todo'|'toml'|'ts'|'uri'|'xml'|'yaml')} ShjLanguage\n */\n\n/**\n * Themes supported in the browser\n * @typedef {('atom-dark'|'github-dark'|'github-dim'|'dark'|'default'|'github-light'|'visual-studio-dark')} ShjBrowserTheme\n */\n\n/**\n * @typedef {Object} ShjOptions\n * @property {Boolean} [hideLineNumbers=false] Indicates whether to hide line numbers\n */\n\n/**\n * @typedef {('inline'|'oneline'|'multiline')} ShjDisplayMode\n * * `inline` inside `code` element\n * * `oneline` inside `div` element and containing only one line\n * * `multiline` inside `div` element\n */\n\n/**\n * Token types\n * @typedef {('deleted'|'err'|'var'|'section'|'kwd'|'class'|'cmnt'|'insert'|'type'|'func'|'bool'|'num'|'oper'|'str'|'esc')} ShjToken\n */\n\nimport expandData from './common.js';\n\nconst langs = {},\n\tsanitize = (str = '') =>\n\t\tstr.replaceAll('&', '&#38;').replaceAll?.('<', '&lt;').replaceAll?.('>', '&gt;'),\n\t/**\n\t * Create a HTML element with the right token styling\n\t *\n\t * @function\n\t * @ignore\n\t * @param {string} str The content (need to be sanitized)\n\t * @param {ShjToken} [token] The type of token\n\t * @returns A HMTL string\n\t */\n\ttoSpan = (str, token) => token ? `<span class=\"shj-syn-${token}\">${str}</span>` : str;\n\n/**\n * Find the tokens in the given code and call the given callback\n *\n * @function tokenize\n * @param {string} src The code\n * @param {ShjLanguage|Array} lang The language of the code\n * @param {function(string, ShjToken=):void} token The callback function\n * this function will be given\n * * the text of the token\n * * the type of the token\n */\nexport async function tokenize(src, lang, token) {\n\ttry {\n\t\tlet m,\n\t\t\tpart,\n\t\t\tfirst = {},\n\t\t\tmatch,\n\t\t\tcache = [],\n\t\t\ti = 0,\n\t\t\tdata = typeof lang === 'string' ? (await (langs[lang] ??= import(`./languages/${lang}.js`))) : lang,\n\t\t\t// make a fast shallow copy to bee able to splice lang without change the original one\n\t\t\tarr = [...typeof lang === 'string' ? data.default : lang.sub];\n\n\t\twhile (i < src.length) {\n\t\t\tfirst.index = null;\n\t\t\tfor (m = arr.length; m-- > 0;) {\n\t\t\t\tpart = arr[m].expand ? expandData[arr[m].expand] : arr[m];\n\t\t\t\t// do not call again exec if the previous result is sufficient\n\t\t\t\tif (cache[m] === undefined || cache[m].match.index < i) {\n\t\t\t\t\tpart.match.lastIndex = i;\n\t\t\t\t\tmatch = part.match.exec(src);\n\t\t\t\t\tif (match === null) {\n\t\t\t\t\t\t// no more match with this regex can be disposed\n\t\t\t\t\t\tarr.splice(m, 1);\n\t\t\t\t\t\tcache.splice(m, 1);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// save match for later use to decrease performance cost\n\t\t\t\t\tcache[m] = { match, lastIndex: part.match.lastIndex };\n\t\t\t\t}\n\t\t\t\t// check if it the first match in the string\n\t\t\t\tif (cache[m].match[0] && (cache[m].match.index <= first.index || first.index === null))\n\t\t\t\t\tfirst = {\n\t\t\t\t\t\tpart: part,\n\t\t\t\t\t\tindex: cache[m].match.index,\n\t\t\t\t\t\tmatch: cache[m].match[0],\n\t\t\t\t\t\tend: cache[m].lastIndex\n\t\t\t\t\t}\n\t\t\t}\n\t\t\tif (first.index === null)\n\t\t\t\tbreak;\n\t\t\ttoken(src.slice(i, first.index), data.type);\n\t\t\ti = first.end;\n\t\t\tif (first.part.sub)\n\t\t\t\tawait tokenize(first.match, typeof first.part.sub === 'string' ? first.part.sub : (typeof first.part.sub === 'function' ? first.part.sub(first.match) : first.part), token);\n\t\t\telse\n\t\t\t\ttoken(first.match, first.part.type);\n\t\t}\n\t\ttoken(src.slice(i, src.length), data.type);\n\t}\n\tcatch {\n\t\ttoken(src);\n\t}\n}\n\n/**\n * Highlight a string passed as argument and return it\n * @example\n * elm.innerHTML = await highlightText(code, 'js');\n *\n * @async\n * @function highlightText\n * @param {string} src The code\n * @param {ShjLanguage} lang The language of the code\n * @param {Boolean} [multiline=true] If it is multiline, it will add a wrapper for the line numbering and header\n * @param {ShjOptions} [opt={}] Customization options\n * @returns {Promise<string>} The highlighted string\n */\nexport async function highlightText(src, lang, multiline = true, opt = {}) {\n\tlet tmp = ''\n\tawait tokenize(src, lang, (str, type) => tmp += toSpan(sanitize(str), type))\n\n\treturn multiline\n\t\t? `<div><div class=\"shj-numbers\">${'<div></div>'.repeat(!opt.hideLineNumbers && src.split('\\n').length)}</div><div>${tmp}</div></div>`\n\t\t: tmp;\n}\n\n/**\n * Highlight a DOM element by getting the new innerHTML with highlightText\n *\n * @async\n * @function highlightElement\n * @param {Element} elm The DOM element\n * @param {ShjLanguage} [lang] The language of the code (seaching by default on `elm` for a 'shj-lang-' class)\n * @param {ShjDisplayMode} [mode] The display mode (guessed by default)\n * @param {ShjOptions} [opt={}] Customization options\n */\nexport async function highlightElement(elm, lang = elm.className.match(/shj-lang-([\\w-]+)/)?.[1], mode, opt) {\n\tlet txt = elm.textContent;\n\tmode ??= `${elm.tagName == 'CODE' ? 'in' : (txt.split('\\n').length < 2 ? 'one' : 'multi')}line`;\n\telm.dataset.lang = lang;\n\telm.className = `${[...elm.classList].filter(className => !className.startsWith('shj-')).join(' ')} shj-lang-${lang} shj-${mode}`;\n\telm.innerHTML = await highlightText(txt, lang, mode == 'multiline', opt);\n}\n\n/**\n * Call highlightElement on element with a css class starting with `shj-lang-`\n *\n * @async\n * @function highlightAll\n * @param {ShjOptions} [opt={}] Customization options\n */\nexport let highlightAll = async (opt) =>\n\tPromise.all(\n\t\tArray.from(document.querySelectorAll('[class*=\"shj-lang-\"]'))\n\t\t.map(elm => highlightElement(elm, undefined, undefined, opt)))\n\n/**\n * @typedef {{ match: RegExp, type: string }\n *   | { match: RegExp, sub: string | ShjLanguageDefinition | (code:string) => ShjLanguageComponent }\n *   | { expand: string }\n * } ShjLanguageComponent\n */\n\n/**\n * @typedef {ShjLanguageComponent[]} ShjLanguageDefinition\n */\n\n/**\n * Load a language and add it to the langs object\n *\n * @function loadLanguage\n * @param {string} languageName The name of the language\n * @param {{ default: ShjLanguageDefinition }} language The language\n */\nexport let loadLanguage = (languageName, language) => {\n\tlangs[languageName] = language;\n}\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/css.js",
    "content": "export default [\n\t{\n\t\tmatch: /\\/\\*((?!\\*\\/)[^])*(\\*\\/)?/g,\n\t\tsub: 'todo'\n\t},\n\t{\n\t\texpand: 'str'\n\t},\n\t{\n\t\ttype: 'kwd',\n\t\tmatch: /@\\w+\\b|\\b(and|not|only|or)\\b|\\b[a-z-]+(?=[^{}]*{)/g\n\t},\n\t{\n\t\ttype: 'var',\n\t\tmatch: /\\b[\\w-]+(?=\\s*:)|(::?|\\.)[\\w-]+(?=[^{}]*{)/g\n\t},\n\t{\n\t\ttype: 'func',\n\t\tmatch: /#[\\w-]+(?=[^{}]*{)/g\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch:  /#[\\da-f]{3,8}/g\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /\\d+(\\.\\d+)?(cm|mm|in|px|pt|pc|em|ex|ch|rem|vm|vh|vmin|vmax|%)?/g,\n\t\tsub: [\n\t\t\t{\n\t\t\t\ttype: 'var',\n\t\t\t\tmatch: /[a-z]+|%/g\n\t\t\t}\n\t\t]\n\t},\n\t{\n\t\tmatch: /url\\([^)]*\\)/g,\n\t\tsub: [\n\t\t\t{\n\t\t\t\ttype: 'func',\n\t\t\t\tmatch: /url(?=\\()/g\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'str',\n\t\t\t\tmatch: /[^()]+/g\n\t\t\t}\n\t\t]\n\t},\n\t{\n\t\ttype: 'func',\n\t\tmatch: /\\b[a-zA-Z]\\w*(?=\\s*\\()/g\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /\\b[a-z-]+\\b/g\n\t}\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/html.js",
    "content": "import xml, { property, xmlElement } from './xml.js'\n\nexport default [\n\t{\n\t\ttype: 'class',\n\t\tmatch: /<!DOCTYPE(\"[^\"]*\"|'[^']*'|[^\"'>])*>/gi,\n\t\tsub: [\n\t\t\t{\n\t\t\t\ttype: 'str',\n\t\t\t\tmatch: /\"[^\"]*\"|'[^']*'/g\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'oper',\n\t\t\t\tmatch: /^<!|>$/g\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'var',\n\t\t\t\tmatch: /DOCTYPE/gi\n\t\t\t}\n\t\t]\n\t},\n\t{\n\t\tmatch: RegExp(`<style${property}>((?!</style>)[^])*</style\\\\s*>`, 'g'),\n\t\tsub: [\n\t\t\t{\n\t\t\t\tmatch: RegExp(`^<style${property}>`, 'g'),\n\t\t\t\tsub: xmlElement.sub\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatch: RegExp(`${xmlElement.match}|[^]*(?=</style\\\\s*>$)`, 'g'),\n\t\t\t\tsub: 'css'\n\t\t\t},\n\t\t\txmlElement\n\t\t]\n\t},\n\t{\n\t\tmatch: RegExp(`<script${property}>((?!</script>)[^])*</script\\\\s*>`, 'g'),\n\t\tsub: [\n\t\t\t{\n\t\t\t\tmatch: RegExp(`^<script${property}>`, 'g'),\n\t\t\t\tsub: xmlElement.sub\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatch: RegExp(`${xmlElement.match}|[^]*(?=</script\\\\s*>$)`, 'g'),\n\t\t\t\tsub: 'js'\n\t\t\t},\n\t\t\txmlElement\n\t\t]\n\t},\n\t...xml\n]"
  },
  {
    "path": "public/lib/speed-highlight/languages/js.js",
    "content": "export default [\n\t{\n\t\tmatch: /\\/\\*\\*((?!\\*\\/)[^])*(\\*\\/)?/g,\n\t\tsub: 'jsdoc'\n\t},\n\t{\n\t\tmatch: /\\/\\/.*\\n?|\\/\\*((?!\\*\\/)[^])*(\\*\\/)?/g,\n\t\tsub: 'todo'\n\t},\n\t{\n\t\texpand: 'str'\n\t},\n\t{\n\t\tmatch: /`((?!`)[^]|\\\\[^])*`?/g,\n\t\tsub: 'js_template_literals'\n\t},\n\t{\n\t\ttype: 'kwd',\n\t\tmatch: /=>|\\b(this|set|get|as|async|await|break|case|catch|class|const|constructor|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|if|implements|import|in|instanceof|interface|let|var|of|new|package|private|protected|public|return|static|super|switch|throw|throws|try|typeof|void|while|with|yield)\\b/g\n\t},\n\t{\n\t\tmatch: /\\/((?!\\/)[^\\r\\n\\\\]|\\\\.)+\\/[dgimsuy]*/g,\n\t\tsub: 'regex'\n\t},\n\t{\n\t\texpand: 'num'\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /\\b(NaN|null|undefined|[A-Z][A-Z_]*)\\b/g\n\t},\n\t{\n\t\ttype: 'bool',\n\t\tmatch: /\\b(true|false)\\b/g\n\t},\n\t{\n\t\ttype: 'oper',\n\t\tmatch: /[/*+:?&|%^~=!,<>.^-]+/g\n\t},\n\t{\n\t\ttype: 'class',\n\t\tmatch: /\\b[A-Z][\\w_]*\\b/g\n\t},\n\t{\n\t\ttype: 'func',\n\t\tmatch: /[a-zA-Z$_][\\w$_]*(?=\\s*((\\?\\.)?\\s*\\(|=\\s*(\\(?[\\w,{}\\[\\])]+\\)? =>|function\\b)))/g\n\t}\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/js_template_literals.js",
    "content": "export default [\n\t{\n\t\tmatch: new class {\n\t\t\texec(str) {\n\t\t\tlet i = this.lastIndex,\n\t\t\t\tj,\n\t\t\t\tf = _ => {\n\t\t\t\twhile (++i < str.length - 2)\n\t\t\t\t\tif (str[i] == '{') f();\n\t\t\t\t\telse if (str[i] == '}') return;\n\t\t\t\t};\n\t\t\tfor (; i < str.length; i++)\n\t\t\t\tif (str[i - 1] != '\\\\' && str[i] == '$' && str[i + 1] == '{') {\n\t\t\t\tj = i++;\n\t\t\t\tf(i);\n\t\t\t\tthis.lastIndex = i + 1;\n\t\t\t\treturn { index: j, 0: str.slice(j, i + 1) };\n\t\t\t\t}\n\t\t\treturn null;\n\t\t\t}\n\t\t}(),\n\t\tsub: [\n\t\t\t{\n\t\t\t\ttype: 'kwd',\n\t\t\t\tmatch: /^\\${|}$/g\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatch: /(?!^\\$|{)[^]+(?=}$)/g,\n\t\t\t\tsub: 'js'\n\t\t\t},\n\t\t],\n\t},\n];\nexport let type = 'str';\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/jsdoc.js",
    "content": "import todo from './todo.js';\n\nexport default [\n\t{\n\t\ttype: 'kwd',\n\t\tmatch: /@\\w+/g\n\t},\n\t{\n\t\ttype: 'class',\n\t\tmatch: /{[\\w\\s|<>,.@\\[\\]]+}/g\n\t},\n\t{\n\t\ttype: 'var',\n\t\tmatch: /\\[[\\w\\s=\"']+\\]/g\n\t},\n\t...todo\n];\nexport let type = 'cmnt';\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/json.js",
    "content": "export default [\n\t{\n\t\ttype: 'var',\n\t\tmatch: /(\"|')?[a-zA-Z]\\w*\\1(?=\\s*:)/g\n\t},\n\t{\n\t\texpand: 'str'\n\t},\n\t{\n\t\texpand: 'num'\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /\\bnull\\b/g\n\t},\n\t{\n\t\ttype: 'bool',\n\t\tmatch: /\\b(true|false)\\b/g\n\t}\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/log.js",
    "content": "export default [\n\t{\n\t\ttype: 'cmnt',\n\t\tmatch: /^#.*/gm\n\t},\n\t{\n\t\texpand: 'strDouble'\n\t},\n\t{\n\t\texpand: 'num'\n\t},\n\t{\n\t\ttype: 'err',\n\t\tmatch: /\\b(err(or)?|[a-z_-]*exception|warn|warning|failed|ko|invalid|not ?found|alert|fatal)\\b/gi\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /\\b(null|undefined)\\b/gi\n\t},\n\t{\n\t\ttype: 'bool',\n\t\tmatch: /\\b(false|true|yes|no)\\b/gi\n\t},\n\t{\n\t\ttype: 'oper',\n\t\tmatch: /\\.|,/g\n\t}\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/plain.js",
    "content": "export default [\n\t{\n\t\texpand: 'strDouble'\n\t}\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/regex.js",
    "content": "export default [\n\t{\n\t\tmatch: /^(?!\\/).*/gm,\n\t\tsub: 'todo'\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /\\[((?!\\])[^\\\\]|\\\\.)*\\]/g\n\t},\n\t{\n\t\ttype: 'kwd',\n\t\tmatch: /\\||\\^|\\$|\\\\.|\\w+($|\\r|\\n)/g\n\t},\n\t{\n\t\ttype: 'var',\n\t\tmatch: /\\*|\\+|\\{\\d+,\\d+\\}/g\n\t}\n];\nexport let type = 'oper';\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/todo.js",
    "content": "export default [\n\t{\n\t\ttype: 'err',\n\t\tmatch: /\\b(TODO|FIXME|DEBUG|OPTIMIZE|WARNING|XXX|BUG)\\b/g\n\t},\n\t{\n\t\ttype: 'class',\n\t\tmatch: /\\bIDEA\\b/g\n\t},\n\t{\n\t\ttype: 'insert',\n\t\tmatch: /\\b(CHANGED|FIX|CHANGE)\\b/g\n\t},\n\t{\n\t\ttype: 'oper',\n\t\tmatch: /\\bQUESTION\\b/g\n\t}\n];\nexport let type = 'cmnt';\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/ts.js",
    "content": "import js from './js.js'\n\nexport default [\n\t{\n\t\ttype: 'type',\n\t\tmatch: /:\\s*(any|void|number|boolean|string|object|never|enum)\\b/g\n\t},\n\t{\n\t\ttype: 'kwd',\n\t\tmatch: /\\b(type|namespace|typedef|interface|public|private|protected|implements|declare|abstract|readonly)\\b/g\n\t},\n\t...js\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/uri.js",
    "content": "export default [\n\t{\n\t\tmatch: /^#.*/gm,\n\t\tsub: 'todo'\n\t},\n\t{\n\t\ttype: 'class',\n\t\tmatch: /^\\w+(?=:?)/gm\n\t},\n\t{\n\t\ttype: 'num',\n\t\tmatch: /:\\d+/g\n\t},\n\t{\n\t\ttype: 'oper',\n\t\tmatch: /[:/&?]|\\w+=/g\n\t},\n\t{\n\t\ttype: 'func',\n\t\tmatch: /[.\\w]+@|#[\\w]+$/gm\n\t},\n\t{\n\t\ttype: 'var',\n\t\tmatch: /\\w+\\.\\w+(\\.\\w+)*/g\n\t}\n]\n"
  },
  {
    "path": "public/lib/speed-highlight/languages/xml.js",
    "content": "export let property = '\\\\s*(\\\\s+[a-z-]+\\\\s*(=\\\\s*([^\"\\']\\\\S*|(\"|\\')(\\\\\\\\[^]|(?!\\\\4)[^])*\\\\4?)?)?\\\\s*)*',\n\txmlElement = {\n\t\tmatch: RegExp(`<\\/?[a-z_-]+${property}\\/?>`, 'g'),\n\t\tsub: [\n\t\t\t{\n\t\t\t\ttype: 'var',\n\t\t\t\tmatch: /^<\\/?[^\\s>\\/]+/g,\n\t\t\t\tsub: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'oper',\n\t\t\t\t\t\tmatch: /^<\\/?/g\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'str',\n\t\t\t\tmatch: /=\\s*([^\"']\\S*|(\"|')(\\\\[^]|(?!\\2)[^])*\\2?)/g,\n\t\t\t\tsub: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'oper',\n\t\t\t\t\t\tmatch: /^=/g\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'oper',\n\t\t\t\tmatch: /\\/?>/g\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'class',\n\t\t\t\tmatch: /[a-z-]+/gi\n\t\t\t}\n\t\t]\n\t};\n\nexport default [\n\t{\n\t\tmatch: /<!--((?!-->)[^])*-->/g,\n\t\tsub: 'todo'\n\t},\n\t{\n\t\ttype: 'class',\n\t\tmatch: RegExp(`<\\\\?xml${property}\\\\?>`, 'gi'),\n\t\tsub: [\n\t\t\t{\n\t\t\t\ttype: 'oper',\n\t\t\t\tmatch: /^<\\?|\\?>$/g\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'str',\n\t\t\t\tmatch: /\"[^\"]*\"|'[^']*'/g\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'var',\n\t\t\t\tmatch: /xml/gi\n\t\t\t}\n\t\t]\n\t},\n\t{\n\t\ttype: 'class',\n\t\tmatch: /<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/gi\n\t},\n\txmlElement,\n\t{\n\t\ttype: 'var',\n\t\tmatch: /&(#x?)?[\\da-z]{1,8};/gi\n\t}\n]"
  },
  {
    "path": "public/lib/speed-highlight/themes/default.css",
    "content": "[class*=\"shj-lang-\"] {\n\twhite-space: pre;\n/*\tmargin: 10px 0;*/\n/*\tborder-radius: 10px;*/\n/*\tpadding: 30px 20px;*/\n\tbackground: white;\n\tcolor: #112;\n/*\tbox-shadow: 0 0 5px #0001;*/\n\ttext-shadow: none;\n/*\tfont: normal 18px Consolas, \"Courier New\", Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;*/\n\tline-height: 24px;\n\tbox-sizing: border-box;\n\tmax-width: min(100%, 100vw)\n}\n.shj-inline {\n/*\tmargin: 0;*/\n/*\tpadding: 2px 5px;*/\n\tdisplay: inline-block;\n/*\tborder-radius: 5px*/\n}\n\n[class*=\"shj-lang-\"]::selection,\n[class*=\"shj-lang-\"] ::selection {background: #bdf5}\n[class*=\"shj-lang-\"] > div {\n\tdisplay: flex;\n\toverflow: auto\n}\n[class*=\"shj-lang-\"] > div :last-child {\n\tflex: 1;\n\toutline: none\n}\n.shj-numbers {\n\tpadding-left: 5px;\n\tcounter-reset: line\n}\n.shj-numbers div {padding-right: 5px}\n.shj-numbers div::before {\n\tcolor: #999;\n\tdisplay: block;\n\tcontent: counter(line);\n\topacity: .5;\n\ttext-align: right;\n\tmargin-right: 5px;\n\tcounter-increment: line\n}\n\n.shj-syn-cmnt {font-style: italic}\n\n.shj-syn-err,\n.shj-syn-kwd {color: #e16}\n.shj-syn-num,\n.shj-syn-class {color: #f60}\n.shj-numbers,\n.shj-syn-cmnt {color: #999}\n.shj-syn-insert,\n.shj-syn-str {color: #7d8}\n.shj-syn-bool {color: #3bf}\n.shj-syn-type,\n.shj-syn-oper {color: #5af}\n.shj-syn-section,\n.shj-syn-func {color: #84f}\n.shj-syn-deleted,\n.shj-syn-var {color: #f44}\n\n.shj-oneline {padding: 12px 10px}\n.shj-lang-http.shj-oneline .shj-syn-kwd {\n\tbackground: #25f;\n\tcolor: #fff;\n\tpadding: 5px 7px;\n\tborder-radius: 5px\n}\n"
  },
  {
    "path": "public/lib/speed-highlight/themes/github-dark.css",
    "content": "@import 'default.css';\n\n[class*=\"shj-lang-\"] {\n\tcolor: #c9d1d9;\n\tbackground: #161b22\n}\n[class*=\"shj-lang-\"]:before {color: #6f9aff}\n\n.shj-syn-insert {color: #98c379}\n.shj-syn-deleted,\n.shj-syn-err,\n.shj-syn-kwd {color: #ff7b72}\n.shj-syn-class {color: #ffa657}\n.shj-numbers,\n.shj-syn-cmnt {color: #8b949e}\n.shj-syn-type,\n.shj-syn-oper,\n.shj-syn-num,\n.shj-syn-section,\n.shj-syn-var,\n.shj-syn-bool {color: #79c0ff}\n.shj-syn-str {color: #a5d6ff}\n.shj-syn-func {color: #d2a8ff}\n"
  },
  {
    "path": "public/lib/speed-highlight/themes/github-light.css",
    "content": "@import 'default.css';\n\n[class*=\"shj-lang-\"] {\n\tcolor: #24292f;\n\tbackground: #fff\n}\n\n.shj-syn-deleted,\n.shj-syn-err,\n.shj-syn-kwd {color: #cf222e}\n.shj-syn-class {color: #953800}\n.shj-numbers,\n.shj-syn-cmnt {color: #6e7781}\n.shj-syn-type,\n.shj-syn-oper,\n.shj-syn-num,\n.shj-syn-section,\n.shj-syn-var,\n.shj-syn-bool {color: #0550ae}\n.shj-syn-str {color: #0a3069}\n.shj-syn-func {color: #8250df}\n"
  },
  {
    "path": "public/manifest.json",
    "content": "{\n    \"name\": \"Plain Vanilla\",\n    \"short_name\": \"Plain Vanilla\",\n    \"icons\": [{\n        \"src\": \"android-chrome-512x512.png\",\n        \"sizes\": \"512x512\"\n    }],\n    \"background_color\": \"#ffffff\",\n    \"description\": \"An explainer for doing web development using only vanilla techniques.\",\n    \"theme_color\": \"#ffffff\",\n    \"display\": \"fullscreen\"\n}"
  },
  {
    "path": "public/pages/applications.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla - Applications</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"description\" content=\"An explainer for developing single-page applications using only vanilla techniques.\">\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"../apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"../index.css\">\n</head>\n<body>\n    <noscript><strong>Please enable JavaScript to view this page correctly.</strong></noscript>\n    <script type=\"module\" src=\"../index.js\"></script>\n    <header>\n        <h1>Applications</h1>\n        <nav id=\"menu-nav\" popover aria-label=\"main\">\n            <ol>\n                <li><a href=\"../index.html\">Welcome</a></li>\n                <li><a href=\"components.html\">Components</a></li>\n                <li><a href=\"styling.html\">Styling</a></li>\n                <li><a href=\"sites.html\">Sites</a></li>\n                <li><a href=\"#\" aria-current=\"page\">Applications</a></li>\n                <li class=\"nav-right\"><a href=\"../blog/\">Blog</a></li>\n            </ol>\n        </nav>\n        <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n            &mldr;\n        </button>\n    </header>\n    <main>\n        <section id=\"project\">\n            <a href=\"#project\" class=\"section-anchor\">#</a>\n            <h2>Project</h2>\n            <p>When richer interactivity and dynamic state are needed, a single-page application is often a better fit than a multi-page website.</p>\n\n            <p>The suggested project layout for single-page applications is the same as for multi-page sites, except:</p>\n            <dl>\n                <dt><del>/public/pages</del></dt>\n                <dd>As there is only <code>index.html</code> there is no need for the pages folder.</dd>\n                <dt>/public/app</dt>\n                <dd>All of the views and routes for the application are in this folder, each implemented as a web component, and registered in <code>index.js</code>.</dd>\n                <dt>/public/app/App.js</dt>\n                <dd>As in the major frameworks, the application is bootstrapped from an App component. See the example below.</dd>\n            </dl>\n        </section>\n        <section id=\"routing\">\n            <a href=\"#routing\" class=\"section-anchor\">#</a>\n            <h2>Routing</h2>\n\n            <p>Without the assistance of a server to do routing, the easiest option is hash-based routing:</p>\n            <ul>\n                <li>The current route is in <code>window.location.hash</code>, e.g. <code>#/about</code>.</li>\n                <li>The route's changes are detected by listening to the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event\">Window hashchange event</a>.</li>\n                <li>Each web component is shown or hidden based on the active route.</li>\n            </ul>\n            <p>This behavior can be encapsulated in a routing web component:</p>\n            <x-code-viewer src=\"./examples/applications/single-page/components/route/route.js\" name=\"components/route/route.js\"></x-code-viewer>\n\n            <p>An example single-page vanilla application that uses this routing component:</p>\n\n            <iframe src=\"./examples/applications/single-page/index.html\" title=\"single-page application\" height=\"400\"></iframe>\n\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/applications/single-page/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/applications/single-page/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/applications/single-page/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"App.js\">\n                    <x-code-viewer src=\"./examples/applications/single-page/app/App.js\" name=\"app/App.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"route.js\">\n                    <x-code-viewer src=\"./examples/applications/single-page/components/route/route.js\" name=\"components/route/route.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>It makes use of the template pattern to avoid showing a broken application if scripting is disabled.</p>\n\n            <p>Adding additional route components to the <code>/app</code> folder is left as an exercise for the reader.</p>\n\n            <aside>\n                <h3>About Search Engines</h3>\n                <p>\n                    The hash-based routing approach is effectively invisible to search engines. Only the initial route will be indexed.\n                    For this reason this approach is not suited to sites that have SEO concerns.\n                    Every route that must be discoverable through a search engine should use the multi-file approach explained on the Sites page.\n                </p>\n            </aside>\n\n            <p>\n                For a more advanced but less intuitive client-side routing solution that uses <code>pushState</code>,\n                see the article on <a href=\"../blog/articles/2025-06-25-routing/\">Clean Client-side Routing</a>.\n            </p>\n\n        </section>\n        <section id=\"entity-encoding\">\n            <a href=\"#entity-encoding\" class=\"section-anchor\">#</a>\n            <h2>Entity encoding</h2>\n            <p>\n                A real-world application will often have complex markup in the web components, filled with variables based on user input.\n                This creates a risk for <a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\">Cross-Site Scripting</a>.\n                In fact, eagle-eyed readers may have noticed in the <a href=\"components.html#passing-data\">Passing Data example</a> of the Components page that a XSS bug snuck in.\n                By entering the following as a name, the output of <code>list.js</code> would have code injected:<br><code>&lt;button onclick=\"alert('gotcha')\"&gt;oops&lt;/button&gt;</code>\n            </p>\n            <p>Go ahead and return to that page to try it ...</p>\n            <p>\n                To solve this we need to encode dangerous HTML entities while plugging variables into HTML markup, something frameworks often do automatically in their templating layer.\n                This <code>html``</code> literal function can be used to do this automatically in a vanilla codebase:\n            </p>\n            <x-code-viewer src=\"../lib/html.js\"></x-code-viewer>\n            <p>\n                The reworked <code>list.js</code> that uses this:\n            </p>\n            <x-code-viewer src=\"./examples/components/data/components/list-safe.js\" name=\"components/list.js\"></x-code-viewer>\n            <p>To learn more on using this function, check the <a href=\"https://github.com/jsebrech/html-literal\">html-literal documentation</a>.</p>\n        </section>\n        <section id=\"managing-state\">\n            <a href=\"#managing-state\" class=\"section-anchor\">#</a>\n            <h2>Managing state</h2>\n\n            <h3>Where state lives</h3>\n\n            <p>\n                State is the source of truth of what the application should show.\n                It is the data that gets turned into markup on the page by the application's logic.\n            </p>\n            <p>\n                In web frameworks state is often carefully managed so that it lives outside of the DOM,\n                and then rendered into the DOM using a view layer.\n                Every time the state is modified, the view layer rerenders the current view based on the new state, updating the DOM behind the scenes to match the new view.\n                In this design the DOM is just a view on the state, but does not actually contain the state.\n            </p>\n            <p>\n                In vanilla web development however, state and view are merged together inside of a web component.\n                The component carries its state in attributes and properties, making it part of the DOM,\n                and it updates its appearance based on changes in that state in a self-contained way.\n                In this design the DOM ends up being the owner of the state, not just a view on that state.\n            </p>\n            <p>Take for example a simple counter:</p>\n            <iframe src=\"./examples/applications/counter/index.html\" title=\"counter example\" height=\"100\"></iframe>\n\n            <x-tab-panel>\n                <x-tab title=\"index.html\">\n                    <x-code-viewer src=\"./examples/applications/counter/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/applications/counter/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"counter.js\" active>\n                    <x-code-viewer src=\"./examples/applications/counter/components/counter.js\" name=\"components/counter.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>\n                The <code>&lt;x-counter&gt;</code> component carries its state in the <code>#count</code> property,\n                it provides an API for safely changing the state with the <code>increment()</code> method, \n                and it always updates its appearance when the state is changed using the <code>update()</code> method.\n            </p>\n\n            <h3>Lifting state up</h3>\n            <p>\n                Putting state inside of web components as attributes and properties at first can seem simple,\n                but when scaling this up to more complex hierarchies of components it quickly becomes difficult to manage.\n                This means care must be taken to organize state across the component hierarchy in the right way.\n            </p>\n            <p>\n                Generally speaking, the <a href=\"https://react.dev/learn/choosing-the-state-structure\">state management principles</a> laid out in the React documentation are sound and should be followed even for vanilla web development.\n                Here they are once again:\n            </p>\n            <ol>\n                <li><strong>Group related state.</strong> If you always update two or more state variables at the same time, consider merging them into a single state variable.</li>\n                <li><strong>Avoid contradictions in state.</strong> When the state is structured in a way that several pieces of state may contradict and “disagree” with each other, you leave room for mistakes. Try to avoid this.</li>\n                <li><strong>Avoid redundant state.</strong> If you can calculate some information from the component's attributes or properties during rendering, you should not put that information into that component's state.</li>\n                <li><strong>Avoid duplication in state.</strong> When the same data is duplicated between multiple state variables, or within nested objects, it is difficult to keep them in sync. Reduce duplication when you can.</li>\n                <li><strong>Avoid deeply nested state.</strong> Deeply hierarchical state is not very convenient to update. When possible, prefer to structure state in a flat way.</li>\n            </ol>\n\n            <p>\n                Let's look at these principes in action by porting the React <a href=\"https://react.dev/learn/sharing-state-between-components\">lifting state up tutorial</a> example application to vanilla code:\n            </p>\n\n            <iframe src=\"./examples/applications/lifting-state-up/index.html\" title=\"lifting state up example\" height=\"400\"></iframe>\n\n            <p>\n                The implementation is divided across two web components: <code>&lt;x-accordion&gt;</code> and <code>&lt;x-panel&gt;</code>.\n                The state is \"lifted up\" from the panels onto the accordion, so that the accordion carries the state for both panels in a single central place.\n            </p>\n            <p>\n                Each of the two panels is stateless. It receives its state through the <code>title</code> and <code>active</code> properties.\n                When it is active, it shows its children (inside of a slot). When it is not active, it shows a button labeled \"Show\". It always shows the title.\n            </p>\n\n            <x-code-viewer src=\"./examples/applications/lifting-state-up/components/panel.js\" name=\"components/panel.js\"></x-code-viewer>\n\n            <p>\n                By contrast, the accordion is where the state for the panels actually lives:\n            </p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\">\n                    <x-code-viewer src=\"./examples/applications/lifting-state-up/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/applications/lifting-state-up/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/applications/lifting-state-up/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"accordion.js\" active>\n                    <x-code-viewer src=\"./examples/applications/lifting-state-up/components/accordion.js\" name=\"components/accordion.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>What to pay attention to:</p>\n            <ul>\n                <li>\n                    The accordion's <code>activeIndex</code> property carries the state, and everything else is derived from that.\n                    This property becomes the single source of truth for the application, avoiding redundant state.\n                </li>\n                <li>\n                    An event listener for the <code>show</code> event sent by a panel will set <code>activeIndex</code> to the right value.\n                    The property setter for <code>activeIndex</code> explicitly calls the <code>update()</code> method to bring the rest of the DOM in sync with the property's new state.\n                </li>\n            </ul>\n            <p>\n                Finally, take a look at the original implementation of <em>Accordion</em> and <em>Panel</em> in React's tutorial:\n            </p>\n            <x-code-viewer src=\"./examples/applications/lifting-state-up/react/App.js\" name=\"App.js (React)\"></x-code-viewer>\n            <p>\n                Take note of how the state is organized the same across the React and vanilla implementations.\n                The differences are in implementation details for state and rendering, not in how the application is structured.\n            </p>\n\n            <aside>\n                <h4>Tread lightly</h4>\n                <p>\n                    In vanilla web development the components become part of the DOM hierarchy, instead of existing outside of the DOM and having changes applied to it automatically by the framework.\n                    This means the application's state itself becomes part of the DOM.\n                </p>\n                <p>\n                    Because there is no framework patching the DOM with only the parts that changed, we have to tread lightly and only update the DOM when and where that is needed.\n                    Recreating too much of the DOM after a state change risks losing state or causing performance issues.\n                    Each web component in this example renders its fixed DOM structure once in <code>connectedCallback()</code> and then updates those DOM elements in the <code>update()</code> method when the state changes.\n                </p>\n            </aside>\n\n            <h3>Passing data deeply</h3>\n\n            <p>\n                While passing state deep into a hierarchy by handing it from parent components to child components via attributes or properties works,\n                it can quickly become verbose and inconvenient. This is especially the case if you have to pass those through many components in the middle\n                which have no need for that state aside from passing it to their child components, an anti-pattern colloquially known as \"prop drilling\".\n            </p>\n            <p>\n                Again we can take inspiration from how popular frameworks like React organize state, by adapting the concept of a context.\n                A context holds state at a high level in the component hierarchy, and it can be accessed directly from anywhere in that hierarchy.\n                The whole concept of a context is explained in the React <a href=\"https://react.dev/learn/passing-data-deeply-with-context\">passing data deeply tutorial</a>.\n            </p>\n            <p>\n                To understand how to apply this concept in vanilla web development let us look at the ThemeContext example from the <a href=\"https://react.dev/reference/react/useContext\">useContext documentation page</a>.\n                Here is an adapted vanilla version that uses a central context to keep track of light or dark theme, toggled by a button.\n            </p>\n\n            <iframe src=\"./examples/applications/passing-data-deeply/index.html\" title=\"passing data deeply example\" height=\"200\"></iframe>\n\n            <p>\n                In this example a special web component <code>&lt;x-theme-context&gt;</code> is created, whose only job is to keep track of state, provide setters to update that state, and dispatch events when the state changes.\n            </p>\n\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"theme-context.js\">\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/components/theme-context.js\" name=\"components/theme-context.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"tiny-context.js\">\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/lib/tiny-context.js\" name=\"lib/tiny-context.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"panel.js\">\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/components/panel.js\" name=\"components/panel.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"button.js\">\n                    <x-code-viewer src=\"./examples/applications/passing-data-deeply/components/button.js\" name=\"components/button.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>Some key take-aways:</p>\n            <ul>\n                <li>\n                    The <code>x-theme-context</code> component applies the <a href=\"https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md\">context protocol</a>, a convention for how web components can implement a context pattern.\n                    It does this by making use of a minimal implementation of the protocol provided in <code>tiny-context.js</code>.\n                </li>\n                <li>\n                    The context component also uses <code>display: contents</code> to avoid impacting the layout.\n                    It exists in the DOM hierarchy, but it becomes effectively invisible.\n                </li>\n                <li>\n                    Instead of <code>useContext</code> every component obtains the nearest theme context by dispatching a <code>context-request</code> event,\n                    whose callback will be answered by the nearest provider higher up in the DOM that provides the asked for context.\n                    By passing <code>true</code> as the subscribe parameter the components can subscribe to updates.\n                </li>\n                <li>\n                    The <code>theme-toggle</code> function is also provided to the button by the context component. This mechanism can be used for dependency injection across web components.\n                </li>\n            </ul>\n\n            <p>\n                The <a href=\"../blog/articles/2024-10-07-needs-more-context/\">needs more context</a> article does a deeper dive into the context protocol and the tiny-context implementation of it.\n            </p>\n            \n            <aside>\n                <h4>Challenge</h4>\n                <p>\n                    This technique can be further extended to implement the reactive concept of reducers, by adding them as a method on a context component\n                    and updating the state through the setters, dispatching the necessary events to update the component hierarchy.\n                </p>\n                <p>\n                    To prove your mastery of vanilla web development use the techniques you've learned to port the React documentation's example <a href=\"https://react.dev/learn/scaling-up-with-reducer-and-context\">Scaling Up with Reducer and Context</a> to vanilla code.\n                </p>\n            </aside>\n        </section>\n        <section>\n            <h2>Up next</h2>\n            <hr />\n            <p>Go build something vanilla!</p>\n            <p><small>(Or keep reading on the <a href=\"../blog/\">blog</a>.)</small></p>\n        </section>\n    </main>\n\n    <footer>\n        <div class=\"contact\">\n            <a href=\"https://sebrechts.net/\">Contact</a>\n            <a href=\"https://github.com/jsebrech/plainvanilla\">GitHub</a>\n        </div>\n        <p class=\"top-link\">\n            <a href=\"#top\">Back to top</a>\n        </p>\n        <x-analytics></x-analytics>\n    </footer>\n</body>\n</html>"
  },
  {
    "path": "public/pages/components.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla - Components</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <meta name=\"description\" content=\"An explainer for doing web development with vanilla web components.\">\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"../apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"../index.css\">\n    <script type=\"module\" src=\"../index.js\" defer></script>\n</head>\n<body>\n    <noscript><strong>Please enable JavaScript to view this page correctly.</strong></noscript>\n    <header>\n        <h1>Components</h1>\n        <nav id=\"menu-nav\" popover aria-label=\"main\">\n            <ol>\n                <li><a href=\"../index.html\">Welcome</a></li>\n                <li><a href=\"#\" aria-current=\"page\">Components</a></li>\n                <li><a href=\"styling.html\">Styling</a></li>\n                <li><a href=\"sites.html\">Sites</a></li>\n                <li><a href=\"applications.html\">Applications</a></li>\n                <li class=\"nav-right\"><a href=\"../blog/\">Blog</a></li>\n            </ol>\n        </nav>\n        <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n            &mldr;\n        </button>\n    </header>\n    <main>\n        <section id=\"what-are-they\">\n            <a href=\"#what-are-they\" class=\"section-anchor\">#</a>\n            <h2>\n                What are they?\n            </h2>\n            <p>\n                <strong>Web Components</strong> are a set of technologies that allow us to extend \n                the <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element\">standard set of HTML elements</a> with additional elements.\n            </p>\n            <p>\n                The three main technologies are:\n            </p>\n            <dl>\n                <dt><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements\">Custom elements</a></dt>\n                <dd>\n                    A way to extend HTML so that instead of having to build all our markup out of <code>&lt;div&gt;</code>, <code>&lt;input&gt;</code>, <code>&lt;span&gt;</code> and friends, \n                    we can build with higher-level primitives.\n                </dd>\n                <dt><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM\">Shadow DOM</a></dt>\n                <dd>\n                    Extending custom elements to have their own separate DOM, isolating complex behavior inside the element from the rest of the page.\n                </dd>\n                <dt><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots\">HTML templates</a></dt>\n                <dd>\n                    Extending custom elements with reusable markup blocks using the <code>&lt;template&gt;</code> and <code>&lt;slot&gt;</code> tags, for quickly generating complex layouts.\n                </dd>\n            </dl>\n            <p>\n                Those 3 bullets tell you everything and nothing at the same time.\n                This probably isn't the first tutorial on Web Components you've seen, and you may find them a confusing topic.\n                However, they're not that complicated as long as you build them up step by step ...\n            </p>\n        </section>\n        <section id=\"simple-component\">\n            <a href=\"#simple-component\" class=\"section-anchor\">#</a>\n            <h2>A simple component</h2>\n            <p>Let's start with the most basic form, a custom element that says <em>'hello world!'</em>:</p>\n            <x-code-viewer src=\"./examples/components/simple/hello-world.js\"></x-code-viewer>\n            <p>We can use it in a page like this:</p>\n            <x-code-viewer src=\"./examples/components/simple/index.html\"></x-code-viewer>\n            <p>Which outputs this page:</p>\n            <iframe src=\"./examples/components/simple/index.html\" title=\"simple component example\"></iframe>\n            <p>So what's happening here?</p>\n            <p>We created a new HTML element, registered as the <code>x-hello-world</code> tag,\n                and used it on the page. When we did that, we got the following DOM structure:\n                <ul>\n                    <li>body (node)\n                        <ul>\n                            <li>x-hello-world (node)\n                                <ul>\n                                    <li>'hello world!' (textContent)</li>\n                                </ul>\n                            </li>\n                        </ul>\n                    </li>\n                </ul>\n            </p>\n            <p>Explaining the code of the custom element line by line:</p>\n            <dl>\n                <dt><code>class HelloWorldComponent extends HTMLElement {</code></dt>\n                <dd>Every custom element is a class extending <code>HTMLElement</code>. \n                    In theory it's possible to extend other classes &ndash; like <code>HTMLButtonElement</code> to extend a <code>&lt;button&gt;</code> &ndash;\n                    but in practice this <a href=\"https://caniuse.com/mdn-api_customelementregistry_builtin_element_support\">doesn't work in Safari</a>.</dd>\n                <dt><code>connectedCallback() {</code></dt>\n                <dd>\n                    This method is called when our element is added to the DOM,\n                    which means the element is ready to make DOM updates.\n                    Note that it may be called multiple times when the element or one of its ancestors is moved around the DOM.\n                </dd>\n                <dt><code>this.textContent = 'hello world!';</code></dt>\n                <dd>The <code>this</code> in this case refers to our element, which has the full <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement\">HTMLElement</a> API,\n                    including its ancestors <code>Element</code> and <code>Node</code>, on which we can find the <code>textContent</code> property\n                    which is used to add the <code>'hello world!'</code> string to the DOM.</dd>\n                <dt><code>customElements.define('x-hello-world', HelloWorldComponent);</code></dt>\n                <dd>For every web component <code>window.customElements.define</code> must be called once to register the custom element's class and associate it with a tag.\n                    After this line is called the custom element becomes available for use in HTML markup, and existing uses of it in already rendered markup will have their constructors called.</dd>\n            </dl>\n            <aside>\n                <h3>Why is it named <code>x-hello-world</code> instead of <code>hello-world</code>?</h3>\n                <p>\n                There are <a href=\"https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name\">custom element tag naming rules</a>, in particular that the name must start with a lowercase letter and contain a dash.\n                On top of that, all tags take part in a global namespace, where there is always a risk of conflicting naming.\n                While <code>hello-world</code> would also be a valid name, in general it is best to start all custom element tag names with a unique prefix of your choice. On this site the placeholder prefix <code>x-</code> was chosen.\n                </p>\n                <p>\n                Another gotcha is that custom element tags cannot be self-closing.\n                So <code>&lt;x-hello-world&gt;&lt;/x-hello-world&gt;</code> is ok, but <code>&lt;x-hello-world /&gt;</code> is not.\n                </p>\n            </aside>\n        </section>\n        <section id=\"advanced-component\">\n            <a href=\"#advanced-component\" class=\"section-anchor\">#</a>\n            <h2>An advanced component</h2>\n            <p>\n                While the simple version above works for a quick demo, you'll probably want to do more pretty quickly:\n            </p>\n            <ul>\n                <li>Adding DOM elements as children to allow for richer content.</li>\n                <li>Passing in attributes, and updating the DOM based on changes in those attributes.</li>\n                <li>Styling the element, preferably in a way that's isolated and scales nicely.</li>\n                <li>Defining all custom elements from a central place, instead of dumping random script tags in the middle of our markup.</li>\n            </ul>\n            <p>\n                To illustrate a way to do those things with custom elements, here's a custom element <code>&lt;x-avatar&gt;</code> that implements\n                a simplified version of the <a href=\"https://www.heroui.com/docs/components/avatar\">HeroUI Avatar component</a> (React):\n            </p>\n\n            <iframe src=\"./examples/components/advanced/simple.html\" title=\"avatar component example\" height=\"70\"></iframe>\n            <x-code-viewer src=\"./examples/components/advanced/components/avatar.js\" name=\"components/avatar.js\"></x-code-viewer>\n            <p>Some key elements that have changed:</p>\n            <ul>\n                <li>The <code>observedAttributes</code> getter returns the element's attributes that when changed cause <code>attributeChangedCallback()</code> to be called by the browser, allowing us to update the UI.</li>\n                <li>\n                    The <code>connectedCallback</code> method is written in the assumption that it will be called multiple times.\n                    This method is in fact called when the element is first added to the DOM, but also when it is moved around.\n                </li>\n                <li>\n                    The <code>update()</code> method handles initial render as well as updates, centralizing the UI logic.\n                    Note that this method is written in a defensive way with the <code>if</code> statement, because it may be called from the <code>attributeChangedCallback()</code> method before <code>connectedCallback()</code> creates the <code>&lt;img&gt;</code> element.\n                </li>\n                <li>The exported <code>registerAvatarComponent</code> function allows centralizing the logic that defines all custom elements in an application.</li>\n            </ul>\n            <p>Once rendered this avatar component will have this DOM structure:</p>\n            <ul>\n                <li>body (node)\n                    <ul>\n                        <li>x-avatar (node)\n                            <ul>\n                                <li>img (node)\n                                    <ul>\n                                        <li>src (attribute)</li>\n                                        <li>alt (attribute)</li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </li>\n                    </ul>\n                </li>\n            </ul>\n            <p>For styling of our component we can use a separate css file:</p>\n            <x-code-viewer src=\"./examples/components/advanced/components/avatar.css\" name=\"components/avatar.css\"></x-code-viewer>\n            <p>Notice that:</p>\n            <ul>\n                <li>Because we know what the tag of our component is, we can easily scope the styles by prepending them with <code>x-avatar</code>, so they won't conflict with the rest of the page.</li>\n                <li>Because a custom element is just HTML, we can style based on the element's custom attributes in pure CSS, like the <code>size</code> attribute which resizes the component without any JavaScript.</li>\n            </ul>\n\n            <p>An example that shows the two different sizes on a webpage:</p>\n            <iframe src=\"./examples/components/advanced/index.html\" title=\"avatar component second example\"></iframe>\n\n            <p>\n                The HTML for this example centralizes the JavaScript and CSS logic to two index files, to make it easier to scale out to more web components.\n                This pattern, or a pattern like it, can keep things organized in a web application that is built out of dozens or hundreds of different web components.\n            </p>\n\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/components/advanced/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/components/advanced/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/components/advanced/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>\n                The <code>&lt;script&gt;</code> tag in this example has moved into the <code>&lt;head&gt;</code> and picked up a <code>defer</code> attribute.\n                This will allow it to download in parallel with the rest of the page, and have it execute right when the page is loaded.\n            </p>\n            <p>\n                In <code>index.css</code> the use of the <code>@import</code> keyword may seem surprising as this keyword is often frowned upon for performance reasons.\n                However, in modern browsers over HTTP/2 and in particular HTTP/3 the performance penalty of this keyword is not that severe,\n                especially because files included with <code>@import</code> now download in parallel.\n            </p>\n            \n            <aside>\n                <h3>Don't we need a bundler?</h3>\n                <p>\n                    If you've paid close attention, you have seen that we're using the <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\">ES module syntax</a> for <code>import</code> and <code>export</code> in our code,\n                    but we haven't set up any JavaScript bundler to transpile that syntax. The magic that makes this work is in <code>index.html</code>,\n                    where the <code>&lt;script&gt;</code> tag's <code>type=\"module\"</code> attribute enables ES module mode for all the included JavaScript.\n                    This is supported by all modern browsers.\n                </p>\n            </aside>\n        </section>\n        <section id=\"adding-children\">\n            <a href=\"#adding-children\" class=\"section-anchor\">#</a>\n            <h2>Adding Children</h2>\n            <p>\n                Allowing children to be added to a web component is not hard. In fact, it is the default behavior.\n                To see how this works, let's extend the avatar example by wrapping it with a badge:\n            </p>\n            <iframe src=\"./examples/components/adding-children/index.html\" title=\"component with children example\"></iframe>\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/components/adding-children/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/components/adding-children/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/components/adding-children/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>To clarify, this is the DOM structure that is created:</p>\n            <ul>\n                <li>div (node)\n                    <ul>\n                        <li>x-badge (node)\n                            <ul>\n                                <li>content (attribute)</li>\n                                <li>span (node, showing content)</li>\n                                <li>x-avatar (node)</li>\n                            </ul>\n                        </li>\n                        <li>input (node)</li>\n                    </ul>\n                </li>\n            </ul>\n\n            <p>The <code>x-avatar</code> component is identical to the previous example, but how does the <code>x-badge</code> work?</p>\n\n            <x-tab-panel>\n                <x-tab title=\"badge.js\" active>\n                    <x-code-viewer src=\"./examples/components/adding-children/components/badge.js\" name=\"components/badge.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"badge.css\">\n                    <x-code-viewer src=\"./examples/components/adding-children/components/badge.css\" name=\"components/badge.css\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>Some notes on what's happening here:</p>\n            <dl>\n                <dt><code>this.insertBefore</code></dt>\n                <dd>\n                    <p>\n                        Care must be taken to not overwrite the children already added in the markup, for example by assigning to <code>innerHTML</code>. \n                        In this case the span that shows the badge is inserted before the child elements.\n                    </p>\n                    <p>\n                        This also means that for custom elements that should not have children,\n                        this can be enforced by calling <code>this.innerHTML = ''</code> from <code>connectedCallback()</code>.\n                    </p>\n                </dd>\n                <dt><code>set content(value) {</code></dt>\n                <dd>\n                    Custom element attributes can only be accessed from JavaScript through the <code>setAttribute()</code> and <code>getAttribute()</code> methods.\n                    To have a cleaner JavaScript API a setter and getter must be created for a class property that wraps the custom element's <code>content</code> attribute.\n                    See the <code>index.html</code> above for where this is called.\n                </dd>\n            </dl>\n            <aside class=\"aside-mirror\">\n                <h3>Detecting children</h3>\n                <p>\n                    Knowing when children are added or removed to a web component is possible with a <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver\">MutationObserver</a>, \n                    by calling its observe method with <code>observer.observe(this, { childList: true })</code>.\n                    Creating it in the constructor will observe a mutation of type <code>childList</code> when the child elements are first added, and also when later on elements are added or removed.\n                </p>\n            </aside>\n        </section>\n        <section id=\"bells-and-whistles\">\n            <a href=\"#bells-and-whistles\" class=\"section-anchor\">#</a>\n            <h2>Bells and whistles</h2>\n            <p>\n                Having seen what regular web components look like, we're now ready to jump up to the final difficulty level of web components, \n                leveraging the more advanced features of Shadow DOM and HTML templates.\n            </p>\n            \n            <p>This can all be brought together in this page layout example, that defines a new <code>&lt;x-header&gt;</code> component:</p>\n            <iframe src=\"./examples/components/shadow-dom/index.html\" title=\"shadow dom component example\" height=\"200\"></iframe>\n            <x-code-viewer src=\"./examples/components/shadow-dom/index.html\"></x-code-viewer>\n\n            <p>This is the code for the newly added <code>&lt;x-header&gt;</code> component:</p>\n            <x-code-viewer src=\"./examples/components/shadow-dom/components/header.js\" name=\"components/header.js\"></x-code-viewer>\n\n            <p>There's a <em>lot</em> happening in <code>header.js</code>, so let's unpack.</p>\n            <dl>\n                <dt><code>const template = document.createElement('template');</code></dt>\n                <dd>\n                    The header code starts out by creating an <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots\">HTML template</a>.\n                    Templates are fragments of HTML that can be easily cloned and appended to a DOM.\n                    For complex web components that have a lot of markup, the use of a template is often convenient.\n                    By instantiating the template outside the class, it can be reused across all instances of the <code>&lt;x-header&gt;</code> component.\n                </dd>\n                <dt><code>&lt;link rel=\"stylesheet\" href=\"${import.meta.resolve('./header.css')}\"&gt;</code></dt>\n                <dd>\n                    Because this component uses a shadow DOM, it is isolated from the styles of the containing page and starts out unstyled.\n                    The <code>header.css</code> needs to be imported into the shadow DOM using the <code>&lt;link&gt;</code> tag.\n                    The special <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve\">import.meta.resolve</a> trick \n                    imports the CSS file from the same path as the <code>header.js</code> file.\n                </dd>\n                <dt><code>&lt;slot&gt;&lt;/slot&gt;</code></dt>\n                <dd>\n                    The <code>&lt;slot&gt;</code> element is where the child elements will go (like the <code>&lt;x-badge&gt;</code> child of <code>&lt;x-header&gt;</code>).\n                    Putting child elements in a slot is similar to using a <code>children</code> prop in a React component.\n                    The use of slots is only possible in web components that have a shadow DOM.\n                </dd>\n                <dt><code>constructor() {</code></dt>\n                <dd>\n                    <p>\n                        This is the first example that uses a constructor. The constructor is called when the element is first created,\n                        but before it's ready for DOM interaction. The default behavior of a constructor is to call the parent class's constructor <code>super()</code>.\n                        So if all that is needed is the default HTMLElement constructor behavior then no constructor needs to be specified.\n                    </p>\n                    <p>\n                        The reason it is specified here is because the constructor is guaranteed to be called exactly once,\n                        which makes it the ideal place to attach a shadow DOM.\n                    </p>\n                </dd>\n                <dt><code>if (!this.shadowRoot) { this.attachShadow({ mode: 'open' });</code></dt>\n                <dd>\n                    <p>\n                        <code>attachShadow</code> attaches a shadow DOM to the current element, an isolated part of the DOM structure with CSS separated from the containing page,\n                        and optionally with the shadow content hidden away from the parent page's JavaScript context (if <code>mode: 'closed'</code> is set).\n                        For web components that are used in a known codebase, it is usually more convenient to use them in open mode,\n                        as is done here.    \n                    </p>\n                    <p>\n                        <code>if (!this.shadowRoot) {</code> is not strictly necessary, but allows for server-side generated HTML,\n                        by making use of <a href=\"https://web.dev/articles/declarative-shadow-dom\">declarative shadow DOM</a>.\n                    </p>\n                </dd>\n                <dt><code>this.shadowRoot.append(template.content.cloneNode(true));</code></dt>\n                <dd>\n                    <p>\n                        The <code>shadowRoot</code> property is the root element of the attached shadow DOM, and is rendered into the page as the <code>&lt;x-header&gt;</code> element's content.\n                        The HTML template is cloned and appended into it.\n                    </p>\n                    <p>\n                        The shadow DOM becomes immediately available as soon as <code>attachShadow</code> is called,\n                        which is why the template can be appended in the constructor, and why the <code>update()</code> method can be called there.\n                        For custom elements without shadow DOM rendering the element's content should be deferred until <code>connectedCallback()</code>.\n                    </p>\n                </dd>\n            </dl>\n\n            <p>All the new files of this example put together:</p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/components/shadow-dom/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/components/shadow-dom/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"reset.css\">\n                    <x-code-viewer src=\"./examples/components/shadow-dom/reset.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/components/shadow-dom/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"header.js\">\n                    <x-code-viewer src=\"./examples/components/shadow-dom/components/header.js\" name=\"components/header.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"header.css\">\n                    <x-code-viewer src=\"./examples/components/shadow-dom/components/header.css\" name=\"components/header.css\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>As you can see in <code>header.css</code>, styling the content of a shadow DOM is a bit different:</p>\n            <ul>\n                <li>The <code>:host</code> pseudo-selector applies styles to the element from the light DOM that hosts the shadow DOM (or in other words, to the custom element itself).</li>\n                <li>The other styles (like <code>h1</code> in this example) are isolated inside the shadow DOM.</li>\n                <li>The shadow DOM starts out unstyled, which is why <code>reset.css</code> is imported again.</li>\n            </ul>\n\n            <aside>\n                <h3>To shadow or not to shadow?</h3>\n                <p>\n                    Because custom elements can contain children with or without a shadow DOM, you may be wondering when to use this feature.\n                </p>\n                <p>\n                    Shadow DOM comes with a number of downsides:\n                </p>\n                <ul>\n                    <li>There is a <a href=\"../blog/articles/2024-09-06-how-fast-are-web-components/\">performance penalty</a>, noticeable when putting hundreds of shadow DOMs on a page.</li>\n                    <li>It can cause <a href=\"https://nolanlawson.com/2022/11/28/shadow-dom-and-accessibility-the-trouble-with-aria/\">accessibility issues</a>.</li>\n                    <li>While Google can crawl inside shadow DOM, <a href=\"https://help.siteimprove.com/support/solutions/articles/80001132321-shadow-dom-support\">other crawlers may have trouble</a>.</li>\n                    <li>\n                        There can be a <abbr title=\"Flash Of Unstyled Content\">FOUC</abbr> while a stylesheet from a <code>&lt;link&gt;</code> tag is loading.\n                        This can be worked around with <a href=\"https://web.dev/articles/constructable-stylesheets\">constructable stylesheets</a>, but this adds complexity.\n                    </li>\n                </ul>\n                <p>\n                    For those reasons, if you're not making components for someone else, you may find it easier to avoid shadow DOM.\n                </p>\n                <p>Shadow DOM is however recommended in these situations:</p>\n                <ul>\n                    <li>Intermediate elements need to be created between the root element and the contained children, like the <code>&lt;header&gt;</code> in the example above. Only the use of a slot inside of a shadow DOM makes this possible.</li>\n                    <li>Multiple places in the web component will accept children. Named slots provide this ability. This can be convenient for layout components.</li>\n                    <li>The styles and DOM need to be isolated from the containing page. This is often the case for web components designed to be used by others or embedded in third-party sites.</li>\n                </ul>\n            </aside>\n        </section>\n        <section id=\"passing-data\">\n            <a href=\"#passing-data\" class=\"section-anchor\">#</a>\n            <h2>Passing Data</h2>\n            <p>\n                Everything up to this point assumes that data passed between web components is very simple, just simple numeric and string attributes passing down.\n                A real world web application however passes complex data such as objects and arrays between parent and child components.\n            </p>\n            <p>\n                This example demonstrates the three major ways that data can be passed between web components:\n            </p>\n            <iframe src=\"./examples/components/data/index.html\" title=\"data passing example\" style=\"height: 250px;\"></iframe>\n            \n            <h3>Events</h3>\n            <p>The first way is passing events, usually from child components to their parent component. This is demonstrated by the form at the top of the example.</p>\n            <x-code-viewer src=\"./examples/components/data/components/form.js\" name=\"components/form.js\"></x-code-viewer>\n            <p>\n                Every time the <strong>Add</strong> button is pressed a <code>CustomEvent</code> of type <code>add</code> is dispatched using the <code>dispatchEvent</code> method.\n                The event data's <code>detail</code> property carries the submitted form data.\n            </p>\n            <p>The event is handled one level up:</p>\n            <x-code-viewer src=\"./examples/components/data/components/app.js\" name=\"components/app.js\"></x-code-viewer>\n            <p>The <code>update()</code> method sends the updated list back down to the <code>&lt;santas-list&gt;</code> and <code>&lt;santas-summary&gt;</code> components, using the next two methods.</p>\n\n            <aside>\n                <h3>Memory leak?</h3>\n                <p>\n                    You may be wondering if real world code would need a <code>removeEventListener()</code> to prevent memory leaks.\n                    In most cases the answer is a surprising <em>no</em>, because DOM event listeners are weakly bound and do not prevent\n                    garbage collection of the thing they are listening to. If it soothes your mind, you're still free to add those remove calls anyway.\n                </p>\n            </aside>\n\n            <h3>Properties</h3>\n            <p>The second way to pass complex data is by using class properties, as exemplified by the <code>&lt;santas-list&gt;</code> component:</p>\n            <x-code-viewer src=\"./examples/components/data/components/list.js\" name=\"components/list.js\"></x-code-viewer>\n            <p>The <code>list</code> setter calls the <code>update()</code> method to rerender the list.</p>\n            <p>This is the recommended way to pass complex data to stateful web components.</p>\n\n            <p>\n                The best practice way of implementing attributes, properties and events is subtle and opinionated.\n                The article <a href=\"../blog/articles/2025-04-21-attribute-property-duality/\">The Attribute-Property Duality</a> dives into this topic in depth,\n                and is recommended reading when making web components that will be embedded in third-party sites or are otherwise expected to behave\n                like built-in elements.\n            </p>\n\n            <aside class=\"aside-mirror\">\n                <h3>Beware of XSS</h3>\n                <p>\n                    Keen observers may have noticed there's a cross-site scripting bug in the above example.\n                    This can be solved by properly encoding entities for <code>person.name</code>.\n                    To see how this can be done, check out the <a href=\"applications.html#entity-encoding\">entity encoding</a> chapter on the Applications page.\n                </p>\n            </aside>\n\n            <h3>Methods</h3>\n            <p>The third way to pass complex data is by calling a method on the web component, as exemplified by the <code>&lt;santas-summary&gt;</code> component:</p>\n            <x-code-viewer src=\"./examples/components/data/components/summary.js\" name=\"components/summary.js\"></x-code-viewer>\n            <p>This is the recommended way to pass complex data to stateless web components.</p>\n\n            <h3>Complete example</h3>\n            <p>Finally then, here is all the code for the Santa's List application:</p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/components/data/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/components/data/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/components/data/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"app.js\">\n                    <x-code-viewer src=\"./examples/components/data/components/app.js\" name=\"components/app.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"form.js\">\n                    <x-code-viewer src=\"./examples/components/data/components/form.js\" name=\"components/form.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"list.js\">\n                    <x-code-viewer src=\"./examples/components/data/components/list.js\" name=\"components/list.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"summary.js\">\n                    <x-code-viewer src=\"./examples/components/data/components/summary.js\" name=\"components/summary.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n        </section>\n        <section>\n            <aside>\n                <h3>The power of the browser</h3>\n                <p>\n                    A reminder that all of this code is still vanilla. It does not make use of any framework, library or build tool and works in all the major browsers.\n                    It will never need changes to be compatible with new dependency versions.\n                    And most importantly, it remains readable and maintainable.\n                </p>\n                <p>\n                    There's still more to say on web components. For a deeper dive, \n                    check out this article on <a href=\"../blog/articles/2024-09-16-life-and-times-of-a-custom-element/\">the web component lifecycle</a>.\n                </p>\n            </aside>\n        </section>\n        <section>\n            <h2>Up next</h2>\n            <hr />\n            <p>Learn about styling Web Components in ways that are encapsulated and reusable.</p>\n            <p><a href=\"styling.html\" class=\"button\">Add Styling</a></p>\n        </section>\n    </main>\n\n    <footer>\n        <div class=\"contact\">\n            <a href=\"https://sebrechts.net/\">Contact</a>\n            <a href=\"https://github.com/jsebrech/plainvanilla\">GitHub</a>\n        </div>\n        <p class=\"top-link\">\n            <a href=\"#top\">Back to top</a>\n        </p>\n        <x-analytics></x-analytics>\n    </footer>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/applications/counter/components/counter.js",
    "content": "class Counter extends HTMLElement {\n    #count = 0;\n\n    increment() {\n        this.#count++;\n        this.update();\n    }\n\n    connectedCallback() {\n        this.update();\n    }\n\n    update() {\n        this.textContent = this.#count;\n    }\n}\n\nexport const registerCounterComponent =\n    () => customElements.define('x-counter', Counter);\n"
  },
  {
    "path": "public/pages/examples/applications/counter/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <style> \n        body { font-family: system-ui, sans-serif; }\n        x-counter { color: red; }\n    </style>\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <p>Let's count to <x-counter></x-counter>.</p>\n    <button onclick=\"document.querySelector('x-counter').increment()\">\n        Increment\n    </button>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/applications/counter/index.js",
    "content": "import { registerCounterComponent } from './components/counter.js';\n\nconst app = () => {\n    registerCounterComponent();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/applications/lifting-state-up/components/accordion.js",
    "content": "class Accordion extends HTMLElement {\n    #activeIndex = 0;\n\n    get activeIndex () { return this.#activeIndex; }\n    set activeIndex(index) { this.#activeIndex = index; this.update(); }\n\n    connectedCallback() {\n        this.innerHTML = `\n            <h2>Almaty, Kazakhstan</h2>\n            <x-panel\n                title=\"About\">\n                With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.\n            </x-panel>\n            <x-panel\n                title=\"Etymology\">\n                The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.\n            </x-panel>\n        `;\n        this.querySelectorAll('x-panel').forEach((panel, index) => {\n            panel.addEventListener('show', () => {\n                this.activeIndex = index;\n            });\n        })\n        this.update();\n    }\n\n    update() {\n        this.querySelectorAll('x-panel').forEach((panel, index) => {\n            panel.setAttribute('active', index === this.activeIndex);\n        });\n    }\n}\n\nexport const registerAccordionComponent = () => {\n    customElements.define('x-accordion', Accordion);\n}\n"
  },
  {
    "path": "public/pages/examples/applications/lifting-state-up/components/panel.js",
    "content": "class Panel extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n    }\n\n    connectedCallback() {\n        this.shadowRoot.innerHTML = `\n            <section className=\"panel\">\n                <h3></h3>\n                <slot></slot>\n                <button>Show</button>\n            </section>\n        `;\n        this.shadowRoot.querySelector('button').onclick = \n            () => this.dispatchEvent(new CustomEvent('show'));\n        this.update();\n    }\n\n    static get observedAttributes() { return ['title', 'active']; }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const heading = this.shadowRoot.querySelector('h3');\n        const slot = this.shadowRoot.querySelector('slot');\n        const button = this.shadowRoot.querySelector('button');\n        if (heading && slot && button) {\n            heading.textContent = this.title;\n            slot.style.display = this.getAttribute('active') === 'true' ? 'block' : 'none';\n            button.style.display = this.getAttribute('active') === 'true' ? 'none' : 'inline';    \n        }\n    }\n}\n\nexport const registerPanelComponent =\n    () => customElements.define('x-panel', Panel);\n"
  },
  {
    "path": "public/pages/examples/applications/lifting-state-up/index.css",
    "content": "body {\n    font-family: system-ui, sans-serif;\n}"
  },
  {
    "path": "public/pages/examples/applications/lifting-state-up/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <x-accordion></x-accordion>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/applications/lifting-state-up/index.js",
    "content": "import { registerAccordionComponent } from './components/accordion.js';\nimport { registerPanelComponent } from './components/panel.js';\n\nconst app = () => {\n    registerAccordionComponent();\n    registerPanelComponent();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/applications/lifting-state-up/react/App.js",
    "content": "import { useState } from 'react';\n\nexport default function Accordion() {\n  const [activeIndex, setActiveIndex] = useState(0);\n  return (\n    <>\n      <h2>Almaty, Kazakhstan</h2>\n      <Panel\n        title=\"About\"\n        isActive={activeIndex === 0}\n        onShow={() => setActiveIndex(0)}\n      >\n        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.\n      </Panel>\n      <Panel\n        title=\"Etymology\"\n        isActive={activeIndex === 1}\n        onShow={() => setActiveIndex(1)}\n      >\n        The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.\n      </Panel>\n    </>\n  );\n}\n\nfunction Panel({\n  title,\n  children,\n  isActive,\n  onShow\n}) {\n  return (\n    <section className=\"panel\">\n      <h3>{title}</h3>\n      {isActive ? (\n        <p>{children}</p>\n      ) : (\n        <button onClick={onShow}>\n          Show\n        </button>\n      )}\n    </section>\n  );\n}\n"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/components/button.js",
    "content": "import { ContextRequestEvent } from \"../lib/tiny-context.js\";\n\nclass ButtonComponent extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n    }\n\n    #theme = 'light';\n    #unsubscribe;\n\n    connectedCallback() {\n        this.shadowRoot.innerHTML = `\n            <link rel=\"stylesheet\" href=\"${import.meta.resolve('../index.css')}\">\n            <button>\n                <slot></slot>\n            </button>\n        `;\n        this.dispatchEvent(new ContextRequestEvent('theme', (theme, unsubscribe) => {\n            this.#theme = theme;\n            this.#unsubscribe = unsubscribe;\n            this.update();\n        }, true));\n        this.dispatchEvent(new ContextRequestEvent('theme-toggle', (toggle) => {\n            this.shadowRoot.querySelector('button').onclick = toggle;\n        }));\n        this.update();\n    }\n\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n\n    update() {\n        const button = this.shadowRoot.querySelector('button');\n        if (button) button.className = 'button-' + this.#theme;\n    }\n}\n\nexport const registerButtonComponent = \n    () => customElements.define('x-button', ButtonComponent);\n"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/components/panel.js",
    "content": "import { ContextRequestEvent } from \"../lib/tiny-context.js\";\n\nclass PanelComponent extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n    }\n\n    #theme = 'light';\n    #unsubscribe;\n\n    connectedCallback() {\n        this.shadowRoot.innerHTML = `\n            <link rel=\"stylesheet\" href=\"${import.meta.resolve('../index.css')}\">\n            <section>\n                <h1></h1>\n                <slot></slot>\n            </section>\n        `;\n        this.dispatchEvent(new ContextRequestEvent('theme', (theme, unsubscribe) => {\n            this.#theme = theme;\n            this.#unsubscribe = unsubscribe;\n            this.update();\n        }, true));\n        this.update();\n    }\n\n    disconnectedCallback() {\n        this.#unsubscribe?.();\n    }\n\n    static get observedAttributes() {\n        return ['title'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const h1 = this.shadowRoot.querySelector('h1');\n        const section = this.shadowRoot.querySelector('section');\n        if (section && h1) {\n            section.className = 'panel-' + this.#theme;\n            h1.textContent = this.getAttribute('title');\n        }\n    }\n}\n\nexport const registerPanelComponent = \n    () => customElements.define('x-panel', PanelComponent);\n"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/components/theme-context.js",
    "content": "import { ContextProvider } from \"../lib/tiny-context.js\";\n\nclass ThemeContext extends HTMLElement {\n\n    themeProvider = new ContextProvider(this, 'theme', 'light');\n    toggleProvider = new ContextProvider(this, 'theme-toggle', () => {\n        this.themeProvider.value = this.themeProvider.value === 'light' ? 'dark' : 'light';\n    });\n\n    connectedCallback() {\n        this.style.display = 'contents';\n    }\n}\n\nexport const registerThemeContext = \n    () => customElements.define('x-theme-context', ThemeContext);\n"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/index.css",
    "content": ":root {\n    font-family: sans-serif;\n}\n\nbody {\n    margin: 20px;\n    padding: 0;\n}\n\n* {\n    box-sizing: border-box;\n}\n\nh1 {\n    margin-top: 0;\n    font-size: 22px;\n}\n\n.panel-light,\n.panel-dark {\n  border: 1px solid black;\n  border-radius: 4px;\n  padding: 20px;\n}\n.panel-light {\n  color: #222;\n  background: #fff;\n}\n\n.panel-dark {\n  color: #fff;\n  background: rgb(23, 32, 42);\n}\n\n.button-light,\n.button-dark {\n  border: 1px solid #777;\n  padding: 5px;\n  margin-right: 10px;\n  margin-top: 10px;\n}\n\n.button-dark {\n  background: #222;\n  color: #fff;\n}\n\n.button-light {\n  background: #fff;\n  color: #222;\n}\n"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <x-theme-context>\n        <x-panel title=\"Welcome\">\n            <x-button>Toggle theme</x-button>\n        </x-panel>\n    </x-theme-context>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/index.js",
    "content": "import { registerThemeContext } from './components/theme-context.js';\nimport { registerPanelComponent } from './components/panel.js';\nimport { registerButtonComponent } from './components/button.js';\n\nconst app = () => {\n    registerThemeContext();\n    registerPanelComponent();\n    registerButtonComponent();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/applications/passing-data-deeply/lib/tiny-context.js",
    "content": "export class ContextRequestEvent extends Event {\n    constructor(context, callback, subscribe) {\n        super('context-request', {\n            bubbles: true,\n            composed: true,\n        });\n        this.context = context;\n        this.callback = callback;\n        this.subscribe = subscribe;\n    }\n}\n\nexport class ContextProvider extends EventTarget {\n    #value;\n    get value() { return this.#value }\n    set value(v) { this.#value = v; this.dispatchEvent(new Event('change')); }\n\n    #context;\n    get context() { return this.#context }\n\n    constructor(target, context, initialValue = undefined) {\n        super();\n        this.#context = context;\n        this.#value = initialValue;\n        if (target) this.attach(target);\n    }\n    \n    attach(target) {\n        target.addEventListener('context-request', this);\n    }\n\n    detach(target) {\n        target.removeEventListener('context-request', this);\n    }\n\n    /**\n     * Handle a context-request event\n     * @param {ContextRequestEvent} e \n     */\n    handleEvent(e) {\n        if (e.context === this.context) {\n            if (e.subscribe) {\n                const unsubscribe = () => this.removeEventListener('change', update);\n                const update = () => e.callback(this.value, unsubscribe);\n                this.addEventListener('change', update);\n                update();\n            } else {\n                e.callback(this.value);\n            }\n            e.stopPropagation();\n        }\n    }\n}\n"
  },
  {
    "path": "public/pages/examples/applications/single-page/app/App.js",
    "content": "class App extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n        <h1>Basic Example</h1>\n\n        <p>\n            This example demonstrates how the features of a framework router\n            can be approximated using web components and a vanilla hash router.\n        </p>\n        <p>\n            Check out the original <a href=\"https://github.com/remix-run/react-router/tree/dev/examples/basic\" target=\"_blank\">React Router basic example</a> for comparison.\n        </p>\n\n        <!-- Routes can be nested, but the path must always be fully specified. -->\n        <x-route path=\"/\">\n            <x-app-layout></x-app-layout>\n            <x-route path=\"/\" exact>\n                <h2>Home</h2>\n            </x-route>\n            <x-route path=\"/about\" exact>\n                <h2>About</h2>\n            </x-route>\n            <x-route path=\"/dashboard\" exact>\n                <h2>Dashboard</h2>\n            </x-route>\n            <x-route path=\"*\">\n                <h2>Nothing to see here</h2>\n                <a href=\"#/\">Go to the home page</a>\n            </x-route>\n        </x-route>\n        `;\n    }\n}\n\nclass AppLayout extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = `\n        <nav>\n            <ul>\n                <li><a href=\"#/\">Home</a></li>\n                <li><a href=\"#/about\">About</a></li>\n                <li><a href=\"#/dashboard\">Dashboard</a></li>\n                <li><a href=\"#/nothing-here\">Nothing Here</a></li>\n            </ul>\n        </nav>\n        <hr />\n        `;\n    }\n}\n\nexport const registerApp = () => {\n    customElements.define('x-app', App);\n    customElements.define('x-app-layout', AppLayout);\n}\n"
  },
  {
    "path": "public/pages/examples/applications/single-page/components/route/route.js",
    "content": "/**\n * Usage:\n * <x-route path=\"/\" exact><p>hello</p><x-route> = only match #/ (or no hash) and show the text \"hello\"\n * <x-route path=\"/\"> = match every route below / (e.g. for site navigation)\n * <x-route path=\"/about\" exact> = only match #/about exactly\n * <x-route path=\"/todos/([\\w]+)\"> = match #/todos/:id and pass id to routeChangedCallback\n * <x-route path=\"/notebooks/([\\w]+)(?:/([\\w]+))?\"> = match #/notebooks/:id and /notebooks/:id/:note and pass id and note to routeChangedCallback\n * <x-route path=\"*\"> = match if no other route matches within the same parent node\n */\nexport class RouteComponent extends HTMLElement {\n\n    constructor() {\n        super();\n        this.update = this.update.bind(this);\n        this.style.display = 'contents';\n    }\n\n    #isActive = false;\n\n    get isActive() {\n        return this.#isActive;\n    }\n\n    connectedCallback() {\n        this.classList.toggle('route', true);\n        window.addEventListener('hashchange', this.update);\n        this.update();\n    }\n\n    disconnectedCallback() {\n        window.removeEventListener('hashchange', this.update);        \n    }\n\n    static get observedAttributes() {\n        return ['path', 'exact'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const path = this.getAttribute('path') || '';\n        const exact = this.hasAttribute('exact');\n        const matches = this.#matchesRoute(path, exact);\n        this.#isActive = !!matches;\n        this.setIsActive(this.#isActive);\n        this.routeChangedCallback.apply(this, matches ? matches.slice() : []);\n    }\n\n    // can be overridden in subclasses to change show/hide method\n    setIsActive(active) {\n        this.style.display = active ? 'contents' : 'none';\n    }\n\n    // for overriding in subclasses to detect parameters\n    // eslint-disable-next-line no-unused-vars\n    routeChangedCallback(...matches) {}\n\n    #matchesRoute(path, exact) {\n        let matches;\n        // '*' triggers fallback route if no other route matches\n        if (path === '*') {\n            const activeRoutes = \n                Array.from(this.parentNode.querySelectorAll('.route')).filter(_ => _.isActive);\n            if (!activeRoutes.length) matches = ['*'];\n        // normal routes\n        } else {\n            const regex = new RegExp(`^#${path.replaceAll('/', '\\\\/')}${exact ? '$' : ''}`, 'gi');\n            const currentPath = window.location.hash || '#/';\n            matches = regex.exec(currentPath);\n        }\n        return matches;\n    }\n}\n\nexport const registerRouteComponent = () => customElements.define('x-route', RouteComponent);\n"
  },
  {
    "path": "public/pages/examples/applications/single-page/index.css",
    "content": "body {\n    font-family: system-ui, sans-serif;\n}"
  },
  {
    "path": "public/pages/examples/applications/single-page/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Single-page Example</title>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <noscript><strong>Please enable JavaScript to view this page.</strong></noscript>\n    <template id=\"root\">\n        <x-app></x-app>\n    </template>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/applications/single-page/index.js",
    "content": "import { registerApp } from \"./app/App.js\";\nimport { registerRouteComponent } from \"./components/route/route.js\";\n\nconst app = () => {\n    registerRouteComponent();\n    registerApp();\n\n    const template = document.querySelector('template#root');\n    if (template) document.body.appendChild(template.content, true);\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/components/adding-children/components/avatar.css",
    "content": "x-avatar {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 2.5rem;\n    height: 2.5rem;\n}\n\nx-avatar[size=lg] {\n    width: 3.5rem;\n    height: 3.5rem;\n}\n\nx-avatar img {\n    border-radius: 9999px;\n    width: 100%;\n    height: 100%;\n    vertical-align: middle;\n    object-fit: cover;\n}\n"
  },
  {
    "path": "public/pages/examples/components/adding-children/components/avatar.js",
    "content": "/**\n * Usage:\n * <x-avatar src=\"https://.../avatar.png\"></x-avatar>\n * <x-avatar src=\"https://.../avatar-large.png\" size=\"lg\"></x-avatar>\n */\nclass AvatarComponent extends HTMLElement {\n    connectedCallback() {\n        if (!this.querySelector('img')) {\n            this.append(document.createElement('img'));\n        }\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['src', 'alt'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const img = this.querySelector('img');\n        if (img) {\n            img.src = this.getAttribute('src');\n            img.alt = this.getAttribute('alt') || 'avatar';    \n        }\n    }\n}\n\nexport const registerAvatarComponent = () => {\n    customElements.define('x-avatar', AvatarComponent);\n}\n"
  },
  {
    "path": "public/pages/examples/components/adding-children/components/badge.css",
    "content": "x-badge {\n    position: relative;\n    display: inline-flex;\n    flex-shrink: 0;\n    box-sizing: border-box;\n}\n\nx-badge > span.x-badge-label {\n    /* size and position */\n    box-sizing: inherit;\n    position: absolute;\n    top: 0.2rem;\n    right: 0.2rem;\n    width: 1.25rem;\n    height: 1.25rem;\n    transform: translate(50%, -50%);\n    z-index: 10;\n    /* colors and fonts */\n    color: white;\n    background-color: rgb(0, 111, 238);\n    border-style: solid;\n    border-color: #333333;\n    border-width: 2px;\n    border-radius: 9999px;\n    font-size: 0.875rem;\n    line-height: 1.2;\n    /* text placement */\n    display: flex;\n    place-content: center;\n    user-select: none;\n}\n"
  },
  {
    "path": "public/pages/examples/components/adding-children/components/badge.js",
    "content": "class BadgeComponent extends HTMLElement {\n    #span;\n\n    connectedCallback() {\n        if (!this.#span) {\n            this.#span = document.createElement('span');\n            this.#span.className = 'x-badge-label';                \n        }\n        this.insertBefore(this.#span, this.firstChild);\n        this.update();\n    }\n\n    update() {\n        if (this.#span) this.#span.textContent = this.getAttribute('content');\n    }\n\n    static get observedAttributes() {\n        return ['content'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    set content(value) {\n        if (this.getAttribute('content') !== value) {\n            this.setAttribute('content', value);\n        }\n    }\n\n    get content() {\n        return this.getAttribute('content');\n    }\n}\n\nexport const registerBadgeComponent = () => customElements.define('x-badge', BadgeComponent);\n"
  },
  {
    "path": "public/pages/examples/components/adding-children/index.css",
    "content": "@import \"./components/avatar.css\";\n@import \"./components/badge.css\";\n\np, div { margin: 1em; font-family: sans-serif; }\nx-badge { vertical-align: middle; }\n"
  },
  {
    "path": "public/pages/examples/components/adding-children/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <p>Avatar and badge, when their powers combine...</p>\n    <div>\n        <x-badge content=\"5\" id=\"live-badge\">\n            <x-avatar src=\"https://i.pravatar.cc/150?u=a042581f4e29026704d\"></x-avatar>\n        </x-badge>\n        &larr;\n        <input type=\"number\" value=\"5\" title=\"badge value\"\n               oninput=\"document.getElementById('live-badge').content = this.value\" />    \n    </div>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/components/adding-children/index.js",
    "content": "import { registerAvatarComponent } from './components/avatar.js';\nimport { registerBadgeComponent } from './components/badge.js';\nconst app = () => {\n    registerAvatarComponent();\n    registerBadgeComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/components/advanced/components/avatar.css",
    "content": "x-avatar {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 2.5rem;\n    height: 2.5rem;\n}\n\nx-avatar[size=lg] {\n    width: 3.5rem;\n    height: 3.5rem;\n}\n\nx-avatar img {\n    border-radius: 9999px;\n    width: 100%;\n    height: 100%;\n    vertical-align: middle;\n    object-fit: cover;\n}\n"
  },
  {
    "path": "public/pages/examples/components/advanced/components/avatar.js",
    "content": "/**\n * Usage:\n * <x-avatar src=\"https://.../avatar.png\"></x-avatar>\n * <x-avatar src=\"https://.../avatar-large.png\" size=\"lg\"></x-avatar>\n */\nclass AvatarComponent extends HTMLElement {\n    connectedCallback() {\n        if (!this.querySelector('img')) {\n            this.append(document.createElement('img'));\n        }\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['src', 'alt'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const img = this.querySelector('img');\n        if (img) {\n            img.src = this.getAttribute('src');\n            img.alt = this.getAttribute('alt') || 'avatar';    \n        }\n    }\n}\n\nexport const registerAvatarComponent = () => {\n    customElements.define('x-avatar', AvatarComponent);\n}\n"
  },
  {
    "path": "public/pages/examples/components/advanced/index.css",
    "content": "@import \"./components/avatar.css\";\nbody { font-family: monospace; }\n"
  },
  {
    "path": "public/pages/examples/components/advanced/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <p>A basic avatar component in two sizes:</p>\n    <x-avatar src=\"https://i.pravatar.cc/150?u=a042581f4e29026024d\"></x-avatar>\n    <x-avatar src=\"https://i.pravatar.cc/150?u=a04258114e29026302d\" size=\"lg\"></x-avatar>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/components/advanced/index.js",
    "content": "import { registerAvatarComponent } from './components/avatar.js';\nconst app = () => {\n    registerAvatarComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/components/advanced/simple.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n</head>\n<body>\n    <script type=\"module\" src=\"index.js\"></script>\n    <x-avatar src=\"https://i.pravatar.cc/150?u=a042581f4e29026024d\"></x-avatar>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/components/data/components/app.js",
    "content": "class SantasApp extends HTMLElement {\n    #theList = [/* { name, nice } */];\n\n    connectedCallback() {\n        if (this.querySelector('h1')) return;\n        this.innerHTML = `\n            <h1>Santa's List</h1>\n            <santas-form></santas-form>\n            <santas-list></santas-list>\n            <santas-summary></santas-summary>\n        `;\n        this.querySelector('santas-form')\n            .addEventListener('add', (e) => {\n                this.#theList.push(e.detail.form);\n                this.update();\n            });\n        this.update();\n    }\n\n    update() {\n        this.querySelector('santas-list').list = this.#theList.slice();\n        this.querySelector('santas-summary').update(this.#theList.slice());\n    }\n}\n\nexport const registerApp = \n    () => customElements.define('santas-app', SantasApp);\n"
  },
  {
    "path": "public/pages/examples/components/data/components/form.js",
    "content": "class SantasForm extends HTMLElement {\n    connectedCallback() {\n        if (this.querySelector('form')) return;\n        this.innerHTML = `\n            <form>\n                <label for=\"name\">Name</label>\n                <input type=\"text\" id=\"name\" name=\"name\" required />\n                <input type=\"checkbox\" id=\"nice\" name=\"nice\" value=\"1\" />\n                <label for=\"nice\">Nice?</label>\n                <button type=\"submit\">Add</button>\n            </form>\n        `;\n        this.querySelector('form').onsubmit = (e) => {\n            e.preventDefault();\n            const data = new FormData(e.target);\n            this.dispatchEvent(new CustomEvent('add', {\n                detail: { form: Object.fromEntries(data.entries()) }\n            }));\n            e.target.reset();\n        }\n    }\n}\n\nexport const registerSantasForm = \n    () => customElements.define('santas-form', SantasForm);\n"
  },
  {
    "path": "public/pages/examples/components/data/components/list-safe.js",
    "content": "import { html } from '../lib/html.js';\n\nclass SantasList extends HTMLElement {\n    #currentList = [/* { name, nice } */];\n    set list(newList) {\n        this.#currentList = newList;\n        this.update();\n    }\n    update() {\n        this.innerHTML = \n            '<ul>' +\n            this.#currentList.map(person => \n\n                // the html`` literal automatically encodes entities in the variables\n                html`<li>${person.name} is ${person.nice ? 'nice' : 'naughty'}</li>`\n                \n            ).join('\\n') +\n            '</ul>';\n    }\n}\n\nexport const registerSantasList =\n    () => customElements.define('santas-list', SantasList);\n"
  },
  {
    "path": "public/pages/examples/components/data/components/list.js",
    "content": "class SantasList extends HTMLElement {\n    #currentList = [/* { name, nice } */];\n    set list(newList) {\n        this.#currentList = newList;\n        this.update();\n    }\n    update() {\n        this.innerHTML = \n            '<ul>' +\n            this.#currentList.map(person => \n                `<li>${person.name} is ${person.nice ? 'nice' : 'naughty'}</li>`\n            ).join('\\n') +\n            '</ul>';\n    }\n}\n\nexport const registerSantasList =\n    () => customElements.define('santas-list', SantasList);\n"
  },
  {
    "path": "public/pages/examples/components/data/components/summary.js",
    "content": "class SantasSummary extends HTMLElement {\n    update(list) {\n        const nice = list.filter((item) => item.nice).length;\n        const naughty = list.length - nice;\n        this.innerHTML = list.length ? `\n            <p>${nice} nice, ${naughty} naughty</p>\n        ` : \"<p>Nobody's on the list yet.</p>\";\n    }\n}\n\nexport const registerSantasSummary = \n    () => customElements.define('santas-summary', SantasSummary);\n"
  },
  {
    "path": "public/pages/examples/components/data/index.css",
    "content": "body { \n    font-family: 'Iowan Old Style', 'Palatino Linotype', 'URW Palladio L', P052, serif;\n    margin: 1em;\n}\n\nbutton { font-family: inherit; font-size: 100%; margin-left: 0.5em; }\n\nsantas-form { display: block }\nsantas-form * { vertical-align: middle; }\n\nsantas-app h1 { color: darkred; }\n"
  },
  {
    "path": "public/pages/examples/components/data/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <santas-app></santas-app>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/components/data/index.js",
    "content": "import { registerSantasForm } from './components/form.js';\nimport { registerSantasList } from './components/list.js';\nimport { registerSantasSummary } from './components/summary.js';\nimport { registerApp } from './components/app.js';\n\nconst app = () => {\n    registerSantasForm();\n    registerSantasList();\n    registerSantasSummary();\n    registerApp();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/components/avatar.css",
    "content": "x-avatar {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 2.5rem;\n    height: 2.5rem;\n}\n\nx-avatar[size=lg] {\n    width: 3.5rem;\n    height: 3.5rem;\n}\n\nx-avatar img {\n    border-radius: 9999px;\n    width: 100%;\n    height: 100%;\n    vertical-align: middle;\n    object-fit: cover;\n}\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/components/avatar.js",
    "content": "/**\n * Usage:\n * <x-avatar src=\"https://.../avatar.png\"></x-avatar>\n * <x-avatar src=\"https://.../avatar-large.png\" size=\"lg\"></x-avatar>\n */\nclass AvatarComponent extends HTMLElement {\n    connectedCallback() {\n        if (!this.querySelector('img')) {\n            this.append(document.createElement('img'));\n        }\n        this.update();\n    }\n\n    static get observedAttributes() {\n        return ['src', 'alt'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    update() {\n        const img = this.querySelector('img');\n        if (img) {\n            img.src = this.getAttribute('src');\n            img.alt = this.getAttribute('alt') || 'avatar';    \n        }\n    }\n}\n\nexport const registerAvatarComponent = () => {\n    customElements.define('x-avatar', AvatarComponent);\n}\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/components/badge.css",
    "content": "x-badge {\n    position: relative;\n    display: inline-flex;\n    flex-shrink: 0;\n    box-sizing: border-box;\n}\n\nx-badge > span.x-badge-label {\n    /* size and position */\n    box-sizing: inherit;\n    position: absolute;\n    top: 0.2rem;\n    right: 0.2rem;\n    width: 1.25rem;\n    height: 1.25rem;\n    transform: translate(50%, -50%);\n    z-index: 10;\n    /* colors and fonts */\n    color: white;\n    background-color: rgb(0, 111, 238);\n    border-style: solid;\n    border-color: #333333;\n    border-width: 2px;\n    border-radius: 9999px;\n    font-size: 0.875rem;\n    line-height: 1.2;\n    /* text placement */\n    display: flex;\n    place-content: center;\n    user-select: none;\n}\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/components/badge.js",
    "content": "class BadgeComponent extends HTMLElement {\n    #span;\n\n    connectedCallback() {\n        if (!this.#span) {\n            this.#span = document.createElement('span');\n            this.#span.className = 'x-badge-label';                \n        }\n        this.insertBefore(this.#span, this.firstChild);\n        this.update();\n    }\n\n    update() {\n        if (this.#span) this.#span.textContent = this.getAttribute('content');\n    }\n\n    static get observedAttributes() {\n        return ['content'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n\n    set content(value) {\n        if (this.getAttribute('content') !== value) {\n            this.setAttribute('content', value);\n        }\n    }\n\n    get content() {\n        return this.getAttribute('content');\n    }\n}\n\nexport const registerBadgeComponent = () => customElements.define('x-badge', BadgeComponent);\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/components/header.css",
    "content": "@import \"../reset.css\";\n\n:host {\n    display: block;\n}\n\nheader {\n    display: flex;\n    flex-flow: row wrap;\n    justify-content: right;\n    align-items: center;\n}\n\nh1 {\n    font-family: system-ui, sans-serif;\n    margin: 0;\n    display: flex;\n    flex: 1 1 auto;\n}\n\n::slotted(*) {\n    display: flex;\n    flex: 0 1 auto;\n}\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/components/header.js",
    "content": "const template = document.createElement('template');\ntemplate.innerHTML = `\n    <link rel=\"stylesheet\" href=\"${import.meta.resolve('./header.css')}\">\n    <header>\n        <h1></h1>\n        <slot></slot>\n    </header>\n`;\n\nclass HeaderComponent extends HTMLElement {\n    constructor() {\n        super();\n        if (!this.shadowRoot) {\n            this.attachShadow({ mode: 'open' });\n            this.shadowRoot.append(template.content.cloneNode(true));\n        }\n        this.update();\n    }\n\n    update() {\n        this.shadowRoot.querySelector('h1').textContent = this.getAttribute('title');\n    }\n\n    static get observedAttributes() {\n        return ['title'];\n    }\n\n    attributeChangedCallback() {\n        this.update();\n    }\n}\n\nexport const registerHeaderComponent = () => customElements.define('x-header', HeaderComponent);\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/index.css",
    "content": "@import \"./reset.css\";\n@import \"./components/avatar.css\";\n@import \"./components/badge.css\";\n\nbody { \n    font-family: system-ui, sans-serif;\n}\n\nx-header, main { \n    margin: 1em; \n    padding: 1em;\n    border: 1px dashed black;\n}\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <x-header title=\"Welcome\">\n        <x-badge content=\"2\">\n            <x-avatar src=\"https://i.pravatar.cc/150?u=a042581f4e29026704d\"></x-avatar>\n        </x-badge>\n    </x-header>\n    <main>\n        <p>Hello, shadow DOM!</p>\n    </main>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/index.js",
    "content": "import { registerAvatarComponent } from './components/avatar.js';\nimport { registerBadgeComponent } from './components/badge.js';\nimport { registerHeaderComponent } from './components/header.js';\nconst app = () => {\n    registerAvatarComponent();\n    registerBadgeComponent();\n    registerHeaderComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/components/shadow-dom/reset.css",
    "content": "/* generic minimal CSS reset\n   inspiration: https://www.digitalocean.com/community/tutorials/css-minimal-css-reset */\n\n:root {\n    box-sizing: border-box;\n    line-height: 1.4;\n    /* https://kilianvalkhof.com/2022/css-html/your-css-reset-needs-text-size-adjust-probably/ */\n    -moz-text-size-adjust: none;\n    -webkit-text-size-adjust: none;\n    text-size-adjust: none;\n}\n\n*, *:before, *:after {\n    box-sizing: inherit;\n}\n\nbody, h1, h2, h3, h4, h5, h6, p {\n    margin: 0;\n    padding: 0;\n    font-weight: normal;\n}\n\nimg {\n    max-width:100%;\n    height:auto;\n}\n"
  },
  {
    "path": "public/pages/examples/components/simple/hello-world.js",
    "content": "class HelloWorldComponent extends HTMLElement {\n    connectedCallback() {\n        this.textContent = 'hello world!';\n    }\n}\ncustomElements.define('x-hello-world', HelloWorldComponent);\n"
  },
  {
    "path": "public/pages/examples/components/simple/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<body>\n    <script src=\"hello-world.js\"></script>\n    <p>I just want to say...</p>\n    <x-hello-world></x-hello-world>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/sites/importmap/components/metrics.js",
    "content": "import dayjs from 'dayjs';\nimport * as webVitals from 'web-vitals';\n\nclass MetricsComponent extends HTMLElement {\n    #now = dayjs();\n    #ttfb;\n    #interval;\n\n    connectedCallback() {\n        webVitals.onTTFB(_ => this.#ttfb = Math.round(_.value));\n        this.#interval = setInterval(() => this.update(), 500);\n    }\n\n    disconnectedCallback() {\n        clearInterval(this.#interval);\n        this.#interval = null;\n    }\n\n    update() {\n        this.innerHTML = `\n            <p>Page loaded ${this.#now.fromNow()}, TTFB ${this.#ttfb} milliseconds</p>\n        `;\n    }\n}\n\nexport const registerMetricsComponent = () => {\n    customElements.define('x-metrics', MetricsComponent);\n}"
  },
  {
    "path": "public/pages/examples/sites/importmap/index.css",
    "content": "body { font-family: sans-serif; }\n"
  },
  {
    "path": "public/pages/examples/sites/importmap/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script src=\"./lib/dayjs/dayjs.min.js\" defer></script>\n    <script src=\"./lib/dayjs/relativeTime.js\" defer></script>\n    <script type=\"importmap\">\n        {\n            \"imports\": {\n                \"dayjs\": \"./lib/dayjs/module.js\",\n                \"web-vitals\": \"./lib/web-vitals.js\"\n            }\n        }\n    </script>\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <x-metrics></x-metrics>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/sites/importmap/index.js",
    "content": "import { registerMetricsComponent } from './components/metrics.js';\n\nconst app = () => {\n    registerMetricsComponent();\n};\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/sites/importmap/lib/dayjs/module.js",
    "content": "// UMD version of dayjs, from https://unpkg.com/dayjs/\nconst dayjs = window.dayjs;\nconst dayjsRelativeTime = window.dayjs_plugin_relativeTime;\ndayjs.extend(dayjsRelativeTime);\n\nexport default dayjs;\n"
  },
  {
    "path": "public/pages/examples/sites/importmap/lib/dayjs/relativeTime.js",
    "content": "!function(r,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define(e):(r=\"undefined\"!=typeof globalThis?globalThis:r||self).dayjs_plugin_relativeTime=e()}(this,(function(){\"use strict\";return function(r,e,t){r=r||{};var n=e.prototype,o={future:\"in %s\",past:\"%s ago\",s:\"a few seconds\",m:\"a minute\",mm:\"%d minutes\",h:\"an hour\",hh:\"%d hours\",d:\"a day\",dd:\"%d days\",M:\"a month\",MM:\"%d months\",y:\"a year\",yy:\"%d years\"};function i(r,e,t,o){return n.fromToBase(r,e,t,o)}t.en.relativeTime=o,n.fromToBase=function(e,n,i,d,u){for(var f,a,s,l=i.$locale().relativeTime||o,h=r.thresholds||[{l:\"s\",r:44,d:\"second\"},{l:\"m\",r:89},{l:\"mm\",r:44,d:\"minute\"},{l:\"h\",r:89},{l:\"hh\",r:21,d:\"hour\"},{l:\"d\",r:35},{l:\"dd\",r:25,d:\"day\"},{l:\"M\",r:45},{l:\"MM\",r:10,d:\"month\"},{l:\"y\",r:17},{l:\"yy\",d:\"year\"}],m=h.length,c=0;c<m;c+=1){var y=h[c];y.d&&(f=d?t(e).diff(i,y.d,!0):i.diff(e,y.d,!0));var p=(r.rounding||Math.round)(Math.abs(f));if(s=f>0,p<=y.r||!y.r){p<=1&&c>0&&(y=h[c-1]);var v=l[y.l];u&&(p=u(\"\"+p)),a=\"string\"==typeof v?v.replace(\"%d\",p):v(p,n,y.l,s);break}}if(n)return a;var M=s?l.future:l.past;return\"function\"==typeof M?M(a):M.replace(\"%s\",a)},n.to=function(r,e){return i(r,e,this,!0)},n.from=function(r,e){return i(r,e,this)};var d=function(r){return r.$u?t.utc():t()};n.toNow=function(r){return this.to(d(this),r)},n.fromNow=function(r){return this.from(d(this),r)}}}));"
  },
  {
    "path": "public/pages/examples/sites/importmap/lib/web-vitals.js",
    "content": "var e,n,t,r,i,o=-1,a=function(e){addEventListener(\"pageshow\",(function(n){n.persisted&&(o=n.timeStamp,e(n))}),!0)},c=function(){var e=self.performance&&performance.getEntriesByType&&performance.getEntriesByType(\"navigation\")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},u=function(){var e=c();return e&&e.activationStart||0},f=function(e,n){var t=c(),r=\"navigate\";o>=0?r=\"back-forward-cache\":t&&(document.prerendering||u()>0?r=\"prerender\":document.wasDiscarded?r=\"restore\":t.type&&(r=t.type.replace(/_/g,\"-\")));return{name:e,value:void 0===n?-1:n,rating:\"good\",delta:0,entries:[],id:\"v4-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:r}},s=function(e,n,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){var r=new PerformanceObserver((function(e){Promise.resolve().then((function(){n(e.getEntries())}))}));return r.observe(Object.assign({type:e,buffered:!0},t||{})),r}}catch(e){}},d=function(e,n,t,r){var i,o;return function(a){n.value>=0&&(a||r)&&((o=n.value-(i||0))||void 0===i)&&(i=n.value,n.delta=o,n.rating=function(e,n){return e>n[1]?\"poor\":e>n[0]?\"needs-improvement\":\"good\"}(n.value,t),e(n))}},l=function(e){requestAnimationFrame((function(){return requestAnimationFrame((function(){return e()}))}))},p=function(e){document.addEventListener(\"visibilitychange\",(function(){\"hidden\"===document.visibilityState&&e()}))},v=function(e){var n=!1;return function(){n||(e(),n=!0)}},m=-1,h=function(){return\"hidden\"!==document.visibilityState||document.prerendering?1/0:0},g=function(e){\"hidden\"===document.visibilityState&&m>-1&&(m=\"visibilitychange\"===e.type?e.timeStamp:0,T())},y=function(){addEventListener(\"visibilitychange\",g,!0),addEventListener(\"prerenderingchange\",g,!0)},T=function(){removeEventListener(\"visibilitychange\",g,!0),removeEventListener(\"prerenderingchange\",g,!0)},E=function(){return m<0&&(m=h(),y(),a((function(){setTimeout((function(){m=h(),y()}),0)}))),{get firstHiddenTime(){return m}}},C=function(e){document.prerendering?addEventListener(\"prerenderingchange\",(function(){return e()}),!0):e()},b=[1800,3e3],S=function(e,n){n=n||{},C((function(){var t,r=E(),i=f(\"FCP\"),o=s(\"paint\",(function(e){e.forEach((function(e){\"first-contentful-paint\"===e.name&&(o.disconnect(),e.startTime<r.firstHiddenTime&&(i.value=Math.max(e.startTime-u(),0),i.entries.push(e),t(!0)))}))}));o&&(t=d(e,i,b,n.reportAllChanges),a((function(r){i=f(\"FCP\"),t=d(e,i,b,n.reportAllChanges),l((function(){i.value=performance.now()-r.timeStamp,t(!0)}))})))}))},L=[.1,.25],w=function(e,n){n=n||{},S(v((function(){var t,r=f(\"CLS\",0),i=0,o=[],c=function(e){e.forEach((function(e){if(!e.hadRecentInput){var n=o[0],t=o[o.length-1];i&&e.startTime-t.startTime<1e3&&e.startTime-n.startTime<5e3?(i+=e.value,o.push(e)):(i=e.value,o=[e])}})),i>r.value&&(r.value=i,r.entries=o,t())},u=s(\"layout-shift\",c);u&&(t=d(e,r,L,n.reportAllChanges),p((function(){c(u.takeRecords()),t(!0)})),a((function(){i=0,r=f(\"CLS\",0),t=d(e,r,L,n.reportAllChanges),l((function(){return t()}))})),setTimeout(t,0))})))},A=0,I=1/0,P=0,M=function(e){e.forEach((function(e){e.interactionId&&(I=Math.min(I,e.interactionId),P=Math.max(P,e.interactionId),A=P?(P-I)/7+1:0)}))},k=function(){return e?A:performance.interactionCount||0},F=function(){\"interactionCount\"in performance||e||(e=s(\"event\",M,{type:\"event\",buffered:!0,durationThreshold:0}))},D=[],x=new Map,R=0,B=function(){var e=Math.min(D.length-1,Math.floor((k()-R)/50));return D[e]},H=[],q=function(e){if(H.forEach((function(n){return n(e)})),e.interactionId||\"first-input\"===e.entryType){var n=D[D.length-1],t=x.get(e.interactionId);if(t||D.length<10||e.duration>n.latency){if(t)e.duration>t.latency?(t.entries=[e],t.latency=e.duration):e.duration===t.latency&&e.startTime===t.entries[0].startTime&&t.entries.push(e);else{var r={id:e.interactionId,latency:e.duration,entries:[e]};x.set(r.id,r),D.push(r)}D.sort((function(e,n){return n.latency-e.latency})),D.length>10&&D.splice(10).forEach((function(e){return x.delete(e.id)}))}}},O=function(e){var n=self.requestIdleCallback||self.setTimeout,t=-1;return e=v(e),\"hidden\"===document.visibilityState?e():(t=n(e),p(e)),t},N=[200,500],j=function(e,n){\"PerformanceEventTiming\"in self&&\"interactionId\"in PerformanceEventTiming.prototype&&(n=n||{},C((function(){var t;F();var r,i=f(\"INP\"),o=function(e){O((function(){e.forEach(q);var n=B();n&&n.latency!==i.value&&(i.value=n.latency,i.entries=n.entries,r())}))},c=s(\"event\",o,{durationThreshold:null!==(t=n.durationThreshold)&&void 0!==t?t:40});r=d(e,i,N,n.reportAllChanges),c&&(c.observe({type:\"first-input\",buffered:!0}),p((function(){o(c.takeRecords()),r(!0)})),a((function(){R=k(),D.length=0,x.clear(),i=f(\"INP\"),r=d(e,i,N,n.reportAllChanges)})))})))},_=[2500,4e3],z={},G=function(e,n){n=n||{},C((function(){var t,r=E(),i=f(\"LCP\"),o=function(e){n.reportAllChanges||(e=e.slice(-1)),e.forEach((function(e){e.startTime<r.firstHiddenTime&&(i.value=Math.max(e.startTime-u(),0),i.entries=[e],t())}))},c=s(\"largest-contentful-paint\",o);if(c){t=d(e,i,_,n.reportAllChanges);var m=v((function(){z[i.id]||(o(c.takeRecords()),c.disconnect(),z[i.id]=!0,t(!0))}));[\"keydown\",\"click\"].forEach((function(e){addEventListener(e,(function(){return O(m)}),!0)})),p(m),a((function(r){i=f(\"LCP\"),t=d(e,i,_,n.reportAllChanges),l((function(){i.value=performance.now()-r.timeStamp,z[i.id]=!0,t(!0)}))}))}}))},J=[800,1800],K=function e(n){document.prerendering?C((function(){return e(n)})):\"complete\"!==document.readyState?addEventListener(\"load\",(function(){return e(n)}),!0):setTimeout(n,0)},Q=function(e,n){n=n||{};var t=f(\"TTFB\"),r=d(e,t,J,n.reportAllChanges);K((function(){var i=c();i&&(t.value=Math.max(i.responseStart-u(),0),t.entries=[i],r(!0),a((function(){t=f(\"TTFB\",0),(r=d(e,t,J,n.reportAllChanges))(!0)})))}))},U={passive:!0,capture:!0},V=new Date,W=function(e,i){n||(n=i,t=e,r=new Date,Z(removeEventListener),X())},X=function(){if(t>=0&&t<r-V){var e={entryType:\"first-input\",name:n.type,target:n.target,cancelable:n.cancelable,startTime:n.timeStamp,processingStart:n.timeStamp+t};i.forEach((function(n){n(e)})),i=[]}},Y=function(e){if(e.cancelable){var n=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,n){var t=function(){W(e,n),i()},r=function(){i()},i=function(){removeEventListener(\"pointerup\",t,U),removeEventListener(\"pointercancel\",r,U)};addEventListener(\"pointerup\",t,U),addEventListener(\"pointercancel\",r,U)}(n,e):W(n,e)}},Z=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(n){return e(n,Y,U)}))},$=[100,300],ee=function(e,r){r=r||{},C((function(){var o,c=E(),u=f(\"FID\"),l=function(e){e.startTime<c.firstHiddenTime&&(u.value=e.processingStart-e.startTime,u.entries.push(e),o(!0))},m=function(e){e.forEach(l)},h=s(\"first-input\",m);o=d(e,u,$,r.reportAllChanges),h&&(p(v((function(){m(h.takeRecords()),h.disconnect()}))),a((function(){var a;u=f(\"FID\"),o=d(e,u,$,r.reportAllChanges),i=[],t=-1,n=null,Z(addEventListener),a=l,i.push(a),X()})))}))};export{L as CLSThresholds,b as FCPThresholds,$ as FIDThresholds,N as INPThresholds,_ as LCPThresholds,J as TTFBThresholds,w as onCLS,S as onFCP,ee as onFID,j as onINP,G as onLCP,Q as onTTFB};\n"
  },
  {
    "path": "public/pages/examples/sites/imports/components/metrics.js",
    "content": "import { dayjs, webVitals } from '../lib/imports.js';\n\nclass MetricsComponent extends HTMLElement {\n    #now = dayjs();\n    #ttfb;\n    #interval;\n\n    connectedCallback() {\n        webVitals.onTTFB(_ => this.#ttfb = Math.round(_.value));\n        this.#interval = setInterval(() => this.update(), 500);\n    }\n\n    disconnectedCallback() {\n        clearInterval(this.#interval);\n        this.#interval = null;\n    }\n\n    update() {\n        this.innerHTML = `\n            <p>Page loaded ${this.#now.fromNow()}, TTFB ${this.#ttfb} milliseconds</p>\n        `;\n    }\n}\n\nexport const registerMetricsComponent = () => {\n    customElements.define('x-metrics', MetricsComponent);\n}"
  },
  {
    "path": "public/pages/examples/sites/imports/index.css",
    "content": "body { font-family: sans-serif; }\n"
  },
  {
    "path": "public/pages/examples/sites/imports/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script src=\"./lib/dayjs/dayjs.min.js\" defer></script>\n    <script src=\"./lib/dayjs/relativeTime.js\" defer></script>\n    \n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <x-metrics></x-metrics>\n</body>\n</html>"
  },
  {
    "path": "public/pages/examples/sites/imports/index.js",
    "content": "import { registerMetricsComponent } from './components/metrics.js';\n\nconst app = () => {\n    registerMetricsComponent();\n};\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/sites/imports/lib/dayjs/relativeTime.js",
    "content": "!function(r,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define(e):(r=\"undefined\"!=typeof globalThis?globalThis:r||self).dayjs_plugin_relativeTime=e()}(this,(function(){\"use strict\";return function(r,e,t){r=r||{};var n=e.prototype,o={future:\"in %s\",past:\"%s ago\",s:\"a few seconds\",m:\"a minute\",mm:\"%d minutes\",h:\"an hour\",hh:\"%d hours\",d:\"a day\",dd:\"%d days\",M:\"a month\",MM:\"%d months\",y:\"a year\",yy:\"%d years\"};function i(r,e,t,o){return n.fromToBase(r,e,t,o)}t.en.relativeTime=o,n.fromToBase=function(e,n,i,d,u){for(var f,a,s,l=i.$locale().relativeTime||o,h=r.thresholds||[{l:\"s\",r:44,d:\"second\"},{l:\"m\",r:89},{l:\"mm\",r:44,d:\"minute\"},{l:\"h\",r:89},{l:\"hh\",r:21,d:\"hour\"},{l:\"d\",r:35},{l:\"dd\",r:25,d:\"day\"},{l:\"M\",r:45},{l:\"MM\",r:10,d:\"month\"},{l:\"y\",r:17},{l:\"yy\",d:\"year\"}],m=h.length,c=0;c<m;c+=1){var y=h[c];y.d&&(f=d?t(e).diff(i,y.d,!0):i.diff(e,y.d,!0));var p=(r.rounding||Math.round)(Math.abs(f));if(s=f>0,p<=y.r||!y.r){p<=1&&c>0&&(y=h[c-1]);var v=l[y.l];u&&(p=u(\"\"+p)),a=\"string\"==typeof v?v.replace(\"%d\",p):v(p,n,y.l,s);break}}if(n)return a;var M=s?l.future:l.past;return\"function\"==typeof M?M(a):M.replace(\"%s\",a)},n.to=function(r,e){return i(r,e,this,!0)},n.from=function(r,e){return i(r,e,this)};var d=function(r){return r.$u?t.utc():t()};n.toNow=function(r){return this.to(d(this),r)},n.fromNow=function(r){return this.from(d(this),r)}}}));"
  },
  {
    "path": "public/pages/examples/sites/imports/lib/imports.js",
    "content": "// UMD version of dayjs, from https://unpkg.com/dayjs/\nconst dayjs = window.dayjs;\nconst dayjsRelativeTime = window.dayjs_plugin_relativeTime;\ndayjs.extend(dayjsRelativeTime);\n\n// ESM version of web-vitals, from https://unpkg.com/web-vitals/dist/web-vitals.js\nimport * as webVitals from './web-vitals.js';\n\nexport { dayjs, webVitals };\n"
  },
  {
    "path": "public/pages/examples/sites/imports/lib/web-vitals.js",
    "content": "var e,n,t,r,i,o=-1,a=function(e){addEventListener(\"pageshow\",(function(n){n.persisted&&(o=n.timeStamp,e(n))}),!0)},c=function(){var e=self.performance&&performance.getEntriesByType&&performance.getEntriesByType(\"navigation\")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},u=function(){var e=c();return e&&e.activationStart||0},f=function(e,n){var t=c(),r=\"navigate\";o>=0?r=\"back-forward-cache\":t&&(document.prerendering||u()>0?r=\"prerender\":document.wasDiscarded?r=\"restore\":t.type&&(r=t.type.replace(/_/g,\"-\")));return{name:e,value:void 0===n?-1:n,rating:\"good\",delta:0,entries:[],id:\"v4-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:r}},s=function(e,n,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){var r=new PerformanceObserver((function(e){Promise.resolve().then((function(){n(e.getEntries())}))}));return r.observe(Object.assign({type:e,buffered:!0},t||{})),r}}catch(e){}},d=function(e,n,t,r){var i,o;return function(a){n.value>=0&&(a||r)&&((o=n.value-(i||0))||void 0===i)&&(i=n.value,n.delta=o,n.rating=function(e,n){return e>n[1]?\"poor\":e>n[0]?\"needs-improvement\":\"good\"}(n.value,t),e(n))}},l=function(e){requestAnimationFrame((function(){return requestAnimationFrame((function(){return e()}))}))},p=function(e){document.addEventListener(\"visibilitychange\",(function(){\"hidden\"===document.visibilityState&&e()}))},v=function(e){var n=!1;return function(){n||(e(),n=!0)}},m=-1,h=function(){return\"hidden\"!==document.visibilityState||document.prerendering?1/0:0},g=function(e){\"hidden\"===document.visibilityState&&m>-1&&(m=\"visibilitychange\"===e.type?e.timeStamp:0,T())},y=function(){addEventListener(\"visibilitychange\",g,!0),addEventListener(\"prerenderingchange\",g,!0)},T=function(){removeEventListener(\"visibilitychange\",g,!0),removeEventListener(\"prerenderingchange\",g,!0)},E=function(){return m<0&&(m=h(),y(),a((function(){setTimeout((function(){m=h(),y()}),0)}))),{get firstHiddenTime(){return m}}},C=function(e){document.prerendering?addEventListener(\"prerenderingchange\",(function(){return e()}),!0):e()},b=[1800,3e3],S=function(e,n){n=n||{},C((function(){var t,r=E(),i=f(\"FCP\"),o=s(\"paint\",(function(e){e.forEach((function(e){\"first-contentful-paint\"===e.name&&(o.disconnect(),e.startTime<r.firstHiddenTime&&(i.value=Math.max(e.startTime-u(),0),i.entries.push(e),t(!0)))}))}));o&&(t=d(e,i,b,n.reportAllChanges),a((function(r){i=f(\"FCP\"),t=d(e,i,b,n.reportAllChanges),l((function(){i.value=performance.now()-r.timeStamp,t(!0)}))})))}))},L=[.1,.25],w=function(e,n){n=n||{},S(v((function(){var t,r=f(\"CLS\",0),i=0,o=[],c=function(e){e.forEach((function(e){if(!e.hadRecentInput){var n=o[0],t=o[o.length-1];i&&e.startTime-t.startTime<1e3&&e.startTime-n.startTime<5e3?(i+=e.value,o.push(e)):(i=e.value,o=[e])}})),i>r.value&&(r.value=i,r.entries=o,t())},u=s(\"layout-shift\",c);u&&(t=d(e,r,L,n.reportAllChanges),p((function(){c(u.takeRecords()),t(!0)})),a((function(){i=0,r=f(\"CLS\",0),t=d(e,r,L,n.reportAllChanges),l((function(){return t()}))})),setTimeout(t,0))})))},A=0,I=1/0,P=0,M=function(e){e.forEach((function(e){e.interactionId&&(I=Math.min(I,e.interactionId),P=Math.max(P,e.interactionId),A=P?(P-I)/7+1:0)}))},k=function(){return e?A:performance.interactionCount||0},F=function(){\"interactionCount\"in performance||e||(e=s(\"event\",M,{type:\"event\",buffered:!0,durationThreshold:0}))},D=[],x=new Map,R=0,B=function(){var e=Math.min(D.length-1,Math.floor((k()-R)/50));return D[e]},H=[],q=function(e){if(H.forEach((function(n){return n(e)})),e.interactionId||\"first-input\"===e.entryType){var n=D[D.length-1],t=x.get(e.interactionId);if(t||D.length<10||e.duration>n.latency){if(t)e.duration>t.latency?(t.entries=[e],t.latency=e.duration):e.duration===t.latency&&e.startTime===t.entries[0].startTime&&t.entries.push(e);else{var r={id:e.interactionId,latency:e.duration,entries:[e]};x.set(r.id,r),D.push(r)}D.sort((function(e,n){return n.latency-e.latency})),D.length>10&&D.splice(10).forEach((function(e){return x.delete(e.id)}))}}},O=function(e){var n=self.requestIdleCallback||self.setTimeout,t=-1;return e=v(e),\"hidden\"===document.visibilityState?e():(t=n(e),p(e)),t},N=[200,500],j=function(e,n){\"PerformanceEventTiming\"in self&&\"interactionId\"in PerformanceEventTiming.prototype&&(n=n||{},C((function(){var t;F();var r,i=f(\"INP\"),o=function(e){O((function(){e.forEach(q);var n=B();n&&n.latency!==i.value&&(i.value=n.latency,i.entries=n.entries,r())}))},c=s(\"event\",o,{durationThreshold:null!==(t=n.durationThreshold)&&void 0!==t?t:40});r=d(e,i,N,n.reportAllChanges),c&&(c.observe({type:\"first-input\",buffered:!0}),p((function(){o(c.takeRecords()),r(!0)})),a((function(){R=k(),D.length=0,x.clear(),i=f(\"INP\"),r=d(e,i,N,n.reportAllChanges)})))})))},_=[2500,4e3],z={},G=function(e,n){n=n||{},C((function(){var t,r=E(),i=f(\"LCP\"),o=function(e){n.reportAllChanges||(e=e.slice(-1)),e.forEach((function(e){e.startTime<r.firstHiddenTime&&(i.value=Math.max(e.startTime-u(),0),i.entries=[e],t())}))},c=s(\"largest-contentful-paint\",o);if(c){t=d(e,i,_,n.reportAllChanges);var m=v((function(){z[i.id]||(o(c.takeRecords()),c.disconnect(),z[i.id]=!0,t(!0))}));[\"keydown\",\"click\"].forEach((function(e){addEventListener(e,(function(){return O(m)}),!0)})),p(m),a((function(r){i=f(\"LCP\"),t=d(e,i,_,n.reportAllChanges),l((function(){i.value=performance.now()-r.timeStamp,z[i.id]=!0,t(!0)}))}))}}))},J=[800,1800],K=function e(n){document.prerendering?C((function(){return e(n)})):\"complete\"!==document.readyState?addEventListener(\"load\",(function(){return e(n)}),!0):setTimeout(n,0)},Q=function(e,n){n=n||{};var t=f(\"TTFB\"),r=d(e,t,J,n.reportAllChanges);K((function(){var i=c();i&&(t.value=Math.max(i.responseStart-u(),0),t.entries=[i],r(!0),a((function(){t=f(\"TTFB\",0),(r=d(e,t,J,n.reportAllChanges))(!0)})))}))},U={passive:!0,capture:!0},V=new Date,W=function(e,i){n||(n=i,t=e,r=new Date,Z(removeEventListener),X())},X=function(){if(t>=0&&t<r-V){var e={entryType:\"first-input\",name:n.type,target:n.target,cancelable:n.cancelable,startTime:n.timeStamp,processingStart:n.timeStamp+t};i.forEach((function(n){n(e)})),i=[]}},Y=function(e){if(e.cancelable){var n=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,n){var t=function(){W(e,n),i()},r=function(){i()},i=function(){removeEventListener(\"pointerup\",t,U),removeEventListener(\"pointercancel\",r,U)};addEventListener(\"pointerup\",t,U),addEventListener(\"pointercancel\",r,U)}(n,e):W(n,e)}},Z=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(n){return e(n,Y,U)}))},$=[100,300],ee=function(e,r){r=r||{},C((function(){var o,c=E(),u=f(\"FID\"),l=function(e){e.startTime<c.firstHiddenTime&&(u.value=e.processingStart-e.startTime,u.entries.push(e),o(!0))},m=function(e){e.forEach(l)},h=s(\"first-input\",m);o=d(e,u,$,r.reportAllChanges),h&&(p(v((function(){m(h.takeRecords()),h.disconnect()}))),a((function(){var a;u=f(\"FID\"),o=d(e,u,$,r.reportAllChanges),i=[],t=-1,n=null,Z(addEventListener),a=l,i.push(a),X()})))}))};export{L as CLSThresholds,b as FCPThresholds,$ as FIDThresholds,N as INPThresholds,_ as LCPThresholds,J as TTFBThresholds,w as onCLS,S as onFCP,ee as onFID,j as onINP,G as onLCP,Q as onTTFB};\n"
  },
  {
    "path": "public/pages/examples/sites/page/example.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <title>Example</title>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\" />\n        <link rel=\"stylesheet\" href=\"index.css\">\n        <script type=\"module\" src=\"index.js\" defer></script>\n    </head>\n    <body>\n        <noscript><strong>Please enable JavaScript to view this page correctly.</strong></noscript>\n        <header>\n            title and navigation ...\n        </header>\n        <main>\n            main content ...\n        </main>\n        <footer>\n            byline and copyright ...\n        </footer>    \n    </body>\n</html>"
  },
  {
    "path": "public/pages/examples/sites/page/example2.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n    <head>\n        <title>Example</title>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-width\" />\n        <link rel=\"stylesheet\" href=\"index.css\">\n        <script type=\"module\" src=\"index.js\" defer></script>\n    </head>\n    <body>\n        <noscript><strong>Please enable JavaScript to view this page.</strong></noscript>\n        <template id=\"page\">\n            <header>\n                title and navigation ...\n            </header>\n            <main>\n                main content ...\n            </main>\n            <footer>\n                byline and copyright ...\n            </footer>    \n        </template>\n    </body>\n</html>"
  },
  {
    "path": "public/pages/examples/sites/page/index.js",
    "content": "const app = () => {\n    const template = document.querySelector('template#page');\n    if (template) document.body.appendChild(template.content, true);\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/styling/replacing-css-modules/nextjs/layout.tsx",
    "content": "import styles from './styles.module.css'\n \nexport default function DashboardLayout({\n  children,\n}: {\n  children: React.ReactNode\n}) {\n  return <section className={styles.dashboard}>{children}</section>\n}"
  },
  {
    "path": "public/pages/examples/styling/replacing-css-modules/nextjs/styles.module.css",
    "content": ".dashboard {\n    padding: 24px;\n}"
  },
  {
    "path": "public/pages/examples/styling/replacing-css-modules/vanilla/layout.js",
    "content": "class Layout extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({ mode: 'open' });\n        this.shadowRoot.innerHTML = `\n            <link rel=\"stylesheet\" href=\"${import.meta.resolve('styles.css')}\">\n            <section class=\"dashboard\"><slot></slot></section>\n        `;\n    }\n}\n\nexport const registerLayoutComponent = \n    () => customElements.define('x-layout', Layout);\n"
  },
  {
    "path": "public/pages/examples/styling/replacing-css-modules/vanilla/styles.css",
    "content": "@import \"../shared.css\";\n\n.dashboard {\n    padding: 24px;\n}"
  },
  {
    "path": "public/pages/examples/styling/scoping-prefixed/components/example/example.css",
    "content": "x-example p {\n    font-family: casual, cursive;\n    color: darkblue;\n}"
  },
  {
    "path": "public/pages/examples/styling/scoping-prefixed/components/example/example.js",
    "content": "class ExampleComponent extends HTMLElement {\n    connectedCallback() {\n        this.innerHTML = '<p>For example...</p>';\n    }\n}\nexport const registerExampleComponent = () => {\n    customElements.define('x-example', ExampleComponent);\n}\n"
  },
  {
    "path": "public/pages/examples/styling/scoping-prefixed/components/example/example_nested.css",
    "content": "x-example {\n    p {\n        font-family: casual, cursive;\n        color: darkblue;\n    }\n}"
  },
  {
    "path": "public/pages/examples/styling/scoping-prefixed/index.css",
    "content": "@import \"./components/example/example.css\";\n"
  },
  {
    "path": "public/pages/examples/styling/scoping-prefixed/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <link rel=\"stylesheet\" href=\"index.css\">\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>\n<body>\n    <x-example></x-example>\n    <p>This &lt;p&gt; is not affected, because it is outside the custom element.</p>\n</html>\n"
  },
  {
    "path": "public/pages/examples/styling/scoping-prefixed/index.js",
    "content": "import { registerExampleComponent } from './components/example/example.js';\nconst app = () => {\n    registerExampleComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/examples/styling/scoping-shadowed/components/example/example.css",
    "content": "p {\n    font-family: casual, cursive;\n    color: darkblue;\n}"
  },
  {
    "path": "public/pages/examples/styling/scoping-shadowed/components/example/example.js",
    "content": "class ExampleComponent extends HTMLElement {\n    constructor() {\n        super();\n        this.attachShadow({mode: 'open'});\n        this.shadowRoot.innerHTML = `\n            <link rel=\"stylesheet\" href=\"${import.meta.resolve('./example.css')}\">\n            <p>For example...</p>\n            <slot></slot>\n        `;\n    }\n}\nexport const registerExampleComponent = () => {\n    customElements.define('x-example', ExampleComponent);\n}\n"
  },
  {
    "path": "public/pages/examples/styling/scoping-shadowed/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <script type=\"module\" src=\"index.js\" defer></script>\n</head>    \n<body>\n    <x-example>\n        <p>This &lt;p&gt; is not affected, even though it is slotted.</p>\n    </x-example>\n</body>\n</html>\n"
  },
  {
    "path": "public/pages/examples/styling/scoping-shadowed/index.js",
    "content": "import { registerExampleComponent } from './components/example/example.js';\nconst app = () => {\n    registerExampleComponent();\n}\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/pages/sites.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla - Sites</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <meta name=\"description\" content=\"An explainer for making web sites using only vanilla techniques.\">\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"../apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"../index.css\">\n    <script type=\"module\" src=\"../index.js\" defer></script>\n</head>\n<body>\n    <noscript><strong>Please enable JavaScript to view this page correctly.</strong></noscript>\n    <header>\n        <h1>Sites</h1>\n        <nav id=\"menu-nav\" popover aria-label=\"main\">\n            <ol>\n                <li><a href=\"../index.html\">Welcome</a></li>\n                <li><a href=\"components.html\">Components</a></li>\n                <li><a href=\"styling.html\">Styling</a></li>\n                <li><a href=\"#\" aria-current=\"page\">Sites</a></li>\n                <li><a href=\"applications.html\">Applications</a></li>\n                <li class=\"nav-right\"><a href=\"../blog/\">Blog</a></li>\n            </ol>\n        </nav>\n        <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n            &mldr;\n        </button>\n    </header>\n    <main>\n        <section id=\"pages\">\n            <a href=\"#pages\" class=\"section-anchor\">#</a>\n            <h2>Pages</h2>\n            <p>For content-driven websites with low interactivity a multi-page approach is best suited.</p>\n            <p>Abandoning the use of frameworks means writing out those HTML pages from scratch. For this it is important to understand what a good minimal HTML page should look like.</p>\n            <x-code-viewer src=\"./examples/sites/page/example.html\"></x-code-viewer>\n            <p>An explanation of each element:</p>\n            <dl>\n                <dt><code>&lt;!doctype html&gt;</code></dt>\n                <dd>The doctype is required to have the HTML parsed as HTML5 instead of an older version.</dd>\n                <dt><code>&lt;html lang=\"en\"&gt;</code></dt>\n                <dd>The lang attribute is recommended to make sure browsers don't misdetect the language used in the page.</dd>\n                <dt><code>&lt;head&gt;&lt;title&gt;</code></dt>\n                <dd>The title will be used for the browser tab and when bookmarking, making it effectively non-optional.</dd>\n                <dt><code>&lt;head&gt;&lt;meta charset=\"utf-8\"&gt;</code></dt>\n                <dd>\n                    This is borderline unnecessary, but just to make sure a page is properly interpreted as UTF-8 this line should be included.\n                    Obviously the editor used to make the page should equally be set to UTF-8.\n                </dd>\n                <dt><code>&lt;head&gt;&lt;meta name=\"viewport\"&gt;</code></dt>\n                <dd>The viewport meta is necessary to have mobile-friendly layout.</dd>\n                <dt><code>&lt;head&gt;&lt;link rel=\"stylesheet\" href=\"index.css\"&gt;</code></dt>\n                <dd>By convention the stylesheet is loaded from <code>&lt;head&gt;</code> in a blocking way to ensure the page's markup does not have a flash of unstyled content.</dd>\n                <dt><code>&lt;head&gt;&lt;script type=\"module\" src=\"index.js\" defer&gt;</code></dt>\n                <dd>The main JavaScript file is in the <code>&lt;head&gt;</code>, and will bootstrap the web components as explained on the components page. The use of <code>defer</code> allows it to download while the rest of the page is loading and get executed at the end.</dd>\n                <dt><code>&lt;body&gt;&lt;noscript&gt;</code></dt>\n                <dd>Because web components don't work without JavaScript it is good practice to include a noscript warning to users that have JavaScript disabled. This warning only needs to be on pages with web components. If you don't want to show anything except the warning, see the template pattern below.</dd>\n                <dt><code>&lt;body&gt;&lt;header/main/footer&gt;</code></dt>\n                <dd>The page's markup should be organized using <a href=\"https://developer.mozilla.org/en-US/blog/aria-accessibility-html-landmark-roles/\">HTML landmarks</a>. Landmarks when used properly help organize the page into logical blocks and make the page's structure accessible. Because they are standards-based, compatibility with present and future accessibility products is more likely.</dd>\n            </dl>\n            <p>\n                Pages that should only show their contents if JavaScript is enabled can use this template pattern:\n            </p>\n\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/sites/page/example2.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/sites/page/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n            \n            <h3>Semantics matter</h3>\n\n            <p>\n                The markup in the page should default to using semantic HTML, to improve accessibility and SEO.\n                Web components should only be used in those cases where the level of complexity and interaction exceeds the capabilities of plain HTML markup.\n            </p>\n            <p>\n                Familiarize yourself with these aspects of semantic HTML:\n            </p>\n            <dl>\n                <dt><a href=\"https://developer.mozilla.org/en-US/blog/aria-accessibility-html-landmark-roles/\">Landmarks</a></dt>\n                <dd>\n                    As mentioned above, landmarks are the backbone of a page's structure and deliver good structure and accessibility by default.\n                </dd>\n                <dt><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element\">Elements</a></dt>\n                <dd>\n                    Being familiar with HTML's set of built-in elements saves time, \n                    both in avoiding the need for custom elements and in easing implementation of the custom elements that are needed.\n                    When properly used HTML elements are accessible by default.\n                    Pay special attention to the newly baseline features that enable complex UI patterns with minimal JavaScript, \n                    like how <a href=\"https://web.dev/learn/css/popover-and-dialog\">popover</a>\n                    and <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog\">dialog</a> can be used to implement HTML-native tooltips, dialogs and menus,\n                    and how the <a href=\"https://developer.mozilla.org/en-US/blog/html-details-exclusive-accordions/\">details</a> element can be used to implement accordions.\n                </dd>\n                <dt><a href=\"https://developer.mozilla.org/en-US/docs/Learn/Forms\">Forms</a></dt>\n                <dd>\n                    HTML's built-in forms can implement many interactivity use cases when used to their full extent.\n                    Be aware of capabilities like \n                    <a href=\"https://developer.mozilla.org/en-US/docs/Learn/Forms/HTML5_input_types\">rich input types</a>, \n                    <a href=\"https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation\">client-side validation</a> and \n                    <a href=\"https://developer.mozilla.org/en-US/docs/Learn/Forms/UI_pseudo-classes\">UI pseudo classes</a>.\n                    When a suitable form input type for a use case cannot be found, consider using <a href=\"https://web.dev/articles/more-capable-form-controls\">form-associated custom elements</a>.\n                    To dive into this topic read the article on <a href=\"../blog/articles/2025-05-09-form-control/\">making a new form control</a>.\n                </dd>\n            </dl>\n\n            <h3>Favicons</h3>\n\n            <p>\n                There is one thing that you will probably want to add to the HTML that is not standards-based and that is a reference to a favicon:\n            </p>\n            <ul>\n                <li>To keep it really simple, put a <code>favicon.ico</code> in the root path of the site and link to it from your HTML: <code>&lt;link rel=\"icon\" href=\"favicon.ico\"&gt;</code></li>\n                <li>Consider <a href=\"https://medium.com/swlh/are-you-using-svg-favicons-yet-a-guide-for-modern-browsers-836a6aace3df\">SVG favicons</a>, but know that Safari does not support them. <a href=\"https://css-tricks.com/svg-favicons-in-action/\">Embed dark mode</a> in the favicon SVG itself or use a generator like <a href=\"https://realfavicongenerator.net/\">RealFaviconGenerator</a> for more convience.</li>\n                <li>Be aware that because favicons are not based on published web standards it is cumbersome to implement the <a href=\"https://dev.to/masakudamatsu/favicon-nightmare-how-to-maintain-sanity-3al7\">de facto standard</a> fully.</li>\n            </ul>\n\n        </section>\n        <section id=\"project\">\n            <a href=\"#project\" class=\"section-anchor\">#</a>\n            <h2>Project</h2>\n            <p>\n                A suggested project layout for a vanilla multi-page website:\n            </p>\n            <dl>\n                <dt>/</dt>\n                <dd>The project root contains the files that will not be published, such as <code>README.md</code>, <code>LICENSE</code> or <code>.gitignore</code>.</dd>\n                <dt>/public</dt>\n                <dd>The public folder is published as-is, without build steps. It is the whole website.</dd>\n                <dt>/public/index.html</dt>\n                <dd>The main landing page of the website, not particularly different from the other pages, except for its path.</dd>\n                <dt>/public/index.[js/css]</dt>\n                <dd>\n                    The main stylesheet and javascript. These contain the shared styles and code for all pages.\n                    <code>index.js</code> loads and registers the web components used on all pages.\n                    By sharing these across multiple HTML pages unnecessary duplication and inconsistencies between pages can be avoided.\n                </dd>\n                <dt>/public/pages/<em>[name]</em>.html</dt>\n                <dd>\n                    All of the site's other pages, each including the same <code>index.js</code> and <code>index.css</code>,\n                    and ofcourse containing the content directly as markup in the HTML, leveraging the web components.\n                </dd>\n                <dt>/public/components/<em>[name]</em>/</dt>\n                <dd>\n                    One folder per web component, containing a <code>[name].js</code> and <code>[name].css</code> file.\n                    The <code>.js</code> file is imported into the <code>index.js</code> file to register the web component.\n                    The <code>.css</code> file is imported into the global <code>index.css</code> or in the shadow DOM, as explained on the styling page.\n                </dd>\n                <dt>/public/lib/</dt>\n                <dd>For all external libraries used as dependencies. See below for how to add and use these dependencies.</dd>\n                <dt>/public/styles/</dt>\n                <dd>The global styles referenced from <code>index.css</code>, as explained on the styling page.</dd>\n            </dl>\n            <p>\n                Configuration files for a smoother workflow in programmer's editors also belong in the project's root.\n                Most of the development experience of a framework-based project is possible without a build step through editor extensions.\n                See the <a href=\"../blog/articles/2024-10-20-editing-plain-vanilla/\">Visual Studio Code setup</a> for this site for an example.\n            </p>\n        </section>\n        <section id=\"routing\">\n            <a href=\"#routing\" class=\"section-anchor\">#</a>\n            <h2>Routing</h2>\n            <p>\n                The old-school routing approach of standard HTML pages and <code>&lt;a&gt;</code> tags to link them together has the advantages of being easily indexed by search engines\n                and fully supporting browser history and bookmarking functionality out of the box. 😉\n            </p>\n        </section>\n        <section id=\"dependencies\">\n            <a href=\"#dependencies\" class=\"section-anchor\">#</a>\n            <h2>Dependencies</h2>\n            <p>At some point you may want to pull in third-party libraries. Without npm and a bundler this is still possible.</p>\n            <h3>Unpkg</h3>\n            <p>\n                To use libraries without a bundler they need to be prebuilt in either ESM or UMD format.\n                These libraries can be obtained from unpkg.com:\n            </p>\n            <ol>\n                <li>Browse to <code>unpkg.com/[library]/</code> (trailing slash matters), for example <a href=\"https://unpkg.com/microlight/\" target=\"_blank\" rel=\"noopener\">unpkg.com/microlight/</a></li>\n                <li>Look for and download the library js file, which may be in a subfolder, like <code>dist</code>, <code>esm</code> or <code>umd</code></li>\n                <li>Place the library file in the <code>lib/</code> folder</li>\n            </ol>\n            <p>Alternatively, the library may be loaded directly from CDN.</p>\n\n            <h3>UMD</h3>\n            <p>\n                The <a href=\"https://jameshfisher.com/2020/10/04/what-are-umd-modules/\">UMD module format</a> is an older format for libraries loaded from script tag,\n                and it is the most widely supported, especially among older libraries.\n                It can be recognized by having <code>typeof define === 'function' && define.amd</code> somewhere in the library JS.\n            </p>\n            <p>To include it in your project:</p>\n            <ol>\n                <li>Include it in a script tag: <code>&lt;script src=\"lib/microlight.js\"&gt;&lt;/script&gt;</code></li>\n                <li>Obtain it off the window: <code>const { microlight } = window;</code></li>\n            </ol>\n\n            <h3>ESM</h3>\n            <p>\n                The <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\">ESM module format</a> (also known as JavaScript modules) is the format specified by the ECMAScript standard, and newer or well-behaved libraries will typically provide an ESM build.\n                It can be recognized by the use of the <code>export</code> keyword.\n            </p>\n            <p>To include it in your project:</p>\n            <ul>\n                <li>Load it from CDN:<br><code>import('https://unpkg.com/web-vitals@4.2.2/dist/web-vitals.js').then((webVitals) => ...)</code></li>\n                <li>Or load it from a local copy:<br><code>import webVitals from 'lib/web-vitals.js'</code></li>\n            </ul>\n\n            <h3>imports.js</h3>\n            <p>\n                To neatly organize libraries and separate them from the rest of the codebase, they can be loaded and exported from an <code>imports.js</code> file.\n                For example, here is a page that uses a UMD build of <a href=\"https://day.js.org/\">Day.js</a> and an ESM build of <a href=\"https://github.com/GoogleChrome/web-vitals\">web-vitals</a>:\n            </p>\n            <iframe src=\"./examples/sites/imports/index.html\" title=\"imports.js example\" height=\"100\"></iframe>\n            <p>The text is rendered by the <code>&lt;x-metrics&gt;</code> component:</p>\n            <x-code-viewer src=\"./examples/sites/imports/components/metrics.js\" name=\"components/metrics.js\"></x-code-viewer>\n            <p>In the <code>/lib</code> folder we find these files:</p>\n            <ul>\n                <li>web-vitals.js - the ESM build of web-vitals</li>\n                <li>dayjs/\n                    <ul>\n                        <li>dayjs.min.js - the UMD build of Day.js</li>\n                        <li>relativeTime.js - the UMD build of this Day.js plugin</li>\n                    </ul>\n                </li>\n                <li>imports.js</li>\n            </ul>\n            <p>Digging deeper into this last file we see how it bundles loading of third-party dependencies:</p>\n            <x-code-viewer src=\"./examples/sites/imports/lib/imports.js\" name=\"lib/imports.js\"></x-code-viewer>\n            <p>\n                It imports the ESM library directly, but it pulls the UMD libraries off the <code>Window</code> object.\n                These are loaded in the HTML.\n            </p>\n\n            <p>Here is the combined example:</p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/sites/imports/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/sites/imports/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/sites/imports/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"metrics.js\">\n                    <x-code-viewer src=\"./examples/sites/imports/components/metrics.js\" name=\"components/metrics.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"imports.js\">\n                    <x-code-viewer src=\"./examples/sites/imports/lib/imports.js\" name=\"lib/imports.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>Regrettably not all libraries have a UMD or ESM build, but more and more do.</p>\n\n            <h3>Import Maps</h3>\n            \n            <p>\n                An alternative to the <code>imports.js</code> approach are <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap\">import maps</a>.\n                These define a unique mapping between importable module name and corresponding library file in a special script tag in the HTML head.\n                This allows a more traditional module-based import syntax in the rest of the codebase.\n            </p>\n            <p>The previous example adapted to use import maps:</p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"./examples/sites/importmap/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"module.js\">\n                    <x-code-viewer src=\"./examples/sites/importmap/lib/dayjs/module.js\" name=\"lib/dayjs/module.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"metrics.js\">\n                    <x-code-viewer src=\"./examples/sites/importmap/components/metrics.js\" name=\"components/metrics.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n            <p>Some things to take into account when using import maps:</p>\n            <ul>\n                <li>\n                    Import maps can only map to ESM modules, so for UMD libraries a wrapper must be provided, \n                    as with the <code>module.js</code> wrapper for <code>dayjs</code> in this example.\n                </li>\n                <li>\n                    External import maps of the form <code>&lt;script type=\"importmap\" src=\"importmap.json\"&gt;</code> are <a href=\"https://github.com/WICG/import-maps/issues/235\">not yet supported</a> in all browsers.\n                    This means the import map must be duplicated in every HTML page.\n                </li>\n                <li>\n                    The import map must be defined before the <code>index.js</code> script is loaded, preferably from the <code>&lthead&gt;</code> section.\n                </li>\n                <li>\n                    Import maps can be used to more easily load libraries from a <code>node_modules</code> folder or from a CDN.\n                    <a href=\"https://generator.jspm.io\">JSPM generator</a> can be used to quickly create an import map for CDN dependencies.\n                    Use this with caution, as adding such external dependencies makes a vanilla codebase rely on the continued availability of that service.\n                </li>\n            </ul>\n        </section>\n        <section id=\"browser-support\">\n            <a href=\"#browser-support\" class=\"section-anchor\">#</a>\n            <h2>Browser support</h2>\n            <p>Vanilla web sites are supported in all modern browsers. But what does that mean?</p>\n            <ul>\n                <li>Everything on this site works in current versions of Safari, Chrome, Edge and Firefox.</li>\n                <li>\n                    Everything on this site has 95% support or more on <a href=\"https://caniuse.com\">caniuse.com</a>, \n                    with the exception of <a href=\"https://caniuse.com/wf-popover\">Popover</a> (87%), \n                    <a href=\"https://caniuse.com/wf-details-name\">mutually-exclusive details</a> (86%), \n                    and <a href=\"https://caniuse.com/css-nesting\">CSS Nesting</a> (90%), and it won't be long before those catch up.\n                </li>\n                <li>\n                    That in turn means you can safely rely on <a href=\"https://caniuse.com/http2\">HTTP/2</a>, <a href=\"https://caniuse.com/html5semantic\">HTML5 semantic elements</a>, <a href=\"https://caniuse.com/custom-elementsv1\">Custom Elements</a>, \n                    <a href=\"https://caniuse.com/template\">Templates</a>, <a href=\"https://caniuse.com/shadowdomv1\">Shadow DOM</a>, <a href=\"https://caniuse.com/mdn-api_mutationobserver\">MutationObserver</a>, \n                    <a href=\"https://caniuse.com/customevent\">CustomEvent</a>, <a href=\"https://caniuse.com/mdn-api_formdata\">FormData</a>, and the <a href=\"https://caniuse.com/element-closest\">Element.closest</a> API.\n                </li>\n                <li>\n                    It's also safe to use <a href=\"https://caniuse.com/es6-module\">JavaScript Modules</a>, <a href=\"https://caniuse.com/es6\">ECMAScript 6 / 2015</a>, \n                    <a href=\"https://caniuse.com/async-functions,object-values,object-entries,mdn-javascript_builtins_object_getownpropertydescriptors,pad-start-end,mdn-javascript_grammar_trailing_commas_trailing_commas_in_functions\">ECMAScript 8 / 2017</a>\n                    and <a href=\"https://caniuse.com/?feats=mdn-javascript_operators_optional_chaining,mdn-javascript_operators_nullish_coalescing,mdn-javascript_builtins_globalthis,es6-module-dynamic-import,bigint,mdn-javascript_builtins_promise_allsettled,mdn-javascript_builtins_string_matchall,mdn-javascript_statements_export_namespace,mdn-javascript_operators_import_meta\">ECMAScript 11 / 2020</a>.\n                </li>\n                <li>\n                    In CSS you can rely on <a href=\"https://caniuse.com/mdn-css_at-rules_import\">@import</a>, <a href=\"https://caniuse.com/css-variables\">variables</a>, \n                    <a href=\"https://caniuse.com/calc\">calc()</a>, <a href=\"https://caniuse.com/flexbox\">flexbox</a>, <a href=\"https://caniuse.com/css-grid\">grid</a>, \n                    <a href=\"https://caniuse.com/css-display-contents\">display: contents</a> and so much more.\n                </li>\n            </ul>\n            <p>To keep up with new web standards, keep an eye on these projects:</p>\n            <ul>\n                <li><a href=\"https://web.dev/baseline\">Baseline</a> keeps track of which features are widely available in browsers and lets you know when they are safe to use.</li>\n                <li><a href=\"https://web.dev/blog/interop-2025\">Interop</a> is a yearly initiative between browser makers to bring new web platform features to all browsers, or fix compatibility of existing ones. Consider it a preview of what will become baseline.</li>\n            </ul>\n        </section>\n        <section id=\"deploying\">\n            <a href=\"#deploying\" class=\"section-anchor\">#</a>\n            <h2>Deploying</h2>\n            <p>Any provider that can host static websites can be used for deployment.</p>\n            <p>An example using <a href=\"https://pages.github.com/\">GitHub Pages</a>:</p>\n            <ol>\n                <li>Upload the project as a repository on GitHub</li>\n                <li>Go to Settings, Pages</li>\n                <li>Source: GitHub Actions</li>\n                <li>Static Website, Configure</li>\n                <li>Scroll down to <code>path</code>, and change it to <code>./public</code></li>\n                <li>Commit changes...</li>\n                <li>Go to the Actions page for the repository, wait for the site to deploy</li>\n            </ol>\n        </section>\n        <section id=\"testing\">\n            <a href=\"#testing\" class=\"section-anchor\">#</a>\n            <h2>Testing</h2>\n\n            <p>\n                Popular testing frameworks are all designed to run in build pipelines.\n                However, a plain vanilla web site has no build.\n                To test web components an old-fashioned approach can be used: testing in the browser using the Mocha framework.\n            </p>\n\n            <p>For example, these are the live unit tests for the <code>&lt;x-tab-panel&gt;</code> component used to present tabbed source code panels on this site:</p>\n            <iframe src=\"../tests/index.html\" title=\"unit tests\" loading=\"lazy\"></iframe>\n\n            <p>And for ultimate coding inception, here is that tabpanel component showing the testing source code:</p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\" active>\n                    <x-code-viewer src=\"../tests/index.html\" name=\"tests/index.html\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"../tests/index.js\" name=\"tests/index.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"tabpanel.test.js\">\n                    <x-code-viewer src=\"../tests/tabpanel.test.js\" name=\"tests/tabpanel.test.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"imports-test.js\">\n                    <x-code-viewer src=\"../tests/imports-test.js\" name=\"tests/imports-test.js\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>Some working notes for how this is set up:</p>\n            <ul>\n                <li>\n                    The entire code for the unit tests, including the testing libraries, is isolated to a <code>public/tests/</code> subfolder.\n                    The tests will therefore be available live by adding <code>/tests</code> to the deployed site's URL.\n                    If you don't want to deploy the tests on the live website, exclude the tests folder during the deploy step.\n                </li>\n                <li>\n                    <a href=\"https://mochajs.org/\">Mocha</a> and <a href=\"https://www.chaijs.com/\">Chai</a> are used as test and assertion frameworks, \n                    because they work in-browser without a build step.\n                </li>\n                <li>\n                    <a href=\"https://testing-library.com\">DOM Testing Library</a> is used to more easily query the DOM. \n                    The <code>imports-test.js</code> file configures it for vanilla use.\n                </li>\n                <li>\n                    An important limitation is that DOM Testing Library <a href=\"https://github.com/testing-library/dom-testing-library/issues/413\">cannot query inside shadow roots</a>.\n                    To test something inside a shadow root it is necessary to first query for the containing web component, \n                    get a handle to its <code>shadowRoot</code> property, and then query inside of that.\n                </li>\n                <li>\n                    Web Components initialize asynchronously, which can make them tricky to test.\n                    Use the <a href=\"https://testing-library.com/docs/dom-testing-library/api-async\">async methods</a> of DOM Testing Library.\n                </li>\n            </ul>\n        </section>\n        <section id=\"example\">\n            <a href=\"#example\" class=\"section-anchor\">#</a>\n            <h2>Example</h2>\n            <p>This website is the example. Check out the <a href=\"https://github.com/jsebrech/plainvanilla/\">project on GitHub</a>.</p>\n        </section>\n        <section>\n            <h2>Up next</h2>\n            <hr />\n            <p>Learn how to build single-page applications using vanilla techniques.</p>\n            <p><a href=\"applications.html\" class=\"button\">Make Applications</a></p>\n        </section>\n    </main>\n\n    <footer>\n        <div class=\"contact\">\n            <a href=\"https://sebrechts.net/\">Contact</a>\n            <a href=\"https://github.com/jsebrech/plainvanilla\">GitHub</a>\n        </div>\n        <p class=\"top-link\">\n            <a href=\"#top\">Back to top</a>\n        </p>\n        <x-analytics></x-analytics>\n    </footer>\n</body>\n</html>"
  },
  {
    "path": "public/pages/styling.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla - Styling</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <meta name=\"description\" content=\"An explainer for styling web sites using only vanilla techniques.\">\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"apple-touch-icon\" href=\"../apple-touch-icon.png\">\n    <link rel=\"stylesheet\" href=\"../index.css\">\n    <script type=\"module\" src=\"../index.js\" defer></script>\n</head>\n<body>\n    <noscript><strong>Please enable JavaScript to view this page correctly.</strong></noscript>\n    <header>\n        <h1>Styling</h1>\n        <nav id=\"menu-nav\" popover aria-label=\"main\">\n            <ol>\n                <li><a href=\"../index.html\">Welcome</a></li>\n                <li><a href=\"components.html\">Components</a></li>\n                <li><a href=\"#\" aria-current=\"page\">Styling</a></li>\n                <li><a href=\"sites.html\">Sites</a></li>\n                <li><a href=\"applications.html\">Applications</a></li>\n                <li class=\"nav-right\"><a href=\"../blog/\">Blog</a></li>\n            </ol>\n        </nav>\n        <button popovertarget=\"menu-nav\" popovertargetaction=\"toggle\" aria-label=\"menu\">\n            &mldr;\n        </button>\n    </header>\n    <main>\n        <section>\n            <h2>Modern CSS</h2>\n            <p>\n                Modern web applications are built on top of rich tooling for dealing with CSS, relying on plenty of NPM packages and build steps.\n                A vanilla web application has to choose a lighter weight path, abandoning the preprocessed modern CSS approaches \n                and choosing strategies that are browser native.\n            </p>\n        </section>\n        <section id=\"reset\">\n            <a href=\"#reset\" class=\"section-anchor\">#</a>\n            <h2>Reset</h2>\n            <p>Resetting the styles to a cross-browser common baseline is standard practice in web development, and vanilla web apps are no different.</p>\n            <p>A minimal reset is the one used by this site:</p>\n            <x-code-viewer src=\"../styles/reset.css\"></x-code-viewer>\n            <p>Other options, in increasing order of complexity:</p>\n            <dl>\n                <dt><a href=\"https://github.com/sindresorhus/modern-normalize\">modern-normalize</a></dt>\n                <dd>\n                    <p>A more comprehensive solution for resetting CSS for modern browsers.</p>\n                    <p><a href=\"https://www.jsdelivr.com/package/npm/modern-normalize\">Include it from CDN</a></p>\n                </dd>\n                <dt><a href=\"https://cferdinandi.github.io/kraken/\">Kraken</a></dt>\n                <dd>\n                    <p>A starting point for front-end projects. It includes a CSS reset, typography, a grid, and other conveniences.</p>\n                    <p><a href=\"https://cdnjs.com/libraries/Kraken\">Include it from CDN</a></p>\n                </dd>\n                <dt><a href=\"https://picocss.com/\">Pico CSS</a></dt>\n                <dd>\n                    <p>A complete starter kit for styling of semantic HTML that includes a CSS reset.</p>\n                    <p><a href=\"https://picocss.com/docs#usage-from-cdn\">Include it from CDN</a></p>\n                </dd>\n                <dt><a href=\"https://tailwindcss.com/\">Tailwind</a></dt>\n                <dd>\n                    <p>If you're going to be using Tailwind anyway, you may as well lean on its CSS reset.</p>\n                    <p><a href=\"https://tailwindcss.com/docs/installation/play-cdn\">Include it from CDN</a></p>\n                </dd>\n            </dl>\n        </section>\n        <section id=\"fonts\">\n            <a href=\"#fonts\" class=\"section-anchor\">#</a>\n            <h2>Fonts</h2>\n            <p>\n                Typography is the keystone of a web site or web application. \n                A lean approach like vanilla web development should be matched with a lean approach for typography.\n                <a href=\"https://modernfontstacks.com/\">Modern Font Stacks</a> describes a varied selection of commonly available fonts with good fallbacks,\n                avoiding the need to load custom fonts and add external dependencies.\n            </p>\n            <p>This site uses the <em>Geometric Humanist</em> stack for normal text, and the <em>Monospace Code</em> stack for source code.</p>\n        </section>\n        <section id=\"toolbox\">\n            <a href=\"#toolbox\" class=\"section-anchor\">#</a>\n            <h2>The Toolbox</h2>\n            <p>\n                In any real world web project the amount of CSS quickly becomes unwieldy unless it is well-structured.\n                Let's look at the toolbox that CSS provides us in modern browsers to provide that structure.\n            </p>\n            <dl>\n                <dt><code>@import</code></dt>\n                <dd>\n                    <p>\n                        The most basic structuring technique is separating CSS into multiple files. \n                        We could add all those files in order as <code>&lt;link&gt;</code> tags into the <code>index.html</code>\n                        but this quickly becomes unworkable if we have multiple HTML pages.\n                        Instead it is better to <code>@import</code> them into the <code>index.css</code> where they will still download in parallel.   \n                    </p>\n                    <p>For example, here's the main CSS file for this site:</p>\n                    <x-code-viewer src=\"../index.css\"></x-code-viewer>\n                    <p>Below is a recommended organization of CSS files.</p>\n                </dd>\n                <dt>Custom properties (variables)</dt>\n                <dd>\n                    <p><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties\">CSS variables</a> can be used to define the site's font and theme in a central place.</p>\n                    <p>For example, here are the variables for this site:</p>\n                    <x-code-viewer src=\"../styles/variables.css\"></x-code-viewer>\n                    <p>CSS variables become even more capable when combined with <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/calc\">calc()</a>.</p>\n                </dd>\n                <dt>Custom elements</dt>\n                <dd>\n                    <p>Styles can be easily scoped to a custom element's tag.</p>\n                    <p>For example, the styles of the avatar component from the components page are all prepended by the <code>x-avatar</code> selector:</p>\n                    <x-code-viewer src=\"./examples/components/advanced/components/avatar.css\"></x-code-viewer>\n                    <p>Custom elements can also have custom attributes that selectors can leverage, as with the <code>[size=lg]</code> style in this example.</p>\n                </dd>\n                <dt>Shadow DOM</dt>\n                <dd>\n                    <p>\n                        Adding a shadow DOM to a web component further isolates its styles from the rest of the page.\n                        For example, the <code>x-header</code> component from the previous page styles its <code>h1</code> element inside its CSS,\n                        without affecting the containing page or the header's child elements.\n                    </p>\n                    <p>\n                        All CSS files that need to apply to the shadow DOM must be loaded into it explicitly,\n                        but <a href=\"https://javascript.info/shadow-dom-style\">CSS variables are passed into the shadow DOM</a>.\n                    </p>\n                    <p>\n                        A limitation of shadow DOMs is that to use custom fonts inside them, they must first be loaded into the light DOM.\n                    </p>\n                </dd>\n            </dl>\n        </section>\n        <section id=\"files\">\n            <a href=\"#files\" class=\"section-anchor\">#</a>\n            <h2>Files</h2>\n            <p>There are many ways to organize CSS files in a repository, but this is the one used here:</p>\n            <dl>\n                <dt><code>/index.css</code></dt>\n                <dd>The root CSS file that imports all the other ones using <code>@import</code>.</dd>\n                <dt><code>/styles/reset.css</code></dt>\n                <dd>The reset stylesheet is the first thing imported.</dd>\n                <dt><code>/styles/variables.css</code></dt>\n                <dd>All CSS variables are defined in this separate file, including the font system.</dd>\n                <dt><code>/styles/global.css</code></dt>\n                <dd>The global styles that apply across the web pages of the site.</dd>\n                <dt><code>/components/example/example.css</code></dt>\n                <dd>All styles that aren't global are specific to a component, in a CSS file located next to the component's JS file.</dd>\n            </dl>\n        </section>\n        <section id=\"scope\">\n            <a href=\"#scope\" class=\"section-anchor\">#</a>\n            <h2>Scope</h2>\n            <p>\n                In order to avoid conflicting styles between pages and components we want to scope styles locally by default.\n                There are two main ways of achieving that in vanilla web development.\n            </p>\n\n            <h3>Prefixed selectors</h3>\n            <p>\n                For custom elements that don't have a shadow DOM we can prefix the styles with the tag of the custom element.\n                For example, here's a simple web component that uses prefixed selectors to create a local scope:\n            </p>\n            <x-tab-panel>\n                <x-tab title=\"index.html\">\n                    <x-code-viewer src=\"./examples/styling/scoping-prefixed/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/styling/scoping-prefixed/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.css\">\n                    <x-code-viewer src=\"./examples/styling/scoping-prefixed/index.css\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"example.js\">\n                    <x-code-viewer src=\"./examples/styling/scoping-prefixed/components/example/example.js\" name=\"components/example/example.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"example.css\" active>\n                    <x-code-viewer src=\"./examples/styling/scoping-prefixed/components/example/example.css\" name=\"components/example/example.css\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <iframe src=\"./examples/styling/scoping-prefixed/index.html\" title=\"prefixed selectors example\"></iframe>\n\n            <aside>\n                <h4>Tip: CSS Nesting</h4>\n                <p>If you want a cleaner syntax, and you are comfortable with the <a href=\"https://caniuse.com/css-nesting\">browser support</a>, consider using <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting\">CSS Nesting</a>.</p>\n                <x-code-viewer src=\"./examples/styling/scoping-prefixed/components/example/example_nested.css\" name=\"components/example/example.css\"></x-code-viewer>\n            </aside>\n\n            <h3>Shadow DOM import</h3>\n            <p>\n                Custom elements that use a shadow DOM start out unstyled with a local scope,\n                and all styles must be explicitly imported into them. Here is the prefixed example reworked to use a shadow DOM instead.\n            </p>\n\n            <x-tab-panel>\n                <x-tab title=\"index.html\">\n                    <x-code-viewer src=\"./examples/styling/scoping-shadowed/index.html\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"index.js\">\n                    <x-code-viewer src=\"./examples/styling/scoping-shadowed/index.js\" name=\"\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"example.js\">\n                    <x-code-viewer src=\"./examples/styling/scoping-shadowed/components/example/example.js\" name=\"components/example/example.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"example.css\" active>\n                    <x-code-viewer src=\"./examples/styling/scoping-shadowed/components/example/example.css\" name=\"components/example/example.css\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <iframe src=\"./examples/styling/scoping-shadowed/index.html\" title=\"shadow dom import example\"></iframe>\n\n            <p>To reuse styles from the surrounding page inside the shadow DOM, consider these options:</p>\n            <ul>\n                <li>Common CSS files can be imported inside the shadow DOM using <code>&lt;link&gt;</code> tags or <code>@import</code>.</li>\n                <li>CSS variables defined in the surrounding page can be referenced inside the shadow DOM's styles.</li>\n                <li>For advanced shadow domination the <code>::part</code> pseudo-element can be used to <a href=\"https://meowni.ca/posts/part-theme-explainer/\">expose an API for styling</a>.</li>\n            </ul>\n        </section>\n        <section id=\"replacing-css-modules\">\n            <a href=\"#replacing-css-modules\" class=\"section-anchor\">#</a>\n            <h2>Replacing CSS modules</h2>\n            <p>\n                The local scoping feature of CSS modules can be replaced by one of the scoping mechanisms described above.\n                For instance, let's take the <a href=\"https://nextjs.org/docs/14/app/building-your-application/styling/css-modules\">example of CSS modules</a> from the Next.JS 14 documentation:\n            </p>\n            <x-tab-panel>\n                <x-tab title=\"layout.tsx\" active>\n                    <x-code-viewer src=\"./examples/styling/replacing-css-modules/nextjs/layout.tsx\" name=\"app/dashboard/layout.tsx\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"styles.module.css\">\n                    <x-code-viewer src=\"./examples/styling/replacing-css-modules/nextjs/styles.module.css\" name=\"app/dashboard/styles.module.css\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n\n            <p>As a vanilla web component, this is what that looks like:</p>\n            <x-tab-panel>\n                <x-tab title=\"layout.js\" active>\n                    <x-code-viewer src=\"./examples/styling/replacing-css-modules/vanilla/layout.js\" name=\"components/dashboard/layout.js\"></x-code-viewer>\n                </x-tab>\n                <x-tab title=\"styles.css\">\n                    <x-code-viewer src=\"./examples/styling/replacing-css-modules/vanilla/styles.css\" name=\"components/dashboard/styles.css\"></x-code-viewer>\n                </x-tab>\n            </x-tab-panel>\n            <p>Because the shadow DOM does not inherit the page's styles, the <code>styles.css</code> must first import the styles that are shared between the page and the shadowed web component.</p>\n        </section>\n        <section id=\"replacing-postcss\">\n            <a href=\"#replacing-postcss\" class=\"section-anchor\">#</a>\n            <h2>Replacing PostCSS</h2>\n            <p>Let's go over the main page of <a href=\"https://postcss.org/\">PostCSS</a> to review its feature set.</p>\n            <dl>\n                <dt>Add vendor prefixes to CSS rules using values from Can I Use.</dt>\n                <dd>\n                    Vendor prefixes are no longer needed for most use cases.\n                    The <code>:fullscreen</code> pseudo-class shown in the example now <a href=\"https://caniuse.com/mdn-css_selectors_fullscreen\">works across browsers unprefixed</a>.\n                </dd>\n                <dt>Convert modern CSS into something most browsers can understand.</dt>\n                <dd>\n                    The modern CSS you want to use is most likely already supported.\n                    The <code>color: oklch()</code> rule shown in the example now <a href=\"https://caniuse.com/?search=oklch\">works across browsers</a>.\n                </dd>\n                <dt>CSS Modules</dt>\n                <dd>\n                    See the alternatives described in the previous section.\n                </dd>\n                <dt>Enforce consistent conventions and avoid errors in your stylesheets with stylelint.</dt>\n                <dd>\n                    The <a href=\"https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint\">vscode-stylelint extension</a> can be added into Visual Studio Code to get the same linting at develop time,\n                    without needing it to be baked into a build step.\n                </dd>\n            </dl>\n            <p><strong>Bottom line:</strong> Microsoft's dropping of support for IE11 combined with the continuing improvements of evergreen browsers has made PostCSS largely unnecessary.</p>\n        </section>\n        <section id=\"replacing-sass\">\n            <a href=\"#replacing-sass\" class=\"section-anchor\">#</a>\n            <h2>Replacing SASS</h2>\n            <p>Similarly to PostCSS, let's go over the main feature set of <a href=\"https://sass-lang.com/guide/\">SASS</a>:</p>\n            <dl>\n                <dt>Variables</dt>\n                <dd>Replaced by <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties\">CSS custom properties</a>.</dd>\n                <dt>Nesting</dt>\n                <dd>CSS nesting is <a href=\"https://caniuse.com/css-nesting\">widely supported</a> across major browsers.</dd>\n                <dt>Modules</dt>\n                <dd>Can be approximated by a combination of <code>@import</code>, CSS variables, and the scoping mechanisms described above.</dd>\n                <dt>Mixins</dt>\n                <dd>Regrettably the <a href=\"https://github.com/w3c/csswg-drafts/issues/9350\">CSS mixins</a> feature that will replace this is still in specification.</dd>\n                <dt>Operators</dt>\n                <dd>In many cases can be replaced by the built-in <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/calc\">calc()</a> feature.</dd>\n            </dl>\n            <p><strong>Bottom-line:</strong> SASS is a lot more powerful than PostCSS, and while many of its features have a vanilla alternative it is not as easy to replace entirely. YMMV whether the added complexity of the SASS preprocessor is worth the additional abilities.</p>\n        </section>\n        <section>\n            <h2>Up next</h2>\n            <hr />\n            <p>Learn about making vanilla sites with web components.</p>\n            <p><a href=\"sites.html\" class=\"button\">Make Sites</a></p>\n        </section>\n    </main>\n\n    <footer>\n        <div class=\"contact\">\n            <a href=\"https://sebrechts.net/\">Contact</a>\n            <a href=\"https://github.com/jsebrech/plainvanilla\">GitHub</a>\n        </div>\n        <p class=\"top-link\">\n            <a href=\"#top\">Back to top</a>\n        </p>\n        <x-analytics></x-analytics>\n    </footer>\n</body>\n</html>"
  },
  {
    "path": "public/robots.txt",
    "content": "User-agent: *\nDisallow: /blog/generator.html\nDisallow: /pages/examples/\n"
  },
  {
    "path": "public/sitemap.txt",
    "content": "https://plainvanillaweb.com/\nhttps://plainvanillaweb.com/index.html\nhttps://plainvanillaweb.com/pages/components.html\nhttps://plainvanillaweb.com/pages/styling.html\nhttps://plainvanillaweb.com/pages/sites.html\nhttps://plainvanillaweb.com/pages/applications.html\nhttps://plainvanillaweb.com/blog/index.html\nhttps://plainvanillaweb.com/blog/archive.html\nhttps://plainvanillaweb.com/blog/articles/2024-08-17-lets-build-a-blog/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-08-25-vanilla-entity-encoding/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-08-30-poor-mans-signals/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-09-03-unix-philosophy/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-09-06-how-fast-are-web-components/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-09-09-sweet-suspense/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-09-16-life-and-times-of-a-custom-element/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-09-28-unreasonable-effectiveness-of-vanilla-js/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-09-30-lived-experience/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-10-07-needs-more-context/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-10-20-editing-plain-vanilla/index.html\nhttps://plainvanillaweb.com/blog/articles/2024-12-16-caching-vanilla-sites/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-01-01-new-years-resolve/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-05-09-form-control/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-06-12-view-transitions/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-06-25-routing/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-07-13-history-architecture/index.html\nhttps://plainvanillaweb.com/blog/articles/2025-07-16-local-first-architecture/index.html\nhttps://plainvanillaweb.com/blog/articles/2026-03-01-redesigning-plain-vanilla/index.html\nhttps://plainvanillaweb.com/blog/articles/2026-03-09-details-matters/index.html\n"
  },
  {
    "path": "public/styles/global.css",
    "content": "html {\n    margin: 0 auto;\n    max-width: 960px;\n    background-color: var(--background-color-html);\n    box-shadow: 0 0 0.5em var(--background-color-html-shadow);\n    color: var(--text-color);\n    overscroll-behavior: none;\n}\n\nbody {\n    font-family: var(--font-system);\n    font-weight: normal;\n    background-color: var(--background-color);\n    padding: var(--body-padding-tb) var(--body-padding-lr);\n    padding-bottom: 0;\n    /* make room for navigation */\n    padding-top: calc(var(--body-padding-tb) + 5em);\n}\n\na, a:hover {\n    color: var(--link-color);\n}\n\nh1 {\n    font-size: 3.5em;\n    position: relative;\n    left: -5px;\n    font-weight: lighter;\n}\n\nh2, h3, h4, p {\n    margin-bottom: 1em;\n}\n\nh2 {\n    margin-top: 1em;\n    font-size: 1.5em;\n    font-weight: lighter;\n}\n\nh3 {\n    margin-top: 1em;\n    font-size: 1.2em;\n}\n\nh4 {\n    font-size: 1em;\n}\n\nul {\n    padding-left: 2em;\n    margin-top: 0.5em;\n}\n\nul ul {\n    margin-top: 0;\n}\n\ndl {\n    padding-left: 0;\n}\n\ndt {\n    margin: 0.5em 0;\n}\n\ndt::before {\n    content: \"\";\n    border-left: 3px solid var(--base-color);\n    margin: 0 calc(1em - 3px) 0 0;\n}\n\ndd {\n    margin-left: 1em;\n    margin-bottom: 1em;\n}\n\nhr {\n    border: none;\n    border-top: 1px solid var(--border-color);\n    margin: -0.5em 0 1em 0;\n    width: 100%;\n}\n\nsection {\n    position: relative;\n}\n\na.section-anchor {\n    color: inherit;\n    display: none;\n    position: absolute;\n    left: -1.5em;\n    padding-left: 0.6em;\n    font-size: 120%;\n    top: 0;\n    padding-top: 0.2em;\n    width: 1.5em;\n    height: 3em;\n    opacity: 0.4;\n}\n\nsection:hover > a.section-anchor {\n    display: inline;\n}\n\nsection:hover > a.section-anchor:hover {\n    opacity: 1;\n    color: var(--link-color);\n}\n\nblockquote {\n    border-left: 10px solid var(--base-color-tint-light);\n    margin: 1.5em 0 1em 0.5em;\n    padding: 0.5em 10px;\n    quotes: \"\\201C\"\"\\201D\"\"\\2018\"\"\\2019\";\n    color: var(--text-color-mute);\n    font-size: 90%;\n}\n\ncite {\n    display: block;\n    margin: 0 0 1em 0.5em;\n}\n\ntable {\n    margin-bottom: 1em;\n}\n\n/* page header and navigation */\n\nheader {\n    margin-bottom: 1.5em;\n    text-align: left;\n}\n\nnav {\n    position: fixed;\n    border: none;\n    top: 0;\n    left: 0;\n    right: 0;\n    width: 100%;\n    max-width: 960px;\n    margin: 0 auto;\n    padding: 3em 0 0 0;\n    /* make content scroll underneath it */\n    background-color: var(--background-color);\n    z-index: 1;\n    box-shadow: 0 1em 1em var(--background-color);\n    clip-path: inset(0px 0 -2em 0);\n}\n\nnav ol {\n    display: flex;\n    margin: 0 var(--body-padding-lr);\n    list-style-type: none;\n    padding: 0.7em 0;\n\n    border-bottom: 1px solid black;\n}\n\nnav ol a {\n    text-decoration: none;\n    color: inherit;\n}\n\nnav ol a:hover {\n    text-decoration: underline;\n    color: inherit;\n}\n\nnav ol a[aria-current],\nnav ol a[aria-current]:hover {\n    font-weight: bold;\n    text-decoration: none;\n}\n\nnav ol li {\n    display: inline;\n}\n\nnav ol li::before {\n    content: \"\";\n    border-left: 1px solid black;\n    margin: 0 0.4em;\n}\n\nnav ol li:first-child::before {\n    display:none;\n}\n\nnav ol li.nav-right {\n    margin-left: auto;\n}\n\nnav ol li.nav-right::before {\n    display: none;\n}\n\n/* responsive nav menu and other content on smaller screens */\n\n@media screen and (max-width: 600px) {\n\n    body {\n        padding-top: var(--body-padding-tb);\n    }\n\n    h1 {\n        font-size: 3em;\n    }\n\n    nav[popover] {\n        top: 4em;\n        right: 1em;\n        padding-top: 1em;\n        background-color: color-mix(in srgb, var(--background-color) 90%, transparent);\n    }\n\n    button[popovertarget] {\n        position: absolute;\n        top: 0;\n        right: 0.5em;\n        padding: 0.5em;\n        font-size: 2em;\n        background: none;\n        color: inherit;\n        border: none;\n    }\n\n    nav ol {\n        flex-direction: column;\n    }\n\n    nav ol li {\n        text-align: right;\n        font-size: 1.4em;\n    }\n\n    nav ol li::before {\n        border-left: none;\n        margin: 0;\n    }\n\n    nav ol li.nav-right {\n        margin-left: 0;\n    }\n}\n\n@media screen and (min-width: 601px) {\n    nav[popover] {\n        display: block;\n    }\n\n    button[popovertarget] {\n        display: none;\n    }\n}\n\n/* (hidden) skip to content link */\n\na.skip-to-content {\n  /* from https://www.a11y-collective.com/blog/skip-to-main-content/ */\n  position: absolute;\n  left: -9999px;\n  z-index: 999;\n  padding: 1em;\n  background-color: black;\n  color: white;\n  opacity: 0;\n}\n\na.skip-to-content:focus {\n  left: 50%;\n  transform: translateX(-50%);\n  opacity: 1;\n}\n\nmain[id] {\n    /* take sticky header into account when scrolling via skip content */\n    scroll-margin-top: 8em;\n}\n\n/* code examples */\n\ncode {\n    color: var(--code-text-color);\n    background-color: var(--code-text-color-bg);\n    overflow-wrap: break-word;\n    font-family: var(--font-system-code);\n    font-size: var(--font-system-code-size);\n}\n\nx-code-viewer {\n    border: 1px solid var(--border-color);\n    margin: 1em 0 1.5em 0;\n    min-height: 6em;\n    max-height: 30em;\n}\n\nx-tab-panel {\n    border: 1px solid var(--border-color);\n    margin: 1em 0 1.5em 0;\n    min-height: 8em;\n}\n\nx-tab-panel x-code-viewer {\n    border: none;\n    margin: 0;\n}\n\niframe {\n    display: block;\n    width: 100%;\n    margin: 1em 0;\n}\n\n/* asides */\n\naside {\n    position: relative;\n    background-color: var(--background-color-mute);\n    text-align: left;\n    margin: 3em 0 3em calc(var(--body-padding-lr) * -1);\n    padding: 3em 2em 3em var(--body-padding-lr);\n}\n\naside.aside-mirror {\n    margin: 3em calc(var(--body-padding-lr) * -1) 3em 0;\n    padding: 3em var(--body-padding-lr) 3em 2em;\n    text-align: right;\n}\n\naside h2, aside h3, aside h4 {\n    margin: 0;\n}\n\naside p {\n    margin: 1em 0 0.5em 0;\n}\n\naside x-code-viewer {\n    margin: 1em 0;\n}\n\n/* page footer */\n\nfooter {\n    margin: 4em calc(var(--body-padding-lr) * -1);\n    padding: 3em var(--body-padding-lr);\n    margin-bottom: 0;\n    background-color: var(--background-color-invert);\n    color: var(--text-color-invert);\n    text-align: right;\n}\n\nfooter .top-link {\n    margin-top: 1.5em;\n    font-size: 0.9em;\n}\n\nfooter a {\n    color: inherit;\n    text-decoration: none;\n}\n\nfooter a:hover {\n    text-decoration: underline;\n    color: inherit;\n}\n\nfooter .contact a::before {\n    font-size: 0.9em;\n    content: \"\";\n    border-left: 1px solid var(--text-color-invert);\n    margin: 0 0.4em 0 0.2em;\n}\n\nfooter .contact a:first-child::before {\n    display:none;\n}\n\n/* utilities */\n\n.hero-text {\n    font-size: 1.2em;\n    line-height: 1.9em;\n    margin-bottom: 1.8em;\n}\n\na.button {\n    display: inline-block;\n    font-size: 1.1em;\n    color: var(--base-color-shade-darker);\n    background-color: var(--base-color);\n    margin-top: 0.5em;\n    padding: 0.5em 3em;\n    border-radius: 5px;\n    box-shadow: 0.1em 0.1em 0.2em -0.1em var(--background-color-html);\n    text-decoration: none;\n}\n\na.button:hover {\n    background-color: var(--base-color-tint-light);\n}"
  },
  {
    "path": "public/styles/reset.css",
    "content": "/* generic minimal CSS reset\n   inspiration: https://www.digitalocean.com/community/tutorials/css-minimal-css-reset */\n\n:root {\n    box-sizing: border-box;\n    line-height: 1.6;\n    /* https://kilianvalkhof.com/2022/css-html/your-css-reset-needs-text-size-adjust-probably/ */\n    -moz-text-size-adjust: none;\n    -webkit-text-size-adjust: none;\n    text-size-adjust: none;\n}\n\n*, *::before, *::after {\n    box-sizing: inherit;\n}\n\nbody, h1, h2, h3, h4, h5, h6, p {\n    margin: 0;\n    padding: 0;\n    font-weight: normal;\n}\n\nimg {\n    max-width:100%;\n    height:auto;\n}\n"
  },
  {
    "path": "public/styles/variables.css",
    "content": ":root {\n    /* https://modernfontstacks.com/\n       geometric humanist font */\n    --font-system: Avenir, Montserrat, Corbel, source-sans-pro, sans-serif;\n    /* monospace code font */\n    --font-system-code: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n    --font-system-code-size: 0.8rem;\n\n    --base-color: #FFCC4D;\n    --base-color-tint-light: #ffdb82;\n    --base-color-tint-lighter: #fff5db;\n    --base-color-shade-dark: #b38f36;\n    --base-color-shade-darker: #191408;\n\n    --background-color-html: #969696;\n    --background-color-html-shadow: #404040;\n    --background-color: #fdfdfd;\n    --background-color-mute: #f2f2f2;\n\n    --text-color: black;\n    --text-color-mute: hsl(0, 0%, 40%);\n\n    --background-color-invert: var(--base-color-shade-darker);\n    --text-color-invert: white;\n\n    --link-color: black;\n\n    --border-color: black;\n\n    --code-text-color: var(--text-color);\n    --code-text-color-bg: inherit;\n\n    --panel-title-color: black;\n    --panel-title-color-bg: var(--base-color-tint-lighter);\n\n    --body-padding-lr: 5em;\n    --body-padding-tb: 3em;\n\n}\n\n@media screen and (max-width: 600px) {\n    :root {\n        --body-padding-lr: 3em;\n        --body-padding-tb: 3em;\n    }\n}\n"
  },
  {
    "path": "public/tests/imports-test.js",
    "content": "const { expect } = window.chai;\nconst { getByText, queries, within, waitFor, fireEvent } = window.TestingLibraryDom;\n\nlet rootContainer;\nlet screen;\n\nbeforeEach(() => {\n    // the hidden div where the test can render elements\n    rootContainer = document.createElement(\"div\");\n    rootContainer.style.position = 'absolute';\n    rootContainer.style.left = '-10000px';\n    document.body.appendChild(rootContainer);\n    // pre-bind @testing-library/dom helpers to rootContainer\n    screen = Object.keys(queries).reduce((helpers, key) => {\n        const fn = queries[key]\n        helpers[key] = fn.bind(null, rootContainer)\n        return helpers\n    }, {});\n});\n\nafterEach(() => {\n    document.body.removeChild(rootContainer);\n    rootContainer = null;\n});\n\nfunction render(el) {\n    rootContainer.appendChild(el);\n}\n\nexport { \n    rootContainer, \n    expect, \n    render, \n    getByText, screen, within, waitFor, fireEvent\n};\n"
  },
  {
    "path": "public/tests/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n    <title>Plain Vanilla - Tests</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\" />\n    <link rel=\"icon\" href=\"../favicon.ico\">\n    <link rel=\"stylesheet\" href=\"../index.css\">\n    <!-- https://unpkg.com/mocha@9.2.2/mocha.css -->\n    <link rel=\"stylesheet\" href=\"./lib/mocha/mocha.css\" />\n    <!-- https://unpkg.com/chai@4.3.6/chai.js -->\n    <script src=\"./lib/mocha/chai.js\" defer></script>\n    <!-- https://unpkg.com/mocha@9.2.2/mocha.js -->\n    <script src=\"./lib/mocha/mocha.js\" defer></script>\n    <!-- https://unpkg.com/@testing-library/dom@8.17.1/dist/@testing-library/dom.umd.js -->\n    <script src=\"./lib/@testing-library/dom.umd.js\" defer></script>\n    \n    <script type=\"module\" class=\"mocha-init\" defer>\n        mocha.setup('bdd');\n        mocha.checkLeaks();\n    </script>\n    \n    <script type=\"module\" src=\"./tabpanel.test.js\" defer></script>\n    \n    <!-- include more tests here -->\n    \n    <script type=\"module\" class=\"mocha-exec\" src=\"./index.js\" defer></script>\n</head>\n<body>\n    <div id=\"mocha\"></div>\n</body>\n</html>\n"
  },
  {
    "path": "public/tests/index.js",
    "content": "import { registerTabPanelComponent } from \"../components/tab-panel/tab-panel.js\";\n\nconst app = () => {\n    registerTabPanelComponent();\n    mocha.run();\n}\n\ndocument.addEventListener('DOMContentLoaded', app);\n"
  },
  {
    "path": "public/tests/lib/@testing-library/dom.umd.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TestingLibraryDom = {}));\n})(this, (function (exports) { 'use strict';\n\n\tfunction _mergeNamespaces(n, m) {\n\t\tm.forEach(function (e) {\n\t\t\te && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {\n\t\t\t\tif (k !== 'default' && !(k in n)) {\n\t\t\t\t\tvar d = Object.getOwnPropertyDescriptor(e, k);\n\t\t\t\t\tObject.defineProperty(n, k, d.get ? d : {\n\t\t\t\t\t\tenumerable: true,\n\t\t\t\t\t\tget: function () { return e[k]; }\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn Object.freeze(n);\n\t}\n\n\tvar build = {};\n\n\tvar ansiStyles = {exports: {}};\n\n\t(function (module) {\n\n\t  const ANSI_BACKGROUND_OFFSET = 10;\n\n\t  const wrapAnsi256 = function (offset) {\n\t    if (offset === void 0) {\n\t      offset = 0;\n\t    }\n\n\t    return code => \"\\x1B[\" + (38 + offset) + \";5;\" + code + \"m\";\n\t  };\n\n\t  const wrapAnsi16m = function (offset) {\n\t    if (offset === void 0) {\n\t      offset = 0;\n\t    }\n\n\t    return (red, green, blue) => \"\\x1B[\" + (38 + offset) + \";2;\" + red + \";\" + green + \";\" + blue + \"m\";\n\t  };\n\n\t  function assembleStyles() {\n\t    const codes = new Map();\n\t    const styles = {\n\t      modifier: {\n\t        reset: [0, 0],\n\t        // 21 isn't widely supported and 22 does the same thing\n\t        bold: [1, 22],\n\t        dim: [2, 22],\n\t        italic: [3, 23],\n\t        underline: [4, 24],\n\t        overline: [53, 55],\n\t        inverse: [7, 27],\n\t        hidden: [8, 28],\n\t        strikethrough: [9, 29]\n\t      },\n\t      color: {\n\t        black: [30, 39],\n\t        red: [31, 39],\n\t        green: [32, 39],\n\t        yellow: [33, 39],\n\t        blue: [34, 39],\n\t        magenta: [35, 39],\n\t        cyan: [36, 39],\n\t        white: [37, 39],\n\t        // Bright color\n\t        blackBright: [90, 39],\n\t        redBright: [91, 39],\n\t        greenBright: [92, 39],\n\t        yellowBright: [93, 39],\n\t        blueBright: [94, 39],\n\t        magentaBright: [95, 39],\n\t        cyanBright: [96, 39],\n\t        whiteBright: [97, 39]\n\t      },\n\t      bgColor: {\n\t        bgBlack: [40, 49],\n\t        bgRed: [41, 49],\n\t        bgGreen: [42, 49],\n\t        bgYellow: [43, 49],\n\t        bgBlue: [44, 49],\n\t        bgMagenta: [45, 49],\n\t        bgCyan: [46, 49],\n\t        bgWhite: [47, 49],\n\t        // Bright color\n\t        bgBlackBright: [100, 49],\n\t        bgRedBright: [101, 49],\n\t        bgGreenBright: [102, 49],\n\t        bgYellowBright: [103, 49],\n\t        bgBlueBright: [104, 49],\n\t        bgMagentaBright: [105, 49],\n\t        bgCyanBright: [106, 49],\n\t        bgWhiteBright: [107, 49]\n\t      }\n\t    }; // Alias bright black as gray (and grey)\n\n\t    styles.color.gray = styles.color.blackBright;\n\t    styles.bgColor.bgGray = styles.bgColor.bgBlackBright;\n\t    styles.color.grey = styles.color.blackBright;\n\t    styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;\n\n\t    for (const [groupName, group] of Object.entries(styles)) {\n\t      for (const [styleName, style] of Object.entries(group)) {\n\t        styles[styleName] = {\n\t          open: \"\\x1B[\" + style[0] + \"m\",\n\t          close: \"\\x1B[\" + style[1] + \"m\"\n\t        };\n\t        group[styleName] = styles[styleName];\n\t        codes.set(style[0], style[1]);\n\t      }\n\n\t      Object.defineProperty(styles, groupName, {\n\t        value: group,\n\t        enumerable: false\n\t      });\n\t    }\n\n\t    Object.defineProperty(styles, 'codes', {\n\t      value: codes,\n\t      enumerable: false\n\t    });\n\t    styles.color.close = '\\u001B[39m';\n\t    styles.bgColor.close = '\\u001B[49m';\n\t    styles.color.ansi256 = wrapAnsi256();\n\t    styles.color.ansi16m = wrapAnsi16m();\n\t    styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);\n\t    styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js\n\n\t    Object.defineProperties(styles, {\n\t      rgbToAnsi256: {\n\t        value: (red, green, blue) => {\n\t          // We use the extended greyscale palette here, with the exception of\n\t          // black and white. normal palette only has 4 greyscale shades.\n\t          if (red === green && green === blue) {\n\t            if (red < 8) {\n\t              return 16;\n\t            }\n\n\t            if (red > 248) {\n\t              return 231;\n\t            }\n\n\t            return Math.round((red - 8) / 247 * 24) + 232;\n\t          }\n\n\t          return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);\n\t        },\n\t        enumerable: false\n\t      },\n\t      hexToRgb: {\n\t        value: hex => {\n\t          const matches = /(?<colorString>[a-f\\d]{6}|[a-f\\d]{3})/i.exec(hex.toString(16));\n\n\t          if (!matches) {\n\t            return [0, 0, 0];\n\t          }\n\n\t          let {\n\t            colorString\n\t          } = matches.groups;\n\n\t          if (colorString.length === 3) {\n\t            colorString = colorString.split('').map(character => character + character).join('');\n\t          }\n\n\t          const integer = Number.parseInt(colorString, 16);\n\t          return [integer >> 16 & 0xFF, integer >> 8 & 0xFF, integer & 0xFF];\n\t        },\n\t        enumerable: false\n\t      },\n\t      hexToAnsi256: {\n\t        value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),\n\t        enumerable: false\n\t      }\n\t    });\n\t    return styles;\n\t  } // Make the export immutable\n\n\n\t  Object.defineProperty(module, 'exports', {\n\t    enumerable: true,\n\t    get: assembleStyles\n\t  });\n\t})(ansiStyles);\n\n\tvar collections = {};\n\n\tObject.defineProperty(collections, '__esModule', {\n\t  value: true\n\t});\n\tcollections.printIteratorEntries = printIteratorEntries;\n\tcollections.printIteratorValues = printIteratorValues;\n\tcollections.printListItems = printListItems;\n\tcollections.printObjectProperties = printObjectProperties;\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t *\n\t */\n\n\tconst getKeysOfEnumerableProperties = (object, compareKeys) => {\n\t  const keys = Object.keys(object).sort(compareKeys);\n\n\t  if (Object.getOwnPropertySymbols) {\n\t    Object.getOwnPropertySymbols(object).forEach(symbol => {\n\t      if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) {\n\t        keys.push(symbol);\n\t      }\n\t    });\n\t  }\n\n\t  return keys;\n\t};\n\t/**\n\t * Return entries (for example, of a map)\n\t * with spacing, indentation, and comma\n\t * without surrounding punctuation (for example, braces)\n\t */\n\n\n\tfunction printIteratorEntries(iterator, config, indentation, depth, refs, printer, // Too bad, so sad that separator for ECMAScript Map has been ' => '\n\t// What a distracting diff if you change a data structure to/from\n\t// ECMAScript Object or Immutable.Map/OrderedMap which use the default.\n\tseparator) {\n\t  if (separator === void 0) {\n\t    separator = ': ';\n\t  }\n\n\t  let result = '';\n\t  let current = iterator.next();\n\n\t  if (!current.done) {\n\t    result += config.spacingOuter;\n\t    const indentationNext = indentation + config.indent;\n\n\t    while (!current.done) {\n\t      const name = printer(current.value[0], config, indentationNext, depth, refs);\n\t      const value = printer(current.value[1], config, indentationNext, depth, refs);\n\t      result += indentationNext + name + separator + value;\n\t      current = iterator.next();\n\n\t      if (!current.done) {\n\t        result += ',' + config.spacingInner;\n\t      } else if (!config.min) {\n\t        result += ',';\n\t      }\n\t    }\n\n\t    result += config.spacingOuter + indentation;\n\t  }\n\n\t  return result;\n\t}\n\t/**\n\t * Return values (for example, of a set)\n\t * with spacing, indentation, and comma\n\t * without surrounding punctuation (braces or brackets)\n\t */\n\n\n\tfunction printIteratorValues(iterator, config, indentation, depth, refs, printer) {\n\t  let result = '';\n\t  let current = iterator.next();\n\n\t  if (!current.done) {\n\t    result += config.spacingOuter;\n\t    const indentationNext = indentation + config.indent;\n\n\t    while (!current.done) {\n\t      result += indentationNext + printer(current.value, config, indentationNext, depth, refs);\n\t      current = iterator.next();\n\n\t      if (!current.done) {\n\t        result += ',' + config.spacingInner;\n\t      } else if (!config.min) {\n\t        result += ',';\n\t      }\n\t    }\n\n\t    result += config.spacingOuter + indentation;\n\t  }\n\n\t  return result;\n\t}\n\t/**\n\t * Return items (for example, of an array)\n\t * with spacing, indentation, and comma\n\t * without surrounding punctuation (for example, brackets)\n\t **/\n\n\n\tfunction printListItems(list, config, indentation, depth, refs, printer) {\n\t  let result = '';\n\n\t  if (list.length) {\n\t    result += config.spacingOuter;\n\t    const indentationNext = indentation + config.indent;\n\n\t    for (let i = 0; i < list.length; i++) {\n\t      result += indentationNext;\n\n\t      if (i in list) {\n\t        result += printer(list[i], config, indentationNext, depth, refs);\n\t      }\n\n\t      if (i < list.length - 1) {\n\t        result += ',' + config.spacingInner;\n\t      } else if (!config.min) {\n\t        result += ',';\n\t      }\n\t    }\n\n\t    result += config.spacingOuter + indentation;\n\t  }\n\n\t  return result;\n\t}\n\t/**\n\t * Return properties of an object\n\t * with spacing, indentation, and comma\n\t * without surrounding punctuation (for example, braces)\n\t */\n\n\n\tfunction printObjectProperties(val, config, indentation, depth, refs, printer) {\n\t  let result = '';\n\t  const keys = getKeysOfEnumerableProperties(val, config.compareKeys);\n\n\t  if (keys.length) {\n\t    result += config.spacingOuter;\n\t    const indentationNext = indentation + config.indent;\n\n\t    for (let i = 0; i < keys.length; i++) {\n\t      const key = keys[i];\n\t      const name = printer(key, config, indentationNext, depth, refs);\n\t      const value = printer(val[key], config, indentationNext, depth, refs);\n\t      result += indentationNext + name + ': ' + value;\n\n\t      if (i < keys.length - 1) {\n\t        result += ',' + config.spacingInner;\n\t      } else if (!config.min) {\n\t        result += ',';\n\t      }\n\t    }\n\n\t    result += config.spacingOuter + indentation;\n\t  }\n\n\t  return result;\n\t}\n\n\tvar AsymmetricMatcher = {};\n\n\tObject.defineProperty(AsymmetricMatcher, '__esModule', {\n\t  value: true\n\t});\n\tAsymmetricMatcher.test = AsymmetricMatcher.serialize = AsymmetricMatcher.default = void 0;\n\tvar _collections$3 = collections;\n\n\tvar global$1 = function () {\n\t  if (typeof globalThis !== 'undefined') {\n\t    return globalThis;\n\t  } else if (typeof global$1 !== 'undefined') {\n\t    return global$1;\n\t  } else if (typeof self !== 'undefined') {\n\t    return self;\n\t  } else if (typeof window !== 'undefined') {\n\t    return window;\n\t  } else {\n\t    return Function('return this')();\n\t  }\n\t}();\n\n\tvar Symbol$2 = global$1['jest-symbol-do-not-touch'] || global$1.Symbol;\n\tconst asymmetricMatcher = typeof Symbol$2 === 'function' && Symbol$2.for ? Symbol$2.for('jest.asymmetricMatcher') : 0x1357a5;\n\tconst SPACE$2 = ' ';\n\n\tconst serialize$6 = (val, config, indentation, depth, refs, printer) => {\n\t  const stringedValue = val.toString();\n\n\t  if (stringedValue === 'ArrayContaining' || stringedValue === 'ArrayNotContaining') {\n\t    if (++depth > config.maxDepth) {\n\t      return '[' + stringedValue + ']';\n\t    }\n\n\t    return stringedValue + SPACE$2 + '[' + (0, _collections$3.printListItems)(val.sample, config, indentation, depth, refs, printer) + ']';\n\t  }\n\n\t  if (stringedValue === 'ObjectContaining' || stringedValue === 'ObjectNotContaining') {\n\t    if (++depth > config.maxDepth) {\n\t      return '[' + stringedValue + ']';\n\t    }\n\n\t    return stringedValue + SPACE$2 + '{' + (0, _collections$3.printObjectProperties)(val.sample, config, indentation, depth, refs, printer) + '}';\n\t  }\n\n\t  if (stringedValue === 'StringMatching' || stringedValue === 'StringNotMatching') {\n\t    return stringedValue + SPACE$2 + printer(val.sample, config, indentation, depth, refs);\n\t  }\n\n\t  if (stringedValue === 'StringContaining' || stringedValue === 'StringNotContaining') {\n\t    return stringedValue + SPACE$2 + printer(val.sample, config, indentation, depth, refs);\n\t  }\n\n\t  return val.toAsymmetricMatcher();\n\t};\n\n\tAsymmetricMatcher.serialize = serialize$6;\n\n\tconst test$6 = val => val && val.$$typeof === asymmetricMatcher;\n\n\tAsymmetricMatcher.test = test$6;\n\tconst plugin$6 = {\n\t  serialize: serialize$6,\n\t  test: test$6\n\t};\n\tvar _default$2k = plugin$6;\n\tAsymmetricMatcher.default = _default$2k;\n\n\tvar ConvertAnsi = {};\n\n\tvar ansiRegex = function (_temp) {\n\t  let {\n\t    onlyFirst = false\n\t  } = _temp === void 0 ? {} : _temp;\n\t  const pattern = ['[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)', '(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))'].join('|');\n\t  return new RegExp(pattern, onlyFirst ? undefined : 'g');\n\t};\n\n\tObject.defineProperty(ConvertAnsi, '__esModule', {\n\t  value: true\n\t});\n\tConvertAnsi.test = ConvertAnsi.serialize = ConvertAnsi.default = void 0;\n\n\tvar _ansiRegex = _interopRequireDefault$9(ansiRegex);\n\n\tvar _ansiStyles$1 = _interopRequireDefault$9(ansiStyles.exports);\n\n\tfunction _interopRequireDefault$9(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\n\tconst toHumanReadableAnsi = text => text.replace((0, _ansiRegex.default)(), match => {\n\t  switch (match) {\n\t    case _ansiStyles$1.default.red.close:\n\t    case _ansiStyles$1.default.green.close:\n\t    case _ansiStyles$1.default.cyan.close:\n\t    case _ansiStyles$1.default.gray.close:\n\t    case _ansiStyles$1.default.white.close:\n\t    case _ansiStyles$1.default.yellow.close:\n\t    case _ansiStyles$1.default.bgRed.close:\n\t    case _ansiStyles$1.default.bgGreen.close:\n\t    case _ansiStyles$1.default.bgYellow.close:\n\t    case _ansiStyles$1.default.inverse.close:\n\t    case _ansiStyles$1.default.dim.close:\n\t    case _ansiStyles$1.default.bold.close:\n\t    case _ansiStyles$1.default.reset.open:\n\t    case _ansiStyles$1.default.reset.close:\n\t      return '</>';\n\n\t    case _ansiStyles$1.default.red.open:\n\t      return '<red>';\n\n\t    case _ansiStyles$1.default.green.open:\n\t      return '<green>';\n\n\t    case _ansiStyles$1.default.cyan.open:\n\t      return '<cyan>';\n\n\t    case _ansiStyles$1.default.gray.open:\n\t      return '<gray>';\n\n\t    case _ansiStyles$1.default.white.open:\n\t      return '<white>';\n\n\t    case _ansiStyles$1.default.yellow.open:\n\t      return '<yellow>';\n\n\t    case _ansiStyles$1.default.bgRed.open:\n\t      return '<bgRed>';\n\n\t    case _ansiStyles$1.default.bgGreen.open:\n\t      return '<bgGreen>';\n\n\t    case _ansiStyles$1.default.bgYellow.open:\n\t      return '<bgYellow>';\n\n\t    case _ansiStyles$1.default.inverse.open:\n\t      return '<inverse>';\n\n\t    case _ansiStyles$1.default.dim.open:\n\t      return '<dim>';\n\n\t    case _ansiStyles$1.default.bold.open:\n\t      return '<bold>';\n\n\t    default:\n\t      return '';\n\t  }\n\t});\n\n\tconst test$5 = val => typeof val === 'string' && !!val.match((0, _ansiRegex.default)());\n\n\tConvertAnsi.test = test$5;\n\n\tconst serialize$5 = (val, config, indentation, depth, refs, printer) => printer(toHumanReadableAnsi(val), config, indentation, depth, refs);\n\n\tConvertAnsi.serialize = serialize$5;\n\tconst plugin$5 = {\n\t  serialize: serialize$5,\n\t  test: test$5\n\t};\n\tvar _default$2j = plugin$5;\n\tConvertAnsi.default = _default$2j;\n\n\tvar DOMCollection$1 = {};\n\n\tObject.defineProperty(DOMCollection$1, '__esModule', {\n\t  value: true\n\t});\n\tDOMCollection$1.test = DOMCollection$1.serialize = DOMCollection$1.default = void 0;\n\tvar _collections$2 = collections;\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\t/* eslint-disable local/ban-types-eventually */\n\n\tconst SPACE$1 = ' ';\n\tconst OBJECT_NAMES = ['DOMStringMap', 'NamedNodeMap'];\n\tconst ARRAY_REGEXP = /^(HTML\\w*Collection|NodeList)$/;\n\n\tconst testName = name => OBJECT_NAMES.indexOf(name) !== -1 || ARRAY_REGEXP.test(name);\n\n\tconst test$4 = val => val && val.constructor && !!val.constructor.name && testName(val.constructor.name);\n\n\tDOMCollection$1.test = test$4;\n\n\tconst isNamedNodeMap = collection => collection.constructor.name === 'NamedNodeMap';\n\n\tconst serialize$4 = (collection, config, indentation, depth, refs, printer) => {\n\t  const name = collection.constructor.name;\n\n\t  if (++depth > config.maxDepth) {\n\t    return '[' + name + ']';\n\t  }\n\n\t  return (config.min ? '' : name + SPACE$1) + (OBJECT_NAMES.indexOf(name) !== -1 ? '{' + (0, _collections$2.printObjectProperties)(isNamedNodeMap(collection) ? Array.from(collection).reduce((props, attribute) => {\n\t    props[attribute.name] = attribute.value;\n\t    return props;\n\t  }, {}) : { ...collection\n\t  }, config, indentation, depth, refs, printer) + '}' : '[' + (0, _collections$2.printListItems)(Array.from(collection), config, indentation, depth, refs, printer) + ']');\n\t};\n\n\tDOMCollection$1.serialize = serialize$4;\n\tconst plugin$4 = {\n\t  serialize: serialize$4,\n\t  test: test$4\n\t};\n\tvar _default$2i = plugin$4;\n\tDOMCollection$1.default = _default$2i;\n\n\tvar DOMElement = {};\n\n\tvar markup = {};\n\n\tvar escapeHTML$2 = {};\n\n\tObject.defineProperty(escapeHTML$2, '__esModule', {\n\t  value: true\n\t});\n\n\tescapeHTML$2.default = escapeHTML$1;\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\n\tfunction escapeHTML$1(str) {\n\t  return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\t}\n\n\tObject.defineProperty(markup, '__esModule', {\n\t  value: true\n\t});\n\tmarkup.printText = markup.printProps = markup.printElementAsLeaf = markup.printElement = markup.printComment = markup.printChildren = void 0;\n\n\tvar _escapeHTML = _interopRequireDefault$8(escapeHTML$2);\n\n\tfunction _interopRequireDefault$8(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\t// Return empty string if keys is empty.\n\n\n\tconst printProps$1 = (keys, props, config, indentation, depth, refs, printer) => {\n\t  const indentationNext = indentation + config.indent;\n\t  const colors = config.colors;\n\t  return keys.map(key => {\n\t    const value = props[key];\n\t    let printed = printer(value, config, indentationNext, depth, refs);\n\n\t    if (typeof value !== 'string') {\n\t      if (printed.indexOf('\\n') !== -1) {\n\t        printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation;\n\t      }\n\n\t      printed = '{' + printed + '}';\n\t    }\n\n\t    return config.spacingInner + indentation + colors.prop.open + key + colors.prop.close + '=' + colors.value.open + printed + colors.value.close;\n\t  }).join('');\n\t}; // Return empty string if children is empty.\n\n\n\tmarkup.printProps = printProps$1;\n\n\tconst printChildren$1 = (children, config, indentation, depth, refs, printer) => children.map(child => config.spacingOuter + indentation + (typeof child === 'string' ? printText$1(child, config) : printer(child, config, indentation, depth, refs))).join('');\n\n\tmarkup.printChildren = printChildren$1;\n\n\tconst printText$1 = (text, config) => {\n\t  const contentColor = config.colors.content;\n\t  return contentColor.open + (0, _escapeHTML.default)(text) + contentColor.close;\n\t};\n\n\tmarkup.printText = printText$1;\n\n\tconst printComment$1 = (comment, config) => {\n\t  const commentColor = config.colors.comment;\n\t  return commentColor.open + '<!--' + (0, _escapeHTML.default)(comment) + '-->' + commentColor.close;\n\t}; // Separate the functions to format props, children, and element,\n\t// so a plugin could override a particular function, if needed.\n\t// Too bad, so sad: the traditional (but unnecessary) space\n\t// in a self-closing tagColor requires a second test of printedProps.\n\n\n\tmarkup.printComment = printComment$1;\n\n\tconst printElement$1 = (type, printedProps, printedChildren, config, indentation) => {\n\t  const tagColor = config.colors.tag;\n\t  return tagColor.open + '<' + type + (printedProps && tagColor.close + printedProps + config.spacingOuter + indentation + tagColor.open) + (printedChildren ? '>' + tagColor.close + printedChildren + config.spacingOuter + indentation + tagColor.open + '</' + type : (printedProps && !config.min ? '' : ' ') + '/') + '>' + tagColor.close;\n\t};\n\n\tmarkup.printElement = printElement$1;\n\n\tconst printElementAsLeaf$1 = (type, config) => {\n\t  const tagColor = config.colors.tag;\n\t  return tagColor.open + '<' + type + tagColor.close + ' …' + tagColor.open + ' />' + tagColor.close;\n\t};\n\n\tmarkup.printElementAsLeaf = printElementAsLeaf$1;\n\n\tObject.defineProperty(DOMElement, '__esModule', {\n\t  value: true\n\t});\n\tDOMElement.test = DOMElement.serialize = DOMElement.default = void 0;\n\tvar _markup$2 = markup;\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\tconst ELEMENT_NODE$2 = 1;\n\tconst TEXT_NODE$2 = 3;\n\tconst COMMENT_NODE$2 = 8;\n\tconst FRAGMENT_NODE$1 = 11;\n\tconst ELEMENT_REGEXP$1 = /^((HTML|SVG)\\w*)?Element$/;\n\n\tconst testHasAttribute = val => {\n\t  try {\n\t    return typeof val.hasAttribute === 'function' && val.hasAttribute('is');\n\t  } catch {\n\t    return false;\n\t  }\n\t};\n\n\tconst testNode$1 = val => {\n\t  const constructorName = val.constructor.name;\n\t  const {\n\t    nodeType,\n\t    tagName\n\t  } = val;\n\t  const isCustomElement = typeof tagName === 'string' && tagName.includes('-') || testHasAttribute(val);\n\t  return nodeType === ELEMENT_NODE$2 && (ELEMENT_REGEXP$1.test(constructorName) || isCustomElement) || nodeType === TEXT_NODE$2 && constructorName === 'Text' || nodeType === COMMENT_NODE$2 && constructorName === 'Comment' || nodeType === FRAGMENT_NODE$1 && constructorName === 'DocumentFragment';\n\t};\n\n\tconst test$3 = val => {\n\t  var _val$constructor;\n\n\t  return (val === null || val === void 0 ? void 0 : (_val$constructor = val.constructor) === null || _val$constructor === void 0 ? void 0 : _val$constructor.name) && testNode$1(val);\n\t};\n\n\tDOMElement.test = test$3;\n\n\tfunction nodeIsText$1(node) {\n\t  return node.nodeType === TEXT_NODE$2;\n\t}\n\n\tfunction nodeIsComment$1(node) {\n\t  return node.nodeType === COMMENT_NODE$2;\n\t}\n\n\tfunction nodeIsFragment$1(node) {\n\t  return node.nodeType === FRAGMENT_NODE$1;\n\t}\n\n\tconst serialize$3 = (node, config, indentation, depth, refs, printer) => {\n\t  if (nodeIsText$1(node)) {\n\t    return (0, _markup$2.printText)(node.data, config);\n\t  }\n\n\t  if (nodeIsComment$1(node)) {\n\t    return (0, _markup$2.printComment)(node.data, config);\n\t  }\n\n\t  const type = nodeIsFragment$1(node) ? 'DocumentFragment' : node.tagName.toLowerCase();\n\n\t  if (++depth > config.maxDepth) {\n\t    return (0, _markup$2.printElementAsLeaf)(type, config);\n\t  }\n\n\t  return (0, _markup$2.printElement)(type, (0, _markup$2.printProps)(nodeIsFragment$1(node) ? [] : Array.from(node.attributes).map(attr => attr.name).sort(), nodeIsFragment$1(node) ? {} : Array.from(node.attributes).reduce((props, attribute) => {\n\t    props[attribute.name] = attribute.value;\n\t    return props;\n\t  }, {}), config, indentation + config.indent, depth, refs, printer), (0, _markup$2.printChildren)(Array.prototype.slice.call(node.childNodes || node.children), config, indentation + config.indent, depth, refs, printer), config, indentation);\n\t};\n\n\tDOMElement.serialize = serialize$3;\n\tconst plugin$3 = {\n\t  serialize: serialize$3,\n\t  test: test$3\n\t};\n\tvar _default$2h = plugin$3;\n\tDOMElement.default = _default$2h;\n\n\tvar Immutable = {};\n\n\tObject.defineProperty(Immutable, '__esModule', {\n\t  value: true\n\t});\n\tImmutable.test = Immutable.serialize = Immutable.default = void 0;\n\tvar _collections$1 = collections;\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\t// SENTINEL constants are from https://github.com/facebook/immutable-js\n\n\tconst IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';\n\tconst IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@';\n\tconst IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@';\n\tconst IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@';\n\tconst IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@';\n\tconst IS_RECORD_SENTINEL = '@@__IMMUTABLE_RECORD__@@'; // immutable v4\n\n\tconst IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@';\n\tconst IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@';\n\tconst IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@';\n\n\tconst getImmutableName = name => 'Immutable.' + name;\n\n\tconst printAsLeaf = name => '[' + name + ']';\n\n\tconst SPACE = ' ';\n\tconst LAZY = '…'; // Seq is lazy if it calls a method like filter\n\n\tconst printImmutableEntries = (val, config, indentation, depth, refs, printer, type) => ++depth > config.maxDepth ? printAsLeaf(getImmutableName(type)) : getImmutableName(type) + SPACE + '{' + (0, _collections$1.printIteratorEntries)(val.entries(), config, indentation, depth, refs, printer) + '}'; // Record has an entries method because it is a collection in immutable v3.\n\t// Return an iterator for Immutable Record from version v3 or v4.\n\n\n\tfunction getRecordEntries(val) {\n\t  let i = 0;\n\t  return {\n\t    next() {\n\t      if (i < val._keys.length) {\n\t        const key = val._keys[i++];\n\t        return {\n\t          done: false,\n\t          value: [key, val.get(key)]\n\t        };\n\t      }\n\n\t      return {\n\t        done: true,\n\t        value: undefined\n\t      };\n\t    }\n\n\t  };\n\t}\n\n\tconst printImmutableRecord = (val, config, indentation, depth, refs, printer) => {\n\t  // _name property is defined only for an Immutable Record instance\n\t  // which was constructed with a second optional descriptive name arg\n\t  const name = getImmutableName(val._name || 'Record');\n\t  return ++depth > config.maxDepth ? printAsLeaf(name) : name + SPACE + '{' + (0, _collections$1.printIteratorEntries)(getRecordEntries(val), config, indentation, depth, refs, printer) + '}';\n\t};\n\n\tconst printImmutableSeq = (val, config, indentation, depth, refs, printer) => {\n\t  const name = getImmutableName('Seq');\n\n\t  if (++depth > config.maxDepth) {\n\t    return printAsLeaf(name);\n\t  }\n\n\t  if (val[IS_KEYED_SENTINEL]) {\n\t    return name + SPACE + '{' + ( // from Immutable collection of entries or from ECMAScript object\n\t    val._iter || val._object ? (0, _collections$1.printIteratorEntries)(val.entries(), config, indentation, depth, refs, printer) : LAZY) + '}';\n\t  }\n\n\t  return name + SPACE + '[' + (val._iter || // from Immutable collection of values\n\t  val._array || // from ECMAScript array\n\t  val._collection || // from ECMAScript collection in immutable v4\n\t  val._iterable // from ECMAScript collection in immutable v3\n\t  ? (0, _collections$1.printIteratorValues)(val.values(), config, indentation, depth, refs, printer) : LAZY) + ']';\n\t};\n\n\tconst printImmutableValues = (val, config, indentation, depth, refs, printer, type) => ++depth > config.maxDepth ? printAsLeaf(getImmutableName(type)) : getImmutableName(type) + SPACE + '[' + (0, _collections$1.printIteratorValues)(val.values(), config, indentation, depth, refs, printer) + ']';\n\n\tconst serialize$2 = (val, config, indentation, depth, refs, printer) => {\n\t  if (val[IS_MAP_SENTINEL]) {\n\t    return printImmutableEntries(val, config, indentation, depth, refs, printer, val[IS_ORDERED_SENTINEL] ? 'OrderedMap' : 'Map');\n\t  }\n\n\t  if (val[IS_LIST_SENTINEL]) {\n\t    return printImmutableValues(val, config, indentation, depth, refs, printer, 'List');\n\t  }\n\n\t  if (val[IS_SET_SENTINEL]) {\n\t    return printImmutableValues(val, config, indentation, depth, refs, printer, val[IS_ORDERED_SENTINEL] ? 'OrderedSet' : 'Set');\n\t  }\n\n\t  if (val[IS_STACK_SENTINEL]) {\n\t    return printImmutableValues(val, config, indentation, depth, refs, printer, 'Stack');\n\t  }\n\n\t  if (val[IS_SEQ_SENTINEL]) {\n\t    return printImmutableSeq(val, config, indentation, depth, refs, printer);\n\t  } // For compatibility with immutable v3 and v4, let record be the default.\n\n\n\t  return printImmutableRecord(val, config, indentation, depth, refs, printer);\n\t}; // Explicitly comparing sentinel properties to true avoids false positive\n\t// when mock identity-obj-proxy returns the key as the value for any key.\n\n\n\tImmutable.serialize = serialize$2;\n\n\tconst test$2 = val => val && (val[IS_ITERABLE_SENTINEL] === true || val[IS_RECORD_SENTINEL] === true);\n\n\tImmutable.test = test$2;\n\tconst plugin$2 = {\n\t  serialize: serialize$2,\n\t  test: test$2\n\t};\n\tvar _default$2g = plugin$2;\n\tImmutable.default = _default$2g;\n\n\tvar ReactElement = {};\n\n\tvar reactIs = {exports: {}};\n\n\t/** @license React v17.0.2\n\t * react-is.production.min.js\n\t *\n\t * Copyright (c) Facebook, Inc. and its affiliates.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\tif (\"function\" === typeof Symbol && Symbol.for) {\n\t  var x = Symbol.for;\n\t  x(\"react.element\");\n\t  x(\"react.portal\");\n\t  x(\"react.fragment\");\n\t  x(\"react.strict_mode\");\n\t  x(\"react.profiler\");\n\t  x(\"react.provider\");\n\t  x(\"react.context\");\n\t  x(\"react.forward_ref\");\n\t  x(\"react.suspense\");\n\t  x(\"react.suspense_list\");\n\t  x(\"react.memo\");\n\t  x(\"react.lazy\");\n\t  x(\"react.block\");\n\t  x(\"react.server.block\");\n\t  x(\"react.fundamental\");\n\t  x(\"react.debug_trace_mode\");\n\t  x(\"react.legacy_hidden\");\n\t}\n\n\tvar reactIs_development = {};\n\n\t/** @license React v17.0.2\n\t * react-is.development.js\n\t *\n\t * Copyright (c) Facebook, Inc. and its affiliates.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\t{\n\t  (function () {\n\t    // When adding new symbols to this file,\n\t    // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'\n\t    // The Symbol used to tag the ReactElement-like types. If there is no native Symbol\n\t    // nor polyfill, then a plain number is used for performance.\n\n\t    var REACT_ELEMENT_TYPE = 0xeac7;\n\t    var REACT_PORTAL_TYPE = 0xeaca;\n\t    var REACT_FRAGMENT_TYPE = 0xeacb;\n\t    var REACT_STRICT_MODE_TYPE = 0xeacc;\n\t    var REACT_PROFILER_TYPE = 0xead2;\n\t    var REACT_PROVIDER_TYPE = 0xeacd;\n\t    var REACT_CONTEXT_TYPE = 0xeace;\n\t    var REACT_FORWARD_REF_TYPE = 0xead0;\n\t    var REACT_SUSPENSE_TYPE = 0xead1;\n\t    var REACT_SUSPENSE_LIST_TYPE = 0xead8;\n\t    var REACT_MEMO_TYPE = 0xead3;\n\t    var REACT_LAZY_TYPE = 0xead4;\n\t    var REACT_BLOCK_TYPE = 0xead9;\n\t    var REACT_SERVER_BLOCK_TYPE = 0xeada;\n\t    var REACT_FUNDAMENTAL_TYPE = 0xead5;\n\t    var REACT_DEBUG_TRACING_MODE_TYPE = 0xeae1;\n\t    var REACT_LEGACY_HIDDEN_TYPE = 0xeae3;\n\n\t    if (typeof Symbol === 'function' && Symbol.for) {\n\t      var symbolFor = Symbol.for;\n\t      REACT_ELEMENT_TYPE = symbolFor('react.element');\n\t      REACT_PORTAL_TYPE = symbolFor('react.portal');\n\t      REACT_FRAGMENT_TYPE = symbolFor('react.fragment');\n\t      REACT_STRICT_MODE_TYPE = symbolFor('react.strict_mode');\n\t      REACT_PROFILER_TYPE = symbolFor('react.profiler');\n\t      REACT_PROVIDER_TYPE = symbolFor('react.provider');\n\t      REACT_CONTEXT_TYPE = symbolFor('react.context');\n\t      REACT_FORWARD_REF_TYPE = symbolFor('react.forward_ref');\n\t      REACT_SUSPENSE_TYPE = symbolFor('react.suspense');\n\t      REACT_SUSPENSE_LIST_TYPE = symbolFor('react.suspense_list');\n\t      REACT_MEMO_TYPE = symbolFor('react.memo');\n\t      REACT_LAZY_TYPE = symbolFor('react.lazy');\n\t      REACT_BLOCK_TYPE = symbolFor('react.block');\n\t      REACT_SERVER_BLOCK_TYPE = symbolFor('react.server.block');\n\t      REACT_FUNDAMENTAL_TYPE = symbolFor('react.fundamental');\n\t      symbolFor('react.scope');\n\t      symbolFor('react.opaque.id');\n\t      REACT_DEBUG_TRACING_MODE_TYPE = symbolFor('react.debug_trace_mode');\n\t      symbolFor('react.offscreen');\n\t      REACT_LEGACY_HIDDEN_TYPE = symbolFor('react.legacy_hidden');\n\t    } // Filter certain DOM attributes (e.g. src, href) if their values are empty strings.\n\n\n\t    var enableScopeAPI = false; // Experimental Create Event Handle API.\n\n\t    function isValidElementType(type) {\n\t      if (typeof type === 'string' || typeof type === 'function') {\n\t        return true;\n\t      } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).\n\n\n\t      if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || type === REACT_DEBUG_TRACING_MODE_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || enableScopeAPI) {\n\t        return true;\n\t      }\n\n\t      if (typeof type === 'object' && type !== null) {\n\t        if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE) {\n\t          return true;\n\t        }\n\t      }\n\n\t      return false;\n\t    }\n\n\t    function typeOf(object) {\n\t      if (typeof object === 'object' && object !== null) {\n\t        var $$typeof = object.$$typeof;\n\n\t        switch ($$typeof) {\n\t          case REACT_ELEMENT_TYPE:\n\t            var type = object.type;\n\n\t            switch (type) {\n\t              case REACT_FRAGMENT_TYPE:\n\t              case REACT_PROFILER_TYPE:\n\t              case REACT_STRICT_MODE_TYPE:\n\t              case REACT_SUSPENSE_TYPE:\n\t              case REACT_SUSPENSE_LIST_TYPE:\n\t                return type;\n\n\t              default:\n\t                var $$typeofType = type && type.$$typeof;\n\n\t                switch ($$typeofType) {\n\t                  case REACT_CONTEXT_TYPE:\n\t                  case REACT_FORWARD_REF_TYPE:\n\t                  case REACT_LAZY_TYPE:\n\t                  case REACT_MEMO_TYPE:\n\t                  case REACT_PROVIDER_TYPE:\n\t                    return $$typeofType;\n\n\t                  default:\n\t                    return $$typeof;\n\t                }\n\n\t            }\n\n\t          case REACT_PORTAL_TYPE:\n\t            return $$typeof;\n\t        }\n\t      }\n\n\t      return undefined;\n\t    }\n\n\t    var ContextConsumer = REACT_CONTEXT_TYPE;\n\t    var ContextProvider = REACT_PROVIDER_TYPE;\n\t    var Element = REACT_ELEMENT_TYPE;\n\t    var ForwardRef = REACT_FORWARD_REF_TYPE;\n\t    var Fragment = REACT_FRAGMENT_TYPE;\n\t    var Lazy = REACT_LAZY_TYPE;\n\t    var Memo = REACT_MEMO_TYPE;\n\t    var Portal = REACT_PORTAL_TYPE;\n\t    var Profiler = REACT_PROFILER_TYPE;\n\t    var StrictMode = REACT_STRICT_MODE_TYPE;\n\t    var Suspense = REACT_SUSPENSE_TYPE;\n\t    var hasWarnedAboutDeprecatedIsAsyncMode = false;\n\t    var hasWarnedAboutDeprecatedIsConcurrentMode = false; // AsyncMode should be deprecated\n\n\t    function isAsyncMode(object) {\n\t      {\n\t        if (!hasWarnedAboutDeprecatedIsAsyncMode) {\n\t          hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint\n\n\t          console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 18+.');\n\t        }\n\t      }\n\t      return false;\n\t    }\n\n\t    function isConcurrentMode(object) {\n\t      {\n\t        if (!hasWarnedAboutDeprecatedIsConcurrentMode) {\n\t          hasWarnedAboutDeprecatedIsConcurrentMode = true; // Using console['warn'] to evade Babel and ESLint\n\n\t          console['warn']('The ReactIs.isConcurrentMode() alias has been deprecated, ' + 'and will be removed in React 18+.');\n\t        }\n\t      }\n\t      return false;\n\t    }\n\n\t    function isContextConsumer(object) {\n\t      return typeOf(object) === REACT_CONTEXT_TYPE;\n\t    }\n\n\t    function isContextProvider(object) {\n\t      return typeOf(object) === REACT_PROVIDER_TYPE;\n\t    }\n\n\t    function isElement(object) {\n\t      return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;\n\t    }\n\n\t    function isForwardRef(object) {\n\t      return typeOf(object) === REACT_FORWARD_REF_TYPE;\n\t    }\n\n\t    function isFragment(object) {\n\t      return typeOf(object) === REACT_FRAGMENT_TYPE;\n\t    }\n\n\t    function isLazy(object) {\n\t      return typeOf(object) === REACT_LAZY_TYPE;\n\t    }\n\n\t    function isMemo(object) {\n\t      return typeOf(object) === REACT_MEMO_TYPE;\n\t    }\n\n\t    function isPortal(object) {\n\t      return typeOf(object) === REACT_PORTAL_TYPE;\n\t    }\n\n\t    function isProfiler(object) {\n\t      return typeOf(object) === REACT_PROFILER_TYPE;\n\t    }\n\n\t    function isStrictMode(object) {\n\t      return typeOf(object) === REACT_STRICT_MODE_TYPE;\n\t    }\n\n\t    function isSuspense(object) {\n\t      return typeOf(object) === REACT_SUSPENSE_TYPE;\n\t    }\n\n\t    reactIs_development.ContextConsumer = ContextConsumer;\n\t    reactIs_development.ContextProvider = ContextProvider;\n\t    reactIs_development.Element = Element;\n\t    reactIs_development.ForwardRef = ForwardRef;\n\t    reactIs_development.Fragment = Fragment;\n\t    reactIs_development.Lazy = Lazy;\n\t    reactIs_development.Memo = Memo;\n\t    reactIs_development.Portal = Portal;\n\t    reactIs_development.Profiler = Profiler;\n\t    reactIs_development.StrictMode = StrictMode;\n\t    reactIs_development.Suspense = Suspense;\n\t    reactIs_development.isAsyncMode = isAsyncMode;\n\t    reactIs_development.isConcurrentMode = isConcurrentMode;\n\t    reactIs_development.isContextConsumer = isContextConsumer;\n\t    reactIs_development.isContextProvider = isContextProvider;\n\t    reactIs_development.isElement = isElement;\n\t    reactIs_development.isForwardRef = isForwardRef;\n\t    reactIs_development.isFragment = isFragment;\n\t    reactIs_development.isLazy = isLazy;\n\t    reactIs_development.isMemo = isMemo;\n\t    reactIs_development.isPortal = isPortal;\n\t    reactIs_development.isProfiler = isProfiler;\n\t    reactIs_development.isStrictMode = isStrictMode;\n\t    reactIs_development.isSuspense = isSuspense;\n\t    reactIs_development.isValidElementType = isValidElementType;\n\t    reactIs_development.typeOf = typeOf;\n\t  })();\n\t}\n\n\t{\n\t  reactIs.exports = reactIs_development;\n\t}\n\n\tObject.defineProperty(ReactElement, '__esModule', {\n\t  value: true\n\t});\n\tReactElement.test = ReactElement.serialize = ReactElement.default = void 0;\n\n\tvar ReactIs = _interopRequireWildcard(reactIs.exports);\n\n\tvar _markup$1 = markup;\n\n\tfunction _getRequireWildcardCache(nodeInterop) {\n\t  if (typeof WeakMap !== 'function') return null;\n\t  var cacheBabelInterop = new WeakMap();\n\t  var cacheNodeInterop = new WeakMap();\n\t  return (_getRequireWildcardCache = function (nodeInterop) {\n\t    return nodeInterop ? cacheNodeInterop : cacheBabelInterop;\n\t  })(nodeInterop);\n\t}\n\n\tfunction _interopRequireWildcard(obj, nodeInterop) {\n\t  if (!nodeInterop && obj && obj.__esModule) {\n\t    return obj;\n\t  }\n\n\t  if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') {\n\t    return {\n\t      default: obj\n\t    };\n\t  }\n\n\t  var cache = _getRequireWildcardCache(nodeInterop);\n\n\t  if (cache && cache.has(obj)) {\n\t    return cache.get(obj);\n\t  }\n\n\t  var newObj = {};\n\t  var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;\n\n\t  for (var key in obj) {\n\t    if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {\n\t      var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;\n\n\t      if (desc && (desc.get || desc.set)) {\n\t        Object.defineProperty(newObj, key, desc);\n\t      } else {\n\t        newObj[key] = obj[key];\n\t      }\n\t    }\n\t  }\n\n\t  newObj.default = obj;\n\n\t  if (cache) {\n\t    cache.set(obj, newObj);\n\t  }\n\n\t  return newObj;\n\t}\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\t// Given element.props.children, or subtree during recursive traversal,\n\t// return flattened array of children.\n\n\n\tconst getChildren = function (arg, children) {\n\t  if (children === void 0) {\n\t    children = [];\n\t  }\n\n\t  if (Array.isArray(arg)) {\n\t    arg.forEach(item => {\n\t      getChildren(item, children);\n\t    });\n\t  } else if (arg != null && arg !== false) {\n\t    children.push(arg);\n\t  }\n\n\t  return children;\n\t};\n\n\tconst getType = element => {\n\t  const type = element.type;\n\n\t  if (typeof type === 'string') {\n\t    return type;\n\t  }\n\n\t  if (typeof type === 'function') {\n\t    return type.displayName || type.name || 'Unknown';\n\t  }\n\n\t  if (ReactIs.isFragment(element)) {\n\t    return 'React.Fragment';\n\t  }\n\n\t  if (ReactIs.isSuspense(element)) {\n\t    return 'React.Suspense';\n\t  }\n\n\t  if (typeof type === 'object' && type !== null) {\n\t    if (ReactIs.isContextProvider(element)) {\n\t      return 'Context.Provider';\n\t    }\n\n\t    if (ReactIs.isContextConsumer(element)) {\n\t      return 'Context.Consumer';\n\t    }\n\n\t    if (ReactIs.isForwardRef(element)) {\n\t      if (type.displayName) {\n\t        return type.displayName;\n\t      }\n\n\t      const functionName = type.render.displayName || type.render.name || '';\n\t      return functionName !== '' ? 'ForwardRef(' + functionName + ')' : 'ForwardRef';\n\t    }\n\n\t    if (ReactIs.isMemo(element)) {\n\t      const functionName = type.displayName || type.type.displayName || type.type.name || '';\n\t      return functionName !== '' ? 'Memo(' + functionName + ')' : 'Memo';\n\t    }\n\t  }\n\n\t  return 'UNDEFINED';\n\t};\n\n\tconst getPropKeys$1 = element => {\n\t  const {\n\t    props\n\t  } = element;\n\t  return Object.keys(props).filter(key => key !== 'children' && props[key] !== undefined).sort();\n\t};\n\n\tconst serialize$1 = (element, config, indentation, depth, refs, printer) => ++depth > config.maxDepth ? (0, _markup$1.printElementAsLeaf)(getType(element), config) : (0, _markup$1.printElement)(getType(element), (0, _markup$1.printProps)(getPropKeys$1(element), element.props, config, indentation + config.indent, depth, refs, printer), (0, _markup$1.printChildren)(getChildren(element.props.children), config, indentation + config.indent, depth, refs, printer), config, indentation);\n\n\tReactElement.serialize = serialize$1;\n\n\tconst test$1 = val => val != null && ReactIs.isElement(val);\n\n\tReactElement.test = test$1;\n\tconst plugin$1 = {\n\t  serialize: serialize$1,\n\t  test: test$1\n\t};\n\tvar _default$2f = plugin$1;\n\tReactElement.default = _default$2f;\n\n\tvar ReactTestComponent = {};\n\n\tObject.defineProperty(ReactTestComponent, '__esModule', {\n\t  value: true\n\t});\n\tReactTestComponent.test = ReactTestComponent.serialize = ReactTestComponent.default = void 0;\n\tvar _markup = markup;\n\n\tvar global = function () {\n\t  if (typeof globalThis !== 'undefined') {\n\t    return globalThis;\n\t  } else if (typeof global !== 'undefined') {\n\t    return global;\n\t  } else if (typeof self !== 'undefined') {\n\t    return self;\n\t  } else if (typeof window !== 'undefined') {\n\t    return window;\n\t  } else {\n\t    return Function('return this')();\n\t  }\n\t}();\n\n\tvar Symbol$1 = global['jest-symbol-do-not-touch'] || global.Symbol;\n\tconst testSymbol = typeof Symbol$1 === 'function' && Symbol$1.for ? Symbol$1.for('react.test.json') : 0xea71357;\n\n\tconst getPropKeys = object => {\n\t  const {\n\t    props\n\t  } = object;\n\t  return props ? Object.keys(props).filter(key => props[key] !== undefined).sort() : [];\n\t};\n\n\tconst serialize = (object, config, indentation, depth, refs, printer) => ++depth > config.maxDepth ? (0, _markup.printElementAsLeaf)(object.type, config) : (0, _markup.printElement)(object.type, object.props ? (0, _markup.printProps)(getPropKeys(object), object.props, config, indentation + config.indent, depth, refs, printer) : '', object.children ? (0, _markup.printChildren)(object.children, config, indentation + config.indent, depth, refs, printer) : '', config, indentation);\n\n\tReactTestComponent.serialize = serialize;\n\n\tconst test = val => val && val.$$typeof === testSymbol;\n\n\tReactTestComponent.test = test;\n\tconst plugin = {\n\t  serialize,\n\t  test\n\t};\n\tvar _default$2e = plugin;\n\tReactTestComponent.default = _default$2e;\n\n\tObject.defineProperty(build, '__esModule', {\n\t  value: true\n\t});\n\tvar default_1 = build.default = DEFAULT_OPTIONS_1 = build.DEFAULT_OPTIONS = void 0;\n\tvar format_1 = build.format = format;\n\tvar plugins_1 = build.plugins = void 0;\n\n\tvar _ansiStyles = _interopRequireDefault$7(ansiStyles.exports);\n\n\tvar _collections = collections;\n\n\tvar _AsymmetricMatcher = _interopRequireDefault$7(AsymmetricMatcher);\n\n\tvar _ConvertAnsi = _interopRequireDefault$7(ConvertAnsi);\n\n\tvar _DOMCollection = _interopRequireDefault$7(DOMCollection$1);\n\n\tvar _DOMElement = _interopRequireDefault$7(DOMElement);\n\n\tvar _Immutable = _interopRequireDefault$7(Immutable);\n\n\tvar _ReactElement = _interopRequireDefault$7(ReactElement);\n\n\tvar _ReactTestComponent = _interopRequireDefault$7(ReactTestComponent);\n\n\tfunction _interopRequireDefault$7(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\t/**\n\t * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n\t *\n\t * This source code is licensed under the MIT license found in the\n\t * LICENSE file in the root directory of this source tree.\n\t */\n\n\t/* eslint-disable local/ban-types-eventually */\n\n\n\tconst toString = Object.prototype.toString;\n\tconst toISOString = Date.prototype.toISOString;\n\tconst errorToString = Error.prototype.toString;\n\tconst regExpToString = RegExp.prototype.toString;\n\t/**\n\t * Explicitly comparing typeof constructor to function avoids undefined as name\n\t * when mock identity-obj-proxy returns the key as the value for any key.\n\t */\n\n\tconst getConstructorName = val => typeof val.constructor === 'function' && val.constructor.name || 'Object';\n\t/* global window */\n\n\t/** Is val is equal to global window object? Works even if it does not exist :) */\n\n\n\tconst isWindow = val => typeof window !== 'undefined' && val === window;\n\n\tconst SYMBOL_REGEXP = /^Symbol\\((.*)\\)(.*)$/;\n\tconst NEWLINE_REGEXP = /\\n/gi;\n\n\tclass PrettyFormatPluginError extends Error {\n\t  constructor(message, stack) {\n\t    super(message);\n\t    this.stack = stack;\n\t    this.name = this.constructor.name;\n\t  }\n\n\t}\n\n\tfunction isToStringedArrayType(toStringed) {\n\t  return toStringed === '[object Array]' || toStringed === '[object ArrayBuffer]' || toStringed === '[object DataView]' || toStringed === '[object Float32Array]' || toStringed === '[object Float64Array]' || toStringed === '[object Int8Array]' || toStringed === '[object Int16Array]' || toStringed === '[object Int32Array]' || toStringed === '[object Uint8Array]' || toStringed === '[object Uint8ClampedArray]' || toStringed === '[object Uint16Array]' || toStringed === '[object Uint32Array]';\n\t}\n\n\tfunction printNumber(val) {\n\t  return Object.is(val, -0) ? '-0' : String(val);\n\t}\n\n\tfunction printBigInt(val) {\n\t  return String(val + \"n\");\n\t}\n\n\tfunction printFunction(val, printFunctionName) {\n\t  if (!printFunctionName) {\n\t    return '[Function]';\n\t  }\n\n\t  return '[Function ' + (val.name || 'anonymous') + ']';\n\t}\n\n\tfunction printSymbol(val) {\n\t  return String(val).replace(SYMBOL_REGEXP, 'Symbol($1)');\n\t}\n\n\tfunction printError(val) {\n\t  return '[' + errorToString.call(val) + ']';\n\t}\n\t/**\n\t * The first port of call for printing an object, handles most of the\n\t * data-types in JS.\n\t */\n\n\n\tfunction printBasicValue(val, printFunctionName, escapeRegex, escapeString) {\n\t  if (val === true || val === false) {\n\t    return '' + val;\n\t  }\n\n\t  if (val === undefined) {\n\t    return 'undefined';\n\t  }\n\n\t  if (val === null) {\n\t    return 'null';\n\t  }\n\n\t  const typeOf = typeof val;\n\n\t  if (typeOf === 'number') {\n\t    return printNumber(val);\n\t  }\n\n\t  if (typeOf === 'bigint') {\n\t    return printBigInt(val);\n\t  }\n\n\t  if (typeOf === 'string') {\n\t    if (escapeString) {\n\t      return '\"' + val.replace(/\"|\\\\/g, '\\\\$&') + '\"';\n\t    }\n\n\t    return '\"' + val + '\"';\n\t  }\n\n\t  if (typeOf === 'function') {\n\t    return printFunction(val, printFunctionName);\n\t  }\n\n\t  if (typeOf === 'symbol') {\n\t    return printSymbol(val);\n\t  }\n\n\t  const toStringed = toString.call(val);\n\n\t  if (toStringed === '[object WeakMap]') {\n\t    return 'WeakMap {}';\n\t  }\n\n\t  if (toStringed === '[object WeakSet]') {\n\t    return 'WeakSet {}';\n\t  }\n\n\t  if (toStringed === '[object Function]' || toStringed === '[object GeneratorFunction]') {\n\t    return printFunction(val, printFunctionName);\n\t  }\n\n\t  if (toStringed === '[object Symbol]') {\n\t    return printSymbol(val);\n\t  }\n\n\t  if (toStringed === '[object Date]') {\n\t    return isNaN(+val) ? 'Date { NaN }' : toISOString.call(val);\n\t  }\n\n\t  if (toStringed === '[object Error]') {\n\t    return printError(val);\n\t  }\n\n\t  if (toStringed === '[object RegExp]') {\n\t    if (escapeRegex) {\n\t      // https://github.com/benjamingr/RegExp.escape/blob/main/polyfill.js\n\t      return regExpToString.call(val).replace(/[\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n\t    }\n\n\t    return regExpToString.call(val);\n\t  }\n\n\t  if (val instanceof Error) {\n\t    return printError(val);\n\t  }\n\n\t  return null;\n\t}\n\t/**\n\t * Handles more complex objects ( such as objects with circular references.\n\t * maps and sets etc )\n\t */\n\n\n\tfunction printComplexValue(val, config, indentation, depth, refs, hasCalledToJSON) {\n\t  if (refs.indexOf(val) !== -1) {\n\t    return '[Circular]';\n\t  }\n\n\t  refs = refs.slice();\n\t  refs.push(val);\n\t  const hitMaxDepth = ++depth > config.maxDepth;\n\t  const min = config.min;\n\n\t  if (config.callToJSON && !hitMaxDepth && val.toJSON && typeof val.toJSON === 'function' && !hasCalledToJSON) {\n\t    return printer(val.toJSON(), config, indentation, depth, refs, true);\n\t  }\n\n\t  const toStringed = toString.call(val);\n\n\t  if (toStringed === '[object Arguments]') {\n\t    return hitMaxDepth ? '[Arguments]' : (min ? '' : 'Arguments ') + '[' + (0, _collections.printListItems)(val, config, indentation, depth, refs, printer) + ']';\n\t  }\n\n\t  if (isToStringedArrayType(toStringed)) {\n\t    return hitMaxDepth ? '[' + val.constructor.name + ']' : (min ? '' : !config.printBasicPrototype && val.constructor.name === 'Array' ? '' : val.constructor.name + ' ') + '[' + (0, _collections.printListItems)(val, config, indentation, depth, refs, printer) + ']';\n\t  }\n\n\t  if (toStringed === '[object Map]') {\n\t    return hitMaxDepth ? '[Map]' : 'Map {' + (0, _collections.printIteratorEntries)(val.entries(), config, indentation, depth, refs, printer, ' => ') + '}';\n\t  }\n\n\t  if (toStringed === '[object Set]') {\n\t    return hitMaxDepth ? '[Set]' : 'Set {' + (0, _collections.printIteratorValues)(val.values(), config, indentation, depth, refs, printer) + '}';\n\t  } // Avoid failure to serialize global window object in jsdom test environment.\n\t  // For example, not even relevant if window is prop of React element.\n\n\n\t  return hitMaxDepth || isWindow(val) ? '[' + getConstructorName(val) + ']' : (min ? '' : !config.printBasicPrototype && getConstructorName(val) === 'Object' ? '' : getConstructorName(val) + ' ') + '{' + (0, _collections.printObjectProperties)(val, config, indentation, depth, refs, printer) + '}';\n\t}\n\n\tfunction isNewPlugin(plugin) {\n\t  return plugin.serialize != null;\n\t}\n\n\tfunction printPlugin(plugin, val, config, indentation, depth, refs) {\n\t  let printed;\n\n\t  try {\n\t    printed = isNewPlugin(plugin) ? plugin.serialize(val, config, indentation, depth, refs, printer) : plugin.print(val, valChild => printer(valChild, config, indentation, depth, refs), str => {\n\t      const indentationNext = indentation + config.indent;\n\t      return indentationNext + str.replace(NEWLINE_REGEXP, '\\n' + indentationNext);\n\t    }, {\n\t      edgeSpacing: config.spacingOuter,\n\t      min: config.min,\n\t      spacing: config.spacingInner\n\t    }, config.colors);\n\t  } catch (error) {\n\t    throw new PrettyFormatPluginError(error.message, error.stack);\n\t  }\n\n\t  if (typeof printed !== 'string') {\n\t    throw new Error(\"pretty-format: Plugin must return type \\\"string\\\" but instead returned \\\"\" + typeof printed + \"\\\".\");\n\t  }\n\n\t  return printed;\n\t}\n\n\tfunction findPlugin(plugins, val) {\n\t  for (let p = 0; p < plugins.length; p++) {\n\t    try {\n\t      if (plugins[p].test(val)) {\n\t        return plugins[p];\n\t      }\n\t    } catch (error) {\n\t      throw new PrettyFormatPluginError(error.message, error.stack);\n\t    }\n\t  }\n\n\t  return null;\n\t}\n\n\tfunction printer(val, config, indentation, depth, refs, hasCalledToJSON) {\n\t  const plugin = findPlugin(config.plugins, val);\n\n\t  if (plugin !== null) {\n\t    return printPlugin(plugin, val, config, indentation, depth, refs);\n\t  }\n\n\t  const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString);\n\n\t  if (basicResult !== null) {\n\t    return basicResult;\n\t  }\n\n\t  return printComplexValue(val, config, indentation, depth, refs, hasCalledToJSON);\n\t}\n\n\tconst DEFAULT_THEME = {\n\t  comment: 'gray',\n\t  content: 'reset',\n\t  prop: 'yellow',\n\t  tag: 'cyan',\n\t  value: 'green'\n\t};\n\tconst DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME);\n\tconst DEFAULT_OPTIONS = {\n\t  callToJSON: true,\n\t  compareKeys: undefined,\n\t  escapeRegex: false,\n\t  escapeString: true,\n\t  highlight: false,\n\t  indent: 2,\n\t  maxDepth: Infinity,\n\t  min: false,\n\t  plugins: [],\n\t  printBasicPrototype: true,\n\t  printFunctionName: true,\n\t  theme: DEFAULT_THEME\n\t};\n\tvar DEFAULT_OPTIONS_1 = build.DEFAULT_OPTIONS = DEFAULT_OPTIONS;\n\n\tfunction validateOptions(options) {\n\t  Object.keys(options).forEach(key => {\n\t    if (!DEFAULT_OPTIONS.hasOwnProperty(key)) {\n\t      throw new Error(\"pretty-format: Unknown option \\\"\" + key + \"\\\".\");\n\t    }\n\t  });\n\n\t  if (options.min && options.indent !== undefined && options.indent !== 0) {\n\t    throw new Error('pretty-format: Options \"min\" and \"indent\" cannot be used together.');\n\t  }\n\n\t  if (options.theme !== undefined) {\n\t    if (options.theme === null) {\n\t      throw new Error('pretty-format: Option \"theme\" must not be null.');\n\t    }\n\n\t    if (typeof options.theme !== 'object') {\n\t      throw new Error(\"pretty-format: Option \\\"theme\\\" must be of type \\\"object\\\" but instead received \\\"\" + typeof options.theme + \"\\\".\");\n\t    }\n\t  }\n\t}\n\n\tconst getColorsHighlight = options => DEFAULT_THEME_KEYS.reduce((colors, key) => {\n\t  const value = options.theme && options.theme[key] !== undefined ? options.theme[key] : DEFAULT_THEME[key];\n\t  const color = value && _ansiStyles.default[value];\n\n\t  if (color && typeof color.close === 'string' && typeof color.open === 'string') {\n\t    colors[key] = color;\n\t  } else {\n\t    throw new Error(\"pretty-format: Option \\\"theme\\\" has a key \\\"\" + key + \"\\\" whose value \\\"\" + value + \"\\\" is undefined in ansi-styles.\");\n\t  }\n\n\t  return colors;\n\t}, Object.create(null));\n\n\tconst getColorsEmpty = () => DEFAULT_THEME_KEYS.reduce((colors, key) => {\n\t  colors[key] = {\n\t    close: '',\n\t    open: ''\n\t  };\n\t  return colors;\n\t}, Object.create(null));\n\n\tconst getPrintFunctionName = options => options && options.printFunctionName !== undefined ? options.printFunctionName : DEFAULT_OPTIONS.printFunctionName;\n\n\tconst getEscapeRegex = options => options && options.escapeRegex !== undefined ? options.escapeRegex : DEFAULT_OPTIONS.escapeRegex;\n\n\tconst getEscapeString = options => options && options.escapeString !== undefined ? options.escapeString : DEFAULT_OPTIONS.escapeString;\n\n\tconst getConfig$1 = options => {\n\t  var _options$printBasicPr;\n\n\t  return {\n\t    callToJSON: options && options.callToJSON !== undefined ? options.callToJSON : DEFAULT_OPTIONS.callToJSON,\n\t    colors: options && options.highlight ? getColorsHighlight(options) : getColorsEmpty(),\n\t    compareKeys: options && typeof options.compareKeys === 'function' ? options.compareKeys : DEFAULT_OPTIONS.compareKeys,\n\t    escapeRegex: getEscapeRegex(options),\n\t    escapeString: getEscapeString(options),\n\t    indent: options && options.min ? '' : createIndent(options && options.indent !== undefined ? options.indent : DEFAULT_OPTIONS.indent),\n\t    maxDepth: options && options.maxDepth !== undefined ? options.maxDepth : DEFAULT_OPTIONS.maxDepth,\n\t    min: options && options.min !== undefined ? options.min : DEFAULT_OPTIONS.min,\n\t    plugins: options && options.plugins !== undefined ? options.plugins : DEFAULT_OPTIONS.plugins,\n\t    printBasicPrototype: (_options$printBasicPr = options === null || options === void 0 ? void 0 : options.printBasicPrototype) !== null && _options$printBasicPr !== void 0 ? _options$printBasicPr : true,\n\t    printFunctionName: getPrintFunctionName(options),\n\t    spacingInner: options && options.min ? ' ' : '\\n',\n\t    spacingOuter: options && options.min ? '' : '\\n'\n\t  };\n\t};\n\n\tfunction createIndent(indent) {\n\t  return new Array(indent + 1).join(' ');\n\t}\n\t/**\n\t * Returns a presentation string of your `val` object\n\t * @param val any potential JavaScript object\n\t * @param options Custom settings\n\t */\n\n\n\tfunction format(val, options) {\n\t  if (options) {\n\t    validateOptions(options);\n\n\t    if (options.plugins) {\n\t      const plugin = findPlugin(options.plugins, val);\n\n\t      if (plugin !== null) {\n\t        return printPlugin(plugin, val, getConfig$1(options), '', 0, []);\n\t      }\n\t    }\n\t  }\n\n\t  const basicResult = printBasicValue(val, getPrintFunctionName(options), getEscapeRegex(options), getEscapeString(options));\n\n\t  if (basicResult !== null) {\n\t    return basicResult;\n\t  }\n\n\t  return printComplexValue(val, getConfig$1(options), '', 0, []);\n\t}\n\n\tconst plugins = {\n\t  AsymmetricMatcher: _AsymmetricMatcher.default,\n\t  ConvertAnsi: _ConvertAnsi.default,\n\t  DOMCollection: _DOMCollection.default,\n\t  DOMElement: _DOMElement.default,\n\t  Immutable: _Immutable.default,\n\t  ReactElement: _ReactElement.default,\n\t  ReactTestComponent: _ReactTestComponent.default\n\t};\n\tplugins_1 = build.plugins = plugins;\n\tvar _default$2d = format;\n\tdefault_1 = build.default = _default$2d;\n\n\tvar index = /*#__PURE__*/_mergeNamespaces({\n\t\t__proto__: null,\n\t\tget DEFAULT_OPTIONS () { return DEFAULT_OPTIONS_1; },\n\t\tformat: format_1,\n\t\tget plugins () { return plugins_1; },\n\t\tget default () { return default_1; }\n\t}, [build]);\n\n\t/**\n\t * Source: https://github.com/facebook/jest/blob/e7bb6a1e26ffab90611b2593912df15b69315611/packages/pretty-format/src/plugins/DOMElement.ts\n\t */\n\n\t/* eslint-disable -- trying to stay as close to the original as possible */\n\n\t/* istanbul ignore file */\n\tfunction escapeHTML(str) {\n\t  return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\t} // Return empty string if keys is empty.\n\n\n\tconst printProps = (keys, props, config, indentation, depth, refs, printer) => {\n\t  const indentationNext = indentation + config.indent;\n\t  const colors = config.colors;\n\t  return keys.map(key => {\n\t    const value = props[key];\n\t    let printed = printer(value, config, indentationNext, depth, refs);\n\n\t    if (typeof value !== 'string') {\n\t      if (printed.indexOf('\\n') !== -1) {\n\t        printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation;\n\t      }\n\n\t      printed = '{' + printed + '}';\n\t    }\n\n\t    return config.spacingInner + indentation + colors.prop.open + key + colors.prop.close + '=' + colors.value.open + printed + colors.value.close;\n\t  }).join('');\n\t}; // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node_type_constants\n\n\n\tconst NodeTypeTextNode = 3; // Return empty string if children is empty.\n\n\tconst printChildren = (children, config, indentation, depth, refs, printer) => children.map(child => {\n\t  const printedChild = typeof child === 'string' ? printText(child, config) : printer(child, config, indentation, depth, refs);\n\n\t  if (printedChild === '' && typeof child === 'object' && child !== null && child.nodeType !== NodeTypeTextNode) {\n\t    // A plugin serialized this Node to '' meaning we should ignore it.\n\t    return '';\n\t  }\n\n\t  return config.spacingOuter + indentation + printedChild;\n\t}).join('');\n\n\tconst printText = (text, config) => {\n\t  const contentColor = config.colors.content;\n\t  return contentColor.open + escapeHTML(text) + contentColor.close;\n\t};\n\n\tconst printComment = (comment, config) => {\n\t  const commentColor = config.colors.comment;\n\t  return commentColor.open + '<!--' + escapeHTML(comment) + '-->' + commentColor.close;\n\t}; // Separate the functions to format props, children, and element,\n\t// so a plugin could override a particular function, if needed.\n\t// Too bad, so sad: the traditional (but unnecessary) space\n\t// in a self-closing tagColor requires a second test of printedProps.\n\n\n\tconst printElement = (type, printedProps, printedChildren, config, indentation) => {\n\t  const tagColor = config.colors.tag;\n\t  return tagColor.open + '<' + type + (printedProps && tagColor.close + printedProps + config.spacingOuter + indentation + tagColor.open) + (printedChildren ? '>' + tagColor.close + printedChildren + config.spacingOuter + indentation + tagColor.open + '</' + type : (printedProps && !config.min ? '' : ' ') + '/') + '>' + tagColor.close;\n\t};\n\n\tconst printElementAsLeaf = (type, config) => {\n\t  const tagColor = config.colors.tag;\n\t  return tagColor.open + '<' + type + tagColor.close + ' …' + tagColor.open + ' />' + tagColor.close;\n\t};\n\n\tconst ELEMENT_NODE$1 = 1;\n\tconst TEXT_NODE$1 = 3;\n\tconst COMMENT_NODE$1 = 8;\n\tconst FRAGMENT_NODE = 11;\n\tconst ELEMENT_REGEXP = /^((HTML|SVG)\\w*)?Element$/;\n\n\tconst testNode = val => {\n\t  const constructorName = val.constructor.name;\n\t  const {\n\t    nodeType,\n\t    tagName\n\t  } = val;\n\t  const isCustomElement = typeof tagName === 'string' && tagName.includes('-') || typeof val.hasAttribute === 'function' && val.hasAttribute('is');\n\t  return nodeType === ELEMENT_NODE$1 && (ELEMENT_REGEXP.test(constructorName) || isCustomElement) || nodeType === TEXT_NODE$1 && constructorName === 'Text' || nodeType === COMMENT_NODE$1 && constructorName === 'Comment' || nodeType === FRAGMENT_NODE && constructorName === 'DocumentFragment';\n\t};\n\n\tfunction nodeIsText(node) {\n\t  return node.nodeType === TEXT_NODE$1;\n\t}\n\n\tfunction nodeIsComment(node) {\n\t  return node.nodeType === COMMENT_NODE$1;\n\t}\n\n\tfunction nodeIsFragment(node) {\n\t  return node.nodeType === FRAGMENT_NODE;\n\t}\n\n\tfunction createDOMElementFilter(filterNode) {\n\t  return {\n\t    test: val => {\n\t      var _val$constructor2;\n\n\t      return (val == null ? void 0 : (_val$constructor2 = val.constructor) == null ? void 0 : _val$constructor2.name) && testNode(val);\n\t    },\n\t    serialize: (node, config, indentation, depth, refs, printer) => {\n\t      if (nodeIsText(node)) {\n\t        return printText(node.data, config);\n\t      }\n\n\t      if (nodeIsComment(node)) {\n\t        return printComment(node.data, config);\n\t      }\n\n\t      const type = nodeIsFragment(node) ? \"DocumentFragment\" : node.tagName.toLowerCase();\n\n\t      if (++depth > config.maxDepth) {\n\t        return printElementAsLeaf(type, config);\n\t      }\n\n\t      return printElement(type, printProps(nodeIsFragment(node) ? [] : Array.from(node.attributes).map(attr => attr.name).sort(), nodeIsFragment(node) ? {} : Array.from(node.attributes).reduce((props, attribute) => {\n\t        props[attribute.name] = attribute.value;\n\t        return props;\n\t      }, {}), config, indentation + config.indent, depth, refs, printer), printChildren(Array.prototype.slice.call(node.childNodes || node.children).filter(filterNode), config, indentation + config.indent, depth, refs, printer), config, indentation);\n\t    }\n\t  };\n\t}\n\n\t// We try to load node dependencies\n\tlet chalk = null;\n\tlet readFileSync = null;\n\tlet codeFrameColumns = null;\n\n\ttry {\n\t  const nodeRequire = module && module.require;\n\t  readFileSync = nodeRequire.call(module, 'fs').readFileSync;\n\t  codeFrameColumns = nodeRequire.call(module, '@babel/code-frame').codeFrameColumns;\n\t  chalk = nodeRequire.call(module, 'chalk');\n\t} catch {// We're in a browser environment\n\t} // frame has the form \"at myMethod (location/to/my/file.js:10:2)\"\n\n\n\tfunction getCodeFrame(frame) {\n\t  const locationStart = frame.indexOf('(') + 1;\n\t  const locationEnd = frame.indexOf(')');\n\t  const frameLocation = frame.slice(locationStart, locationEnd);\n\t  const frameLocationElements = frameLocation.split(':');\n\t  const [filename, line, column] = [frameLocationElements[0], parseInt(frameLocationElements[1], 10), parseInt(frameLocationElements[2], 10)];\n\t  let rawFileContents = '';\n\n\t  try {\n\t    rawFileContents = readFileSync(filename, 'utf-8');\n\t  } catch {\n\t    return '';\n\t  }\n\n\t  const codeFrame = codeFrameColumns(rawFileContents, {\n\t    start: {\n\t      line,\n\t      column\n\t    }\n\t  }, {\n\t    highlightCode: true,\n\t    linesBelow: 0\n\t  });\n\t  return chalk.dim(frameLocation) + \"\\n\" + codeFrame + \"\\n\";\n\t}\n\n\tfunction getUserCodeFrame() {\n\t  // If we couldn't load dependencies, we can't generate the user trace\n\n\t  /* istanbul ignore next */\n\t  if (!readFileSync || !codeFrameColumns) {\n\t    return '';\n\t  }\n\n\t  const err = new Error();\n\t  const firstClientCodeFrame = err.stack.split('\\n').slice(1) // Remove first line which has the form \"Error: TypeError\"\n\t  .find(frame => !frame.includes('node_modules/')); // Ignore frames from 3rd party libraries\n\n\t  return getCodeFrame(firstClientCodeFrame);\n\t}\n\n\t// Constant node.nodeType for text nodes, see:\n\t// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants\n\tconst TEXT_NODE = 3;\n\n\tfunction jestFakeTimersAreEnabled() {\n\t  /* istanbul ignore else */\n\t  if (typeof jest !== 'undefined' && jest !== null) {\n\t    return (// legacy timers\n\t      setTimeout._isMockFunction === true || // modern timers\n\t      Object.prototype.hasOwnProperty.call(setTimeout, 'clock')\n\t    );\n\t  } // istanbul ignore next\n\n\n\t  return false;\n\t}\n\n\tfunction getDocument() {\n\t  /* istanbul ignore if */\n\t  if (typeof window === 'undefined') {\n\t    throw new Error('Could not find default container');\n\t  }\n\n\t  return window.document;\n\t}\n\n\tfunction getWindowFromNode(node) {\n\t  if (node.defaultView) {\n\t    // node is document\n\t    return node.defaultView;\n\t  } else if (node.ownerDocument && node.ownerDocument.defaultView) {\n\t    // node is a DOM node\n\t    return node.ownerDocument.defaultView;\n\t  } else if (node.window) {\n\t    // node is window\n\t    return node.window;\n\t  } else if (node.ownerDocument && node.ownerDocument.defaultView === null) {\n\t    throw new Error(\"It looks like the window object is not available for the provided node.\");\n\t  } else if (node.then instanceof Function) {\n\t    throw new Error(\"It looks like you passed a Promise object instead of a DOM node. Did you do something like `fireEvent.click(screen.findBy...` when you meant to use a `getBy` query `fireEvent.click(screen.getBy...`, or await the findBy query `fireEvent.click(await screen.findBy...`?\");\n\t  } else if (Array.isArray(node)) {\n\t    throw new Error(\"It looks like you passed an Array instead of a DOM node. Did you do something like `fireEvent.click(screen.getAllBy...` when you meant to use a `getBy` query `fireEvent.click(screen.getBy...`?\");\n\t  } else if (typeof node.debug === 'function' && typeof node.logTestingPlaygroundURL === 'function') {\n\t    throw new Error(\"It looks like you passed a `screen` object. Did you do something like `fireEvent.click(screen, ...` when you meant to use a query, e.g. `fireEvent.click(screen.getBy..., `?\");\n\t  } else {\n\t    // The user passed something unusual to a calling function\n\t    throw new Error(\"The given node is not an Element, the node type is: \" + typeof node + \".\");\n\t  }\n\t}\n\n\tfunction checkContainerType(container) {\n\t  if (!container || !(typeof container.querySelector === 'function') || !(typeof container.querySelectorAll === 'function')) {\n\t    throw new TypeError(\"Expected container to be an Element, a Document or a DocumentFragment but got \" + getTypeName(container) + \".\");\n\t  }\n\n\t  function getTypeName(object) {\n\t    if (typeof object === 'object') {\n\t      return object === null ? 'null' : object.constructor.name;\n\t    }\n\n\t    return typeof object;\n\t  }\n\t}\n\n\tconst inNode = () => typeof process !== 'undefined' && process.versions !== undefined && process.versions.node !== undefined;\n\n\tconst {\n\t  DOMCollection\n\t} = plugins_1; // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node_type_constants\n\n\tconst ELEMENT_NODE = 1;\n\tconst COMMENT_NODE = 8; // https://github.com/facebook/jest/blob/615084195ae1ae61ddd56162c62bbdda17587569/packages/pretty-format/src/plugins/DOMElement.ts#L50\n\n\tfunction filterCommentsAndDefaultIgnoreTagsTags(value) {\n\t  return value.nodeType !== COMMENT_NODE && (value.nodeType !== ELEMENT_NODE || !value.matches(getConfig().defaultIgnore));\n\t}\n\n\tfunction prettyDOM(dom, maxLength, options) {\n\t  if (options === void 0) {\n\t    options = {};\n\t  }\n\n\t  if (!dom) {\n\t    dom = getDocument().body;\n\t  }\n\n\t  if (typeof maxLength !== 'number') {\n\t    maxLength = typeof process !== 'undefined' && undefined || 7000;\n\t  }\n\n\t  if (maxLength === 0) {\n\t    return '';\n\t  }\n\n\t  if (dom.documentElement) {\n\t    dom = dom.documentElement;\n\t  }\n\n\t  let domTypeName = typeof dom;\n\n\t  if (domTypeName === 'object') {\n\t    domTypeName = dom.constructor.name;\n\t  } else {\n\t    // To don't fall with `in` operator\n\t    dom = {};\n\t  }\n\n\t  if (!('outerHTML' in dom)) {\n\t    throw new TypeError(\"Expected an element or document but got \" + domTypeName);\n\t  }\n\n\t  const {\n\t    filterNode = filterCommentsAndDefaultIgnoreTagsTags,\n\t    ...prettyFormatOptions\n\t  } = options;\n\t  const debugContent = format_1(dom, {\n\t    plugins: [createDOMElementFilter(filterNode), DOMCollection],\n\t    printFunctionName: false,\n\t    highlight: inNode(),\n\t    ...prettyFormatOptions\n\t  });\n\t  return maxLength !== undefined && dom.outerHTML.length > maxLength ? debugContent.slice(0, maxLength) + \"...\" : debugContent;\n\t}\n\n\tconst logDOM = function () {\n\t  const userCodeFrame = getUserCodeFrame();\n\n\t  if (userCodeFrame) {\n\t    console.log(prettyDOM(...arguments) + \"\\n\\n\" + userCodeFrame);\n\t  } else {\n\t    console.log(prettyDOM(...arguments));\n\t  }\n\t};\n\n\t// It would be cleaner for this to live inside './queries', but\n\t// other parts of the code assume that all exports from\n\t// './queries' are query functions.\n\tlet config = {\n\t  testIdAttribute: 'data-testid',\n\t  asyncUtilTimeout: 1000,\n\t  // asyncWrapper and advanceTimersWrapper is to support React's async `act` function.\n\t  // forcing react-testing-library to wrap all async functions would've been\n\t  // a total nightmare (consider wrapping every findBy* query and then also\n\t  // updating `within` so those would be wrapped too. Total nightmare).\n\t  // so we have this config option that's really only intended for\n\t  // react-testing-library to use. For that reason, this feature will remain\n\t  // undocumented.\n\t  asyncWrapper: cb => cb(),\n\t  unstable_advanceTimersWrapper: cb => cb(),\n\t  eventWrapper: cb => cb(),\n\t  // default value for the `hidden` option in `ByRole` queries\n\t  defaultHidden: false,\n\t  // default value for the `ignore` option in `ByText` queries\n\t  defaultIgnore: 'script, style',\n\t  // showOriginalStackTrace flag to show the full error stack traces for async errors\n\t  showOriginalStackTrace: false,\n\t  // throw errors w/ suggestions for better queries. Opt in so off by default.\n\t  throwSuggestions: false,\n\n\t  // called when getBy* queries fail. (message, container) => Error\n\t  getElementError(message, container) {\n\t    const prettifiedDOM = prettyDOM(container);\n\t    const error = new Error([message, \"Ignored nodes: comments, \" + config.defaultIgnore + \"\\n\" + prettifiedDOM].filter(Boolean).join('\\n\\n'));\n\t    error.name = 'TestingLibraryElementError';\n\t    return error;\n\t  },\n\n\t  _disableExpensiveErrorDiagnostics: false,\n\t  computedStyleSupportsPseudoElements: false\n\t};\n\tfunction runWithExpensiveErrorDiagnosticsDisabled(callback) {\n\t  try {\n\t    config._disableExpensiveErrorDiagnostics = true;\n\t    return callback();\n\t  } finally {\n\t    config._disableExpensiveErrorDiagnostics = false;\n\t  }\n\t}\n\tfunction configure(newConfig) {\n\t  if (typeof newConfig === 'function') {\n\t    // Pass the existing config out to the provided function\n\t    // and accept a delta in return\n\t    newConfig = newConfig(config);\n\t  } // Merge the incoming config delta\n\n\n\t  config = { ...config,\n\t    ...newConfig\n\t  };\n\t}\n\tfunction getConfig() {\n\t  return config;\n\t}\n\n\tconst labelledNodeNames = ['button', 'meter', 'output', 'progress', 'select', 'textarea', 'input'];\n\n\tfunction getTextContent(node) {\n\t  if (labelledNodeNames.includes(node.nodeName.toLowerCase())) {\n\t    return '';\n\t  }\n\n\t  if (node.nodeType === TEXT_NODE) return node.textContent;\n\t  return Array.from(node.childNodes).map(childNode => getTextContent(childNode)).join('');\n\t}\n\n\tfunction getLabelContent(element) {\n\t  let textContent;\n\n\t  if (element.tagName.toLowerCase() === 'label') {\n\t    textContent = getTextContent(element);\n\t  } else {\n\t    textContent = element.value || element.textContent;\n\t  }\n\n\t  return textContent;\n\t} // Based on https://github.com/eps1lon/dom-accessibility-api/pull/352\n\n\n\tfunction getRealLabels(element) {\n\t  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- types are not aware of older browsers that don't implement `labels`\n\t  if (element.labels !== undefined) {\n\t    var _labels;\n\n\t    return (_labels = element.labels) != null ? _labels : [];\n\t  }\n\n\t  if (!isLabelable(element)) return [];\n\t  const labels = element.ownerDocument.querySelectorAll('label');\n\t  return Array.from(labels).filter(label => label.control === element);\n\t}\n\n\tfunction isLabelable(element) {\n\t  return /BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/.test(element.tagName) || element.tagName === 'INPUT' && element.getAttribute('type') !== 'hidden';\n\t}\n\n\tfunction getLabels$1(container, element, _temp) {\n\t  let {\n\t    selector = '*'\n\t  } = _temp === void 0 ? {} : _temp;\n\t  const ariaLabelledBy = element.getAttribute('aria-labelledby');\n\t  const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : [];\n\t  return labelsId.length ? labelsId.map(labelId => {\n\t    const labellingElement = container.querySelector(\"[id=\\\"\" + labelId + \"\\\"]\");\n\t    return labellingElement ? {\n\t      content: getLabelContent(labellingElement),\n\t      formControl: null\n\t    } : {\n\t      content: '',\n\t      formControl: null\n\t    };\n\t  }) : Array.from(getRealLabels(element)).map(label => {\n\t    const textToMatch = getLabelContent(label);\n\t    const formControlSelector = 'button, input, meter, output, progress, select, textarea';\n\t    const labelledFormControl = Array.from(label.querySelectorAll(formControlSelector)).filter(formControlElement => formControlElement.matches(selector))[0];\n\t    return {\n\t      content: textToMatch,\n\t      formControl: labelledFormControl\n\t    };\n\t  });\n\t}\n\n\tfunction assertNotNullOrUndefined(matcher) {\n\t  if (matcher === null || matcher === undefined) {\n\t    throw new Error( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- implicitly converting `T` to `string`\n\t    \"It looks like \" + matcher + \" was passed instead of a matcher. Did you do something like getByText(\" + matcher + \")?\");\n\t  }\n\t}\n\n\tfunction fuzzyMatches(textToMatch, node, matcher, normalizer) {\n\t  if (typeof textToMatch !== 'string') {\n\t    return false;\n\t  }\n\n\t  assertNotNullOrUndefined(matcher);\n\t  const normalizedText = normalizer(textToMatch);\n\n\t  if (typeof matcher === 'string' || typeof matcher === 'number') {\n\t    return normalizedText.toLowerCase().includes(matcher.toString().toLowerCase());\n\t  } else if (typeof matcher === 'function') {\n\t    return matcher(normalizedText, node);\n\t  } else {\n\t    return matchRegExp(matcher, normalizedText);\n\t  }\n\t}\n\n\tfunction matches(textToMatch, node, matcher, normalizer) {\n\t  if (typeof textToMatch !== 'string') {\n\t    return false;\n\t  }\n\n\t  assertNotNullOrUndefined(matcher);\n\t  const normalizedText = normalizer(textToMatch);\n\n\t  if (matcher instanceof Function) {\n\t    return matcher(normalizedText, node);\n\t  } else if (matcher instanceof RegExp) {\n\t    return matchRegExp(matcher, normalizedText);\n\t  } else {\n\t    return normalizedText === String(matcher);\n\t  }\n\t}\n\n\tfunction getDefaultNormalizer(_temp) {\n\t  let {\n\t    trim = true,\n\t    collapseWhitespace = true\n\t  } = _temp === void 0 ? {} : _temp;\n\t  return text => {\n\t    let normalizedText = text;\n\t    normalizedText = trim ? normalizedText.trim() : normalizedText;\n\t    normalizedText = collapseWhitespace ? normalizedText.replace(/\\s+/g, ' ') : normalizedText;\n\t    return normalizedText;\n\t  };\n\t}\n\t/**\n\t * Constructs a normalizer to pass to functions in matches.js\n\t * @param {boolean|undefined} trim The user-specified value for `trim`, without\n\t * any defaulting having been applied\n\t * @param {boolean|undefined} collapseWhitespace The user-specified value for\n\t * `collapseWhitespace`, without any defaulting having been applied\n\t * @param {Function|undefined} normalizer The user-specified normalizer\n\t * @returns {Function} A normalizer\n\t */\n\n\n\tfunction makeNormalizer(_ref) {\n\t  let {\n\t    trim,\n\t    collapseWhitespace,\n\t    normalizer\n\t  } = _ref;\n\n\t  if (!normalizer) {\n\t    // No custom normalizer specified. Just use default.\n\t    return getDefaultNormalizer({\n\t      trim,\n\t      collapseWhitespace\n\t    });\n\t  }\n\n\t  if (typeof trim !== 'undefined' || typeof collapseWhitespace !== 'undefined') {\n\t    // They've also specified a value for trim or collapseWhitespace\n\t    throw new Error('trim and collapseWhitespace are not supported with a normalizer. ' + 'If you want to use the default trim and collapseWhitespace logic in your normalizer, ' + 'use \"getDefaultNormalizer({trim, collapseWhitespace})\" and compose that into your normalizer');\n\t  }\n\n\t  return normalizer;\n\t}\n\n\tfunction matchRegExp(matcher, text) {\n\t  const match = matcher.test(text);\n\n\t  if (matcher.global && matcher.lastIndex !== 0) {\n\t    console.warn(\"To match all elements we had to reset the lastIndex of the RegExp because the global flag is enabled. We encourage to remove the global flag from the RegExp.\");\n\t    matcher.lastIndex = 0;\n\t  }\n\n\t  return match;\n\t}\n\n\tfunction getNodeText(node) {\n\t  if (node.matches('input[type=submit], input[type=button], input[type=reset]')) {\n\t    return node.value;\n\t  }\n\n\t  return Array.from(node.childNodes).filter(child => child.nodeType === TEXT_NODE && Boolean(child.textContent)).map(c => c.textContent).join('');\n\t}\n\n\t/**\n\t * @source {https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Polyfill}\n\t * but without thisArg (too hard to type, no need to `this`)\n\t */\n\tvar toStr = Object.prototype.toString;\n\n\tfunction isCallable(fn) {\n\t  return typeof fn === \"function\" || toStr.call(fn) === \"[object Function]\";\n\t}\n\n\tfunction toInteger(value) {\n\t  var number = Number(value);\n\n\t  if (isNaN(number)) {\n\t    return 0;\n\t  }\n\n\t  if (number === 0 || !isFinite(number)) {\n\t    return number;\n\t  }\n\n\t  return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));\n\t}\n\n\tvar maxSafeInteger = Math.pow(2, 53) - 1;\n\n\tfunction toLength(value) {\n\t  var len = toInteger(value);\n\t  return Math.min(Math.max(len, 0), maxSafeInteger);\n\t}\n\t/**\n\t * Creates an array from an iterable object.\n\t * @param iterable An iterable object to convert to an array.\n\t */\n\n\t/**\n\t * Creates an array from an iterable object.\n\t * @param iterable An iterable object to convert to an array.\n\t * @param mapfn A mapping function to call on every element of the array.\n\t * @param thisArg Value of 'this' used to invoke the mapfn.\n\t */\n\n\n\tfunction arrayFrom(arrayLike, mapFn) {\n\t  // 1. Let C be the this value.\n\t  // edit(@eps1lon): we're not calling it as Array.from\n\t  var C = Array; // 2. Let items be ToObject(arrayLike).\n\n\t  var items = Object(arrayLike); // 3. ReturnIfAbrupt(items).\n\n\t  if (arrayLike == null) {\n\t    throw new TypeError(\"Array.from requires an array-like object - not null or undefined\");\n\t  } // 4. If mapfn is undefined, then let mapping be false.\n\t  // const mapFn = arguments.length > 1 ? arguments[1] : void undefined;\n\n\n\t  if (typeof mapFn !== \"undefined\") {\n\t    // 5. else\n\t    // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.\n\t    if (!isCallable(mapFn)) {\n\t      throw new TypeError(\"Array.from: when provided, the second argument must be a function\");\n\t    }\n\t  } // 10. Let lenValue be Get(items, \"length\").\n\t  // 11. Let len be ToLength(lenValue).\n\n\n\t  var len = toLength(items.length); // 13. If IsConstructor(C) is true, then\n\t  // 13. a. Let A be the result of calling the [[Construct]] internal method\n\t  // of C with an argument list containing the single item len.\n\t  // 14. a. Else, Let A be ArrayCreate(len).\n\n\t  var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Let k be 0.\n\n\t  var k = 0; // 17. Repeat, while k < len… (also steps a - h)\n\n\t  var kValue;\n\n\t  while (k < len) {\n\t    kValue = items[k];\n\n\t    if (mapFn) {\n\t      A[k] = mapFn(kValue, k);\n\t    } else {\n\t      A[k] = kValue;\n\t    }\n\n\t    k += 1;\n\t  } // 18. Let putStatus be Put(A, \"length\", len, true).\n\n\n\t  A.length = len; // 20. Return A.\n\n\t  return A;\n\t}\n\n\tfunction _classCallCheck(instance, Constructor) {\n\t  if (!(instance instanceof Constructor)) {\n\t    throw new TypeError(\"Cannot call a class as a function\");\n\t  }\n\t}\n\n\tfunction _defineProperties(target, props) {\n\t  for (var i = 0; i < props.length; i++) {\n\t    var descriptor = props[i];\n\t    descriptor.enumerable = descriptor.enumerable || false;\n\t    descriptor.configurable = true;\n\t    if (\"value\" in descriptor) descriptor.writable = true;\n\t    Object.defineProperty(target, descriptor.key, descriptor);\n\t  }\n\t}\n\n\tfunction _createClass(Constructor, protoProps, staticProps) {\n\t  if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n\t  if (staticProps) _defineProperties(Constructor, staticProps);\n\t  Object.defineProperty(Constructor, \"prototype\", {\n\t    writable: false\n\t  });\n\t  return Constructor;\n\t}\n\n\tfunction _defineProperty$2(obj, key, value) {\n\t  if (key in obj) {\n\t    Object.defineProperty(obj, key, {\n\t      value: value,\n\t      enumerable: true,\n\t      configurable: true,\n\t      writable: true\n\t    });\n\t  } else {\n\t    obj[key] = value;\n\t  }\n\n\t  return obj;\n\t} // for environments without Set we fallback to arrays with unique members\n\n\n\tvar SetLike = /*#__PURE__*/function () {\n\t  function SetLike() {\n\t    var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n\n\t    _classCallCheck(this, SetLike);\n\n\t    _defineProperty$2(this, \"items\", void 0);\n\n\t    this.items = items;\n\t  }\n\n\t  _createClass(SetLike, [{\n\t    key: \"add\",\n\t    value: function add(value) {\n\t      if (this.has(value) === false) {\n\t        this.items.push(value);\n\t      }\n\n\t      return this;\n\t    }\n\t  }, {\n\t    key: \"clear\",\n\t    value: function clear() {\n\t      this.items = [];\n\t    }\n\t  }, {\n\t    key: \"delete\",\n\t    value: function _delete(value) {\n\t      var previousLength = this.items.length;\n\t      this.items = this.items.filter(function (item) {\n\t        return item !== value;\n\t      });\n\t      return previousLength !== this.items.length;\n\t    }\n\t  }, {\n\t    key: \"forEach\",\n\t    value: function forEach(callbackfn) {\n\t      var _this = this;\n\n\t      this.items.forEach(function (item) {\n\t        callbackfn(item, item, _this);\n\t      });\n\t    }\n\t  }, {\n\t    key: \"has\",\n\t    value: function has(value) {\n\t      return this.items.indexOf(value) !== -1;\n\t    }\n\t  }, {\n\t    key: \"size\",\n\t    get: function get() {\n\t      return this.items.length;\n\t    }\n\t  }]);\n\n\t  return SetLike;\n\t}();\n\n\tvar SetLike$1 = typeof Set === \"undefined\" ? Set : SetLike;\n\n\t// https://w3c.github.io/html-aria/#document-conformance-requirements-for-use-of-aria-attributes-in-html\n\n\t/**\n\t * Safe Element.localName for all supported environments\n\t * @param element\n\t */\n\tfunction getLocalName(element) {\n\t  var _element$localName;\n\n\t  return (// eslint-disable-next-line no-restricted-properties -- actual guard for environments without localName\n\t    (_element$localName = element.localName) !== null && _element$localName !== void 0 ? _element$localName : // eslint-disable-next-line no-restricted-properties -- required for the fallback\n\t    element.tagName.toLowerCase()\n\t  );\n\t}\n\tvar localNameToRoleMappings = {\n\t  article: \"article\",\n\t  aside: \"complementary\",\n\t  button: \"button\",\n\t  datalist: \"listbox\",\n\t  dd: \"definition\",\n\t  details: \"group\",\n\t  dialog: \"dialog\",\n\t  dt: \"term\",\n\t  fieldset: \"group\",\n\t  figure: \"figure\",\n\t  // WARNING: Only with an accessible name\n\t  form: \"form\",\n\t  footer: \"contentinfo\",\n\t  h1: \"heading\",\n\t  h2: \"heading\",\n\t  h3: \"heading\",\n\t  h4: \"heading\",\n\t  h5: \"heading\",\n\t  h6: \"heading\",\n\t  header: \"banner\",\n\t  hr: \"separator\",\n\t  html: \"document\",\n\t  legend: \"legend\",\n\t  li: \"listitem\",\n\t  math: \"math\",\n\t  main: \"main\",\n\t  menu: \"list\",\n\t  nav: \"navigation\",\n\t  ol: \"list\",\n\t  optgroup: \"group\",\n\t  // WARNING: Only in certain context\n\t  option: \"option\",\n\t  output: \"status\",\n\t  progress: \"progressbar\",\n\t  // WARNING: Only with an accessible name\n\t  section: \"region\",\n\t  summary: \"button\",\n\t  table: \"table\",\n\t  tbody: \"rowgroup\",\n\t  textarea: \"textbox\",\n\t  tfoot: \"rowgroup\",\n\t  // WARNING: Only in certain context\n\t  td: \"cell\",\n\t  th: \"columnheader\",\n\t  thead: \"rowgroup\",\n\t  tr: \"row\",\n\t  ul: \"list\"\n\t};\n\tvar prohibitedAttributes = {\n\t  caption: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  code: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  deletion: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  emphasis: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  generic: new Set([\"aria-label\", \"aria-labelledby\", \"aria-roledescription\"]),\n\t  insertion: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  paragraph: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  presentation: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  strong: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  subscript: new Set([\"aria-label\", \"aria-labelledby\"]),\n\t  superscript: new Set([\"aria-label\", \"aria-labelledby\"])\n\t};\n\t/**\n\t *\n\t * @param element\n\t * @param role The role used for this element. This is specified to control whether you want to use the implicit or explicit role.\n\t */\n\n\tfunction hasGlobalAriaAttributes(element, role) {\n\t  // https://rawgit.com/w3c/aria/stable/#global_states\n\t  // commented attributes are deprecated\n\t  return [\"aria-atomic\", \"aria-busy\", \"aria-controls\", \"aria-current\", \"aria-describedby\", \"aria-details\", // \"disabled\",\n\t  \"aria-dropeffect\", // \"errormessage\",\n\t  \"aria-flowto\", \"aria-grabbed\", // \"haspopup\",\n\t  \"aria-hidden\", // \"invalid\",\n\t  \"aria-keyshortcuts\", \"aria-label\", \"aria-labelledby\", \"aria-live\", \"aria-owns\", \"aria-relevant\", \"aria-roledescription\"].some(function (attributeName) {\n\t    var _prohibitedAttributes;\n\n\t    return element.hasAttribute(attributeName) && !((_prohibitedAttributes = prohibitedAttributes[role]) !== null && _prohibitedAttributes !== void 0 && _prohibitedAttributes.has(attributeName));\n\t  });\n\t}\n\n\tfunction ignorePresentationalRole(element, implicitRole) {\n\t  // https://rawgit.com/w3c/aria/stable/#conflict_resolution_presentation_none\n\t  return hasGlobalAriaAttributes(element, implicitRole);\n\t}\n\n\tfunction getRole(element) {\n\t  var explicitRole = getExplicitRole(element);\n\n\t  if (explicitRole === null || explicitRole === \"presentation\") {\n\t    var implicitRole = getImplicitRole(element);\n\n\t    if (explicitRole !== \"presentation\" || ignorePresentationalRole(element, implicitRole || \"\")) {\n\t      return implicitRole;\n\t    }\n\t  }\n\n\t  return explicitRole;\n\t}\n\n\tfunction getImplicitRole(element) {\n\t  var mappedByTag = localNameToRoleMappings[getLocalName(element)];\n\n\t  if (mappedByTag !== undefined) {\n\t    return mappedByTag;\n\t  }\n\n\t  switch (getLocalName(element)) {\n\t    case \"a\":\n\t    case \"area\":\n\t    case \"link\":\n\t      if (element.hasAttribute(\"href\")) {\n\t        return \"link\";\n\t      }\n\n\t      break;\n\n\t    case \"img\":\n\t      if (element.getAttribute(\"alt\") === \"\" && !ignorePresentationalRole(element, \"img\")) {\n\t        return \"presentation\";\n\t      }\n\n\t      return \"img\";\n\n\t    case \"input\":\n\t      {\n\t        var _ref = element,\n\t            type = _ref.type;\n\n\t        switch (type) {\n\t          case \"button\":\n\t          case \"image\":\n\t          case \"reset\":\n\t          case \"submit\":\n\t            return \"button\";\n\n\t          case \"checkbox\":\n\t          case \"radio\":\n\t            return type;\n\n\t          case \"range\":\n\t            return \"slider\";\n\n\t          case \"email\":\n\t          case \"tel\":\n\t          case \"text\":\n\t          case \"url\":\n\t            if (element.hasAttribute(\"list\")) {\n\t              return \"combobox\";\n\t            }\n\n\t            return \"textbox\";\n\n\t          case \"search\":\n\t            if (element.hasAttribute(\"list\")) {\n\t              return \"combobox\";\n\t            }\n\n\t            return \"searchbox\";\n\n\t          case \"number\":\n\t            return \"spinbutton\";\n\n\t          default:\n\t            return null;\n\t        }\n\t      }\n\n\t    case \"select\":\n\t      if (element.hasAttribute(\"multiple\") || element.size > 1) {\n\t        return \"listbox\";\n\t      }\n\n\t      return \"combobox\";\n\t  }\n\n\t  return null;\n\t}\n\n\tfunction getExplicitRole(element) {\n\t  var role = element.getAttribute(\"role\");\n\n\t  if (role !== null) {\n\t    var explicitRole = role.trim().split(\" \")[0]; // String.prototype.split(sep, limit) will always return an array with at least one member\n\t    // as long as limit is either undefined or > 0\n\n\t    if (explicitRole.length > 0) {\n\t      return explicitRole;\n\t    }\n\t  }\n\n\t  return null;\n\t}\n\n\tfunction isElement(node) {\n\t  return node !== null && node.nodeType === node.ELEMENT_NODE;\n\t}\n\tfunction isHTMLTableCaptionElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"caption\";\n\t}\n\tfunction isHTMLInputElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"input\";\n\t}\n\tfunction isHTMLOptGroupElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"optgroup\";\n\t}\n\tfunction isHTMLSelectElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"select\";\n\t}\n\tfunction isHTMLTableElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"table\";\n\t}\n\tfunction isHTMLTextAreaElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"textarea\";\n\t}\n\tfunction safeWindow(node) {\n\t  var _ref = node.ownerDocument === null ? node : node.ownerDocument,\n\t      defaultView = _ref.defaultView;\n\n\t  if (defaultView === null) {\n\t    throw new TypeError(\"no window available\");\n\t  }\n\n\t  return defaultView;\n\t}\n\tfunction isHTMLFieldSetElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"fieldset\";\n\t}\n\tfunction isHTMLLegendElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"legend\";\n\t}\n\tfunction isHTMLSlotElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"slot\";\n\t}\n\tfunction isSVGElement(node) {\n\t  return isElement(node) && node.ownerSVGElement !== undefined;\n\t}\n\tfunction isSVGSVGElement(node) {\n\t  return isElement(node) && getLocalName(node) === \"svg\";\n\t}\n\tfunction isSVGTitleElement(node) {\n\t  return isSVGElement(node) && getLocalName(node) === \"title\";\n\t}\n\t/**\n\t *\n\t * @param {Node} node -\n\t * @param {string} attributeName -\n\t * @returns {Element[]} -\n\t */\n\n\tfunction queryIdRefs(node, attributeName) {\n\t  if (isElement(node) && node.hasAttribute(attributeName)) {\n\t    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- safe due to hasAttribute check\n\t    var ids = node.getAttribute(attributeName).split(\" \"); // Browsers that don't support shadow DOM won't have getRootNode\n\n\t    var root = node.getRootNode ? node.getRootNode() : node.ownerDocument;\n\t    return ids.map(function (id) {\n\t      return root.getElementById(id);\n\t    }).filter(function (element) {\n\t      return element !== null;\n\t    } // TODO: why does this not narrow?\n\t    );\n\t  }\n\n\t  return [];\n\t}\n\tfunction hasAnyConcreteRoles(node, roles) {\n\t  if (isElement(node)) {\n\t    return roles.indexOf(getRole(node)) !== -1;\n\t  }\n\n\t  return false;\n\t}\n\n\t/**\n\t * implements https://w3c.github.io/accname/\n\t */\n\t/**\n\t *  A string of characters where all carriage returns, newlines, tabs, and form-feeds are replaced with a single space, and multiple spaces are reduced to a single space. The string contains only character data; it does not contain any markup.\n\t */\n\n\t/**\n\t *\n\t * @param {string} string -\n\t * @returns {FlatString} -\n\t */\n\n\tfunction asFlatString(s) {\n\t  return s.trim().replace(/\\s\\s+/g, \" \");\n\t}\n\t/**\n\t *\n\t * @param node -\n\t * @param options - These are not optional to prevent accidentally calling it without options in `computeAccessibleName`\n\t * @returns {boolean} -\n\t */\n\n\n\tfunction isHidden(node, getComputedStyleImplementation) {\n\t  if (!isElement(node)) {\n\t    return false;\n\t  }\n\n\t  if (node.hasAttribute(\"hidden\") || node.getAttribute(\"aria-hidden\") === \"true\") {\n\t    return true;\n\t  }\n\n\t  var style = getComputedStyleImplementation(node);\n\t  return style.getPropertyValue(\"display\") === \"none\" || style.getPropertyValue(\"visibility\") === \"hidden\";\n\t}\n\t/**\n\t * @param {Node} node -\n\t * @returns {boolean} - As defined in step 2E of https://w3c.github.io/accname/#mapping_additional_nd_te\n\t */\n\n\n\tfunction isControl(node) {\n\t  return hasAnyConcreteRoles(node, [\"button\", \"combobox\", \"listbox\", \"textbox\"]) || hasAbstractRole(node, \"range\");\n\t}\n\n\tfunction hasAbstractRole(node, role) {\n\t  if (!isElement(node)) {\n\t    return false;\n\t  }\n\n\t  switch (role) {\n\t    case \"range\":\n\t      return hasAnyConcreteRoles(node, [\"meter\", \"progressbar\", \"scrollbar\", \"slider\", \"spinbutton\"]);\n\n\t    default:\n\t      throw new TypeError(\"No knowledge about abstract role '\".concat(role, \"'. This is likely a bug :(\"));\n\t  }\n\t}\n\t/**\n\t * element.querySelectorAll but also considers owned tree\n\t * @param element\n\t * @param selectors\n\t */\n\n\n\tfunction querySelectorAllSubtree(element, selectors) {\n\t  var elements = arrayFrom(element.querySelectorAll(selectors));\n\t  queryIdRefs(element, \"aria-owns\").forEach(function (root) {\n\t    // babel transpiles this assuming an iterator\n\t    elements.push.apply(elements, arrayFrom(root.querySelectorAll(selectors)));\n\t  });\n\t  return elements;\n\t}\n\n\tfunction querySelectedOptions(listbox) {\n\t  if (isHTMLSelectElement(listbox)) {\n\t    // IE11 polyfill\n\t    return listbox.selectedOptions || querySelectorAllSubtree(listbox, \"[selected]\");\n\t  }\n\n\t  return querySelectorAllSubtree(listbox, '[aria-selected=\"true\"]');\n\t}\n\n\tfunction isMarkedPresentational(node) {\n\t  return hasAnyConcreteRoles(node, [\"none\", \"presentation\"]);\n\t}\n\t/**\n\t * Elements specifically listed in html-aam\n\t *\n\t * We don't need this for `label` or `legend` elements.\n\t * Their implicit roles already allow \"naming from content\".\n\t *\n\t * sources:\n\t *\n\t * - https://w3c.github.io/html-aam/#table-element\n\t */\n\n\n\tfunction isNativeHostLanguageTextAlternativeElement(node) {\n\t  return isHTMLTableCaptionElement(node);\n\t}\n\t/**\n\t * https://w3c.github.io/aria/#namefromcontent\n\t */\n\n\n\tfunction allowsNameFromContent(node) {\n\t  return hasAnyConcreteRoles(node, [\"button\", \"cell\", \"checkbox\", \"columnheader\", \"gridcell\", \"heading\", \"label\", \"legend\", \"link\", \"menuitem\", \"menuitemcheckbox\", \"menuitemradio\", \"option\", \"radio\", \"row\", \"rowheader\", \"switch\", \"tab\", \"tooltip\", \"treeitem\"]);\n\t}\n\t/**\n\t * TODO https://github.com/eps1lon/dom-accessibility-api/issues/100\n\t */\n\n\n\tfunction isDescendantOfNativeHostLanguageTextAlternativeElement( // eslint-disable-next-line @typescript-eslint/no-unused-vars -- not implemented yet\n\tnode) {\n\t  return false;\n\t}\n\n\tfunction getValueOfTextbox(element) {\n\t  if (isHTMLInputElement(element) || isHTMLTextAreaElement(element)) {\n\t    return element.value;\n\t  } // https://github.com/eps1lon/dom-accessibility-api/issues/4\n\n\n\t  return element.textContent || \"\";\n\t}\n\n\tfunction getTextualContent(declaration) {\n\t  var content = declaration.getPropertyValue(\"content\");\n\n\t  if (/^[\"'].*[\"']$/.test(content)) {\n\t    return content.slice(1, -1);\n\t  }\n\n\t  return \"\";\n\t}\n\t/**\n\t * https://html.spec.whatwg.org/multipage/forms.html#category-label\n\t * TODO: form-associated custom elements\n\t * @param element\n\t */\n\n\n\tfunction isLabelableElement(element) {\n\t  var localName = getLocalName(element);\n\t  return localName === \"button\" || localName === \"input\" && element.getAttribute(\"type\") !== \"hidden\" || localName === \"meter\" || localName === \"output\" || localName === \"progress\" || localName === \"select\" || localName === \"textarea\";\n\t}\n\t/**\n\t * > [...], then the first such descendant in tree order is the label element's labeled control.\n\t * -- https://html.spec.whatwg.org/multipage/forms.html#labeled-control\n\t * @param element\n\t */\n\n\n\tfunction findLabelableElement(element) {\n\t  if (isLabelableElement(element)) {\n\t    return element;\n\t  }\n\n\t  var labelableElement = null;\n\t  element.childNodes.forEach(function (childNode) {\n\t    if (labelableElement === null && isElement(childNode)) {\n\t      var descendantLabelableElement = findLabelableElement(childNode);\n\n\t      if (descendantLabelableElement !== null) {\n\t        labelableElement = descendantLabelableElement;\n\t      }\n\t    }\n\t  });\n\t  return labelableElement;\n\t}\n\t/**\n\t * Polyfill of HTMLLabelElement.control\n\t * https://html.spec.whatwg.org/multipage/forms.html#labeled-control\n\t * @param label\n\t */\n\n\n\tfunction getControlOfLabel(label) {\n\t  if (label.control !== undefined) {\n\t    return label.control;\n\t  }\n\n\t  var htmlFor = label.getAttribute(\"for\");\n\n\t  if (htmlFor !== null) {\n\t    return label.ownerDocument.getElementById(htmlFor);\n\t  }\n\n\t  return findLabelableElement(label);\n\t}\n\t/**\n\t * Polyfill of HTMLInputElement.labels\n\t * https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/labels\n\t * @param element\n\t */\n\n\n\tfunction getLabels(element) {\n\t  var labelsProperty = element.labels;\n\n\t  if (labelsProperty === null) {\n\t    return labelsProperty;\n\t  }\n\n\t  if (labelsProperty !== undefined) {\n\t    return arrayFrom(labelsProperty);\n\t  } // polyfill\n\n\n\t  if (!isLabelableElement(element)) {\n\t    return null;\n\t  }\n\n\t  var document = element.ownerDocument;\n\t  return arrayFrom(document.querySelectorAll(\"label\")).filter(function (label) {\n\t    return getControlOfLabel(label) === element;\n\t  });\n\t}\n\t/**\n\t * Gets the contents of a slot used for computing the accname\n\t * @param slot\n\t */\n\n\n\tfunction getSlotContents(slot) {\n\t  // Computing the accessible name for elements containing slots is not\n\t  // currently defined in the spec. This implementation reflects the\n\t  // behavior of NVDA 2020.2/Firefox 81 and iOS VoiceOver/Safari 13.6.\n\t  var assignedNodes = slot.assignedNodes();\n\n\t  if (assignedNodes.length === 0) {\n\t    // if no nodes are assigned to the slot, it displays the default content\n\t    return arrayFrom(slot.childNodes);\n\t  }\n\n\t  return assignedNodes;\n\t}\n\t/**\n\t * implements https://w3c.github.io/accname/#mapping_additional_nd_te\n\t * @param root\n\t * @param options\n\t * @returns\n\t */\n\n\n\tfunction computeTextAlternative(root) {\n\t  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\t  var consultedNodes = new SetLike$1();\n\t  var window = safeWindow(root);\n\t  var _options$compute = options.compute,\n\t      compute = _options$compute === void 0 ? \"name\" : _options$compute,\n\t      _options$computedStyl = options.computedStyleSupportsPseudoElements,\n\t      computedStyleSupportsPseudoElements = _options$computedStyl === void 0 ? options.getComputedStyle !== undefined : _options$computedStyl,\n\t      _options$getComputedS = options.getComputedStyle,\n\t      getComputedStyle = _options$getComputedS === void 0 ? window.getComputedStyle.bind(window) : _options$getComputedS,\n\t      _options$hidden = options.hidden,\n\t      hidden = _options$hidden === void 0 ? false : _options$hidden; // 2F.i\n\n\t  function computeMiscTextAlternative(node, context) {\n\t    var accumulatedText = \"\";\n\n\t    if (isElement(node) && computedStyleSupportsPseudoElements) {\n\t      var pseudoBefore = getComputedStyle(node, \"::before\");\n\t      var beforeContent = getTextualContent(pseudoBefore);\n\t      accumulatedText = \"\".concat(beforeContent, \" \").concat(accumulatedText);\n\t    } // FIXME: Including aria-owns is not defined in the spec\n\t    // But it is required in the web-platform-test\n\n\n\t    var childNodes = isHTMLSlotElement(node) ? getSlotContents(node) : arrayFrom(node.childNodes).concat(queryIdRefs(node, \"aria-owns\"));\n\t    childNodes.forEach(function (child) {\n\t      var result = computeTextAlternative(child, {\n\t        isEmbeddedInLabel: context.isEmbeddedInLabel,\n\t        isReferenced: false,\n\t        recursion: true\n\t      }); // TODO: Unclear why display affects delimiter\n\t      // see https://github.com/w3c/accname/issues/3\n\n\t      var display = isElement(child) ? getComputedStyle(child).getPropertyValue(\"display\") : \"inline\";\n\t      var separator = display !== \"inline\" ? \" \" : \"\"; // trailing separator for wpt tests\n\n\t      accumulatedText += \"\".concat(separator).concat(result).concat(separator);\n\t    });\n\n\t    if (isElement(node) && computedStyleSupportsPseudoElements) {\n\t      var pseudoAfter = getComputedStyle(node, \"::after\");\n\t      var afterContent = getTextualContent(pseudoAfter);\n\t      accumulatedText = \"\".concat(accumulatedText, \" \").concat(afterContent);\n\t    }\n\n\t    return accumulatedText.trim();\n\t  }\n\n\t  function computeElementTextAlternative(node) {\n\t    if (!isElement(node)) {\n\t      return null;\n\t    }\n\t    /**\n\t     *\n\t     * @param element\n\t     * @param attributeName\n\t     * @returns A string non-empty string or `null`\n\t     */\n\n\n\t    function useAttribute(element, attributeName) {\n\t      var attribute = element.getAttributeNode(attributeName);\n\n\t      if (attribute !== null && !consultedNodes.has(attribute) && attribute.value.trim() !== \"\") {\n\t        consultedNodes.add(attribute);\n\t        return attribute.value;\n\t      }\n\n\t      return null;\n\t    } // https://w3c.github.io/html-aam/#fieldset-and-legend-elements\n\n\n\t    if (isHTMLFieldSetElement(node)) {\n\t      consultedNodes.add(node);\n\t      var children = arrayFrom(node.childNodes);\n\n\t      for (var i = 0; i < children.length; i += 1) {\n\t        var child = children[i];\n\n\t        if (isHTMLLegendElement(child)) {\n\t          return computeTextAlternative(child, {\n\t            isEmbeddedInLabel: false,\n\t            isReferenced: false,\n\t            recursion: false\n\t          });\n\t        }\n\t      }\n\t    } else if (isHTMLTableElement(node)) {\n\t      // https://w3c.github.io/html-aam/#table-element\n\t      consultedNodes.add(node);\n\n\t      var _children = arrayFrom(node.childNodes);\n\n\t      for (var _i = 0; _i < _children.length; _i += 1) {\n\t        var _child = _children[_i];\n\n\t        if (isHTMLTableCaptionElement(_child)) {\n\t          return computeTextAlternative(_child, {\n\t            isEmbeddedInLabel: false,\n\t            isReferenced: false,\n\t            recursion: false\n\t          });\n\t        }\n\t      }\n\t    } else if (isSVGSVGElement(node)) {\n\t      // https://www.w3.org/TR/svg-aam-1.0/\n\t      consultedNodes.add(node);\n\n\t      var _children2 = arrayFrom(node.childNodes);\n\n\t      for (var _i2 = 0; _i2 < _children2.length; _i2 += 1) {\n\t        var _child2 = _children2[_i2];\n\n\t        if (isSVGTitleElement(_child2)) {\n\t          return _child2.textContent;\n\t        }\n\t      }\n\n\t      return null;\n\t    } else if (getLocalName(node) === \"img\" || getLocalName(node) === \"area\") {\n\t      // https://w3c.github.io/html-aam/#area-element\n\t      // https://w3c.github.io/html-aam/#img-element\n\t      var nameFromAlt = useAttribute(node, \"alt\");\n\n\t      if (nameFromAlt !== null) {\n\t        return nameFromAlt;\n\t      }\n\t    } else if (isHTMLOptGroupElement(node)) {\n\t      var nameFromLabel = useAttribute(node, \"label\");\n\n\t      if (nameFromLabel !== null) {\n\t        return nameFromLabel;\n\t      }\n\t    }\n\n\t    if (isHTMLInputElement(node) && (node.type === \"button\" || node.type === \"submit\" || node.type === \"reset\")) {\n\t      // https://w3c.github.io/html-aam/#input-type-text-input-type-password-input-type-search-input-type-tel-input-type-email-input-type-url-and-textarea-element-accessible-description-computation\n\t      var nameFromValue = useAttribute(node, \"value\");\n\n\t      if (nameFromValue !== null) {\n\t        return nameFromValue;\n\t      } // TODO: l10n\n\n\n\t      if (node.type === \"submit\") {\n\t        return \"Submit\";\n\t      } // TODO: l10n\n\n\n\t      if (node.type === \"reset\") {\n\t        return \"Reset\";\n\t      }\n\t    }\n\n\t    var labels = getLabels(node);\n\n\t    if (labels !== null && labels.length !== 0) {\n\t      consultedNodes.add(node);\n\t      return arrayFrom(labels).map(function (element) {\n\t        return computeTextAlternative(element, {\n\t          isEmbeddedInLabel: true,\n\t          isReferenced: false,\n\t          recursion: true\n\t        });\n\t      }).filter(function (label) {\n\t        return label.length > 0;\n\t      }).join(\" \");\n\t    } // https://w3c.github.io/html-aam/#input-type-image-accessible-name-computation\n\t    // TODO: wpt test consider label elements but html-aam does not mention them\n\t    // We follow existing implementations over spec\n\n\n\t    if (isHTMLInputElement(node) && node.type === \"image\") {\n\t      var _nameFromAlt = useAttribute(node, \"alt\");\n\n\t      if (_nameFromAlt !== null) {\n\t        return _nameFromAlt;\n\t      }\n\n\t      var nameFromTitle = useAttribute(node, \"title\");\n\n\t      if (nameFromTitle !== null) {\n\t        return nameFromTitle;\n\t      } // TODO: l10n\n\n\n\t      return \"Submit Query\";\n\t    }\n\n\t    if (hasAnyConcreteRoles(node, [\"button\"])) {\n\t      // https://www.w3.org/TR/html-aam-1.0/#button-element\n\t      var nameFromSubTree = computeMiscTextAlternative(node, {\n\t        isEmbeddedInLabel: false,\n\t        isReferenced: false\n\t      });\n\n\t      if (nameFromSubTree !== \"\") {\n\t        return nameFromSubTree;\n\t      }\n\n\t      return useAttribute(node, \"title\");\n\t    }\n\n\t    return useAttribute(node, \"title\");\n\t  }\n\n\t  function computeTextAlternative(current, context) {\n\t    if (consultedNodes.has(current)) {\n\t      return \"\";\n\t    } // 2A\n\n\n\t    if (!hidden && isHidden(current, getComputedStyle) && !context.isReferenced) {\n\t      consultedNodes.add(current);\n\t      return \"\";\n\t    } // 2B\n\n\n\t    var labelElements = queryIdRefs(current, \"aria-labelledby\");\n\n\t    if (compute === \"name\" && !context.isReferenced && labelElements.length > 0) {\n\t      return labelElements.map(function (element) {\n\t        return computeTextAlternative(element, {\n\t          isEmbeddedInLabel: context.isEmbeddedInLabel,\n\t          isReferenced: true,\n\t          // thais isn't recursion as specified, otherwise we would skip\n\t          // `aria-label` in\n\t          // <input id=\"myself\" aria-label=\"foo\" aria-labelledby=\"myself\"\n\t          recursion: false\n\t        });\n\t      }).join(\" \");\n\t    } // 2C\n\t    // Changed from the spec in anticipation of https://github.com/w3c/accname/issues/64\n\t    // spec says we should only consider skipping if we have a non-empty label\n\n\n\t    var skipToStep2E = context.recursion && isControl(current) && compute === \"name\";\n\n\t    if (!skipToStep2E) {\n\t      var ariaLabel = (isElement(current) && current.getAttribute(\"aria-label\") || \"\").trim();\n\n\t      if (ariaLabel !== \"\" && compute === \"name\") {\n\t        consultedNodes.add(current);\n\t        return ariaLabel;\n\t      } // 2D\n\n\n\t      if (!isMarkedPresentational(current)) {\n\t        var elementTextAlternative = computeElementTextAlternative(current);\n\n\t        if (elementTextAlternative !== null) {\n\t          consultedNodes.add(current);\n\t          return elementTextAlternative;\n\t        }\n\t      }\n\t    } // special casing, cheating to make tests pass\n\t    // https://github.com/w3c/accname/issues/67\n\n\n\t    if (hasAnyConcreteRoles(current, [\"menu\"])) {\n\t      consultedNodes.add(current);\n\t      return \"\";\n\t    } // 2E\n\n\n\t    if (skipToStep2E || context.isEmbeddedInLabel || context.isReferenced) {\n\t      if (hasAnyConcreteRoles(current, [\"combobox\", \"listbox\"])) {\n\t        consultedNodes.add(current);\n\t        var selectedOptions = querySelectedOptions(current);\n\n\t        if (selectedOptions.length === 0) {\n\t          // defined per test `name_heading_combobox`\n\t          return isHTMLInputElement(current) ? current.value : \"\";\n\t        }\n\n\t        return arrayFrom(selectedOptions).map(function (selectedOption) {\n\t          return computeTextAlternative(selectedOption, {\n\t            isEmbeddedInLabel: context.isEmbeddedInLabel,\n\t            isReferenced: false,\n\t            recursion: true\n\t          });\n\t        }).join(\" \");\n\t      }\n\n\t      if (hasAbstractRole(current, \"range\")) {\n\t        consultedNodes.add(current);\n\n\t        if (current.hasAttribute(\"aria-valuetext\")) {\n\t          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- safe due to hasAttribute guard\n\t          return current.getAttribute(\"aria-valuetext\");\n\t        }\n\n\t        if (current.hasAttribute(\"aria-valuenow\")) {\n\t          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- safe due to hasAttribute guard\n\t          return current.getAttribute(\"aria-valuenow\");\n\t        } // Otherwise, use the value as specified by a host language attribute.\n\n\n\t        return current.getAttribute(\"value\") || \"\";\n\t      }\n\n\t      if (hasAnyConcreteRoles(current, [\"textbox\"])) {\n\t        consultedNodes.add(current);\n\t        return getValueOfTextbox(current);\n\t      }\n\t    } // 2F: https://w3c.github.io/accname/#step2F\n\n\n\t    if (allowsNameFromContent(current) || isElement(current) && context.isReferenced || isNativeHostLanguageTextAlternativeElement(current) || isDescendantOfNativeHostLanguageTextAlternativeElement()) {\n\t      consultedNodes.add(current);\n\t      return computeMiscTextAlternative(current, {\n\t        isEmbeddedInLabel: context.isEmbeddedInLabel,\n\t        isReferenced: false\n\t      });\n\t    }\n\n\t    if (current.nodeType === current.TEXT_NODE) {\n\t      consultedNodes.add(current);\n\t      return current.textContent || \"\";\n\t    }\n\n\t    if (context.recursion) {\n\t      consultedNodes.add(current);\n\t      return computeMiscTextAlternative(current, {\n\t        isEmbeddedInLabel: context.isEmbeddedInLabel,\n\t        isReferenced: false\n\t      });\n\t    }\n\n\n\t    consultedNodes.add(current);\n\t    return \"\";\n\t  }\n\n\t  return asFlatString(computeTextAlternative(root, {\n\t    isEmbeddedInLabel: false,\n\t    // by spec computeAccessibleDescription starts with the referenced elements as roots\n\t    isReferenced: compute === \"description\",\n\t    recursion: false\n\t  }));\n\t}\n\n\tfunction ownKeys(object, enumerableOnly) {\n\t  var keys = Object.keys(object);\n\n\t  if (Object.getOwnPropertySymbols) {\n\t    var symbols = Object.getOwnPropertySymbols(object);\n\t    enumerableOnly && (symbols = symbols.filter(function (sym) {\n\t      return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n\t    })), keys.push.apply(keys, symbols);\n\t  }\n\n\t  return keys;\n\t}\n\n\tfunction _objectSpread(target) {\n\t  for (var i = 1; i < arguments.length; i++) {\n\t    var source = null != arguments[i] ? arguments[i] : {};\n\t    i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {\n\t      _defineProperty$1(target, key, source[key]);\n\t    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {\n\t      Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n\t    });\n\t  }\n\n\t  return target;\n\t}\n\n\tfunction _defineProperty$1(obj, key, value) {\n\t  if (key in obj) {\n\t    Object.defineProperty(obj, key, {\n\t      value: value,\n\t      enumerable: true,\n\t      configurable: true,\n\t      writable: true\n\t    });\n\t  } else {\n\t    obj[key] = value;\n\t  }\n\n\t  return obj;\n\t}\n\t/**\n\t * @param root\n\t * @param options\n\t * @returns\n\t */\n\n\tfunction computeAccessibleDescription(root) {\n\t  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\t  var description = queryIdRefs(root, \"aria-describedby\").map(function (element) {\n\t    return computeTextAlternative(element, _objectSpread(_objectSpread({}, options), {}, {\n\t      compute: \"description\"\n\t    }));\n\t  }).join(\" \"); // TODO: Technically we need to make sure that node wasn't used for the accessible name\n\t  //       This causes `description_1.0_combobox-focusable-manual` to fail\n\t  //\n\t  // https://www.w3.org/TR/html-aam-1.0/#accessible-name-and-description-computation\n\t  // says for so many elements to use the `title` that we assume all elements are considered\n\n\t  if (description === \"\") {\n\t    var title = root.getAttribute(\"title\");\n\t    description = title === null ? \"\" : title;\n\t  }\n\n\t  return description;\n\t}\n\n\t/**\n\t * https://w3c.github.io/aria/#namefromprohibited\n\t */\n\n\tfunction prohibitsNaming(node) {\n\t  return hasAnyConcreteRoles(node, [\"caption\", \"code\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"superscript\"]);\n\t}\n\t/**\n\t * implements https://w3c.github.io/accname/#mapping_additional_nd_name\n\t * @param root\n\t * @param options\n\t * @returns\n\t */\n\n\n\tfunction computeAccessibleName(root) {\n\t  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n\t  if (prohibitsNaming(root)) {\n\t    return \"\";\n\t  }\n\n\t  return computeTextAlternative(root, options);\n\t}\n\n\tvar lib = {};\n\n\tvar ariaPropsMap$1 = {};\n\n\tObject.defineProperty(ariaPropsMap$1, \"__esModule\", {\n\t  value: true\n\t});\n\tariaPropsMap$1.default = void 0;\n\n\tfunction _slicedToArray$4(arr, i) {\n\t  return _arrayWithHoles$4(arr) || _iterableToArrayLimit$4(arr, i) || _unsupportedIterableToArray$4(arr, i) || _nonIterableRest$4();\n\t}\n\n\tfunction _nonIterableRest$4() {\n\t  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t}\n\n\tfunction _unsupportedIterableToArray$4(o, minLen) {\n\t  if (!o) return;\n\t  if (typeof o === \"string\") return _arrayLikeToArray$4(o, minLen);\n\t  var n = Object.prototype.toString.call(o).slice(8, -1);\n\t  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$4(o, minLen);\n\t}\n\n\tfunction _arrayLikeToArray$4(arr, len) {\n\t  if (len == null || len > arr.length) len = arr.length;\n\n\t  for (var i = 0, arr2 = new Array(len); i < len; i++) {\n\t    arr2[i] = arr[i];\n\t  }\n\n\t  return arr2;\n\t}\n\n\tfunction _iterableToArrayLimit$4(arr, i) {\n\t  var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n\n\t  if (_i == null) return;\n\t  var _arr = [];\n\t  var _n = true;\n\t  var _d = false;\n\n\t  var _s, _e;\n\n\t  try {\n\t    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n\t      _arr.push(_s.value);\n\n\t      if (i && _arr.length === i) break;\n\t    }\n\t  } catch (err) {\n\t    _d = true;\n\t    _e = err;\n\t  } finally {\n\t    try {\n\t      if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n\t    } finally {\n\t      if (_d) throw _e;\n\t    }\n\t  }\n\n\t  return _arr;\n\t}\n\n\tfunction _arrayWithHoles$4(arr) {\n\t  if (Array.isArray(arr)) return arr;\n\t}\n\n\tvar properties = [['aria-activedescendant', {\n\t  'type': 'id'\n\t}], ['aria-atomic', {\n\t  'type': 'boolean'\n\t}], ['aria-autocomplete', {\n\t  'type': 'token',\n\t  'values': ['inline', 'list', 'both', 'none']\n\t}], ['aria-busy', {\n\t  'type': 'boolean'\n\t}], ['aria-checked', {\n\t  'type': 'tristate'\n\t}], ['aria-colcount', {\n\t  type: 'integer'\n\t}], ['aria-colindex', {\n\t  type: 'integer'\n\t}], ['aria-colspan', {\n\t  type: 'integer'\n\t}], ['aria-controls', {\n\t  'type': 'idlist'\n\t}], ['aria-current', {\n\t  type: 'token',\n\t  values: ['page', 'step', 'location', 'date', 'time', true, false]\n\t}], ['aria-describedby', {\n\t  'type': 'idlist'\n\t}], ['aria-details', {\n\t  'type': 'id'\n\t}], ['aria-disabled', {\n\t  'type': 'boolean'\n\t}], ['aria-dropeffect', {\n\t  'type': 'tokenlist',\n\t  'values': ['copy', 'execute', 'link', 'move', 'none', 'popup']\n\t}], ['aria-errormessage', {\n\t  'type': 'id'\n\t}], ['aria-expanded', {\n\t  'type': 'boolean',\n\t  'allowundefined': true\n\t}], ['aria-flowto', {\n\t  'type': 'idlist'\n\t}], ['aria-grabbed', {\n\t  'type': 'boolean',\n\t  'allowundefined': true\n\t}], ['aria-haspopup', {\n\t  'type': 'token',\n\t  'values': [false, true, 'menu', 'listbox', 'tree', 'grid', 'dialog']\n\t}], ['aria-hidden', {\n\t  'type': 'boolean',\n\t  'allowundefined': true\n\t}], ['aria-invalid', {\n\t  'type': 'token',\n\t  'values': ['grammar', false, 'spelling', true]\n\t}], ['aria-keyshortcuts', {\n\t  type: 'string'\n\t}], ['aria-label', {\n\t  'type': 'string'\n\t}], ['aria-labelledby', {\n\t  'type': 'idlist'\n\t}], ['aria-level', {\n\t  'type': 'integer'\n\t}], ['aria-live', {\n\t  'type': 'token',\n\t  'values': ['assertive', 'off', 'polite']\n\t}], ['aria-modal', {\n\t  type: 'boolean'\n\t}], ['aria-multiline', {\n\t  'type': 'boolean'\n\t}], ['aria-multiselectable', {\n\t  'type': 'boolean'\n\t}], ['aria-orientation', {\n\t  'type': 'token',\n\t  'values': ['vertical', 'undefined', 'horizontal']\n\t}], ['aria-owns', {\n\t  'type': 'idlist'\n\t}], ['aria-placeholder', {\n\t  type: 'string'\n\t}], ['aria-posinset', {\n\t  'type': 'integer'\n\t}], ['aria-pressed', {\n\t  'type': 'tristate'\n\t}], ['aria-readonly', {\n\t  'type': 'boolean'\n\t}], ['aria-relevant', {\n\t  'type': 'tokenlist',\n\t  'values': ['additions', 'all', 'removals', 'text']\n\t}], ['aria-required', {\n\t  'type': 'boolean'\n\t}], ['aria-roledescription', {\n\t  type: 'string'\n\t}], ['aria-rowcount', {\n\t  type: 'integer'\n\t}], ['aria-rowindex', {\n\t  type: 'integer'\n\t}], ['aria-rowspan', {\n\t  type: 'integer'\n\t}], ['aria-selected', {\n\t  'type': 'boolean',\n\t  'allowundefined': true\n\t}], ['aria-setsize', {\n\t  'type': 'integer'\n\t}], ['aria-sort', {\n\t  'type': 'token',\n\t  'values': ['ascending', 'descending', 'none', 'other']\n\t}], ['aria-valuemax', {\n\t  'type': 'number'\n\t}], ['aria-valuemin', {\n\t  'type': 'number'\n\t}], ['aria-valuenow', {\n\t  'type': 'number'\n\t}], ['aria-valuetext', {\n\t  'type': 'string'\n\t}]];\n\tvar ariaPropsMap = {\n\t  entries: function entries() {\n\t    return properties;\n\t  },\n\t  get: function get(key) {\n\t    var item = properties.find(function (tuple) {\n\t      return tuple[0] === key ? true : false;\n\t    });\n\t    return item && item[1];\n\t  },\n\t  has: function has(key) {\n\t    return !!this.get(key);\n\t  },\n\t  keys: function keys() {\n\t    return properties.map(function (_ref) {\n\t      var _ref2 = _slicedToArray$4(_ref, 1),\n\t          key = _ref2[0];\n\n\t      return key;\n\t    });\n\t  },\n\t  values: function values() {\n\t    return properties.map(function (_ref3) {\n\t      var _ref4 = _slicedToArray$4(_ref3, 2),\n\t          values = _ref4[1];\n\n\t      return values;\n\t    });\n\t  }\n\t};\n\tvar _default$2c = ariaPropsMap;\n\tariaPropsMap$1.default = _default$2c;\n\n\tvar domMap$1 = {};\n\n\tObject.defineProperty(domMap$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdomMap$1.default = void 0;\n\n\tfunction _slicedToArray$3(arr, i) {\n\t  return _arrayWithHoles$3(arr) || _iterableToArrayLimit$3(arr, i) || _unsupportedIterableToArray$3(arr, i) || _nonIterableRest$3();\n\t}\n\n\tfunction _nonIterableRest$3() {\n\t  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t}\n\n\tfunction _unsupportedIterableToArray$3(o, minLen) {\n\t  if (!o) return;\n\t  if (typeof o === \"string\") return _arrayLikeToArray$3(o, minLen);\n\t  var n = Object.prototype.toString.call(o).slice(8, -1);\n\t  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$3(o, minLen);\n\t}\n\n\tfunction _arrayLikeToArray$3(arr, len) {\n\t  if (len == null || len > arr.length) len = arr.length;\n\n\t  for (var i = 0, arr2 = new Array(len); i < len; i++) {\n\t    arr2[i] = arr[i];\n\t  }\n\n\t  return arr2;\n\t}\n\n\tfunction _iterableToArrayLimit$3(arr, i) {\n\t  var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n\n\t  if (_i == null) return;\n\t  var _arr = [];\n\t  var _n = true;\n\t  var _d = false;\n\n\t  var _s, _e;\n\n\t  try {\n\t    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n\t      _arr.push(_s.value);\n\n\t      if (i && _arr.length === i) break;\n\t    }\n\t  } catch (err) {\n\t    _d = true;\n\t    _e = err;\n\t  } finally {\n\t    try {\n\t      if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n\t    } finally {\n\t      if (_d) throw _e;\n\t    }\n\t  }\n\n\t  return _arr;\n\t}\n\n\tfunction _arrayWithHoles$3(arr) {\n\t  if (Array.isArray(arr)) return arr;\n\t}\n\n\tvar dom$1 = [['a', {\n\t  reserved: false\n\t}], ['abbr', {\n\t  reserved: false\n\t}], ['acronym', {\n\t  reserved: false\n\t}], ['address', {\n\t  reserved: false\n\t}], ['applet', {\n\t  reserved: false\n\t}], ['area', {\n\t  reserved: false\n\t}], ['article', {\n\t  reserved: false\n\t}], ['aside', {\n\t  reserved: false\n\t}], ['audio', {\n\t  reserved: false\n\t}], ['b', {\n\t  reserved: false\n\t}], ['base', {\n\t  reserved: true\n\t}], ['bdi', {\n\t  reserved: false\n\t}], ['bdo', {\n\t  reserved: false\n\t}], ['big', {\n\t  reserved: false\n\t}], ['blink', {\n\t  reserved: false\n\t}], ['blockquote', {\n\t  reserved: false\n\t}], ['body', {\n\t  reserved: false\n\t}], ['br', {\n\t  reserved: false\n\t}], ['button', {\n\t  reserved: false\n\t}], ['canvas', {\n\t  reserved: false\n\t}], ['caption', {\n\t  reserved: false\n\t}], ['center', {\n\t  reserved: false\n\t}], ['cite', {\n\t  reserved: false\n\t}], ['code', {\n\t  reserved: false\n\t}], ['col', {\n\t  reserved: true\n\t}], ['colgroup', {\n\t  reserved: true\n\t}], ['content', {\n\t  reserved: false\n\t}], ['data', {\n\t  reserved: false\n\t}], ['datalist', {\n\t  reserved: false\n\t}], ['dd', {\n\t  reserved: false\n\t}], ['del', {\n\t  reserved: false\n\t}], ['details', {\n\t  reserved: false\n\t}], ['dfn', {\n\t  reserved: false\n\t}], ['dialog', {\n\t  reserved: false\n\t}], ['dir', {\n\t  reserved: false\n\t}], ['div', {\n\t  reserved: false\n\t}], ['dl', {\n\t  reserved: false\n\t}], ['dt', {\n\t  reserved: false\n\t}], ['em', {\n\t  reserved: false\n\t}], ['embed', {\n\t  reserved: false\n\t}], ['fieldset', {\n\t  reserved: false\n\t}], ['figcaption', {\n\t  reserved: false\n\t}], ['figure', {\n\t  reserved: false\n\t}], ['font', {\n\t  reserved: false\n\t}], ['footer', {\n\t  reserved: false\n\t}], ['form', {\n\t  reserved: false\n\t}], ['frame', {\n\t  reserved: false\n\t}], ['frameset', {\n\t  reserved: false\n\t}], ['h1', {\n\t  reserved: false\n\t}], ['h2', {\n\t  reserved: false\n\t}], ['h3', {\n\t  reserved: false\n\t}], ['h4', {\n\t  reserved: false\n\t}], ['h5', {\n\t  reserved: false\n\t}], ['h6', {\n\t  reserved: false\n\t}], ['head', {\n\t  reserved: true\n\t}], ['header', {\n\t  reserved: false\n\t}], ['hgroup', {\n\t  reserved: false\n\t}], ['hr', {\n\t  reserved: false\n\t}], ['html', {\n\t  reserved: true\n\t}], ['i', {\n\t  reserved: false\n\t}], ['iframe', {\n\t  reserved: false\n\t}], ['img', {\n\t  reserved: false\n\t}], ['input', {\n\t  reserved: false\n\t}], ['ins', {\n\t  reserved: false\n\t}], ['kbd', {\n\t  reserved: false\n\t}], ['keygen', {\n\t  reserved: false\n\t}], ['label', {\n\t  reserved: false\n\t}], ['legend', {\n\t  reserved: false\n\t}], ['li', {\n\t  reserved: false\n\t}], ['link', {\n\t  reserved: true\n\t}], ['main', {\n\t  reserved: false\n\t}], ['map', {\n\t  reserved: false\n\t}], ['mark', {\n\t  reserved: false\n\t}], ['marquee', {\n\t  reserved: false\n\t}], ['menu', {\n\t  reserved: false\n\t}], ['menuitem', {\n\t  reserved: false\n\t}], ['meta', {\n\t  reserved: true\n\t}], ['meter', {\n\t  reserved: false\n\t}], ['nav', {\n\t  reserved: false\n\t}], ['noembed', {\n\t  reserved: true\n\t}], ['noscript', {\n\t  reserved: true\n\t}], ['object', {\n\t  reserved: false\n\t}], ['ol', {\n\t  reserved: false\n\t}], ['optgroup', {\n\t  reserved: false\n\t}], ['option', {\n\t  reserved: false\n\t}], ['output', {\n\t  reserved: false\n\t}], ['p', {\n\t  reserved: false\n\t}], ['param', {\n\t  reserved: true\n\t}], ['picture', {\n\t  reserved: true\n\t}], ['pre', {\n\t  reserved: false\n\t}], ['progress', {\n\t  reserved: false\n\t}], ['q', {\n\t  reserved: false\n\t}], ['rp', {\n\t  reserved: false\n\t}], ['rt', {\n\t  reserved: false\n\t}], ['rtc', {\n\t  reserved: false\n\t}], ['ruby', {\n\t  reserved: false\n\t}], ['s', {\n\t  reserved: false\n\t}], ['samp', {\n\t  reserved: false\n\t}], ['script', {\n\t  reserved: true\n\t}], ['section', {\n\t  reserved: false\n\t}], ['select', {\n\t  reserved: false\n\t}], ['small', {\n\t  reserved: false\n\t}], ['source', {\n\t  reserved: true\n\t}], ['spacer', {\n\t  reserved: false\n\t}], ['span', {\n\t  reserved: false\n\t}], ['strike', {\n\t  reserved: false\n\t}], ['strong', {\n\t  reserved: false\n\t}], ['style', {\n\t  reserved: true\n\t}], ['sub', {\n\t  reserved: false\n\t}], ['summary', {\n\t  reserved: false\n\t}], ['sup', {\n\t  reserved: false\n\t}], ['table', {\n\t  reserved: false\n\t}], ['tbody', {\n\t  reserved: false\n\t}], ['td', {\n\t  reserved: false\n\t}], ['textarea', {\n\t  reserved: false\n\t}], ['tfoot', {\n\t  reserved: false\n\t}], ['th', {\n\t  reserved: false\n\t}], ['thead', {\n\t  reserved: false\n\t}], ['time', {\n\t  reserved: false\n\t}], ['title', {\n\t  reserved: true\n\t}], ['tr', {\n\t  reserved: false\n\t}], ['track', {\n\t  reserved: true\n\t}], ['tt', {\n\t  reserved: false\n\t}], ['u', {\n\t  reserved: false\n\t}], ['ul', {\n\t  reserved: false\n\t}], ['var', {\n\t  reserved: false\n\t}], ['video', {\n\t  reserved: false\n\t}], ['wbr', {\n\t  reserved: false\n\t}], ['xmp', {\n\t  reserved: false\n\t}]];\n\tvar domMap = {\n\t  entries: function entries() {\n\t    return dom$1;\n\t  },\n\t  get: function get(key) {\n\t    var item = dom$1.find(function (tuple) {\n\t      return tuple[0] === key ? true : false;\n\t    });\n\t    return item && item[1];\n\t  },\n\t  has: function has(key) {\n\t    return !!this.get(key);\n\t  },\n\t  keys: function keys() {\n\t    return dom$1.map(function (_ref) {\n\t      var _ref2 = _slicedToArray$3(_ref, 1),\n\t          key = _ref2[0];\n\n\t      return key;\n\t    });\n\t  },\n\t  values: function values() {\n\t    return dom$1.map(function (_ref3) {\n\t      var _ref4 = _slicedToArray$3(_ref3, 2),\n\t          values = _ref4[1];\n\n\t      return values;\n\t    });\n\t  }\n\t};\n\tvar _default$2b = domMap;\n\tdomMap$1.default = _default$2b;\n\n\tvar rolesMap$1 = {};\n\n\tvar ariaAbstractRoles$1 = {};\n\n\tvar commandRole$1 = {};\n\n\tObject.defineProperty(commandRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcommandRole$1.default = void 0;\n\tvar commandRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'menuitem'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget']]\n\t};\n\tvar _default$2a = commandRole;\n\tcommandRole$1.default = _default$2a;\n\n\tvar compositeRole$1 = {};\n\n\tObject.defineProperty(compositeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcompositeRole$1.default = void 0;\n\tvar compositeRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-activedescendant': null,\n\t    'aria-disabled': null\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget']]\n\t};\n\tvar _default$29 = compositeRole;\n\tcompositeRole$1.default = _default$29;\n\n\tvar inputRole$1 = {};\n\n\tObject.defineProperty(inputRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tinputRole$1.default = void 0;\n\tvar inputRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'input'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget']]\n\t};\n\tvar _default$28 = inputRole;\n\tinputRole$1.default = _default$28;\n\n\tvar landmarkRole$1 = {};\n\n\tObject.defineProperty(landmarkRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tlandmarkRole$1.default = void 0;\n\tvar landmarkRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$27 = landmarkRole;\n\tlandmarkRole$1.default = _default$27;\n\n\tvar rangeRole$1 = {};\n\n\tObject.defineProperty(rangeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\trangeRole$1.default = void 0;\n\tvar rangeRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-valuemax': null,\n\t    'aria-valuemin': null,\n\t    'aria-valuenow': null\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$26 = rangeRole;\n\trangeRole$1.default = _default$26;\n\n\tvar roletypeRole$1 = {};\n\n\tObject.defineProperty(roletypeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\troletypeRole$1.default = void 0;\n\tvar roletypeRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: [],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-atomic': null,\n\t    'aria-busy': null,\n\t    'aria-controls': null,\n\t    'aria-current': null,\n\t    'aria-describedby': null,\n\t    'aria-details': null,\n\t    'aria-dropeffect': null,\n\t    'aria-flowto': null,\n\t    'aria-grabbed': null,\n\t    'aria-hidden': null,\n\t    'aria-keyshortcuts': null,\n\t    'aria-label': null,\n\t    'aria-labelledby': null,\n\t    'aria-live': null,\n\t    'aria-owns': null,\n\t    'aria-relevant': null,\n\t    'aria-roledescription': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'rel'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'role'\n\t    },\n\t    module: 'XHTML'\n\t  }, {\n\t    concept: {\n\t      name: 'type'\n\t    },\n\t    module: 'Dublin Core'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: []\n\t};\n\tvar _default$25 = roletypeRole;\n\troletypeRole$1.default = _default$25;\n\n\tvar sectionRole$1 = {};\n\n\tObject.defineProperty(sectionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsectionRole$1.default = void 0;\n\tvar sectionRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: [],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'frontmatter'\n\t    },\n\t    module: 'DTB'\n\t  }, {\n\t    concept: {\n\t      name: 'level'\n\t    },\n\t    module: 'DTB'\n\t  }, {\n\t    concept: {\n\t      name: 'level'\n\t    },\n\t    module: 'SMIL'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$24 = sectionRole;\n\tsectionRole$1.default = _default$24;\n\n\tvar sectionheadRole$1 = {};\n\n\tObject.defineProperty(sectionheadRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsectionheadRole$1.default = void 0;\n\tvar sectionheadRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$23 = sectionheadRole;\n\tsectionheadRole$1.default = _default$23;\n\n\tvar selectRole$1 = {};\n\n\tObject.defineProperty(selectRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tselectRole$1.default = void 0;\n\tvar selectRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-orientation': null\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite'], ['roletype', 'structure', 'section', 'group']]\n\t};\n\tvar _default$22 = selectRole;\n\tselectRole$1.default = _default$22;\n\n\tvar structureRole$1 = {};\n\n\tObject.defineProperty(structureRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tstructureRole$1.default = void 0;\n\tvar structureRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: [],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype']]\n\t};\n\tvar _default$21 = structureRole;\n\tstructureRole$1.default = _default$21;\n\n\tvar widgetRole$1 = {};\n\n\tObject.defineProperty(widgetRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\twidgetRole$1.default = void 0;\n\tvar widgetRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: [],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype']]\n\t};\n\tvar _default$20 = widgetRole;\n\twidgetRole$1.default = _default$20;\n\n\tvar windowRole$1 = {};\n\n\tObject.defineProperty(windowRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\twindowRole$1.default = void 0;\n\tvar windowRole = {\n\t  abstract: true,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-modal': null\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype']]\n\t};\n\tvar _default$1$ = windowRole;\n\twindowRole$1.default = _default$1$;\n\n\tObject.defineProperty(ariaAbstractRoles$1, \"__esModule\", {\n\t  value: true\n\t});\n\tariaAbstractRoles$1.default = void 0;\n\n\tvar _commandRole = _interopRequireDefault$6(commandRole$1);\n\n\tvar _compositeRole = _interopRequireDefault$6(compositeRole$1);\n\n\tvar _inputRole = _interopRequireDefault$6(inputRole$1);\n\n\tvar _landmarkRole = _interopRequireDefault$6(landmarkRole$1);\n\n\tvar _rangeRole = _interopRequireDefault$6(rangeRole$1);\n\n\tvar _roletypeRole = _interopRequireDefault$6(roletypeRole$1);\n\n\tvar _sectionRole = _interopRequireDefault$6(sectionRole$1);\n\n\tvar _sectionheadRole = _interopRequireDefault$6(sectionheadRole$1);\n\n\tvar _selectRole = _interopRequireDefault$6(selectRole$1);\n\n\tvar _structureRole = _interopRequireDefault$6(structureRole$1);\n\n\tvar _widgetRole = _interopRequireDefault$6(widgetRole$1);\n\n\tvar _windowRole = _interopRequireDefault$6(windowRole$1);\n\n\tfunction _interopRequireDefault$6(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tvar ariaAbstractRoles = [['command', _commandRole.default], ['composite', _compositeRole.default], ['input', _inputRole.default], ['landmark', _landmarkRole.default], ['range', _rangeRole.default], ['roletype', _roletypeRole.default], ['section', _sectionRole.default], ['sectionhead', _sectionheadRole.default], ['select', _selectRole.default], ['structure', _structureRole.default], ['widget', _widgetRole.default], ['window', _windowRole.default]];\n\tvar _default$1_ = ariaAbstractRoles;\n\tariaAbstractRoles$1.default = _default$1_;\n\n\tvar ariaLiteralRoles$1 = {};\n\n\tvar alertRole$1 = {};\n\n\tObject.defineProperty(alertRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\talertRole$1.default = void 0;\n\tvar alertRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-atomic': 'true',\n\t    'aria-live': 'assertive'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'alert'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1Z = alertRole;\n\talertRole$1.default = _default$1Z;\n\n\tvar alertdialogRole$1 = {};\n\n\tObject.defineProperty(alertdialogRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\talertdialogRole$1.default = void 0;\n\tvar alertdialogRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'alert'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'alert'], ['roletype', 'window', 'dialog']]\n\t};\n\tvar _default$1Y = alertdialogRole;\n\talertdialogRole$1.default = _default$1Y;\n\n\tvar applicationRole$1 = {};\n\n\tObject.defineProperty(applicationRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tapplicationRole$1.default = void 0;\n\tvar applicationRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-activedescendant': null,\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'Device Independence Delivery Unit'\n\t    }\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$1X = applicationRole;\n\tapplicationRole$1.default = _default$1X;\n\n\tvar articleRole$1 = {};\n\n\tObject.defineProperty(articleRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tarticleRole$1.default = void 0;\n\tvar articleRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-posinset': null,\n\t    'aria-setsize': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'article'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'document']]\n\t};\n\tvar _default$1W = articleRole;\n\tarticleRole$1.default = _default$1W;\n\n\tvar bannerRole$1 = {};\n\n\tObject.defineProperty(bannerRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tbannerRole$1.default = void 0;\n\tvar bannerRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      constraints: ['direct descendant of document'],\n\t      name: 'header'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$1V = bannerRole;\n\tbannerRole$1.default = _default$1V;\n\n\tvar blockquoteRole$1 = {};\n\n\tObject.defineProperty(blockquoteRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tblockquoteRole$1.default = void 0;\n\tvar blockquoteRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1U = blockquoteRole;\n\tblockquoteRole$1.default = _default$1U;\n\n\tvar buttonRole$1 = {};\n\n\tObject.defineProperty(buttonRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tbuttonRole$1.default = void 0;\n\tvar buttonRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-pressed': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'aria-pressed'\n\t      }, {\n\t        name: 'type',\n\t        value: 'checkbox'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'aria-expanded',\n\t        value: 'false'\n\t      }],\n\t      name: 'summary'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'aria-expanded',\n\t        value: 'true'\n\t      }],\n\t      constraints: ['direct descendant of details element with the open attribute defined'],\n\t      name: 'summary'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'button'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'image'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'reset'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'submit'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'button'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'trigger'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command']]\n\t};\n\tvar _default$1T = buttonRole;\n\tbuttonRole$1.default = _default$1T;\n\n\tvar captionRole$1 = {};\n\n\tObject.defineProperty(captionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcaptionRole$1.default = void 0;\n\tvar captionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: ['figure', 'grid', 'table'],\n\t  requiredContextRole: ['figure', 'grid', 'table'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1S = captionRole;\n\tcaptionRole$1.default = _default$1S;\n\n\tvar cellRole$1 = {};\n\n\tObject.defineProperty(cellRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcellRole$1.default = void 0;\n\tvar cellRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-colindex': null,\n\t    'aria-colspan': null,\n\t    'aria-rowindex': null,\n\t    'aria-rowspan': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      constraints: ['descendant of table'],\n\t      name: 'td'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: ['row'],\n\t  requiredContextRole: ['row'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1R = cellRole;\n\tcellRole$1.default = _default$1R;\n\n\tvar checkboxRole$1 = {};\n\n\tObject.defineProperty(checkboxRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcheckboxRole$1.default = void 0;\n\tvar checkboxRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-checked': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-invalid': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'checkbox'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'option'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-checked': null\n\t  },\n\t  superClass: [['roletype', 'widget', 'input']]\n\t};\n\tvar _default$1Q = checkboxRole;\n\tcheckboxRole$1.default = _default$1Q;\n\n\tvar codeRole$1 = {};\n\n\tObject.defineProperty(codeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcodeRole$1.default = void 0;\n\tvar codeRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1P = codeRole;\n\tcodeRole$1.default = _default$1P;\n\n\tvar columnheaderRole$1 = {};\n\n\tObject.defineProperty(columnheaderRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcolumnheaderRole$1.default = void 0;\n\tvar columnheaderRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-sort': null\n\t  },\n\t  relatedConcepts: [{\n\t    attributes: [{\n\t      name: 'scope',\n\t      value: 'col'\n\t    }],\n\t    concept: {\n\t      name: 'th'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: ['row'],\n\t  requiredContextRole: ['row'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'cell'], ['roletype', 'structure', 'section', 'cell', 'gridcell'], ['roletype', 'widget', 'gridcell'], ['roletype', 'structure', 'sectionhead']]\n\t};\n\tvar _default$1O = columnheaderRole;\n\tcolumnheaderRole$1.default = _default$1O;\n\n\tvar comboboxRole$1 = {};\n\n\tObject.defineProperty(comboboxRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcomboboxRole$1.default = void 0;\n\tvar comboboxRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-activedescendant': null,\n\t    'aria-autocomplete': null,\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null,\n\t    'aria-expanded': 'false',\n\t    'aria-haspopup': 'listbox'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'email'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'search'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'tel'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'text'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'url'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'url'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'multiple'\n\t      }, {\n\t        constraints: ['undefined'],\n\t        name: 'size'\n\t      }],\n\t      name: 'select'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'multiple'\n\t      }, {\n\t        name: 'size',\n\t        value: 1\n\t      }],\n\t      name: 'select'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'select'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-controls': null,\n\t    'aria-expanded': 'false'\n\t  },\n\t  superClass: [['roletype', 'widget', 'input']]\n\t};\n\tvar _default$1N = comboboxRole;\n\tcomboboxRole$1.default = _default$1N;\n\n\tvar complementaryRole$1 = {};\n\n\tObject.defineProperty(complementaryRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcomplementaryRole$1.default = void 0;\n\tvar complementaryRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'aside'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$1M = complementaryRole;\n\tcomplementaryRole$1.default = _default$1M;\n\n\tvar contentinfoRole$1 = {};\n\n\tObject.defineProperty(contentinfoRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tcontentinfoRole$1.default = void 0;\n\tvar contentinfoRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      constraints: ['direct descendant of document'],\n\t      name: 'footer'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$1L = contentinfoRole;\n\tcontentinfoRole$1.default = _default$1L;\n\n\tvar definitionRole$1 = {};\n\n\tObject.defineProperty(definitionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdefinitionRole$1.default = void 0;\n\tvar definitionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'dd'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1K = definitionRole;\n\tdefinitionRole$1.default = _default$1K;\n\n\tvar deletionRole$1 = {};\n\n\tObject.defineProperty(deletionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdeletionRole$1.default = void 0;\n\tvar deletionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1J = deletionRole;\n\tdeletionRole$1.default = _default$1J;\n\n\tvar dialogRole$1 = {};\n\n\tObject.defineProperty(dialogRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdialogRole$1.default = void 0;\n\tvar dialogRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'dialog'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'window']]\n\t};\n\tvar _default$1I = dialogRole;\n\tdialogRole$1.default = _default$1I;\n\n\tvar directoryRole$1 = {};\n\n\tObject.defineProperty(directoryRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdirectoryRole$1.default = void 0;\n\tvar directoryRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    module: 'DAISY Guide'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'list']]\n\t};\n\tvar _default$1H = directoryRole;\n\tdirectoryRole$1.default = _default$1H;\n\n\tvar documentRole$1 = {};\n\n\tObject.defineProperty(documentRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocumentRole$1.default = void 0;\n\tvar documentRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'Device Independence Delivery Unit'\n\t    }\n\t  }, {\n\t    concept: {\n\t      name: 'body'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$1G = documentRole;\n\tdocumentRole$1.default = _default$1G;\n\n\tvar emphasisRole$1 = {};\n\n\tObject.defineProperty(emphasisRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\temphasisRole$1.default = void 0;\n\tvar emphasisRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1F = emphasisRole;\n\temphasisRole$1.default = _default$1F;\n\n\tvar feedRole$1 = {};\n\n\tObject.defineProperty(feedRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tfeedRole$1.default = void 0;\n\tvar feedRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['article']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'list']]\n\t};\n\tvar _default$1E = feedRole;\n\tfeedRole$1.default = _default$1E;\n\n\tvar figureRole$1 = {};\n\n\tObject.defineProperty(figureRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tfigureRole$1.default = void 0;\n\tvar figureRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'figure'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1D = figureRole;\n\tfigureRole$1.default = _default$1D;\n\n\tvar formRole$1 = {};\n\n\tObject.defineProperty(formRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tformRole$1.default = void 0;\n\tvar formRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'aria-label'\n\t      }],\n\t      name: 'form'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'aria-labelledby'\n\t      }],\n\t      name: 'form'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'name'\n\t      }],\n\t      name: 'form'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$1C = formRole;\n\tformRole$1.default = _default$1C;\n\n\tvar genericRole$1 = {};\n\n\tObject.defineProperty(genericRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tgenericRole$1.default = void 0;\n\tvar genericRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'span'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'div'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$1B = genericRole;\n\tgenericRole$1.default = _default$1B;\n\n\tvar gridRole$1 = {};\n\n\tObject.defineProperty(gridRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tgridRole$1.default = void 0;\n\tvar gridRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-multiselectable': null,\n\t    'aria-readonly': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'role',\n\t        value: 'grid'\n\t      }],\n\t      name: 'table'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['row'], ['row', 'rowgroup']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite'], ['roletype', 'structure', 'section', 'table']]\n\t};\n\tvar _default$1A = gridRole;\n\tgridRole$1.default = _default$1A;\n\n\tvar gridcellRole$1 = {};\n\n\tObject.defineProperty(gridcellRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tgridcellRole$1.default = void 0;\n\tvar gridcellRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null,\n\t    'aria-selected': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'role',\n\t        value: 'gridcell'\n\t      }],\n\t      name: 'td'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: ['row'],\n\t  requiredContextRole: ['row'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'cell'], ['roletype', 'widget']]\n\t};\n\tvar _default$1z = gridcellRole;\n\tgridcellRole$1.default = _default$1z;\n\n\tvar groupRole$1 = {};\n\n\tObject.defineProperty(groupRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tgroupRole$1.default = void 0;\n\tvar groupRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-activedescendant': null,\n\t    'aria-disabled': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'details'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'fieldset'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'optgroup'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1y = groupRole;\n\tgroupRole$1.default = _default$1y;\n\n\tvar headingRole$1 = {};\n\n\tObject.defineProperty(headingRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\theadingRole$1.default = void 0;\n\tvar headingRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-level': '2'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'h1'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'h2'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'h3'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'h4'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'h5'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'h6'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-level': '2'\n\t  },\n\t  superClass: [['roletype', 'structure', 'sectionhead']]\n\t};\n\tvar _default$1x = headingRole;\n\theadingRole$1.default = _default$1x;\n\n\tvar imgRole$1 = {};\n\n\tObject.defineProperty(imgRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\timgRole$1.default = void 0;\n\tvar imgRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'alt'\n\t      }],\n\t      name: 'img'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'alt'\n\t      }],\n\t      name: 'img'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'imggroup'\n\t    },\n\t    module: 'DTB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1w = imgRole;\n\timgRole$1.default = _default$1w;\n\n\tvar insertionRole$1 = {};\n\n\tObject.defineProperty(insertionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tinsertionRole$1.default = void 0;\n\tvar insertionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1v = insertionRole;\n\tinsertionRole$1.default = _default$1v;\n\n\tvar linkRole$1 = {};\n\n\tObject.defineProperty(linkRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tlinkRole$1.default = void 0;\n\tvar linkRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'href'\n\t      }],\n\t      name: 'a'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'href'\n\t      }],\n\t      name: 'area'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'href'\n\t      }],\n\t      name: 'link'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command']]\n\t};\n\tvar _default$1u = linkRole;\n\tlinkRole$1.default = _default$1u;\n\n\tvar listRole$1 = {};\n\n\tObject.defineProperty(listRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tlistRole$1.default = void 0;\n\tvar listRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'menu'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'ol'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'ul'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['listitem']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1t = listRole;\n\tlistRole$1.default = _default$1t;\n\n\tvar listboxRole$1 = {};\n\n\tObject.defineProperty(listboxRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tlistboxRole$1.default = void 0;\n\tvar listboxRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-invalid': null,\n\t    'aria-multiselectable': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null,\n\t    'aria-orientation': 'vertical'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['>1'],\n\t        name: 'size'\n\t      }, {\n\t        name: 'multiple'\n\t      }],\n\t      name: 'select'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['>1'],\n\t        name: 'size'\n\t      }],\n\t      name: 'select'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        name: 'multiple'\n\t      }],\n\t      name: 'select'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'datalist'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'list'\n\t    },\n\t    module: 'ARIA'\n\t  }, {\n\t    concept: {\n\t      name: 'select'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['option', 'group'], ['option']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite', 'select'], ['roletype', 'structure', 'section', 'group', 'select']]\n\t};\n\tvar _default$1s = listboxRole;\n\tlistboxRole$1.default = _default$1s;\n\n\tvar listitemRole$1 = {};\n\n\tObject.defineProperty(listitemRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tlistitemRole$1.default = void 0;\n\tvar listitemRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-level': null,\n\t    'aria-posinset': null,\n\t    'aria-setsize': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      constraints: ['direct descendant of ol, ul or menu'],\n\t      name: 'li'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'item'\n\t    },\n\t    module: 'XForms'\n\t  }],\n\t  requireContextRole: ['directory', 'list'],\n\t  requiredContextRole: ['directory', 'list'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1r = listitemRole;\n\tlistitemRole$1.default = _default$1r;\n\n\tvar logRole$1 = {};\n\n\tObject.defineProperty(logRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tlogRole$1.default = void 0;\n\tvar logRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-live': 'polite'\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1q = logRole;\n\tlogRole$1.default = _default$1q;\n\n\tvar mainRole$1 = {};\n\n\tObject.defineProperty(mainRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmainRole$1.default = void 0;\n\tvar mainRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'main'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$1p = mainRole;\n\tmainRole$1.default = _default$1p;\n\n\tvar marqueeRole$1 = {};\n\n\tObject.defineProperty(marqueeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmarqueeRole$1.default = void 0;\n\tvar marqueeRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1o = marqueeRole;\n\tmarqueeRole$1.default = _default$1o;\n\n\tvar mathRole$1 = {};\n\n\tObject.defineProperty(mathRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmathRole$1.default = void 0;\n\tvar mathRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'math'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1n = mathRole;\n\tmathRole$1.default = _default$1n;\n\n\tvar menuRole$1 = {};\n\n\tObject.defineProperty(menuRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmenuRole$1.default = void 0;\n\tvar menuRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-orientation': 'vertical'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'MENU'\n\t    },\n\t    module: 'JAPI'\n\t  }, {\n\t    concept: {\n\t      name: 'list'\n\t    },\n\t    module: 'ARIA'\n\t  }, {\n\t    concept: {\n\t      name: 'select'\n\t    },\n\t    module: 'XForms'\n\t  }, {\n\t    concept: {\n\t      name: 'sidebar'\n\t    },\n\t    module: 'DTB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['menuitem', 'group'], ['menuitemradio', 'group'], ['menuitemcheckbox', 'group'], ['menuitem'], ['menuitemcheckbox'], ['menuitemradio']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite', 'select'], ['roletype', 'structure', 'section', 'group', 'select']]\n\t};\n\tvar _default$1m = menuRole;\n\tmenuRole$1.default = _default$1m;\n\n\tvar menubarRole$1 = {};\n\n\tObject.defineProperty(menubarRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmenubarRole$1.default = void 0;\n\tvar menubarRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-orientation': 'horizontal'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'toolbar'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['menuitem', 'group'], ['menuitemradio', 'group'], ['menuitemcheckbox', 'group'], ['menuitem'], ['menuitemcheckbox'], ['menuitemradio']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite', 'select', 'menu'], ['roletype', 'structure', 'section', 'group', 'select', 'menu']]\n\t};\n\tvar _default$1l = menubarRole;\n\tmenubarRole$1.default = _default$1l;\n\n\tvar menuitemRole$1 = {};\n\n\tObject.defineProperty(menuitemRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmenuitemRole$1.default = void 0;\n\tvar menuitemRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-posinset': null,\n\t    'aria-setsize': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'MENU_ITEM'\n\t    },\n\t    module: 'JAPI'\n\t  }, {\n\t    concept: {\n\t      name: 'listitem'\n\t    },\n\t    module: 'ARIA'\n\t  }, {\n\t    concept: {\n\t      name: 'menuitem'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'option'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: ['group', 'menu', 'menubar'],\n\t  requiredContextRole: ['group', 'menu', 'menubar'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command']]\n\t};\n\tvar _default$1k = menuitemRole;\n\tmenuitemRole$1.default = _default$1k;\n\n\tvar menuitemcheckboxRole$1 = {};\n\n\tObject.defineProperty(menuitemcheckboxRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmenuitemcheckboxRole$1.default = void 0;\n\tvar menuitemcheckboxRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'menuitem'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: ['group', 'menu', 'menubar'],\n\t  requiredContextRole: ['group', 'menu', 'menubar'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-checked': null\n\t  },\n\t  superClass: [['roletype', 'widget', 'input', 'checkbox'], ['roletype', 'widget', 'command', 'menuitem']]\n\t};\n\tvar _default$1j = menuitemcheckboxRole;\n\tmenuitemcheckboxRole$1.default = _default$1j;\n\n\tvar menuitemradioRole$1 = {};\n\n\tObject.defineProperty(menuitemradioRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmenuitemradioRole$1.default = void 0;\n\tvar menuitemradioRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'menuitem'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: ['group', 'menu', 'menubar'],\n\t  requiredContextRole: ['group', 'menu', 'menubar'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-checked': null\n\t  },\n\t  superClass: [['roletype', 'widget', 'input', 'checkbox', 'menuitemcheckbox'], ['roletype', 'widget', 'command', 'menuitem', 'menuitemcheckbox'], ['roletype', 'widget', 'input', 'radio']]\n\t};\n\tvar _default$1i = menuitemradioRole;\n\tmenuitemradioRole$1.default = _default$1i;\n\n\tvar meterRole$1 = {};\n\n\tObject.defineProperty(meterRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tmeterRole$1.default = void 0;\n\tvar meterRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-valuetext': null,\n\t    'aria-valuemax': '100',\n\t    'aria-valuemin': '0'\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-valuenow': null\n\t  },\n\t  superClass: [['roletype', 'structure', 'range']]\n\t};\n\tvar _default$1h = meterRole;\n\tmeterRole$1.default = _default$1h;\n\n\tvar navigationRole$1 = {};\n\n\tObject.defineProperty(navigationRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tnavigationRole$1.default = void 0;\n\tvar navigationRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'nav'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$1g = navigationRole;\n\tnavigationRole$1.default = _default$1g;\n\n\tvar noneRole$1 = {};\n\n\tObject.defineProperty(noneRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tnoneRole$1.default = void 0;\n\tvar noneRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: [],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: []\n\t};\n\tvar _default$1f = noneRole;\n\tnoneRole$1.default = _default$1f;\n\n\tvar noteRole$1 = {};\n\n\tObject.defineProperty(noteRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tnoteRole$1.default = void 0;\n\tvar noteRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1e = noteRole;\n\tnoteRole$1.default = _default$1e;\n\n\tvar optionRole$1 = {};\n\n\tObject.defineProperty(optionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\toptionRole$1.default = void 0;\n\tvar optionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-checked': null,\n\t    'aria-posinset': null,\n\t    'aria-setsize': null,\n\t    'aria-selected': 'false'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'item'\n\t    },\n\t    module: 'XForms'\n\t  }, {\n\t    concept: {\n\t      name: 'listitem'\n\t    },\n\t    module: 'ARIA'\n\t  }, {\n\t    concept: {\n\t      name: 'option'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-selected': 'false'\n\t  },\n\t  superClass: [['roletype', 'widget', 'input']]\n\t};\n\tvar _default$1d = optionRole;\n\toptionRole$1.default = _default$1d;\n\n\tvar paragraphRole$1 = {};\n\n\tObject.defineProperty(paragraphRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tparagraphRole$1.default = void 0;\n\tvar paragraphRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$1c = paragraphRole;\n\tparagraphRole$1.default = _default$1c;\n\n\tvar presentationRole$1 = {};\n\n\tObject.defineProperty(presentationRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tpresentationRole$1.default = void 0;\n\tvar presentationRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$1b = presentationRole;\n\tpresentationRole$1.default = _default$1b;\n\n\tvar progressbarRole$1 = {};\n\n\tObject.defineProperty(progressbarRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tprogressbarRole$1.default = void 0;\n\tvar progressbarRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-valuetext': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'progress'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'status'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'range'], ['roletype', 'widget']]\n\t};\n\tvar _default$1a = progressbarRole;\n\tprogressbarRole$1.default = _default$1a;\n\n\tvar radioRole$1 = {};\n\n\tObject.defineProperty(radioRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tradioRole$1.default = void 0;\n\tvar radioRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-checked': null,\n\t    'aria-posinset': null,\n\t    'aria-setsize': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'radio'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-checked': null\n\t  },\n\t  superClass: [['roletype', 'widget', 'input']]\n\t};\n\tvar _default$19 = radioRole;\n\tradioRole$1.default = _default$19;\n\n\tvar radiogroupRole$1 = {};\n\n\tObject.defineProperty(radiogroupRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tradiogroupRole$1.default = void 0;\n\tvar radiogroupRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'list'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['radio']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite', 'select'], ['roletype', 'structure', 'section', 'group', 'select']]\n\t};\n\tvar _default$18 = radiogroupRole;\n\tradiogroupRole$1.default = _default$18;\n\n\tvar regionRole$1 = {};\n\n\tObject.defineProperty(regionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tregionRole$1.default = void 0;\n\tvar regionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'aria-label'\n\t      }],\n\t      name: 'section'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['set'],\n\t        name: 'aria-labelledby'\n\t      }],\n\t      name: 'section'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'Device Independence Glossart perceivable unit'\n\t    }\n\t  }, {\n\t    concept: {\n\t      name: 'frame'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$17 = regionRole;\n\tregionRole$1.default = _default$17;\n\n\tvar rowRole$1 = {};\n\n\tObject.defineProperty(rowRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\trowRole$1.default = void 0;\n\tvar rowRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-colindex': null,\n\t    'aria-expanded': null,\n\t    'aria-level': null,\n\t    'aria-posinset': null,\n\t    'aria-rowindex': null,\n\t    'aria-selected': null,\n\t    'aria-setsize': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'tr'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: ['grid', 'rowgroup', 'table', 'treegrid'],\n\t  requiredContextRole: ['grid', 'rowgroup', 'table', 'treegrid'],\n\t  requiredOwnedElements: [['cell'], ['columnheader'], ['gridcell'], ['rowheader']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'group'], ['roletype', 'widget']]\n\t};\n\tvar _default$16 = rowRole;\n\trowRole$1.default = _default$16;\n\n\tvar rowgroupRole$1 = {};\n\n\tObject.defineProperty(rowgroupRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\trowgroupRole$1.default = void 0;\n\tvar rowgroupRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'tbody'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'tfoot'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'thead'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: ['grid', 'table', 'treegrid'],\n\t  requiredContextRole: ['grid', 'table', 'treegrid'],\n\t  requiredOwnedElements: [['row']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$15 = rowgroupRole;\n\trowgroupRole$1.default = _default$15;\n\n\tvar rowheaderRole$1 = {};\n\n\tObject.defineProperty(rowheaderRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\trowheaderRole$1.default = void 0;\n\tvar rowheaderRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-sort': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'scope',\n\t        value: 'row'\n\t      }],\n\t      name: 'th'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: ['row'],\n\t  requiredContextRole: ['row'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'cell'], ['roletype', 'structure', 'section', 'cell', 'gridcell'], ['roletype', 'widget', 'gridcell'], ['roletype', 'structure', 'sectionhead']]\n\t};\n\tvar _default$14 = rowheaderRole;\n\trowheaderRole$1.default = _default$14;\n\n\tvar scrollbarRole$1 = {};\n\n\tObject.defineProperty(scrollbarRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tscrollbarRole$1.default = void 0;\n\tvar scrollbarRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-valuetext': null,\n\t    'aria-orientation': 'vertical',\n\t    'aria-valuemax': '100',\n\t    'aria-valuemin': '0'\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-controls': null,\n\t    'aria-valuenow': null\n\t  },\n\t  superClass: [['roletype', 'structure', 'range'], ['roletype', 'widget']]\n\t};\n\tvar _default$13 = scrollbarRole;\n\tscrollbarRole$1.default = _default$13;\n\n\tvar searchRole$1 = {};\n\n\tObject.defineProperty(searchRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsearchRole$1.default = void 0;\n\tvar searchRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$12 = searchRole;\n\tsearchRole$1.default = _default$12;\n\n\tvar searchboxRole$1 = {};\n\n\tObject.defineProperty(searchboxRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsearchboxRole$1.default = void 0;\n\tvar searchboxRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'search'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'input', 'textbox']]\n\t};\n\tvar _default$11 = searchboxRole;\n\tsearchboxRole$1.default = _default$11;\n\n\tvar separatorRole$1 = {};\n\n\tObject.defineProperty(separatorRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tseparatorRole$1.default = void 0;\n\tvar separatorRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-orientation': 'horizontal',\n\t    'aria-valuemax': '100',\n\t    'aria-valuemin': '0',\n\t    'aria-valuenow': null,\n\t    'aria-valuetext': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'hr'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure']]\n\t};\n\tvar _default$10 = separatorRole;\n\tseparatorRole$1.default = _default$10;\n\n\tvar sliderRole$1 = {};\n\n\tObject.defineProperty(sliderRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsliderRole$1.default = void 0;\n\tvar sliderRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null,\n\t    'aria-readonly': null,\n\t    'aria-valuetext': null,\n\t    'aria-orientation': 'horizontal',\n\t    'aria-valuemax': '100',\n\t    'aria-valuemin': '0'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'range'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-valuenow': null\n\t  },\n\t  superClass: [['roletype', 'widget', 'input'], ['roletype', 'structure', 'range']]\n\t};\n\tvar _default$$ = sliderRole;\n\tsliderRole$1.default = _default$$;\n\n\tvar spinbuttonRole$1 = {};\n\n\tObject.defineProperty(spinbuttonRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tspinbuttonRole$1.default = void 0;\n\tvar spinbuttonRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null,\n\t    'aria-valuetext': null,\n\t    'aria-valuenow': '0'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        name: 'type',\n\t        value: 'number'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite'], ['roletype', 'widget', 'input'], ['roletype', 'structure', 'range']]\n\t};\n\tvar _default$_ = spinbuttonRole;\n\tspinbuttonRole$1.default = _default$_;\n\n\tvar statusRole$1 = {};\n\n\tObject.defineProperty(statusRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tstatusRole$1.default = void 0;\n\tvar statusRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-atomic': 'true',\n\t    'aria-live': 'polite'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'output'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$Z = statusRole;\n\tstatusRole$1.default = _default$Z;\n\n\tvar strongRole$1 = {};\n\n\tObject.defineProperty(strongRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tstrongRole$1.default = void 0;\n\tvar strongRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$Y = strongRole;\n\tstrongRole$1.default = _default$Y;\n\n\tvar subscriptRole$1 = {};\n\n\tObject.defineProperty(subscriptRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsubscriptRole$1.default = void 0;\n\tvar subscriptRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$X = subscriptRole;\n\tsubscriptRole$1.default = _default$X;\n\n\tvar superscriptRole$1 = {};\n\n\tObject.defineProperty(superscriptRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tsuperscriptRole$1.default = void 0;\n\tvar superscriptRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['prohibited'],\n\t  prohibitedProps: ['aria-label', 'aria-labelledby'],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$W = superscriptRole;\n\tsuperscriptRole$1.default = _default$W;\n\n\tvar switchRole$1 = {};\n\n\tObject.defineProperty(switchRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tswitchRole$1.default = void 0;\n\tvar switchRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'button'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-checked': null\n\t  },\n\t  superClass: [['roletype', 'widget', 'input', 'checkbox']]\n\t};\n\tvar _default$V = switchRole;\n\tswitchRole$1.default = _default$V;\n\n\tvar tabRole$1 = {};\n\n\tObject.defineProperty(tabRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttabRole$1.default = void 0;\n\tvar tabRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-posinset': null,\n\t    'aria-setsize': null,\n\t    'aria-selected': 'false'\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: ['tablist'],\n\t  requiredContextRole: ['tablist'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'sectionhead'], ['roletype', 'widget']]\n\t};\n\tvar _default$U = tabRole;\n\ttabRole$1.default = _default$U;\n\n\tvar tableRole$1 = {};\n\n\tObject.defineProperty(tableRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttableRole$1.default = void 0;\n\tvar tableRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-colcount': null,\n\t    'aria-rowcount': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'table'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['row'], ['row', 'rowgroup']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$T = tableRole;\n\ttableRole$1.default = _default$T;\n\n\tvar tablistRole$1 = {};\n\n\tObject.defineProperty(tablistRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttablistRole$1.default = void 0;\n\tvar tablistRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-level': null,\n\t    'aria-multiselectable': null,\n\t    'aria-orientation': 'horizontal'\n\t  },\n\t  relatedConcepts: [{\n\t    module: 'DAISY',\n\t    concept: {\n\t      name: 'guide'\n\t    }\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['tab']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite']]\n\t};\n\tvar _default$S = tablistRole;\n\ttablistRole$1.default = _default$S;\n\n\tvar tabpanelRole$1 = {};\n\n\tObject.defineProperty(tabpanelRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttabpanelRole$1.default = void 0;\n\tvar tabpanelRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$R = tabpanelRole;\n\ttabpanelRole$1.default = _default$R;\n\n\tvar termRole$1 = {};\n\n\tObject.defineProperty(termRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttermRole$1.default = void 0;\n\tvar termRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'dfn'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'dt'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$Q = termRole;\n\ttermRole$1.default = _default$Q;\n\n\tvar textboxRole$1 = {};\n\n\tObject.defineProperty(textboxRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttextboxRole$1.default = void 0;\n\tvar textboxRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-activedescendant': null,\n\t    'aria-autocomplete': null,\n\t    'aria-errormessage': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null,\n\t    'aria-multiline': null,\n\t    'aria-placeholder': null,\n\t    'aria-readonly': null,\n\t    'aria-required': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'type'\n\t      }, {\n\t        constraints: ['undefined'],\n\t        name: 'list'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'email'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'tel'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'text'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      attributes: [{\n\t        constraints: ['undefined'],\n\t        name: 'list'\n\t      }, {\n\t        name: 'type',\n\t        value: 'url'\n\t      }],\n\t      name: 'input'\n\t    },\n\t    module: 'HTML'\n\t  }, {\n\t    concept: {\n\t      name: 'input'\n\t    },\n\t    module: 'XForms'\n\t  }, {\n\t    concept: {\n\t      name: 'textarea'\n\t    },\n\t    module: 'HTML'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'input']]\n\t};\n\tvar _default$P = textboxRole;\n\ttextboxRole$1.default = _default$P;\n\n\tvar timeRole$1 = {};\n\n\tObject.defineProperty(timeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttimeRole$1.default = void 0;\n\tvar timeRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$O = timeRole;\n\ttimeRole$1.default = _default$O;\n\n\tvar timerRole$1 = {};\n\n\tObject.defineProperty(timerRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttimerRole$1.default = void 0;\n\tvar timerRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'status']]\n\t};\n\tvar _default$N = timerRole;\n\ttimerRole$1.default = _default$N;\n\n\tvar toolbarRole$1 = {};\n\n\tObject.defineProperty(toolbarRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttoolbarRole$1.default = void 0;\n\tvar toolbarRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-orientation': 'horizontal'\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'menubar'\n\t    },\n\t    module: 'ARIA'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'group']]\n\t};\n\tvar _default$M = toolbarRole;\n\ttoolbarRole$1.default = _default$M;\n\n\tvar tooltipRole$1 = {};\n\n\tObject.defineProperty(tooltipRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttooltipRole$1.default = void 0;\n\tvar tooltipRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$L = tooltipRole;\n\ttooltipRole$1.default = _default$L;\n\n\tvar treeRole$1 = {};\n\n\tObject.defineProperty(treeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttreeRole$1.default = void 0;\n\tvar treeRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null,\n\t    'aria-multiselectable': null,\n\t    'aria-required': null,\n\t    'aria-orientation': 'vertical'\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['treeitem', 'group'], ['treeitem']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite', 'select'], ['roletype', 'structure', 'section', 'group', 'select']]\n\t};\n\tvar _default$K = treeRole;\n\ttreeRole$1.default = _default$K;\n\n\tvar treegridRole$1 = {};\n\n\tObject.defineProperty(treegridRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttreegridRole$1.default = void 0;\n\tvar treegridRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['row'], ['row', 'rowgroup']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'composite', 'grid'], ['roletype', 'structure', 'section', 'table', 'grid'], ['roletype', 'widget', 'composite', 'select', 'tree'], ['roletype', 'structure', 'section', 'group', 'select', 'tree']]\n\t};\n\tvar _default$J = treegridRole;\n\ttreegridRole$1.default = _default$J;\n\n\tvar treeitemRole$1 = {};\n\n\tObject.defineProperty(treeitemRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\ttreeitemRole$1.default = void 0;\n\tvar treeitemRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: ['group', 'tree'],\n\t  requiredContextRole: ['group', 'tree'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {\n\t    'aria-selected': null\n\t  },\n\t  superClass: [['roletype', 'structure', 'section', 'listitem'], ['roletype', 'widget', 'input', 'option']]\n\t};\n\tvar _default$I = treeitemRole;\n\ttreeitemRole$1.default = _default$I;\n\n\tObject.defineProperty(ariaLiteralRoles$1, \"__esModule\", {\n\t  value: true\n\t});\n\tariaLiteralRoles$1.default = void 0;\n\n\tvar _alertRole = _interopRequireDefault$5(alertRole$1);\n\n\tvar _alertdialogRole = _interopRequireDefault$5(alertdialogRole$1);\n\n\tvar _applicationRole = _interopRequireDefault$5(applicationRole$1);\n\n\tvar _articleRole = _interopRequireDefault$5(articleRole$1);\n\n\tvar _bannerRole = _interopRequireDefault$5(bannerRole$1);\n\n\tvar _blockquoteRole = _interopRequireDefault$5(blockquoteRole$1);\n\n\tvar _buttonRole = _interopRequireDefault$5(buttonRole$1);\n\n\tvar _captionRole = _interopRequireDefault$5(captionRole$1);\n\n\tvar _cellRole = _interopRequireDefault$5(cellRole$1);\n\n\tvar _checkboxRole = _interopRequireDefault$5(checkboxRole$1);\n\n\tvar _codeRole = _interopRequireDefault$5(codeRole$1);\n\n\tvar _columnheaderRole = _interopRequireDefault$5(columnheaderRole$1);\n\n\tvar _comboboxRole = _interopRequireDefault$5(comboboxRole$1);\n\n\tvar _complementaryRole = _interopRequireDefault$5(complementaryRole$1);\n\n\tvar _contentinfoRole = _interopRequireDefault$5(contentinfoRole$1);\n\n\tvar _definitionRole = _interopRequireDefault$5(definitionRole$1);\n\n\tvar _deletionRole = _interopRequireDefault$5(deletionRole$1);\n\n\tvar _dialogRole = _interopRequireDefault$5(dialogRole$1);\n\n\tvar _directoryRole = _interopRequireDefault$5(directoryRole$1);\n\n\tvar _documentRole = _interopRequireDefault$5(documentRole$1);\n\n\tvar _emphasisRole = _interopRequireDefault$5(emphasisRole$1);\n\n\tvar _feedRole = _interopRequireDefault$5(feedRole$1);\n\n\tvar _figureRole = _interopRequireDefault$5(figureRole$1);\n\n\tvar _formRole = _interopRequireDefault$5(formRole$1);\n\n\tvar _genericRole = _interopRequireDefault$5(genericRole$1);\n\n\tvar _gridRole = _interopRequireDefault$5(gridRole$1);\n\n\tvar _gridcellRole = _interopRequireDefault$5(gridcellRole$1);\n\n\tvar _groupRole = _interopRequireDefault$5(groupRole$1);\n\n\tvar _headingRole = _interopRequireDefault$5(headingRole$1);\n\n\tvar _imgRole = _interopRequireDefault$5(imgRole$1);\n\n\tvar _insertionRole = _interopRequireDefault$5(insertionRole$1);\n\n\tvar _linkRole = _interopRequireDefault$5(linkRole$1);\n\n\tvar _listRole = _interopRequireDefault$5(listRole$1);\n\n\tvar _listboxRole = _interopRequireDefault$5(listboxRole$1);\n\n\tvar _listitemRole = _interopRequireDefault$5(listitemRole$1);\n\n\tvar _logRole = _interopRequireDefault$5(logRole$1);\n\n\tvar _mainRole = _interopRequireDefault$5(mainRole$1);\n\n\tvar _marqueeRole = _interopRequireDefault$5(marqueeRole$1);\n\n\tvar _mathRole = _interopRequireDefault$5(mathRole$1);\n\n\tvar _menuRole = _interopRequireDefault$5(menuRole$1);\n\n\tvar _menubarRole = _interopRequireDefault$5(menubarRole$1);\n\n\tvar _menuitemRole = _interopRequireDefault$5(menuitemRole$1);\n\n\tvar _menuitemcheckboxRole = _interopRequireDefault$5(menuitemcheckboxRole$1);\n\n\tvar _menuitemradioRole = _interopRequireDefault$5(menuitemradioRole$1);\n\n\tvar _meterRole = _interopRequireDefault$5(meterRole$1);\n\n\tvar _navigationRole = _interopRequireDefault$5(navigationRole$1);\n\n\tvar _noneRole = _interopRequireDefault$5(noneRole$1);\n\n\tvar _noteRole = _interopRequireDefault$5(noteRole$1);\n\n\tvar _optionRole = _interopRequireDefault$5(optionRole$1);\n\n\tvar _paragraphRole = _interopRequireDefault$5(paragraphRole$1);\n\n\tvar _presentationRole = _interopRequireDefault$5(presentationRole$1);\n\n\tvar _progressbarRole = _interopRequireDefault$5(progressbarRole$1);\n\n\tvar _radioRole = _interopRequireDefault$5(radioRole$1);\n\n\tvar _radiogroupRole = _interopRequireDefault$5(radiogroupRole$1);\n\n\tvar _regionRole = _interopRequireDefault$5(regionRole$1);\n\n\tvar _rowRole = _interopRequireDefault$5(rowRole$1);\n\n\tvar _rowgroupRole = _interopRequireDefault$5(rowgroupRole$1);\n\n\tvar _rowheaderRole = _interopRequireDefault$5(rowheaderRole$1);\n\n\tvar _scrollbarRole = _interopRequireDefault$5(scrollbarRole$1);\n\n\tvar _searchRole = _interopRequireDefault$5(searchRole$1);\n\n\tvar _searchboxRole = _interopRequireDefault$5(searchboxRole$1);\n\n\tvar _separatorRole = _interopRequireDefault$5(separatorRole$1);\n\n\tvar _sliderRole = _interopRequireDefault$5(sliderRole$1);\n\n\tvar _spinbuttonRole = _interopRequireDefault$5(spinbuttonRole$1);\n\n\tvar _statusRole = _interopRequireDefault$5(statusRole$1);\n\n\tvar _strongRole = _interopRequireDefault$5(strongRole$1);\n\n\tvar _subscriptRole = _interopRequireDefault$5(subscriptRole$1);\n\n\tvar _superscriptRole = _interopRequireDefault$5(superscriptRole$1);\n\n\tvar _switchRole = _interopRequireDefault$5(switchRole$1);\n\n\tvar _tabRole = _interopRequireDefault$5(tabRole$1);\n\n\tvar _tableRole = _interopRequireDefault$5(tableRole$1);\n\n\tvar _tablistRole = _interopRequireDefault$5(tablistRole$1);\n\n\tvar _tabpanelRole = _interopRequireDefault$5(tabpanelRole$1);\n\n\tvar _termRole = _interopRequireDefault$5(termRole$1);\n\n\tvar _textboxRole = _interopRequireDefault$5(textboxRole$1);\n\n\tvar _timeRole = _interopRequireDefault$5(timeRole$1);\n\n\tvar _timerRole = _interopRequireDefault$5(timerRole$1);\n\n\tvar _toolbarRole = _interopRequireDefault$5(toolbarRole$1);\n\n\tvar _tooltipRole = _interopRequireDefault$5(tooltipRole$1);\n\n\tvar _treeRole = _interopRequireDefault$5(treeRole$1);\n\n\tvar _treegridRole = _interopRequireDefault$5(treegridRole$1);\n\n\tvar _treeitemRole = _interopRequireDefault$5(treeitemRole$1);\n\n\tfunction _interopRequireDefault$5(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tvar ariaLiteralRoles = [['alert', _alertRole.default], ['alertdialog', _alertdialogRole.default], ['application', _applicationRole.default], ['article', _articleRole.default], ['banner', _bannerRole.default], ['blockquote', _blockquoteRole.default], ['button', _buttonRole.default], ['caption', _captionRole.default], ['cell', _cellRole.default], ['checkbox', _checkboxRole.default], ['code', _codeRole.default], ['columnheader', _columnheaderRole.default], ['combobox', _comboboxRole.default], ['complementary', _complementaryRole.default], ['contentinfo', _contentinfoRole.default], ['definition', _definitionRole.default], ['deletion', _deletionRole.default], ['dialog', _dialogRole.default], ['directory', _directoryRole.default], ['document', _documentRole.default], ['emphasis', _emphasisRole.default], ['feed', _feedRole.default], ['figure', _figureRole.default], ['form', _formRole.default], ['generic', _genericRole.default], ['grid', _gridRole.default], ['gridcell', _gridcellRole.default], ['group', _groupRole.default], ['heading', _headingRole.default], ['img', _imgRole.default], ['insertion', _insertionRole.default], ['link', _linkRole.default], ['list', _listRole.default], ['listbox', _listboxRole.default], ['listitem', _listitemRole.default], ['log', _logRole.default], ['main', _mainRole.default], ['marquee', _marqueeRole.default], ['math', _mathRole.default], ['menu', _menuRole.default], ['menubar', _menubarRole.default], ['menuitem', _menuitemRole.default], ['menuitemcheckbox', _menuitemcheckboxRole.default], ['menuitemradio', _menuitemradioRole.default], ['meter', _meterRole.default], ['navigation', _navigationRole.default], ['none', _noneRole.default], ['note', _noteRole.default], ['option', _optionRole.default], ['paragraph', _paragraphRole.default], ['presentation', _presentationRole.default], ['progressbar', _progressbarRole.default], ['radio', _radioRole.default], ['radiogroup', _radiogroupRole.default], ['region', _regionRole.default], ['row', _rowRole.default], ['rowgroup', _rowgroupRole.default], ['rowheader', _rowheaderRole.default], ['scrollbar', _scrollbarRole.default], ['search', _searchRole.default], ['searchbox', _searchboxRole.default], ['separator', _separatorRole.default], ['slider', _sliderRole.default], ['spinbutton', _spinbuttonRole.default], ['status', _statusRole.default], ['strong', _strongRole.default], ['subscript', _subscriptRole.default], ['superscript', _superscriptRole.default], ['switch', _switchRole.default], ['tab', _tabRole.default], ['table', _tableRole.default], ['tablist', _tablistRole.default], ['tabpanel', _tabpanelRole.default], ['term', _termRole.default], ['textbox', _textboxRole.default], ['time', _timeRole.default], ['timer', _timerRole.default], ['toolbar', _toolbarRole.default], ['tooltip', _tooltipRole.default], ['tree', _treeRole.default], ['treegrid', _treegridRole.default], ['treeitem', _treeitemRole.default]];\n\tvar _default$H = ariaLiteralRoles;\n\tariaLiteralRoles$1.default = _default$H;\n\n\tvar ariaDpubRoles$1 = {};\n\n\tvar docAbstractRole$1 = {};\n\n\tObject.defineProperty(docAbstractRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocAbstractRole$1.default = void 0;\n\tvar docAbstractRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'abstract [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$G = docAbstractRole;\n\tdocAbstractRole$1.default = _default$G;\n\n\tvar docAcknowledgmentsRole$1 = {};\n\n\tObject.defineProperty(docAcknowledgmentsRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocAcknowledgmentsRole$1.default = void 0;\n\tvar docAcknowledgmentsRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'acknowledgments [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$F = docAcknowledgmentsRole;\n\tdocAcknowledgmentsRole$1.default = _default$F;\n\n\tvar docAfterwordRole$1 = {};\n\n\tObject.defineProperty(docAfterwordRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocAfterwordRole$1.default = void 0;\n\tvar docAfterwordRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'afterword [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$E = docAfterwordRole;\n\tdocAfterwordRole$1.default = _default$E;\n\n\tvar docAppendixRole$1 = {};\n\n\tObject.defineProperty(docAppendixRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocAppendixRole$1.default = void 0;\n\tvar docAppendixRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'appendix [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$D = docAppendixRole;\n\tdocAppendixRole$1.default = _default$D;\n\n\tvar docBacklinkRole$1 = {};\n\n\tObject.defineProperty(docBacklinkRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocBacklinkRole$1.default = void 0;\n\tvar docBacklinkRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'content'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'referrer [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command', 'link']]\n\t};\n\tvar _default$C = docBacklinkRole;\n\tdocBacklinkRole$1.default = _default$C;\n\n\tvar docBiblioentryRole$1 = {};\n\n\tObject.defineProperty(docBiblioentryRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocBiblioentryRole$1.default = void 0;\n\tvar docBiblioentryRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'EPUB biblioentry [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: ['doc-bibliography'],\n\t  requiredContextRole: ['doc-bibliography'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'listitem']]\n\t};\n\tvar _default$B = docBiblioentryRole;\n\tdocBiblioentryRole$1.default = _default$B;\n\n\tvar docBibliographyRole$1 = {};\n\n\tObject.defineProperty(docBibliographyRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocBibliographyRole$1.default = void 0;\n\tvar docBibliographyRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'bibliography [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['doc-biblioentry']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$A = docBibliographyRole;\n\tdocBibliographyRole$1.default = _default$A;\n\n\tvar docBibliorefRole$1 = {};\n\n\tObject.defineProperty(docBibliorefRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocBibliorefRole$1.default = void 0;\n\tvar docBibliorefRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'biblioref [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command', 'link']]\n\t};\n\tvar _default$z = docBibliorefRole;\n\tdocBibliorefRole$1.default = _default$z;\n\n\tvar docChapterRole$1 = {};\n\n\tObject.defineProperty(docChapterRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocChapterRole$1.default = void 0;\n\tvar docChapterRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'chapter [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$y = docChapterRole;\n\tdocChapterRole$1.default = _default$y;\n\n\tvar docColophonRole$1 = {};\n\n\tObject.defineProperty(docColophonRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocColophonRole$1.default = void 0;\n\tvar docColophonRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'colophon [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$x = docColophonRole;\n\tdocColophonRole$1.default = _default$x;\n\n\tvar docConclusionRole$1 = {};\n\n\tObject.defineProperty(docConclusionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocConclusionRole$1.default = void 0;\n\tvar docConclusionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'conclusion [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$w = docConclusionRole;\n\tdocConclusionRole$1.default = _default$w;\n\n\tvar docCoverRole$1 = {};\n\n\tObject.defineProperty(docCoverRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocCoverRole$1.default = void 0;\n\tvar docCoverRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'cover [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'img']]\n\t};\n\tvar _default$v = docCoverRole;\n\tdocCoverRole$1.default = _default$v;\n\n\tvar docCreditRole$1 = {};\n\n\tObject.defineProperty(docCreditRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocCreditRole$1.default = void 0;\n\tvar docCreditRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'credit [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$u = docCreditRole;\n\tdocCreditRole$1.default = _default$u;\n\n\tvar docCreditsRole$1 = {};\n\n\tObject.defineProperty(docCreditsRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocCreditsRole$1.default = void 0;\n\tvar docCreditsRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'credits [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$t = docCreditsRole;\n\tdocCreditsRole$1.default = _default$t;\n\n\tvar docDedicationRole$1 = {};\n\n\tObject.defineProperty(docDedicationRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocDedicationRole$1.default = void 0;\n\tvar docDedicationRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'dedication [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$s = docDedicationRole;\n\tdocDedicationRole$1.default = _default$s;\n\n\tvar docEndnoteRole$1 = {};\n\n\tObject.defineProperty(docEndnoteRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocEndnoteRole$1.default = void 0;\n\tvar docEndnoteRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'rearnote [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: ['doc-endnotes'],\n\t  requiredContextRole: ['doc-endnotes'],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'listitem']]\n\t};\n\tvar _default$r = docEndnoteRole;\n\tdocEndnoteRole$1.default = _default$r;\n\n\tvar docEndnotesRole$1 = {};\n\n\tObject.defineProperty(docEndnotesRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocEndnotesRole$1.default = void 0;\n\tvar docEndnotesRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'rearnotes [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['doc-endnote']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$q = docEndnotesRole;\n\tdocEndnotesRole$1.default = _default$q;\n\n\tvar docEpigraphRole$1 = {};\n\n\tObject.defineProperty(docEpigraphRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocEpigraphRole$1.default = void 0;\n\tvar docEpigraphRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'epigraph [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$p = docEpigraphRole;\n\tdocEpigraphRole$1.default = _default$p;\n\n\tvar docEpilogueRole$1 = {};\n\n\tObject.defineProperty(docEpilogueRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocEpilogueRole$1.default = void 0;\n\tvar docEpilogueRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'epilogue [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$o = docEpilogueRole;\n\tdocEpilogueRole$1.default = _default$o;\n\n\tvar docErrataRole$1 = {};\n\n\tObject.defineProperty(docErrataRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocErrataRole$1.default = void 0;\n\tvar docErrataRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'errata [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$n = docErrataRole;\n\tdocErrataRole$1.default = _default$n;\n\n\tvar docExampleRole$1 = {};\n\n\tObject.defineProperty(docExampleRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocExampleRole$1.default = void 0;\n\tvar docExampleRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$m = docExampleRole;\n\tdocExampleRole$1.default = _default$m;\n\n\tvar docFootnoteRole$1 = {};\n\n\tObject.defineProperty(docFootnoteRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocFootnoteRole$1.default = void 0;\n\tvar docFootnoteRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'footnote [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$l = docFootnoteRole;\n\tdocFootnoteRole$1.default = _default$l;\n\n\tvar docForewordRole$1 = {};\n\n\tObject.defineProperty(docForewordRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocForewordRole$1.default = void 0;\n\tvar docForewordRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'foreword [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$k = docForewordRole;\n\tdocForewordRole$1.default = _default$k;\n\n\tvar docGlossaryRole$1 = {};\n\n\tObject.defineProperty(docGlossaryRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocGlossaryRole$1.default = void 0;\n\tvar docGlossaryRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'glossary [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [['definition'], ['term']],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$j = docGlossaryRole;\n\tdocGlossaryRole$1.default = _default$j;\n\n\tvar docGlossrefRole$1 = {};\n\n\tObject.defineProperty(docGlossrefRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocGlossrefRole$1.default = void 0;\n\tvar docGlossrefRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'glossref [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command', 'link']]\n\t};\n\tvar _default$i = docGlossrefRole;\n\tdocGlossrefRole$1.default = _default$i;\n\n\tvar docIndexRole$1 = {};\n\n\tObject.defineProperty(docIndexRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocIndexRole$1.default = void 0;\n\tvar docIndexRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'index [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark', 'navigation']]\n\t};\n\tvar _default$h = docIndexRole;\n\tdocIndexRole$1.default = _default$h;\n\n\tvar docIntroductionRole$1 = {};\n\n\tObject.defineProperty(docIntroductionRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocIntroductionRole$1.default = void 0;\n\tvar docIntroductionRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'introduction [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$g = docIntroductionRole;\n\tdocIntroductionRole$1.default = _default$g;\n\n\tvar docNoterefRole$1 = {};\n\n\tObject.defineProperty(docNoterefRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocNoterefRole$1.default = void 0;\n\tvar docNoterefRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author', 'contents'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'noteref [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'widget', 'command', 'link']]\n\t};\n\tvar _default$f = docNoterefRole;\n\tdocNoterefRole$1.default = _default$f;\n\n\tvar docNoticeRole$1 = {};\n\n\tObject.defineProperty(docNoticeRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocNoticeRole$1.default = void 0;\n\tvar docNoticeRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'notice [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'note']]\n\t};\n\tvar _default$e = docNoticeRole;\n\tdocNoticeRole$1.default = _default$e;\n\n\tvar docPagebreakRole$1 = {};\n\n\tObject.defineProperty(docPagebreakRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocPagebreakRole$1.default = void 0;\n\tvar docPagebreakRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: true,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'pagebreak [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'separator']]\n\t};\n\tvar _default$d = docPagebreakRole;\n\tdocPagebreakRole$1.default = _default$d;\n\n\tvar docPagelistRole$1 = {};\n\n\tObject.defineProperty(docPagelistRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocPagelistRole$1.default = void 0;\n\tvar docPagelistRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'page-list [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark', 'navigation']]\n\t};\n\tvar _default$c = docPagelistRole;\n\tdocPagelistRole$1.default = _default$c;\n\n\tvar docPartRole$1 = {};\n\n\tObject.defineProperty(docPartRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocPartRole$1.default = void 0;\n\tvar docPartRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: true,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'part [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$b = docPartRole;\n\tdocPartRole$1.default = _default$b;\n\n\tvar docPrefaceRole$1 = {};\n\n\tObject.defineProperty(docPrefaceRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocPrefaceRole$1.default = void 0;\n\tvar docPrefaceRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'preface [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$a = docPrefaceRole;\n\tdocPrefaceRole$1.default = _default$a;\n\n\tvar docPrologueRole$1 = {};\n\n\tObject.defineProperty(docPrologueRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocPrologueRole$1.default = void 0;\n\tvar docPrologueRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'prologue [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark']]\n\t};\n\tvar _default$9 = docPrologueRole;\n\tdocPrologueRole$1.default = _default$9;\n\n\tvar docPullquoteRole$1 = {};\n\n\tObject.defineProperty(docPullquoteRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocPullquoteRole$1.default = void 0;\n\tvar docPullquoteRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {},\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'pullquote [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['none']]\n\t};\n\tvar _default$8 = docPullquoteRole;\n\tdocPullquoteRole$1.default = _default$8;\n\n\tvar docQnaRole$1 = {};\n\n\tObject.defineProperty(docQnaRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocQnaRole$1.default = void 0;\n\tvar docQnaRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'qna [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section']]\n\t};\n\tvar _default$7 = docQnaRole;\n\tdocQnaRole$1.default = _default$7;\n\n\tvar docSubtitleRole$1 = {};\n\n\tObject.defineProperty(docSubtitleRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocSubtitleRole$1.default = void 0;\n\tvar docSubtitleRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'subtitle [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'sectionhead']]\n\t};\n\tvar _default$6 = docSubtitleRole;\n\tdocSubtitleRole$1.default = _default$6;\n\n\tvar docTipRole$1 = {};\n\n\tObject.defineProperty(docTipRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocTipRole$1.default = void 0;\n\tvar docTipRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'help [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'note']]\n\t};\n\tvar _default$5 = docTipRole;\n\tdocTipRole$1.default = _default$5;\n\n\tvar docTocRole$1 = {};\n\n\tObject.defineProperty(docTocRole$1, \"__esModule\", {\n\t  value: true\n\t});\n\tdocTocRole$1.default = void 0;\n\tvar docTocRole = {\n\t  abstract: false,\n\t  accessibleNameRequired: false,\n\t  baseConcepts: [],\n\t  childrenPresentational: false,\n\t  nameFrom: ['author'],\n\t  prohibitedProps: [],\n\t  props: {\n\t    'aria-disabled': null,\n\t    'aria-errormessage': null,\n\t    'aria-expanded': null,\n\t    'aria-haspopup': null,\n\t    'aria-invalid': null\n\t  },\n\t  relatedConcepts: [{\n\t    concept: {\n\t      name: 'toc [EPUB-SSV]'\n\t    },\n\t    module: 'EPUB'\n\t  }],\n\t  requireContextRole: [],\n\t  requiredContextRole: [],\n\t  requiredOwnedElements: [],\n\t  requiredProps: {},\n\t  superClass: [['roletype', 'structure', 'section', 'landmark', 'navigation']]\n\t};\n\tvar _default$4 = docTocRole;\n\tdocTocRole$1.default = _default$4;\n\n\tObject.defineProperty(ariaDpubRoles$1, \"__esModule\", {\n\t  value: true\n\t});\n\tariaDpubRoles$1.default = void 0;\n\n\tvar _docAbstractRole = _interopRequireDefault$4(docAbstractRole$1);\n\n\tvar _docAcknowledgmentsRole = _interopRequireDefault$4(docAcknowledgmentsRole$1);\n\n\tvar _docAfterwordRole = _interopRequireDefault$4(docAfterwordRole$1);\n\n\tvar _docAppendixRole = _interopRequireDefault$4(docAppendixRole$1);\n\n\tvar _docBacklinkRole = _interopRequireDefault$4(docBacklinkRole$1);\n\n\tvar _docBiblioentryRole = _interopRequireDefault$4(docBiblioentryRole$1);\n\n\tvar _docBibliographyRole = _interopRequireDefault$4(docBibliographyRole$1);\n\n\tvar _docBibliorefRole = _interopRequireDefault$4(docBibliorefRole$1);\n\n\tvar _docChapterRole = _interopRequireDefault$4(docChapterRole$1);\n\n\tvar _docColophonRole = _interopRequireDefault$4(docColophonRole$1);\n\n\tvar _docConclusionRole = _interopRequireDefault$4(docConclusionRole$1);\n\n\tvar _docCoverRole = _interopRequireDefault$4(docCoverRole$1);\n\n\tvar _docCreditRole = _interopRequireDefault$4(docCreditRole$1);\n\n\tvar _docCreditsRole = _interopRequireDefault$4(docCreditsRole$1);\n\n\tvar _docDedicationRole = _interopRequireDefault$4(docDedicationRole$1);\n\n\tvar _docEndnoteRole = _interopRequireDefault$4(docEndnoteRole$1);\n\n\tvar _docEndnotesRole = _interopRequireDefault$4(docEndnotesRole$1);\n\n\tvar _docEpigraphRole = _interopRequireDefault$4(docEpigraphRole$1);\n\n\tvar _docEpilogueRole = _interopRequireDefault$4(docEpilogueRole$1);\n\n\tvar _docErrataRole = _interopRequireDefault$4(docErrataRole$1);\n\n\tvar _docExampleRole = _interopRequireDefault$4(docExampleRole$1);\n\n\tvar _docFootnoteRole = _interopRequireDefault$4(docFootnoteRole$1);\n\n\tvar _docForewordRole = _interopRequireDefault$4(docForewordRole$1);\n\n\tvar _docGlossaryRole = _interopRequireDefault$4(docGlossaryRole$1);\n\n\tvar _docGlossrefRole = _interopRequireDefault$4(docGlossrefRole$1);\n\n\tvar _docIndexRole = _interopRequireDefault$4(docIndexRole$1);\n\n\tvar _docIntroductionRole = _interopRequireDefault$4(docIntroductionRole$1);\n\n\tvar _docNoterefRole = _interopRequireDefault$4(docNoterefRole$1);\n\n\tvar _docNoticeRole = _interopRequireDefault$4(docNoticeRole$1);\n\n\tvar _docPagebreakRole = _interopRequireDefault$4(docPagebreakRole$1);\n\n\tvar _docPagelistRole = _interopRequireDefault$4(docPagelistRole$1);\n\n\tvar _docPartRole = _interopRequireDefault$4(docPartRole$1);\n\n\tvar _docPrefaceRole = _interopRequireDefault$4(docPrefaceRole$1);\n\n\tvar _docPrologueRole = _interopRequireDefault$4(docPrologueRole$1);\n\n\tvar _docPullquoteRole = _interopRequireDefault$4(docPullquoteRole$1);\n\n\tvar _docQnaRole = _interopRequireDefault$4(docQnaRole$1);\n\n\tvar _docSubtitleRole = _interopRequireDefault$4(docSubtitleRole$1);\n\n\tvar _docTipRole = _interopRequireDefault$4(docTipRole$1);\n\n\tvar _docTocRole = _interopRequireDefault$4(docTocRole$1);\n\n\tfunction _interopRequireDefault$4(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tvar ariaDpubRoles = [['doc-abstract', _docAbstractRole.default], ['doc-acknowledgments', _docAcknowledgmentsRole.default], ['doc-afterword', _docAfterwordRole.default], ['doc-appendix', _docAppendixRole.default], ['doc-backlink', _docBacklinkRole.default], ['doc-biblioentry', _docBiblioentryRole.default], ['doc-bibliography', _docBibliographyRole.default], ['doc-biblioref', _docBibliorefRole.default], ['doc-chapter', _docChapterRole.default], ['doc-colophon', _docColophonRole.default], ['doc-conclusion', _docConclusionRole.default], ['doc-cover', _docCoverRole.default], ['doc-credit', _docCreditRole.default], ['doc-credits', _docCreditsRole.default], ['doc-dedication', _docDedicationRole.default], ['doc-endnote', _docEndnoteRole.default], ['doc-endnotes', _docEndnotesRole.default], ['doc-epigraph', _docEpigraphRole.default], ['doc-epilogue', _docEpilogueRole.default], ['doc-errata', _docErrataRole.default], ['doc-example', _docExampleRole.default], ['doc-footnote', _docFootnoteRole.default], ['doc-foreword', _docForewordRole.default], ['doc-glossary', _docGlossaryRole.default], ['doc-glossref', _docGlossrefRole.default], ['doc-index', _docIndexRole.default], ['doc-introduction', _docIntroductionRole.default], ['doc-noteref', _docNoterefRole.default], ['doc-notice', _docNoticeRole.default], ['doc-pagebreak', _docPagebreakRole.default], ['doc-pagelist', _docPagelistRole.default], ['doc-part', _docPartRole.default], ['doc-preface', _docPrefaceRole.default], ['doc-prologue', _docPrologueRole.default], ['doc-pullquote', _docPullquoteRole.default], ['doc-qna', _docQnaRole.default], ['doc-subtitle', _docSubtitleRole.default], ['doc-tip', _docTipRole.default], ['doc-toc', _docTocRole.default]];\n\tvar _default$3 = ariaDpubRoles;\n\tariaDpubRoles$1.default = _default$3;\n\n\tObject.defineProperty(rolesMap$1, \"__esModule\", {\n\t  value: true\n\t});\n\trolesMap$1.default = void 0;\n\n\tvar _ariaAbstractRoles = _interopRequireDefault$3(ariaAbstractRoles$1);\n\n\tvar _ariaLiteralRoles = _interopRequireDefault$3(ariaLiteralRoles$1);\n\n\tvar _ariaDpubRoles = _interopRequireDefault$3(ariaDpubRoles$1);\n\n\tfunction _interopRequireDefault$3(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tfunction _defineProperty(obj, key, value) {\n\t  if (key in obj) {\n\t    Object.defineProperty(obj, key, {\n\t      value: value,\n\t      enumerable: true,\n\t      configurable: true,\n\t      writable: true\n\t    });\n\t  } else {\n\t    obj[key] = value;\n\t  }\n\n\t  return obj;\n\t}\n\n\tfunction _createForOfIteratorHelper(o, allowArrayLike) {\n\t  var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"];\n\n\t  if (!it) {\n\t    if (Array.isArray(o) || (it = _unsupportedIterableToArray$2(o)) || allowArrayLike && o && typeof o.length === \"number\") {\n\t      if (it) o = it;\n\t      var i = 0;\n\n\t      var F = function F() {};\n\n\t      return {\n\t        s: F,\n\t        n: function n() {\n\t          if (i >= o.length) return {\n\t            done: true\n\t          };\n\t          return {\n\t            done: false,\n\t            value: o[i++]\n\t          };\n\t        },\n\t        e: function e(_e2) {\n\t          throw _e2;\n\t        },\n\t        f: F\n\t      };\n\t    }\n\n\t    throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t  }\n\n\t  var normalCompletion = true,\n\t      didErr = false,\n\t      err;\n\t  return {\n\t    s: function s() {\n\t      it = it.call(o);\n\t    },\n\t    n: function n() {\n\t      var step = it.next();\n\t      normalCompletion = step.done;\n\t      return step;\n\t    },\n\t    e: function e(_e3) {\n\t      didErr = true;\n\t      err = _e3;\n\t    },\n\t    f: function f() {\n\t      try {\n\t        if (!normalCompletion && it.return != null) it.return();\n\t      } finally {\n\t        if (didErr) throw err;\n\t      }\n\t    }\n\t  };\n\t}\n\n\tfunction _slicedToArray$2(arr, i) {\n\t  return _arrayWithHoles$2(arr) || _iterableToArrayLimit$2(arr, i) || _unsupportedIterableToArray$2(arr, i) || _nonIterableRest$2();\n\t}\n\n\tfunction _nonIterableRest$2() {\n\t  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t}\n\n\tfunction _unsupportedIterableToArray$2(o, minLen) {\n\t  if (!o) return;\n\t  if (typeof o === \"string\") return _arrayLikeToArray$2(o, minLen);\n\t  var n = Object.prototype.toString.call(o).slice(8, -1);\n\t  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$2(o, minLen);\n\t}\n\n\tfunction _arrayLikeToArray$2(arr, len) {\n\t  if (len == null || len > arr.length) len = arr.length;\n\n\t  for (var i = 0, arr2 = new Array(len); i < len; i++) {\n\t    arr2[i] = arr[i];\n\t  }\n\n\t  return arr2;\n\t}\n\n\tfunction _iterableToArrayLimit$2(arr, i) {\n\t  var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n\n\t  if (_i == null) return;\n\t  var _arr = [];\n\t  var _n = true;\n\t  var _d = false;\n\n\t  var _s, _e;\n\n\t  try {\n\t    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n\t      _arr.push(_s.value);\n\n\t      if (i && _arr.length === i) break;\n\t    }\n\t  } catch (err) {\n\t    _d = true;\n\t    _e = err;\n\t  } finally {\n\t    try {\n\t      if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n\t    } finally {\n\t      if (_d) throw _e;\n\t    }\n\t  }\n\n\t  return _arr;\n\t}\n\n\tfunction _arrayWithHoles$2(arr) {\n\t  if (Array.isArray(arr)) return arr;\n\t}\n\n\tvar roles$1 = [].concat(_ariaAbstractRoles.default, _ariaLiteralRoles.default, _ariaDpubRoles.default);\n\troles$1.forEach(function (_ref) {\n\t  var _ref2 = _slicedToArray$2(_ref, 2),\n\t      roleDefinition = _ref2[1]; // Conglomerate the properties\n\n\n\t  var _iterator = _createForOfIteratorHelper(roleDefinition.superClass),\n\t      _step;\n\n\t  try {\n\t    for (_iterator.s(); !(_step = _iterator.n()).done;) {\n\t      var superClassIter = _step.value;\n\n\t      var _iterator2 = _createForOfIteratorHelper(superClassIter),\n\t          _step2;\n\n\t      try {\n\t        var _loop = function _loop() {\n\t          var superClassName = _step2.value;\n\t          var superClassRoleTuple = roles$1.find(function (_ref3) {\n\t            var _ref4 = _slicedToArray$2(_ref3, 1),\n\t                name = _ref4[0];\n\n\t            return name === superClassName;\n\t          });\n\n\t          if (superClassRoleTuple) {\n\t            var superClassDefinition = superClassRoleTuple[1];\n\n\t            for (var _i2 = 0, _Object$keys = Object.keys(superClassDefinition.props); _i2 < _Object$keys.length; _i2++) {\n\t              var prop = _Object$keys[_i2];\n\n\t              if ( // $FlowIssue Accessing the hasOwnProperty on the Object prototype is fine.\n\t              !Object.prototype.hasOwnProperty.call(roleDefinition.props, prop)) {\n\t                Object.assign(roleDefinition.props, _defineProperty({}, prop, superClassDefinition.props[prop]));\n\t              }\n\t            }\n\t          }\n\t        };\n\n\t        for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n\t          _loop();\n\t        }\n\t      } catch (err) {\n\t        _iterator2.e(err);\n\t      } finally {\n\t        _iterator2.f();\n\t      }\n\t    }\n\t  } catch (err) {\n\t    _iterator.e(err);\n\t  } finally {\n\t    _iterator.f();\n\t  }\n\t});\n\tvar rolesMap = {\n\t  entries: function entries() {\n\t    return roles$1;\n\t  },\n\t  get: function get(key) {\n\t    var item = roles$1.find(function (tuple) {\n\t      return tuple[0] === key ? true : false;\n\t    });\n\t    return item && item[1];\n\t  },\n\t  has: function has(key) {\n\t    return !!this.get(key);\n\t  },\n\t  keys: function keys() {\n\t    return roles$1.map(function (_ref5) {\n\t      var _ref6 = _slicedToArray$2(_ref5, 1),\n\t          key = _ref6[0];\n\n\t      return key;\n\t    });\n\t  },\n\t  values: function values() {\n\t    return roles$1.map(function (_ref7) {\n\t      var _ref8 = _slicedToArray$2(_ref7, 2),\n\t          values = _ref8[1];\n\n\t      return values;\n\t    });\n\t  }\n\t};\n\tvar _default$2 = rolesMap;\n\trolesMap$1.default = _default$2;\n\n\tvar elementRoleMap$1 = {};\n\n\tObject.defineProperty(elementRoleMap$1, \"__esModule\", {\n\t  value: true\n\t});\n\telementRoleMap$1.default = void 0;\n\n\tvar _rolesMap$2 = _interopRequireDefault$2(rolesMap$1);\n\n\tfunction _interopRequireDefault$2(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tfunction _slicedToArray$1(arr, i) {\n\t  return _arrayWithHoles$1(arr) || _iterableToArrayLimit$1(arr, i) || _unsupportedIterableToArray$1(arr, i) || _nonIterableRest$1();\n\t}\n\n\tfunction _nonIterableRest$1() {\n\t  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t}\n\n\tfunction _unsupportedIterableToArray$1(o, minLen) {\n\t  if (!o) return;\n\t  if (typeof o === \"string\") return _arrayLikeToArray$1(o, minLen);\n\t  var n = Object.prototype.toString.call(o).slice(8, -1);\n\t  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen);\n\t}\n\n\tfunction _arrayLikeToArray$1(arr, len) {\n\t  if (len == null || len > arr.length) len = arr.length;\n\n\t  for (var i = 0, arr2 = new Array(len); i < len; i++) {\n\t    arr2[i] = arr[i];\n\t  }\n\n\t  return arr2;\n\t}\n\n\tfunction _iterableToArrayLimit$1(arr, i) {\n\t  var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n\n\t  if (_i == null) return;\n\t  var _arr = [];\n\t  var _n = true;\n\t  var _d = false;\n\n\t  var _s, _e;\n\n\t  try {\n\t    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n\t      _arr.push(_s.value);\n\n\t      if (i && _arr.length === i) break;\n\t    }\n\t  } catch (err) {\n\t    _d = true;\n\t    _e = err;\n\t  } finally {\n\t    try {\n\t      if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n\t    } finally {\n\t      if (_d) throw _e;\n\t    }\n\t  }\n\n\t  return _arr;\n\t}\n\n\tfunction _arrayWithHoles$1(arr) {\n\t  if (Array.isArray(arr)) return arr;\n\t}\n\n\tvar elementRoles$1 = [];\n\n\tvar keys$1 = _rolesMap$2.default.keys();\n\n\tfor (var i$1 = 0; i$1 < keys$1.length; i$1++) {\n\t  var _key = keys$1[i$1];\n\n\t  var role = _rolesMap$2.default.get(_key);\n\n\t  if (role) {\n\t    var concepts = [].concat(role.baseConcepts, role.relatedConcepts);\n\n\t    for (var k = 0; k < concepts.length; k++) {\n\t      var relation = concepts[k];\n\n\t      if (relation.module === 'HTML') {\n\t        var concept = relation.concept;\n\n\t        if (concept) {\n\t          (function () {\n\t            var conceptStr = JSON.stringify(concept);\n\t            var elementRoleRelation = elementRoles$1.find(function (relation) {\n\t              return JSON.stringify(relation[0]) === conceptStr;\n\t            });\n\t            var roles = void 0;\n\n\t            if (elementRoleRelation) {\n\t              roles = elementRoleRelation[1];\n\t            } else {\n\t              roles = [];\n\t            }\n\n\t            var isUnique = true;\n\n\t            for (var _i = 0; _i < roles.length; _i++) {\n\t              if (roles[_i] === _key) {\n\t                isUnique = false;\n\t                break;\n\t              }\n\t            }\n\n\t            if (isUnique) {\n\t              roles.push(_key);\n\t            }\n\n\t            elementRoles$1.push([concept, roles]);\n\t          })();\n\t        }\n\t      }\n\t    }\n\t  }\n\t}\n\n\tvar elementRoleMap = {\n\t  entries: function entries() {\n\t    return elementRoles$1;\n\t  },\n\t  get: function get(key) {\n\t    var item = elementRoles$1.find(function (tuple) {\n\t      return JSON.stringify(tuple[0]) === JSON.stringify(key) ? true : false;\n\t    });\n\t    return item && item[1];\n\t  },\n\t  has: function has(key) {\n\t    return !!this.get(key);\n\t  },\n\t  keys: function keys() {\n\t    return elementRoles$1.map(function (_ref) {\n\t      var _ref2 = _slicedToArray$1(_ref, 1),\n\t          key = _ref2[0];\n\n\t      return key;\n\t    });\n\t  },\n\t  values: function values() {\n\t    return elementRoles$1.map(function (_ref3) {\n\t      var _ref4 = _slicedToArray$1(_ref3, 2),\n\t          values = _ref4[1];\n\n\t      return values;\n\t    });\n\t  }\n\t};\n\tvar _default$1 = elementRoleMap;\n\telementRoleMap$1.default = _default$1;\n\n\tvar roleElementMap$1 = {};\n\n\tObject.defineProperty(roleElementMap$1, \"__esModule\", {\n\t  value: true\n\t});\n\troleElementMap$1.default = void 0;\n\n\tvar _rolesMap$1 = _interopRequireDefault$1(rolesMap$1);\n\n\tfunction _interopRequireDefault$1(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tfunction _slicedToArray(arr, i) {\n\t  return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n\t}\n\n\tfunction _nonIterableRest() {\n\t  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t}\n\n\tfunction _unsupportedIterableToArray(o, minLen) {\n\t  if (!o) return;\n\t  if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n\t  var n = Object.prototype.toString.call(o).slice(8, -1);\n\t  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n\t}\n\n\tfunction _arrayLikeToArray(arr, len) {\n\t  if (len == null || len > arr.length) len = arr.length;\n\n\t  for (var i = 0, arr2 = new Array(len); i < len; i++) {\n\t    arr2[i] = arr[i];\n\t  }\n\n\t  return arr2;\n\t}\n\n\tfunction _iterableToArrayLimit(arr, i) {\n\t  var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n\n\t  if (_i == null) return;\n\t  var _arr = [];\n\t  var _n = true;\n\t  var _d = false;\n\n\t  var _s, _e;\n\n\t  try {\n\t    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n\t      _arr.push(_s.value);\n\n\t      if (i && _arr.length === i) break;\n\t    }\n\t  } catch (err) {\n\t    _d = true;\n\t    _e = err;\n\t  } finally {\n\t    try {\n\t      if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n\t    } finally {\n\t      if (_d) throw _e;\n\t    }\n\t  }\n\n\t  return _arr;\n\t}\n\n\tfunction _arrayWithHoles(arr) {\n\t  if (Array.isArray(arr)) return arr;\n\t}\n\n\tvar roleElement = [];\n\n\tvar keys = _rolesMap$1.default.keys();\n\n\tvar _loop = function _loop(i) {\n\t  var key = keys[i];\n\n\t  var role = _rolesMap$1.default.get(key);\n\n\t  if (role) {\n\t    var concepts = [].concat(role.baseConcepts, role.relatedConcepts);\n\n\t    for (var k = 0; k < concepts.length; k++) {\n\t      var relation = concepts[k];\n\n\t      if (relation.module === 'HTML') {\n\t        var concept = relation.concept;\n\n\t        if (concept) {\n\t          var roleElementRelation = roleElement.find(function (item) {\n\t            return item[0] === key;\n\t          });\n\t          var relationConcepts = void 0;\n\n\t          if (roleElementRelation) {\n\t            relationConcepts = roleElementRelation[1];\n\t          } else {\n\t            relationConcepts = [];\n\t          }\n\n\t          relationConcepts.push(concept);\n\t          roleElement.push([key, relationConcepts]);\n\t        }\n\t      }\n\t    }\n\t  }\n\t};\n\n\tfor (var i = 0; i < keys.length; i++) {\n\t  _loop(i);\n\t}\n\n\tvar roleElementMap = {\n\t  entries: function entries() {\n\t    return roleElement;\n\t  },\n\t  get: function get(key) {\n\t    var item = roleElement.find(function (tuple) {\n\t      return tuple[0] === key ? true : false;\n\t    });\n\t    return item && item[1];\n\t  },\n\t  has: function has(key) {\n\t    return !!this.get(key);\n\t  },\n\t  keys: function keys() {\n\t    return roleElement.map(function (_ref) {\n\t      var _ref2 = _slicedToArray(_ref, 1),\n\t          key = _ref2[0];\n\n\t      return key;\n\t    });\n\t  },\n\t  values: function values() {\n\t    return roleElement.map(function (_ref3) {\n\t      var _ref4 = _slicedToArray(_ref3, 2),\n\t          values = _ref4[1];\n\n\t      return values;\n\t    });\n\t  }\n\t};\n\tvar _default = roleElementMap;\n\troleElementMap$1.default = _default;\n\n\tObject.defineProperty(lib, \"__esModule\", {\n\t  value: true\n\t});\n\tvar roleElements_1 = lib.roleElements = elementRoles_1 = lib.elementRoles = roles_1 = lib.roles = lib.dom = lib.aria = void 0;\n\n\tvar _ariaPropsMap = _interopRequireDefault(ariaPropsMap$1);\n\n\tvar _domMap = _interopRequireDefault(domMap$1);\n\n\tvar _rolesMap = _interopRequireDefault(rolesMap$1);\n\n\tvar _elementRoleMap = _interopRequireDefault(elementRoleMap$1);\n\n\tvar _roleElementMap = _interopRequireDefault(roleElementMap$1);\n\n\tfunction _interopRequireDefault(obj) {\n\t  return obj && obj.__esModule ? obj : {\n\t    default: obj\n\t  };\n\t}\n\n\tvar aria = _ariaPropsMap.default;\n\tlib.aria = aria;\n\tvar dom = _domMap.default;\n\tlib.dom = dom;\n\tvar roles = _rolesMap.default;\n\tvar roles_1 = lib.roles = roles;\n\tvar elementRoles = _elementRoleMap.default;\n\tvar elementRoles_1 = lib.elementRoles = elementRoles;\n\tvar roleElements = _roleElementMap.default;\n\troleElements_1 = lib.roleElements = roleElements;\n\n\tconst elementRoleList = buildElementRoleList(elementRoles_1);\n\t/**\n\t * @param {Element} element -\n\t * @returns {boolean} - `true` if `element` and its subtree are inaccessible\n\t */\n\n\tfunction isSubtreeInaccessible(element) {\n\t  if (element.hidden === true) {\n\t    return true;\n\t  }\n\n\t  if (element.getAttribute('aria-hidden') === 'true') {\n\t    return true;\n\t  }\n\n\t  const window = element.ownerDocument.defaultView;\n\n\t  if (window.getComputedStyle(element).display === 'none') {\n\t    return true;\n\t  }\n\n\t  return false;\n\t}\n\t/**\n\t * Partial implementation https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion\n\t * which should only be used for elements with a non-presentational role i.e.\n\t * `role=\"none\"` and `role=\"presentation\"` will not be excluded.\n\t *\n\t * Implements aria-hidden semantics (i.e. parent overrides child)\n\t * Ignores \"Child Presentational: True\" characteristics\n\t *\n\t * @param {Element} element -\n\t * @param {object} [options] -\n\t * @param {function (element: Element): boolean} options.isSubtreeInaccessible -\n\t * can be used to return cached results from previous isSubtreeInaccessible calls\n\t * @returns {boolean} true if excluded, otherwise false\n\t */\n\n\n\tfunction isInaccessible(element, options) {\n\t  if (options === void 0) {\n\t    options = {};\n\t  }\n\n\t  const {\n\t    isSubtreeInaccessible: isSubtreeInaccessibleImpl = isSubtreeInaccessible\n\t  } = options;\n\t  const window = element.ownerDocument.defaultView; // since visibility is inherited we can exit early\n\n\t  if (window.getComputedStyle(element).visibility === 'hidden') {\n\t    return true;\n\t  }\n\n\t  let currentElement = element;\n\n\t  while (currentElement) {\n\t    if (isSubtreeInaccessibleImpl(currentElement)) {\n\t      return true;\n\t    }\n\n\t    currentElement = currentElement.parentElement;\n\t  }\n\n\t  return false;\n\t}\n\n\tfunction getImplicitAriaRoles(currentNode) {\n\t  // eslint bug here:\n\t  // eslint-disable-next-line no-unused-vars\n\t  for (const {\n\t    match,\n\t    roles\n\t  } of elementRoleList) {\n\t    if (match(currentNode)) {\n\t      return [...roles];\n\t    }\n\t  }\n\n\t  return [];\n\t}\n\n\tfunction buildElementRoleList(elementRolesMap) {\n\t  function makeElementSelector(_ref) {\n\t    let {\n\t      name,\n\t      attributes\n\t    } = _ref;\n\t    return \"\" + name + attributes.map(_ref2 => {\n\t      let {\n\t        name: attributeName,\n\t        value,\n\t        constraints = []\n\t      } = _ref2;\n\t      const shouldNotExist = constraints.indexOf('undefined') !== -1;\n\n\t      if (shouldNotExist) {\n\t        return \":not([\" + attributeName + \"])\";\n\t      } else if (value) {\n\t        return \"[\" + attributeName + \"=\\\"\" + value + \"\\\"]\";\n\t      } else {\n\t        return \"[\" + attributeName + \"]\";\n\t      }\n\t    }).join('');\n\t  }\n\n\t  function getSelectorSpecificity(_ref3) {\n\t    let {\n\t      attributes = []\n\t    } = _ref3;\n\t    return attributes.length;\n\t  }\n\n\t  function bySelectorSpecificity(_ref4, _ref5) {\n\t    let {\n\t      specificity: leftSpecificity\n\t    } = _ref4;\n\t    let {\n\t      specificity: rightSpecificity\n\t    } = _ref5;\n\t    return rightSpecificity - leftSpecificity;\n\t  }\n\n\t  function match(element) {\n\t    let {\n\t      attributes = []\n\t    } = element; // https://github.com/testing-library/dom-testing-library/issues/814\n\n\t    const typeTextIndex = attributes.findIndex(attribute => attribute.value && attribute.name === 'type' && attribute.value === 'text');\n\n\t    if (typeTextIndex >= 0) {\n\t      // not using splice to not mutate the attributes array\n\t      attributes = [...attributes.slice(0, typeTextIndex), ...attributes.slice(typeTextIndex + 1)];\n\t    }\n\n\t    const selector = makeElementSelector({ ...element,\n\t      attributes\n\t    });\n\t    return node => {\n\t      if (typeTextIndex >= 0 && node.type !== 'text') {\n\t        return false;\n\t      }\n\n\t      return node.matches(selector);\n\t    };\n\t  }\n\n\t  let result = []; // eslint bug here:\n\t  // eslint-disable-next-line no-unused-vars\n\n\t  for (const [element, roles] of elementRolesMap.entries()) {\n\t    result = [...result, {\n\t      match: match(element),\n\t      roles: Array.from(roles),\n\t      specificity: getSelectorSpecificity(element)\n\t    }];\n\t  }\n\n\t  return result.sort(bySelectorSpecificity);\n\t}\n\n\tfunction getRoles(container, _temp) {\n\t  let {\n\t    hidden = false\n\t  } = _temp === void 0 ? {} : _temp;\n\n\t  function flattenDOM(node) {\n\t    return [node, ...Array.from(node.children).reduce((acc, child) => [...acc, ...flattenDOM(child)], [])];\n\t  }\n\n\t  return flattenDOM(container).filter(element => {\n\t    return hidden === false ? isInaccessible(element) === false : true;\n\t  }).reduce((acc, node) => {\n\t    let roles = []; // TODO: This violates html-aria which does not allow any role on every element\n\n\t    if (node.hasAttribute('role')) {\n\t      roles = node.getAttribute('role').split(' ').slice(0, 1);\n\t    } else {\n\t      roles = getImplicitAriaRoles(node);\n\t    }\n\n\t    return roles.reduce((rolesAcc, role) => Array.isArray(rolesAcc[role]) ? { ...rolesAcc,\n\t      [role]: [...rolesAcc[role], node]\n\t    } : { ...rolesAcc,\n\t      [role]: [node]\n\t    }, acc);\n\t  }, {});\n\t}\n\n\tfunction prettyRoles(dom, _ref6) {\n\t  let {\n\t    hidden,\n\t    includeDescription\n\t  } = _ref6;\n\t  const roles = getRoles(dom, {\n\t    hidden\n\t  }); // We prefer to skip generic role, we don't recommend it\n\n\t  return Object.entries(roles).filter(_ref7 => {\n\t    let [role] = _ref7;\n\t    return role !== 'generic';\n\t  }).map(_ref8 => {\n\t    let [role, elements] = _ref8;\n\t    const delimiterBar = '-'.repeat(50);\n\t    const elementsString = elements.map(el => {\n\t      const nameString = \"Name \\\"\" + computeAccessibleName(el, {\n\t        computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements\n\t      }) + \"\\\":\\n\";\n\t      const domString = prettyDOM(el.cloneNode(false));\n\n\t      if (includeDescription) {\n\t        const descriptionString = \"Description \\\"\" + computeAccessibleDescription(el, {\n\t          computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements\n\t        }) + \"\\\":\\n\";\n\t        return \"\" + nameString + descriptionString + domString;\n\t      }\n\n\t      return \"\" + nameString + domString;\n\t    }).join('\\n\\n');\n\t    return role + \":\\n\\n\" + elementsString + \"\\n\\n\" + delimiterBar;\n\t  }).join('\\n');\n\t}\n\n\tconst logRoles = function (dom, _temp2) {\n\t  let {\n\t    hidden = false\n\t  } = _temp2 === void 0 ? {} : _temp2;\n\t  return console.log(prettyRoles(dom, {\n\t    hidden\n\t  }));\n\t};\n\t/**\n\t * @param {Element} element -\n\t * @returns {boolean | undefined} - false/true if (not)selected, undefined if not selectable\n\t */\n\n\n\tfunction computeAriaSelected(element) {\n\t  // implicit value from html-aam mappings: https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings\n\t  // https://www.w3.org/TR/html-aam-1.0/#details-id-97\n\t  if (element.tagName === 'OPTION') {\n\t    return element.selected;\n\t  } // explicit value\n\n\n\t  return checkBooleanAttribute(element, 'aria-selected');\n\t}\n\t/**\n\t * @param {Element} element -\n\t * @returns {boolean | undefined} - false/true if (not)checked, undefined if not checked-able\n\t */\n\n\n\tfunction computeAriaChecked(element) {\n\t  // implicit value from html-aam mappings: https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings\n\t  // https://www.w3.org/TR/html-aam-1.0/#details-id-56\n\t  // https://www.w3.org/TR/html-aam-1.0/#details-id-67\n\t  if ('indeterminate' in element && element.indeterminate) {\n\t    return undefined;\n\t  }\n\n\t  if ('checked' in element) {\n\t    return element.checked;\n\t  } // explicit value\n\n\n\t  return checkBooleanAttribute(element, 'aria-checked');\n\t}\n\t/**\n\t * @param {Element} element -\n\t * @returns {boolean | undefined} - false/true if (not)pressed, undefined if not press-able\n\t */\n\n\n\tfunction computeAriaPressed(element) {\n\t  // https://www.w3.org/TR/wai-aria-1.1/#aria-pressed\n\t  return checkBooleanAttribute(element, 'aria-pressed');\n\t}\n\t/**\n\t * @param {Element} element -\n\t * @returns {boolean | string | null} -\n\t */\n\n\n\tfunction computeAriaCurrent(element) {\n\t  var _ref9, _checkBooleanAttribut;\n\n\t  // https://www.w3.org/TR/wai-aria-1.1/#aria-current\n\t  return (_ref9 = (_checkBooleanAttribut = checkBooleanAttribute(element, 'aria-current')) != null ? _checkBooleanAttribut : element.getAttribute('aria-current')) != null ? _ref9 : false;\n\t}\n\t/**\n\t * @param {Element} element -\n\t * @returns {boolean | undefined} - false/true if (not)expanded, undefined if not expand-able\n\t */\n\n\n\tfunction computeAriaExpanded(element) {\n\t  // https://www.w3.org/TR/wai-aria-1.1/#aria-expanded\n\t  return checkBooleanAttribute(element, 'aria-expanded');\n\t}\n\n\tfunction checkBooleanAttribute(element, attribute) {\n\t  const attributeValue = element.getAttribute(attribute);\n\n\t  if (attributeValue === 'true') {\n\t    return true;\n\t  }\n\n\t  if (attributeValue === 'false') {\n\t    return false;\n\t  }\n\n\t  return undefined;\n\t}\n\t/**\n\t * @param {Element} element -\n\t * @returns {number | undefined} - number if implicit heading or aria-level present, otherwise undefined\n\t */\n\n\n\tfunction computeHeadingLevel(element) {\n\t  // https://w3c.github.io/html-aam/#el-h1-h6\n\t  // https://w3c.github.io/html-aam/#el-h1-h6\n\t  const implicitHeadingLevels = {\n\t    H1: 1,\n\t    H2: 2,\n\t    H3: 3,\n\t    H4: 4,\n\t    H5: 5,\n\t    H6: 6\n\t  }; // explicit aria-level value\n\t  // https://www.w3.org/TR/wai-aria-1.2/#aria-level\n\n\t  const ariaLevelAttribute = element.getAttribute('aria-level') && Number(element.getAttribute('aria-level'));\n\t  return ariaLevelAttribute || implicitHeadingLevels[element.tagName];\n\t}\n\n\tconst normalize = getDefaultNormalizer();\n\n\tfunction escapeRegExp(string) {\n\t  return string.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n\t}\n\n\tfunction getRegExpMatcher(string) {\n\t  return new RegExp(escapeRegExp(string.toLowerCase()), 'i');\n\t}\n\n\tfunction makeSuggestion(queryName, element, content, _ref) {\n\t  let {\n\t    variant,\n\t    name\n\t  } = _ref;\n\t  let warning = '';\n\t  const queryOptions = {};\n\t  const queryArgs = [['Role', 'TestId'].includes(queryName) ? content : getRegExpMatcher(content)];\n\n\t  if (name) {\n\t    queryOptions.name = getRegExpMatcher(name);\n\t  }\n\n\t  if (queryName === 'Role' && isInaccessible(element)) {\n\t    queryOptions.hidden = true;\n\t    warning = \"Element is inaccessible. This means that the element and all its children are invisible to screen readers.\\n    If you are using the aria-hidden prop, make sure this is the right choice for your case.\\n    \";\n\t  }\n\n\t  if (Object.keys(queryOptions).length > 0) {\n\t    queryArgs.push(queryOptions);\n\t  }\n\n\t  const queryMethod = variant + \"By\" + queryName;\n\t  return {\n\t    queryName,\n\t    queryMethod,\n\t    queryArgs,\n\t    variant,\n\t    warning,\n\n\t    toString() {\n\t      if (warning) {\n\t        console.warn(warning);\n\t      }\n\n\t      let [text, options] = queryArgs;\n\t      text = typeof text === 'string' ? \"'\" + text + \"'\" : text;\n\t      options = options ? \", { \" + Object.entries(options).map(_ref2 => {\n\t        let [k, v] = _ref2;\n\t        return k + \": \" + v;\n\t      }).join(', ') + \" }\" : '';\n\t      return queryMethod + \"(\" + text + options + \")\";\n\t    }\n\n\t  };\n\t}\n\n\tfunction canSuggest(currentMethod, requestedMethod, data) {\n\t  return data && (!requestedMethod || requestedMethod.toLowerCase() === currentMethod.toLowerCase());\n\t}\n\n\tfunction getSuggestedQuery(element, variant, method) {\n\t  var _element$getAttribute, _getImplicitAriaRoles;\n\n\t  if (variant === void 0) {\n\t    variant = 'get';\n\t  }\n\n\t  // don't create suggestions for script and style elements\n\t  if (element.matches(getConfig().defaultIgnore)) {\n\t    return undefined;\n\t  } //We prefer to suggest something else if the role is generic\n\n\n\t  const role = (_element$getAttribute = element.getAttribute('role')) != null ? _element$getAttribute : (_getImplicitAriaRoles = getImplicitAriaRoles(element)) == null ? void 0 : _getImplicitAriaRoles[0];\n\n\t  if (role !== 'generic' && canSuggest('Role', method, role)) {\n\t    return makeSuggestion('Role', element, role, {\n\t      variant,\n\t      name: computeAccessibleName(element, {\n\t        computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements\n\t      })\n\t    });\n\t  }\n\n\t  const labelText = getLabels$1(document, element).map(label => label.content).join(' ');\n\n\t  if (canSuggest('LabelText', method, labelText)) {\n\t    return makeSuggestion('LabelText', element, labelText, {\n\t      variant\n\t    });\n\t  }\n\n\t  const placeholderText = element.getAttribute('placeholder');\n\n\t  if (canSuggest('PlaceholderText', method, placeholderText)) {\n\t    return makeSuggestion('PlaceholderText', element, placeholderText, {\n\t      variant\n\t    });\n\t  }\n\n\t  const textContent = normalize(getNodeText(element));\n\n\t  if (canSuggest('Text', method, textContent)) {\n\t    return makeSuggestion('Text', element, textContent, {\n\t      variant\n\t    });\n\t  }\n\n\t  if (canSuggest('DisplayValue', method, element.value)) {\n\t    return makeSuggestion('DisplayValue', element, normalize(element.value), {\n\t      variant\n\t    });\n\t  }\n\n\t  const alt = element.getAttribute('alt');\n\n\t  if (canSuggest('AltText', method, alt)) {\n\t    return makeSuggestion('AltText', element, alt, {\n\t      variant\n\t    });\n\t  }\n\n\t  const title = element.getAttribute('title');\n\n\t  if (canSuggest('Title', method, title)) {\n\t    return makeSuggestion('Title', element, title, {\n\t      variant\n\t    });\n\t  }\n\n\t  const testId = element.getAttribute(getConfig().testIdAttribute);\n\n\t  if (canSuggest('TestId', method, testId)) {\n\t    return makeSuggestion('TestId', element, testId, {\n\t      variant\n\t    });\n\t  }\n\n\t  return undefined;\n\t}\n\n\t// closer to their code (because async stack traces are hard to follow).\n\n\tfunction copyStackTrace(target, source) {\n\t  target.stack = source.stack.replace(source.message, target.message);\n\t}\n\n\tfunction waitFor(callback, _ref) {\n\t  let {\n\t    container = getDocument(),\n\t    timeout = getConfig().asyncUtilTimeout,\n\t    showOriginalStackTrace = getConfig().showOriginalStackTrace,\n\t    stackTraceError,\n\t    interval = 50,\n\t    onTimeout = error => {\n\t      error.message = getConfig().getElementError(error.message, container).message;\n\t      return error;\n\t    },\n\t    mutationObserverOptions = {\n\t      subtree: true,\n\t      childList: true,\n\t      attributes: true,\n\t      characterData: true\n\t    }\n\t  } = _ref;\n\n\t  if (typeof callback !== 'function') {\n\t    throw new TypeError('Received `callback` arg must be a function');\n\t  }\n\n\t  return new Promise(async (resolve, reject) => {\n\t    let lastError, intervalId, observer;\n\t    let finished = false;\n\t    let promiseStatus = 'idle';\n\t    const overallTimeoutTimer = setTimeout(handleTimeout, timeout);\n\t    const usingJestFakeTimers = jestFakeTimersAreEnabled();\n\n\t    if (usingJestFakeTimers) {\n\t      const {\n\t        unstable_advanceTimersWrapper: advanceTimersWrapper\n\t      } = getConfig();\n\t      checkCallback(); // this is a dangerous rule to disable because it could lead to an\n\t      // infinite loop. However, eslint isn't smart enough to know that we're\n\t      // setting finished inside `onDone` which will be called when we're done\n\t      // waiting or when we've timed out.\n\t      // eslint-disable-next-line no-unmodified-loop-condition\n\n\t      while (!finished) {\n\t        if (!jestFakeTimersAreEnabled()) {\n\t          const error = new Error(\"Changed from using fake timers to real timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to real timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830\");\n\t          if (!showOriginalStackTrace) copyStackTrace(error, stackTraceError);\n\t          reject(error);\n\t          return;\n\t        } // we *could* (maybe should?) use `advanceTimersToNextTimer` but it's\n\t        // possible that could make this loop go on forever if someone is using\n\t        // third party code that's setting up recursive timers so rapidly that\n\t        // the user's timer's don't get a chance to resolve. So we'll advance\n\t        // by an interval instead. (We have a test for this case).\n\n\n\t        advanceTimersWrapper(() => {\n\t          jest.advanceTimersByTime(interval);\n\t        }); // It's really important that checkCallback is run *before* we flush\n\t        // in-flight promises. To be honest, I'm not sure why, and I can't quite\n\t        // think of a way to reproduce the problem in a test, but I spent\n\t        // an entire day banging my head against a wall on this.\n\n\t        checkCallback();\n\n\t        if (finished) {\n\t          break;\n\t        } // In this rare case, we *need* to wait for in-flight promises\n\t        // to resolve before continuing. We don't need to take advantage\n\t        // of parallelization so we're fine.\n\t        // https://stackoverflow.com/a/59243586/971592\n\t        // eslint-disable-next-line no-await-in-loop\n\n\n\t        await advanceTimersWrapper(async () => {\n\t          await new Promise(r => {\n\t            setTimeout(r, 0);\n\t            jest.advanceTimersByTime(0);\n\t          });\n\t        });\n\t      }\n\t    } else {\n\t      try {\n\t        checkContainerType(container);\n\t      } catch (e) {\n\t        reject(e);\n\t        return;\n\t      }\n\n\t      intervalId = setInterval(checkRealTimersCallback, interval);\n\t      const {\n\t        MutationObserver\n\t      } = getWindowFromNode(container);\n\t      observer = new MutationObserver(checkRealTimersCallback);\n\t      observer.observe(container, mutationObserverOptions);\n\t      checkCallback();\n\t    }\n\n\t    function onDone(error, result) {\n\t      finished = true;\n\t      clearTimeout(overallTimeoutTimer);\n\n\t      if (!usingJestFakeTimers) {\n\t        clearInterval(intervalId);\n\t        observer.disconnect();\n\t      }\n\n\t      if (error) {\n\t        reject(error);\n\t      } else {\n\t        resolve(result);\n\t      }\n\t    }\n\n\t    function checkRealTimersCallback() {\n\t      if (jestFakeTimersAreEnabled()) {\n\t        const error = new Error(\"Changed from using real timers to fake timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to fake timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830\");\n\t        if (!showOriginalStackTrace) copyStackTrace(error, stackTraceError);\n\t        return reject(error);\n\t      } else {\n\t        return checkCallback();\n\t      }\n\t    }\n\n\t    function checkCallback() {\n\t      if (promiseStatus === 'pending') return;\n\n\t      try {\n\t        const result = runWithExpensiveErrorDiagnosticsDisabled(callback);\n\n\t        if (typeof (result == null ? void 0 : result.then) === 'function') {\n\t          promiseStatus = 'pending';\n\t          result.then(resolvedValue => {\n\t            promiseStatus = 'resolved';\n\t            onDone(null, resolvedValue);\n\t          }, rejectedValue => {\n\t            promiseStatus = 'rejected';\n\t            lastError = rejectedValue;\n\t          });\n\t        } else {\n\t          onDone(null, result);\n\t        } // If `callback` throws, wait for the next mutation, interval, or timeout.\n\n\t      } catch (error) {\n\t        // Save the most recent callback error to reject the promise with it in the event of a timeout\n\t        lastError = error;\n\t      }\n\t    }\n\n\t    function handleTimeout() {\n\t      let error;\n\n\t      if (lastError) {\n\t        error = lastError;\n\n\t        if (!showOriginalStackTrace && error.name === 'TestingLibraryElementError') {\n\t          copyStackTrace(error, stackTraceError);\n\t        }\n\t      } else {\n\t        error = new Error('Timed out in waitFor.');\n\n\t        if (!showOriginalStackTrace) {\n\t          copyStackTrace(error, stackTraceError);\n\t        }\n\t      }\n\n\t      onDone(onTimeout(error), null);\n\t    }\n\t  });\n\t}\n\n\tfunction waitForWrapper(callback, options) {\n\t  // create the error here so its stack trace is as close to the\n\t  // calling code as possible\n\t  const stackTraceError = new Error('STACK_TRACE_MESSAGE');\n\t  return getConfig().asyncWrapper(() => waitFor(callback, {\n\t    stackTraceError,\n\t    ...options\n\t  }));\n\t}\n\t/*\n\teslint\n\t  max-lines-per-function: [\"error\", {\"max\": 200}],\n\t*/\n\n\tfunction getElementError(message, container) {\n\t  return getConfig().getElementError(message, container);\n\t}\n\n\tfunction getMultipleElementsFoundError(message, container) {\n\t  return getElementError(message + \"\\n\\n(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).\", container);\n\t}\n\n\tfunction queryAllByAttribute(attribute, container, text, _temp) {\n\t  let {\n\t    exact = true,\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  } = _temp === void 0 ? {} : _temp;\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  return Array.from(container.querySelectorAll(\"[\" + attribute + \"]\")).filter(node => matcher(node.getAttribute(attribute), node, text, matchNormalizer));\n\t}\n\n\tfunction queryByAttribute(attribute, container, text, options) {\n\t  const els = queryAllByAttribute(attribute, container, text, options);\n\n\t  if (els.length > 1) {\n\t    throw getMultipleElementsFoundError(\"Found multiple elements by [\" + attribute + \"=\" + text + \"]\", container);\n\t  }\n\n\t  return els[0] || null;\n\t} // this accepts a query function and returns a function which throws an error\n\t// if more than one elements is returned, otherwise it returns the first\n\t// element or null\n\n\n\tfunction makeSingleQuery(allQuery, getMultipleError) {\n\t  return function (container) {\n\t    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n\t      args[_key - 1] = arguments[_key];\n\t    }\n\n\t    const els = allQuery(container, ...args);\n\n\t    if (els.length > 1) {\n\t      const elementStrings = els.map(element => getElementError(null, element).message).join('\\n\\n');\n\t      throw getMultipleElementsFoundError(getMultipleError(container, ...args) + \"\\n\\nHere are the matching elements:\\n\\n\" + elementStrings, container);\n\t    }\n\n\t    return els[0] || null;\n\t  };\n\t}\n\n\tfunction getSuggestionError(suggestion, container) {\n\t  return getConfig().getElementError(\"A better query is available, try this:\\n\" + suggestion.toString() + \"\\n\", container);\n\t} // this accepts a query function and returns a function which throws an error\n\t// if an empty list of elements is returned\n\n\n\tfunction makeGetAllQuery(allQuery, getMissingError) {\n\t  return function (container) {\n\t    for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n\t      args[_key2 - 1] = arguments[_key2];\n\t    }\n\n\t    const els = allQuery(container, ...args);\n\n\t    if (!els.length) {\n\t      throw getConfig().getElementError(getMissingError(container, ...args), container);\n\t    }\n\n\t    return els;\n\t  };\n\t} // this accepts a getter query function and returns a function which calls\n\t// waitFor and passing a function which invokes the getter.\n\n\n\tfunction makeFindQuery(getter) {\n\t  return (container, text, options, waitForOptions) => {\n\t    return waitForWrapper(() => {\n\t      return getter(container, text, options);\n\t    }, {\n\t      container,\n\t      ...waitForOptions\n\t    });\n\t  };\n\t}\n\n\tconst wrapSingleQueryWithSuggestion = (query, queryAllByName, variant) => function (container) {\n\t  for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {\n\t    args[_key3 - 1] = arguments[_key3];\n\t  }\n\n\t  const element = query(container, ...args);\n\t  const [{\n\t    suggest = getConfig().throwSuggestions\n\t  } = {}] = args.slice(-1);\n\n\t  if (element && suggest) {\n\t    const suggestion = getSuggestedQuery(element, variant);\n\n\t    if (suggestion && !queryAllByName.endsWith(suggestion.queryName)) {\n\t      throw getSuggestionError(suggestion.toString(), container);\n\t    }\n\t  }\n\n\t  return element;\n\t};\n\n\tconst wrapAllByQueryWithSuggestion = (query, queryAllByName, variant) => function (container) {\n\t  for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {\n\t    args[_key4 - 1] = arguments[_key4];\n\t  }\n\n\t  const els = query(container, ...args);\n\t  const [{\n\t    suggest = getConfig().throwSuggestions\n\t  } = {}] = args.slice(-1);\n\n\t  if (els.length && suggest) {\n\t    // get a unique list of all suggestion messages.  We are only going to make a suggestion if\n\t    // all the suggestions are the same\n\t    const uniqueSuggestionMessages = [...new Set(els.map(element => {\n\t      var _getSuggestedQuery;\n\n\t      return (_getSuggestedQuery = getSuggestedQuery(element, variant)) == null ? void 0 : _getSuggestedQuery.toString();\n\t    }))];\n\n\t    if ( // only want to suggest if all the els have the same suggestion.\n\t    uniqueSuggestionMessages.length === 1 && !queryAllByName.endsWith( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: Can this be null at runtime?\n\t    getSuggestedQuery(els[0], variant).queryName)) {\n\t      throw getSuggestionError(uniqueSuggestionMessages[0], container);\n\t    }\n\t  }\n\n\t  return els;\n\t}; // TODO: This deviates from the published declarations\n\t// However, the implementation always required a dyadic (after `container`) not variadic `queryAllBy` considering the implementation of `makeFindQuery`\n\t// This is at least statically true and can be verified by accepting `QueryMethod<Arguments, HTMLElement[]>`\n\n\n\tfunction buildQueries(queryAllBy, getMultipleError, getMissingError) {\n\t  const queryBy = wrapSingleQueryWithSuggestion(makeSingleQuery(queryAllBy, getMultipleError), queryAllBy.name, 'query');\n\t  const getAllBy = makeGetAllQuery(queryAllBy, getMissingError);\n\t  const getBy = makeSingleQuery(getAllBy, getMultipleError);\n\t  const getByWithSuggestions = wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'get');\n\t  const getAllWithSuggestions = wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name.replace('query', 'get'), 'getAll');\n\t  const findAllBy = makeFindQuery(wrapAllByQueryWithSuggestion(getAllBy, queryAllBy.name, 'findAll'));\n\t  const findBy = makeFindQuery(wrapSingleQueryWithSuggestion(getBy, queryAllBy.name, 'find'));\n\t  return [queryBy, getAllWithSuggestions, getByWithSuggestions, findAllBy, findBy];\n\t}\n\n\tvar queryHelpers = /*#__PURE__*/Object.freeze({\n\t\t__proto__: null,\n\t\tgetElementError: getElementError,\n\t\twrapAllByQueryWithSuggestion: wrapAllByQueryWithSuggestion,\n\t\twrapSingleQueryWithSuggestion: wrapSingleQueryWithSuggestion,\n\t\tgetMultipleElementsFoundError: getMultipleElementsFoundError,\n\t\tqueryAllByAttribute: queryAllByAttribute,\n\t\tqueryByAttribute: queryByAttribute,\n\t\tmakeSingleQuery: makeSingleQuery,\n\t\tmakeGetAllQuery: makeGetAllQuery,\n\t\tmakeFindQuery: makeFindQuery,\n\t\tbuildQueries: buildQueries\n\t});\n\n\tfunction queryAllLabels(container) {\n\t  return Array.from(container.querySelectorAll('label,input')).map(node => {\n\t    return {\n\t      node,\n\t      textToMatch: getLabelContent(node)\n\t    };\n\t  }).filter(_ref => {\n\t    let {\n\t      textToMatch\n\t    } = _ref;\n\t    return textToMatch !== null;\n\t  });\n\t}\n\n\tconst queryAllLabelsByText = function (container, text, _temp) {\n\t  let {\n\t    exact = true,\n\t    trim,\n\t    collapseWhitespace,\n\t    normalizer\n\t  } = _temp === void 0 ? {} : _temp;\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  const textToMatchByLabels = queryAllLabels(container);\n\t  return textToMatchByLabels.filter(_ref2 => {\n\t    let {\n\t      node,\n\t      textToMatch\n\t    } = _ref2;\n\t    return matcher(textToMatch, node, text, matchNormalizer);\n\t  }).map(_ref3 => {\n\t    let {\n\t      node\n\t    } = _ref3;\n\t    return node;\n\t  });\n\t};\n\n\tconst queryAllByLabelText = function (container, text, _temp2) {\n\t  let {\n\t    selector = '*',\n\t    exact = true,\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  } = _temp2 === void 0 ? {} : _temp2;\n\t  checkContainerType(container);\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  const matchingLabelledElements = Array.from(container.querySelectorAll('*')).filter(element => {\n\t    return getRealLabels(element).length || element.hasAttribute('aria-labelledby');\n\t  }).reduce((labelledElements, labelledElement) => {\n\t    const labelList = getLabels$1(container, labelledElement, {\n\t      selector\n\t    });\n\t    labelList.filter(label => Boolean(label.formControl)).forEach(label => {\n\t      if (matcher(label.content, label.formControl, text, matchNormalizer) && label.formControl) labelledElements.push(label.formControl);\n\t    });\n\t    const labelsValue = labelList.filter(label => Boolean(label.content)).map(label => label.content);\n\t    if (matcher(labelsValue.join(' '), labelledElement, text, matchNormalizer)) labelledElements.push(labelledElement);\n\n\t    if (labelsValue.length > 1) {\n\t      labelsValue.forEach((labelValue, index) => {\n\t        if (matcher(labelValue, labelledElement, text, matchNormalizer)) labelledElements.push(labelledElement);\n\t        const labelsFiltered = [...labelsValue];\n\t        labelsFiltered.splice(index, 1);\n\n\t        if (labelsFiltered.length > 1) {\n\t          if (matcher(labelsFiltered.join(' '), labelledElement, text, matchNormalizer)) labelledElements.push(labelledElement);\n\t        }\n\t      });\n\t    }\n\n\t    return labelledElements;\n\t  }, []).concat(queryAllByAttribute('aria-label', container, text, {\n\t    exact,\n\t    normalizer: matchNormalizer\n\t  }));\n\t  return Array.from(new Set(matchingLabelledElements)).filter(element => element.matches(selector));\n\t}; // the getAll* query would normally look like this:\n\t// const getAllByLabelText = makeGetAllQuery(\n\t//   queryAllByLabelText,\n\t//   (c, text) => `Unable to find a label with the text of: ${text}`,\n\t// )\n\t// however, we can give a more helpful error message than the generic one,\n\t// so we're writing this one out by hand.\n\n\n\tconst getAllByLabelText = function (container, text) {\n\t  for (var _len = arguments.length, rest = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {\n\t    rest[_key - 2] = arguments[_key];\n\t  }\n\n\t  const els = queryAllByLabelText(container, text, ...rest);\n\n\t  if (!els.length) {\n\t    const labels = queryAllLabelsByText(container, text, ...rest);\n\n\t    if (labels.length) {\n\t      const tagNames = labels.map(label => getTagNameOfElementAssociatedWithLabelViaFor(container, label)).filter(tagName => !!tagName);\n\n\t      if (tagNames.length) {\n\t        throw getConfig().getElementError(tagNames.map(tagName => \"Found a label with the text of: \" + text + \", however the element associated with this label (<\" + tagName + \" />) is non-labellable [https://html.spec.whatwg.org/multipage/forms.html#category-label]. If you really need to label a <\" + tagName + \" />, you can use aria-label or aria-labelledby instead.\").join('\\n\\n'), container);\n\t      } else {\n\t        throw getConfig().getElementError(\"Found a label with the text of: \" + text + \", however no form control was found associated to that label. Make sure you're using the \\\"for\\\" attribute or \\\"aria-labelledby\\\" attribute correctly.\", container);\n\t      }\n\t    } else {\n\t      throw getConfig().getElementError(\"Unable to find a label with the text of: \" + text, container);\n\t    }\n\t  }\n\n\t  return els;\n\t};\n\n\tfunction getTagNameOfElementAssociatedWithLabelViaFor(container, label) {\n\t  const htmlFor = label.getAttribute('for');\n\n\t  if (!htmlFor) {\n\t    return null;\n\t  }\n\n\t  const element = container.querySelector(\"[id=\\\"\" + htmlFor + \"\\\"]\");\n\t  return element ? element.tagName.toLowerCase() : null;\n\t} // the reason mentioned above is the same reason we're not using buildQueries\n\n\n\tconst getMultipleError$7 = (c, text) => \"Found multiple elements with the text of: \" + text;\n\n\tconst queryByLabelText = wrapSingleQueryWithSuggestion(makeSingleQuery(queryAllByLabelText, getMultipleError$7), queryAllByLabelText.name, 'query');\n\tconst getByLabelText = makeSingleQuery(getAllByLabelText, getMultipleError$7);\n\tconst findAllByLabelText = makeFindQuery(wrapAllByQueryWithSuggestion(getAllByLabelText, getAllByLabelText.name, 'findAll'));\n\tconst findByLabelText = makeFindQuery(wrapSingleQueryWithSuggestion(getByLabelText, getAllByLabelText.name, 'find'));\n\tconst getAllByLabelTextWithSuggestions = wrapAllByQueryWithSuggestion(getAllByLabelText, getAllByLabelText.name, 'getAll');\n\tconst getByLabelTextWithSuggestions = wrapSingleQueryWithSuggestion(getByLabelText, getAllByLabelText.name, 'get');\n\tconst queryAllByLabelTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByLabelText, queryAllByLabelText.name, 'queryAll');\n\n\tconst queryAllByPlaceholderText = function () {\n\t  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n\t    args[_key] = arguments[_key];\n\t  }\n\n\t  checkContainerType(args[0]);\n\t  return queryAllByAttribute('placeholder', ...args);\n\t};\n\n\tconst getMultipleError$6 = (c, text) => \"Found multiple elements with the placeholder text of: \" + text;\n\n\tconst getMissingError$6 = (c, text) => \"Unable to find an element with the placeholder text of: \" + text;\n\n\tconst queryAllByPlaceholderTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByPlaceholderText, queryAllByPlaceholderText.name, 'queryAll');\n\tconst [queryByPlaceholderText, getAllByPlaceholderText, getByPlaceholderText, findAllByPlaceholderText, findByPlaceholderText] = buildQueries(queryAllByPlaceholderText, getMultipleError$6, getMissingError$6);\n\n\tconst queryAllByText = function (container, text, _temp) {\n\t  let {\n\t    selector = '*',\n\t    exact = true,\n\t    collapseWhitespace,\n\t    trim,\n\t    ignore = getConfig().defaultIgnore,\n\t    normalizer\n\t  } = _temp === void 0 ? {} : _temp;\n\t  checkContainerType(container);\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  let baseArray = [];\n\n\t  if (typeof container.matches === 'function' && container.matches(selector)) {\n\t    baseArray = [container];\n\t  }\n\n\t  return [...baseArray, ...Array.from(container.querySelectorAll(selector))] // TODO: `matches` according lib.dom.d.ts can get only `string` but according our code it can handle also boolean :)\n\t  .filter(node => !ignore || !node.matches(ignore)).filter(node => matcher(getNodeText(node), node, text, matchNormalizer));\n\t};\n\n\tconst getMultipleError$5 = (c, text) => \"Found multiple elements with the text: \" + text;\n\n\tconst getMissingError$5 = function (c, text, options) {\n\t  if (options === void 0) {\n\t    options = {};\n\t  }\n\n\t  const {\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  } = options;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  const normalizedText = matchNormalizer(text.toString());\n\t  const isNormalizedDifferent = normalizedText !== text.toString();\n\t  return \"Unable to find an element with the text: \" + (isNormalizedDifferent ? normalizedText + \" (normalized from '\" + text + \"')\" : text) + \". This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.\";\n\t};\n\n\tconst queryAllByTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByText, queryAllByText.name, 'queryAll');\n\tconst [queryByText, getAllByText, getByText, findAllByText, findByText] = buildQueries(queryAllByText, getMultipleError$5, getMissingError$5);\n\n\tconst queryAllByDisplayValue = function (container, value, _temp) {\n\t  let {\n\t    exact = true,\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  } = _temp === void 0 ? {} : _temp;\n\t  checkContainerType(container);\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  return Array.from(container.querySelectorAll(\"input,textarea,select\")).filter(node => {\n\t    if (node.tagName === 'SELECT') {\n\t      const selectedOptions = Array.from(node.options).filter(option => option.selected);\n\t      return selectedOptions.some(optionNode => matcher(getNodeText(optionNode), optionNode, value, matchNormalizer));\n\t    } else {\n\t      return matcher(node.value, node, value, matchNormalizer);\n\t    }\n\t  });\n\t};\n\n\tconst getMultipleError$4 = (c, value) => \"Found multiple elements with the display value: \" + value + \".\";\n\n\tconst getMissingError$4 = (c, value) => \"Unable to find an element with the display value: \" + value + \".\";\n\n\tconst queryAllByDisplayValueWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByDisplayValue, queryAllByDisplayValue.name, 'queryAll');\n\tconst [queryByDisplayValue, getAllByDisplayValue, getByDisplayValue, findAllByDisplayValue, findByDisplayValue] = buildQueries(queryAllByDisplayValue, getMultipleError$4, getMissingError$4);\n\n\tconst VALID_TAG_REGEXP = /^(img|input|area|.+-.+)$/i;\n\n\tconst queryAllByAltText = function (container, alt, options) {\n\t  if (options === void 0) {\n\t    options = {};\n\t  }\n\n\t  checkContainerType(container);\n\t  return queryAllByAttribute('alt', container, alt, options).filter(node => VALID_TAG_REGEXP.test(node.tagName));\n\t};\n\n\tconst getMultipleError$3 = (c, alt) => \"Found multiple elements with the alt text: \" + alt;\n\n\tconst getMissingError$3 = (c, alt) => \"Unable to find an element with the alt text: \" + alt;\n\n\tconst queryAllByAltTextWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByAltText, queryAllByAltText.name, 'queryAll');\n\tconst [queryByAltText, getAllByAltText, getByAltText, findAllByAltText, findByAltText] = buildQueries(queryAllByAltText, getMultipleError$3, getMissingError$3);\n\n\tconst isSvgTitle = node => {\n\t  var _node$parentElement;\n\n\t  return node.tagName.toLowerCase() === 'title' && ((_node$parentElement = node.parentElement) == null ? void 0 : _node$parentElement.tagName.toLowerCase()) === 'svg';\n\t};\n\n\tconst queryAllByTitle = function (container, text, _temp) {\n\t  let {\n\t    exact = true,\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  } = _temp === void 0 ? {} : _temp;\n\t  checkContainerType(container);\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\t  return Array.from(container.querySelectorAll('[title], svg > title')).filter(node => matcher(node.getAttribute('title'), node, text, matchNormalizer) || isSvgTitle(node) && matcher(getNodeText(node), node, text, matchNormalizer));\n\t};\n\n\tconst getMultipleError$2 = (c, title) => \"Found multiple elements with the title: \" + title + \".\";\n\n\tconst getMissingError$2 = (c, title) => \"Unable to find an element with the title: \" + title + \".\";\n\n\tconst queryAllByTitleWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByTitle, queryAllByTitle.name, 'queryAll');\n\tconst [queryByTitle, getAllByTitle, getByTitle, findAllByTitle, findByTitle] = buildQueries(queryAllByTitle, getMultipleError$2, getMissingError$2);\n\n\tfunction queryAllByRole(container, role, _temp) {\n\t  let {\n\t    exact = true,\n\t    collapseWhitespace,\n\t    hidden = getConfig().defaultHidden,\n\t    name,\n\t    description,\n\t    trim,\n\t    normalizer,\n\t    queryFallbacks = false,\n\t    selected,\n\t    checked,\n\t    pressed,\n\t    current,\n\t    level,\n\t    expanded\n\t  } = _temp === void 0 ? {} : _temp;\n\t  checkContainerType(container);\n\t  const matcher = exact ? matches : fuzzyMatches;\n\t  const matchNormalizer = makeNormalizer({\n\t    collapseWhitespace,\n\t    trim,\n\t    normalizer\n\t  });\n\n\t  if (selected !== undefined) {\n\t    var _allRoles$get;\n\n\t    // guard against unknown roles\n\t    if (((_allRoles$get = roles_1.get(role)) == null ? void 0 : _allRoles$get.props['aria-selected']) === undefined) {\n\t      throw new Error(\"\\\"aria-selected\\\" is not supported on role \\\"\" + role + \"\\\".\");\n\t    }\n\t  }\n\n\t  if (checked !== undefined) {\n\t    var _allRoles$get2;\n\n\t    // guard against unknown roles\n\t    if (((_allRoles$get2 = roles_1.get(role)) == null ? void 0 : _allRoles$get2.props['aria-checked']) === undefined) {\n\t      throw new Error(\"\\\"aria-checked\\\" is not supported on role \\\"\" + role + \"\\\".\");\n\t    }\n\t  }\n\n\t  if (pressed !== undefined) {\n\t    var _allRoles$get3;\n\n\t    // guard against unknown roles\n\t    if (((_allRoles$get3 = roles_1.get(role)) == null ? void 0 : _allRoles$get3.props['aria-pressed']) === undefined) {\n\t      throw new Error(\"\\\"aria-pressed\\\" is not supported on role \\\"\" + role + \"\\\".\");\n\t    }\n\t  }\n\n\t  if (current !== undefined) {\n\t    var _allRoles$get4;\n\n\t    /* istanbul ignore next */\n\t    // guard against unknown roles\n\t    // All currently released ARIA versions support `aria-current` on all roles.\n\t    // Leaving this for symetry and forward compatibility\n\t    if (((_allRoles$get4 = roles_1.get(role)) == null ? void 0 : _allRoles$get4.props['aria-current']) === undefined) {\n\t      throw new Error(\"\\\"aria-current\\\" is not supported on role \\\"\" + role + \"\\\".\");\n\t    }\n\t  }\n\n\t  if (level !== undefined) {\n\t    // guard against using `level` option with any role other than `heading`\n\t    if (role !== 'heading') {\n\t      throw new Error(\"Role \\\"\" + role + \"\\\" cannot have \\\"level\\\" property.\");\n\t    }\n\t  }\n\n\t  if (expanded !== undefined) {\n\t    var _allRoles$get5;\n\n\t    // guard against unknown roles\n\t    if (((_allRoles$get5 = roles_1.get(role)) == null ? void 0 : _allRoles$get5.props['aria-expanded']) === undefined) {\n\t      throw new Error(\"\\\"aria-expanded\\\" is not supported on role \\\"\" + role + \"\\\".\");\n\t    }\n\t  }\n\n\t  const subtreeIsInaccessibleCache = new WeakMap();\n\n\t  function cachedIsSubtreeInaccessible(element) {\n\t    if (!subtreeIsInaccessibleCache.has(element)) {\n\t      subtreeIsInaccessibleCache.set(element, isSubtreeInaccessible(element));\n\t    }\n\n\t    return subtreeIsInaccessibleCache.get(element);\n\t  }\n\n\t  return Array.from(container.querySelectorAll( // Only query elements that can be matched by the following filters\n\t  makeRoleSelector(role, exact, normalizer ? matchNormalizer : undefined))).filter(node => {\n\t    const isRoleSpecifiedExplicitly = node.hasAttribute('role');\n\n\t    if (isRoleSpecifiedExplicitly) {\n\t      const roleValue = node.getAttribute('role');\n\n\t      if (queryFallbacks) {\n\t        return roleValue.split(' ').filter(Boolean).some(text => matcher(text, node, role, matchNormalizer));\n\t      } // if a custom normalizer is passed then let normalizer handle the role value\n\n\n\t      if (normalizer) {\n\t        return matcher(roleValue, node, role, matchNormalizer);\n\t      } // other wise only send the first word to match\n\n\n\t      const [firstWord] = roleValue.split(' ');\n\t      return matcher(firstWord, node, role, matchNormalizer);\n\t    }\n\n\t    const implicitRoles = getImplicitAriaRoles(node);\n\t    return implicitRoles.some(implicitRole => matcher(implicitRole, node, role, matchNormalizer));\n\t  }).filter(element => {\n\t    if (selected !== undefined) {\n\t      return selected === computeAriaSelected(element);\n\t    }\n\n\t    if (checked !== undefined) {\n\t      return checked === computeAriaChecked(element);\n\t    }\n\n\t    if (pressed !== undefined) {\n\t      return pressed === computeAriaPressed(element);\n\t    }\n\n\t    if (current !== undefined) {\n\t      return current === computeAriaCurrent(element);\n\t    }\n\n\t    if (expanded !== undefined) {\n\t      return expanded === computeAriaExpanded(element);\n\t    }\n\n\t    if (level !== undefined) {\n\t      return level === computeHeadingLevel(element);\n\t    } // don't care if aria attributes are unspecified\n\n\n\t    return true;\n\t  }).filter(element => {\n\t    if (name === undefined) {\n\t      // Don't care\n\t      return true;\n\t    }\n\n\t    return matches(computeAccessibleName(element, {\n\t      computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements\n\t    }), element, name, text => text);\n\t  }).filter(element => {\n\t    if (description === undefined) {\n\t      // Don't care\n\t      return true;\n\t    }\n\n\t    return matches(computeAccessibleDescription(element, {\n\t      computedStyleSupportsPseudoElements: getConfig().computedStyleSupportsPseudoElements\n\t    }), element, description, text => text);\n\t  }).filter(element => {\n\t    return hidden === false ? isInaccessible(element, {\n\t      isSubtreeInaccessible: cachedIsSubtreeInaccessible\n\t    }) === false : true;\n\t  });\n\t}\n\n\tfunction makeRoleSelector(role, exact, customNormalizer) {\n\t  var _roleElements$get;\n\n\t  if (typeof role !== 'string') {\n\t    // For non-string role parameters we can not determine the implicitRoleSelectors.\n\t    return '*';\n\t  }\n\n\t  const explicitRoleSelector = exact && !customNormalizer ? \"*[role~=\\\"\" + role + \"\\\"]\" : '*[role]';\n\t  const roleRelations = (_roleElements$get = roleElements_1.get(role)) != null ? _roleElements$get : new Set();\n\t  const implicitRoleSelectors = new Set(Array.from(roleRelations).map(_ref => {\n\t    let {\n\t      name\n\t    } = _ref;\n\t    return name;\n\t  })); // Current transpilation config sometimes assumes `...` is always applied to arrays.\n\t  // `...` is equivalent to `Array.prototype.concat` for arrays.\n\t  // If you replace this code with `[explicitRoleSelector, ...implicitRoleSelectors]`, make sure every transpilation target retains the `...` in favor of `Array.prototype.concat`.\n\n\t  return [explicitRoleSelector].concat(Array.from(implicitRoleSelectors)).join(',');\n\t}\n\n\tconst getNameHint = name => {\n\t  let nameHint = '';\n\n\t  if (name === undefined) {\n\t    nameHint = '';\n\t  } else if (typeof name === 'string') {\n\t    nameHint = \" and name \\\"\" + name + \"\\\"\";\n\t  } else {\n\t    nameHint = \" and name `\" + name + \"`\";\n\t  }\n\n\t  return nameHint;\n\t};\n\n\tconst getMultipleError$1 = function (c, role, _temp2) {\n\t  let {\n\t    name\n\t  } = _temp2 === void 0 ? {} : _temp2;\n\t  return \"Found multiple elements with the role \\\"\" + role + \"\\\"\" + getNameHint(name);\n\t};\n\n\tconst getMissingError$1 = function (container, role, _temp3) {\n\t  let {\n\t    hidden = getConfig().defaultHidden,\n\t    name,\n\t    description\n\t  } = _temp3 === void 0 ? {} : _temp3;\n\n\t  if (getConfig()._disableExpensiveErrorDiagnostics) {\n\t    return \"Unable to find role=\\\"\" + role + \"\\\"\" + getNameHint(name);\n\t  }\n\n\t  let roles = '';\n\t  Array.from(container.children).forEach(childElement => {\n\t    roles += prettyRoles(childElement, {\n\t      hidden,\n\t      includeDescription: description !== undefined\n\t    });\n\t  });\n\t  let roleMessage;\n\n\t  if (roles.length === 0) {\n\t    if (hidden === false) {\n\t      roleMessage = 'There are no accessible roles. But there might be some inaccessible roles. ' + 'If you wish to access them, then set the `hidden` option to `true`. ' + 'Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole';\n\t    } else {\n\t      roleMessage = 'There are no available roles.';\n\t    }\n\t  } else {\n\t    roleMessage = (\"\\nHere are the \" + (hidden === false ? 'accessible' : 'available') + \" roles:\\n\\n  \" + roles.replace(/\\n/g, '\\n  ').replace(/\\n\\s\\s\\n/g, '\\n\\n') + \"\\n\").trim();\n\t  }\n\n\t  let nameHint = '';\n\n\t  if (name === undefined) {\n\t    nameHint = '';\n\t  } else if (typeof name === 'string') {\n\t    nameHint = \" and name \\\"\" + name + \"\\\"\";\n\t  } else {\n\t    nameHint = \" and name `\" + name + \"`\";\n\t  }\n\n\t  let descriptionHint = '';\n\n\t  if (description === undefined) {\n\t    descriptionHint = '';\n\t  } else if (typeof description === 'string') {\n\t    descriptionHint = \" and description \\\"\" + description + \"\\\"\";\n\t  } else {\n\t    descriptionHint = \" and description `\" + description + \"`\";\n\t  }\n\n\t  return (\"\\nUnable to find an \" + (hidden === false ? 'accessible ' : '') + \"element with the role \\\"\" + role + \"\\\"\" + nameHint + descriptionHint + \"\\n\\n\" + roleMessage).trim();\n\t};\n\n\tconst queryAllByRoleWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByRole, queryAllByRole.name, 'queryAll');\n\tconst [queryByRole, getAllByRole, getByRole, findAllByRole, findByRole] = buildQueries(queryAllByRole, getMultipleError$1, getMissingError$1);\n\n\tconst getTestIdAttribute = () => getConfig().testIdAttribute;\n\n\tconst queryAllByTestId = function () {\n\t  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n\t    args[_key] = arguments[_key];\n\t  }\n\n\t  checkContainerType(args[0]);\n\t  return queryAllByAttribute(getTestIdAttribute(), ...args);\n\t};\n\n\tconst getMultipleError = (c, id) => \"Found multiple elements by: [\" + getTestIdAttribute() + \"=\\\"\" + id + \"\\\"]\";\n\n\tconst getMissingError = (c, id) => \"Unable to find an element by: [\" + getTestIdAttribute() + \"=\\\"\" + id + \"\\\"]\";\n\n\tconst queryAllByTestIdWithSuggestions = wrapAllByQueryWithSuggestion(queryAllByTestId, queryAllByTestId.name, 'queryAll');\n\tconst [queryByTestId, getAllByTestId, getByTestId, findAllByTestId, findByTestId] = buildQueries(queryAllByTestId, getMultipleError, getMissingError);\n\n\tvar queries = /*#__PURE__*/Object.freeze({\n\t\t__proto__: null,\n\t\tqueryAllByLabelText: queryAllByLabelTextWithSuggestions,\n\t\tqueryByLabelText: queryByLabelText,\n\t\tgetAllByLabelText: getAllByLabelTextWithSuggestions,\n\t\tgetByLabelText: getByLabelTextWithSuggestions,\n\t\tfindAllByLabelText: findAllByLabelText,\n\t\tfindByLabelText: findByLabelText,\n\t\tqueryByPlaceholderText: queryByPlaceholderText,\n\t\tqueryAllByPlaceholderText: queryAllByPlaceholderTextWithSuggestions,\n\t\tgetByPlaceholderText: getByPlaceholderText,\n\t\tgetAllByPlaceholderText: getAllByPlaceholderText,\n\t\tfindAllByPlaceholderText: findAllByPlaceholderText,\n\t\tfindByPlaceholderText: findByPlaceholderText,\n\t\tqueryByText: queryByText,\n\t\tqueryAllByText: queryAllByTextWithSuggestions,\n\t\tgetByText: getByText,\n\t\tgetAllByText: getAllByText,\n\t\tfindAllByText: findAllByText,\n\t\tfindByText: findByText,\n\t\tqueryByDisplayValue: queryByDisplayValue,\n\t\tqueryAllByDisplayValue: queryAllByDisplayValueWithSuggestions,\n\t\tgetByDisplayValue: getByDisplayValue,\n\t\tgetAllByDisplayValue: getAllByDisplayValue,\n\t\tfindAllByDisplayValue: findAllByDisplayValue,\n\t\tfindByDisplayValue: findByDisplayValue,\n\t\tqueryByAltText: queryByAltText,\n\t\tqueryAllByAltText: queryAllByAltTextWithSuggestions,\n\t\tgetByAltText: getByAltText,\n\t\tgetAllByAltText: getAllByAltText,\n\t\tfindAllByAltText: findAllByAltText,\n\t\tfindByAltText: findByAltText,\n\t\tqueryByTitle: queryByTitle,\n\t\tqueryAllByTitle: queryAllByTitleWithSuggestions,\n\t\tgetByTitle: getByTitle,\n\t\tgetAllByTitle: getAllByTitle,\n\t\tfindAllByTitle: findAllByTitle,\n\t\tfindByTitle: findByTitle,\n\t\tqueryByRole: queryByRole,\n\t\tqueryAllByRole: queryAllByRoleWithSuggestions,\n\t\tgetAllByRole: getAllByRole,\n\t\tgetByRole: getByRole,\n\t\tfindAllByRole: findAllByRole,\n\t\tfindByRole: findByRole,\n\t\tqueryByTestId: queryByTestId,\n\t\tqueryAllByTestId: queryAllByTestIdWithSuggestions,\n\t\tgetByTestId: getByTestId,\n\t\tgetAllByTestId: getAllByTestId,\n\t\tfindAllByTestId: findAllByTestId,\n\t\tfindByTestId: findByTestId\n\t});\n\n\t/**\n\t * @typedef {{[key: string]: Function}} FuncMap\n\t */\n\n\t/**\n\t * @param {HTMLElement} element container\n\t * @param {FuncMap} queries object of functions\n\t * @param {Object} initialValue for reducer\n\t * @returns {FuncMap} returns object of functions bound to container\n\t */\n\n\tfunction getQueriesForElement(element, queries$1, initialValue) {\n\t  if (queries$1 === void 0) {\n\t    queries$1 = queries;\n\t  }\n\n\t  if (initialValue === void 0) {\n\t    initialValue = {};\n\t  }\n\n\t  return Object.keys(queries$1).reduce((helpers, key) => {\n\t    const fn = queries$1[key];\n\t    helpers[key] = fn.bind(null, element);\n\t    return helpers;\n\t  }, initialValue);\n\t}\n\n\tconst isRemoved = result => !result || Array.isArray(result) && !result.length; // Check if the element is not present.\n\t// As the name implies, waitForElementToBeRemoved should check `present` --> `removed`\n\n\n\tfunction initialCheck(elements) {\n\t  if (isRemoved(elements)) {\n\t    throw new Error('The element(s) given to waitForElementToBeRemoved are already removed. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.');\n\t  }\n\t}\n\n\tasync function waitForElementToBeRemoved(callback, options) {\n\t  // created here so we get a nice stacktrace\n\t  const timeoutError = new Error('Timed out in waitForElementToBeRemoved.');\n\n\t  if (typeof callback !== 'function') {\n\t    initialCheck(callback);\n\t    const elements = Array.isArray(callback) ? callback : [callback];\n\t    const getRemainingElements = elements.map(element => {\n\t      let parent = element.parentElement;\n\t      if (parent === null) return () => null;\n\n\t      while (parent.parentElement) parent = parent.parentElement;\n\n\t      return () => parent.contains(element) ? element : null;\n\t    });\n\n\t    callback = () => getRemainingElements.map(c => c()).filter(Boolean);\n\t  }\n\n\t  initialCheck(callback());\n\t  return waitForWrapper(() => {\n\t    let result;\n\n\t    try {\n\t      result = callback();\n\t    } catch (error) {\n\t      if (error.name === 'TestingLibraryElementError') {\n\t        return undefined;\n\t      }\n\n\t      throw error;\n\t    }\n\n\t    if (!isRemoved(result)) {\n\t      throw timeoutError;\n\t    }\n\n\t    return undefined;\n\t  }, options);\n\t}\n\t/*\n\teslint\n\t  require-await: \"off\"\n\t*/\n\n\tconst eventMap = {\n\t  // Clipboard Events\n\t  copy: {\n\t    EventType: 'ClipboardEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  cut: {\n\t    EventType: 'ClipboardEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  paste: {\n\t    EventType: 'ClipboardEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  // Composition Events\n\t  compositionEnd: {\n\t    EventType: 'CompositionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  compositionStart: {\n\t    EventType: 'CompositionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  compositionUpdate: {\n\t    EventType: 'CompositionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  // Keyboard Events\n\t  keyDown: {\n\t    EventType: 'KeyboardEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      charCode: 0,\n\t      composed: true\n\t    }\n\t  },\n\t  keyPress: {\n\t    EventType: 'KeyboardEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      charCode: 0,\n\t      composed: true\n\t    }\n\t  },\n\t  keyUp: {\n\t    EventType: 'KeyboardEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      charCode: 0,\n\t      composed: true\n\t    }\n\t  },\n\t  // Focus Events\n\t  focus: {\n\t    EventType: 'FocusEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  blur: {\n\t    EventType: 'FocusEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  focusIn: {\n\t    EventType: 'FocusEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  focusOut: {\n\t    EventType: 'FocusEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  // Form Events\n\t  change: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  input: {\n\t    EventType: 'InputEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  invalid: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: true\n\t    }\n\t  },\n\t  submit: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true\n\t    }\n\t  },\n\t  reset: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true\n\t    }\n\t  },\n\t  // Mouse Events\n\t  click: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      button: 0,\n\t      composed: true\n\t    }\n\t  },\n\t  contextMenu: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  dblClick: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  drag: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  dragEnd: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  dragEnter: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  dragExit: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  dragLeave: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  dragOver: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  dragStart: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  drop: {\n\t    EventType: 'DragEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseDown: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseEnter: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseLeave: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseMove: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseOut: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseOver: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  mouseUp: {\n\t    EventType: 'MouseEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  // Selection Events\n\t  select: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  // Touch Events\n\t  touchCancel: {\n\t    EventType: 'TouchEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  touchEnd: {\n\t    EventType: 'TouchEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  touchMove: {\n\t    EventType: 'TouchEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  touchStart: {\n\t    EventType: 'TouchEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  // UI Events\n\t  resize: {\n\t    EventType: 'UIEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  scroll: {\n\t    EventType: 'UIEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  // Wheel Events\n\t  wheel: {\n\t    EventType: 'WheelEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  // Media Events\n\t  abort: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  canPlay: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  canPlayThrough: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  durationChange: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  emptied: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  encrypted: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  ended: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  loadedData: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  loadedMetadata: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  loadStart: {\n\t    EventType: 'ProgressEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  pause: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  play: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  playing: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  progress: {\n\t    EventType: 'ProgressEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  rateChange: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  seeked: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  seeking: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  stalled: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  suspend: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  timeUpdate: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  volumeChange: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  waiting: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  // Events\n\t  load: {\n\t    // TODO: load events can be UIEvent or Event depending on what generated them\n\t    // This is were this abstraction breaks down.\n\t    // But the common targets are <img />, <script /> and window.\n\t    // Neither of these targets receive a UIEvent\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  error: {\n\t    EventType: 'Event',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  // Animation Events\n\t  animationStart: {\n\t    EventType: 'AnimationEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  animationEnd: {\n\t    EventType: 'AnimationEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  animationIteration: {\n\t    EventType: 'AnimationEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  // Transition Events\n\t  transitionCancel: {\n\t    EventType: 'TransitionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  transitionEnd: {\n\t    EventType: 'TransitionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true\n\t    }\n\t  },\n\t  transitionRun: {\n\t    EventType: 'TransitionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  transitionStart: {\n\t    EventType: 'TransitionEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  },\n\t  // pointer events\n\t  pointerOver: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  pointerEnter: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  pointerDown: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  pointerMove: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  pointerUp: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  pointerCancel: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  pointerOut: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: true,\n\t      composed: true\n\t    }\n\t  },\n\t  pointerLeave: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: false,\n\t      cancelable: false\n\t    }\n\t  },\n\t  gotPointerCapture: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  lostPointerCapture: {\n\t    EventType: 'PointerEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false,\n\t      composed: true\n\t    }\n\t  },\n\t  // history events\n\t  popState: {\n\t    EventType: 'PopStateEvent',\n\t    defaultInit: {\n\t      bubbles: true,\n\t      cancelable: false\n\t    }\n\t  }\n\t};\n\tconst eventAliasMap = {\n\t  doubleClick: 'dblClick'\n\t};\n\n\tfunction fireEvent(element, event) {\n\t  return getConfig().eventWrapper(() => {\n\t    if (!event) {\n\t      throw new Error(\"Unable to fire an event - please provide an event object.\");\n\t    }\n\n\t    if (!element) {\n\t      throw new Error(\"Unable to fire a \\\"\" + event.type + \"\\\" event - please provide a DOM element.\");\n\t    }\n\n\t    return element.dispatchEvent(event);\n\t  });\n\t}\n\n\tfunction createEvent(eventName, node, init, _temp) {\n\t  let {\n\t    EventType = 'Event',\n\t    defaultInit = {}\n\t  } = _temp === void 0 ? {} : _temp;\n\n\t  if (!node) {\n\t    throw new Error(\"Unable to fire a \\\"\" + eventName + \"\\\" event - please provide a DOM element.\");\n\t  }\n\n\t  const eventInit = { ...defaultInit,\n\t    ...init\n\t  };\n\t  const {\n\t    target: {\n\t      value,\n\t      files,\n\t      ...targetProperties\n\t    } = {}\n\t  } = eventInit;\n\n\t  if (value !== undefined) {\n\t    setNativeValue(node, value);\n\t  }\n\n\t  if (files !== undefined) {\n\t    // input.files is a read-only property so this is not allowed:\n\t    // input.files = [file]\n\t    // so we have to use this workaround to set the property\n\t    Object.defineProperty(node, 'files', {\n\t      configurable: true,\n\t      enumerable: true,\n\t      writable: true,\n\t      value: files\n\t    });\n\t  }\n\n\t  Object.assign(node, targetProperties);\n\t  const window = getWindowFromNode(node);\n\t  const EventConstructor = window[EventType] || window.Event;\n\t  let event;\n\t  /* istanbul ignore else  */\n\n\t  if (typeof EventConstructor === 'function') {\n\t    event = new EventConstructor(eventName, eventInit);\n\t  } else {\n\t    // IE11 polyfill from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill\n\t    event = window.document.createEvent(EventType);\n\t    const {\n\t      bubbles,\n\t      cancelable,\n\t      detail,\n\t      ...otherInit\n\t    } = eventInit;\n\t    event.initEvent(eventName, bubbles, cancelable, detail);\n\t    Object.keys(otherInit).forEach(eventKey => {\n\t      event[eventKey] = otherInit[eventKey];\n\t    });\n\t  } // DataTransfer is not supported in jsdom: https://github.com/jsdom/jsdom/issues/1568\n\n\n\t  const dataTransferProperties = ['dataTransfer', 'clipboardData'];\n\t  dataTransferProperties.forEach(dataTransferKey => {\n\t    const dataTransferValue = eventInit[dataTransferKey];\n\n\t    if (typeof dataTransferValue === 'object') {\n\t      /* istanbul ignore if  */\n\t      if (typeof window.DataTransfer === 'function') {\n\t        Object.defineProperty(event, dataTransferKey, {\n\t          value: Object.getOwnPropertyNames(dataTransferValue).reduce((acc, propName) => {\n\t            Object.defineProperty(acc, propName, {\n\t              value: dataTransferValue[propName]\n\t            });\n\t            return acc;\n\t          }, new window.DataTransfer())\n\t        });\n\t      } else {\n\t        Object.defineProperty(event, dataTransferKey, {\n\t          value: dataTransferValue\n\t        });\n\t      }\n\t    }\n\t  });\n\t  return event;\n\t}\n\n\tObject.keys(eventMap).forEach(key => {\n\t  const {\n\t    EventType,\n\t    defaultInit\n\t  } = eventMap[key];\n\t  const eventName = key.toLowerCase();\n\n\t  createEvent[key] = (node, init) => createEvent(eventName, node, init, {\n\t    EventType,\n\t    defaultInit\n\t  });\n\n\t  fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](node, init));\n\t}); // function written after some investigation here:\n\t// https://github.com/facebook/react/issues/10135#issuecomment-401496776\n\n\tfunction setNativeValue(element, value) {\n\t  const {\n\t    set: valueSetter\n\t  } = Object.getOwnPropertyDescriptor(element, 'value') || {};\n\t  const prototype = Object.getPrototypeOf(element);\n\t  const {\n\t    set: prototypeValueSetter\n\t  } = Object.getOwnPropertyDescriptor(prototype, 'value') || {};\n\n\t  if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {\n\t    prototypeValueSetter.call(element, value);\n\t  } else {\n\t    /* istanbul ignore if */\n\t    // eslint-disable-next-line no-lonely-if -- Can't be ignored by istanbul otherwise\n\t    if (valueSetter) {\n\t      valueSetter.call(element, value);\n\t    } else {\n\t      throw new Error('The given element does not have a value setter');\n\t    }\n\t  }\n\t}\n\n\tObject.keys(eventAliasMap).forEach(aliasKey => {\n\t  const key = eventAliasMap[aliasKey];\n\n\t  fireEvent[aliasKey] = function () {\n\t    return fireEvent[key](...arguments);\n\t  };\n\t});\n\t/* eslint complexity:[\"error\", 9] */\n\n\tvar lzString$1 = {exports: {}};\n\n\t(function (module) {\n\t  // Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>\n\t  // This work is free. You can redistribute it and/or modify it\n\t  // under the terms of the WTFPL, Version 2\n\t  // For more information see LICENSE.txt or http://www.wtfpl.net/\n\t  //\n\t  // For more information, the home page:\n\t  // http://pieroxy.net/blog/pages/lz-string/testing.html\n\t  //\n\t  // LZ-based compression algorithm, version 1.4.4\n\t  var LZString = function () {\n\t    // private property\n\t    var f = String.fromCharCode;\n\t    var keyStrBase64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\t    var keyStrUriSafe = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$\";\n\t    var baseReverseDic = {};\n\n\t    function getBaseValue(alphabet, character) {\n\t      if (!baseReverseDic[alphabet]) {\n\t        baseReverseDic[alphabet] = {};\n\n\t        for (var i = 0; i < alphabet.length; i++) {\n\t          baseReverseDic[alphabet][alphabet.charAt(i)] = i;\n\t        }\n\t      }\n\n\t      return baseReverseDic[alphabet][character];\n\t    }\n\n\t    var LZString = {\n\t      compressToBase64: function (input) {\n\t        if (input == null) return \"\";\n\n\t        var res = LZString._compress(input, 6, function (a) {\n\t          return keyStrBase64.charAt(a);\n\t        });\n\n\t        switch (res.length % 4) {\n\t          // To produce valid Base64\n\t          default: // When could this happen ?\n\n\t          case 0:\n\t            return res;\n\n\t          case 1:\n\t            return res + \"===\";\n\n\t          case 2:\n\t            return res + \"==\";\n\n\t          case 3:\n\t            return res + \"=\";\n\t        }\n\t      },\n\t      decompressFromBase64: function (input) {\n\t        if (input == null) return \"\";\n\t        if (input == \"\") return null;\n\t        return LZString._decompress(input.length, 32, function (index) {\n\t          return getBaseValue(keyStrBase64, input.charAt(index));\n\t        });\n\t      },\n\t      compressToUTF16: function (input) {\n\t        if (input == null) return \"\";\n\t        return LZString._compress(input, 15, function (a) {\n\t          return f(a + 32);\n\t        }) + \" \";\n\t      },\n\t      decompressFromUTF16: function (compressed) {\n\t        if (compressed == null) return \"\";\n\t        if (compressed == \"\") return null;\n\t        return LZString._decompress(compressed.length, 16384, function (index) {\n\t          return compressed.charCodeAt(index) - 32;\n\t        });\n\t      },\n\t      //compress into uint8array (UCS-2 big endian format)\n\t      compressToUint8Array: function (uncompressed) {\n\t        var compressed = LZString.compress(uncompressed);\n\t        var buf = new Uint8Array(compressed.length * 2); // 2 bytes per character\n\n\t        for (var i = 0, TotalLen = compressed.length; i < TotalLen; i++) {\n\t          var current_value = compressed.charCodeAt(i);\n\t          buf[i * 2] = current_value >>> 8;\n\t          buf[i * 2 + 1] = current_value % 256;\n\t        }\n\n\t        return buf;\n\t      },\n\t      //decompress from uint8array (UCS-2 big endian format)\n\t      decompressFromUint8Array: function (compressed) {\n\t        if (compressed === null || compressed === undefined) {\n\t          return LZString.decompress(compressed);\n\t        } else {\n\t          var buf = new Array(compressed.length / 2); // 2 bytes per character\n\n\t          for (var i = 0, TotalLen = buf.length; i < TotalLen; i++) {\n\t            buf[i] = compressed[i * 2] * 256 + compressed[i * 2 + 1];\n\t          }\n\n\t          var result = [];\n\t          buf.forEach(function (c) {\n\t            result.push(f(c));\n\t          });\n\t          return LZString.decompress(result.join(''));\n\t        }\n\t      },\n\t      //compress into a string that is already URI encoded\n\t      compressToEncodedURIComponent: function (input) {\n\t        if (input == null) return \"\";\n\t        return LZString._compress(input, 6, function (a) {\n\t          return keyStrUriSafe.charAt(a);\n\t        });\n\t      },\n\t      //decompress from an output of compressToEncodedURIComponent\n\t      decompressFromEncodedURIComponent: function (input) {\n\t        if (input == null) return \"\";\n\t        if (input == \"\") return null;\n\t        input = input.replace(/ /g, \"+\");\n\t        return LZString._decompress(input.length, 32, function (index) {\n\t          return getBaseValue(keyStrUriSafe, input.charAt(index));\n\t        });\n\t      },\n\t      compress: function (uncompressed) {\n\t        return LZString._compress(uncompressed, 16, function (a) {\n\t          return f(a);\n\t        });\n\t      },\n\t      _compress: function (uncompressed, bitsPerChar, getCharFromInt) {\n\t        if (uncompressed == null) return \"\";\n\t        var i,\n\t            value,\n\t            context_dictionary = {},\n\t            context_dictionaryToCreate = {},\n\t            context_c = \"\",\n\t            context_wc = \"\",\n\t            context_w = \"\",\n\t            context_enlargeIn = 2,\n\t            // Compensate for the first entry which should not count\n\t        context_dictSize = 3,\n\t            context_numBits = 2,\n\t            context_data = [],\n\t            context_data_val = 0,\n\t            context_data_position = 0,\n\t            ii;\n\n\t        for (ii = 0; ii < uncompressed.length; ii += 1) {\n\t          context_c = uncompressed.charAt(ii);\n\n\t          if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {\n\t            context_dictionary[context_c] = context_dictSize++;\n\t            context_dictionaryToCreate[context_c] = true;\n\t          }\n\n\t          context_wc = context_w + context_c;\n\n\t          if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {\n\t            context_w = context_wc;\n\t          } else {\n\t            if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {\n\t              if (context_w.charCodeAt(0) < 256) {\n\t                for (i = 0; i < context_numBits; i++) {\n\t                  context_data_val = context_data_val << 1;\n\n\t                  if (context_data_position == bitsPerChar - 1) {\n\t                    context_data_position = 0;\n\t                    context_data.push(getCharFromInt(context_data_val));\n\t                    context_data_val = 0;\n\t                  } else {\n\t                    context_data_position++;\n\t                  }\n\t                }\n\n\t                value = context_w.charCodeAt(0);\n\n\t                for (i = 0; i < 8; i++) {\n\t                  context_data_val = context_data_val << 1 | value & 1;\n\n\t                  if (context_data_position == bitsPerChar - 1) {\n\t                    context_data_position = 0;\n\t                    context_data.push(getCharFromInt(context_data_val));\n\t                    context_data_val = 0;\n\t                  } else {\n\t                    context_data_position++;\n\t                  }\n\n\t                  value = value >> 1;\n\t                }\n\t              } else {\n\t                value = 1;\n\n\t                for (i = 0; i < context_numBits; i++) {\n\t                  context_data_val = context_data_val << 1 | value;\n\n\t                  if (context_data_position == bitsPerChar - 1) {\n\t                    context_data_position = 0;\n\t                    context_data.push(getCharFromInt(context_data_val));\n\t                    context_data_val = 0;\n\t                  } else {\n\t                    context_data_position++;\n\t                  }\n\n\t                  value = 0;\n\t                }\n\n\t                value = context_w.charCodeAt(0);\n\n\t                for (i = 0; i < 16; i++) {\n\t                  context_data_val = context_data_val << 1 | value & 1;\n\n\t                  if (context_data_position == bitsPerChar - 1) {\n\t                    context_data_position = 0;\n\t                    context_data.push(getCharFromInt(context_data_val));\n\t                    context_data_val = 0;\n\t                  } else {\n\t                    context_data_position++;\n\t                  }\n\n\t                  value = value >> 1;\n\t                }\n\t              }\n\n\t              context_enlargeIn--;\n\n\t              if (context_enlargeIn == 0) {\n\t                context_enlargeIn = Math.pow(2, context_numBits);\n\t                context_numBits++;\n\t              }\n\n\t              delete context_dictionaryToCreate[context_w];\n\t            } else {\n\t              value = context_dictionary[context_w];\n\n\t              for (i = 0; i < context_numBits; i++) {\n\t                context_data_val = context_data_val << 1 | value & 1;\n\n\t                if (context_data_position == bitsPerChar - 1) {\n\t                  context_data_position = 0;\n\t                  context_data.push(getCharFromInt(context_data_val));\n\t                  context_data_val = 0;\n\t                } else {\n\t                  context_data_position++;\n\t                }\n\n\t                value = value >> 1;\n\t              }\n\t            }\n\n\t            context_enlargeIn--;\n\n\t            if (context_enlargeIn == 0) {\n\t              context_enlargeIn = Math.pow(2, context_numBits);\n\t              context_numBits++;\n\t            } // Add wc to the dictionary.\n\n\n\t            context_dictionary[context_wc] = context_dictSize++;\n\t            context_w = String(context_c);\n\t          }\n\t        } // Output the code for w.\n\n\n\t        if (context_w !== \"\") {\n\t          if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {\n\t            if (context_w.charCodeAt(0) < 256) {\n\t              for (i = 0; i < context_numBits; i++) {\n\t                context_data_val = context_data_val << 1;\n\n\t                if (context_data_position == bitsPerChar - 1) {\n\t                  context_data_position = 0;\n\t                  context_data.push(getCharFromInt(context_data_val));\n\t                  context_data_val = 0;\n\t                } else {\n\t                  context_data_position++;\n\t                }\n\t              }\n\n\t              value = context_w.charCodeAt(0);\n\n\t              for (i = 0; i < 8; i++) {\n\t                context_data_val = context_data_val << 1 | value & 1;\n\n\t                if (context_data_position == bitsPerChar - 1) {\n\t                  context_data_position = 0;\n\t                  context_data.push(getCharFromInt(context_data_val));\n\t                  context_data_val = 0;\n\t                } else {\n\t                  context_data_position++;\n\t                }\n\n\t                value = value >> 1;\n\t              }\n\t            } else {\n\t              value = 1;\n\n\t              for (i = 0; i < context_numBits; i++) {\n\t                context_data_val = context_data_val << 1 | value;\n\n\t                if (context_data_position == bitsPerChar - 1) {\n\t                  context_data_position = 0;\n\t                  context_data.push(getCharFromInt(context_data_val));\n\t                  context_data_val = 0;\n\t                } else {\n\t                  context_data_position++;\n\t                }\n\n\t                value = 0;\n\t              }\n\n\t              value = context_w.charCodeAt(0);\n\n\t              for (i = 0; i < 16; i++) {\n\t                context_data_val = context_data_val << 1 | value & 1;\n\n\t                if (context_data_position == bitsPerChar - 1) {\n\t                  context_data_position = 0;\n\t                  context_data.push(getCharFromInt(context_data_val));\n\t                  context_data_val = 0;\n\t                } else {\n\t                  context_data_position++;\n\t                }\n\n\t                value = value >> 1;\n\t              }\n\t            }\n\n\t            context_enlargeIn--;\n\n\t            if (context_enlargeIn == 0) {\n\t              context_enlargeIn = Math.pow(2, context_numBits);\n\t              context_numBits++;\n\t            }\n\n\t            delete context_dictionaryToCreate[context_w];\n\t          } else {\n\t            value = context_dictionary[context_w];\n\n\t            for (i = 0; i < context_numBits; i++) {\n\t              context_data_val = context_data_val << 1 | value & 1;\n\n\t              if (context_data_position == bitsPerChar - 1) {\n\t                context_data_position = 0;\n\t                context_data.push(getCharFromInt(context_data_val));\n\t                context_data_val = 0;\n\t              } else {\n\t                context_data_position++;\n\t              }\n\n\t              value = value >> 1;\n\t            }\n\t          }\n\n\t          context_enlargeIn--;\n\n\t          if (context_enlargeIn == 0) {\n\t            context_enlargeIn = Math.pow(2, context_numBits);\n\t            context_numBits++;\n\t          }\n\t        } // Mark the end of the stream\n\n\n\t        value = 2;\n\n\t        for (i = 0; i < context_numBits; i++) {\n\t          context_data_val = context_data_val << 1 | value & 1;\n\n\t          if (context_data_position == bitsPerChar - 1) {\n\t            context_data_position = 0;\n\t            context_data.push(getCharFromInt(context_data_val));\n\t            context_data_val = 0;\n\t          } else {\n\t            context_data_position++;\n\t          }\n\n\t          value = value >> 1;\n\t        } // Flush the last char\n\n\n\t        while (true) {\n\t          context_data_val = context_data_val << 1;\n\n\t          if (context_data_position == bitsPerChar - 1) {\n\t            context_data.push(getCharFromInt(context_data_val));\n\t            break;\n\t          } else context_data_position++;\n\t        }\n\n\t        return context_data.join('');\n\t      },\n\t      decompress: function (compressed) {\n\t        if (compressed == null) return \"\";\n\t        if (compressed == \"\") return null;\n\t        return LZString._decompress(compressed.length, 32768, function (index) {\n\t          return compressed.charCodeAt(index);\n\t        });\n\t      },\n\t      _decompress: function (length, resetValue, getNextValue) {\n\t        var dictionary = [],\n\t            enlargeIn = 4,\n\t            dictSize = 4,\n\t            numBits = 3,\n\t            entry = \"\",\n\t            result = [],\n\t            i,\n\t            w,\n\t            bits,\n\t            resb,\n\t            maxpower,\n\t            power,\n\t            c,\n\t            data = {\n\t          val: getNextValue(0),\n\t          position: resetValue,\n\t          index: 1\n\t        };\n\n\t        for (i = 0; i < 3; i += 1) {\n\t          dictionary[i] = i;\n\t        }\n\n\t        bits = 0;\n\t        maxpower = Math.pow(2, 2);\n\t        power = 1;\n\n\t        while (power != maxpower) {\n\t          resb = data.val & data.position;\n\t          data.position >>= 1;\n\n\t          if (data.position == 0) {\n\t            data.position = resetValue;\n\t            data.val = getNextValue(data.index++);\n\t          }\n\n\t          bits |= (resb > 0 ? 1 : 0) * power;\n\t          power <<= 1;\n\t        }\n\n\t        switch (bits) {\n\t          case 0:\n\t            bits = 0;\n\t            maxpower = Math.pow(2, 8);\n\t            power = 1;\n\n\t            while (power != maxpower) {\n\t              resb = data.val & data.position;\n\t              data.position >>= 1;\n\n\t              if (data.position == 0) {\n\t                data.position = resetValue;\n\t                data.val = getNextValue(data.index++);\n\t              }\n\n\t              bits |= (resb > 0 ? 1 : 0) * power;\n\t              power <<= 1;\n\t            }\n\n\t            c = f(bits);\n\t            break;\n\n\t          case 1:\n\t            bits = 0;\n\t            maxpower = Math.pow(2, 16);\n\t            power = 1;\n\n\t            while (power != maxpower) {\n\t              resb = data.val & data.position;\n\t              data.position >>= 1;\n\n\t              if (data.position == 0) {\n\t                data.position = resetValue;\n\t                data.val = getNextValue(data.index++);\n\t              }\n\n\t              bits |= (resb > 0 ? 1 : 0) * power;\n\t              power <<= 1;\n\t            }\n\n\t            c = f(bits);\n\t            break;\n\n\t          case 2:\n\t            return \"\";\n\t        }\n\n\t        dictionary[3] = c;\n\t        w = c;\n\t        result.push(c);\n\n\t        while (true) {\n\t          if (data.index > length) {\n\t            return \"\";\n\t          }\n\n\t          bits = 0;\n\t          maxpower = Math.pow(2, numBits);\n\t          power = 1;\n\n\t          while (power != maxpower) {\n\t            resb = data.val & data.position;\n\t            data.position >>= 1;\n\n\t            if (data.position == 0) {\n\t              data.position = resetValue;\n\t              data.val = getNextValue(data.index++);\n\t            }\n\n\t            bits |= (resb > 0 ? 1 : 0) * power;\n\t            power <<= 1;\n\t          }\n\n\t          switch (c = bits) {\n\t            case 0:\n\t              bits = 0;\n\t              maxpower = Math.pow(2, 8);\n\t              power = 1;\n\n\t              while (power != maxpower) {\n\t                resb = data.val & data.position;\n\t                data.position >>= 1;\n\n\t                if (data.position == 0) {\n\t                  data.position = resetValue;\n\t                  data.val = getNextValue(data.index++);\n\t                }\n\n\t                bits |= (resb > 0 ? 1 : 0) * power;\n\t                power <<= 1;\n\t              }\n\n\t              dictionary[dictSize++] = f(bits);\n\t              c = dictSize - 1;\n\t              enlargeIn--;\n\t              break;\n\n\t            case 1:\n\t              bits = 0;\n\t              maxpower = Math.pow(2, 16);\n\t              power = 1;\n\n\t              while (power != maxpower) {\n\t                resb = data.val & data.position;\n\t                data.position >>= 1;\n\n\t                if (data.position == 0) {\n\t                  data.position = resetValue;\n\t                  data.val = getNextValue(data.index++);\n\t                }\n\n\t                bits |= (resb > 0 ? 1 : 0) * power;\n\t                power <<= 1;\n\t              }\n\n\t              dictionary[dictSize++] = f(bits);\n\t              c = dictSize - 1;\n\t              enlargeIn--;\n\t              break;\n\n\t            case 2:\n\t              return result.join('');\n\t          }\n\n\t          if (enlargeIn == 0) {\n\t            enlargeIn = Math.pow(2, numBits);\n\t            numBits++;\n\t          }\n\n\t          if (dictionary[c]) {\n\t            entry = dictionary[c];\n\t          } else {\n\t            if (c === dictSize) {\n\t              entry = w + w.charAt(0);\n\t            } else {\n\t              return null;\n\t            }\n\t          }\n\n\t          result.push(entry); // Add w+entry[0] to the dictionary.\n\n\t          dictionary[dictSize++] = w + entry.charAt(0);\n\t          enlargeIn--;\n\t          w = entry;\n\n\t          if (enlargeIn == 0) {\n\t            enlargeIn = Math.pow(2, numBits);\n\t            numBits++;\n\t          }\n\t        }\n\t      }\n\t    };\n\t    return LZString;\n\t  }();\n\n\t  if (module != null) {\n\t    module.exports = LZString;\n\t  }\n\t})(lzString$1);\n\n\tvar lzString = lzString$1.exports;\n\n\t// WARNING: `lz-string` only has a default export but statically we assume named exports are allowd\n\n\tfunction unindent(string) {\n\t  // remove white spaces first, to save a few bytes.\n\t  // testing-playground will reformat on load any ways.\n\t  return string.replace(/[ \\t]*[\\n][ \\t]*/g, '\\n');\n\t}\n\n\tfunction encode(value) {\n\t  return lzString.compressToEncodedURIComponent(unindent(value));\n\t}\n\n\tfunction getPlaygroundUrl(markup) {\n\t  return \"https://testing-playground.com/#markup=\" + encode(markup);\n\t}\n\n\tconst debug = (element, maxLength, options) => Array.isArray(element) ? element.forEach(el => logDOM(el, maxLength, options)) : logDOM(element, maxLength, options);\n\n\tconst logTestingPlaygroundURL = function (element) {\n\t  if (element === void 0) {\n\t    element = getDocument().body;\n\t  }\n\n\t  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\t  if (!element || !('innerHTML' in element)) {\n\t    console.log(\"The element you're providing isn't a valid DOM element.\");\n\t    return;\n\t  } // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\n\n\t  if (!element.innerHTML) {\n\t    console.log(\"The provided element doesn't have any children.\");\n\t    return;\n\t  }\n\n\t  const playgroundUrl = getPlaygroundUrl(element.innerHTML);\n\t  console.log(\"Open this URL in your browser\\n\\n\" + playgroundUrl);\n\t  return playgroundUrl;\n\t};\n\n\tconst initialValue = {\n\t  debug,\n\t  logTestingPlaygroundURL\n\t};\n\tconst screen = typeof document !== 'undefined' && document.body // eslint-disable-line @typescript-eslint/no-unnecessary-condition\n\t? getQueriesForElement(document.body, queries, initialValue) : Object.keys(queries).reduce((helpers, key) => {\n\t  // `key` is for all intents and purposes the type of keyof `helpers`, which itself is the type of `initialValue` plus incoming properties from `queries`\n\t  // if `Object.keys(something)` returned Array<keyof typeof something> this explicit type assertion would not be necessary\n\t  // see https://stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript\n\t  helpers[key] = () => {\n\t    throw new TypeError('For queries bound to document.body a global document has to be available... Learn more: https://testing-library.com/s/screen-global-error');\n\t  };\n\n\t  return helpers;\n\t}, initialValue);\n\n\texports.buildQueries = buildQueries;\n\texports.configure = configure;\n\texports.createEvent = createEvent;\n\texports.findAllByAltText = findAllByAltText;\n\texports.findAllByDisplayValue = findAllByDisplayValue;\n\texports.findAllByLabelText = findAllByLabelText;\n\texports.findAllByPlaceholderText = findAllByPlaceholderText;\n\texports.findAllByRole = findAllByRole;\n\texports.findAllByTestId = findAllByTestId;\n\texports.findAllByText = findAllByText;\n\texports.findAllByTitle = findAllByTitle;\n\texports.findByAltText = findByAltText;\n\texports.findByDisplayValue = findByDisplayValue;\n\texports.findByLabelText = findByLabelText;\n\texports.findByPlaceholderText = findByPlaceholderText;\n\texports.findByRole = findByRole;\n\texports.findByTestId = findByTestId;\n\texports.findByText = findByText;\n\texports.findByTitle = findByTitle;\n\texports.fireEvent = fireEvent;\n\texports.getAllByAltText = getAllByAltText;\n\texports.getAllByDisplayValue = getAllByDisplayValue;\n\texports.getAllByLabelText = getAllByLabelTextWithSuggestions;\n\texports.getAllByPlaceholderText = getAllByPlaceholderText;\n\texports.getAllByRole = getAllByRole;\n\texports.getAllByTestId = getAllByTestId;\n\texports.getAllByText = getAllByText;\n\texports.getAllByTitle = getAllByTitle;\n\texports.getByAltText = getByAltText;\n\texports.getByDisplayValue = getByDisplayValue;\n\texports.getByLabelText = getByLabelTextWithSuggestions;\n\texports.getByPlaceholderText = getByPlaceholderText;\n\texports.getByRole = getByRole;\n\texports.getByTestId = getByTestId;\n\texports.getByText = getByText;\n\texports.getByTitle = getByTitle;\n\texports.getConfig = getConfig;\n\texports.getDefaultNormalizer = getDefaultNormalizer;\n\texports.getElementError = getElementError;\n\texports.getMultipleElementsFoundError = getMultipleElementsFoundError;\n\texports.getNodeText = getNodeText;\n\texports.getQueriesForElement = getQueriesForElement;\n\texports.getRoles = getRoles;\n\texports.getSuggestedQuery = getSuggestedQuery;\n\texports.isInaccessible = isInaccessible;\n\texports.logDOM = logDOM;\n\texports.logRoles = logRoles;\n\texports.makeFindQuery = makeFindQuery;\n\texports.makeGetAllQuery = makeGetAllQuery;\n\texports.makeSingleQuery = makeSingleQuery;\n\texports.prettyDOM = prettyDOM;\n\texports.prettyFormat = index;\n\texports.queries = queries;\n\texports.queryAllByAltText = queryAllByAltTextWithSuggestions;\n\texports.queryAllByAttribute = queryAllByAttribute;\n\texports.queryAllByDisplayValue = queryAllByDisplayValueWithSuggestions;\n\texports.queryAllByLabelText = queryAllByLabelTextWithSuggestions;\n\texports.queryAllByPlaceholderText = queryAllByPlaceholderTextWithSuggestions;\n\texports.queryAllByRole = queryAllByRoleWithSuggestions;\n\texports.queryAllByTestId = queryAllByTestIdWithSuggestions;\n\texports.queryAllByText = queryAllByTextWithSuggestions;\n\texports.queryAllByTitle = queryAllByTitleWithSuggestions;\n\texports.queryByAltText = queryByAltText;\n\texports.queryByAttribute = queryByAttribute;\n\texports.queryByDisplayValue = queryByDisplayValue;\n\texports.queryByLabelText = queryByLabelText;\n\texports.queryByPlaceholderText = queryByPlaceholderText;\n\texports.queryByRole = queryByRole;\n\texports.queryByTestId = queryByTestId;\n\texports.queryByText = queryByText;\n\texports.queryByTitle = queryByTitle;\n\texports.queryHelpers = queryHelpers;\n\texports.screen = screen;\n\texports.waitFor = waitForWrapper;\n\texports.waitForElementToBeRemoved = waitForElementToBeRemoved;\n\texports.within = getQueriesForElement;\n\texports.wrapAllByQueryWithSuggestion = wrapAllByQueryWithSuggestion;\n\texports.wrapSingleQueryWithSuggestion = wrapSingleQueryWithSuggestion;\n\n\tObject.defineProperty(exports, '__esModule', { value: true });\n\n}));\n//# sourceMappingURL=dom.umd.js.map\n"
  },
  {
    "path": "public/tests/lib/mocha/chai.js",
    "content": "(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.chai = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\nmodule.exports = require('./lib/chai');\n\n},{\"./lib/chai\":2}],2:[function(require,module,exports){\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar used = [];\n\n/*!\n * Chai version\n */\n\nexports.version = '4.3.3';\n\n/*!\n * Assertion Error\n */\n\nexports.AssertionError = require('assertion-error');\n\n/*!\n * Utils for plugins (not exported)\n */\n\nvar util = require('./chai/utils');\n\n/**\n * # .use(function)\n *\n * Provides a way to extend the internals of Chai.\n *\n * @param {Function}\n * @returns {this} for chaining\n * @api public\n */\n\nexports.use = function (fn) {\n  if (!~used.indexOf(fn)) {\n    fn(exports, util);\n    used.push(fn);\n  }\n\n  return exports;\n};\n\n/*!\n * Utility Functions\n */\n\nexports.util = util;\n\n/*!\n * Configuration\n */\n\nvar config = require('./chai/config');\nexports.config = config;\n\n/*!\n * Primary `Assertion` prototype\n */\n\nvar assertion = require('./chai/assertion');\nexports.use(assertion);\n\n/*!\n * Core Assertions\n */\n\nvar core = require('./chai/core/assertions');\nexports.use(core);\n\n/*!\n * Expect interface\n */\n\nvar expect = require('./chai/interface/expect');\nexports.use(expect);\n\n/*!\n * Should interface\n */\n\nvar should = require('./chai/interface/should');\nexports.use(should);\n\n/*!\n * Assert interface\n */\n\nvar assert = require('./chai/interface/assert');\nexports.use(assert);\n\n},{\"./chai/assertion\":3,\"./chai/config\":4,\"./chai/core/assertions\":5,\"./chai/interface/assert\":6,\"./chai/interface/expect\":7,\"./chai/interface/should\":8,\"./chai/utils\":22,\"assertion-error\":33}],3:[function(require,module,exports){\n/*!\n * chai\n * http://chaijs.com\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar config = require('./config');\n\nmodule.exports = function (_chai, util) {\n  /*!\n   * Module dependencies.\n   */\n\n  var AssertionError = _chai.AssertionError\n    , flag = util.flag;\n\n  /*!\n   * Module export.\n   */\n\n  _chai.Assertion = Assertion;\n\n  /*!\n   * Assertion Constructor\n   *\n   * Creates object for chaining.\n   *\n   * `Assertion` objects contain metadata in the form of flags. Three flags can\n   * be assigned during instantiation by passing arguments to this constructor:\n   *\n   * - `object`: This flag contains the target of the assertion. For example, in\n   *   the assertion `expect(numKittens).to.equal(7);`, the `object` flag will\n   *   contain `numKittens` so that the `equal` assertion can reference it when\n   *   needed.\n   *\n   * - `message`: This flag contains an optional custom error message to be\n   *   prepended to the error message that's generated by the assertion when it\n   *   fails.\n   *\n   * - `ssfi`: This flag stands for \"start stack function indicator\". It\n   *   contains a function reference that serves as the starting point for\n   *   removing frames from the stack trace of the error that's created by the\n   *   assertion when it fails. The goal is to provide a cleaner stack trace to\n   *   end users by removing Chai's internal functions. Note that it only works\n   *   in environments that support `Error.captureStackTrace`, and only when\n   *   `Chai.config.includeStack` hasn't been set to `false`.\n   *\n   * - `lockSsfi`: This flag controls whether or not the given `ssfi` flag\n   *   should retain its current value, even as assertions are chained off of\n   *   this object. This is usually set to `true` when creating a new assertion\n   *   from within another assertion. It's also temporarily set to `true` before\n   *   an overwritten assertion gets called by the overwriting assertion.\n   *\n   * @param {Mixed} obj target of the assertion\n   * @param {String} msg (optional) custom error message\n   * @param {Function} ssfi (optional) starting point for removing stack frames\n   * @param {Boolean} lockSsfi (optional) whether or not the ssfi flag is locked\n   * @api private\n   */\n\n  function Assertion (obj, msg, ssfi, lockSsfi) {\n    flag(this, 'ssfi', ssfi || Assertion);\n    flag(this, 'lockSsfi', lockSsfi);\n    flag(this, 'object', obj);\n    flag(this, 'message', msg);\n\n    return util.proxify(this);\n  }\n\n  Object.defineProperty(Assertion, 'includeStack', {\n    get: function() {\n      console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.');\n      return config.includeStack;\n    },\n    set: function(value) {\n      console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.');\n      config.includeStack = value;\n    }\n  });\n\n  Object.defineProperty(Assertion, 'showDiff', {\n    get: function() {\n      console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.');\n      return config.showDiff;\n    },\n    set: function(value) {\n      console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.');\n      config.showDiff = value;\n    }\n  });\n\n  Assertion.addProperty = function (name, fn) {\n    util.addProperty(this.prototype, name, fn);\n  };\n\n  Assertion.addMethod = function (name, fn) {\n    util.addMethod(this.prototype, name, fn);\n  };\n\n  Assertion.addChainableMethod = function (name, fn, chainingBehavior) {\n    util.addChainableMethod(this.prototype, name, fn, chainingBehavior);\n  };\n\n  Assertion.overwriteProperty = function (name, fn) {\n    util.overwriteProperty(this.prototype, name, fn);\n  };\n\n  Assertion.overwriteMethod = function (name, fn) {\n    util.overwriteMethod(this.prototype, name, fn);\n  };\n\n  Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) {\n    util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior);\n  };\n\n  /**\n   * ### .assert(expression, message, negateMessage, expected, actual, showDiff)\n   *\n   * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass.\n   *\n   * @name assert\n   * @param {Philosophical} expression to be tested\n   * @param {String|Function} message or function that returns message to display if expression fails\n   * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails\n   * @param {Mixed} expected value (remember to check for negation)\n   * @param {Mixed} actual (optional) will default to `this.obj`\n   * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails\n   * @api private\n   */\n\n  Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) {\n    var ok = util.test(this, arguments);\n    if (false !== showDiff) showDiff = true;\n    if (undefined === expected && undefined === _actual) showDiff = false;\n    if (true !== config.showDiff) showDiff = false;\n\n    if (!ok) {\n      msg = util.getMessage(this, arguments);\n      var actual = util.getActual(this, arguments);\n      var assertionErrorObjectProperties = {\n          actual: actual\n        , expected: expected\n        , showDiff: showDiff\n      };\n\n      var operator = util.getOperator(this, arguments);\n      if (operator) {\n        assertionErrorObjectProperties.operator = operator;\n      }\n\n      throw new AssertionError(\n        msg,\n        assertionErrorObjectProperties,\n        (config.includeStack) ? this.assert : flag(this, 'ssfi'));\n    }\n  };\n\n  /*!\n   * ### ._obj\n   *\n   * Quick reference to stored `actual` value for plugin developers.\n   *\n   * @api private\n   */\n\n  Object.defineProperty(Assertion.prototype, '_obj',\n    { get: function () {\n        return flag(this, 'object');\n      }\n    , set: function (val) {\n        flag(this, 'object', val);\n      }\n  });\n};\n\n},{\"./config\":4}],4:[function(require,module,exports){\nmodule.exports = {\n\n  /**\n   * ### config.includeStack\n   *\n   * User configurable property, influences whether stack trace\n   * is included in Assertion error message. Default of false\n   * suppresses stack trace in the error message.\n   *\n   *     chai.config.includeStack = true;  // enable stack on error\n   *\n   * @param {Boolean}\n   * @api public\n   */\n\n  includeStack: false,\n\n  /**\n   * ### config.showDiff\n   *\n   * User configurable property, influences whether or not\n   * the `showDiff` flag should be included in the thrown\n   * AssertionErrors. `false` will always be `false`; `true`\n   * will be true when the assertion has requested a diff\n   * be shown.\n   *\n   * @param {Boolean}\n   * @api public\n   */\n\n  showDiff: true,\n\n  /**\n   * ### config.truncateThreshold\n   *\n   * User configurable property, sets length threshold for actual and\n   * expected values in assertion errors. If this threshold is exceeded, for\n   * example for large data structures, the value is replaced with something\n   * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`.\n   *\n   * Set it to zero if you want to disable truncating altogether.\n   *\n   * This is especially userful when doing assertions on arrays: having this\n   * set to a reasonable large value makes the failure messages readily\n   * inspectable.\n   *\n   *     chai.config.truncateThreshold = 0;  // disable truncating\n   *\n   * @param {Number}\n   * @api public\n   */\n\n  truncateThreshold: 40,\n\n  /**\n   * ### config.useProxy\n   *\n   * User configurable property, defines if chai will use a Proxy to throw\n   * an error when a non-existent property is read, which protects users\n   * from typos when using property-based assertions.\n   *\n   * Set it to false if you want to disable this feature.\n   *\n   *     chai.config.useProxy = false;  // disable use of Proxy\n   *\n   * This feature is automatically disabled regardless of this config value\n   * in environments that don't support proxies.\n   *\n   * @param {Boolean}\n   * @api public\n   */\n\n  useProxy: true,\n\n  /**\n   * ### config.proxyExcludedKeys\n   *\n   * User configurable property, defines which properties should be ignored\n   * instead of throwing an error if they do not exist on the assertion.\n   * This is only applied if the environment Chai is running in supports proxies and\n   * if the `useProxy` configuration setting is enabled.\n   * By default, `then` and `inspect` will not throw an error if they do not exist on the\n   * assertion object because the `.inspect` property is read by `util.inspect` (for example, when\n   * using `console.log` on the assertion object) and `.then` is necessary for promise type-checking.\n   *\n   *     // By default these keys will not throw an error if they do not exist on the assertion object\n   *     chai.config.proxyExcludedKeys = ['then', 'inspect'];\n   *\n   * @param {Array}\n   * @api public\n   */\n\n  proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON']\n};\n\n},{}],5:[function(require,module,exports){\n/*!\n * chai\n * http://chaijs.com\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, _) {\n  var Assertion = chai.Assertion\n    , AssertionError = chai.AssertionError\n    , flag = _.flag;\n\n  /**\n   * ### Language Chains\n   *\n   * The following are provided as chainable getters to improve the readability\n   * of your assertions.\n   *\n   * **Chains**\n   *\n   * - to\n   * - be\n   * - been\n   * - is\n   * - that\n   * - which\n   * - and\n   * - has\n   * - have\n   * - with\n   * - at\n   * - of\n   * - same\n   * - but\n   * - does\n   * - still\n   * - also\n   *\n   * @name language chains\n   * @namespace BDD\n   * @api public\n   */\n\n  [ 'to', 'be', 'been', 'is'\n  , 'and', 'has', 'have', 'with'\n  , 'that', 'which', 'at', 'of'\n  , 'same', 'but', 'does', 'still', \"also\" ].forEach(function (chain) {\n    Assertion.addProperty(chain);\n  });\n\n  /**\n   * ### .not\n   *\n   * Negates all assertions that follow in the chain.\n   *\n   *     expect(function () {}).to.not.throw();\n   *     expect({a: 1}).to.not.have.property('b');\n   *     expect([1, 2]).to.be.an('array').that.does.not.include(3);\n   *\n   * Just because you can negate any assertion with `.not` doesn't mean you\n   * should. With great power comes great responsibility. It's often best to\n   * assert that the one expected output was produced, rather than asserting\n   * that one of countless unexpected outputs wasn't produced. See individual\n   * assertions for specific guidance.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(2).to.not.equal(1); // Not recommended\n   *\n   * @name not\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('not', function () {\n    flag(this, 'negate', true);\n  });\n\n  /**\n   * ### .deep\n   *\n   * Causes all `.equal`, `.include`, `.members`, `.keys`, and `.property`\n   * assertions that follow in the chain to use deep equality instead of strict\n   * (`===`) equality. See the `deep-eql` project page for info on the deep\n   * equality algorithm: https://github.com/chaijs/deep-eql.\n   *\n   *     // Target object deeply (but not strictly) equals `{a: 1}`\n   *     expect({a: 1}).to.deep.equal({a: 1});\n   *     expect({a: 1}).to.not.equal({a: 1});\n   *\n   *     // Target array deeply (but not strictly) includes `{a: 1}`\n   *     expect([{a: 1}]).to.deep.include({a: 1});\n   *     expect([{a: 1}]).to.not.include({a: 1});\n   *\n   *     // Target object deeply (but not strictly) includes `x: {a: 1}`\n   *     expect({x: {a: 1}}).to.deep.include({x: {a: 1}});\n   *     expect({x: {a: 1}}).to.not.include({x: {a: 1}});\n   *\n   *     // Target array deeply (but not strictly) has member `{a: 1}`\n   *     expect([{a: 1}]).to.have.deep.members([{a: 1}]);\n   *     expect([{a: 1}]).to.not.have.members([{a: 1}]);\n   *\n   *     // Target set deeply (but not strictly) has key `{a: 1}`\n   *     expect(new Set([{a: 1}])).to.have.deep.keys([{a: 1}]);\n   *     expect(new Set([{a: 1}])).to.not.have.keys([{a: 1}]);\n   *\n   *     // Target object deeply (but not strictly) has property `x: {a: 1}`\n   *     expect({x: {a: 1}}).to.have.deep.property('x', {a: 1});\n   *     expect({x: {a: 1}}).to.not.have.property('x', {a: 1});\n   *\n   * @name deep\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('deep', function () {\n    flag(this, 'deep', true);\n  });\n\n  /**\n   * ### .nested\n   *\n   * Enables dot- and bracket-notation in all `.property` and `.include`\n   * assertions that follow in the chain.\n   *\n   *     expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]');\n   *     expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'});\n   *\n   * If `.` or `[]` are part of an actual property name, they can be escaped by\n   * adding two backslashes before them.\n   *\n   *     expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\\\.a.\\\\[b\\\\]');\n   *     expect({'.a': {'[b]': 'x'}}).to.nested.include({'\\\\.a.\\\\[b\\\\]': 'x'});\n   *\n   * `.nested` cannot be combined with `.own`.\n   *\n   * @name nested\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('nested', function () {\n    flag(this, 'nested', true);\n  });\n\n  /**\n   * ### .own\n   *\n   * Causes all `.property` and `.include` assertions that follow in the chain\n   * to ignore inherited properties.\n   *\n   *     Object.prototype.b = 2;\n   *\n   *     expect({a: 1}).to.have.own.property('a');\n   *     expect({a: 1}).to.have.property('b');\n   *     expect({a: 1}).to.not.have.own.property('b');\n   *\n   *     expect({a: 1}).to.own.include({a: 1});\n   *     expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2});\n   *\n   * `.own` cannot be combined with `.nested`.\n   *\n   * @name own\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('own', function () {\n    flag(this, 'own', true);\n  });\n\n  /**\n   * ### .ordered\n   *\n   * Causes all `.members` assertions that follow in the chain to require that\n   * members be in the same order.\n   *\n   *     expect([1, 2]).to.have.ordered.members([1, 2])\n   *       .but.not.have.ordered.members([2, 1]);\n   *\n   * When `.include` and `.ordered` are combined, the ordering begins at the\n   * start of both arrays.\n   *\n   *     expect([1, 2, 3]).to.include.ordered.members([1, 2])\n   *       .but.not.include.ordered.members([2, 3]);\n   *\n   * @name ordered\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('ordered', function () {\n    flag(this, 'ordered', true);\n  });\n\n  /**\n   * ### .any\n   *\n   * Causes all `.keys` assertions that follow in the chain to only require that\n   * the target have at least one of the given keys. This is the opposite of\n   * `.all`, which requires that the target have all of the given keys.\n   *\n   *     expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');\n   *\n   * See the `.keys` doc for guidance on when to use `.any` or `.all`.\n   *\n   * @name any\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('any', function () {\n    flag(this, 'any', true);\n    flag(this, 'all', false);\n  });\n\n  /**\n   * ### .all\n   *\n   * Causes all `.keys` assertions that follow in the chain to require that the\n   * target have all of the given keys. This is the opposite of `.any`, which\n   * only requires that the target have at least one of the given keys.\n   *\n   *     expect({a: 1, b: 2}).to.have.all.keys('a', 'b');\n   *\n   * Note that `.all` is used by default when neither `.all` nor `.any` are\n   * added earlier in the chain. However, it's often best to add `.all` anyway\n   * because it improves readability.\n   *\n   * See the `.keys` doc for guidance on when to use `.any` or `.all`.\n   *\n   * @name all\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('all', function () {\n    flag(this, 'all', true);\n    flag(this, 'any', false);\n  });\n\n  /**\n   * ### .a(type[, msg])\n   *\n   * Asserts that the target's type is equal to the given string `type`. Types\n   * are case insensitive. See the `type-detect` project page for info on the\n   * type detection algorithm: https://github.com/chaijs/type-detect.\n   *\n   *     expect('foo').to.be.a('string');\n   *     expect({a: 1}).to.be.an('object');\n   *     expect(null).to.be.a('null');\n   *     expect(undefined).to.be.an('undefined');\n   *     expect(new Error).to.be.an('error');\n   *     expect(Promise.resolve()).to.be.a('promise');\n   *     expect(new Float32Array).to.be.a('float32array');\n   *     expect(Symbol()).to.be.a('symbol');\n   *\n   * `.a` supports objects that have a custom type set via `Symbol.toStringTag`.\n   *\n   *     var myObj = {\n   *       [Symbol.toStringTag]: 'myCustomType'\n   *     };\n   *\n   *     expect(myObj).to.be.a('myCustomType').but.not.an('object');\n   *\n   * It's often best to use `.a` to check a target's type before making more\n   * assertions on the same target. That way, you avoid unexpected behavior from\n   * any assertion that does different things based on the target's type.\n   *\n   *     expect([1, 2, 3]).to.be.an('array').that.includes(2);\n   *     expect([]).to.be.an('array').that.is.empty;\n   *\n   * Add `.not` earlier in the chain to negate `.a`. However, it's often best to\n   * assert that the target is the expected type, rather than asserting that it\n   * isn't one of many unexpected types.\n   *\n   *     expect('foo').to.be.a('string'); // Recommended\n   *     expect('foo').to.not.be.an('array'); // Not recommended\n   *\n   * `.a` accepts an optional `msg` argument which is a custom error message to\n   * show when the assertion fails. The message can also be given as the second\n   * argument to `expect`.\n   *\n   *     expect(1).to.be.a('string', 'nooo why fail??');\n   *     expect(1, 'nooo why fail??').to.be.a('string');\n   *\n   * `.a` can also be used as a language chain to improve the readability of\n   * your assertions.\n   *\n   *     expect({b: 2}).to.have.a.property('b');\n   *\n   * The alias `.an` can be used interchangeably with `.a`.\n   *\n   * @name a\n   * @alias an\n   * @param {String} type\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function an (type, msg) {\n    if (msg) flag(this, 'message', msg);\n    type = type.toLowerCase();\n    var obj = flag(this, 'object')\n      , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';\n\n    this.assert(\n        type === _.type(obj).toLowerCase()\n      , 'expected #{this} to be ' + article + type\n      , 'expected #{this} not to be ' + article + type\n    );\n  }\n\n  Assertion.addChainableMethod('an', an);\n  Assertion.addChainableMethod('a', an);\n\n  /**\n   * ### .include(val[, msg])\n   *\n   * When the target is a string, `.include` asserts that the given string `val`\n   * is a substring of the target.\n   *\n   *     expect('foobar').to.include('foo');\n   *\n   * When the target is an array, `.include` asserts that the given `val` is a\n   * member of the target.\n   *\n   *     expect([1, 2, 3]).to.include(2);\n   *\n   * When the target is an object, `.include` asserts that the given object\n   * `val`'s properties are a subset of the target's properties.\n   *\n   *     expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2});\n   *\n   * When the target is a Set or WeakSet, `.include` asserts that the given `val` is a\n   * member of the target. SameValueZero equality algorithm is used.\n   *\n   *     expect(new Set([1, 2])).to.include(2);\n   *\n   * When the target is a Map, `.include` asserts that the given `val` is one of\n   * the values of the target. SameValueZero equality algorithm is used.\n   *\n   *     expect(new Map([['a', 1], ['b', 2]])).to.include(2);\n   *\n   * Because `.include` does different things based on the target's type, it's\n   * important to check the target's type before using `.include`. See the `.a`\n   * doc for info on testing a target's type.\n   *\n   *     expect([1, 2, 3]).to.be.an('array').that.includes(2);\n   *\n   * By default, strict (`===`) equality is used to compare array members and\n   * object properties. Add `.deep` earlier in the chain to use deep equality\n   * instead (WeakSet targets are not supported). See the `deep-eql` project\n   * page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql.\n   *\n   *     // Target array deeply (but not strictly) includes `{a: 1}`\n   *     expect([{a: 1}]).to.deep.include({a: 1});\n   *     expect([{a: 1}]).to.not.include({a: 1});\n   *\n   *     // Target object deeply (but not strictly) includes `x: {a: 1}`\n   *     expect({x: {a: 1}}).to.deep.include({x: {a: 1}});\n   *     expect({x: {a: 1}}).to.not.include({x: {a: 1}});\n   *\n   * By default, all of the target's properties are searched when working with\n   * objects. This includes properties that are inherited and/or non-enumerable.\n   * Add `.own` earlier in the chain to exclude the target's inherited\n   * properties from the search.\n   *\n   *     Object.prototype.b = 2;\n   *\n   *     expect({a: 1}).to.own.include({a: 1});\n   *     expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2});\n   *\n   * Note that a target object is always only searched for `val`'s own\n   * enumerable properties.\n   *\n   * `.deep` and `.own` can be combined.\n   *\n   *     expect({a: {b: 2}}).to.deep.own.include({a: {b: 2}});\n   *\n   * Add `.nested` earlier in the chain to enable dot- and bracket-notation when\n   * referencing nested properties.\n   *\n   *     expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'});\n   *\n   * If `.` or `[]` are part of an actual property name, they can be escaped by\n   * adding two backslashes before them.\n   *\n   *     expect({'.a': {'[b]': 2}}).to.nested.include({'\\\\.a.\\\\[b\\\\]': 2});\n   *\n   * `.deep` and `.nested` can be combined.\n   *\n   *     expect({a: {b: [{c: 3}]}}).to.deep.nested.include({'a.b[0]': {c: 3}});\n   *\n   * `.own` and `.nested` cannot be combined.\n   *\n   * Add `.not` earlier in the chain to negate `.include`.\n   *\n   *     expect('foobar').to.not.include('taco');\n   *     expect([1, 2, 3]).to.not.include(4);\n   *\n   * However, it's dangerous to negate `.include` when the target is an object.\n   * The problem is that it creates uncertain expectations by asserting that the\n   * target object doesn't have all of `val`'s key/value pairs but may or may\n   * not have some of them. It's often best to identify the exact output that's\n   * expected, and then write an assertion that only accepts that exact output.\n   *\n   * When the target object isn't even expected to have `val`'s keys, it's\n   * often best to assert exactly that.\n   *\n   *     expect({c: 3}).to.not.have.any.keys('a', 'b'); // Recommended\n   *     expect({c: 3}).to.not.include({a: 1, b: 2}); // Not recommended\n   *\n   * When the target object is expected to have `val`'s keys, it's often best to\n   * assert that each of the properties has its expected value, rather than\n   * asserting that each property doesn't have one of many unexpected values.\n   *\n   *     expect({a: 3, b: 4}).to.include({a: 3, b: 4}); // Recommended\n   *     expect({a: 3, b: 4}).to.not.include({a: 1, b: 2}); // Not recommended\n   *\n   * `.include` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect([1, 2, 3]).to.include(4, 'nooo why fail??');\n   *     expect([1, 2, 3], 'nooo why fail??').to.include(4);\n   *\n   * `.include` can also be used as a language chain, causing all `.members` and\n   * `.keys` assertions that follow in the chain to require the target to be a\n   * superset of the expected set, rather than an identical set. Note that\n   * `.members` ignores duplicates in the subset when `.include` is added.\n   *\n   *     // Target object's keys are a superset of ['a', 'b'] but not identical\n   *     expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b');\n   *     expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b');\n   *\n   *     // Target array is a superset of [1, 2] but not identical\n   *     expect([1, 2, 3]).to.include.members([1, 2]);\n   *     expect([1, 2, 3]).to.not.have.members([1, 2]);\n   *\n   *     // Duplicates in the subset are ignored\n   *     expect([1, 2, 3]).to.include.members([1, 2, 2, 2]);\n   *\n   * Note that adding `.any` earlier in the chain causes the `.keys` assertion\n   * to ignore `.include`.\n   *\n   *     // Both assertions are identical\n   *     expect({a: 1}).to.include.any.keys('a', 'b');\n   *     expect({a: 1}).to.have.any.keys('a', 'b');\n   *\n   * The aliases `.includes`, `.contain`, and `.contains` can be used\n   * interchangeably with `.include`.\n   *\n   * @name include\n   * @alias contain\n   * @alias includes\n   * @alias contains\n   * @param {Mixed} val\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function SameValueZero(a, b) {\n    return (_.isNaN(a) && _.isNaN(b)) || a === b;\n  }\n\n  function includeChainingBehavior () {\n    flag(this, 'contains', true);\n  }\n\n  function include (val, msg) {\n    if (msg) flag(this, 'message', msg);\n\n    var obj = flag(this, 'object')\n      , objType = _.type(obj).toLowerCase()\n      , flagMsg = flag(this, 'message')\n      , negate = flag(this, 'negate')\n      , ssfi = flag(this, 'ssfi')\n      , isDeep = flag(this, 'deep')\n      , descriptor = isDeep ? 'deep ' : '';\n\n    flagMsg = flagMsg ? flagMsg + ': ' : '';\n\n    var included = false;\n\n    switch (objType) {\n      case 'string':\n        included = obj.indexOf(val) !== -1;\n        break;\n\n      case 'weakset':\n        if (isDeep) {\n          throw new AssertionError(\n            flagMsg + 'unable to use .deep.include with WeakSet',\n            undefined,\n            ssfi\n          );\n        }\n\n        included = obj.has(val);\n        break;\n\n      case 'map':\n        var isEql = isDeep ? _.eql : SameValueZero;\n        obj.forEach(function (item) {\n          included = included || isEql(item, val);\n        });\n        break;\n\n      case 'set':\n        if (isDeep) {\n          obj.forEach(function (item) {\n            included = included || _.eql(item, val);\n          });\n        } else {\n          included = obj.has(val);\n        }\n        break;\n\n      case 'array':\n        if (isDeep) {\n          included = obj.some(function (item) {\n            return _.eql(item, val);\n          })\n        } else {\n          included = obj.indexOf(val) !== -1;\n        }\n        break;\n\n      default:\n        // This block is for asserting a subset of properties in an object.\n        // `_.expectTypes` isn't used here because `.include` should work with\n        // objects with a custom `@@toStringTag`.\n        if (val !== Object(val)) {\n          throw new AssertionError(\n            flagMsg + 'the given combination of arguments ('\n            + objType + ' and '\n            + _.type(val).toLowerCase() + ')'\n            + ' is invalid for this assertion. '\n            + 'You can use an array, a map, an object, a set, a string, '\n            + 'or a weakset instead of a '\n            + _.type(val).toLowerCase(),\n            undefined,\n            ssfi\n          );\n        }\n\n        var props = Object.keys(val)\n          , firstErr = null\n          , numErrs = 0;\n\n        props.forEach(function (prop) {\n          var propAssertion = new Assertion(obj);\n          _.transferFlags(this, propAssertion, true);\n          flag(propAssertion, 'lockSsfi', true);\n\n          if (!negate || props.length === 1) {\n            propAssertion.property(prop, val[prop]);\n            return;\n          }\n\n          try {\n            propAssertion.property(prop, val[prop]);\n          } catch (err) {\n            if (!_.checkError.compatibleConstructor(err, AssertionError)) {\n              throw err;\n            }\n            if (firstErr === null) firstErr = err;\n            numErrs++;\n          }\n        }, this);\n\n        // When validating .not.include with multiple properties, we only want\n        // to throw an assertion error if all of the properties are included,\n        // in which case we throw the first property assertion error that we\n        // encountered.\n        if (negate && props.length > 1 && numErrs === props.length) {\n          throw firstErr;\n        }\n        return;\n    }\n\n    // Assert inclusion in collection or substring in a string.\n    this.assert(\n      included\n      , 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)\n      , 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));\n  }\n\n  Assertion.addChainableMethod('include', include, includeChainingBehavior);\n  Assertion.addChainableMethod('contain', include, includeChainingBehavior);\n  Assertion.addChainableMethod('contains', include, includeChainingBehavior);\n  Assertion.addChainableMethod('includes', include, includeChainingBehavior);\n\n  /**\n   * ### .ok\n   *\n   * Asserts that the target is a truthy value (considered `true` in boolean context).\n   * However, it's often best to assert that the target is strictly (`===`) or\n   * deeply equal to its expected value.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.be.ok; // Not recommended\n   *\n   *     expect(true).to.be.true; // Recommended\n   *     expect(true).to.be.ok; // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.ok`.\n   *\n   *     expect(0).to.equal(0); // Recommended\n   *     expect(0).to.not.be.ok; // Not recommended\n   *\n   *     expect(false).to.be.false; // Recommended\n   *     expect(false).to.not.be.ok; // Not recommended\n   *\n   *     expect(null).to.be.null; // Recommended\n   *     expect(null).to.not.be.ok; // Not recommended\n   *\n   *     expect(undefined).to.be.undefined; // Recommended\n   *     expect(undefined).to.not.be.ok; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(false, 'nooo why fail??').to.be.ok;\n   *\n   * @name ok\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('ok', function () {\n    this.assert(\n        flag(this, 'object')\n      , 'expected #{this} to be truthy'\n      , 'expected #{this} to be falsy');\n  });\n\n  /**\n   * ### .true\n   *\n   * Asserts that the target is strictly (`===`) equal to `true`.\n   *\n   *     expect(true).to.be.true;\n   *\n   * Add `.not` earlier in the chain to negate `.true`. However, it's often best\n   * to assert that the target is equal to its expected value, rather than not\n   * equal to `true`.\n   *\n   *     expect(false).to.be.false; // Recommended\n   *     expect(false).to.not.be.true; // Not recommended\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.true; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(false, 'nooo why fail??').to.be.true;\n   *\n   * @name true\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('true', function () {\n    this.assert(\n        true === flag(this, 'object')\n      , 'expected #{this} to be true'\n      , 'expected #{this} to be false'\n      , flag(this, 'negate') ? false : true\n    );\n  });\n\n  /**\n   * ### .false\n   *\n   * Asserts that the target is strictly (`===`) equal to `false`.\n   *\n   *     expect(false).to.be.false;\n   *\n   * Add `.not` earlier in the chain to negate `.false`. However, it's often\n   * best to assert that the target is equal to its expected value, rather than\n   * not equal to `false`.\n   *\n   *     expect(true).to.be.true; // Recommended\n   *     expect(true).to.not.be.false; // Not recommended\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.false; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(true, 'nooo why fail??').to.be.false;\n   *\n   * @name false\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('false', function () {\n    this.assert(\n        false === flag(this, 'object')\n      , 'expected #{this} to be false'\n      , 'expected #{this} to be true'\n      , flag(this, 'negate') ? true : false\n    );\n  });\n\n  /**\n   * ### .null\n   *\n   * Asserts that the target is strictly (`===`) equal to `null`.\n   *\n   *     expect(null).to.be.null;\n   *\n   * Add `.not` earlier in the chain to negate `.null`. However, it's often best\n   * to assert that the target is equal to its expected value, rather than not\n   * equal to `null`.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.null; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(42, 'nooo why fail??').to.be.null;\n   *\n   * @name null\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('null', function () {\n    this.assert(\n        null === flag(this, 'object')\n      , 'expected #{this} to be null'\n      , 'expected #{this} not to be null'\n    );\n  });\n\n  /**\n   * ### .undefined\n   *\n   * Asserts that the target is strictly (`===`) equal to `undefined`.\n   *\n   *     expect(undefined).to.be.undefined;\n   *\n   * Add `.not` earlier in the chain to negate `.undefined`. However, it's often\n   * best to assert that the target is equal to its expected value, rather than\n   * not equal to `undefined`.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.undefined; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(42, 'nooo why fail??').to.be.undefined;\n   *\n   * @name undefined\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('undefined', function () {\n    this.assert(\n        undefined === flag(this, 'object')\n      , 'expected #{this} to be undefined'\n      , 'expected #{this} not to be undefined'\n    );\n  });\n\n  /**\n   * ### .NaN\n   *\n   * Asserts that the target is exactly `NaN`.\n   *\n   *     expect(NaN).to.be.NaN;\n   *\n   * Add `.not` earlier in the chain to negate `.NaN`. However, it's often best\n   * to assert that the target is equal to its expected value, rather than not\n   * equal to `NaN`.\n   *\n   *     expect('foo').to.equal('foo'); // Recommended\n   *     expect('foo').to.not.be.NaN; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(42, 'nooo why fail??').to.be.NaN;\n   *\n   * @name NaN\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('NaN', function () {\n    this.assert(\n        _.isNaN(flag(this, 'object'))\n        , 'expected #{this} to be NaN'\n        , 'expected #{this} not to be NaN'\n    );\n  });\n\n  /**\n   * ### .exist\n   *\n   * Asserts that the target is not strictly (`===`) equal to either `null` or\n   * `undefined`. However, it's often best to assert that the target is equal to\n   * its expected value.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.exist; // Not recommended\n   *\n   *     expect(0).to.equal(0); // Recommended\n   *     expect(0).to.exist; // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.exist`.\n   *\n   *     expect(null).to.be.null; // Recommended\n   *     expect(null).to.not.exist; // Not recommended\n   *\n   *     expect(undefined).to.be.undefined; // Recommended\n   *     expect(undefined).to.not.exist; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(null, 'nooo why fail??').to.exist;\n   *\n   * The alias `.exists` can be used interchangeably with `.exist`.\n   *\n   * @name exist\n   * @alias exists\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertExist () {\n    var val = flag(this, 'object');\n    this.assert(\n        val !== null && val !== undefined\n      , 'expected #{this} to exist'\n      , 'expected #{this} to not exist'\n    );\n  }\n\n  Assertion.addProperty('exist', assertExist);\n  Assertion.addProperty('exists', assertExist);\n\n  /**\n   * ### .empty\n   *\n   * When the target is a string or array, `.empty` asserts that the target's\n   * `length` property is strictly (`===`) equal to `0`.\n   *\n   *     expect([]).to.be.empty;\n   *     expect('').to.be.empty;\n   *\n   * When the target is a map or set, `.empty` asserts that the target's `size`\n   * property is strictly equal to `0`.\n   *\n   *     expect(new Set()).to.be.empty;\n   *     expect(new Map()).to.be.empty;\n   *\n   * When the target is a non-function object, `.empty` asserts that the target\n   * doesn't have any own enumerable properties. Properties with Symbol-based\n   * keys are excluded from the count.\n   *\n   *     expect({}).to.be.empty;\n   *\n   * Because `.empty` does different things based on the target's type, it's\n   * important to check the target's type before using `.empty`. See the `.a`\n   * doc for info on testing a target's type.\n   *\n   *     expect([]).to.be.an('array').that.is.empty;\n   *\n   * Add `.not` earlier in the chain to negate `.empty`. However, it's often\n   * best to assert that the target contains its expected number of values,\n   * rather than asserting that it's not empty.\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(3); // Recommended\n   *     expect([1, 2, 3]).to.not.be.empty; // Not recommended\n   *\n   *     expect(new Set([1, 2, 3])).to.have.property('size', 3); // Recommended\n   *     expect(new Set([1, 2, 3])).to.not.be.empty; // Not recommended\n   *\n   *     expect(Object.keys({a: 1})).to.have.lengthOf(1); // Recommended\n   *     expect({a: 1}).to.not.be.empty; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect([1, 2, 3], 'nooo why fail??').to.be.empty;\n   *\n   * @name empty\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('empty', function () {\n    var val = flag(this, 'object')\n      , ssfi = flag(this, 'ssfi')\n      , flagMsg = flag(this, 'message')\n      , itemsCount;\n\n    flagMsg = flagMsg ? flagMsg + ': ' : '';\n\n    switch (_.type(val).toLowerCase()) {\n      case 'array':\n      case 'string':\n        itemsCount = val.length;\n        break;\n      case 'map':\n      case 'set':\n        itemsCount = val.size;\n        break;\n      case 'weakmap':\n      case 'weakset':\n        throw new AssertionError(\n          flagMsg + '.empty was passed a weak collection',\n          undefined,\n          ssfi\n        );\n      case 'function':\n        var msg = flagMsg + '.empty was passed a function ' + _.getName(val);\n        throw new AssertionError(msg.trim(), undefined, ssfi);\n      default:\n        if (val !== Object(val)) {\n          throw new AssertionError(\n            flagMsg + '.empty was passed non-string primitive ' + _.inspect(val),\n            undefined,\n            ssfi\n          );\n        }\n        itemsCount = Object.keys(val).length;\n    }\n\n    this.assert(\n        0 === itemsCount\n      , 'expected #{this} to be empty'\n      , 'expected #{this} not to be empty'\n    );\n  });\n\n  /**\n   * ### .arguments\n   *\n   * Asserts that the target is an `arguments` object.\n   *\n   *     function test () {\n   *       expect(arguments).to.be.arguments;\n   *     }\n   *\n   *     test();\n   *\n   * Add `.not` earlier in the chain to negate `.arguments`. However, it's often\n   * best to assert which type the target is expected to be, rather than\n   * asserting that it’s not an `arguments` object.\n   *\n   *     expect('foo').to.be.a('string'); // Recommended\n   *     expect('foo').to.not.be.arguments; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect({}, 'nooo why fail??').to.be.arguments;\n   *\n   * The alias `.Arguments` can be used interchangeably with `.arguments`.\n   *\n   * @name arguments\n   * @alias Arguments\n   * @namespace BDD\n   * @api public\n   */\n\n  function checkArguments () {\n    var obj = flag(this, 'object')\n      , type = _.type(obj);\n    this.assert(\n        'Arguments' === type\n      , 'expected #{this} to be arguments but got ' + type\n      , 'expected #{this} to not be arguments'\n    );\n  }\n\n  Assertion.addProperty('arguments', checkArguments);\n  Assertion.addProperty('Arguments', checkArguments);\n\n  /**\n   * ### .equal(val[, msg])\n   *\n   * Asserts that the target is strictly (`===`) equal to the given `val`.\n   *\n   *     expect(1).to.equal(1);\n   *     expect('foo').to.equal('foo');\n   *\n   * Add `.deep` earlier in the chain to use deep equality instead. See the\n   * `deep-eql` project page for info on the deep equality algorithm:\n   * https://github.com/chaijs/deep-eql.\n   *\n   *     // Target object deeply (but not strictly) equals `{a: 1}`\n   *     expect({a: 1}).to.deep.equal({a: 1});\n   *     expect({a: 1}).to.not.equal({a: 1});\n   *\n   *     // Target array deeply (but not strictly) equals `[1, 2]`\n   *     expect([1, 2]).to.deep.equal([1, 2]);\n   *     expect([1, 2]).to.not.equal([1, 2]);\n   *\n   * Add `.not` earlier in the chain to negate `.equal`. However, it's often\n   * best to assert that the target is equal to its expected value, rather than\n   * not equal to one of countless unexpected values.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.equal(2); // Not recommended\n   *\n   * `.equal` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect(1).to.equal(2, 'nooo why fail??');\n   *     expect(1, 'nooo why fail??').to.equal(2);\n   *\n   * The aliases `.equals` and `eq` can be used interchangeably with `.equal`.\n   *\n   * @name equal\n   * @alias equals\n   * @alias eq\n   * @param {Mixed} val\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertEqual (val, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    if (flag(this, 'deep')) {\n      var prevLockSsfi = flag(this, 'lockSsfi');\n      flag(this, 'lockSsfi', true);\n      this.eql(val);\n      flag(this, 'lockSsfi', prevLockSsfi);\n    } else {\n      this.assert(\n          val === obj\n        , 'expected #{this} to equal #{exp}'\n        , 'expected #{this} to not equal #{exp}'\n        , val\n        , this._obj\n        , true\n      );\n    }\n  }\n\n  Assertion.addMethod('equal', assertEqual);\n  Assertion.addMethod('equals', assertEqual);\n  Assertion.addMethod('eq', assertEqual);\n\n  /**\n   * ### .eql(obj[, msg])\n   *\n   * Asserts that the target is deeply equal to the given `obj`. See the\n   * `deep-eql` project page for info on the deep equality algorithm:\n   * https://github.com/chaijs/deep-eql.\n   *\n   *     // Target object is deeply (but not strictly) equal to {a: 1}\n   *     expect({a: 1}).to.eql({a: 1}).but.not.equal({a: 1});\n   *\n   *     // Target array is deeply (but not strictly) equal to [1, 2]\n   *     expect([1, 2]).to.eql([1, 2]).but.not.equal([1, 2]);\n   *\n   * Add `.not` earlier in the chain to negate `.eql`. However, it's often best\n   * to assert that the target is deeply equal to its expected value, rather\n   * than not deeply equal to one of countless unexpected values.\n   *\n   *     expect({a: 1}).to.eql({a: 1}); // Recommended\n   *     expect({a: 1}).to.not.eql({b: 2}); // Not recommended\n   *\n   * `.eql` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect({a: 1}).to.eql({b: 2}, 'nooo why fail??');\n   *     expect({a: 1}, 'nooo why fail??').to.eql({b: 2});\n   *\n   * The alias `.eqls` can be used interchangeably with `.eql`.\n   *\n   * The `.deep.equal` assertion is almost identical to `.eql` but with one\n   * difference: `.deep.equal` causes deep equality comparisons to also be used\n   * for any other assertions that follow in the chain.\n   *\n   * @name eql\n   * @alias eqls\n   * @param {Mixed} obj\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertEql(obj, msg) {\n    if (msg) flag(this, 'message', msg);\n    this.assert(\n        _.eql(obj, flag(this, 'object'))\n      , 'expected #{this} to deeply equal #{exp}'\n      , 'expected #{this} to not deeply equal #{exp}'\n      , obj\n      , this._obj\n      , true\n    );\n  }\n\n  Assertion.addMethod('eql', assertEql);\n  Assertion.addMethod('eqls', assertEql);\n\n  /**\n   * ### .above(n[, msg])\n   *\n   * Asserts that the target is a number or a date greater than the given number or date `n` respectively.\n   * However, it's often best to assert that the target is equal to its expected\n   * value.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(2).to.be.above(1); // Not recommended\n   *\n   * Add `.lengthOf` earlier in the chain to assert that the target's `length`\n   * or `size` is greater than the given number `n`.\n   *\n   *     expect('foo').to.have.lengthOf(3); // Recommended\n   *     expect('foo').to.have.lengthOf.above(2); // Not recommended\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(3); // Recommended\n   *     expect([1, 2, 3]).to.have.lengthOf.above(2); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.above`.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(1).to.not.be.above(2); // Not recommended\n   *\n   * `.above` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect(1).to.be.above(2, 'nooo why fail??');\n   *     expect(1, 'nooo why fail??').to.be.above(2);\n   *\n   * The aliases `.gt` and `.greaterThan` can be used interchangeably with\n   * `.above`.\n   *\n   * @name above\n   * @alias gt\n   * @alias greaterThan\n   * @param {Number} n\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertAbove (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , doLength = flag(this, 'doLength')\n      , flagMsg = flag(this, 'message')\n      , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')\n      , ssfi = flag(this, 'ssfi')\n      , objType = _.type(obj).toLowerCase()\n      , nType = _.type(n).toLowerCase()\n      , errorMessage\n      , shouldThrow = true;\n\n    if (doLength && objType !== 'map' && objType !== 'set') {\n      new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');\n    }\n\n    if (!doLength && (objType === 'date' && nType !== 'date')) {\n      errorMessage = msgPrefix + 'the argument to above must be a date';\n    } else if (nType !== 'number' && (doLength || objType === 'number')) {\n      errorMessage = msgPrefix + 'the argument to above must be a number';\n    } else if (!doLength && (objType !== 'date' && objType !== 'number')) {\n      var printObj = (objType === 'string') ? \"'\" + obj + \"'\" : obj;\n      errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';\n    } else {\n      shouldThrow = false;\n    }\n\n    if (shouldThrow) {\n      throw new AssertionError(errorMessage, undefined, ssfi);\n    }\n\n    if (doLength) {\n      var descriptor = 'length'\n        , itemsCount;\n      if (objType === 'map' || objType === 'set') {\n        descriptor = 'size';\n        itemsCount = obj.size;\n      } else {\n        itemsCount = obj.length;\n      }\n      this.assert(\n          itemsCount > n\n        , 'expected #{this} to have a ' + descriptor + ' above #{exp} but got #{act}'\n        , 'expected #{this} to not have a ' + descriptor + ' above #{exp}'\n        , n\n        , itemsCount\n      );\n    } else {\n      this.assert(\n          obj > n\n        , 'expected #{this} to be above #{exp}'\n        , 'expected #{this} to be at most #{exp}'\n        , n\n      );\n    }\n  }\n\n  Assertion.addMethod('above', assertAbove);\n  Assertion.addMethod('gt', assertAbove);\n  Assertion.addMethod('greaterThan', assertAbove);\n\n  /**\n   * ### .least(n[, msg])\n   *\n   * Asserts that the target is a number or a date greater than or equal to the given\n   * number or date `n` respectively. However, it's often best to assert that the target is equal to\n   * its expected value.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(2).to.be.at.least(1); // Not recommended\n   *     expect(2).to.be.at.least(2); // Not recommended\n   *\n   * Add `.lengthOf` earlier in the chain to assert that the target's `length`\n   * or `size` is greater than or equal to the given number `n`.\n   *\n   *     expect('foo').to.have.lengthOf(3); // Recommended\n   *     expect('foo').to.have.lengthOf.at.least(2); // Not recommended\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(3); // Recommended\n   *     expect([1, 2, 3]).to.have.lengthOf.at.least(2); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.least`.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.at.least(2); // Not recommended\n   *\n   * `.least` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect(1).to.be.at.least(2, 'nooo why fail??');\n   *     expect(1, 'nooo why fail??').to.be.at.least(2);\n   *\n   * The aliases `.gte` and `.greaterThanOrEqual` can be used interchangeably with\n   * `.least`.\n   *\n   * @name least\n   * @alias gte\n   * @alias greaterThanOrEqual\n   * @param {Number} n\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertLeast (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , doLength = flag(this, 'doLength')\n      , flagMsg = flag(this, 'message')\n      , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')\n      , ssfi = flag(this, 'ssfi')\n      , objType = _.type(obj).toLowerCase()\n      , nType = _.type(n).toLowerCase()\n      , errorMessage\n      , shouldThrow = true;\n\n    if (doLength && objType !== 'map' && objType !== 'set') {\n      new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');\n    }\n\n    if (!doLength && (objType === 'date' && nType !== 'date')) {\n      errorMessage = msgPrefix + 'the argument to least must be a date';\n    } else if (nType !== 'number' && (doLength || objType === 'number')) {\n      errorMessage = msgPrefix + 'the argument to least must be a number';\n    } else if (!doLength && (objType !== 'date' && objType !== 'number')) {\n      var printObj = (objType === 'string') ? \"'\" + obj + \"'\" : obj;\n      errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';\n    } else {\n      shouldThrow = false;\n    }\n\n    if (shouldThrow) {\n      throw new AssertionError(errorMessage, undefined, ssfi);\n    }\n\n    if (doLength) {\n      var descriptor = 'length'\n        , itemsCount;\n      if (objType === 'map' || objType === 'set') {\n        descriptor = 'size';\n        itemsCount = obj.size;\n      } else {\n        itemsCount = obj.length;\n      }\n      this.assert(\n          itemsCount >= n\n        , 'expected #{this} to have a ' + descriptor + ' at least #{exp} but got #{act}'\n        , 'expected #{this} to have a ' + descriptor + ' below #{exp}'\n        , n\n        , itemsCount\n      );\n    } else {\n      this.assert(\n          obj >= n\n        , 'expected #{this} to be at least #{exp}'\n        , 'expected #{this} to be below #{exp}'\n        , n\n      );\n    }\n  }\n\n  Assertion.addMethod('least', assertLeast);\n  Assertion.addMethod('gte', assertLeast);\n  Assertion.addMethod('greaterThanOrEqual', assertLeast);\n\n  /**\n   * ### .below(n[, msg])\n   *\n   * Asserts that the target is a number or a date less than the given number or date `n` respectively.\n   * However, it's often best to assert that the target is equal to its expected\n   * value.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.be.below(2); // Not recommended\n   *\n   * Add `.lengthOf` earlier in the chain to assert that the target's `length`\n   * or `size` is less than the given number `n`.\n   *\n   *     expect('foo').to.have.lengthOf(3); // Recommended\n   *     expect('foo').to.have.lengthOf.below(4); // Not recommended\n   *\n   *     expect([1, 2, 3]).to.have.length(3); // Recommended\n   *     expect([1, 2, 3]).to.have.lengthOf.below(4); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.below`.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(2).to.not.be.below(1); // Not recommended\n   *\n   * `.below` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect(2).to.be.below(1, 'nooo why fail??');\n   *     expect(2, 'nooo why fail??').to.be.below(1);\n   *\n   * The aliases `.lt` and `.lessThan` can be used interchangeably with\n   * `.below`.\n   *\n   * @name below\n   * @alias lt\n   * @alias lessThan\n   * @param {Number} n\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertBelow (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , doLength = flag(this, 'doLength')\n      , flagMsg = flag(this, 'message')\n      , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')\n      , ssfi = flag(this, 'ssfi')\n      , objType = _.type(obj).toLowerCase()\n      , nType = _.type(n).toLowerCase()\n      , errorMessage\n      , shouldThrow = true;\n\n    if (doLength && objType !== 'map' && objType !== 'set') {\n      new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');\n    }\n\n    if (!doLength && (objType === 'date' && nType !== 'date')) {\n      errorMessage = msgPrefix + 'the argument to below must be a date';\n    } else if (nType !== 'number' && (doLength || objType === 'number')) {\n      errorMessage = msgPrefix + 'the argument to below must be a number';\n    } else if (!doLength && (objType !== 'date' && objType !== 'number')) {\n      var printObj = (objType === 'string') ? \"'\" + obj + \"'\" : obj;\n      errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';\n    } else {\n      shouldThrow = false;\n    }\n\n    if (shouldThrow) {\n      throw new AssertionError(errorMessage, undefined, ssfi);\n    }\n\n    if (doLength) {\n      var descriptor = 'length'\n        , itemsCount;\n      if (objType === 'map' || objType === 'set') {\n        descriptor = 'size';\n        itemsCount = obj.size;\n      } else {\n        itemsCount = obj.length;\n      }\n      this.assert(\n          itemsCount < n\n        , 'expected #{this} to have a ' + descriptor + ' below #{exp} but got #{act}'\n        , 'expected #{this} to not have a ' + descriptor + ' below #{exp}'\n        , n\n        , itemsCount\n      );\n    } else {\n      this.assert(\n          obj < n\n        , 'expected #{this} to be below #{exp}'\n        , 'expected #{this} to be at least #{exp}'\n        , n\n      );\n    }\n  }\n\n  Assertion.addMethod('below', assertBelow);\n  Assertion.addMethod('lt', assertBelow);\n  Assertion.addMethod('lessThan', assertBelow);\n\n  /**\n   * ### .most(n[, msg])\n   *\n   * Asserts that the target is a number or a date less than or equal to the given number\n   * or date `n` respectively. However, it's often best to assert that the target is equal to its\n   * expected value.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.be.at.most(2); // Not recommended\n   *     expect(1).to.be.at.most(1); // Not recommended\n   *\n   * Add `.lengthOf` earlier in the chain to assert that the target's `length`\n   * or `size` is less than or equal to the given number `n`.\n   *\n   *     expect('foo').to.have.lengthOf(3); // Recommended\n   *     expect('foo').to.have.lengthOf.at.most(4); // Not recommended\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(3); // Recommended\n   *     expect([1, 2, 3]).to.have.lengthOf.at.most(4); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.most`.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(2).to.not.be.at.most(1); // Not recommended\n   *\n   * `.most` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect(2).to.be.at.most(1, 'nooo why fail??');\n   *     expect(2, 'nooo why fail??').to.be.at.most(1);\n   *\n   * The aliases `.lte` and `.lessThanOrEqual` can be used interchangeably with\n   * `.most`.\n   *\n   * @name most\n   * @alias lte\n   * @alias lessThanOrEqual\n   * @param {Number} n\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertMost (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , doLength = flag(this, 'doLength')\n      , flagMsg = flag(this, 'message')\n      , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')\n      , ssfi = flag(this, 'ssfi')\n      , objType = _.type(obj).toLowerCase()\n      , nType = _.type(n).toLowerCase()\n      , errorMessage\n      , shouldThrow = true;\n\n    if (doLength && objType !== 'map' && objType !== 'set') {\n      new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');\n    }\n\n    if (!doLength && (objType === 'date' && nType !== 'date')) {\n      errorMessage = msgPrefix + 'the argument to most must be a date';\n    } else if (nType !== 'number' && (doLength || objType === 'number')) {\n      errorMessage = msgPrefix + 'the argument to most must be a number';\n    } else if (!doLength && (objType !== 'date' && objType !== 'number')) {\n      var printObj = (objType === 'string') ? \"'\" + obj + \"'\" : obj;\n      errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';\n    } else {\n      shouldThrow = false;\n    }\n\n    if (shouldThrow) {\n      throw new AssertionError(errorMessage, undefined, ssfi);\n    }\n\n    if (doLength) {\n      var descriptor = 'length'\n        , itemsCount;\n      if (objType === 'map' || objType === 'set') {\n        descriptor = 'size';\n        itemsCount = obj.size;\n      } else {\n        itemsCount = obj.length;\n      }\n      this.assert(\n          itemsCount <= n\n        , 'expected #{this} to have a ' + descriptor + ' at most #{exp} but got #{act}'\n        , 'expected #{this} to have a ' + descriptor + ' above #{exp}'\n        , n\n        , itemsCount\n      );\n    } else {\n      this.assert(\n          obj <= n\n        , 'expected #{this} to be at most #{exp}'\n        , 'expected #{this} to be above #{exp}'\n        , n\n      );\n    }\n  }\n\n  Assertion.addMethod('most', assertMost);\n  Assertion.addMethod('lte', assertMost);\n  Assertion.addMethod('lessThanOrEqual', assertMost);\n\n  /**\n   * ### .within(start, finish[, msg])\n   *\n   * Asserts that the target is a number or a date greater than or equal to the given\n   * number or date `start`, and less than or equal to the given number or date `finish` respectively.\n   * However, it's often best to assert that the target is equal to its expected\n   * value.\n   *\n   *     expect(2).to.equal(2); // Recommended\n   *     expect(2).to.be.within(1, 3); // Not recommended\n   *     expect(2).to.be.within(2, 3); // Not recommended\n   *     expect(2).to.be.within(1, 2); // Not recommended\n   *\n   * Add `.lengthOf` earlier in the chain to assert that the target's `length`\n   * or `size` is greater than or equal to the given number `start`, and less\n   * than or equal to the given number `finish`.\n   *\n   *     expect('foo').to.have.lengthOf(3); // Recommended\n   *     expect('foo').to.have.lengthOf.within(2, 4); // Not recommended\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(3); // Recommended\n   *     expect([1, 2, 3]).to.have.lengthOf.within(2, 4); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.within`.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.within(2, 4); // Not recommended\n   *\n   * `.within` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect(4).to.be.within(1, 3, 'nooo why fail??');\n   *     expect(4, 'nooo why fail??').to.be.within(1, 3);\n   *\n   * @name within\n   * @param {Number} start lower bound inclusive\n   * @param {Number} finish upper bound inclusive\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addMethod('within', function (start, finish, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , doLength = flag(this, 'doLength')\n      , flagMsg = flag(this, 'message')\n      , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')\n      , ssfi = flag(this, 'ssfi')\n      , objType = _.type(obj).toLowerCase()\n      , startType = _.type(start).toLowerCase()\n      , finishType = _.type(finish).toLowerCase()\n      , errorMessage\n      , shouldThrow = true\n      , range = (startType === 'date' && finishType === 'date')\n          ? start.toISOString() + '..' + finish.toISOString()\n          : start + '..' + finish;\n\n    if (doLength && objType !== 'map' && objType !== 'set') {\n      new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');\n    }\n\n    if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {\n      errorMessage = msgPrefix + 'the arguments to within must be dates';\n    } else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) {\n      errorMessage = msgPrefix + 'the arguments to within must be numbers';\n    } else if (!doLength && (objType !== 'date' && objType !== 'number')) {\n      var printObj = (objType === 'string') ? \"'\" + obj + \"'\" : obj;\n      errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';\n    } else {\n      shouldThrow = false;\n    }\n\n    if (shouldThrow) {\n      throw new AssertionError(errorMessage, undefined, ssfi);\n    }\n\n    if (doLength) {\n      var descriptor = 'length'\n        , itemsCount;\n      if (objType === 'map' || objType === 'set') {\n        descriptor = 'size';\n        itemsCount = obj.size;\n      } else {\n        itemsCount = obj.length;\n      }\n      this.assert(\n          itemsCount >= start && itemsCount <= finish\n        , 'expected #{this} to have a ' + descriptor + ' within ' + range\n        , 'expected #{this} to not have a ' + descriptor + ' within ' + range\n      );\n    } else {\n      this.assert(\n          obj >= start && obj <= finish\n        , 'expected #{this} to be within ' + range\n        , 'expected #{this} to not be within ' + range\n      );\n    }\n  });\n\n  /**\n   * ### .instanceof(constructor[, msg])\n   *\n   * Asserts that the target is an instance of the given `constructor`.\n   *\n   *     function Cat () { }\n   *\n   *     expect(new Cat()).to.be.an.instanceof(Cat);\n   *     expect([1, 2]).to.be.an.instanceof(Array);\n   *\n   * Add `.not` earlier in the chain to negate `.instanceof`.\n   *\n   *     expect({a: 1}).to.not.be.an.instanceof(Array);\n   *\n   * `.instanceof` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect(1).to.be.an.instanceof(Array, 'nooo why fail??');\n   *     expect(1, 'nooo why fail??').to.be.an.instanceof(Array);\n   *\n   * Due to limitations in ES5, `.instanceof` may not always work as expected\n   * when using a transpiler such as Babel or TypeScript. In particular, it may\n   * produce unexpected results when subclassing built-in object such as\n   * `Array`, `Error`, and `Map`. See your transpiler's docs for details:\n   *\n   * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes))\n   * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n   *\n   * The alias `.instanceOf` can be used interchangeably with `.instanceof`.\n   *\n   * @name instanceof\n   * @param {Constructor} constructor\n   * @param {String} msg _optional_\n   * @alias instanceOf\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertInstanceOf (constructor, msg) {\n    if (msg) flag(this, 'message', msg);\n\n    var target = flag(this, 'object')\n    var ssfi = flag(this, 'ssfi');\n    var flagMsg = flag(this, 'message');\n\n    try {\n      var isInstanceOf = target instanceof constructor;\n    } catch (err) {\n      if (err instanceof TypeError) {\n        flagMsg = flagMsg ? flagMsg + ': ' : '';\n        throw new AssertionError(\n          flagMsg + 'The instanceof assertion needs a constructor but '\n            + _.type(constructor) + ' was given.',\n          undefined,\n          ssfi\n        );\n      }\n      throw err;\n    }\n\n    var name = _.getName(constructor);\n    if (name === null) {\n      name = 'an unnamed constructor';\n    }\n\n    this.assert(\n        isInstanceOf\n      , 'expected #{this} to be an instance of ' + name\n      , 'expected #{this} to not be an instance of ' + name\n    );\n  };\n\n  Assertion.addMethod('instanceof', assertInstanceOf);\n  Assertion.addMethod('instanceOf', assertInstanceOf);\n\n  /**\n   * ### .property(name[, val[, msg]])\n   *\n   * Asserts that the target has a property with the given key `name`.\n   *\n   *     expect({a: 1}).to.have.property('a');\n   *\n   * When `val` is provided, `.property` also asserts that the property's value\n   * is equal to the given `val`.\n   *\n   *     expect({a: 1}).to.have.property('a', 1);\n   *\n   * By default, strict (`===`) equality is used. Add `.deep` earlier in the\n   * chain to use deep equality instead. See the `deep-eql` project page for\n   * info on the deep equality algorithm: https://github.com/chaijs/deep-eql.\n   *\n   *     // Target object deeply (but not strictly) has property `x: {a: 1}`\n   *     expect({x: {a: 1}}).to.have.deep.property('x', {a: 1});\n   *     expect({x: {a: 1}}).to.not.have.property('x', {a: 1});\n   *\n   * The target's enumerable and non-enumerable properties are always included\n   * in the search. By default, both own and inherited properties are included.\n   * Add `.own` earlier in the chain to exclude inherited properties from the\n   * search.\n   *\n   *     Object.prototype.b = 2;\n   *\n   *     expect({a: 1}).to.have.own.property('a');\n   *     expect({a: 1}).to.have.own.property('a', 1);\n   *     expect({a: 1}).to.have.property('b');\n   *     expect({a: 1}).to.not.have.own.property('b');\n   *\n   * `.deep` and `.own` can be combined.\n   *\n   *     expect({x: {a: 1}}).to.have.deep.own.property('x', {a: 1});\n   *\n   * Add `.nested` earlier in the chain to enable dot- and bracket-notation when\n   * referencing nested properties.\n   *\n   *     expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]');\n   *     expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]', 'y');\n   *\n   * If `.` or `[]` are part of an actual property name, they can be escaped by\n   * adding two backslashes before them.\n   *\n   *     expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\\\.a.\\\\[b\\\\]');\n   *\n   * `.deep` and `.nested` can be combined.\n   *\n   *     expect({a: {b: [{c: 3}]}})\n   *       .to.have.deep.nested.property('a.b[0]', {c: 3});\n   *\n   * `.own` and `.nested` cannot be combined.\n   *\n   * Add `.not` earlier in the chain to negate `.property`.\n   *\n   *     expect({a: 1}).to.not.have.property('b');\n   *\n   * However, it's dangerous to negate `.property` when providing `val`. The\n   * problem is that it creates uncertain expectations by asserting that the\n   * target either doesn't have a property with the given key `name`, or that it\n   * does have a property with the given key `name` but its value isn't equal to\n   * the given `val`. It's often best to identify the exact output that's\n   * expected, and then write an assertion that only accepts that exact output.\n   *\n   * When the target isn't expected to have a property with the given key\n   * `name`, it's often best to assert exactly that.\n   *\n   *     expect({b: 2}).to.not.have.property('a'); // Recommended\n   *     expect({b: 2}).to.not.have.property('a', 1); // Not recommended\n   *\n   * When the target is expected to have a property with the given key `name`,\n   * it's often best to assert that the property has its expected value, rather\n   * than asserting that it doesn't have one of many unexpected values.\n   *\n   *     expect({a: 3}).to.have.property('a', 3); // Recommended\n   *     expect({a: 3}).to.not.have.property('a', 1); // Not recommended\n   *\n   * `.property` changes the target of any assertions that follow in the chain\n   * to be the value of the property from the original target object.\n   *\n   *     expect({a: 1}).to.have.property('a').that.is.a('number');\n   *\n   * `.property` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`. When not providing `val`, only use the\n   * second form.\n   *\n   *     // Recommended\n   *     expect({a: 1}).to.have.property('a', 2, 'nooo why fail??');\n   *     expect({a: 1}, 'nooo why fail??').to.have.property('a', 2);\n   *     expect({a: 1}, 'nooo why fail??').to.have.property('b');\n   *\n   *     // Not recommended\n   *     expect({a: 1}).to.have.property('b', undefined, 'nooo why fail??');\n   *\n   * The above assertion isn't the same thing as not providing `val`. Instead,\n   * it's asserting that the target object has a `b` property that's equal to\n   * `undefined`.\n   *\n   * The assertions `.ownProperty` and `.haveOwnProperty` can be used\n   * interchangeably with `.own.property`.\n   *\n   * @name property\n   * @param {String} name\n   * @param {Mixed} val (optional)\n   * @param {String} msg _optional_\n   * @returns value of property for chaining\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertProperty (name, val, msg) {\n    if (msg) flag(this, 'message', msg);\n\n    var isNested = flag(this, 'nested')\n      , isOwn = flag(this, 'own')\n      , flagMsg = flag(this, 'message')\n      , obj = flag(this, 'object')\n      , ssfi = flag(this, 'ssfi')\n      , nameType = typeof name;\n\n    flagMsg = flagMsg ? flagMsg + ': ' : '';\n\n    if (isNested) {\n      if (nameType !== 'string') {\n        throw new AssertionError(\n          flagMsg + 'the argument to property must be a string when using nested syntax',\n          undefined,\n          ssfi\n        );\n      }\n    } else {\n      if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') {\n        throw new AssertionError(\n          flagMsg + 'the argument to property must be a string, number, or symbol',\n          undefined,\n          ssfi\n        );\n      }\n    }\n\n    if (isNested && isOwn) {\n      throw new AssertionError(\n        flagMsg + 'The \"nested\" and \"own\" flags cannot be combined.',\n        undefined,\n        ssfi\n      );\n    }\n\n    if (obj === null || obj === undefined) {\n      throw new AssertionError(\n        flagMsg + 'Target cannot be null or undefined.',\n        undefined,\n        ssfi\n      );\n    }\n\n    var isDeep = flag(this, 'deep')\n      , negate = flag(this, 'negate')\n      , pathInfo = isNested ? _.getPathInfo(obj, name) : null\n      , value = isNested ? pathInfo.value : obj[name];\n\n    var descriptor = '';\n    if (isDeep) descriptor += 'deep ';\n    if (isOwn) descriptor += 'own ';\n    if (isNested) descriptor += 'nested ';\n    descriptor += 'property ';\n\n    var hasProperty;\n    if (isOwn) hasProperty = Object.prototype.hasOwnProperty.call(obj, name);\n    else if (isNested) hasProperty = pathInfo.exists;\n    else hasProperty = _.hasProperty(obj, name);\n\n    // When performing a negated assertion for both name and val, merely having\n    // a property with the given name isn't enough to cause the assertion to\n    // fail. It must both have a property with the given name, and the value of\n    // that property must equal the given val. Therefore, skip this assertion in\n    // favor of the next.\n    if (!negate || arguments.length === 1) {\n      this.assert(\n          hasProperty\n        , 'expected #{this} to have ' + descriptor + _.inspect(name)\n        , 'expected #{this} to not have ' + descriptor + _.inspect(name));\n    }\n\n    if (arguments.length > 1) {\n      this.assert(\n          hasProperty && (isDeep ? _.eql(val, value) : val === value)\n        , 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'\n        , 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}'\n        , val\n        , value\n      );\n    }\n\n    flag(this, 'object', value);\n  }\n\n  Assertion.addMethod('property', assertProperty);\n\n  function assertOwnProperty (name, value, msg) {\n    flag(this, 'own', true);\n    assertProperty.apply(this, arguments);\n  }\n\n  Assertion.addMethod('ownProperty', assertOwnProperty);\n  Assertion.addMethod('haveOwnProperty', assertOwnProperty);\n\n  /**\n   * ### .ownPropertyDescriptor(name[, descriptor[, msg]])\n   *\n   * Asserts that the target has its own property descriptor with the given key\n   * `name`. Enumerable and non-enumerable properties are included in the\n   * search.\n   *\n   *     expect({a: 1}).to.have.ownPropertyDescriptor('a');\n   *\n   * When `descriptor` is provided, `.ownPropertyDescriptor` also asserts that\n   * the property's descriptor is deeply equal to the given `descriptor`. See\n   * the `deep-eql` project page for info on the deep equality algorithm:\n   * https://github.com/chaijs/deep-eql.\n   *\n   *     expect({a: 1}).to.have.ownPropertyDescriptor('a', {\n   *       configurable: true,\n   *       enumerable: true,\n   *       writable: true,\n   *       value: 1,\n   *     });\n   *\n   * Add `.not` earlier in the chain to negate `.ownPropertyDescriptor`.\n   *\n   *     expect({a: 1}).to.not.have.ownPropertyDescriptor('b');\n   *\n   * However, it's dangerous to negate `.ownPropertyDescriptor` when providing\n   * a `descriptor`. The problem is that it creates uncertain expectations by\n   * asserting that the target either doesn't have a property descriptor with\n   * the given key `name`, or that it does have a property descriptor with the\n   * given key `name` but it’s not deeply equal to the given `descriptor`. It's\n   * often best to identify the exact output that's expected, and then write an\n   * assertion that only accepts that exact output.\n   *\n   * When the target isn't expected to have a property descriptor with the given\n   * key `name`, it's often best to assert exactly that.\n   *\n   *     // Recommended\n   *     expect({b: 2}).to.not.have.ownPropertyDescriptor('a');\n   *\n   *     // Not recommended\n   *     expect({b: 2}).to.not.have.ownPropertyDescriptor('a', {\n   *       configurable: true,\n   *       enumerable: true,\n   *       writable: true,\n   *       value: 1,\n   *     });\n   *\n   * When the target is expected to have a property descriptor with the given\n   * key `name`, it's often best to assert that the property has its expected\n   * descriptor, rather than asserting that it doesn't have one of many\n   * unexpected descriptors.\n   *\n   *     // Recommended\n   *     expect({a: 3}).to.have.ownPropertyDescriptor('a', {\n   *       configurable: true,\n   *       enumerable: true,\n   *       writable: true,\n   *       value: 3,\n   *     });\n   *\n   *     // Not recommended\n   *     expect({a: 3}).to.not.have.ownPropertyDescriptor('a', {\n   *       configurable: true,\n   *       enumerable: true,\n   *       writable: true,\n   *       value: 1,\n   *     });\n   *\n   * `.ownPropertyDescriptor` changes the target of any assertions that follow\n   * in the chain to be the value of the property descriptor from the original\n   * target object.\n   *\n   *     expect({a: 1}).to.have.ownPropertyDescriptor('a')\n   *       .that.has.property('enumerable', true);\n   *\n   * `.ownPropertyDescriptor` accepts an optional `msg` argument which is a\n   * custom error message to show when the assertion fails. The message can also\n   * be given as the second argument to `expect`. When not providing\n   * `descriptor`, only use the second form.\n   *\n   *     // Recommended\n   *     expect({a: 1}).to.have.ownPropertyDescriptor('a', {\n   *       configurable: true,\n   *       enumerable: true,\n   *       writable: true,\n   *       value: 2,\n   *     }, 'nooo why fail??');\n   *\n   *     // Recommended\n   *     expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('a', {\n   *       configurable: true,\n   *       enumerable: true,\n   *       writable: true,\n   *       value: 2,\n   *     });\n   *\n   *     // Recommended\n   *     expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('b');\n   *\n   *     // Not recommended\n   *     expect({a: 1})\n   *       .to.have.ownPropertyDescriptor('b', undefined, 'nooo why fail??');\n   *\n   * The above assertion isn't the same thing as not providing `descriptor`.\n   * Instead, it's asserting that the target object has a `b` property\n   * descriptor that's deeply equal to `undefined`.\n   *\n   * The alias `.haveOwnPropertyDescriptor` can be used interchangeably with\n   * `.ownPropertyDescriptor`.\n   *\n   * @name ownPropertyDescriptor\n   * @alias haveOwnPropertyDescriptor\n   * @param {String} name\n   * @param {Object} descriptor _optional_\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertOwnPropertyDescriptor (name, descriptor, msg) {\n    if (typeof descriptor === 'string') {\n      msg = descriptor;\n      descriptor = null;\n    }\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);\n    if (actualDescriptor && descriptor) {\n      this.assert(\n          _.eql(descriptor, actualDescriptor)\n        , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)\n        , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)\n        , descriptor\n        , actualDescriptor\n        , true\n      );\n    } else {\n      this.assert(\n          actualDescriptor\n        , 'expected #{this} to have an own property descriptor for ' + _.inspect(name)\n        , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name)\n      );\n    }\n    flag(this, 'object', actualDescriptor);\n  }\n\n  Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor);\n  Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor);\n\n  /**\n   * ### .lengthOf(n[, msg])\n   *\n   * Asserts that the target's `length` or `size` is equal to the given number\n   * `n`.\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(3);\n   *     expect('foo').to.have.lengthOf(3);\n   *     expect(new Set([1, 2, 3])).to.have.lengthOf(3);\n   *     expect(new Map([['a', 1], ['b', 2], ['c', 3]])).to.have.lengthOf(3);\n   *\n   * Add `.not` earlier in the chain to negate `.lengthOf`. However, it's often\n   * best to assert that the target's `length` property is equal to its expected\n   * value, rather than not equal to one of many unexpected values.\n   *\n   *     expect('foo').to.have.lengthOf(3); // Recommended\n   *     expect('foo').to.not.have.lengthOf(4); // Not recommended\n   *\n   * `.lengthOf` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect([1, 2, 3]).to.have.lengthOf(2, 'nooo why fail??');\n   *     expect([1, 2, 3], 'nooo why fail??').to.have.lengthOf(2);\n   *\n   * `.lengthOf` can also be used as a language chain, causing all `.above`,\n   * `.below`, `.least`, `.most`, and `.within` assertions that follow in the\n   * chain to use the target's `length` property as the target. However, it's\n   * often best to assert that the target's `length` property is equal to its\n   * expected length, rather than asserting that its `length` property falls\n   * within some range of values.\n   *\n   *     // Recommended\n   *     expect([1, 2, 3]).to.have.lengthOf(3);\n   *\n   *     // Not recommended\n   *     expect([1, 2, 3]).to.have.lengthOf.above(2);\n   *     expect([1, 2, 3]).to.have.lengthOf.below(4);\n   *     expect([1, 2, 3]).to.have.lengthOf.at.least(3);\n   *     expect([1, 2, 3]).to.have.lengthOf.at.most(3);\n   *     expect([1, 2, 3]).to.have.lengthOf.within(2,4);\n   *\n   * Due to a compatibility issue, the alias `.length` can't be chained directly\n   * off of an uninvoked method such as `.a`. Therefore, `.length` can't be used\n   * interchangeably with `.lengthOf` in every situation. It's recommended to\n   * always use `.lengthOf` instead of `.length`.\n   *\n   *     expect([1, 2, 3]).to.have.a.length(3); // incompatible; throws error\n   *     expect([1, 2, 3]).to.have.a.lengthOf(3);  // passes as expected\n   *\n   * @name lengthOf\n   * @alias length\n   * @param {Number} n\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertLengthChain () {\n    flag(this, 'doLength', true);\n  }\n\n  function assertLength (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , objType = _.type(obj).toLowerCase()\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi')\n      , descriptor = 'length'\n      , itemsCount;\n\n    switch (objType) {\n      case 'map':\n      case 'set':\n        descriptor = 'size';\n        itemsCount = obj.size;\n        break;\n      default:\n        new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');\n        itemsCount = obj.length;\n    }\n\n    this.assert(\n        itemsCount == n\n      , 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}'\n      , 'expected #{this} to not have a ' + descriptor + ' of #{act}'\n      , n\n      , itemsCount\n    );\n  }\n\n  Assertion.addChainableMethod('length', assertLength, assertLengthChain);\n  Assertion.addChainableMethod('lengthOf', assertLength, assertLengthChain);\n\n  /**\n   * ### .match(re[, msg])\n   *\n   * Asserts that the target matches the given regular expression `re`.\n   *\n   *     expect('foobar').to.match(/^foo/);\n   *\n   * Add `.not` earlier in the chain to negate `.match`.\n   *\n   *     expect('foobar').to.not.match(/taco/);\n   *\n   * `.match` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect('foobar').to.match(/taco/, 'nooo why fail??');\n   *     expect('foobar', 'nooo why fail??').to.match(/taco/);\n   *\n   * The alias `.matches` can be used interchangeably with `.match`.\n   *\n   * @name match\n   * @alias matches\n   * @param {RegExp} re\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n  function assertMatch(re, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    this.assert(\n        re.exec(obj)\n      , 'expected #{this} to match ' + re\n      , 'expected #{this} not to match ' + re\n    );\n  }\n\n  Assertion.addMethod('match', assertMatch);\n  Assertion.addMethod('matches', assertMatch);\n\n  /**\n   * ### .string(str[, msg])\n   *\n   * Asserts that the target string contains the given substring `str`.\n   *\n   *     expect('foobar').to.have.string('bar');\n   *\n   * Add `.not` earlier in the chain to negate `.string`.\n   *\n   *     expect('foobar').to.not.have.string('taco');\n   *\n   * `.string` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect('foobar').to.have.string('taco', 'nooo why fail??');\n   *     expect('foobar', 'nooo why fail??').to.have.string('taco');\n   *\n   * @name string\n   * @param {String} str\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addMethod('string', function (str, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi');\n    new Assertion(obj, flagMsg, ssfi, true).is.a('string');\n\n    this.assert(\n        ~obj.indexOf(str)\n      , 'expected #{this} to contain ' + _.inspect(str)\n      , 'expected #{this} to not contain ' + _.inspect(str)\n    );\n  });\n\n  /**\n   * ### .keys(key1[, key2[, ...]])\n   *\n   * Asserts that the target object, array, map, or set has the given keys. Only\n   * the target's own inherited properties are included in the search.\n   *\n   * When the target is an object or array, keys can be provided as one or more\n   * string arguments, a single array argument, or a single object argument. In\n   * the latter case, only the keys in the given object matter; the values are\n   * ignored.\n   *\n   *     expect({a: 1, b: 2}).to.have.all.keys('a', 'b');\n   *     expect(['x', 'y']).to.have.all.keys(0, 1);\n   *\n   *     expect({a: 1, b: 2}).to.have.all.keys(['a', 'b']);\n   *     expect(['x', 'y']).to.have.all.keys([0, 1]);\n   *\n   *     expect({a: 1, b: 2}).to.have.all.keys({a: 4, b: 5}); // ignore 4 and 5\n   *     expect(['x', 'y']).to.have.all.keys({0: 4, 1: 5}); // ignore 4 and 5\n   *\n   * When the target is a map or set, each key must be provided as a separate\n   * argument.\n   *\n   *     expect(new Map([['a', 1], ['b', 2]])).to.have.all.keys('a', 'b');\n   *     expect(new Set(['a', 'b'])).to.have.all.keys('a', 'b');\n   *\n   * Because `.keys` does different things based on the target's type, it's\n   * important to check the target's type before using `.keys`. See the `.a` doc\n   * for info on testing a target's type.\n   *\n   *     expect({a: 1, b: 2}).to.be.an('object').that.has.all.keys('a', 'b');\n   *\n   * By default, strict (`===`) equality is used to compare keys of maps and\n   * sets. Add `.deep` earlier in the chain to use deep equality instead. See\n   * the `deep-eql` project page for info on the deep equality algorithm:\n   * https://github.com/chaijs/deep-eql.\n   *\n   *     // Target set deeply (but not strictly) has key `{a: 1}`\n   *     expect(new Set([{a: 1}])).to.have.all.deep.keys([{a: 1}]);\n   *     expect(new Set([{a: 1}])).to.not.have.all.keys([{a: 1}]);\n   *\n   * By default, the target must have all of the given keys and no more. Add\n   * `.any` earlier in the chain to only require that the target have at least\n   * one of the given keys. Also, add `.not` earlier in the chain to negate\n   * `.keys`. It's often best to add `.any` when negating `.keys`, and to use\n   * `.all` when asserting `.keys` without negation.\n   *\n   * When negating `.keys`, `.any` is preferred because `.not.any.keys` asserts\n   * exactly what's expected of the output, whereas `.not.all.keys` creates\n   * uncertain expectations.\n   *\n   *     // Recommended; asserts that target doesn't have any of the given keys\n   *     expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');\n   *\n   *     // Not recommended; asserts that target doesn't have all of the given\n   *     // keys but may or may not have some of them\n   *     expect({a: 1, b: 2}).to.not.have.all.keys('c', 'd');\n   *\n   * When asserting `.keys` without negation, `.all` is preferred because\n   * `.all.keys` asserts exactly what's expected of the output, whereas\n   * `.any.keys` creates uncertain expectations.\n   *\n   *     // Recommended; asserts that target has all the given keys\n   *     expect({a: 1, b: 2}).to.have.all.keys('a', 'b');\n   *\n   *     // Not recommended; asserts that target has at least one of the given\n   *     // keys but may or may not have more of them\n   *     expect({a: 1, b: 2}).to.have.any.keys('a', 'b');\n   *\n   * Note that `.all` is used by default when neither `.all` nor `.any` appear\n   * earlier in the chain. However, it's often best to add `.all` anyway because\n   * it improves readability.\n   *\n   *     // Both assertions are identical\n   *     expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); // Recommended\n   *     expect({a: 1, b: 2}).to.have.keys('a', 'b'); // Not recommended\n   *\n   * Add `.include` earlier in the chain to require that the target's keys be a\n   * superset of the expected keys, rather than identical sets.\n   *\n   *     // Target object's keys are a superset of ['a', 'b'] but not identical\n   *     expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b');\n   *     expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b');\n   *\n   * However, if `.any` and `.include` are combined, only the `.any` takes\n   * effect. The `.include` is ignored in this case.\n   *\n   *     // Both assertions are identical\n   *     expect({a: 1}).to.have.any.keys('a', 'b');\n   *     expect({a: 1}).to.include.any.keys('a', 'b');\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect({a: 1}, 'nooo why fail??').to.have.key('b');\n   *\n   * The alias `.key` can be used interchangeably with `.keys`.\n   *\n   * @name keys\n   * @alias key\n   * @param {...String|Array|Object} keys\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertKeys (keys) {\n    var obj = flag(this, 'object')\n      , objType = _.type(obj)\n      , keysType = _.type(keys)\n      , ssfi = flag(this, 'ssfi')\n      , isDeep = flag(this, 'deep')\n      , str\n      , deepStr = ''\n      , actual\n      , ok = true\n      , flagMsg = flag(this, 'message');\n\n    flagMsg = flagMsg ? flagMsg + ': ' : '';\n    var mixedArgsMsg = flagMsg + 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments';\n\n    if (objType === 'Map' || objType === 'Set') {\n      deepStr = isDeep ? 'deeply ' : '';\n      actual = [];\n\n      // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach.\n      obj.forEach(function (val, key) { actual.push(key) });\n\n      if (keysType !== 'Array') {\n        keys = Array.prototype.slice.call(arguments);\n      }\n    } else {\n      actual = _.getOwnEnumerableProperties(obj);\n\n      switch (keysType) {\n        case 'Array':\n          if (arguments.length > 1) {\n            throw new AssertionError(mixedArgsMsg, undefined, ssfi);\n          }\n          break;\n        case 'Object':\n          if (arguments.length > 1) {\n            throw new AssertionError(mixedArgsMsg, undefined, ssfi);\n          }\n          keys = Object.keys(keys);\n          break;\n        default:\n          keys = Array.prototype.slice.call(arguments);\n      }\n\n      // Only stringify non-Symbols because Symbols would become \"Symbol()\"\n      keys = keys.map(function (val) {\n        return typeof val === 'symbol' ? val : String(val);\n      });\n    }\n\n    if (!keys.length) {\n      throw new AssertionError(flagMsg + 'keys required', undefined, ssfi);\n    }\n\n    var len = keys.length\n      , any = flag(this, 'any')\n      , all = flag(this, 'all')\n      , expected = keys;\n\n    if (!any && !all) {\n      all = true;\n    }\n\n    // Has any\n    if (any) {\n      ok = expected.some(function(expectedKey) {\n        return actual.some(function(actualKey) {\n          if (isDeep) {\n            return _.eql(expectedKey, actualKey);\n          } else {\n            return expectedKey === actualKey;\n          }\n        });\n      });\n    }\n\n    // Has all\n    if (all) {\n      ok = expected.every(function(expectedKey) {\n        return actual.some(function(actualKey) {\n          if (isDeep) {\n            return _.eql(expectedKey, actualKey);\n          } else {\n            return expectedKey === actualKey;\n          }\n        });\n      });\n\n      if (!flag(this, 'contains')) {\n        ok = ok && keys.length == actual.length;\n      }\n    }\n\n    // Key string\n    if (len > 1) {\n      keys = keys.map(function(key) {\n        return _.inspect(key);\n      });\n      var last = keys.pop();\n      if (all) {\n        str = keys.join(', ') + ', and ' + last;\n      }\n      if (any) {\n        str = keys.join(', ') + ', or ' + last;\n      }\n    } else {\n      str = _.inspect(keys[0]);\n    }\n\n    // Form\n    str = (len > 1 ? 'keys ' : 'key ') + str;\n\n    // Have / include\n    str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;\n\n    // Assertion\n    this.assert(\n        ok\n      , 'expected #{this} to ' + deepStr + str\n      , 'expected #{this} to not ' + deepStr + str\n      , expected.slice(0).sort(_.compareByInspect)\n      , actual.sort(_.compareByInspect)\n      , true\n    );\n  }\n\n  Assertion.addMethod('keys', assertKeys);\n  Assertion.addMethod('key', assertKeys);\n\n  /**\n   * ### .throw([errorLike], [errMsgMatcher], [msg])\n   *\n   * When no arguments are provided, `.throw` invokes the target function and\n   * asserts that an error is thrown.\n   *\n   *     var badFn = function () { throw new TypeError('Illegal salmon!'); };\n   *\n   *     expect(badFn).to.throw();\n   *\n   * When one argument is provided, and it's an error constructor, `.throw`\n   * invokes the target function and asserts that an error is thrown that's an\n   * instance of that error constructor.\n   *\n   *     var badFn = function () { throw new TypeError('Illegal salmon!'); };\n   *\n   *     expect(badFn).to.throw(TypeError);\n   *\n   * When one argument is provided, and it's an error instance, `.throw` invokes\n   * the target function and asserts that an error is thrown that's strictly\n   * (`===`) equal to that error instance.\n   *\n   *     var err = new TypeError('Illegal salmon!');\n   *     var badFn = function () { throw err; };\n   *\n   *     expect(badFn).to.throw(err);\n   *\n   * When one argument is provided, and it's a string, `.throw` invokes the\n   * target function and asserts that an error is thrown with a message that\n   * contains that string.\n   *\n   *     var badFn = function () { throw new TypeError('Illegal salmon!'); };\n   *\n   *     expect(badFn).to.throw('salmon');\n   *\n   * When one argument is provided, and it's a regular expression, `.throw`\n   * invokes the target function and asserts that an error is thrown with a\n   * message that matches that regular expression.\n   *\n   *     var badFn = function () { throw new TypeError('Illegal salmon!'); };\n   *\n   *     expect(badFn).to.throw(/salmon/);\n   *\n   * When two arguments are provided, and the first is an error instance or\n   * constructor, and the second is a string or regular expression, `.throw`\n   * invokes the function and asserts that an error is thrown that fulfills both\n   * conditions as described above.\n   *\n   *     var err = new TypeError('Illegal salmon!');\n   *     var badFn = function () { throw err; };\n   *\n   *     expect(badFn).to.throw(TypeError, 'salmon');\n   *     expect(badFn).to.throw(TypeError, /salmon/);\n   *     expect(badFn).to.throw(err, 'salmon');\n   *     expect(badFn).to.throw(err, /salmon/);\n   *\n   * Add `.not` earlier in the chain to negate `.throw`.\n   *\n   *     var goodFn = function () {};\n   *\n   *     expect(goodFn).to.not.throw();\n   *\n   * However, it's dangerous to negate `.throw` when providing any arguments.\n   * The problem is that it creates uncertain expectations by asserting that the\n   * target either doesn't throw an error, or that it throws an error but of a\n   * different type than the given type, or that it throws an error of the given\n   * type but with a message that doesn't include the given string. It's often\n   * best to identify the exact output that's expected, and then write an\n   * assertion that only accepts that exact output.\n   *\n   * When the target isn't expected to throw an error, it's often best to assert\n   * exactly that.\n   *\n   *     var goodFn = function () {};\n   *\n   *     expect(goodFn).to.not.throw(); // Recommended\n   *     expect(goodFn).to.not.throw(ReferenceError, 'x'); // Not recommended\n   *\n   * When the target is expected to throw an error, it's often best to assert\n   * that the error is of its expected type, and has a message that includes an\n   * expected string, rather than asserting that it doesn't have one of many\n   * unexpected types, and doesn't have a message that includes some string.\n   *\n   *     var badFn = function () { throw new TypeError('Illegal salmon!'); };\n   *\n   *     expect(badFn).to.throw(TypeError, 'salmon'); // Recommended\n   *     expect(badFn).to.not.throw(ReferenceError, 'x'); // Not recommended\n   *\n   * `.throw` changes the target of any assertions that follow in the chain to\n   * be the error object that's thrown.\n   *\n   *     var err = new TypeError('Illegal salmon!');\n   *     err.code = 42;\n   *     var badFn = function () { throw err; };\n   *\n   *     expect(badFn).to.throw(TypeError).with.property('code', 42);\n   *\n   * `.throw` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`. When not providing two arguments, always use\n   * the second form.\n   *\n   *     var goodFn = function () {};\n   *\n   *     expect(goodFn).to.throw(TypeError, 'x', 'nooo why fail??');\n   *     expect(goodFn, 'nooo why fail??').to.throw();\n   *\n   * Due to limitations in ES5, `.throw` may not always work as expected when\n   * using a transpiler such as Babel or TypeScript. In particular, it may\n   * produce unexpected results when subclassing the built-in `Error` object and\n   * then passing the subclassed constructor to `.throw`. See your transpiler's\n   * docs for details:\n   *\n   * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes))\n   * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work))\n   *\n   * Beware of some common mistakes when using the `throw` assertion. One common\n   * mistake is to accidentally invoke the function yourself instead of letting\n   * the `throw` assertion invoke the function for you. For example, when\n   * testing if a function named `fn` throws, provide `fn` instead of `fn()` as\n   * the target for the assertion.\n   *\n   *     expect(fn).to.throw();     // Good! Tests `fn` as desired\n   *     expect(fn()).to.throw();   // Bad! Tests result of `fn()`, not `fn`\n   *\n   * If you need to assert that your function `fn` throws when passed certain\n   * arguments, then wrap a call to `fn` inside of another function.\n   *\n   *     expect(function () { fn(42); }).to.throw();  // Function expression\n   *     expect(() => fn(42)).to.throw();             // ES6 arrow function\n   *\n   * Another common mistake is to provide an object method (or any stand-alone\n   * function that relies on `this`) as the target of the assertion. Doing so is\n   * problematic because the `this` context will be lost when the function is\n   * invoked by `.throw`; there's no way for it to know what `this` is supposed\n   * to be. There are two ways around this problem. One solution is to wrap the\n   * method or function call inside of another function. Another solution is to\n   * use `bind`.\n   *\n   *     expect(function () { cat.meow(); }).to.throw();  // Function expression\n   *     expect(() => cat.meow()).to.throw();             // ES6 arrow function\n   *     expect(cat.meow.bind(cat)).to.throw();           // Bind\n   *\n   * Finally, it's worth mentioning that it's a best practice in JavaScript to\n   * only throw `Error` and derivatives of `Error` such as `ReferenceError`,\n   * `TypeError`, and user-defined objects that extend `Error`. No other type of\n   * value will generate a stack trace when initialized. With that said, the\n   * `throw` assertion does technically support any type of value being thrown,\n   * not just `Error` and its derivatives.\n   *\n   * The aliases `.throws` and `.Throw` can be used interchangeably with\n   * `.throw`.\n   *\n   * @name throw\n   * @alias throws\n   * @alias Throw\n   * @param {Error|ErrorConstructor} errorLike\n   * @param {String|RegExp} errMsgMatcher error message\n   * @param {String} msg _optional_\n   * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n   * @returns error for chaining (null if no error)\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertThrows (errorLike, errMsgMatcher, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , ssfi = flag(this, 'ssfi')\n      , flagMsg = flag(this, 'message')\n      , negate = flag(this, 'negate') || false;\n    new Assertion(obj, flagMsg, ssfi, true).is.a('function');\n\n    if (errorLike instanceof RegExp || typeof errorLike === 'string') {\n      errMsgMatcher = errorLike;\n      errorLike = null;\n    }\n\n    var caughtErr;\n    try {\n      obj();\n    } catch (err) {\n      caughtErr = err;\n    }\n\n    // If we have the negate flag enabled and at least one valid argument it means we do expect an error\n    // but we want it to match a given set of criteria\n    var everyArgIsUndefined = errorLike === undefined && errMsgMatcher === undefined;\n\n    // If we've got the negate flag enabled and both args, we should only fail if both aren't compatible\n    // See Issue #551 and PR #683@GitHub\n    var everyArgIsDefined = Boolean(errorLike && errMsgMatcher);\n    var errorLikeFail = false;\n    var errMsgMatcherFail = false;\n\n    // Checking if error was thrown\n    if (everyArgIsUndefined || !everyArgIsUndefined && !negate) {\n      // We need this to display results correctly according to their types\n      var errorLikeString = 'an error';\n      if (errorLike instanceof Error) {\n        errorLikeString = '#{exp}';\n      } else if (errorLike) {\n        errorLikeString = _.checkError.getConstructorName(errorLike);\n      }\n\n      this.assert(\n          caughtErr\n        , 'expected #{this} to throw ' + errorLikeString\n        , 'expected #{this} to not throw an error but #{act} was thrown'\n        , errorLike && errorLike.toString()\n        , (caughtErr instanceof Error ?\n            caughtErr.toString() : (typeof caughtErr === 'string' ? caughtErr : caughtErr &&\n                                    _.checkError.getConstructorName(caughtErr)))\n      );\n    }\n\n    if (errorLike && caughtErr) {\n      // We should compare instances only if `errorLike` is an instance of `Error`\n      if (errorLike instanceof Error) {\n        var isCompatibleInstance = _.checkError.compatibleInstance(caughtErr, errorLike);\n\n        if (isCompatibleInstance === negate) {\n          // These checks were created to ensure we won't fail too soon when we've got both args and a negate\n          // See Issue #551 and PR #683@GitHub\n          if (everyArgIsDefined && negate) {\n            errorLikeFail = true;\n          } else {\n            this.assert(\n                negate\n              , 'expected #{this} to throw #{exp} but #{act} was thrown'\n              , 'expected #{this} to not throw #{exp}' + (caughtErr && !negate ? ' but #{act} was thrown' : '')\n              , errorLike.toString()\n              , caughtErr.toString()\n            );\n          }\n        }\n      }\n\n      var isCompatibleConstructor = _.checkError.compatibleConstructor(caughtErr, errorLike);\n      if (isCompatibleConstructor === negate) {\n        if (everyArgIsDefined && negate) {\n            errorLikeFail = true;\n        } else {\n          this.assert(\n              negate\n            , 'expected #{this} to throw #{exp} but #{act} was thrown'\n            , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '')\n            , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike))\n            , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr))\n          );\n        }\n      }\n    }\n\n    if (caughtErr && errMsgMatcher !== undefined && errMsgMatcher !== null) {\n      // Here we check compatible messages\n      var placeholder = 'including';\n      if (errMsgMatcher instanceof RegExp) {\n        placeholder = 'matching'\n      }\n\n      var isCompatibleMessage = _.checkError.compatibleMessage(caughtErr, errMsgMatcher);\n      if (isCompatibleMessage === negate) {\n        if (everyArgIsDefined && negate) {\n            errMsgMatcherFail = true;\n        } else {\n          this.assert(\n            negate\n            , 'expected #{this} to throw error ' + placeholder + ' #{exp} but got #{act}'\n            , 'expected #{this} to throw error not ' + placeholder + ' #{exp}'\n            ,  errMsgMatcher\n            ,  _.checkError.getMessage(caughtErr)\n          );\n        }\n      }\n    }\n\n    // If both assertions failed and both should've matched we throw an error\n    if (errorLikeFail && errMsgMatcherFail) {\n      this.assert(\n        negate\n        , 'expected #{this} to throw #{exp} but #{act} was thrown'\n        , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '')\n        , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike))\n        , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr))\n      );\n    }\n\n    flag(this, 'object', caughtErr);\n  };\n\n  Assertion.addMethod('throw', assertThrows);\n  Assertion.addMethod('throws', assertThrows);\n  Assertion.addMethod('Throw', assertThrows);\n\n  /**\n   * ### .respondTo(method[, msg])\n   *\n   * When the target is a non-function object, `.respondTo` asserts that the\n   * target has a method with the given name `method`. The method can be own or\n   * inherited, and it can be enumerable or non-enumerable.\n   *\n   *     function Cat () {}\n   *     Cat.prototype.meow = function () {};\n   *\n   *     expect(new Cat()).to.respondTo('meow');\n   *\n   * When the target is a function, `.respondTo` asserts that the target's\n   * `prototype` property has a method with the given name `method`. Again, the\n   * method can be own or inherited, and it can be enumerable or non-enumerable.\n   *\n   *     function Cat () {}\n   *     Cat.prototype.meow = function () {};\n   *\n   *     expect(Cat).to.respondTo('meow');\n   *\n   * Add `.itself` earlier in the chain to force `.respondTo` to treat the\n   * target as a non-function object, even if it's a function. Thus, it asserts\n   * that the target has a method with the given name `method`, rather than\n   * asserting that the target's `prototype` property has a method with the\n   * given name `method`.\n   *\n   *     function Cat () {}\n   *     Cat.prototype.meow = function () {};\n   *     Cat.hiss = function () {};\n   *\n   *     expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow');\n   *\n   * When not adding `.itself`, it's important to check the target's type before\n   * using `.respondTo`. See the `.a` doc for info on checking a target's type.\n   *\n   *     function Cat () {}\n   *     Cat.prototype.meow = function () {};\n   *\n   *     expect(new Cat()).to.be.an('object').that.respondsTo('meow');\n   *\n   * Add `.not` earlier in the chain to negate `.respondTo`.\n   *\n   *     function Dog () {}\n   *     Dog.prototype.bark = function () {};\n   *\n   *     expect(new Dog()).to.not.respondTo('meow');\n   *\n   * `.respondTo` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect({}).to.respondTo('meow', 'nooo why fail??');\n   *     expect({}, 'nooo why fail??').to.respondTo('meow');\n   *\n   * The alias `.respondsTo` can be used interchangeably with `.respondTo`.\n   *\n   * @name respondTo\n   * @alias respondsTo\n   * @param {String} method\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function respondTo (method, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , itself = flag(this, 'itself')\n      , context = ('function' === typeof obj && !itself)\n        ? obj.prototype[method]\n        : obj[method];\n\n    this.assert(\n        'function' === typeof context\n      , 'expected #{this} to respond to ' + _.inspect(method)\n      , 'expected #{this} to not respond to ' + _.inspect(method)\n    );\n  }\n\n  Assertion.addMethod('respondTo', respondTo);\n  Assertion.addMethod('respondsTo', respondTo);\n\n  /**\n   * ### .itself\n   *\n   * Forces all `.respondTo` assertions that follow in the chain to behave as if\n   * the target is a non-function object, even if it's a function. Thus, it\n   * causes `.respondTo` to assert that the target has a method with the given\n   * name, rather than asserting that the target's `prototype` property has a\n   * method with the given name.\n   *\n   *     function Cat () {}\n   *     Cat.prototype.meow = function () {};\n   *     Cat.hiss = function () {};\n   *\n   *     expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow');\n   *\n   * @name itself\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('itself', function () {\n    flag(this, 'itself', true);\n  });\n\n  /**\n   * ### .satisfy(matcher[, msg])\n   *\n   * Invokes the given `matcher` function with the target being passed as the\n   * first argument, and asserts that the value returned is truthy.\n   *\n   *     expect(1).to.satisfy(function(num) {\n   *       return num > 0;\n   *     });\n   *\n   * Add `.not` earlier in the chain to negate `.satisfy`.\n   *\n   *     expect(1).to.not.satisfy(function(num) {\n   *       return num > 2;\n   *     });\n   *\n   * `.satisfy` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect(1).to.satisfy(function(num) {\n   *       return num > 2;\n   *     }, 'nooo why fail??');\n   *\n   *     expect(1, 'nooo why fail??').to.satisfy(function(num) {\n   *       return num > 2;\n   *     });\n   *\n   * The alias `.satisfies` can be used interchangeably with `.satisfy`.\n   *\n   * @name satisfy\n   * @alias satisfies\n   * @param {Function} matcher\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function satisfy (matcher, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    var result = matcher(obj);\n    this.assert(\n        result\n      , 'expected #{this} to satisfy ' + _.objDisplay(matcher)\n      , 'expected #{this} to not satisfy' + _.objDisplay(matcher)\n      , flag(this, 'negate') ? false : true\n      , result\n    );\n  }\n\n  Assertion.addMethod('satisfy', satisfy);\n  Assertion.addMethod('satisfies', satisfy);\n\n  /**\n   * ### .closeTo(expected, delta[, msg])\n   *\n   * Asserts that the target is a number that's within a given +/- `delta` range\n   * of the given number `expected`. However, it's often best to assert that the\n   * target is equal to its expected value.\n   *\n   *     // Recommended\n   *     expect(1.5).to.equal(1.5);\n   *\n   *     // Not recommended\n   *     expect(1.5).to.be.closeTo(1, 0.5);\n   *     expect(1.5).to.be.closeTo(2, 0.5);\n   *     expect(1.5).to.be.closeTo(1, 1);\n   *\n   * Add `.not` earlier in the chain to negate `.closeTo`.\n   *\n   *     expect(1.5).to.equal(1.5); // Recommended\n   *     expect(1.5).to.not.be.closeTo(3, 1); // Not recommended\n   *\n   * `.closeTo` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect(1.5).to.be.closeTo(3, 1, 'nooo why fail??');\n   *     expect(1.5, 'nooo why fail??').to.be.closeTo(3, 1);\n   *\n   * The alias `.approximately` can be used interchangeably with `.closeTo`.\n   *\n   * @name closeTo\n   * @alias approximately\n   * @param {Number} expected\n   * @param {Number} delta\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function closeTo(expected, delta, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi');\n\n    new Assertion(obj, flagMsg, ssfi, true).is.a('number');\n    if (typeof expected !== 'number' || typeof delta !== 'number') {\n      flagMsg = flagMsg ? flagMsg + ': ' : '';\n      var deltaMessage = delta === undefined ? \", and a delta is required\" : \"\";\n      throw new AssertionError(\n          flagMsg + 'the arguments to closeTo or approximately must be numbers' + deltaMessage,\n          undefined,\n          ssfi\n      );\n    }\n\n    this.assert(\n        Math.abs(obj - expected) <= delta\n      , 'expected #{this} to be close to ' + expected + ' +/- ' + delta\n      , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta\n    );\n  }\n\n  Assertion.addMethod('closeTo', closeTo);\n  Assertion.addMethod('approximately', closeTo);\n\n  // Note: Duplicates are ignored if testing for inclusion instead of sameness.\n  function isSubsetOf(subset, superset, cmp, contains, ordered) {\n    if (!contains) {\n      if (subset.length !== superset.length) return false;\n      superset = superset.slice();\n    }\n\n    return subset.every(function(elem, idx) {\n      if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx];\n\n      if (!cmp) {\n        var matchIdx = superset.indexOf(elem);\n        if (matchIdx === -1) return false;\n\n        // Remove match from superset so not counted twice if duplicate in subset.\n        if (!contains) superset.splice(matchIdx, 1);\n        return true;\n      }\n\n      return superset.some(function(elem2, matchIdx) {\n        if (!cmp(elem, elem2)) return false;\n\n        // Remove match from superset so not counted twice if duplicate in subset.\n        if (!contains) superset.splice(matchIdx, 1);\n        return true;\n      });\n    });\n  }\n\n  /**\n   * ### .members(set[, msg])\n   *\n   * Asserts that the target array has the same members as the given array\n   * `set`.\n   *\n   *     expect([1, 2, 3]).to.have.members([2, 1, 3]);\n   *     expect([1, 2, 2]).to.have.members([2, 1, 2]);\n   *\n   * By default, members are compared using strict (`===`) equality. Add `.deep`\n   * earlier in the chain to use deep equality instead. See the `deep-eql`\n   * project page for info on the deep equality algorithm:\n   * https://github.com/chaijs/deep-eql.\n   *\n   *     // Target array deeply (but not strictly) has member `{a: 1}`\n   *     expect([{a: 1}]).to.have.deep.members([{a: 1}]);\n   *     expect([{a: 1}]).to.not.have.members([{a: 1}]);\n   *\n   * By default, order doesn't matter. Add `.ordered` earlier in the chain to\n   * require that members appear in the same order.\n   *\n   *     expect([1, 2, 3]).to.have.ordered.members([1, 2, 3]);\n   *     expect([1, 2, 3]).to.have.members([2, 1, 3])\n   *       .but.not.ordered.members([2, 1, 3]);\n   *\n   * By default, both arrays must be the same size. Add `.include` earlier in\n   * the chain to require that the target's members be a superset of the\n   * expected members. Note that duplicates are ignored in the subset when\n   * `.include` is added.\n   *\n   *     // Target array is a superset of [1, 2] but not identical\n   *     expect([1, 2, 3]).to.include.members([1, 2]);\n   *     expect([1, 2, 3]).to.not.have.members([1, 2]);\n   *\n   *     // Duplicates in the subset are ignored\n   *     expect([1, 2, 3]).to.include.members([1, 2, 2, 2]);\n   *\n   * `.deep`, `.ordered`, and `.include` can all be combined. However, if\n   * `.include` and `.ordered` are combined, the ordering begins at the start of\n   * both arrays.\n   *\n   *     expect([{a: 1}, {b: 2}, {c: 3}])\n   *       .to.include.deep.ordered.members([{a: 1}, {b: 2}])\n   *       .but.not.include.deep.ordered.members([{b: 2}, {c: 3}]);\n   *\n   * Add `.not` earlier in the chain to negate `.members`. However, it's\n   * dangerous to do so. The problem is that it creates uncertain expectations\n   * by asserting that the target array doesn't have all of the same members as\n   * the given array `set` but may or may not have some of them. It's often best\n   * to identify the exact output that's expected, and then write an assertion\n   * that only accepts that exact output.\n   *\n   *     expect([1, 2]).to.not.include(3).and.not.include(4); // Recommended\n   *     expect([1, 2]).to.not.have.members([3, 4]); // Not recommended\n   *\n   * `.members` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`.\n   *\n   *     expect([1, 2]).to.have.members([1, 2, 3], 'nooo why fail??');\n   *     expect([1, 2], 'nooo why fail??').to.have.members([1, 2, 3]);\n   *\n   * @name members\n   * @param {Array} set\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addMethod('members', function (subset, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi');\n\n    new Assertion(obj, flagMsg, ssfi, true).to.be.an('array');\n    new Assertion(subset, flagMsg, ssfi, true).to.be.an('array');\n\n    var contains = flag(this, 'contains');\n    var ordered = flag(this, 'ordered');\n\n    var subject, failMsg, failNegateMsg;\n\n    if (contains) {\n      subject = ordered ? 'an ordered superset' : 'a superset';\n      failMsg = 'expected #{this} to be ' + subject + ' of #{exp}';\n      failNegateMsg = 'expected #{this} to not be ' + subject + ' of #{exp}';\n    } else {\n      subject = ordered ? 'ordered members' : 'members';\n      failMsg = 'expected #{this} to have the same ' + subject + ' as #{exp}';\n      failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}';\n    }\n\n    var cmp = flag(this, 'deep') ? _.eql : undefined;\n\n    this.assert(\n        isSubsetOf(subset, obj, cmp, contains, ordered)\n      , failMsg\n      , failNegateMsg\n      , subset\n      , obj\n      , true\n    );\n  });\n\n  /**\n   * ### .oneOf(list[, msg])\n   *\n   * Asserts that the target is a member of the given array `list`. However,\n   * it's often best to assert that the target is equal to its expected value.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.be.oneOf([1, 2, 3]); // Not recommended\n   *\n   * Comparisons are performed using strict (`===`) equality.\n   *\n   * Add `.not` earlier in the chain to negate `.oneOf`.\n   *\n   *     expect(1).to.equal(1); // Recommended\n   *     expect(1).to.not.be.oneOf([2, 3, 4]); // Not recommended\n   *\n   * It can also be chained with `.contain` or `.include`, which will work with\n   * both arrays and strings:\n   *\n   *     expect('Today is sunny').to.contain.oneOf(['sunny', 'cloudy'])\n   *     expect('Today is rainy').to.not.contain.oneOf(['sunny', 'cloudy'])\n   *     expect([1,2,3]).to.contain.oneOf([3,4,5])\n   *     expect([1,2,3]).to.not.contain.oneOf([4,5,6])\n   *\n   * `.oneOf` accepts an optional `msg` argument which is a custom error message\n   * to show when the assertion fails. The message can also be given as the\n   * second argument to `expect`.\n   *\n   *     expect(1).to.be.oneOf([2, 3, 4], 'nooo why fail??');\n   *     expect(1, 'nooo why fail??').to.be.oneOf([2, 3, 4]);\n   *\n   * @name oneOf\n   * @param {Array<*>} list\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function oneOf (list, msg) {\n    if (msg) flag(this, 'message', msg);\n    var expected = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi')\n      , contains = flag(this, 'contains')\n      , isDeep = flag(this, 'deep');\n    new Assertion(list, flagMsg, ssfi, true).to.be.an('array');\n\n    if (contains) {\n      this.assert(\n        list.some(function(possibility) { return expected.indexOf(possibility) > -1 })\n        , 'expected #{this} to contain one of #{exp}'\n        , 'expected #{this} to not contain one of #{exp}'\n        , list\n        , expected\n      );\n    } else {\n      if (isDeep) {\n        this.assert(\n          list.some(function(possibility) { return _.eql(expected, possibility) })\n          , 'expected #{this} to deeply equal one of #{exp}'\n          , 'expected #{this} to deeply equal one of #{exp}'\n          , list\n          , expected\n        );\n      } else {\n        this.assert(\n          list.indexOf(expected) > -1\n          , 'expected #{this} to be one of #{exp}'\n          , 'expected #{this} to not be one of #{exp}'\n          , list\n          , expected\n        );\n      }\n    }\n  }\n\n  Assertion.addMethod('oneOf', oneOf);\n\n  /**\n   * ### .change(subject[, prop[, msg]])\n   *\n   * When one argument is provided, `.change` asserts that the given function\n   * `subject` returns a different value when it's invoked before the target\n   * function compared to when it's invoked afterward. However, it's often best\n   * to assert that `subject` is equal to its expected value.\n   *\n   *     var dots = ''\n   *       , addDot = function () { dots += '.'; }\n   *       , getDots = function () { return dots; };\n   *\n   *     // Recommended\n   *     expect(getDots()).to.equal('');\n   *     addDot();\n   *     expect(getDots()).to.equal('.');\n   *\n   *     // Not recommended\n   *     expect(addDot).to.change(getDots);\n   *\n   * When two arguments are provided, `.change` asserts that the value of the\n   * given object `subject`'s `prop` property is different before invoking the\n   * target function compared to afterward.\n   *\n   *     var myObj = {dots: ''}\n   *       , addDot = function () { myObj.dots += '.'; };\n   *\n   *     // Recommended\n   *     expect(myObj).to.have.property('dots', '');\n   *     addDot();\n   *     expect(myObj).to.have.property('dots', '.');\n   *\n   *     // Not recommended\n   *     expect(addDot).to.change(myObj, 'dots');\n   *\n   * Strict (`===`) equality is used to compare before and after values.\n   *\n   * Add `.not` earlier in the chain to negate `.change`.\n   *\n   *     var dots = ''\n   *       , noop = function () {}\n   *       , getDots = function () { return dots; };\n   *\n   *     expect(noop).to.not.change(getDots);\n   *\n   *     var myObj = {dots: ''}\n   *       , noop = function () {};\n   *\n   *     expect(noop).to.not.change(myObj, 'dots');\n   *\n   * `.change` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`. When not providing two arguments, always\n   * use the second form.\n   *\n   *     var myObj = {dots: ''}\n   *       , addDot = function () { myObj.dots += '.'; };\n   *\n   *     expect(addDot).to.not.change(myObj, 'dots', 'nooo why fail??');\n   *\n   *     var dots = ''\n   *       , addDot = function () { dots += '.'; }\n   *       , getDots = function () { return dots; };\n   *\n   *     expect(addDot, 'nooo why fail??').to.not.change(getDots);\n   *\n   * `.change` also causes all `.by` assertions that follow in the chain to\n   * assert how much a numeric subject was increased or decreased by. However,\n   * it's dangerous to use `.change.by`. The problem is that it creates\n   * uncertain expectations by asserting that the subject either increases by\n   * the given delta, or that it decreases by the given delta. It's often best\n   * to identify the exact output that's expected, and then write an assertion\n   * that only accepts that exact output.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; }\n   *       , subtractTwo = function () { myObj.val -= 2; };\n   *\n   *     expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended\n   *     expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended\n   *\n   *     expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended\n   *     expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended\n   *\n   * The alias `.changes` can be used interchangeably with `.change`.\n   *\n   * @name change\n   * @alias changes\n   * @param {String} subject\n   * @param {String} prop name _optional_\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertChanges (subject, prop, msg) {\n    if (msg) flag(this, 'message', msg);\n    var fn = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi');\n    new Assertion(fn, flagMsg, ssfi, true).is.a('function');\n\n    var initial;\n    if (!prop) {\n      new Assertion(subject, flagMsg, ssfi, true).is.a('function');\n      initial = subject();\n    } else {\n      new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop);\n      initial = subject[prop];\n    }\n\n    fn();\n\n    var final = prop === undefined || prop === null ? subject() : subject[prop];\n    var msgObj = prop === undefined || prop === null ? initial : '.' + prop;\n\n    // This gets flagged because of the .by(delta) assertion\n    flag(this, 'deltaMsgObj', msgObj);\n    flag(this, 'initialDeltaValue', initial);\n    flag(this, 'finalDeltaValue', final);\n    flag(this, 'deltaBehavior', 'change');\n    flag(this, 'realDelta', final !== initial);\n\n    this.assert(\n      initial !== final\n      , 'expected ' + msgObj + ' to change'\n      , 'expected ' + msgObj + ' to not change'\n    );\n  }\n\n  Assertion.addMethod('change', assertChanges);\n  Assertion.addMethod('changes', assertChanges);\n\n  /**\n   * ### .increase(subject[, prop[, msg]])\n   *\n   * When one argument is provided, `.increase` asserts that the given function\n   * `subject` returns a greater number when it's invoked after invoking the\n   * target function compared to when it's invoked beforehand. `.increase` also\n   * causes all `.by` assertions that follow in the chain to assert how much\n   * greater of a number is returned. It's often best to assert that the return\n   * value increased by the expected amount, rather than asserting it increased\n   * by any amount.\n   *\n   *     var val = 1\n   *       , addTwo = function () { val += 2; }\n   *       , getVal = function () { return val; };\n   *\n   *     expect(addTwo).to.increase(getVal).by(2); // Recommended\n   *     expect(addTwo).to.increase(getVal); // Not recommended\n   *\n   * When two arguments are provided, `.increase` asserts that the value of the\n   * given object `subject`'s `prop` property is greater after invoking the\n   * target function compared to beforehand.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; };\n   *\n   *     expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended\n   *     expect(addTwo).to.increase(myObj, 'val'); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.increase`. However, it's\n   * dangerous to do so. The problem is that it creates uncertain expectations\n   * by asserting that the subject either decreases, or that it stays the same.\n   * It's often best to identify the exact output that's expected, and then\n   * write an assertion that only accepts that exact output.\n   *\n   * When the subject is expected to decrease, it's often best to assert that it\n   * decreased by the expected amount.\n   *\n   *     var myObj = {val: 1}\n   *       , subtractTwo = function () { myObj.val -= 2; };\n   *\n   *     expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended\n   *     expect(subtractTwo).to.not.increase(myObj, 'val'); // Not recommended\n   *\n   * When the subject is expected to stay the same, it's often best to assert\n   * exactly that.\n   *\n   *     var myObj = {val: 1}\n   *       , noop = function () {};\n   *\n   *     expect(noop).to.not.change(myObj, 'val'); // Recommended\n   *     expect(noop).to.not.increase(myObj, 'val'); // Not recommended\n   *\n   * `.increase` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`. When not providing two arguments, always\n   * use the second form.\n   *\n   *     var myObj = {val: 1}\n   *       , noop = function () {};\n   *\n   *     expect(noop).to.increase(myObj, 'val', 'nooo why fail??');\n   *\n   *     var val = 1\n   *       , noop = function () {}\n   *       , getVal = function () { return val; };\n   *\n   *     expect(noop, 'nooo why fail??').to.increase(getVal);\n   *\n   * The alias `.increases` can be used interchangeably with `.increase`.\n   *\n   * @name increase\n   * @alias increases\n   * @param {String|Function} subject\n   * @param {String} prop name _optional_\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertIncreases (subject, prop, msg) {\n    if (msg) flag(this, 'message', msg);\n    var fn = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi');\n    new Assertion(fn, flagMsg, ssfi, true).is.a('function');\n\n    var initial;\n    if (!prop) {\n      new Assertion(subject, flagMsg, ssfi, true).is.a('function');\n      initial = subject();\n    } else {\n      new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop);\n      initial = subject[prop];\n    }\n\n    // Make sure that the target is a number\n    new Assertion(initial, flagMsg, ssfi, true).is.a('number');\n\n    fn();\n\n    var final = prop === undefined || prop === null ? subject() : subject[prop];\n    var msgObj = prop === undefined || prop === null ? initial : '.' + prop;\n\n    flag(this, 'deltaMsgObj', msgObj);\n    flag(this, 'initialDeltaValue', initial);\n    flag(this, 'finalDeltaValue', final);\n    flag(this, 'deltaBehavior', 'increase');\n    flag(this, 'realDelta', final - initial);\n\n    this.assert(\n      final - initial > 0\n      , 'expected ' + msgObj + ' to increase'\n      , 'expected ' + msgObj + ' to not increase'\n    );\n  }\n\n  Assertion.addMethod('increase', assertIncreases);\n  Assertion.addMethod('increases', assertIncreases);\n\n  /**\n   * ### .decrease(subject[, prop[, msg]])\n   *\n   * When one argument is provided, `.decrease` asserts that the given function\n   * `subject` returns a lesser number when it's invoked after invoking the\n   * target function compared to when it's invoked beforehand. `.decrease` also\n   * causes all `.by` assertions that follow in the chain to assert how much\n   * lesser of a number is returned. It's often best to assert that the return\n   * value decreased by the expected amount, rather than asserting it decreased\n   * by any amount.\n   *\n   *     var val = 1\n   *       , subtractTwo = function () { val -= 2; }\n   *       , getVal = function () { return val; };\n   *\n   *     expect(subtractTwo).to.decrease(getVal).by(2); // Recommended\n   *     expect(subtractTwo).to.decrease(getVal); // Not recommended\n   *\n   * When two arguments are provided, `.decrease` asserts that the value of the\n   * given object `subject`'s `prop` property is lesser after invoking the\n   * target function compared to beforehand.\n   *\n   *     var myObj = {val: 1}\n   *       , subtractTwo = function () { myObj.val -= 2; };\n   *\n   *     expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended\n   *     expect(subtractTwo).to.decrease(myObj, 'val'); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.decrease`. However, it's\n   * dangerous to do so. The problem is that it creates uncertain expectations\n   * by asserting that the subject either increases, or that it stays the same.\n   * It's often best to identify the exact output that's expected, and then\n   * write an assertion that only accepts that exact output.\n   *\n   * When the subject is expected to increase, it's often best to assert that it\n   * increased by the expected amount.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; };\n   *\n   *     expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended\n   *     expect(addTwo).to.not.decrease(myObj, 'val'); // Not recommended\n   *\n   * When the subject is expected to stay the same, it's often best to assert\n   * exactly that.\n   *\n   *     var myObj = {val: 1}\n   *       , noop = function () {};\n   *\n   *     expect(noop).to.not.change(myObj, 'val'); // Recommended\n   *     expect(noop).to.not.decrease(myObj, 'val'); // Not recommended\n   *\n   * `.decrease` accepts an optional `msg` argument which is a custom error\n   * message to show when the assertion fails. The message can also be given as\n   * the second argument to `expect`. When not providing two arguments, always\n   * use the second form.\n   *\n   *     var myObj = {val: 1}\n   *       , noop = function () {};\n   *\n   *     expect(noop).to.decrease(myObj, 'val', 'nooo why fail??');\n   *\n   *     var val = 1\n   *       , noop = function () {}\n   *       , getVal = function () { return val; };\n   *\n   *     expect(noop, 'nooo why fail??').to.decrease(getVal);\n   *\n   * The alias `.decreases` can be used interchangeably with `.decrease`.\n   *\n   * @name decrease\n   * @alias decreases\n   * @param {String|Function} subject\n   * @param {String} prop name _optional_\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertDecreases (subject, prop, msg) {\n    if (msg) flag(this, 'message', msg);\n    var fn = flag(this, 'object')\n      , flagMsg = flag(this, 'message')\n      , ssfi = flag(this, 'ssfi');\n    new Assertion(fn, flagMsg, ssfi, true).is.a('function');\n\n    var initial;\n    if (!prop) {\n      new Assertion(subject, flagMsg, ssfi, true).is.a('function');\n      initial = subject();\n    } else {\n      new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop);\n      initial = subject[prop];\n    }\n\n    // Make sure that the target is a number\n    new Assertion(initial, flagMsg, ssfi, true).is.a('number');\n\n    fn();\n\n    var final = prop === undefined || prop === null ? subject() : subject[prop];\n    var msgObj = prop === undefined || prop === null ? initial : '.' + prop;\n\n    flag(this, 'deltaMsgObj', msgObj);\n    flag(this, 'initialDeltaValue', initial);\n    flag(this, 'finalDeltaValue', final);\n    flag(this, 'deltaBehavior', 'decrease');\n    flag(this, 'realDelta', initial - final);\n\n    this.assert(\n      final - initial < 0\n      , 'expected ' + msgObj + ' to decrease'\n      , 'expected ' + msgObj + ' to not decrease'\n    );\n  }\n\n  Assertion.addMethod('decrease', assertDecreases);\n  Assertion.addMethod('decreases', assertDecreases);\n\n  /**\n   * ### .by(delta[, msg])\n   *\n   * When following an `.increase` assertion in the chain, `.by` asserts that\n   * the subject of the `.increase` assertion increased by the given `delta`.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; };\n   *\n   *     expect(addTwo).to.increase(myObj, 'val').by(2);\n   *\n   * When following a `.decrease` assertion in the chain, `.by` asserts that the\n   * subject of the `.decrease` assertion decreased by the given `delta`.\n   *\n   *     var myObj = {val: 1}\n   *       , subtractTwo = function () { myObj.val -= 2; };\n   *\n   *     expect(subtractTwo).to.decrease(myObj, 'val').by(2);\n   *\n   * When following a `.change` assertion in the chain, `.by` asserts that the\n   * subject of the `.change` assertion either increased or decreased by the\n   * given `delta`. However, it's dangerous to use `.change.by`. The problem is\n   * that it creates uncertain expectations. It's often best to identify the\n   * exact output that's expected, and then write an assertion that only accepts\n   * that exact output.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; }\n   *       , subtractTwo = function () { myObj.val -= 2; };\n   *\n   *     expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended\n   *     expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended\n   *\n   *     expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended\n   *     expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended\n   *\n   * Add `.not` earlier in the chain to negate `.by`. However, it's often best\n   * to assert that the subject changed by its expected delta, rather than\n   * asserting that it didn't change by one of countless unexpected deltas.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; };\n   *\n   *     // Recommended\n   *     expect(addTwo).to.increase(myObj, 'val').by(2);\n   *\n   *     // Not recommended\n   *     expect(addTwo).to.increase(myObj, 'val').but.not.by(3);\n   *\n   * `.by` accepts an optional `msg` argument which is a custom error message to\n   * show when the assertion fails. The message can also be given as the second\n   * argument to `expect`.\n   *\n   *     var myObj = {val: 1}\n   *       , addTwo = function () { myObj.val += 2; };\n   *\n   *     expect(addTwo).to.increase(myObj, 'val').by(3, 'nooo why fail??');\n   *     expect(addTwo, 'nooo why fail??').to.increase(myObj, 'val').by(3);\n   *\n   * @name by\n   * @param {Number} delta\n   * @param {String} msg _optional_\n   * @namespace BDD\n   * @api public\n   */\n\n  function assertDelta(delta, msg) {\n    if (msg) flag(this, 'message', msg);\n\n    var msgObj = flag(this, 'deltaMsgObj');\n    var initial = flag(this, 'initialDeltaValue');\n    var final = flag(this, 'finalDeltaValue');\n    var behavior = flag(this, 'deltaBehavior');\n    var realDelta = flag(this, 'realDelta');\n\n    var expression;\n    if (behavior === 'change') {\n      expression = Math.abs(final - initial) === Math.abs(delta);\n    } else {\n      expression = realDelta === Math.abs(delta);\n    }\n\n    this.assert(\n      expression\n      , 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta\n      , 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta\n    );\n  }\n\n  Assertion.addMethod('by', assertDelta);\n\n  /**\n   * ### .extensible\n   *\n   * Asserts that the target is extensible, which means that new properties can\n   * be added to it. Primitives are never extensible.\n   *\n   *     expect({a: 1}).to.be.extensible;\n   *\n   * Add `.not` earlier in the chain to negate `.extensible`.\n   *\n   *     var nonExtensibleObject = Object.preventExtensions({})\n   *       , sealedObject = Object.seal({})\n   *       , frozenObject = Object.freeze({});\n   *\n   *     expect(nonExtensibleObject).to.not.be.extensible;\n   *     expect(sealedObject).to.not.be.extensible;\n   *     expect(frozenObject).to.not.be.extensible;\n   *     expect(1).to.not.be.extensible;\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect(1, 'nooo why fail??').to.be.extensible;\n   *\n   * @name extensible\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('extensible', function() {\n    var obj = flag(this, 'object');\n\n    // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.\n    // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false.\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n    // The following provides ES6 behavior for ES5 environments.\n\n    var isExtensible = obj === Object(obj) && Object.isExtensible(obj);\n\n    this.assert(\n      isExtensible\n      , 'expected #{this} to be extensible'\n      , 'expected #{this} to not be extensible'\n    );\n  });\n\n  /**\n   * ### .sealed\n   *\n   * Asserts that the target is sealed, which means that new properties can't be\n   * added to it, and its existing properties can't be reconfigured or deleted.\n   * However, it's possible that its existing properties can still be reassigned\n   * to different values. Primitives are always sealed.\n   *\n   *     var sealedObject = Object.seal({});\n   *     var frozenObject = Object.freeze({});\n   *\n   *     expect(sealedObject).to.be.sealed;\n   *     expect(frozenObject).to.be.sealed;\n   *     expect(1).to.be.sealed;\n   *\n   * Add `.not` earlier in the chain to negate `.sealed`.\n   *\n   *     expect({a: 1}).to.not.be.sealed;\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect({a: 1}, 'nooo why fail??').to.be.sealed;\n   *\n   * @name sealed\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('sealed', function() {\n    var obj = flag(this, 'object');\n\n    // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.\n    // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true.\n    // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n    // The following provides ES6 behavior for ES5 environments.\n\n    var isSealed = obj === Object(obj) ? Object.isSealed(obj) : true;\n\n    this.assert(\n      isSealed\n      , 'expected #{this} to be sealed'\n      , 'expected #{this} to not be sealed'\n    );\n  });\n\n  /**\n   * ### .frozen\n   *\n   * Asserts that the target is frozen, which means that new properties can't be\n   * added to it, and its existing properties can't be reassigned to different\n   * values, reconfigured, or deleted. Primitives are always frozen.\n   *\n   *     var frozenObject = Object.freeze({});\n   *\n   *     expect(frozenObject).to.be.frozen;\n   *     expect(1).to.be.frozen;\n   *\n   * Add `.not` earlier in the chain to negate `.frozen`.\n   *\n   *     expect({a: 1}).to.not.be.frozen;\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect({a: 1}, 'nooo why fail??').to.be.frozen;\n   *\n   * @name frozen\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('frozen', function() {\n    var obj = flag(this, 'object');\n\n    // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.\n    // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true.\n    // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n    // The following provides ES6 behavior for ES5 environments.\n\n    var isFrozen = obj === Object(obj) ? Object.isFrozen(obj) : true;\n\n    this.assert(\n      isFrozen\n      , 'expected #{this} to be frozen'\n      , 'expected #{this} to not be frozen'\n    );\n  });\n\n  /**\n   * ### .finite\n   *\n   * Asserts that the target is a number, and isn't `NaN` or positive/negative\n   * `Infinity`.\n   *\n   *     expect(1).to.be.finite;\n   *\n   * Add `.not` earlier in the chain to negate `.finite`. However, it's\n   * dangerous to do so. The problem is that it creates uncertain expectations\n   * by asserting that the subject either isn't a number, or that it's `NaN`, or\n   * that it's positive `Infinity`, or that it's negative `Infinity`. It's often\n   * best to identify the exact output that's expected, and then write an\n   * assertion that only accepts that exact output.\n   *\n   * When the target isn't expected to be a number, it's often best to assert\n   * that it's the expected type, rather than asserting that it isn't one of\n   * many unexpected types.\n   *\n   *     expect('foo').to.be.a('string'); // Recommended\n   *     expect('foo').to.not.be.finite; // Not recommended\n   *\n   * When the target is expected to be `NaN`, it's often best to assert exactly\n   * that.\n   *\n   *     expect(NaN).to.be.NaN; // Recommended\n   *     expect(NaN).to.not.be.finite; // Not recommended\n   *\n   * When the target is expected to be positive infinity, it's often best to\n   * assert exactly that.\n   *\n   *     expect(Infinity).to.equal(Infinity); // Recommended\n   *     expect(Infinity).to.not.be.finite; // Not recommended\n   *\n   * When the target is expected to be negative infinity, it's often best to\n   * assert exactly that.\n   *\n   *     expect(-Infinity).to.equal(-Infinity); // Recommended\n   *     expect(-Infinity).to.not.be.finite; // Not recommended\n   *\n   * A custom error message can be given as the second argument to `expect`.\n   *\n   *     expect('foo', 'nooo why fail??').to.be.finite;\n   *\n   * @name finite\n   * @namespace BDD\n   * @api public\n   */\n\n  Assertion.addProperty('finite', function(msg) {\n    var obj = flag(this, 'object');\n\n    this.assert(\n        typeof obj === 'number' && isFinite(obj)\n      , 'expected #{this} to be a finite number'\n      , 'expected #{this} to not be a finite number'\n    );\n  });\n};\n\n},{}],6:[function(require,module,exports){\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, util) {\n  /*!\n   * Chai dependencies.\n   */\n\n  var Assertion = chai.Assertion\n    , flag = util.flag;\n\n  /*!\n   * Module export.\n   */\n\n  /**\n   * ### assert(expression, message)\n   *\n   * Write your own test expressions.\n   *\n   *     assert('foo' !== 'bar', 'foo is not bar');\n   *     assert(Array.isArray([]), 'empty arrays are arrays');\n   *\n   * @param {Mixed} expression to test for truthiness\n   * @param {String} message to display on error\n   * @name assert\n   * @namespace Assert\n   * @api public\n   */\n\n  var assert = chai.assert = function (express, errmsg) {\n    var test = new Assertion(null, null, chai.assert, true);\n    test.assert(\n        express\n      , errmsg\n      , '[ negation message unavailable ]'\n    );\n  };\n\n  /**\n   * ### .fail([message])\n   * ### .fail(actual, expected, [message], [operator])\n   *\n   * Throw a failure. Node.js `assert` module-compatible.\n   *\n   *     assert.fail();\n   *     assert.fail(\"custom error message\");\n   *     assert.fail(1, 2);\n   *     assert.fail(1, 2, \"custom error message\");\n   *     assert.fail(1, 2, \"custom error message\", \">\");\n   *     assert.fail(1, 2, undefined, \">\");\n   *\n   * @name fail\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @param {String} operator\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.fail = function (actual, expected, message, operator) {\n    if (arguments.length < 2) {\n        // Comply with Node's fail([message]) interface\n\n        message = actual;\n        actual = undefined;\n    }\n\n    message = message || 'assert.fail()';\n    throw new chai.AssertionError(message, {\n        actual: actual\n      , expected: expected\n      , operator: operator\n    }, assert.fail);\n  };\n\n  /**\n   * ### .isOk(object, [message])\n   *\n   * Asserts that `object` is truthy.\n   *\n   *     assert.isOk('everything', 'everything is ok');\n   *     assert.isOk(false, 'this will fail');\n   *\n   * @name isOk\n   * @alias ok\n   * @param {Mixed} object to test\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isOk = function (val, msg) {\n    new Assertion(val, msg, assert.isOk, true).is.ok;\n  };\n\n  /**\n   * ### .isNotOk(object, [message])\n   *\n   * Asserts that `object` is falsy.\n   *\n   *     assert.isNotOk('everything', 'this will fail');\n   *     assert.isNotOk(false, 'this will pass');\n   *\n   * @name isNotOk\n   * @alias notOk\n   * @param {Mixed} object to test\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotOk = function (val, msg) {\n    new Assertion(val, msg, assert.isNotOk, true).is.not.ok;\n  };\n\n  /**\n   * ### .equal(actual, expected, [message])\n   *\n   * Asserts non-strict equality (`==`) of `actual` and `expected`.\n   *\n   *     assert.equal(3, '3', '== coerces values to strings');\n   *\n   * @name equal\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.equal = function (act, exp, msg) {\n    var test = new Assertion(act, msg, assert.equal, true);\n\n    test.assert(\n        exp == flag(test, 'object')\n      , 'expected #{this} to equal #{exp}'\n      , 'expected #{this} to not equal #{act}'\n      , exp\n      , act\n      , true\n    );\n  };\n\n  /**\n   * ### .notEqual(actual, expected, [message])\n   *\n   * Asserts non-strict inequality (`!=`) of `actual` and `expected`.\n   *\n   *     assert.notEqual(3, 4, 'these numbers are not equal');\n   *\n   * @name notEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notEqual = function (act, exp, msg) {\n    var test = new Assertion(act, msg, assert.notEqual, true);\n\n    test.assert(\n        exp != flag(test, 'object')\n      , 'expected #{this} to not equal #{exp}'\n      , 'expected #{this} to equal #{act}'\n      , exp\n      , act\n      , true\n    );\n  };\n\n  /**\n   * ### .strictEqual(actual, expected, [message])\n   *\n   * Asserts strict equality (`===`) of `actual` and `expected`.\n   *\n   *     assert.strictEqual(true, true, 'these booleans are strictly equal');\n   *\n   * @name strictEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.strictEqual = function (act, exp, msg) {\n    new Assertion(act, msg, assert.strictEqual, true).to.equal(exp);\n  };\n\n  /**\n   * ### .notStrictEqual(actual, expected, [message])\n   *\n   * Asserts strict inequality (`!==`) of `actual` and `expected`.\n   *\n   *     assert.notStrictEqual(3, '3', 'no coercion for strict equality');\n   *\n   * @name notStrictEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notStrictEqual = function (act, exp, msg) {\n    new Assertion(act, msg, assert.notStrictEqual, true).to.not.equal(exp);\n  };\n\n  /**\n   * ### .deepEqual(actual, expected, [message])\n   *\n   * Asserts that `actual` is deeply equal to `expected`.\n   *\n   *     assert.deepEqual({ tea: 'green' }, { tea: 'green' });\n   *\n   * @name deepEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @alias deepStrictEqual\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.deepEqual = assert.deepStrictEqual = function (act, exp, msg) {\n    new Assertion(act, msg, assert.deepEqual, true).to.eql(exp);\n  };\n\n  /**\n   * ### .notDeepEqual(actual, expected, [message])\n   *\n   * Assert that `actual` is not deeply equal to `expected`.\n   *\n   *     assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' });\n   *\n   * @name notDeepEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notDeepEqual = function (act, exp, msg) {\n    new Assertion(act, msg, assert.notDeepEqual, true).to.not.eql(exp);\n  };\n\n   /**\n   * ### .isAbove(valueToCheck, valueToBeAbove, [message])\n   *\n   * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove`.\n   *\n   *     assert.isAbove(5, 2, '5 is strictly greater than 2');\n   *\n   * @name isAbove\n   * @param {Mixed} valueToCheck\n   * @param {Mixed} valueToBeAbove\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isAbove = function (val, abv, msg) {\n    new Assertion(val, msg, assert.isAbove, true).to.be.above(abv);\n  };\n\n   /**\n   * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message])\n   *\n   * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast`.\n   *\n   *     assert.isAtLeast(5, 2, '5 is greater or equal to 2');\n   *     assert.isAtLeast(3, 3, '3 is greater or equal to 3');\n   *\n   * @name isAtLeast\n   * @param {Mixed} valueToCheck\n   * @param {Mixed} valueToBeAtLeast\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isAtLeast = function (val, atlst, msg) {\n    new Assertion(val, msg, assert.isAtLeast, true).to.be.least(atlst);\n  };\n\n   /**\n   * ### .isBelow(valueToCheck, valueToBeBelow, [message])\n   *\n   * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow`.\n   *\n   *     assert.isBelow(3, 6, '3 is strictly less than 6');\n   *\n   * @name isBelow\n   * @param {Mixed} valueToCheck\n   * @param {Mixed} valueToBeBelow\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isBelow = function (val, blw, msg) {\n    new Assertion(val, msg, assert.isBelow, true).to.be.below(blw);\n  };\n\n   /**\n   * ### .isAtMost(valueToCheck, valueToBeAtMost, [message])\n   *\n   * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost`.\n   *\n   *     assert.isAtMost(3, 6, '3 is less than or equal to 6');\n   *     assert.isAtMost(4, 4, '4 is less than or equal to 4');\n   *\n   * @name isAtMost\n   * @param {Mixed} valueToCheck\n   * @param {Mixed} valueToBeAtMost\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isAtMost = function (val, atmst, msg) {\n    new Assertion(val, msg, assert.isAtMost, true).to.be.most(atmst);\n  };\n\n  /**\n   * ### .isTrue(value, [message])\n   *\n   * Asserts that `value` is true.\n   *\n   *     var teaServed = true;\n   *     assert.isTrue(teaServed, 'the tea has been served');\n   *\n   * @name isTrue\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isTrue = function (val, msg) {\n    new Assertion(val, msg, assert.isTrue, true).is['true'];\n  };\n\n  /**\n   * ### .isNotTrue(value, [message])\n   *\n   * Asserts that `value` is not true.\n   *\n   *     var tea = 'tasty chai';\n   *     assert.isNotTrue(tea, 'great, time for tea!');\n   *\n   * @name isNotTrue\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotTrue = function (val, msg) {\n    new Assertion(val, msg, assert.isNotTrue, true).to.not.equal(true);\n  };\n\n  /**\n   * ### .isFalse(value, [message])\n   *\n   * Asserts that `value` is false.\n   *\n   *     var teaServed = false;\n   *     assert.isFalse(teaServed, 'no tea yet? hmm...');\n   *\n   * @name isFalse\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isFalse = function (val, msg) {\n    new Assertion(val, msg, assert.isFalse, true).is['false'];\n  };\n\n  /**\n   * ### .isNotFalse(value, [message])\n   *\n   * Asserts that `value` is not false.\n   *\n   *     var tea = 'tasty chai';\n   *     assert.isNotFalse(tea, 'great, time for tea!');\n   *\n   * @name isNotFalse\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotFalse = function (val, msg) {\n    new Assertion(val, msg, assert.isNotFalse, true).to.not.equal(false);\n  };\n\n  /**\n   * ### .isNull(value, [message])\n   *\n   * Asserts that `value` is null.\n   *\n   *     assert.isNull(err, 'there was no error');\n   *\n   * @name isNull\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNull = function (val, msg) {\n    new Assertion(val, msg, assert.isNull, true).to.equal(null);\n  };\n\n  /**\n   * ### .isNotNull(value, [message])\n   *\n   * Asserts that `value` is not null.\n   *\n   *     var tea = 'tasty chai';\n   *     assert.isNotNull(tea, 'great, time for tea!');\n   *\n   * @name isNotNull\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotNull = function (val, msg) {\n    new Assertion(val, msg, assert.isNotNull, true).to.not.equal(null);\n  };\n\n  /**\n   * ### .isNaN\n   *\n   * Asserts that value is NaN.\n   *\n   *     assert.isNaN(NaN, 'NaN is NaN');\n   *\n   * @name isNaN\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNaN = function (val, msg) {\n    new Assertion(val, msg, assert.isNaN, true).to.be.NaN;\n  };\n\n  /**\n   * ### .isNotNaN\n   *\n   * Asserts that value is not NaN.\n   *\n   *     assert.isNotNaN(4, '4 is not NaN');\n   *\n   * @name isNotNaN\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n  assert.isNotNaN = function (val, msg) {\n    new Assertion(val, msg, assert.isNotNaN, true).not.to.be.NaN;\n  };\n\n  /**\n   * ### .exists\n   *\n   * Asserts that the target is neither `null` nor `undefined`.\n   *\n   *     var foo = 'hi';\n   *\n   *     assert.exists(foo, 'foo is neither `null` nor `undefined`');\n   *\n   * @name exists\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.exists = function (val, msg) {\n    new Assertion(val, msg, assert.exists, true).to.exist;\n  };\n\n  /**\n   * ### .notExists\n   *\n   * Asserts that the target is either `null` or `undefined`.\n   *\n   *     var bar = null\n   *       , baz;\n   *\n   *     assert.notExists(bar);\n   *     assert.notExists(baz, 'baz is either null or undefined');\n   *\n   * @name notExists\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notExists = function (val, msg) {\n    new Assertion(val, msg, assert.notExists, true).to.not.exist;\n  };\n\n  /**\n   * ### .isUndefined(value, [message])\n   *\n   * Asserts that `value` is `undefined`.\n   *\n   *     var tea;\n   *     assert.isUndefined(tea, 'no tea defined');\n   *\n   * @name isUndefined\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isUndefined = function (val, msg) {\n    new Assertion(val, msg, assert.isUndefined, true).to.equal(undefined);\n  };\n\n  /**\n   * ### .isDefined(value, [message])\n   *\n   * Asserts that `value` is not `undefined`.\n   *\n   *     var tea = 'cup of chai';\n   *     assert.isDefined(tea, 'tea has been defined');\n   *\n   * @name isDefined\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isDefined = function (val, msg) {\n    new Assertion(val, msg, assert.isDefined, true).to.not.equal(undefined);\n  };\n\n  /**\n   * ### .isFunction(value, [message])\n   *\n   * Asserts that `value` is a function.\n   *\n   *     function serveTea() { return 'cup of tea'; };\n   *     assert.isFunction(serveTea, 'great, we can have tea now');\n   *\n   * @name isFunction\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isFunction = function (val, msg) {\n    new Assertion(val, msg, assert.isFunction, true).to.be.a('function');\n  };\n\n  /**\n   * ### .isNotFunction(value, [message])\n   *\n   * Asserts that `value` is _not_ a function.\n   *\n   *     var serveTea = [ 'heat', 'pour', 'sip' ];\n   *     assert.isNotFunction(serveTea, 'great, we have listed the steps');\n   *\n   * @name isNotFunction\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotFunction = function (val, msg) {\n    new Assertion(val, msg, assert.isNotFunction, true).to.not.be.a('function');\n  };\n\n  /**\n   * ### .isObject(value, [message])\n   *\n   * Asserts that `value` is an object of type 'Object' (as revealed by `Object.prototype.toString`).\n   * _The assertion does not match subclassed objects._\n   *\n   *     var selection = { name: 'Chai', serve: 'with spices' };\n   *     assert.isObject(selection, 'tea selection is an object');\n   *\n   * @name isObject\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isObject = function (val, msg) {\n    new Assertion(val, msg, assert.isObject, true).to.be.a('object');\n  };\n\n  /**\n   * ### .isNotObject(value, [message])\n   *\n   * Asserts that `value` is _not_ an object of type 'Object' (as revealed by `Object.prototype.toString`).\n   *\n   *     var selection = 'chai'\n   *     assert.isNotObject(selection, 'tea selection is not an object');\n   *     assert.isNotObject(null, 'null is not an object');\n   *\n   * @name isNotObject\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotObject = function (val, msg) {\n    new Assertion(val, msg, assert.isNotObject, true).to.not.be.a('object');\n  };\n\n  /**\n   * ### .isArray(value, [message])\n   *\n   * Asserts that `value` is an array.\n   *\n   *     var menu = [ 'green', 'chai', 'oolong' ];\n   *     assert.isArray(menu, 'what kind of tea do we want?');\n   *\n   * @name isArray\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isArray = function (val, msg) {\n    new Assertion(val, msg, assert.isArray, true).to.be.an('array');\n  };\n\n  /**\n   * ### .isNotArray(value, [message])\n   *\n   * Asserts that `value` is _not_ an array.\n   *\n   *     var menu = 'green|chai|oolong';\n   *     assert.isNotArray(menu, 'what kind of tea do we want?');\n   *\n   * @name isNotArray\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotArray = function (val, msg) {\n    new Assertion(val, msg, assert.isNotArray, true).to.not.be.an('array');\n  };\n\n  /**\n   * ### .isString(value, [message])\n   *\n   * Asserts that `value` is a string.\n   *\n   *     var teaOrder = 'chai';\n   *     assert.isString(teaOrder, 'order placed');\n   *\n   * @name isString\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isString = function (val, msg) {\n    new Assertion(val, msg, assert.isString, true).to.be.a('string');\n  };\n\n  /**\n   * ### .isNotString(value, [message])\n   *\n   * Asserts that `value` is _not_ a string.\n   *\n   *     var teaOrder = 4;\n   *     assert.isNotString(teaOrder, 'order placed');\n   *\n   * @name isNotString\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotString = function (val, msg) {\n    new Assertion(val, msg, assert.isNotString, true).to.not.be.a('string');\n  };\n\n  /**\n   * ### .isNumber(value, [message])\n   *\n   * Asserts that `value` is a number.\n   *\n   *     var cups = 2;\n   *     assert.isNumber(cups, 'how many cups');\n   *\n   * @name isNumber\n   * @param {Number} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNumber = function (val, msg) {\n    new Assertion(val, msg, assert.isNumber, true).to.be.a('number');\n  };\n\n  /**\n   * ### .isNotNumber(value, [message])\n   *\n   * Asserts that `value` is _not_ a number.\n   *\n   *     var cups = '2 cups please';\n   *     assert.isNotNumber(cups, 'how many cups');\n   *\n   * @name isNotNumber\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotNumber = function (val, msg) {\n    new Assertion(val, msg, assert.isNotNumber, true).to.not.be.a('number');\n  };\n\n   /**\n   * ### .isFinite(value, [message])\n   *\n   * Asserts that `value` is a finite number. Unlike `.isNumber`, this will fail for `NaN` and `Infinity`.\n   *\n   *     var cups = 2;\n   *     assert.isFinite(cups, 'how many cups');\n   *\n   *     assert.isFinite(NaN); // throws\n   *\n   * @name isFinite\n   * @param {Number} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isFinite = function (val, msg) {\n    new Assertion(val, msg, assert.isFinite, true).to.be.finite;\n  };\n\n  /**\n   * ### .isBoolean(value, [message])\n   *\n   * Asserts that `value` is a boolean.\n   *\n   *     var teaReady = true\n   *       , teaServed = false;\n   *\n   *     assert.isBoolean(teaReady, 'is the tea ready');\n   *     assert.isBoolean(teaServed, 'has tea been served');\n   *\n   * @name isBoolean\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isBoolean = function (val, msg) {\n    new Assertion(val, msg, assert.isBoolean, true).to.be.a('boolean');\n  };\n\n  /**\n   * ### .isNotBoolean(value, [message])\n   *\n   * Asserts that `value` is _not_ a boolean.\n   *\n   *     var teaReady = 'yep'\n   *       , teaServed = 'nope';\n   *\n   *     assert.isNotBoolean(teaReady, 'is the tea ready');\n   *     assert.isNotBoolean(teaServed, 'has tea been served');\n   *\n   * @name isNotBoolean\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotBoolean = function (val, msg) {\n    new Assertion(val, msg, assert.isNotBoolean, true).to.not.be.a('boolean');\n  };\n\n  /**\n   * ### .typeOf(value, name, [message])\n   *\n   * Asserts that `value`'s type is `name`, as determined by\n   * `Object.prototype.toString`.\n   *\n   *     assert.typeOf({ tea: 'chai' }, 'object', 'we have an object');\n   *     assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array');\n   *     assert.typeOf('tea', 'string', 'we have a string');\n   *     assert.typeOf(/tea/, 'regexp', 'we have a regular expression');\n   *     assert.typeOf(null, 'null', 'we have a null');\n   *     assert.typeOf(undefined, 'undefined', 'we have an undefined');\n   *\n   * @name typeOf\n   * @param {Mixed} value\n   * @param {String} name\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.typeOf = function (val, type, msg) {\n    new Assertion(val, msg, assert.typeOf, true).to.be.a(type);\n  };\n\n  /**\n   * ### .notTypeOf(value, name, [message])\n   *\n   * Asserts that `value`'s type is _not_ `name`, as determined by\n   * `Object.prototype.toString`.\n   *\n   *     assert.notTypeOf('tea', 'number', 'strings are not numbers');\n   *\n   * @name notTypeOf\n   * @param {Mixed} value\n   * @param {String} typeof name\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notTypeOf = function (val, type, msg) {\n    new Assertion(val, msg, assert.notTypeOf, true).to.not.be.a(type);\n  };\n\n  /**\n   * ### .instanceOf(object, constructor, [message])\n   *\n   * Asserts that `value` is an instance of `constructor`.\n   *\n   *     var Tea = function (name) { this.name = name; }\n   *       , chai = new Tea('chai');\n   *\n   *     assert.instanceOf(chai, Tea, 'chai is an instance of tea');\n   *\n   * @name instanceOf\n   * @param {Object} object\n   * @param {Constructor} constructor\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.instanceOf = function (val, type, msg) {\n    new Assertion(val, msg, assert.instanceOf, true).to.be.instanceOf(type);\n  };\n\n  /**\n   * ### .notInstanceOf(object, constructor, [message])\n   *\n   * Asserts `value` is not an instance of `constructor`.\n   *\n   *     var Tea = function (name) { this.name = name; }\n   *       , chai = new String('chai');\n   *\n   *     assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea');\n   *\n   * @name notInstanceOf\n   * @param {Object} object\n   * @param {Constructor} constructor\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notInstanceOf = function (val, type, msg) {\n    new Assertion(val, msg, assert.notInstanceOf, true)\n      .to.not.be.instanceOf(type);\n  };\n\n  /**\n   * ### .include(haystack, needle, [message])\n   *\n   * Asserts that `haystack` includes `needle`. Can be used to assert the\n   * inclusion of a value in an array, a substring in a string, or a subset of\n   * properties in an object.\n   *\n   *     assert.include([1,2,3], 2, 'array contains value');\n   *     assert.include('foobar', 'foo', 'string contains substring');\n   *     assert.include({ foo: 'bar', hello: 'universe' }, { foo: 'bar' }, 'object contains property');\n   *\n   * Strict equality (===) is used. When asserting the inclusion of a value in\n   * an array, the array is searched for an element that's strictly equal to the\n   * given value. When asserting a subset of properties in an object, the object\n   * is searched for the given property keys, checking that each one is present\n   * and strictly equal to the given property value. For instance:\n   *\n   *     var obj1 = {a: 1}\n   *       , obj2 = {b: 2};\n   *     assert.include([obj1, obj2], obj1);\n   *     assert.include({foo: obj1, bar: obj2}, {foo: obj1});\n   *     assert.include({foo: obj1, bar: obj2}, {foo: obj1, bar: obj2});\n   *\n   * @name include\n   * @param {Array|String} haystack\n   * @param {Mixed} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.include = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.include, true).include(inc);\n  };\n\n  /**\n   * ### .notInclude(haystack, needle, [message])\n   *\n   * Asserts that `haystack` does not include `needle`. Can be used to assert\n   * the absence of a value in an array, a substring in a string, or a subset of\n   * properties in an object.\n   *\n   *     assert.notInclude([1,2,3], 4, \"array doesn't contain value\");\n   *     assert.notInclude('foobar', 'baz', \"string doesn't contain substring\");\n   *     assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn't contain property');\n   *\n   * Strict equality (===) is used. When asserting the absence of a value in an\n   * array, the array is searched to confirm the absence of an element that's\n   * strictly equal to the given value. When asserting a subset of properties in\n   * an object, the object is searched to confirm that at least one of the given\n   * property keys is either not present or not strictly equal to the given\n   * property value. For instance:\n   *\n   *     var obj1 = {a: 1}\n   *       , obj2 = {b: 2};\n   *     assert.notInclude([obj1, obj2], {a: 1});\n   *     assert.notInclude({foo: obj1, bar: obj2}, {foo: {a: 1}});\n   *     assert.notInclude({foo: obj1, bar: obj2}, {foo: obj1, bar: {b: 2}});\n   *\n   * @name notInclude\n   * @param {Array|String} haystack\n   * @param {Mixed} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notInclude = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.notInclude, true).not.include(inc);\n  };\n\n  /**\n   * ### .deepInclude(haystack, needle, [message])\n   *\n   * Asserts that `haystack` includes `needle`. Can be used to assert the\n   * inclusion of a value in an array or a subset of properties in an object.\n   * Deep equality is used.\n   *\n   *     var obj1 = {a: 1}\n   *       , obj2 = {b: 2};\n   *     assert.deepInclude([obj1, obj2], {a: 1});\n   *     assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}});\n   *     assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 2}});\n   *\n   * @name deepInclude\n   * @param {Array|String} haystack\n   * @param {Mixed} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.deepInclude = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.deepInclude, true).deep.include(inc);\n  };\n\n  /**\n   * ### .notDeepInclude(haystack, needle, [message])\n   *\n   * Asserts that `haystack` does not include `needle`. Can be used to assert\n   * the absence of a value in an array or a subset of properties in an object.\n   * Deep equality is used.\n   *\n   *     var obj1 = {a: 1}\n   *       , obj2 = {b: 2};\n   *     assert.notDeepInclude([obj1, obj2], {a: 9});\n   *     assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 9}});\n   *     assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}});\n   *\n   * @name notDeepInclude\n   * @param {Array|String} haystack\n   * @param {Mixed} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notDeepInclude = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.notDeepInclude, true).not.deep.include(inc);\n  };\n\n  /**\n   * ### .nestedInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' includes 'needle'.\n   * Can be used to assert the inclusion of a subset of properties in an\n   * object.\n   * Enables the use of dot- and bracket-notation for referencing nested\n   * properties.\n   * '[]' and '.' in property names can be escaped using double backslashes.\n   *\n   *     assert.nestedInclude({'.a': {'b': 'x'}}, {'\\\\.a.[b]': 'x'});\n   *     assert.nestedInclude({'a': {'[b]': 'x'}}, {'a.\\\\[b\\\\]': 'x'});\n   *\n   * @name nestedInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.nestedInclude = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.nestedInclude, true).nested.include(inc);\n  };\n\n  /**\n   * ### .notNestedInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' does not include 'needle'.\n   * Can be used to assert the absence of a subset of properties in an\n   * object.\n   * Enables the use of dot- and bracket-notation for referencing nested\n   * properties.\n   * '[]' and '.' in property names can be escaped using double backslashes.\n   *\n   *     assert.notNestedInclude({'.a': {'b': 'x'}}, {'\\\\.a.b': 'y'});\n   *     assert.notNestedInclude({'a': {'[b]': 'x'}}, {'a.\\\\[b\\\\]': 'y'});\n   *\n   * @name notNestedInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notNestedInclude = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.notNestedInclude, true)\n      .not.nested.include(inc);\n  };\n\n  /**\n   * ### .deepNestedInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' includes 'needle'.\n   * Can be used to assert the inclusion of a subset of properties in an\n   * object while checking for deep equality.\n   * Enables the use of dot- and bracket-notation for referencing nested\n   * properties.\n   * '[]' and '.' in property names can be escaped using double backslashes.\n   *\n   *     assert.deepNestedInclude({a: {b: [{x: 1}]}}, {'a.b[0]': {x: 1}});\n   *     assert.deepNestedInclude({'.a': {'[b]': {x: 1}}}, {'\\\\.a.\\\\[b\\\\]': {x: 1}});\n   *\n   * @name deepNestedInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.deepNestedInclude = function(exp, inc, msg) {\n    new Assertion(exp, msg, assert.deepNestedInclude, true)\n      .deep.nested.include(inc);\n  };\n\n  /**\n   * ### .notDeepNestedInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' does not include 'needle'.\n   * Can be used to assert the absence of a subset of properties in an\n   * object while checking for deep equality.\n   * Enables the use of dot- and bracket-notation for referencing nested\n   * properties.\n   * '[]' and '.' in property names can be escaped using double backslashes.\n   *\n   *     assert.notDeepNestedInclude({a: {b: [{x: 1}]}}, {'a.b[0]': {y: 1}})\n   *     assert.notDeepNestedInclude({'.a': {'[b]': {x: 1}}}, {'\\\\.a.\\\\[b\\\\]': {y: 2}});\n   *\n   * @name notDeepNestedInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notDeepNestedInclude = function(exp, inc, msg) {\n    new Assertion(exp, msg, assert.notDeepNestedInclude, true)\n      .not.deep.nested.include(inc);\n  };\n\n  /**\n   * ### .ownInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' includes 'needle'.\n   * Can be used to assert the inclusion of a subset of properties in an\n   * object while ignoring inherited properties.\n   *\n   *     assert.ownInclude({ a: 1 }, { a: 1 });\n   *\n   * @name ownInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.ownInclude = function(exp, inc, msg) {\n    new Assertion(exp, msg, assert.ownInclude, true).own.include(inc);\n  };\n\n  /**\n   * ### .notOwnInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' includes 'needle'.\n   * Can be used to assert the absence of a subset of properties in an\n   * object while ignoring inherited properties.\n   *\n   *     Object.prototype.b = 2;\n   *\n   *     assert.notOwnInclude({ a: 1 }, { b: 2 });\n   *\n   * @name notOwnInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notOwnInclude = function(exp, inc, msg) {\n    new Assertion(exp, msg, assert.notOwnInclude, true).not.own.include(inc);\n  };\n\n  /**\n   * ### .deepOwnInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' includes 'needle'.\n   * Can be used to assert the inclusion of a subset of properties in an\n   * object while ignoring inherited properties and checking for deep equality.\n   *\n   *      assert.deepOwnInclude({a: {b: 2}}, {a: {b: 2}});\n   *\n   * @name deepOwnInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.deepOwnInclude = function(exp, inc, msg) {\n    new Assertion(exp, msg, assert.deepOwnInclude, true)\n      .deep.own.include(inc);\n  };\n\n   /**\n   * ### .notDeepOwnInclude(haystack, needle, [message])\n   *\n   * Asserts that 'haystack' includes 'needle'.\n   * Can be used to assert the absence of a subset of properties in an\n   * object while ignoring inherited properties and checking for deep equality.\n   *\n   *      assert.notDeepOwnInclude({a: {b: 2}}, {a: {c: 3}});\n   *\n   * @name notDeepOwnInclude\n   * @param {Object} haystack\n   * @param {Object} needle\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notDeepOwnInclude = function(exp, inc, msg) {\n    new Assertion(exp, msg, assert.notDeepOwnInclude, true)\n      .not.deep.own.include(inc);\n  };\n\n  /**\n   * ### .match(value, regexp, [message])\n   *\n   * Asserts that `value` matches the regular expression `regexp`.\n   *\n   *     assert.match('foobar', /^foo/, 'regexp matches');\n   *\n   * @name match\n   * @param {Mixed} value\n   * @param {RegExp} regexp\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.match = function (exp, re, msg) {\n    new Assertion(exp, msg, assert.match, true).to.match(re);\n  };\n\n  /**\n   * ### .notMatch(value, regexp, [message])\n   *\n   * Asserts that `value` does not match the regular expression `regexp`.\n   *\n   *     assert.notMatch('foobar', /^foo/, 'regexp does not match');\n   *\n   * @name notMatch\n   * @param {Mixed} value\n   * @param {RegExp} regexp\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notMatch = function (exp, re, msg) {\n    new Assertion(exp, msg, assert.notMatch, true).to.not.match(re);\n  };\n\n  /**\n   * ### .property(object, property, [message])\n   *\n   * Asserts that `object` has a direct or inherited property named by\n   * `property`.\n   *\n   *     assert.property({ tea: { green: 'matcha' }}, 'tea');\n   *     assert.property({ tea: { green: 'matcha' }}, 'toString');\n   *\n   * @name property\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.property = function (obj, prop, msg) {\n    new Assertion(obj, msg, assert.property, true).to.have.property(prop);\n  };\n\n  /**\n   * ### .notProperty(object, property, [message])\n   *\n   * Asserts that `object` does _not_ have a direct or inherited property named\n   * by `property`.\n   *\n   *     assert.notProperty({ tea: { green: 'matcha' }}, 'coffee');\n   *\n   * @name notProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg, assert.notProperty, true)\n      .to.not.have.property(prop);\n  };\n\n  /**\n   * ### .propertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a direct or inherited property named by\n   * `property` with a value given by `value`. Uses a strict equality check\n   * (===).\n   *\n   *     assert.propertyVal({ tea: 'is good' }, 'tea', 'is good');\n   *\n   * @name propertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.propertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.propertyVal, true)\n      .to.have.property(prop, val);\n  };\n\n  /**\n   * ### .notPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` does _not_ have a direct or inherited property named\n   * by `property` with value given by `value`. Uses a strict equality check\n   * (===).\n   *\n   *     assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad');\n   *     assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good');\n   *\n   * @name notPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.notPropertyVal, true)\n      .to.not.have.property(prop, val);\n  };\n\n  /**\n   * ### .deepPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a direct or inherited property named by\n   * `property` with a value given by `value`. Uses a deep equality check.\n   *\n   *     assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' });\n   *\n   * @name deepPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.deepPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.deepPropertyVal, true)\n      .to.have.deep.property(prop, val);\n  };\n\n  /**\n   * ### .notDeepPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` does _not_ have a direct or inherited property named\n   * by `property` with value given by `value`. Uses a deep equality check.\n   *\n   *     assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' });\n   *     assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' });\n   *     assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' });\n   *\n   * @name notDeepPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notDeepPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.notDeepPropertyVal, true)\n      .to.not.have.deep.property(prop, val);\n  };\n\n  /**\n   * ### .ownProperty(object, property, [message])\n   *\n   * Asserts that `object` has a direct property named by `property`. Inherited\n   * properties aren't checked.\n   *\n   *     assert.ownProperty({ tea: { green: 'matcha' }}, 'tea');\n   *\n   * @name ownProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @api public\n   */\n\n  assert.ownProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg, assert.ownProperty, true)\n      .to.have.own.property(prop);\n  };\n\n  /**\n   * ### .notOwnProperty(object, property, [message])\n   *\n   * Asserts that `object` does _not_ have a direct property named by\n   * `property`. Inherited properties aren't checked.\n   *\n   *     assert.notOwnProperty({ tea: { green: 'matcha' }}, 'coffee');\n   *     assert.notOwnProperty({}, 'toString');\n   *\n   * @name notOwnProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notOwnProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg, assert.notOwnProperty, true)\n      .to.not.have.own.property(prop);\n  };\n\n  /**\n   * ### .ownPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a direct property named by `property` and a value\n   * equal to the provided `value`. Uses a strict equality check (===).\n   * Inherited properties aren't checked.\n   *\n   *     assert.ownPropertyVal({ coffee: 'is good'}, 'coffee', 'is good');\n   *\n   * @name ownPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.ownPropertyVal = function (obj, prop, value, msg) {\n    new Assertion(obj, msg, assert.ownPropertyVal, true)\n      .to.have.own.property(prop, value);\n  };\n\n  /**\n   * ### .notOwnPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` does _not_ have a direct property named by `property`\n   * with a value equal to the provided `value`. Uses a strict equality check\n   * (===). Inherited properties aren't checked.\n   *\n   *     assert.notOwnPropertyVal({ tea: 'is better'}, 'tea', 'is worse');\n   *     assert.notOwnPropertyVal({}, 'toString', Object.prototype.toString);\n   *\n   * @name notOwnPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notOwnPropertyVal = function (obj, prop, value, msg) {\n    new Assertion(obj, msg, assert.notOwnPropertyVal, true)\n      .to.not.have.own.property(prop, value);\n  };\n\n  /**\n   * ### .deepOwnPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a direct property named by `property` and a value\n   * equal to the provided `value`. Uses a deep equality check. Inherited\n   * properties aren't checked.\n   *\n   *     assert.deepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' });\n   *\n   * @name deepOwnPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.deepOwnPropertyVal = function (obj, prop, value, msg) {\n    new Assertion(obj, msg, assert.deepOwnPropertyVal, true)\n      .to.have.deep.own.property(prop, value);\n  };\n\n  /**\n   * ### .notDeepOwnPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` does _not_ have a direct property named by `property`\n   * with a value equal to the provided `value`. Uses a deep equality check.\n   * Inherited properties aren't checked.\n   *\n   *     assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' });\n   *     assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' });\n   *     assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' });\n   *     assert.notDeepOwnPropertyVal({}, 'toString', Object.prototype.toString);\n   *\n   * @name notDeepOwnPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notDeepOwnPropertyVal = function (obj, prop, value, msg) {\n    new Assertion(obj, msg, assert.notDeepOwnPropertyVal, true)\n      .to.not.have.deep.own.property(prop, value);\n  };\n\n  /**\n   * ### .nestedProperty(object, property, [message])\n   *\n   * Asserts that `object` has a direct or inherited property named by\n   * `property`, which can be a string using dot- and bracket-notation for\n   * nested reference.\n   *\n   *     assert.nestedProperty({ tea: { green: 'matcha' }}, 'tea.green');\n   *\n   * @name nestedProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.nestedProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg, assert.nestedProperty, true)\n      .to.have.nested.property(prop);\n  };\n\n  /**\n   * ### .notNestedProperty(object, property, [message])\n   *\n   * Asserts that `object` does _not_ have a property named by `property`, which\n   * can be a string using dot- and bracket-notation for nested reference. The\n   * property cannot exist on the object nor anywhere in its prototype chain.\n   *\n   *     assert.notNestedProperty({ tea: { green: 'matcha' }}, 'tea.oolong');\n   *\n   * @name notNestedProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notNestedProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg, assert.notNestedProperty, true)\n      .to.not.have.nested.property(prop);\n  };\n\n  /**\n   * ### .nestedPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a property named by `property` with value given\n   * by `value`. `property` can use dot- and bracket-notation for nested\n   * reference. Uses a strict equality check (===).\n   *\n   *     assert.nestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha');\n   *\n   * @name nestedPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.nestedPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.nestedPropertyVal, true)\n      .to.have.nested.property(prop, val);\n  };\n\n  /**\n   * ### .notNestedPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` does _not_ have a property named by `property` with\n   * value given by `value`. `property` can use dot- and bracket-notation for\n   * nested reference. Uses a strict equality check (===).\n   *\n   *     assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');\n   *     assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'coffee.green', 'matcha');\n   *\n   * @name notNestedPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notNestedPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.notNestedPropertyVal, true)\n      .to.not.have.nested.property(prop, val);\n  };\n\n  /**\n   * ### .deepNestedPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a property named by `property` with a value given\n   * by `value`. `property` can use dot- and bracket-notation for nested\n   * reference. Uses a deep equality check.\n   *\n   *     assert.deepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yum' });\n   *\n   * @name deepNestedPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.deepNestedPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.deepNestedPropertyVal, true)\n      .to.have.deep.nested.property(prop, val);\n  };\n\n  /**\n   * ### .notDeepNestedPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` does _not_ have a property named by `property` with\n   * value given by `value`. `property` can use dot- and bracket-notation for\n   * nested reference. Uses a deep equality check.\n   *\n   *     assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' });\n   *     assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' });\n   *     assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' });\n   *\n   * @name notDeepNestedPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notDeepNestedPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg, assert.notDeepNestedPropertyVal, true)\n      .to.not.have.deep.nested.property(prop, val);\n  }\n\n  /**\n   * ### .lengthOf(object, length, [message])\n   *\n   * Asserts that `object` has a `length` or `size` with the expected value.\n   *\n   *     assert.lengthOf([1,2,3], 3, 'array has length of 3');\n   *     assert.lengthOf('foobar', 6, 'string has length of 6');\n   *     assert.lengthOf(new Set([1,2,3]), 3, 'set has size of 3');\n   *     assert.lengthOf(new Map([['a',1],['b',2],['c',3]]), 3, 'map has size of 3');\n   *\n   * @name lengthOf\n   * @param {Mixed} object\n   * @param {Number} length\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.lengthOf = function (exp, len, msg) {\n    new Assertion(exp, msg, assert.lengthOf, true).to.have.lengthOf(len);\n  };\n\n  /**\n   * ### .hasAnyKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has at least one of the `keys` provided.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'iDontExist', 'baz']);\n   *     assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, iDontExist: 99, baz: 1337});\n   *     assert.hasAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']);\n   *     assert.hasAnyKeys(new Set([{foo: 'bar'}, 'anotherKey']), [{foo: 'bar'}, 'anotherKey']);\n   *\n   * @name hasAnyKeys\n   * @param {Mixed} object\n   * @param {Array|Object} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.hasAnyKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.hasAnyKeys, true).to.have.any.keys(keys);\n  }\n\n  /**\n   * ### .hasAllKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has all and only all of the `keys` provided.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.hasAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'bar', 'baz']);\n   *     assert.hasAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, bar: 99, baz: 1337]);\n   *     assert.hasAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']);\n   *     assert.hasAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'anotherKey']);\n   *\n   * @name hasAllKeys\n   * @param {Mixed} object\n   * @param {String[]} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.hasAllKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.hasAllKeys, true).to.have.all.keys(keys);\n  }\n\n  /**\n   * ### .containsAllKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has all of the `keys` provided but may have more keys not listed.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'baz']);\n   *     assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'bar', 'baz']);\n   *     assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, baz: 1337});\n   *     assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, bar: 99, baz: 1337});\n   *     assert.containsAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}]);\n   *     assert.containsAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']);\n   *     assert.containsAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}]);\n   *     assert.containsAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'anotherKey']);\n   *\n   * @name containsAllKeys\n   * @param {Mixed} object\n   * @param {String[]} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.containsAllKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.containsAllKeys, true)\n      .to.contain.all.keys(keys);\n  }\n\n  /**\n   * ### .doesNotHaveAnyKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has none of the `keys` provided.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.doesNotHaveAnyKeys({foo: 1, bar: 2, baz: 3}, ['one', 'two', 'example']);\n   *     assert.doesNotHaveAnyKeys({foo: 1, bar: 2, baz: 3}, {one: 1, two: 2, example: 'foo'});\n   *     assert.doesNotHaveAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{one: 'two'}, 'example']);\n   *     assert.doesNotHaveAnyKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{one: 'two'}, 'example']);\n   *\n   * @name doesNotHaveAnyKeys\n   * @param {Mixed} object\n   * @param {String[]} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotHaveAnyKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.doesNotHaveAnyKeys, true)\n      .to.not.have.any.keys(keys);\n  }\n\n  /**\n   * ### .doesNotHaveAllKeys(object, [keys], [message])\n   *\n   * Asserts that `object` does not have at least one of the `keys` provided.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.doesNotHaveAllKeys({foo: 1, bar: 2, baz: 3}, ['one', 'two', 'example']);\n   *     assert.doesNotHaveAllKeys({foo: 1, bar: 2, baz: 3}, {one: 1, two: 2, example: 'foo'});\n   *     assert.doesNotHaveAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{one: 'two'}, 'example']);\n   *     assert.doesNotHaveAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{one: 'two'}, 'example']);\n   *\n   * @name doesNotHaveAllKeys\n   * @param {Mixed} object\n   * @param {String[]} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotHaveAllKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.doesNotHaveAllKeys, true)\n      .to.not.have.all.keys(keys);\n  }\n\n  /**\n   * ### .hasAnyDeepKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has at least one of the `keys` provided.\n   * Since Sets and Maps can have objects as keys you can use this assertion to perform\n   * a deep comparison.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'});\n   *     assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), [{one: 'one'}, {two: 'two'}]);\n   *     assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]);\n   *     assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'});\n   *     assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {three: 'three'}]);\n   *     assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]);\n   *\n   * @name hasAnyDeepKeys\n   * @param {Mixed} object\n   * @param {Array|Object} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.hasAnyDeepKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.hasAnyDeepKeys, true)\n      .to.have.any.deep.keys(keys);\n  }\n\n /**\n   * ### .hasAllDeepKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has all and only all of the `keys` provided.\n   * Since Sets and Maps can have objects as keys you can use this assertion to perform\n   * a deep comparison.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne']]), {one: 'one'});\n   *     assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]);\n   *     assert.hasAllDeepKeys(new Set([{one: 'one'}]), {one: 'one'});\n   *     assert.hasAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]);\n   *\n   * @name hasAllDeepKeys\n   * @param {Mixed} object\n   * @param {Array|Object} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.hasAllDeepKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.hasAllDeepKeys, true)\n      .to.have.all.deep.keys(keys);\n  }\n\n /**\n   * ### .containsAllDeepKeys(object, [keys], [message])\n   *\n   * Asserts that `object` contains all of the `keys` provided.\n   * Since Sets and Maps can have objects as keys you can use this assertion to perform\n   * a deep comparison.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'});\n   *     assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]);\n   *     assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'});\n   *     assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]);\n   *\n   * @name containsAllDeepKeys\n   * @param {Mixed} object\n   * @param {Array|Object} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.containsAllDeepKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.containsAllDeepKeys, true)\n      .to.contain.all.deep.keys(keys);\n  }\n\n /**\n   * ### .doesNotHaveAnyDeepKeys(object, [keys], [message])\n   *\n   * Asserts that `object` has none of the `keys` provided.\n   * Since Sets and Maps can have objects as keys you can use this assertion to perform\n   * a deep comparison.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'});\n   *     assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {fifty: 'fifty'}]);\n   *     assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'});\n   *     assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{twenty: 'twenty'}, {fifty: 'fifty'}]);\n   *\n   * @name doesNotHaveAnyDeepKeys\n   * @param {Mixed} object\n   * @param {Array|Object} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotHaveAnyDeepKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.doesNotHaveAnyDeepKeys, true)\n      .to.not.have.any.deep.keys(keys);\n  }\n\n /**\n   * ### .doesNotHaveAllDeepKeys(object, [keys], [message])\n   *\n   * Asserts that `object` does not have at least one of the `keys` provided.\n   * Since Sets and Maps can have objects as keys you can use this assertion to perform\n   * a deep comparison.\n   * You can also provide a single object instead of a `keys` array and its keys\n   * will be used as the expected set of keys.\n   *\n   *     assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'});\n   *     assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {one: 'one'}]);\n   *     assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'});\n   *     assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {fifty: 'fifty'}]);\n   *\n   * @name doesNotHaveAllDeepKeys\n   * @param {Mixed} object\n   * @param {Array|Object} keys\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotHaveAllDeepKeys = function (obj, keys, msg) {\n    new Assertion(obj, msg, assert.doesNotHaveAllDeepKeys, true)\n      .to.not.have.all.deep.keys(keys);\n  }\n\n /**\n   * ### .throws(fn, [errorLike/string/regexp], [string/regexp], [message])\n   *\n   * If `errorLike` is an `Error` constructor, asserts that `fn` will throw an error that is an\n   * instance of `errorLike`.\n   * If `errorLike` is an `Error` instance, asserts that the error thrown is the same\n   * instance as `errorLike`.\n   * If `errMsgMatcher` is provided, it also asserts that the error thrown will have a\n   * message matching `errMsgMatcher`.\n   *\n   *     assert.throws(fn, 'Error thrown must have this msg');\n   *     assert.throws(fn, /Error thrown must have a msg that matches this/);\n   *     assert.throws(fn, ReferenceError);\n   *     assert.throws(fn, errorInstance);\n   *     assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg');\n   *     assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg');\n   *     assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/);\n   *     assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/);\n   *\n   * @name throws\n   * @alias throw\n   * @alias Throw\n   * @param {Function} fn\n   * @param {ErrorConstructor|Error} errorLike\n   * @param {RegExp|String} errMsgMatcher\n   * @param {String} message\n   * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.throws = function (fn, errorLike, errMsgMatcher, msg) {\n    if ('string' === typeof errorLike || errorLike instanceof RegExp) {\n      errMsgMatcher = errorLike;\n      errorLike = null;\n    }\n\n    var assertErr = new Assertion(fn, msg, assert.throws, true)\n      .to.throw(errorLike, errMsgMatcher);\n    return flag(assertErr, 'object');\n  };\n\n  /**\n   * ### .doesNotThrow(fn, [errorLike/string/regexp], [string/regexp], [message])\n   *\n   * If `errorLike` is an `Error` constructor, asserts that `fn` will _not_ throw an error that is an\n   * instance of `errorLike`.\n   * If `errorLike` is an `Error` instance, asserts that the error thrown is _not_ the same\n   * instance as `errorLike`.\n   * If `errMsgMatcher` is provided, it also asserts that the error thrown will _not_ have a\n   * message matching `errMsgMatcher`.\n   *\n   *     assert.doesNotThrow(fn, 'Any Error thrown must not have this message');\n   *     assert.doesNotThrow(fn, /Any Error thrown must not match this/);\n   *     assert.doesNotThrow(fn, Error);\n   *     assert.doesNotThrow(fn, errorInstance);\n   *     assert.doesNotThrow(fn, Error, 'Error must not have this message');\n   *     assert.doesNotThrow(fn, errorInstance, 'Error must not have this message');\n   *     assert.doesNotThrow(fn, Error, /Error must not match this/);\n   *     assert.doesNotThrow(fn, errorInstance, /Error must not match this/);\n   *\n   * @name doesNotThrow\n   * @param {Function} fn\n   * @param {ErrorConstructor} errorLike\n   * @param {RegExp|String} errMsgMatcher\n   * @param {String} message\n   * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotThrow = function (fn, errorLike, errMsgMatcher, msg) {\n    if ('string' === typeof errorLike || errorLike instanceof RegExp) {\n      errMsgMatcher = errorLike;\n      errorLike = null;\n    }\n\n    new Assertion(fn, msg, assert.doesNotThrow, true)\n      .to.not.throw(errorLike, errMsgMatcher);\n  };\n\n  /**\n   * ### .operator(val1, operator, val2, [message])\n   *\n   * Compares two values using `operator`.\n   *\n   *     assert.operator(1, '<', 2, 'everything is ok');\n   *     assert.operator(1, '>', 2, 'this will fail');\n   *\n   * @name operator\n   * @param {Mixed} val1\n   * @param {String} operator\n   * @param {Mixed} val2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.operator = function (val, operator, val2, msg) {\n    var ok;\n    switch(operator) {\n      case '==':\n        ok = val == val2;\n        break;\n      case '===':\n        ok = val === val2;\n        break;\n      case '>':\n        ok = val > val2;\n        break;\n      case '>=':\n        ok = val >= val2;\n        break;\n      case '<':\n        ok = val < val2;\n        break;\n      case '<=':\n        ok = val <= val2;\n        break;\n      case '!=':\n        ok = val != val2;\n        break;\n      case '!==':\n        ok = val !== val2;\n        break;\n      default:\n        msg = msg ? msg + ': ' : msg;\n        throw new chai.AssertionError(\n          msg + 'Invalid operator \"' + operator + '\"',\n          undefined,\n          assert.operator\n        );\n    }\n    var test = new Assertion(ok, msg, assert.operator, true);\n    test.assert(\n        true === flag(test, 'object')\n      , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2)\n      , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) );\n  };\n\n  /**\n   * ### .closeTo(actual, expected, delta, [message])\n   *\n   * Asserts that the target is equal `expected`, to within a +/- `delta` range.\n   *\n   *     assert.closeTo(1.5, 1, 0.5, 'numbers are close');\n   *\n   * @name closeTo\n   * @param {Number} actual\n   * @param {Number} expected\n   * @param {Number} delta\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.closeTo = function (act, exp, delta, msg) {\n    new Assertion(act, msg, assert.closeTo, true).to.be.closeTo(exp, delta);\n  };\n\n  /**\n   * ### .approximately(actual, expected, delta, [message])\n   *\n   * Asserts that the target is equal `expected`, to within a +/- `delta` range.\n   *\n   *     assert.approximately(1.5, 1, 0.5, 'numbers are close');\n   *\n   * @name approximately\n   * @param {Number} actual\n   * @param {Number} expected\n   * @param {Number} delta\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.approximately = function (act, exp, delta, msg) {\n    new Assertion(act, msg, assert.approximately, true)\n      .to.be.approximately(exp, delta);\n  };\n\n  /**\n   * ### .sameMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` have the same members in any order. Uses a\n   * strict equality check (===).\n   *\n   *     assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members');\n   *\n   * @name sameMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.sameMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.sameMembers, true)\n      .to.have.same.members(set2);\n  }\n\n  /**\n   * ### .notSameMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` don't have the same members in any order.\n   * Uses a strict equality check (===).\n   *\n   *     assert.notSameMembers([ 1, 2, 3 ], [ 5, 1, 3 ], 'not same members');\n   *\n   * @name notSameMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notSameMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.notSameMembers, true)\n      .to.not.have.same.members(set2);\n  }\n\n  /**\n   * ### .sameDeepMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` have the same members in any order. Uses a\n   * deep equality check.\n   *\n   *     assert.sameDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members');\n   *\n   * @name sameDeepMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.sameDeepMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.sameDeepMembers, true)\n      .to.have.same.deep.members(set2);\n  }\n\n  /**\n   * ### .notSameDeepMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` don't have the same members in any order.\n   * Uses a deep equality check.\n   *\n   *     assert.notSameDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [{ b: 2 }, { a: 1 }, { f: 5 }], 'not same deep members');\n   *\n   * @name notSameDeepMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notSameDeepMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.notSameDeepMembers, true)\n      .to.not.have.same.deep.members(set2);\n  }\n\n  /**\n   * ### .sameOrderedMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` have the same members in the same order.\n   * Uses a strict equality check (===).\n   *\n   *     assert.sameOrderedMembers([ 1, 2, 3 ], [ 1, 2, 3 ], 'same ordered members');\n   *\n   * @name sameOrderedMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.sameOrderedMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.sameOrderedMembers, true)\n      .to.have.same.ordered.members(set2);\n  }\n\n  /**\n   * ### .notSameOrderedMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` don't have the same members in the same\n   * order. Uses a strict equality check (===).\n   *\n   *     assert.notSameOrderedMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'not same ordered members');\n   *\n   * @name notSameOrderedMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notSameOrderedMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.notSameOrderedMembers, true)\n      .to.not.have.same.ordered.members(set2);\n  }\n\n  /**\n   * ### .sameDeepOrderedMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` have the same members in the same order.\n   * Uses a deep equality check.\n   *\n   *     assert.sameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 }, { c: 3 } ], 'same deep ordered members');\n   *\n   * @name sameDeepOrderedMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.sameDeepOrderedMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.sameDeepOrderedMembers, true)\n      .to.have.same.deep.ordered.members(set2);\n  }\n\n  /**\n   * ### .notSameDeepOrderedMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` don't have the same members in the same\n   * order. Uses a deep equality check.\n   *\n   *     assert.notSameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 }, { z: 5 } ], 'not same deep ordered members');\n   *     assert.notSameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 }, { c: 3 } ], 'not same deep ordered members');\n   *\n   * @name notSameDeepOrderedMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notSameDeepOrderedMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg, assert.notSameDeepOrderedMembers, true)\n      .to.not.have.same.deep.ordered.members(set2);\n  }\n\n  /**\n   * ### .includeMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` is included in `superset` in any order. Uses a\n   * strict equality check (===). Duplicates are ignored.\n   *\n   *     assert.includeMembers([ 1, 2, 3 ], [ 2, 1, 2 ], 'include members');\n   *\n   * @name includeMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.includeMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.includeMembers, true)\n      .to.include.members(subset);\n  }\n\n  /**\n   * ### .notIncludeMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` isn't included in `superset` in any order. Uses a\n   * strict equality check (===). Duplicates are ignored.\n   *\n   *     assert.notIncludeMembers([ 1, 2, 3 ], [ 5, 1 ], 'not include members');\n   *\n   * @name notIncludeMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notIncludeMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.notIncludeMembers, true)\n      .to.not.include.members(subset);\n  }\n\n  /**\n   * ### .includeDeepMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` is included in `superset` in any order. Uses a deep\n   * equality check. Duplicates are ignored.\n   *\n   *     assert.includeDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 }, { b: 2 } ], 'include deep members');\n   *\n   * @name includeDeepMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.includeDeepMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.includeDeepMembers, true)\n      .to.include.deep.members(subset);\n  }\n\n  /**\n   * ### .notIncludeDeepMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` isn't included in `superset` in any order. Uses a\n   * deep equality check. Duplicates are ignored.\n   *\n   *     assert.notIncludeDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { f: 5 } ], 'not include deep members');\n   *\n   * @name notIncludeDeepMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notIncludeDeepMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.notIncludeDeepMembers, true)\n      .to.not.include.deep.members(subset);\n  }\n\n  /**\n   * ### .includeOrderedMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` is included in `superset` in the same order\n   * beginning with the first element in `superset`. Uses a strict equality\n   * check (===).\n   *\n   *     assert.includeOrderedMembers([ 1, 2, 3 ], [ 1, 2 ], 'include ordered members');\n   *\n   * @name includeOrderedMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.includeOrderedMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.includeOrderedMembers, true)\n      .to.include.ordered.members(subset);\n  }\n\n  /**\n   * ### .notIncludeOrderedMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` isn't included in `superset` in the same order\n   * beginning with the first element in `superset`. Uses a strict equality\n   * check (===).\n   *\n   *     assert.notIncludeOrderedMembers([ 1, 2, 3 ], [ 2, 1 ], 'not include ordered members');\n   *     assert.notIncludeOrderedMembers([ 1, 2, 3 ], [ 2, 3 ], 'not include ordered members');\n   *\n   * @name notIncludeOrderedMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notIncludeOrderedMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.notIncludeOrderedMembers, true)\n      .to.not.include.ordered.members(subset);\n  }\n\n  /**\n   * ### .includeDeepOrderedMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` is included in `superset` in the same order\n   * beginning with the first element in `superset`. Uses a deep equality\n   * check.\n   *\n   *     assert.includeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 } ], 'include deep ordered members');\n   *\n   * @name includeDeepOrderedMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.includeDeepOrderedMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.includeDeepOrderedMembers, true)\n      .to.include.deep.ordered.members(subset);\n  }\n\n  /**\n   * ### .notIncludeDeepOrderedMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` isn't included in `superset` in the same order\n   * beginning with the first element in `superset`. Uses a deep equality\n   * check.\n   *\n   *     assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { f: 5 } ], 'not include deep ordered members');\n   *     assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 } ], 'not include deep ordered members');\n   *     assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { c: 3 } ], 'not include deep ordered members');\n   *\n   * @name notIncludeDeepOrderedMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.notIncludeDeepOrderedMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg, assert.notIncludeDeepOrderedMembers, true)\n      .to.not.include.deep.ordered.members(subset);\n  }\n\n  /**\n   * ### .oneOf(inList, list, [message])\n   *\n   * Asserts that non-object, non-array value `inList` appears in the flat array `list`.\n   *\n   *     assert.oneOf(1, [ 2, 1 ], 'Not found in list');\n   *\n   * @name oneOf\n   * @param {*} inList\n   * @param {Array<*>} list\n   * @param {String} message\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.oneOf = function (inList, list, msg) {\n    new Assertion(inList, msg, assert.oneOf, true).to.be.oneOf(list);\n  }\n\n  /**\n   * ### .changes(function, object, property, [message])\n   *\n   * Asserts that a function changes the value of a property.\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 22 };\n   *     assert.changes(fn, obj, 'val');\n   *\n   * @name changes\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.changes = function (fn, obj, prop, msg) {\n    if (arguments.length === 3 && typeof obj === 'function') {\n      msg = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.changes, true).to.change(obj, prop);\n  }\n\n   /**\n   * ### .changesBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function changes the value of a property by an amount (delta).\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val += 2 };\n   *     assert.changesBy(fn, obj, 'val', 2);\n   *\n   * @name changesBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.changesBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.changesBy, true)\n      .to.change(obj, prop).by(delta);\n  }\n\n   /**\n   * ### .doesNotChange(function, object, property, [message])\n   *\n   * Asserts that a function does not change the value of a property.\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { console.log('foo'); };\n   *     assert.doesNotChange(fn, obj, 'val');\n   *\n   * @name doesNotChange\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotChange = function (fn, obj, prop, msg) {\n    if (arguments.length === 3 && typeof obj === 'function') {\n      msg = prop;\n      prop = null;\n    }\n\n    return new Assertion(fn, msg, assert.doesNotChange, true)\n      .to.not.change(obj, prop);\n  }\n\n  /**\n   * ### .changesButNotBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function does not change the value of a property or of a function's return value by an amount (delta)\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val += 10 };\n   *     assert.changesButNotBy(fn, obj, 'val', 5);\n   *\n   * @name changesButNotBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.changesButNotBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.changesButNotBy, true)\n      .to.change(obj, prop).but.not.by(delta);\n  }\n\n  /**\n   * ### .increases(function, object, property, [message])\n   *\n   * Asserts that a function increases a numeric object property.\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 13 };\n   *     assert.increases(fn, obj, 'val');\n   *\n   * @name increases\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.increases = function (fn, obj, prop, msg) {\n    if (arguments.length === 3 && typeof obj === 'function') {\n      msg = prop;\n      prop = null;\n    }\n\n    return new Assertion(fn, msg, assert.increases, true)\n      .to.increase(obj, prop);\n  }\n\n  /**\n   * ### .increasesBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function increases a numeric object property or a function's return value by an amount (delta).\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val += 10 };\n   *     assert.increasesBy(fn, obj, 'val', 10);\n   *\n   * @name increasesBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.increasesBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.increasesBy, true)\n      .to.increase(obj, prop).by(delta);\n  }\n\n  /**\n   * ### .doesNotIncrease(function, object, property, [message])\n   *\n   * Asserts that a function does not increase a numeric object property.\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 8 };\n   *     assert.doesNotIncrease(fn, obj, 'val');\n   *\n   * @name doesNotIncrease\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotIncrease = function (fn, obj, prop, msg) {\n    if (arguments.length === 3 && typeof obj === 'function') {\n      msg = prop;\n      prop = null;\n    }\n\n    return new Assertion(fn, msg, assert.doesNotIncrease, true)\n      .to.not.increase(obj, prop);\n  }\n\n  /**\n   * ### .increasesButNotBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function does not increase a numeric object property or function's return value by an amount (delta).\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 15 };\n   *     assert.increasesButNotBy(fn, obj, 'val', 10);\n   *\n   * @name increasesButNotBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.increasesButNotBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.increasesButNotBy, true)\n      .to.increase(obj, prop).but.not.by(delta);\n  }\n\n  /**\n   * ### .decreases(function, object, property, [message])\n   *\n   * Asserts that a function decreases a numeric object property.\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 5 };\n   *     assert.decreases(fn, obj, 'val');\n   *\n   * @name decreases\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.decreases = function (fn, obj, prop, msg) {\n    if (arguments.length === 3 && typeof obj === 'function') {\n      msg = prop;\n      prop = null;\n    }\n\n    return new Assertion(fn, msg, assert.decreases, true)\n      .to.decrease(obj, prop);\n  }\n\n  /**\n   * ### .decreasesBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function decreases a numeric object property or a function's return value by an amount (delta)\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val -= 5 };\n   *     assert.decreasesBy(fn, obj, 'val', 5);\n   *\n   * @name decreasesBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.decreasesBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.decreasesBy, true)\n      .to.decrease(obj, prop).by(delta);\n  }\n\n  /**\n   * ### .doesNotDecrease(function, object, property, [message])\n   *\n   * Asserts that a function does not decreases a numeric object property.\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 15 };\n   *     assert.doesNotDecrease(fn, obj, 'val');\n   *\n   * @name doesNotDecrease\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotDecrease = function (fn, obj, prop, msg) {\n    if (arguments.length === 3 && typeof obj === 'function') {\n      msg = prop;\n      prop = null;\n    }\n\n    return new Assertion(fn, msg, assert.doesNotDecrease, true)\n      .to.not.decrease(obj, prop);\n  }\n\n  /**\n   * ### .doesNotDecreaseBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta)\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 5 };\n   *     assert.doesNotDecreaseBy(fn, obj, 'val', 1);\n   *\n   * @name doesNotDecreaseBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.doesNotDecreaseBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    return new Assertion(fn, msg, assert.doesNotDecreaseBy, true)\n      .to.not.decrease(obj, prop).by(delta);\n  }\n\n  /**\n   * ### .decreasesButNotBy(function, object, property, delta, [message])\n   *\n   * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta)\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 5 };\n   *     assert.decreasesButNotBy(fn, obj, 'val', 1);\n   *\n   * @name decreasesButNotBy\n   * @param {Function} modifier function\n   * @param {Object} object or getter function\n   * @param {String} property name _optional_\n   * @param {Number} change amount (delta)\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.decreasesButNotBy = function (fn, obj, prop, delta, msg) {\n    if (arguments.length === 4 && typeof obj === 'function') {\n      var tmpMsg = delta;\n      delta = prop;\n      msg = tmpMsg;\n    } else if (arguments.length === 3) {\n      delta = prop;\n      prop = null;\n    }\n\n    new Assertion(fn, msg, assert.decreasesButNotBy, true)\n      .to.decrease(obj, prop).but.not.by(delta);\n  }\n\n  /*!\n   * ### .ifError(object)\n   *\n   * Asserts if value is not a false value, and throws if it is a true value.\n   * This is added to allow for chai to be a drop-in replacement for Node's\n   * assert class.\n   *\n   *     var err = new Error('I am a custom error');\n   *     assert.ifError(err); // Rethrows err!\n   *\n   * @name ifError\n   * @param {Object} object\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.ifError = function (val) {\n    if (val) {\n      throw(val);\n    }\n  };\n\n  /**\n   * ### .isExtensible(object)\n   *\n   * Asserts that `object` is extensible (can have new properties added to it).\n   *\n   *     assert.isExtensible({});\n   *\n   * @name isExtensible\n   * @alias extensible\n   * @param {Object} object\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isExtensible = function (obj, msg) {\n    new Assertion(obj, msg, assert.isExtensible, true).to.be.extensible;\n  };\n\n  /**\n   * ### .isNotExtensible(object)\n   *\n   * Asserts that `object` is _not_ extensible.\n   *\n   *     var nonExtensibleObject = Object.preventExtensions({});\n   *     var sealedObject = Object.seal({});\n   *     var frozenObject = Object.freeze({});\n   *\n   *     assert.isNotExtensible(nonExtensibleObject);\n   *     assert.isNotExtensible(sealedObject);\n   *     assert.isNotExtensible(frozenObject);\n   *\n   * @name isNotExtensible\n   * @alias notExtensible\n   * @param {Object} object\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotExtensible = function (obj, msg) {\n    new Assertion(obj, msg, assert.isNotExtensible, true).to.not.be.extensible;\n  };\n\n  /**\n   * ### .isSealed(object)\n   *\n   * Asserts that `object` is sealed (cannot have new properties added to it\n   * and its existing properties cannot be removed).\n   *\n   *     var sealedObject = Object.seal({});\n   *     var frozenObject = Object.seal({});\n   *\n   *     assert.isSealed(sealedObject);\n   *     assert.isSealed(frozenObject);\n   *\n   * @name isSealed\n   * @alias sealed\n   * @param {Object} object\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isSealed = function (obj, msg) {\n    new Assertion(obj, msg, assert.isSealed, true).to.be.sealed;\n  };\n\n  /**\n   * ### .isNotSealed(object)\n   *\n   * Asserts that `object` is _not_ sealed.\n   *\n   *     assert.isNotSealed({});\n   *\n   * @name isNotSealed\n   * @alias notSealed\n   * @param {Object} object\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotSealed = function (obj, msg) {\n    new Assertion(obj, msg, assert.isNotSealed, true).to.not.be.sealed;\n  };\n\n  /**\n   * ### .isFrozen(object)\n   *\n   * Asserts that `object` is frozen (cannot have new properties added to it\n   * and its existing properties cannot be modified).\n   *\n   *     var frozenObject = Object.freeze({});\n   *     assert.frozen(frozenObject);\n   *\n   * @name isFrozen\n   * @alias frozen\n   * @param {Object} object\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isFrozen = function (obj, msg) {\n    new Assertion(obj, msg, assert.isFrozen, true).to.be.frozen;\n  };\n\n  /**\n   * ### .isNotFrozen(object)\n   *\n   * Asserts that `object` is _not_ frozen.\n   *\n   *     assert.isNotFrozen({});\n   *\n   * @name isNotFrozen\n   * @alias notFrozen\n   * @param {Object} object\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotFrozen = function (obj, msg) {\n    new Assertion(obj, msg, assert.isNotFrozen, true).to.not.be.frozen;\n  };\n\n  /**\n   * ### .isEmpty(target)\n   *\n   * Asserts that the target does not contain any values.\n   * For arrays and strings, it checks the `length` property.\n   * For `Map` and `Set` instances, it checks the `size` property.\n   * For non-function objects, it gets the count of own\n   * enumerable string keys.\n   *\n   *     assert.isEmpty([]);\n   *     assert.isEmpty('');\n   *     assert.isEmpty(new Map);\n   *     assert.isEmpty({});\n   *\n   * @name isEmpty\n   * @alias empty\n   * @param {Object|Array|String|Map|Set} target\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isEmpty = function(val, msg) {\n    new Assertion(val, msg, assert.isEmpty, true).to.be.empty;\n  };\n\n  /**\n   * ### .isNotEmpty(target)\n   *\n   * Asserts that the target contains values.\n   * For arrays and strings, it checks the `length` property.\n   * For `Map` and `Set` instances, it checks the `size` property.\n   * For non-function objects, it gets the count of own\n   * enumerable string keys.\n   *\n   *     assert.isNotEmpty([1, 2]);\n   *     assert.isNotEmpty('34');\n   *     assert.isNotEmpty(new Set([5, 6]));\n   *     assert.isNotEmpty({ key: 7 });\n   *\n   * @name isNotEmpty\n   * @alias notEmpty\n   * @param {Object|Array|String|Map|Set} target\n   * @param {String} message _optional_\n   * @namespace Assert\n   * @api public\n   */\n\n  assert.isNotEmpty = function(val, msg) {\n    new Assertion(val, msg, assert.isNotEmpty, true).to.not.be.empty;\n  };\n\n  /*!\n   * Aliases.\n   */\n\n  (function alias(name, as){\n    assert[as] = assert[name];\n    return alias;\n  })\n  ('isOk', 'ok')\n  ('isNotOk', 'notOk')\n  ('throws', 'throw')\n  ('throws', 'Throw')\n  ('isExtensible', 'extensible')\n  ('isNotExtensible', 'notExtensible')\n  ('isSealed', 'sealed')\n  ('isNotSealed', 'notSealed')\n  ('isFrozen', 'frozen')\n  ('isNotFrozen', 'notFrozen')\n  ('isEmpty', 'empty')\n  ('isNotEmpty', 'notEmpty');\n};\n\n},{}],7:[function(require,module,exports){\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, util) {\n  chai.expect = function (val, message) {\n    return new chai.Assertion(val, message);\n  };\n\n  /**\n   * ### .fail([message])\n   * ### .fail(actual, expected, [message], [operator])\n   *\n   * Throw a failure.\n   *\n   *     expect.fail();\n   *     expect.fail(\"custom error message\");\n   *     expect.fail(1, 2);\n   *     expect.fail(1, 2, \"custom error message\");\n   *     expect.fail(1, 2, \"custom error message\", \">\");\n   *     expect.fail(1, 2, undefined, \">\");\n   *\n   * @name fail\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @param {String} operator\n   * @namespace BDD\n   * @api public\n   */\n\n  chai.expect.fail = function (actual, expected, message, operator) {\n    if (arguments.length < 2) {\n        message = actual;\n        actual = undefined;\n    }\n\n    message = message || 'expect.fail()';\n    throw new chai.AssertionError(message, {\n        actual: actual\n      , expected: expected\n      , operator: operator\n    }, chai.expect.fail);\n  };\n};\n\n},{}],8:[function(require,module,exports){\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, util) {\n  var Assertion = chai.Assertion;\n\n  function loadShould () {\n    // explicitly define this method as function as to have it's name to include as `ssfi`\n    function shouldGetter() {\n      if (this instanceof String\n          || this instanceof Number\n          || this instanceof Boolean\n          || typeof Symbol === 'function' && this instanceof Symbol\n          || typeof BigInt === 'function' && this instanceof BigInt) {\n        return new Assertion(this.valueOf(), null, shouldGetter);\n      }\n      return new Assertion(this, null, shouldGetter);\n    }\n    function shouldSetter(value) {\n      // See https://github.com/chaijs/chai/issues/86: this makes\n      // `whatever.should = someValue` actually set `someValue`, which is\n      // especially useful for `global.should = require('chai').should()`.\n      //\n      // Note that we have to use [[DefineProperty]] instead of [[Put]]\n      // since otherwise we would trigger this very setter!\n      Object.defineProperty(this, 'should', {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    }\n    // modify Object.prototype to have `should`\n    Object.defineProperty(Object.prototype, 'should', {\n      set: shouldSetter\n      , get: shouldGetter\n      , configurable: true\n    });\n\n    var should = {};\n\n    /**\n     * ### .fail([message])\n     * ### .fail(actual, expected, [message], [operator])\n     *\n     * Throw a failure.\n     *\n     *     should.fail();\n     *     should.fail(\"custom error message\");\n     *     should.fail(1, 2);\n     *     should.fail(1, 2, \"custom error message\");\n     *     should.fail(1, 2, \"custom error message\", \">\");\n     *     should.fail(1, 2, undefined, \">\");\n     *\n     *\n     * @name fail\n     * @param {Mixed} actual\n     * @param {Mixed} expected\n     * @param {String} message\n     * @param {String} operator\n     * @namespace BDD\n     * @api public\n     */\n\n    should.fail = function (actual, expected, message, operator) {\n      if (arguments.length < 2) {\n          message = actual;\n          actual = undefined;\n      }\n\n      message = message || 'should.fail()';\n      throw new chai.AssertionError(message, {\n          actual: actual\n        , expected: expected\n        , operator: operator\n      }, should.fail);\n    };\n\n    /**\n     * ### .equal(actual, expected, [message])\n     *\n     * Asserts non-strict equality (`==`) of `actual` and `expected`.\n     *\n     *     should.equal(3, '3', '== coerces values to strings');\n     *\n     * @name equal\n     * @param {Mixed} actual\n     * @param {Mixed} expected\n     * @param {String} message\n     * @namespace Should\n     * @api public\n     */\n\n    should.equal = function (val1, val2, msg) {\n      new Assertion(val1, msg).to.equal(val2);\n    };\n\n    /**\n     * ### .throw(function, [constructor/string/regexp], [string/regexp], [message])\n     *\n     * Asserts that `function` will throw an error that is an instance of\n     * `constructor`, or alternately that it will throw an error with message\n     * matching `regexp`.\n     *\n     *     should.throw(fn, 'function throws a reference error');\n     *     should.throw(fn, /function throws a reference error/);\n     *     should.throw(fn, ReferenceError);\n     *     should.throw(fn, ReferenceError, 'function throws a reference error');\n     *     should.throw(fn, ReferenceError, /function throws a reference error/);\n     *\n     * @name throw\n     * @alias Throw\n     * @param {Function} function\n     * @param {ErrorConstructor} constructor\n     * @param {RegExp} regexp\n     * @param {String} message\n     * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n     * @namespace Should\n     * @api public\n     */\n\n    should.Throw = function (fn, errt, errs, msg) {\n      new Assertion(fn, msg).to.Throw(errt, errs);\n    };\n\n    /**\n     * ### .exist\n     *\n     * Asserts that the target is neither `null` nor `undefined`.\n     *\n     *     var foo = 'hi';\n     *\n     *     should.exist(foo, 'foo exists');\n     *\n     * @name exist\n     * @namespace Should\n     * @api public\n     */\n\n    should.exist = function (val, msg) {\n      new Assertion(val, msg).to.exist;\n    }\n\n    // negation\n    should.not = {}\n\n    /**\n     * ### .not.equal(actual, expected, [message])\n     *\n     * Asserts non-strict inequality (`!=`) of `actual` and `expected`.\n     *\n     *     should.not.equal(3, 4, 'these numbers are not equal');\n     *\n     * @name not.equal\n     * @param {Mixed} actual\n     * @param {Mixed} expected\n     * @param {String} message\n     * @namespace Should\n     * @api public\n     */\n\n    should.not.equal = function (val1, val2, msg) {\n      new Assertion(val1, msg).to.not.equal(val2);\n    };\n\n    /**\n     * ### .throw(function, [constructor/regexp], [message])\n     *\n     * Asserts that `function` will _not_ throw an error that is an instance of\n     * `constructor`, or alternately that it will not throw an error with message\n     * matching `regexp`.\n     *\n     *     should.not.throw(fn, Error, 'function does not throw');\n     *\n     * @name not.throw\n     * @alias not.Throw\n     * @param {Function} function\n     * @param {ErrorConstructor} constructor\n     * @param {RegExp} regexp\n     * @param {String} message\n     * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n     * @namespace Should\n     * @api public\n     */\n\n    should.not.Throw = function (fn, errt, errs, msg) {\n      new Assertion(fn, msg).to.not.Throw(errt, errs);\n    };\n\n    /**\n     * ### .not.exist\n     *\n     * Asserts that the target is neither `null` nor `undefined`.\n     *\n     *     var bar = null;\n     *\n     *     should.not.exist(bar, 'bar does not exist');\n     *\n     * @name not.exist\n     * @namespace Should\n     * @api public\n     */\n\n    should.not.exist = function (val, msg) {\n      new Assertion(val, msg).to.not.exist;\n    }\n\n    should['throw'] = should['Throw'];\n    should.not['throw'] = should.not['Throw'];\n\n    return should;\n  };\n\n  chai.should = loadShould;\n  chai.Should = loadShould;\n};\n\n},{}],9:[function(require,module,exports){\n/*!\n * Chai - addChainingMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar addLengthGuard = require('./addLengthGuard');\nvar chai = require('../../chai');\nvar flag = require('./flag');\nvar proxify = require('./proxify');\nvar transferFlags = require('./transferFlags');\n\n/*!\n * Module variables\n */\n\n// Check whether `Object.setPrototypeOf` is supported\nvar canSetPrototype = typeof Object.setPrototypeOf === 'function';\n\n// Without `Object.setPrototypeOf` support, this module will need to add properties to a function.\n// However, some of functions' own props are not configurable and should be skipped.\nvar testFn = function() {};\nvar excludeNames = Object.getOwnPropertyNames(testFn).filter(function(name) {\n  var propDesc = Object.getOwnPropertyDescriptor(testFn, name);\n\n  // Note: PhantomJS 1.x includes `callee` as one of `testFn`'s own properties,\n  // but then returns `undefined` as the property descriptor for `callee`. As a\n  // workaround, we perform an otherwise unnecessary type-check for `propDesc`,\n  // and then filter it out if it's not an object as it should be.\n  if (typeof propDesc !== 'object')\n    return true;\n\n  return !propDesc.configurable;\n});\n\n// Cache `Function` properties\nvar call  = Function.prototype.call,\n    apply = Function.prototype.apply;\n\n/**\n * ### .addChainableMethod(ctx, name, method, chainingBehavior)\n *\n * Adds a method to an object, such that the method can also be chained.\n *\n *     utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) {\n *       var obj = utils.flag(this, 'object');\n *       new chai.Assertion(obj).to.be.equal(str);\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.addChainableMethod('foo', fn, chainingBehavior);\n *\n * The result can then be used as both a method assertion, executing both `method` and\n * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`.\n *\n *     expect(fooStr).to.be.foo('bar');\n *     expect(fooStr).to.be.foo.equal('foo');\n *\n * @param {Object} ctx object to which the method is added\n * @param {String} name of method to add\n * @param {Function} method function to be used for `name`, when called\n * @param {Function} chainingBehavior function to be called every time the property is accessed\n * @namespace Utils\n * @name addChainableMethod\n * @api public\n */\n\nmodule.exports = function addChainableMethod(ctx, name, method, chainingBehavior) {\n  if (typeof chainingBehavior !== 'function') {\n    chainingBehavior = function () { };\n  }\n\n  var chainableBehavior = {\n      method: method\n    , chainingBehavior: chainingBehavior\n  };\n\n  // save the methods so we can overwrite them later, if we need to.\n  if (!ctx.__methods) {\n    ctx.__methods = {};\n  }\n  ctx.__methods[name] = chainableBehavior;\n\n  Object.defineProperty(ctx, name,\n    { get: function chainableMethodGetter() {\n        chainableBehavior.chainingBehavior.call(this);\n\n        var chainableMethodWrapper = function () {\n          // Setting the `ssfi` flag to `chainableMethodWrapper` causes this\n          // function to be the starting point for removing implementation\n          // frames from the stack trace of a failed assertion.\n          //\n          // However, we only want to use this function as the starting point if\n          // the `lockSsfi` flag isn't set.\n          //\n          // If the `lockSsfi` flag is set, then this assertion is being\n          // invoked from inside of another assertion. In this case, the `ssfi`\n          // flag has already been set by the outer assertion.\n          //\n          // Note that overwriting a chainable method merely replaces the saved\n          // methods in `ctx.__methods` instead of completely replacing the\n          // overwritten assertion. Therefore, an overwriting assertion won't\n          // set the `ssfi` or `lockSsfi` flags.\n          if (!flag(this, 'lockSsfi')) {\n            flag(this, 'ssfi', chainableMethodWrapper);\n          }\n\n          var result = chainableBehavior.method.apply(this, arguments);\n          if (result !== undefined) {\n            return result;\n          }\n\n          var newAssertion = new chai.Assertion();\n          transferFlags(this, newAssertion);\n          return newAssertion;\n        };\n\n        addLengthGuard(chainableMethodWrapper, name, true);\n\n        // Use `Object.setPrototypeOf` if available\n        if (canSetPrototype) {\n          // Inherit all properties from the object by replacing the `Function` prototype\n          var prototype = Object.create(this);\n          // Restore the `call` and `apply` methods from `Function`\n          prototype.call = call;\n          prototype.apply = apply;\n          Object.setPrototypeOf(chainableMethodWrapper, prototype);\n        }\n        // Otherwise, redefine all properties (slow!)\n        else {\n          var asserterNames = Object.getOwnPropertyNames(ctx);\n          asserterNames.forEach(function (asserterName) {\n            if (excludeNames.indexOf(asserterName) !== -1) {\n              return;\n            }\n\n            var pd = Object.getOwnPropertyDescriptor(ctx, asserterName);\n            Object.defineProperty(chainableMethodWrapper, asserterName, pd);\n          });\n        }\n\n        transferFlags(this, chainableMethodWrapper);\n        return proxify(chainableMethodWrapper);\n      }\n    , configurable: true\n  });\n};\n\n},{\"../../chai\":2,\"./addLengthGuard\":10,\"./flag\":15,\"./proxify\":30,\"./transferFlags\":32}],10:[function(require,module,exports){\nvar fnLengthDesc = Object.getOwnPropertyDescriptor(function () {}, 'length');\n\n/*!\n * Chai - addLengthGuard utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .addLengthGuard(fn, assertionName, isChainable)\n *\n * Define `length` as a getter on the given uninvoked method assertion. The\n * getter acts as a guard against chaining `length` directly off of an uninvoked\n * method assertion, which is a problem because it references `function`'s\n * built-in `length` property instead of Chai's `length` assertion. When the\n * getter catches the user making this mistake, it throws an error with a\n * helpful message.\n *\n * There are two ways in which this mistake can be made. The first way is by\n * chaining the `length` assertion directly off of an uninvoked chainable\n * method. In this case, Chai suggests that the user use `lengthOf` instead. The\n * second way is by chaining the `length` assertion directly off of an uninvoked\n * non-chainable method. Non-chainable methods must be invoked prior to\n * chaining. In this case, Chai suggests that the user consult the docs for the\n * given assertion.\n *\n * If the `length` property of functions is unconfigurable, then return `fn`\n * without modification.\n *\n * Note that in ES6, the function's `length` property is configurable, so once\n * support for legacy environments is dropped, Chai's `length` property can\n * replace the built-in function's `length` property, and this length guard will\n * no longer be necessary. In the mean time, maintaining consistency across all\n * environments is the priority.\n *\n * @param {Function} fn\n * @param {String} assertionName\n * @param {Boolean} isChainable\n * @namespace Utils\n * @name addLengthGuard\n */\n\nmodule.exports = function addLengthGuard (fn, assertionName, isChainable) {\n  if (!fnLengthDesc.configurable) return fn;\n\n  Object.defineProperty(fn, 'length', {\n    get: function () {\n      if (isChainable) {\n        throw Error('Invalid Chai property: ' + assertionName + '.length. Due' +\n          ' to a compatibility issue, \"length\" cannot directly follow \"' +\n          assertionName + '\". Use \"' + assertionName + '.lengthOf\" instead.');\n      }\n\n      throw Error('Invalid Chai property: ' + assertionName + '.length. See' +\n        ' docs for proper usage of \"' + assertionName + '\".');\n    }\n  });\n\n  return fn;\n};\n\n},{}],11:[function(require,module,exports){\n/*!\n * Chai - addMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar addLengthGuard = require('./addLengthGuard');\nvar chai = require('../../chai');\nvar flag = require('./flag');\nvar proxify = require('./proxify');\nvar transferFlags = require('./transferFlags');\n\n/**\n * ### .addMethod(ctx, name, method)\n *\n * Adds a method to the prototype of an object.\n *\n *     utils.addMethod(chai.Assertion.prototype, 'foo', function (str) {\n *       var obj = utils.flag(this, 'object');\n *       new chai.Assertion(obj).to.be.equal(str);\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.addMethod('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(fooStr).to.be.foo('bar');\n *\n * @param {Object} ctx object to which the method is added\n * @param {String} name of method to add\n * @param {Function} method function to be used for name\n * @namespace Utils\n * @name addMethod\n * @api public\n */\n\nmodule.exports = function addMethod(ctx, name, method) {\n  var methodWrapper = function () {\n    // Setting the `ssfi` flag to `methodWrapper` causes this function to be the\n    // starting point for removing implementation frames from the stack trace of\n    // a failed assertion.\n    //\n    // However, we only want to use this function as the starting point if the\n    // `lockSsfi` flag isn't set.\n    //\n    // If the `lockSsfi` flag is set, then either this assertion has been\n    // overwritten by another assertion, or this assertion is being invoked from\n    // inside of another assertion. In the first case, the `ssfi` flag has\n    // already been set by the overwriting assertion. In the second case, the\n    // `ssfi` flag has already been set by the outer assertion.\n    if (!flag(this, 'lockSsfi')) {\n      flag(this, 'ssfi', methodWrapper);\n    }\n\n    var result = method.apply(this, arguments);\n    if (result !== undefined)\n      return result;\n\n    var newAssertion = new chai.Assertion();\n    transferFlags(this, newAssertion);\n    return newAssertion;\n  };\n\n  addLengthGuard(methodWrapper, name, false);\n  ctx[name] = proxify(methodWrapper, name);\n};\n\n},{\"../../chai\":2,\"./addLengthGuard\":10,\"./flag\":15,\"./proxify\":30,\"./transferFlags\":32}],12:[function(require,module,exports){\n/*!\n * Chai - addProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar chai = require('../../chai');\nvar flag = require('./flag');\nvar isProxyEnabled = require('./isProxyEnabled');\nvar transferFlags = require('./transferFlags');\n\n/**\n * ### .addProperty(ctx, name, getter)\n *\n * Adds a property to the prototype of an object.\n *\n *     utils.addProperty(chai.Assertion.prototype, 'foo', function () {\n *       var obj = utils.flag(this, 'object');\n *       new chai.Assertion(obj).to.be.instanceof(Foo);\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.addProperty('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.be.foo;\n *\n * @param {Object} ctx object to which the property is added\n * @param {String} name of property to add\n * @param {Function} getter function to be used for name\n * @namespace Utils\n * @name addProperty\n * @api public\n */\n\nmodule.exports = function addProperty(ctx, name, getter) {\n  getter = getter === undefined ? function () {} : getter;\n\n  Object.defineProperty(ctx, name,\n    { get: function propertyGetter() {\n        // Setting the `ssfi` flag to `propertyGetter` causes this function to\n        // be the starting point for removing implementation frames from the\n        // stack trace of a failed assertion.\n        //\n        // However, we only want to use this function as the starting point if\n        // the `lockSsfi` flag isn't set and proxy protection is disabled.\n        //\n        // If the `lockSsfi` flag is set, then either this assertion has been\n        // overwritten by another assertion, or this assertion is being invoked\n        // from inside of another assertion. In the first case, the `ssfi` flag\n        // has already been set by the overwriting assertion. In the second\n        // case, the `ssfi` flag has already been set by the outer assertion.\n        //\n        // If proxy protection is enabled, then the `ssfi` flag has already been\n        // set by the proxy getter.\n        if (!isProxyEnabled() && !flag(this, 'lockSsfi')) {\n          flag(this, 'ssfi', propertyGetter);\n        }\n\n        var result = getter.call(this);\n        if (result !== undefined)\n          return result;\n\n        var newAssertion = new chai.Assertion();\n        transferFlags(this, newAssertion);\n        return newAssertion;\n      }\n    , configurable: true\n  });\n};\n\n},{\"../../chai\":2,\"./flag\":15,\"./isProxyEnabled\":25,\"./transferFlags\":32}],13:[function(require,module,exports){\n/*!\n * Chai - compareByInspect utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar inspect = require('./inspect');\n\n/**\n * ### .compareByInspect(mixed, mixed)\n *\n * To be used as a compareFunction with Array.prototype.sort. Compares elements\n * using inspect instead of default behavior of using toString so that Symbols\n * and objects with irregular/missing toString can still be sorted without a\n * TypeError.\n *\n * @param {Mixed} first element to compare\n * @param {Mixed} second element to compare\n * @returns {Number} -1 if 'a' should come before 'b'; otherwise 1\n * @name compareByInspect\n * @namespace Utils\n * @api public\n */\n\nmodule.exports = function compareByInspect(a, b) {\n  return inspect(a) < inspect(b) ? -1 : 1;\n};\n\n},{\"./inspect\":23}],14:[function(require,module,exports){\n/*!\n * Chai - expectTypes utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .expectTypes(obj, types)\n *\n * Ensures that the object being tested against is of a valid type.\n *\n *     utils.expectTypes(this, ['array', 'object', 'string']);\n *\n * @param {Mixed} obj constructed Assertion\n * @param {Array} type A list of allowed types for this assertion\n * @namespace Utils\n * @name expectTypes\n * @api public\n */\n\nvar AssertionError = require('assertion-error');\nvar flag = require('./flag');\nvar type = require('type-detect');\n\nmodule.exports = function expectTypes(obj, types) {\n  var flagMsg = flag(obj, 'message');\n  var ssfi = flag(obj, 'ssfi');\n\n  flagMsg = flagMsg ? flagMsg + ': ' : '';\n\n  obj = flag(obj, 'object');\n  types = types.map(function (t) { return t.toLowerCase(); });\n  types.sort();\n\n  // Transforms ['lorem', 'ipsum'] into 'a lorem, or an ipsum'\n  var str = types.map(function (t, index) {\n    var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a';\n    var or = types.length > 1 && index === types.length - 1 ? 'or ' : '';\n    return or + art + ' ' + t;\n  }).join(', ');\n\n  var objType = type(obj).toLowerCase();\n\n  if (!types.some(function (expected) { return objType === expected; })) {\n    throw new AssertionError(\n      flagMsg + 'object tested must be ' + str + ', but ' + objType + ' given',\n      undefined,\n      ssfi\n    );\n  }\n};\n\n},{\"./flag\":15,\"assertion-error\":33,\"type-detect\":39}],15:[function(require,module,exports){\n/*!\n * Chai - flag utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .flag(object, key, [value])\n *\n * Get or set a flag value on an object. If a\n * value is provided it will be set, else it will\n * return the currently set value or `undefined` if\n * the value is not set.\n *\n *     utils.flag(this, 'foo', 'bar'); // setter\n *     utils.flag(this, 'foo'); // getter, returns `bar`\n *\n * @param {Object} object constructed Assertion\n * @param {String} key\n * @param {Mixed} value (optional)\n * @namespace Utils\n * @name flag\n * @api private\n */\n\nmodule.exports = function flag(obj, key, value) {\n  var flags = obj.__flags || (obj.__flags = Object.create(null));\n  if (arguments.length === 3) {\n    flags[key] = value;\n  } else {\n    return flags[key];\n  }\n};\n\n},{}],16:[function(require,module,exports){\n/*!\n * Chai - getActual utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .getActual(object, [actual])\n *\n * Returns the `actual` value for an Assertion.\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n * @namespace Utils\n * @name getActual\n */\n\nmodule.exports = function getActual(obj, args) {\n  return args.length > 4 ? args[4] : obj._obj;\n};\n\n},{}],17:[function(require,module,exports){\n/*!\n * Chai - message composition utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar flag = require('./flag')\n  , getActual = require('./getActual')\n  , objDisplay = require('./objDisplay');\n\n/**\n * ### .getMessage(object, message, negateMessage)\n *\n * Construct the error message based on flags\n * and template tags. Template tags will return\n * a stringified inspection of the object referenced.\n *\n * Message template tags:\n * - `#{this}` current asserted object\n * - `#{act}` actual value\n * - `#{exp}` expected value\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n * @namespace Utils\n * @name getMessage\n * @api public\n */\n\nmodule.exports = function getMessage(obj, args) {\n  var negate = flag(obj, 'negate')\n    , val = flag(obj, 'object')\n    , expected = args[3]\n    , actual = getActual(obj, args)\n    , msg = negate ? args[2] : args[1]\n    , flagMsg = flag(obj, 'message');\n\n  if(typeof msg === \"function\") msg = msg();\n  msg = msg || '';\n  msg = msg\n    .replace(/#\\{this\\}/g, function () { return objDisplay(val); })\n    .replace(/#\\{act\\}/g, function () { return objDisplay(actual); })\n    .replace(/#\\{exp\\}/g, function () { return objDisplay(expected); });\n\n  return flagMsg ? flagMsg + ': ' + msg : msg;\n};\n\n},{\"./flag\":15,\"./getActual\":16,\"./objDisplay\":26}],18:[function(require,module,exports){\nvar type = require('type-detect');\n\nvar flag = require('./flag');\n\nfunction isObjectType(obj) {\n  var objectType = type(obj);\n  var objectTypes = ['Array', 'Object', 'function'];\n\n  return objectTypes.indexOf(objectType) !== -1;\n}\n\n/**\n * ### .getOperator(message)\n *\n * Extract the operator from error message.\n * Operator defined is based on below link\n * https://nodejs.org/api/assert.html#assert_assert.\n *\n * Returns the `operator` or `undefined` value for an Assertion.\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n * @namespace Utils\n * @name getOperator\n * @api public\n */\n\nmodule.exports = function getOperator(obj, args) {\n  var operator = flag(obj, 'operator');\n  var negate = flag(obj, 'negate');\n  var expected = args[3];\n  var msg = negate ? args[2] : args[1];\n\n  if (operator) {\n    return operator;\n  }\n\n  if (typeof msg === 'function') msg = msg();\n\n  msg = msg || '';\n  if (!msg) {\n    return undefined;\n  }\n\n  if (/\\shave\\s/.test(msg)) {\n    return undefined;\n  }\n\n  var isObject = isObjectType(expected);\n  if (/\\snot\\s/.test(msg)) {\n    return isObject ? 'notDeepStrictEqual' : 'notStrictEqual';\n  }\n\n  return isObject ? 'deepStrictEqual' : 'strictEqual';\n};\n\n},{\"./flag\":15,\"type-detect\":39}],19:[function(require,module,exports){\n/*!\n * Chai - getOwnEnumerableProperties utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar getOwnEnumerablePropertySymbols = require('./getOwnEnumerablePropertySymbols');\n\n/**\n * ### .getOwnEnumerableProperties(object)\n *\n * This allows the retrieval of directly-owned enumerable property names and\n * symbols of an object. This function is necessary because Object.keys only\n * returns enumerable property names, not enumerable property symbols.\n *\n * @param {Object} object\n * @returns {Array}\n * @namespace Utils\n * @name getOwnEnumerableProperties\n * @api public\n */\n\nmodule.exports = function getOwnEnumerableProperties(obj) {\n  return Object.keys(obj).concat(getOwnEnumerablePropertySymbols(obj));\n};\n\n},{\"./getOwnEnumerablePropertySymbols\":20}],20:[function(require,module,exports){\n/*!\n * Chai - getOwnEnumerablePropertySymbols utility\n * Copyright(c) 2011-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .getOwnEnumerablePropertySymbols(object)\n *\n * This allows the retrieval of directly-owned enumerable property symbols of an\n * object. This function is necessary because Object.getOwnPropertySymbols\n * returns both enumerable and non-enumerable property symbols.\n *\n * @param {Object} object\n * @returns {Array}\n * @namespace Utils\n * @name getOwnEnumerablePropertySymbols\n * @api public\n */\n\nmodule.exports = function getOwnEnumerablePropertySymbols(obj) {\n  if (typeof Object.getOwnPropertySymbols !== 'function') return [];\n\n  return Object.getOwnPropertySymbols(obj).filter(function (sym) {\n    return Object.getOwnPropertyDescriptor(obj, sym).enumerable;\n  });\n};\n\n},{}],21:[function(require,module,exports){\n/*!\n * Chai - getProperties utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .getProperties(object)\n *\n * This allows the retrieval of property names of an object, enumerable or not,\n * inherited or not.\n *\n * @param {Object} object\n * @returns {Array}\n * @namespace Utils\n * @name getProperties\n * @api public\n */\n\nmodule.exports = function getProperties(object) {\n  var result = Object.getOwnPropertyNames(object);\n\n  function addProperty(property) {\n    if (result.indexOf(property) === -1) {\n      result.push(property);\n    }\n  }\n\n  var proto = Object.getPrototypeOf(object);\n  while (proto !== null) {\n    Object.getOwnPropertyNames(proto).forEach(addProperty);\n    proto = Object.getPrototypeOf(proto);\n  }\n\n  return result;\n};\n\n},{}],22:[function(require,module,exports){\n/*!\n * chai\n * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Dependencies that are used for multiple exports are required here only once\n */\n\nvar pathval = require('pathval');\n\n/*!\n * test utility\n */\n\nexports.test = require('./test');\n\n/*!\n * type utility\n */\n\nexports.type = require('type-detect');\n\n/*!\n * expectTypes utility\n */\nexports.expectTypes = require('./expectTypes');\n\n/*!\n * message utility\n */\n\nexports.getMessage = require('./getMessage');\n\n/*!\n * actual utility\n */\n\nexports.getActual = require('./getActual');\n\n/*!\n * Inspect util\n */\n\nexports.inspect = require('./inspect');\n\n/*!\n * Object Display util\n */\n\nexports.objDisplay = require('./objDisplay');\n\n/*!\n * Flag utility\n */\n\nexports.flag = require('./flag');\n\n/*!\n * Flag transferring utility\n */\n\nexports.transferFlags = require('./transferFlags');\n\n/*!\n * Deep equal utility\n */\n\nexports.eql = require('deep-eql');\n\n/*!\n * Deep path info\n */\n\nexports.getPathInfo = pathval.getPathInfo;\n\n/*!\n * Check if a property exists\n */\n\nexports.hasProperty = pathval.hasProperty;\n\n/*!\n * Function name\n */\n\nexports.getName = require('get-func-name');\n\n/*!\n * add Property\n */\n\nexports.addProperty = require('./addProperty');\n\n/*!\n * add Method\n */\n\nexports.addMethod = require('./addMethod');\n\n/*!\n * overwrite Property\n */\n\nexports.overwriteProperty = require('./overwriteProperty');\n\n/*!\n * overwrite Method\n */\n\nexports.overwriteMethod = require('./overwriteMethod');\n\n/*!\n * Add a chainable method\n */\n\nexports.addChainableMethod = require('./addChainableMethod');\n\n/*!\n * Overwrite chainable method\n */\n\nexports.overwriteChainableMethod = require('./overwriteChainableMethod');\n\n/*!\n * Compare by inspect method\n */\n\nexports.compareByInspect = require('./compareByInspect');\n\n/*!\n * Get own enumerable property symbols method\n */\n\nexports.getOwnEnumerablePropertySymbols = require('./getOwnEnumerablePropertySymbols');\n\n/*!\n * Get own enumerable properties method\n */\n\nexports.getOwnEnumerableProperties = require('./getOwnEnumerableProperties');\n\n/*!\n * Checks error against a given set of criteria\n */\n\nexports.checkError = require('check-error');\n\n/*!\n * Proxify util\n */\n\nexports.proxify = require('./proxify');\n\n/*!\n * addLengthGuard util\n */\n\nexports.addLengthGuard = require('./addLengthGuard');\n\n/*!\n * isProxyEnabled helper\n */\n\nexports.isProxyEnabled = require('./isProxyEnabled');\n\n/*!\n * isNaN method\n */\n\nexports.isNaN = require('./isNaN');\n\n/*!\n * getOperator method\n */\n\nexports.getOperator = require('./getOperator');\n},{\"./addChainableMethod\":9,\"./addLengthGuard\":10,\"./addMethod\":11,\"./addProperty\":12,\"./compareByInspect\":13,\"./expectTypes\":14,\"./flag\":15,\"./getActual\":16,\"./getMessage\":17,\"./getOperator\":18,\"./getOwnEnumerableProperties\":19,\"./getOwnEnumerablePropertySymbols\":20,\"./inspect\":23,\"./isNaN\":24,\"./isProxyEnabled\":25,\"./objDisplay\":26,\"./overwriteChainableMethod\":27,\"./overwriteMethod\":28,\"./overwriteProperty\":29,\"./proxify\":30,\"./test\":31,\"./transferFlags\":32,\"check-error\":34,\"deep-eql\":35,\"get-func-name\":36,\"pathval\":38,\"type-detect\":39}],23:[function(require,module,exports){\n// This is (almost) directly from Node.js utils\n// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js\n\nvar getName = require('get-func-name');\nvar loupe = require('loupe');\nvar config = require('../config');\n\nmodule.exports = inspect;\n\n/**\n * ### .inspect(obj, [showHidden], [depth], [colors])\n *\n * Echoes the value of a value. Tries to print the value out\n * in the best way possible given the different types.\n *\n * @param {Object} obj The object to print out.\n * @param {Boolean} showHidden Flag that shows hidden (not enumerable)\n *    properties of objects. Default is false.\n * @param {Number} depth Depth in which to descend in object. Default is 2.\n * @param {Boolean} colors Flag to turn on ANSI escape codes to color the\n *    output. Default is false (no coloring).\n * @namespace Utils\n * @name inspect\n */\nfunction inspect(obj, showHidden, depth, colors) {\n  var options = {\n    colors: colors,\n    depth: (typeof depth === 'undefined' ? 2 : depth),\n    showHidden: showHidden,\n    truncate: config.truncateThreshold ? config.truncateThreshold : Infinity,\n  };\n  return loupe.inspect(obj, options);\n}\n\n},{\"../config\":4,\"get-func-name\":36,\"loupe\":37}],24:[function(require,module,exports){\n/*!\n * Chai - isNaN utility\n * Copyright(c) 2012-2015 Sakthipriyan Vairamani <thechargingvolcano@gmail.com>\n * MIT Licensed\n */\n\n/**\n * ### .isNaN(value)\n *\n * Checks if the given value is NaN or not.\n *\n *     utils.isNaN(NaN); // true\n *\n * @param {Value} The value which has to be checked if it is NaN\n * @name isNaN\n * @api private\n */\n\nfunction isNaN(value) {\n  // Refer http://www.ecma-international.org/ecma-262/6.0/#sec-isnan-number\n  // section's NOTE.\n  return value !== value;\n}\n\n// If ECMAScript 6's Number.isNaN is present, prefer that.\nmodule.exports = Number.isNaN || isNaN;\n\n},{}],25:[function(require,module,exports){\nvar config = require('../config');\n\n/*!\n * Chai - isProxyEnabled helper\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .isProxyEnabled()\n *\n * Helper function to check if Chai's proxy protection feature is enabled. If\n * proxies are unsupported or disabled via the user's Chai config, then return\n * false. Otherwise, return true.\n *\n * @namespace Utils\n * @name isProxyEnabled\n */\n\nmodule.exports = function isProxyEnabled() {\n  return config.useProxy &&\n    typeof Proxy !== 'undefined' &&\n    typeof Reflect !== 'undefined';\n};\n\n},{\"../config\":4}],26:[function(require,module,exports){\n/*!\n * Chai - flag utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar inspect = require('./inspect');\nvar config = require('../config');\n\n/**\n * ### .objDisplay(object)\n *\n * Determines if an object or an array matches\n * criteria to be inspected in-line for error\n * messages or should be truncated.\n *\n * @param {Mixed} javascript object to inspect\n * @name objDisplay\n * @namespace Utils\n * @api public\n */\n\nmodule.exports = function objDisplay(obj) {\n  var str = inspect(obj)\n    , type = Object.prototype.toString.call(obj);\n\n  if (config.truncateThreshold && str.length >= config.truncateThreshold) {\n    if (type === '[object Function]') {\n      return !obj.name || obj.name === ''\n        ? '[Function]'\n        : '[Function: ' + obj.name + ']';\n    } else if (type === '[object Array]') {\n      return '[ Array(' + obj.length + ') ]';\n    } else if (type === '[object Object]') {\n      var keys = Object.keys(obj)\n        , kstr = keys.length > 2\n          ? keys.splice(0, 2).join(', ') + ', ...'\n          : keys.join(', ');\n      return '{ Object (' + kstr + ') }';\n    } else {\n      return str;\n    }\n  } else {\n    return str;\n  }\n};\n\n},{\"../config\":4,\"./inspect\":23}],27:[function(require,module,exports){\n/*!\n * Chai - overwriteChainableMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar chai = require('../../chai');\nvar transferFlags = require('./transferFlags');\n\n/**\n * ### .overwriteChainableMethod(ctx, name, method, chainingBehavior)\n *\n * Overwrites an already existing chainable method\n * and provides access to the previous function or\n * property.  Must return functions to be used for\n * name.\n *\n *     utils.overwriteChainableMethod(chai.Assertion.prototype, 'lengthOf',\n *       function (_super) {\n *       }\n *     , function (_super) {\n *       }\n *     );\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.overwriteChainableMethod('foo', fn, fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.have.lengthOf(3);\n *     expect(myFoo).to.have.lengthOf.above(3);\n *\n * @param {Object} ctx object whose method / property is to be overwritten\n * @param {String} name of method / property to overwrite\n * @param {Function} method function that returns a function to be used for name\n * @param {Function} chainingBehavior function that returns a function to be used for property\n * @namespace Utils\n * @name overwriteChainableMethod\n * @api public\n */\n\nmodule.exports = function overwriteChainableMethod(ctx, name, method, chainingBehavior) {\n  var chainableBehavior = ctx.__methods[name];\n\n  var _chainingBehavior = chainableBehavior.chainingBehavior;\n  chainableBehavior.chainingBehavior = function overwritingChainableMethodGetter() {\n    var result = chainingBehavior(_chainingBehavior).call(this);\n    if (result !== undefined) {\n      return result;\n    }\n\n    var newAssertion = new chai.Assertion();\n    transferFlags(this, newAssertion);\n    return newAssertion;\n  };\n\n  var _method = chainableBehavior.method;\n  chainableBehavior.method = function overwritingChainableMethodWrapper() {\n    var result = method(_method).apply(this, arguments);\n    if (result !== undefined) {\n      return result;\n    }\n\n    var newAssertion = new chai.Assertion();\n    transferFlags(this, newAssertion);\n    return newAssertion;\n  };\n};\n\n},{\"../../chai\":2,\"./transferFlags\":32}],28:[function(require,module,exports){\n/*!\n * Chai - overwriteMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar addLengthGuard = require('./addLengthGuard');\nvar chai = require('../../chai');\nvar flag = require('./flag');\nvar proxify = require('./proxify');\nvar transferFlags = require('./transferFlags');\n\n/**\n * ### .overwriteMethod(ctx, name, fn)\n *\n * Overwrites an already existing method and provides\n * access to previous function. Must return function\n * to be used for name.\n *\n *     utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) {\n *       return function (str) {\n *         var obj = utils.flag(this, 'object');\n *         if (obj instanceof Foo) {\n *           new chai.Assertion(obj.value).to.equal(str);\n *         } else {\n *           _super.apply(this, arguments);\n *         }\n *       }\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.overwriteMethod('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.equal('bar');\n *\n * @param {Object} ctx object whose method is to be overwritten\n * @param {String} name of method to overwrite\n * @param {Function} method function that returns a function to be used for name\n * @namespace Utils\n * @name overwriteMethod\n * @api public\n */\n\nmodule.exports = function overwriteMethod(ctx, name, method) {\n  var _method = ctx[name]\n    , _super = function () {\n      throw new Error(name + ' is not a function');\n    };\n\n  if (_method && 'function' === typeof _method)\n    _super = _method;\n\n  var overwritingMethodWrapper = function () {\n    // Setting the `ssfi` flag to `overwritingMethodWrapper` causes this\n    // function to be the starting point for removing implementation frames from\n    // the stack trace of a failed assertion.\n    //\n    // However, we only want to use this function as the starting point if the\n    // `lockSsfi` flag isn't set.\n    //\n    // If the `lockSsfi` flag is set, then either this assertion has been\n    // overwritten by another assertion, or this assertion is being invoked from\n    // inside of another assertion. In the first case, the `ssfi` flag has\n    // already been set by the overwriting assertion. In the second case, the\n    // `ssfi` flag has already been set by the outer assertion.\n    if (!flag(this, 'lockSsfi')) {\n      flag(this, 'ssfi', overwritingMethodWrapper);\n    }\n\n    // Setting the `lockSsfi` flag to `true` prevents the overwritten assertion\n    // from changing the `ssfi` flag. By this point, the `ssfi` flag is already\n    // set to the correct starting point for this assertion.\n    var origLockSsfi = flag(this, 'lockSsfi');\n    flag(this, 'lockSsfi', true);\n    var result = method(_super).apply(this, arguments);\n    flag(this, 'lockSsfi', origLockSsfi);\n\n    if (result !== undefined) {\n      return result;\n    }\n\n    var newAssertion = new chai.Assertion();\n    transferFlags(this, newAssertion);\n    return newAssertion;\n  }\n\n  addLengthGuard(overwritingMethodWrapper, name, false);\n  ctx[name] = proxify(overwritingMethodWrapper, name);\n};\n\n},{\"../../chai\":2,\"./addLengthGuard\":10,\"./flag\":15,\"./proxify\":30,\"./transferFlags\":32}],29:[function(require,module,exports){\n/*!\n * Chai - overwriteProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar chai = require('../../chai');\nvar flag = require('./flag');\nvar isProxyEnabled = require('./isProxyEnabled');\nvar transferFlags = require('./transferFlags');\n\n/**\n * ### .overwriteProperty(ctx, name, fn)\n *\n * Overwrites an already existing property getter and provides\n * access to previous value. Must return function to use as getter.\n *\n *     utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) {\n *       return function () {\n *         var obj = utils.flag(this, 'object');\n *         if (obj instanceof Foo) {\n *           new chai.Assertion(obj.name).to.equal('bar');\n *         } else {\n *           _super.call(this);\n *         }\n *       }\n *     });\n *\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.overwriteProperty('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.be.ok;\n *\n * @param {Object} ctx object whose property is to be overwritten\n * @param {String} name of property to overwrite\n * @param {Function} getter function that returns a getter function to be used for name\n * @namespace Utils\n * @name overwriteProperty\n * @api public\n */\n\nmodule.exports = function overwriteProperty(ctx, name, getter) {\n  var _get = Object.getOwnPropertyDescriptor(ctx, name)\n    , _super = function () {};\n\n  if (_get && 'function' === typeof _get.get)\n    _super = _get.get\n\n  Object.defineProperty(ctx, name,\n    { get: function overwritingPropertyGetter() {\n        // Setting the `ssfi` flag to `overwritingPropertyGetter` causes this\n        // function to be the starting point for removing implementation frames\n        // from the stack trace of a failed assertion.\n        //\n        // However, we only want to use this function as the starting point if\n        // the `lockSsfi` flag isn't set and proxy protection is disabled.\n        //\n        // If the `lockSsfi` flag is set, then either this assertion has been\n        // overwritten by another assertion, or this assertion is being invoked\n        // from inside of another assertion. In the first case, the `ssfi` flag\n        // has already been set by the overwriting assertion. In the second\n        // case, the `ssfi` flag has already been set by the outer assertion.\n        //\n        // If proxy protection is enabled, then the `ssfi` flag has already been\n        // set by the proxy getter.\n        if (!isProxyEnabled() && !flag(this, 'lockSsfi')) {\n          flag(this, 'ssfi', overwritingPropertyGetter);\n        }\n\n        // Setting the `lockSsfi` flag to `true` prevents the overwritten\n        // assertion from changing the `ssfi` flag. By this point, the `ssfi`\n        // flag is already set to the correct starting point for this assertion.\n        var origLockSsfi = flag(this, 'lockSsfi');\n        flag(this, 'lockSsfi', true);\n        var result = getter(_super).call(this);\n        flag(this, 'lockSsfi', origLockSsfi);\n\n        if (result !== undefined) {\n          return result;\n        }\n\n        var newAssertion = new chai.Assertion();\n        transferFlags(this, newAssertion);\n        return newAssertion;\n      }\n    , configurable: true\n  });\n};\n\n},{\"../../chai\":2,\"./flag\":15,\"./isProxyEnabled\":25,\"./transferFlags\":32}],30:[function(require,module,exports){\nvar config = require('../config');\nvar flag = require('./flag');\nvar getProperties = require('./getProperties');\nvar isProxyEnabled = require('./isProxyEnabled');\n\n/*!\n * Chai - proxify utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .proxify(object)\n *\n * Return a proxy of given object that throws an error when a non-existent\n * property is read. By default, the root cause is assumed to be a misspelled\n * property, and thus an attempt is made to offer a reasonable suggestion from\n * the list of existing properties. However, if a nonChainableMethodName is\n * provided, then the root cause is instead a failure to invoke a non-chainable\n * method prior to reading the non-existent property.\n *\n * If proxies are unsupported or disabled via the user's Chai config, then\n * return object without modification.\n *\n * @param {Object} obj\n * @param {String} nonChainableMethodName\n * @namespace Utils\n * @name proxify\n */\n\nvar builtins = ['__flags', '__methods', '_obj', 'assert'];\n\nmodule.exports = function proxify(obj, nonChainableMethodName) {\n  if (!isProxyEnabled()) return obj;\n\n  return new Proxy(obj, {\n    get: function proxyGetter(target, property) {\n      // This check is here because we should not throw errors on Symbol properties\n      // such as `Symbol.toStringTag`.\n      // The values for which an error should be thrown can be configured using\n      // the `config.proxyExcludedKeys` setting.\n      if (typeof property === 'string' &&\n          config.proxyExcludedKeys.indexOf(property) === -1 &&\n          !Reflect.has(target, property)) {\n        // Special message for invalid property access of non-chainable methods.\n        if (nonChainableMethodName) {\n          throw Error('Invalid Chai property: ' + nonChainableMethodName + '.' +\n            property + '. See docs for proper usage of \"' +\n            nonChainableMethodName + '\".');\n        }\n\n        // If the property is reasonably close to an existing Chai property,\n        // suggest that property to the user. Only suggest properties with a\n        // distance less than 4.\n        var suggestion = null;\n        var suggestionDistance = 4;\n        getProperties(target).forEach(function(prop) {\n          if (\n            !Object.prototype.hasOwnProperty(prop) &&\n            builtins.indexOf(prop) === -1\n          ) {\n            var dist = stringDistanceCapped(\n              property,\n              prop,\n              suggestionDistance\n            );\n            if (dist < suggestionDistance) {\n              suggestion = prop;\n              suggestionDistance = dist;\n            }\n          }\n        });\n\n        if (suggestion !== null) {\n          throw Error('Invalid Chai property: ' + property +\n            '. Did you mean \"' + suggestion + '\"?');\n        } else {\n          throw Error('Invalid Chai property: ' + property);\n        }\n      }\n\n      // Use this proxy getter as the starting point for removing implementation\n      // frames from the stack trace of a failed assertion. For property\n      // assertions, this prevents the proxy getter from showing up in the stack\n      // trace since it's invoked before the property getter. For method and\n      // chainable method assertions, this flag will end up getting changed to\n      // the method wrapper, which is good since this frame will no longer be in\n      // the stack once the method is invoked. Note that Chai builtin assertion\n      // properties such as `__flags` are skipped since this is only meant to\n      // capture the starting point of an assertion. This step is also skipped\n      // if the `lockSsfi` flag is set, thus indicating that this assertion is\n      // being called from within another assertion. In that case, the `ssfi`\n      // flag is already set to the outer assertion's starting point.\n      if (builtins.indexOf(property) === -1 && !flag(target, 'lockSsfi')) {\n        flag(target, 'ssfi', proxyGetter);\n      }\n\n      return Reflect.get(target, property);\n    }\n  });\n};\n\n/**\n * # stringDistanceCapped(strA, strB, cap)\n * Return the Levenshtein distance between two strings, but no more than cap.\n * @param {string} strA\n * @param {string} strB\n * @param {number} number\n * @return {number} min(string distance between strA and strB, cap)\n * @api private\n */\n\nfunction stringDistanceCapped(strA, strB, cap) {\n  if (Math.abs(strA.length - strB.length) >= cap) {\n    return cap;\n  }\n\n  var memo = [];\n  // `memo` is a two-dimensional array containing distances.\n  // memo[i][j] is the distance between strA.slice(0, i) and\n  // strB.slice(0, j).\n  for (var i = 0; i <= strA.length; i++) {\n    memo[i] = Array(strB.length + 1).fill(0);\n    memo[i][0] = i;\n  }\n  for (var j = 0; j < strB.length; j++) {\n    memo[0][j] = j;\n  }\n\n  for (var i = 1; i <= strA.length; i++) {\n    var ch = strA.charCodeAt(i - 1);\n    for (var j = 1; j <= strB.length; j++) {\n      if (Math.abs(i - j) >= cap) {\n        memo[i][j] = cap;\n        continue;\n      }\n      memo[i][j] = Math.min(\n        memo[i - 1][j] + 1,\n        memo[i][j - 1] + 1,\n        memo[i - 1][j - 1] +\n          (ch === strB.charCodeAt(j - 1) ? 0 : 1)\n      );\n    }\n  }\n\n  return memo[strA.length][strB.length];\n}\n\n},{\"../config\":4,\"./flag\":15,\"./getProperties\":21,\"./isProxyEnabled\":25}],31:[function(require,module,exports){\n/*!\n * Chai - test utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar flag = require('./flag');\n\n/**\n * ### .test(object, expression)\n *\n * Test and object for expression.\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n * @namespace Utils\n * @name test\n */\n\nmodule.exports = function test(obj, args) {\n  var negate = flag(obj, 'negate')\n    , expr = args[0];\n  return negate ? !expr : expr;\n};\n\n},{\"./flag\":15}],32:[function(require,module,exports){\n/*!\n * Chai - transferFlags utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .transferFlags(assertion, object, includeAll = true)\n *\n * Transfer all the flags for `assertion` to `object`. If\n * `includeAll` is set to `false`, then the base Chai\n * assertion flags (namely `object`, `ssfi`, `lockSsfi`,\n * and `message`) will not be transferred.\n *\n *\n *     var newAssertion = new Assertion();\n *     utils.transferFlags(assertion, newAssertion);\n *\n *     var anotherAssertion = new Assertion(myObj);\n *     utils.transferFlags(assertion, anotherAssertion, false);\n *\n * @param {Assertion} assertion the assertion to transfer the flags from\n * @param {Object} object the object to transfer the flags to; usually a new assertion\n * @param {Boolean} includeAll\n * @namespace Utils\n * @name transferFlags\n * @api private\n */\n\nmodule.exports = function transferFlags(assertion, object, includeAll) {\n  var flags = assertion.__flags || (assertion.__flags = Object.create(null));\n\n  if (!object.__flags) {\n    object.__flags = Object.create(null);\n  }\n\n  includeAll = arguments.length === 3 ? includeAll : true;\n\n  for (var flag in flags) {\n    if (includeAll ||\n        (flag !== 'object' && flag !== 'ssfi' && flag !== 'lockSsfi' && flag != 'message')) {\n      object.__flags[flag] = flags[flag];\n    }\n  }\n};\n\n},{}],33:[function(require,module,exports){\n/*!\n * assertion-error\n * Copyright(c) 2013 Jake Luer <jake@qualiancy.com>\n * MIT Licensed\n */\n\n/*!\n * Return a function that will copy properties from\n * one object to another excluding any originally\n * listed. Returned function will create a new `{}`.\n *\n * @param {String} excluded properties ...\n * @return {Function}\n */\n\nfunction exclude () {\n  var excludes = [].slice.call(arguments);\n\n  function excludeProps (res, obj) {\n    Object.keys(obj).forEach(function (key) {\n      if (!~excludes.indexOf(key)) res[key] = obj[key];\n    });\n  }\n\n  return function extendExclude () {\n    var args = [].slice.call(arguments)\n      , i = 0\n      , res = {};\n\n    for (; i < args.length; i++) {\n      excludeProps(res, args[i]);\n    }\n\n    return res;\n  };\n};\n\n/*!\n * Primary Exports\n */\n\nmodule.exports = AssertionError;\n\n/**\n * ### AssertionError\n *\n * An extension of the JavaScript `Error` constructor for\n * assertion and validation scenarios.\n *\n * @param {String} message\n * @param {Object} properties to include (optional)\n * @param {callee} start stack function (optional)\n */\n\nfunction AssertionError (message, _props, ssf) {\n  var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON')\n    , props = extend(_props || {});\n\n  // default values\n  this.message = message || 'Unspecified AssertionError';\n  this.showDiff = false;\n\n  // copy from properties\n  for (var key in props) {\n    this[key] = props[key];\n  }\n\n  // capture stack trace\n  ssf = ssf || AssertionError;\n  if (Error.captureStackTrace) {\n    Error.captureStackTrace(this, ssf);\n  } else {\n    try {\n      throw new Error();\n    } catch(e) {\n      this.stack = e.stack;\n    }\n  }\n}\n\n/*!\n * Inherit from Error.prototype\n */\n\nAssertionError.prototype = Object.create(Error.prototype);\n\n/*!\n * Statically set name\n */\n\nAssertionError.prototype.name = 'AssertionError';\n\n/*!\n * Ensure correct constructor\n */\n\nAssertionError.prototype.constructor = AssertionError;\n\n/**\n * Allow errors to be converted to JSON for static transfer.\n *\n * @param {Boolean} include stack (default: `true`)\n * @return {Object} object that can be `JSON.stringify`\n */\n\nAssertionError.prototype.toJSON = function (stack) {\n  var extend = exclude('constructor', 'toJSON', 'stack')\n    , props = extend({ name: this.name }, this);\n\n  // include stack if exists and not turned off\n  if (false !== stack && this.stack) {\n    props.stack = this.stack;\n  }\n\n  return props;\n};\n\n},{}],34:[function(require,module,exports){\n'use strict';\n\n/* !\n * Chai - checkError utility\n * Copyright(c) 2012-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .checkError\n *\n * Checks that an error conforms to a given set of criteria and/or retrieves information about it.\n *\n * @api public\n */\n\n/**\n * ### .compatibleInstance(thrown, errorLike)\n *\n * Checks if two instances are compatible (strict equal).\n * Returns false if errorLike is not an instance of Error, because instances\n * can only be compatible if they're both error instances.\n *\n * @name compatibleInstance\n * @param {Error} thrown error\n * @param {Error|ErrorConstructor} errorLike object to compare against\n * @namespace Utils\n * @api public\n */\n\nfunction compatibleInstance(thrown, errorLike) {\n  return errorLike instanceof Error && thrown === errorLike;\n}\n\n/**\n * ### .compatibleConstructor(thrown, errorLike)\n *\n * Checks if two constructors are compatible.\n * This function can receive either an error constructor or\n * an error instance as the `errorLike` argument.\n * Constructors are compatible if they're the same or if one is\n * an instance of another.\n *\n * @name compatibleConstructor\n * @param {Error} thrown error\n * @param {Error|ErrorConstructor} errorLike object to compare against\n * @namespace Utils\n * @api public\n */\n\nfunction compatibleConstructor(thrown, errorLike) {\n  if (errorLike instanceof Error) {\n    // If `errorLike` is an instance of any error we compare their constructors\n    return thrown.constructor === errorLike.constructor || thrown instanceof errorLike.constructor;\n  } else if (errorLike.prototype instanceof Error || errorLike === Error) {\n    // If `errorLike` is a constructor that inherits from Error, we compare `thrown` to `errorLike` directly\n    return thrown.constructor === errorLike || thrown instanceof errorLike;\n  }\n\n  return false;\n}\n\n/**\n * ### .compatibleMessage(thrown, errMatcher)\n *\n * Checks if an error's message is compatible with a matcher (String or RegExp).\n * If the message contains the String or passes the RegExp test,\n * it is considered compatible.\n *\n * @name compatibleMessage\n * @param {Error} thrown error\n * @param {String|RegExp} errMatcher to look for into the message\n * @namespace Utils\n * @api public\n */\n\nfunction compatibleMessage(thrown, errMatcher) {\n  var comparisonString = typeof thrown === 'string' ? thrown : thrown.message;\n  if (errMatcher instanceof RegExp) {\n    return errMatcher.test(comparisonString);\n  } else if (typeof errMatcher === 'string') {\n    return comparisonString.indexOf(errMatcher) !== -1; // eslint-disable-line no-magic-numbers\n  }\n\n  return false;\n}\n\n/**\n * ### .getFunctionName(constructorFn)\n *\n * Returns the name of a function.\n * This also includes a polyfill function if `constructorFn.name` is not defined.\n *\n * @name getFunctionName\n * @param {Function} constructorFn\n * @namespace Utils\n * @api private\n */\n\nvar functionNameMatch = /\\s*function(?:\\s|\\s*\\/\\*[^(?:*\\/)]+\\*\\/\\s*)*([^\\(\\/]+)/;\nfunction getFunctionName(constructorFn) {\n  var name = '';\n  if (typeof constructorFn.name === 'undefined') {\n    // Here we run a polyfill if constructorFn.name is not defined\n    var match = String(constructorFn).match(functionNameMatch);\n    if (match) {\n      name = match[1];\n    }\n  } else {\n    name = constructorFn.name;\n  }\n\n  return name;\n}\n\n/**\n * ### .getConstructorName(errorLike)\n *\n * Gets the constructor name for an Error instance or constructor itself.\n *\n * @name getConstructorName\n * @param {Error|ErrorConstructor} errorLike\n * @namespace Utils\n * @api public\n */\n\nfunction getConstructorName(errorLike) {\n  var constructorName = errorLike;\n  if (errorLike instanceof Error) {\n    constructorName = getFunctionName(errorLike.constructor);\n  } else if (typeof errorLike === 'function') {\n    // If `err` is not an instance of Error it is an error constructor itself or another function.\n    // If we've got a common function we get its name, otherwise we may need to create a new instance\n    // of the error just in case it's a poorly-constructed error. Please see chaijs/chai/issues/45 to know more.\n    constructorName = getFunctionName(errorLike).trim() ||\n        getFunctionName(new errorLike()); // eslint-disable-line new-cap\n  }\n\n  return constructorName;\n}\n\n/**\n * ### .getMessage(errorLike)\n *\n * Gets the error message from an error.\n * If `err` is a String itself, we return it.\n * If the error has no message, we return an empty string.\n *\n * @name getMessage\n * @param {Error|String} errorLike\n * @namespace Utils\n * @api public\n */\n\nfunction getMessage(errorLike) {\n  var msg = '';\n  if (errorLike && errorLike.message) {\n    msg = errorLike.message;\n  } else if (typeof errorLike === 'string') {\n    msg = errorLike;\n  }\n\n  return msg;\n}\n\nmodule.exports = {\n  compatibleInstance: compatibleInstance,\n  compatibleConstructor: compatibleConstructor,\n  compatibleMessage: compatibleMessage,\n  getMessage: getMessage,\n  getConstructorName: getConstructorName,\n};\n\n},{}],35:[function(require,module,exports){\n'use strict';\n/* globals Symbol: false, Uint8Array: false, WeakMap: false */\n/*!\n * deep-eql\n * Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar type = require('type-detect');\nfunction FakeMap() {\n  this._key = 'chai/deep-eql__' + Math.random() + Date.now();\n}\n\nFakeMap.prototype = {\n  get: function getMap(key) {\n    return key[this._key];\n  },\n  set: function setMap(key, value) {\n    if (Object.isExtensible(key)) {\n      Object.defineProperty(key, this._key, {\n        value: value,\n        configurable: true,\n      });\n    }\n  },\n};\n\nvar MemoizeMap = typeof WeakMap === 'function' ? WeakMap : FakeMap;\n/*!\n * Check to see if the MemoizeMap has recorded a result of the two operands\n *\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @param {MemoizeMap} memoizeMap\n * @returns {Boolean|null} result\n*/\nfunction memoizeCompare(leftHandOperand, rightHandOperand, memoizeMap) {\n  // Technically, WeakMap keys can *only* be objects, not primitives.\n  if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {\n    return null;\n  }\n  var leftHandMap = memoizeMap.get(leftHandOperand);\n  if (leftHandMap) {\n    var result = leftHandMap.get(rightHandOperand);\n    if (typeof result === 'boolean') {\n      return result;\n    }\n  }\n  return null;\n}\n\n/*!\n * Set the result of the equality into the MemoizeMap\n *\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @param {MemoizeMap} memoizeMap\n * @param {Boolean} result\n*/\nfunction memoizeSet(leftHandOperand, rightHandOperand, memoizeMap, result) {\n  // Technically, WeakMap keys can *only* be objects, not primitives.\n  if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {\n    return;\n  }\n  var leftHandMap = memoizeMap.get(leftHandOperand);\n  if (leftHandMap) {\n    leftHandMap.set(rightHandOperand, result);\n  } else {\n    leftHandMap = new MemoizeMap();\n    leftHandMap.set(rightHandOperand, result);\n    memoizeMap.set(leftHandOperand, leftHandMap);\n  }\n}\n\n/*!\n * Primary Export\n */\n\nmodule.exports = deepEqual;\nmodule.exports.MemoizeMap = MemoizeMap;\n\n/**\n * Assert deeply nested sameValue equality between two objects of any type.\n *\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @param {Object} [options] (optional) Additional options\n * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.\n * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of\n    complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular\n    references to blow the stack.\n * @return {Boolean} equal match\n */\nfunction deepEqual(leftHandOperand, rightHandOperand, options) {\n  // If we have a comparator, we can't assume anything; so bail to its check first.\n  if (options && options.comparator) {\n    return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);\n  }\n\n  var simpleResult = simpleEqual(leftHandOperand, rightHandOperand);\n  if (simpleResult !== null) {\n    return simpleResult;\n  }\n\n  // Deeper comparisons are pushed through to a larger function\n  return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);\n}\n\n/**\n * Many comparisons can be canceled out early via simple equality or primitive checks.\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @return {Boolean|null} equal match\n */\nfunction simpleEqual(leftHandOperand, rightHandOperand) {\n  // Equal references (except for Numbers) can be returned early\n  if (leftHandOperand === rightHandOperand) {\n    // Handle +-0 cases\n    return leftHandOperand !== 0 || 1 / leftHandOperand === 1 / rightHandOperand;\n  }\n\n  // handle NaN cases\n  if (\n    leftHandOperand !== leftHandOperand && // eslint-disable-line no-self-compare\n    rightHandOperand !== rightHandOperand // eslint-disable-line no-self-compare\n  ) {\n    return true;\n  }\n\n  // Anything that is not an 'object', i.e. symbols, functions, booleans, numbers,\n  // strings, and undefined, can be compared by reference.\n  if (isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {\n    // Easy out b/c it would have passed the first equality check\n    return false;\n  }\n  return null;\n}\n\n/*!\n * The main logic of the `deepEqual` function.\n *\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @param {Object} [options] (optional) Additional options\n * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.\n * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of\n    complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular\n    references to blow the stack.\n * @return {Boolean} equal match\n*/\nfunction extensiveDeepEqual(leftHandOperand, rightHandOperand, options) {\n  options = options || {};\n  options.memoize = options.memoize === false ? false : options.memoize || new MemoizeMap();\n  var comparator = options && options.comparator;\n\n  // Check if a memoized result exists.\n  var memoizeResultLeft = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize);\n  if (memoizeResultLeft !== null) {\n    return memoizeResultLeft;\n  }\n  var memoizeResultRight = memoizeCompare(rightHandOperand, leftHandOperand, options.memoize);\n  if (memoizeResultRight !== null) {\n    return memoizeResultRight;\n  }\n\n  // If a comparator is present, use it.\n  if (comparator) {\n    var comparatorResult = comparator(leftHandOperand, rightHandOperand);\n    // Comparators may return null, in which case we want to go back to default behavior.\n    if (comparatorResult === false || comparatorResult === true) {\n      memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult);\n      return comparatorResult;\n    }\n    // To allow comparators to override *any* behavior, we ran them first. Since it didn't decide\n    // what to do, we need to make sure to return the basic tests first before we move on.\n    var simpleResult = simpleEqual(leftHandOperand, rightHandOperand);\n    if (simpleResult !== null) {\n      // Don't memoize this, it takes longer to set/retrieve than to just compare.\n      return simpleResult;\n    }\n  }\n\n  var leftHandType = type(leftHandOperand);\n  if (leftHandType !== type(rightHandOperand)) {\n    memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false);\n    return false;\n  }\n\n  // Temporarily set the operands in the memoize object to prevent blowing the stack\n  memoizeSet(leftHandOperand, rightHandOperand, options.memoize, true);\n\n  var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options);\n  memoizeSet(leftHandOperand, rightHandOperand, options.memoize, result);\n  return result;\n}\n\nfunction extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options) {\n  switch (leftHandType) {\n    case 'String':\n    case 'Number':\n    case 'Boolean':\n    case 'Date':\n      // If these types are their instance types (e.g. `new Number`) then re-deepEqual against their values\n      return deepEqual(leftHandOperand.valueOf(), rightHandOperand.valueOf());\n    case 'Promise':\n    case 'Symbol':\n    case 'function':\n    case 'WeakMap':\n    case 'WeakSet':\n    case 'Error':\n      return leftHandOperand === rightHandOperand;\n    case 'Arguments':\n    case 'Int8Array':\n    case 'Uint8Array':\n    case 'Uint8ClampedArray':\n    case 'Int16Array':\n    case 'Uint16Array':\n    case 'Int32Array':\n    case 'Uint32Array':\n    case 'Float32Array':\n    case 'Float64Array':\n    case 'Array':\n      return iterableEqual(leftHandOperand, rightHandOperand, options);\n    case 'RegExp':\n      return regexpEqual(leftHandOperand, rightHandOperand);\n    case 'Generator':\n      return generatorEqual(leftHandOperand, rightHandOperand, options);\n    case 'DataView':\n      return iterableEqual(new Uint8Array(leftHandOperand.buffer), new Uint8Array(rightHandOperand.buffer), options);\n    case 'ArrayBuffer':\n      return iterableEqual(new Uint8Array(leftHandOperand), new Uint8Array(rightHandOperand), options);\n    case 'Set':\n      return entriesEqual(leftHandOperand, rightHandOperand, options);\n    case 'Map':\n      return entriesEqual(leftHandOperand, rightHandOperand, options);\n    default:\n      return objectEqual(leftHandOperand, rightHandOperand, options);\n  }\n}\n\n/*!\n * Compare two Regular Expressions for equality.\n *\n * @param {RegExp} leftHandOperand\n * @param {RegExp} rightHandOperand\n * @return {Boolean} result\n */\n\nfunction regexpEqual(leftHandOperand, rightHandOperand) {\n  return leftHandOperand.toString() === rightHandOperand.toString();\n}\n\n/*!\n * Compare two Sets/Maps for equality. Faster than other equality functions.\n *\n * @param {Set} leftHandOperand\n * @param {Set} rightHandOperand\n * @param {Object} [options] (Optional)\n * @return {Boolean} result\n */\n\nfunction entriesEqual(leftHandOperand, rightHandOperand, options) {\n  // IE11 doesn't support Set#entries or Set#@@iterator, so we need manually populate using Set#forEach\n  if (leftHandOperand.size !== rightHandOperand.size) {\n    return false;\n  }\n  if (leftHandOperand.size === 0) {\n    return true;\n  }\n  var leftHandItems = [];\n  var rightHandItems = [];\n  leftHandOperand.forEach(function gatherEntries(key, value) {\n    leftHandItems.push([ key, value ]);\n  });\n  rightHandOperand.forEach(function gatherEntries(key, value) {\n    rightHandItems.push([ key, value ]);\n  });\n  return iterableEqual(leftHandItems.sort(), rightHandItems.sort(), options);\n}\n\n/*!\n * Simple equality for flat iterable objects such as Arrays, TypedArrays or Node.js buffers.\n *\n * @param {Iterable} leftHandOperand\n * @param {Iterable} rightHandOperand\n * @param {Object} [options] (Optional)\n * @return {Boolean} result\n */\n\nfunction iterableEqual(leftHandOperand, rightHandOperand, options) {\n  var length = leftHandOperand.length;\n  if (length !== rightHandOperand.length) {\n    return false;\n  }\n  if (length === 0) {\n    return true;\n  }\n  var index = -1;\n  while (++index < length) {\n    if (deepEqual(leftHandOperand[index], rightHandOperand[index], options) === false) {\n      return false;\n    }\n  }\n  return true;\n}\n\n/*!\n * Simple equality for generator objects such as those returned by generator functions.\n *\n * @param {Iterable} leftHandOperand\n * @param {Iterable} rightHandOperand\n * @param {Object} [options] (Optional)\n * @return {Boolean} result\n */\n\nfunction generatorEqual(leftHandOperand, rightHandOperand, options) {\n  return iterableEqual(getGeneratorEntries(leftHandOperand), getGeneratorEntries(rightHandOperand), options);\n}\n\n/*!\n * Determine if the given object has an @@iterator function.\n *\n * @param {Object} target\n * @return {Boolean} `true` if the object has an @@iterator function.\n */\nfunction hasIteratorFunction(target) {\n  return typeof Symbol !== 'undefined' &&\n    typeof target === 'object' &&\n    typeof Symbol.iterator !== 'undefined' &&\n    typeof target[Symbol.iterator] === 'function';\n}\n\n/*!\n * Gets all iterator entries from the given Object. If the Object has no @@iterator function, returns an empty array.\n * This will consume the iterator - which could have side effects depending on the @@iterator implementation.\n *\n * @param {Object} target\n * @returns {Array} an array of entries from the @@iterator function\n */\nfunction getIteratorEntries(target) {\n  if (hasIteratorFunction(target)) {\n    try {\n      return getGeneratorEntries(target[Symbol.iterator]());\n    } catch (iteratorError) {\n      return [];\n    }\n  }\n  return [];\n}\n\n/*!\n * Gets all entries from a Generator. This will consume the generator - which could have side effects.\n *\n * @param {Generator} target\n * @returns {Array} an array of entries from the Generator.\n */\nfunction getGeneratorEntries(generator) {\n  var generatorResult = generator.next();\n  var accumulator = [ generatorResult.value ];\n  while (generatorResult.done === false) {\n    generatorResult = generator.next();\n    accumulator.push(generatorResult.value);\n  }\n  return accumulator;\n}\n\n/*!\n * Gets all own and inherited enumerable keys from a target.\n *\n * @param {Object} target\n * @returns {Array} an array of own and inherited enumerable keys from the target.\n */\nfunction getEnumerableKeys(target) {\n  var keys = [];\n  for (var key in target) {\n    keys.push(key);\n  }\n  return keys;\n}\n\n/*!\n * Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of\n * each key. If any value of the given key is not equal, the function will return false (early).\n *\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @param {Array} keys An array of keys to compare the values of leftHandOperand and rightHandOperand against\n * @param {Object} [options] (Optional)\n * @return {Boolean} result\n */\nfunction keysEqual(leftHandOperand, rightHandOperand, keys, options) {\n  var length = keys.length;\n  if (length === 0) {\n    return true;\n  }\n  for (var i = 0; i < length; i += 1) {\n    if (deepEqual(leftHandOperand[keys[i]], rightHandOperand[keys[i]], options) === false) {\n      return false;\n    }\n  }\n  return true;\n}\n\n/*!\n * Recursively check the equality of two Objects. Once basic sameness has been established it will defer to `deepEqual`\n * for each enumerable key in the object.\n *\n * @param {Mixed} leftHandOperand\n * @param {Mixed} rightHandOperand\n * @param {Object} [options] (Optional)\n * @return {Boolean} result\n */\n\nfunction objectEqual(leftHandOperand, rightHandOperand, options) {\n  var leftHandKeys = getEnumerableKeys(leftHandOperand);\n  var rightHandKeys = getEnumerableKeys(rightHandOperand);\n  if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) {\n    leftHandKeys.sort();\n    rightHandKeys.sort();\n    if (iterableEqual(leftHandKeys, rightHandKeys) === false) {\n      return false;\n    }\n    return keysEqual(leftHandOperand, rightHandOperand, leftHandKeys, options);\n  }\n\n  var leftHandEntries = getIteratorEntries(leftHandOperand);\n  var rightHandEntries = getIteratorEntries(rightHandOperand);\n  if (leftHandEntries.length && leftHandEntries.length === rightHandEntries.length) {\n    leftHandEntries.sort();\n    rightHandEntries.sort();\n    return iterableEqual(leftHandEntries, rightHandEntries, options);\n  }\n\n  if (leftHandKeys.length === 0 &&\n      leftHandEntries.length === 0 &&\n      rightHandKeys.length === 0 &&\n      rightHandEntries.length === 0) {\n    return true;\n  }\n\n  return false;\n}\n\n/*!\n * Returns true if the argument is a primitive.\n *\n * This intentionally returns true for all objects that can be compared by reference,\n * including functions and symbols.\n *\n * @param {Mixed} value\n * @return {Boolean} result\n */\nfunction isPrimitive(value) {\n  return value === null || typeof value !== 'object';\n}\n\n},{\"type-detect\":39}],36:[function(require,module,exports){\n'use strict';\n\n/* !\n * Chai - getFuncName utility\n * Copyright(c) 2012-2016 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .getFuncName(constructorFn)\n *\n * Returns the name of a function.\n * When a non-function instance is passed, returns `null`.\n * This also includes a polyfill function if `aFunc.name` is not defined.\n *\n * @name getFuncName\n * @param {Function} funct\n * @namespace Utils\n * @api public\n */\n\nvar toString = Function.prototype.toString;\nvar functionNameMatch = /\\s*function(?:\\s|\\s*\\/\\*[^(?:*\\/)]+\\*\\/\\s*)*([^\\s\\(\\/]+)/;\nfunction getFuncName(aFunc) {\n  if (typeof aFunc !== 'function') {\n    return null;\n  }\n\n  var name = '';\n  if (typeof Function.prototype.name === 'undefined' && typeof aFunc.name === 'undefined') {\n    // Here we run a polyfill if Function does not support the `name` property and if aFunc.name is not defined\n    var match = toString.call(aFunc).match(functionNameMatch);\n    if (match) {\n      name = match[1];\n    }\n  } else {\n    // If we've got a `name` property we just use it\n    name = aFunc.name;\n  }\n\n  return name;\n}\n\nmodule.exports = getFuncName;\n\n},{}],37:[function(require,module,exports){\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n  typeof define === 'function' && define.amd ? define(['exports'], factory) :\n  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.loupe = {}));\n}(this, (function (exports) { 'use strict';\n\n  function _typeof(obj) {\n    \"@babel/helpers - typeof\";\n\n    if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n      _typeof = function (obj) {\n        return typeof obj;\n      };\n    } else {\n      _typeof = function (obj) {\n        return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n      };\n    }\n\n    return _typeof(obj);\n  }\n\n  function _slicedToArray(arr, i) {\n    return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n  }\n\n  function _arrayWithHoles(arr) {\n    if (Array.isArray(arr)) return arr;\n  }\n\n  function _iterableToArrayLimit(arr, i) {\n    if (typeof Symbol === \"undefined\" || !(Symbol.iterator in Object(arr))) return;\n    var _arr = [];\n    var _n = true;\n    var _d = false;\n    var _e = undefined;\n\n    try {\n      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n        _arr.push(_s.value);\n\n        if (i && _arr.length === i) break;\n      }\n    } catch (err) {\n      _d = true;\n      _e = err;\n    } finally {\n      try {\n        if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n      } finally {\n        if (_d) throw _e;\n      }\n    }\n\n    return _arr;\n  }\n\n  function _unsupportedIterableToArray(o, minLen) {\n    if (!o) return;\n    if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n    var n = Object.prototype.toString.call(o).slice(8, -1);\n    if (n === \"Object\" && o.constructor) n = o.constructor.name;\n    if (n === \"Map\" || n === \"Set\") return Array.from(o);\n    if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n  }\n\n  function _arrayLikeToArray(arr, len) {\n    if (len == null || len > arr.length) len = arr.length;\n\n    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n    return arr2;\n  }\n\n  function _nonIterableRest() {\n    throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n  }\n\n  var ansiColors = {\n    bold: ['1', '22'],\n    dim: ['2', '22'],\n    italic: ['3', '23'],\n    underline: ['4', '24'],\n    // 5 & 6 are blinking\n    inverse: ['7', '27'],\n    hidden: ['8', '28'],\n    strike: ['9', '29'],\n    // 10-20 are fonts\n    // 21-29 are resets for 1-9\n    black: ['30', '39'],\n    red: ['31', '39'],\n    green: ['32', '39'],\n    yellow: ['33', '39'],\n    blue: ['34', '39'],\n    magenta: ['35', '39'],\n    cyan: ['36', '39'],\n    white: ['37', '39'],\n    brightblack: ['30;1', '39'],\n    brightred: ['31;1', '39'],\n    brightgreen: ['32;1', '39'],\n    brightyellow: ['33;1', '39'],\n    brightblue: ['34;1', '39'],\n    brightmagenta: ['35;1', '39'],\n    brightcyan: ['36;1', '39'],\n    brightwhite: ['37;1', '39'],\n    grey: ['90', '39']\n  };\n  var styles = {\n    special: 'cyan',\n    number: 'yellow',\n    bigint: 'yellow',\n    boolean: 'yellow',\n    undefined: 'grey',\n    null: 'bold',\n    string: 'green',\n    symbol: 'green',\n    date: 'magenta',\n    regexp: 'red'\n  };\n  var truncator = '…';\n\n  function colorise(value, styleType) {\n    var color = ansiColors[styles[styleType]] || ansiColors[styleType];\n\n    if (!color) {\n      return String(value);\n    }\n\n    return \"\\x1B[\".concat(color[0], \"m\").concat(String(value), \"\\x1B[\").concat(color[1], \"m\");\n  }\n\n  function normaliseOptions() {\n    var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n        _ref$showHidden = _ref.showHidden,\n        showHidden = _ref$showHidden === void 0 ? false : _ref$showHidden,\n        _ref$depth = _ref.depth,\n        depth = _ref$depth === void 0 ? 2 : _ref$depth,\n        _ref$colors = _ref.colors,\n        colors = _ref$colors === void 0 ? false : _ref$colors,\n        _ref$customInspect = _ref.customInspect,\n        customInspect = _ref$customInspect === void 0 ? true : _ref$customInspect,\n        _ref$showProxy = _ref.showProxy,\n        showProxy = _ref$showProxy === void 0 ? false : _ref$showProxy,\n        _ref$maxArrayLength = _ref.maxArrayLength,\n        maxArrayLength = _ref$maxArrayLength === void 0 ? Infinity : _ref$maxArrayLength,\n        _ref$breakLength = _ref.breakLength,\n        breakLength = _ref$breakLength === void 0 ? Infinity : _ref$breakLength,\n        _ref$seen = _ref.seen,\n        seen = _ref$seen === void 0 ? [] : _ref$seen,\n        _ref$truncate = _ref.truncate,\n        truncate = _ref$truncate === void 0 ? Infinity : _ref$truncate,\n        _ref$stylize = _ref.stylize,\n        stylize = _ref$stylize === void 0 ? String : _ref$stylize;\n\n    var options = {\n      showHidden: Boolean(showHidden),\n      depth: Number(depth),\n      colors: Boolean(colors),\n      customInspect: Boolean(customInspect),\n      showProxy: Boolean(showProxy),\n      maxArrayLength: Number(maxArrayLength),\n      breakLength: Number(breakLength),\n      truncate: Number(truncate),\n      seen: seen,\n      stylize: stylize\n    };\n\n    if (options.colors) {\n      options.stylize = colorise;\n    }\n\n    return options;\n  }\n  function truncate(string, length) {\n    var tail = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : truncator;\n    string = String(string);\n    var tailLength = tail.length;\n    var stringLength = string.length;\n\n    if (tailLength > length && stringLength > tailLength) {\n      return tail;\n    }\n\n    if (stringLength > length && stringLength > tailLength) {\n      return \"\".concat(string.slice(0, length - tailLength)).concat(tail);\n    }\n\n    return string;\n  } // eslint-disable-next-line complexity\n\n  function inspectList(list, options, inspectItem) {\n    var separator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ', ';\n    inspectItem = inspectItem || options.inspect;\n    var size = list.length;\n    if (size === 0) return '';\n    var originalLength = options.truncate;\n    var output = '';\n    var peek = '';\n    var truncated = '';\n\n    for (var i = 0; i < size; i += 1) {\n      var last = i + 1 === list.length;\n      var secondToLast = i + 2 === list.length;\n      truncated = \"\".concat(truncator, \"(\").concat(list.length - i, \")\");\n      var value = list[i]; // If there is more than one remaining we need to account for a separator of `, `\n\n      options.truncate = originalLength - output.length - (last ? 0 : separator.length);\n      var string = peek || inspectItem(value, options) + (last ? '' : separator);\n      var nextLength = output.length + string.length;\n      var truncatedLength = nextLength + truncated.length; // If this is the last element, and adding it would\n      // take us over length, but adding the truncator wouldn't - then break now\n\n      if (last && nextLength > originalLength && output.length + truncated.length <= originalLength) {\n        break;\n      } // If this isn't the last or second to last element to scan,\n      // but the string is already over length then break here\n\n\n      if (!last && !secondToLast && truncatedLength > originalLength) {\n        break;\n      } // Peek at the next string to determine if we should\n      // break early before adding this item to the output\n\n\n      peek = last ? '' : inspectItem(list[i + 1], options) + (secondToLast ? '' : separator); // If we have one element left, but this element and\n      // the next takes over length, the break early\n\n      if (!last && secondToLast && truncatedLength > originalLength && nextLength + peek.length > originalLength) {\n        break;\n      }\n\n      output += string; // If the next element takes us to length -\n      // but there are more after that, then we should truncate now\n\n      if (!last && !secondToLast && nextLength + peek.length >= originalLength) {\n        truncated = \"\".concat(truncator, \"(\").concat(list.length - i - 1, \")\");\n        break;\n      }\n\n      truncated = '';\n    }\n\n    return \"\".concat(output).concat(truncated);\n  }\n\n  function quoteComplexKey(key) {\n    if (key.match(/^[a-zA-Z_][a-zA-Z_0-9]*$/)) {\n      return key;\n    }\n\n    return JSON.stringify(key).replace(/'/g, \"\\\\'\").replace(/\\\\\"/g, '\"').replace(/(^\"|\"$)/g, \"'\");\n  }\n\n  function inspectProperty(_ref2, options) {\n    var _ref3 = _slicedToArray(_ref2, 2),\n        key = _ref3[0],\n        value = _ref3[1];\n\n    options.truncate -= 2;\n\n    if (typeof key === 'string') {\n      key = quoteComplexKey(key);\n    } else if (typeof key !== 'number') {\n      key = \"[\".concat(options.inspect(key, options), \"]\");\n    }\n\n    options.truncate -= key.length;\n    value = options.inspect(value, options);\n    return \"\".concat(key, \": \").concat(value);\n  }\n\n  function inspectArray(array, options) {\n    // Object.keys will always output the Array indices first, so we can slice by\n    // `array.length` to get non-index properties\n    var nonIndexProperties = Object.keys(array).slice(array.length);\n    if (!array.length && !nonIndexProperties.length) return '[]';\n    options.truncate -= 4;\n    var listContents = inspectList(array, options);\n    options.truncate -= listContents.length;\n    var propertyContents = '';\n\n    if (nonIndexProperties.length) {\n      propertyContents = inspectList(nonIndexProperties.map(function (key) {\n        return [key, array[key]];\n      }), options, inspectProperty);\n    }\n\n    return \"[ \".concat(listContents).concat(propertyContents ? \", \".concat(propertyContents) : '', \" ]\");\n  }\n\n  /* !\n   * Chai - getFuncName utility\n   * Copyright(c) 2012-2016 Jake Luer <jake@alogicalparadox.com>\n   * MIT Licensed\n   */\n\n  /**\n   * ### .getFuncName(constructorFn)\n   *\n   * Returns the name of a function.\n   * When a non-function instance is passed, returns `null`.\n   * This also includes a polyfill function if `aFunc.name` is not defined.\n   *\n   * @name getFuncName\n   * @param {Function} funct\n   * @namespace Utils\n   * @api public\n   */\n\n  var toString = Function.prototype.toString;\n  var functionNameMatch = /\\s*function(?:\\s|\\s*\\/\\*[^(?:*\\/)]+\\*\\/\\s*)*([^\\s\\(\\/]+)/;\n  function getFuncName(aFunc) {\n    if (typeof aFunc !== 'function') {\n      return null;\n    }\n\n    var name = '';\n    if (typeof Function.prototype.name === 'undefined' && typeof aFunc.name === 'undefined') {\n      // Here we run a polyfill if Function does not support the `name` property and if aFunc.name is not defined\n      var match = toString.call(aFunc).match(functionNameMatch);\n      if (match) {\n        name = match[1];\n      }\n    } else {\n      // If we've got a `name` property we just use it\n      name = aFunc.name;\n    }\n\n    return name;\n  }\n\n  var getFuncName_1 = getFuncName;\n\n  var getArrayName = function getArrayName(array) {\n    // We need to special case Node.js' Buffers, which report to be Uint8Array\n    if (typeof Buffer === 'function' && array instanceof Buffer) {\n      return 'Buffer';\n    }\n\n    if (array[Symbol.toStringTag]) {\n      return array[Symbol.toStringTag];\n    }\n\n    return getFuncName_1(array.constructor);\n  };\n\n  function inspectTypedArray(array, options) {\n    var name = getArrayName(array);\n    options.truncate -= name.length + 4; // Object.keys will always output the Array indices first, so we can slice by\n    // `array.length` to get non-index properties\n\n    var nonIndexProperties = Object.keys(array).slice(array.length);\n    if (!array.length && !nonIndexProperties.length) return \"\".concat(name, \"[]\"); // As we know TypedArrays only contain Unsigned Integers, we can skip inspecting each one and simply\n    // stylise the toString() value of them\n\n    var output = '';\n\n    for (var i = 0; i < array.length; i++) {\n      var string = \"\".concat(options.stylize(truncate(array[i], options.truncate), 'number')).concat(i === array.length - 1 ? '' : ', ');\n      options.truncate -= string.length;\n\n      if (array[i] !== array.length && options.truncate <= 3) {\n        output += \"\".concat(truncator, \"(\").concat(array.length - array[i] + 1, \")\");\n        break;\n      }\n\n      output += string;\n    }\n\n    var propertyContents = '';\n\n    if (nonIndexProperties.length) {\n      propertyContents = inspectList(nonIndexProperties.map(function (key) {\n        return [key, array[key]];\n      }), options, inspectProperty);\n    }\n\n    return \"\".concat(name, \"[ \").concat(output).concat(propertyContents ? \", \".concat(propertyContents) : '', \" ]\");\n  }\n\n  function inspectDate(dateObject, options) {\n    // If we need to - truncate the time portion, but never the date\n    var split = dateObject.toJSON().split('T');\n    var date = split[0];\n    return options.stylize(\"\".concat(date, \"T\").concat(truncate(split[1], options.truncate - date.length - 1)), 'date');\n  }\n\n  function inspectFunction(func, options) {\n    var name = getFuncName_1(func);\n\n    if (!name) {\n      return options.stylize('[Function]', 'special');\n    }\n\n    return options.stylize(\"[Function \".concat(truncate(name, options.truncate - 11), \"]\"), 'special');\n  }\n\n  function inspectMapEntry(_ref, options) {\n    var _ref2 = _slicedToArray(_ref, 2),\n        key = _ref2[0],\n        value = _ref2[1];\n\n    options.truncate -= 4;\n    key = options.inspect(key, options);\n    options.truncate -= key.length;\n    value = options.inspect(value, options);\n    return \"\".concat(key, \" => \").concat(value);\n  } // IE11 doesn't support `map.entries()`\n\n\n  function mapToEntries(map) {\n    var entries = [];\n    map.forEach(function (value, key) {\n      entries.push([key, value]);\n    });\n    return entries;\n  }\n\n  function inspectMap(map, options) {\n    var size = map.size - 1;\n\n    if (size <= 0) {\n      return 'Map{}';\n    }\n\n    options.truncate -= 7;\n    return \"Map{ \".concat(inspectList(mapToEntries(map), options, inspectMapEntry), \" }\");\n  }\n\n  var isNaN = Number.isNaN || function (i) {\n    return i !== i;\n  }; // eslint-disable-line no-self-compare\n\n\n  function inspectNumber(number, options) {\n    if (isNaN(number)) {\n      return options.stylize('NaN', 'number');\n    }\n\n    if (number === Infinity) {\n      return options.stylize('Infinity', 'number');\n    }\n\n    if (number === -Infinity) {\n      return options.stylize('-Infinity', 'number');\n    }\n\n    if (number === 0) {\n      return options.stylize(1 / number === Infinity ? '+0' : '-0', 'number');\n    }\n\n    return options.stylize(truncate(number, options.truncate), 'number');\n  }\n\n  function inspectBigInt(number, options) {\n    var nums = truncate(number.toString(), options.truncate - 1);\n    if (nums !== truncator) nums += 'n';\n    return options.stylize(nums, 'bigint');\n  }\n\n  function inspectRegExp(value, options) {\n    var flags = value.toString().split('/')[2];\n    var sourceLength = options.truncate - (2 + flags.length);\n    var source = value.source;\n    return options.stylize(\"/\".concat(truncate(source, sourceLength), \"/\").concat(flags), 'regexp');\n  }\n\n  function arrayFromSet(set) {\n    var values = [];\n    set.forEach(function (value) {\n      values.push(value);\n    });\n    return values;\n  }\n\n  function inspectSet(set, options) {\n    if (set.size === 0) return 'Set{}';\n    options.truncate -= 7;\n    return \"Set{ \".concat(inspectList(arrayFromSet(set), options), \" }\");\n  }\n\n  var stringEscapeChars = new RegExp(\"['\\\\u0000-\\\\u001f\\\\u007f-\\\\u009f\\\\u00ad\\\\u0600-\\\\u0604\\\\u070f\\\\u17b4\\\\u17b5\" + \"\\\\u200c-\\\\u200f\\\\u2028-\\\\u202f\\\\u2060-\\\\u206f\\\\ufeff\\\\ufff0-\\\\uffff]\", 'g');\n  var escapeCharacters = {\n    '\\b': '\\\\b',\n    '\\t': '\\\\t',\n    '\\n': '\\\\n',\n    '\\f': '\\\\f',\n    '\\r': '\\\\r',\n    \"'\": \"\\\\'\",\n    '\\\\': '\\\\\\\\'\n  };\n  var hex = 16;\n  var unicodeLength = 4;\n\n  function escape(char) {\n    return escapeCharacters[char] || \"\\\\u\".concat(\"0000\".concat(char.charCodeAt(0).toString(hex)).slice(-unicodeLength));\n  }\n\n  function inspectString(string, options) {\n    if (stringEscapeChars.test(string)) {\n      string = string.replace(stringEscapeChars, escape);\n    }\n\n    return options.stylize(\"'\".concat(truncate(string, options.truncate - 2), \"'\"), 'string');\n  }\n\n  function inspectSymbol(value) {\n    if ('description' in Symbol.prototype) {\n      return value.description ? \"Symbol(\".concat(value.description, \")\") : 'Symbol()';\n    }\n\n    return value.toString();\n  }\n\n  var getPromiseValue = function getPromiseValue() {\n    return 'Promise{…}';\n  };\n\n  try {\n    var _process$binding = process.binding('util'),\n        getPromiseDetails = _process$binding.getPromiseDetails,\n        kPending = _process$binding.kPending,\n        kRejected = _process$binding.kRejected;\n\n    if (Array.isArray(getPromiseDetails(Promise.resolve()))) {\n      getPromiseValue = function getPromiseValue(value, options) {\n        var _getPromiseDetails = getPromiseDetails(value),\n            _getPromiseDetails2 = _slicedToArray(_getPromiseDetails, 2),\n            state = _getPromiseDetails2[0],\n            innerValue = _getPromiseDetails2[1];\n\n        if (state === kPending) {\n          return 'Promise{<pending>}';\n        }\n\n        return \"Promise\".concat(state === kRejected ? '!' : '', \"{\").concat(options.inspect(innerValue, options), \"}\");\n      };\n    }\n  } catch (notNode) {\n    /* ignore */\n  }\n\n  var inspectPromise = getPromiseValue;\n\n  function inspectObject(object, options) {\n    var properties = Object.getOwnPropertyNames(object);\n    var symbols = Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(object) : [];\n\n    if (properties.length === 0 && symbols.length === 0) {\n      return '{}';\n    }\n\n    options.truncate -= 4;\n    options.seen = options.seen || [];\n\n    if (options.seen.indexOf(object) >= 0) {\n      return '[Circular]';\n    }\n\n    options.seen.push(object);\n    var propertyContents = inspectList(properties.map(function (key) {\n      return [key, object[key]];\n    }), options, inspectProperty);\n    var symbolContents = inspectList(symbols.map(function (key) {\n      return [key, object[key]];\n    }), options, inspectProperty);\n    options.seen.pop();\n    var sep = '';\n\n    if (propertyContents && symbolContents) {\n      sep = ', ';\n    }\n\n    return \"{ \".concat(propertyContents).concat(sep).concat(symbolContents, \" }\");\n  }\n\n  var toStringTag = typeof Symbol !== 'undefined' && Symbol.toStringTag ? Symbol.toStringTag : false;\n  function inspectClass(value, options) {\n    var name = '';\n\n    if (toStringTag && toStringTag in value) {\n      name = value[toStringTag];\n    }\n\n    name = name || getFuncName_1(value.constructor); // Babel transforms anonymous classes to the name `_class`\n\n    if (!name || name === '_class') {\n      name = '<Anonymous Class>';\n    }\n\n    options.truncate -= name.length;\n    return \"\".concat(name).concat(inspectObject(value, options));\n  }\n\n  function inspectArguments(args, options) {\n    if (args.length === 0) return 'Arguments[]';\n    options.truncate -= 13;\n    return \"Arguments[ \".concat(inspectList(args, options), \" ]\");\n  }\n\n  var errorKeys = ['stack', 'line', 'column', 'name', 'message', 'fileName', 'lineNumber', 'columnNumber', 'number', 'description'];\n  function inspectObject$1(error, options) {\n    var properties = Object.getOwnPropertyNames(error).filter(function (key) {\n      return errorKeys.indexOf(key) === -1;\n    });\n    var name = error.name;\n    options.truncate -= name.length;\n    var message = '';\n\n    if (typeof error.message === 'string') {\n      message = truncate(error.message, options.truncate);\n    } else {\n      properties.unshift('message');\n    }\n\n    message = message ? \": \".concat(message) : '';\n    options.truncate -= message.length + 5;\n    var propertyContents = inspectList(properties.map(function (key) {\n      return [key, error[key]];\n    }), options, inspectProperty);\n    return \"\".concat(name).concat(message).concat(propertyContents ? \" { \".concat(propertyContents, \" }\") : '');\n  }\n\n  function inspectAttribute(_ref, options) {\n    var _ref2 = _slicedToArray(_ref, 2),\n        key = _ref2[0],\n        value = _ref2[1];\n\n    options.truncate -= 3;\n\n    if (!value) {\n      return \"\".concat(options.stylize(key, 'yellow'));\n    }\n\n    return \"\".concat(options.stylize(key, 'yellow'), \"=\").concat(options.stylize(\"\\\"\".concat(value, \"\\\"\"), 'string'));\n  }\n  function inspectHTMLCollection(collection, options) {\n    // eslint-disable-next-line no-use-before-define\n    return inspectList(collection, options, inspectHTML, '\\n');\n  }\n  function inspectHTML(element, options) {\n    var properties = element.getAttributeNames();\n    var name = element.tagName.toLowerCase();\n    var head = options.stylize(\"<\".concat(name), 'special');\n    var headClose = options.stylize(\">\", 'special');\n    var tail = options.stylize(\"</\".concat(name, \">\"), 'special');\n    options.truncate -= name.length * 2 + 5;\n    var propertyContents = '';\n\n    if (properties.length > 0) {\n      propertyContents += ' ';\n      propertyContents += inspectList(properties.map(function (key) {\n        return [key, element.getAttribute(key)];\n      }), options, inspectAttribute, ' ');\n    }\n\n    options.truncate -= propertyContents.length;\n    var truncate = options.truncate;\n    var children = inspectHTMLCollection(element.children, options);\n\n    if (children && children.length > truncate) {\n      children = \"\".concat(truncator, \"(\").concat(element.children.length, \")\");\n    }\n\n    return \"\".concat(head).concat(propertyContents).concat(headClose).concat(children).concat(tail);\n  }\n\n  var symbolsSupported = typeof Symbol === 'function' && typeof Symbol.for === 'function';\n  var chaiInspect = symbolsSupported ? Symbol.for('chai/inspect') : '@@chai/inspect';\n  var nodeInspect = false;\n\n  try {\n    // eslint-disable-next-line global-require\n    var nodeUtil = require('util');\n\n    nodeInspect = nodeUtil.inspect ? nodeUtil.inspect.custom : false;\n  } catch (noNodeInspect) {\n    nodeInspect = false;\n  }\n\n  var constructorMap = new WeakMap();\n  var stringTagMap = {};\n  var baseTypesMap = {\n    undefined: function undefined$1(value, options) {\n      return options.stylize('undefined', 'undefined');\n    },\n    null: function _null(value, options) {\n      return options.stylize(null, 'null');\n    },\n    boolean: function boolean(value, options) {\n      return options.stylize(value, 'boolean');\n    },\n    Boolean: function Boolean(value, options) {\n      return options.stylize(value, 'boolean');\n    },\n    number: inspectNumber,\n    Number: inspectNumber,\n    bigint: inspectBigInt,\n    BigInt: inspectBigInt,\n    string: inspectString,\n    String: inspectString,\n    function: inspectFunction,\n    Function: inspectFunction,\n    symbol: inspectSymbol,\n    // A Symbol polyfill will return `Symbol` not `symbol` from typedetect\n    Symbol: inspectSymbol,\n    Array: inspectArray,\n    Date: inspectDate,\n    Map: inspectMap,\n    Set: inspectSet,\n    RegExp: inspectRegExp,\n    Promise: inspectPromise,\n    // WeakSet, WeakMap are totally opaque to us\n    WeakSet: function WeakSet(value, options) {\n      return options.stylize('WeakSet{…}', 'special');\n    },\n    WeakMap: function WeakMap(value, options) {\n      return options.stylize('WeakMap{…}', 'special');\n    },\n    Arguments: inspectArguments,\n    Int8Array: inspectTypedArray,\n    Uint8Array: inspectTypedArray,\n    Uint8ClampedArray: inspectTypedArray,\n    Int16Array: inspectTypedArray,\n    Uint16Array: inspectTypedArray,\n    Int32Array: inspectTypedArray,\n    Uint32Array: inspectTypedArray,\n    Float32Array: inspectTypedArray,\n    Float64Array: inspectTypedArray,\n    Generator: function Generator() {\n      return '';\n    },\n    DataView: function DataView() {\n      return '';\n    },\n    ArrayBuffer: function ArrayBuffer() {\n      return '';\n    },\n    Error: inspectObject$1,\n    HTMLCollection: inspectHTMLCollection,\n    NodeList: inspectHTMLCollection\n  }; // eslint-disable-next-line complexity\n\n  var inspectCustom = function inspectCustom(value, options, type) {\n    if (chaiInspect in value && typeof value[chaiInspect] === 'function') {\n      return value[chaiInspect](options);\n    }\n\n    if (nodeInspect && nodeInspect in value && typeof value[nodeInspect] === 'function') {\n      return value[nodeInspect](options.depth, options);\n    }\n\n    if ('inspect' in value && typeof value.inspect === 'function') {\n      return value.inspect(options.depth, options);\n    }\n\n    if ('constructor' in value && constructorMap.has(value.constructor)) {\n      return constructorMap.get(value.constructor)(value, options);\n    }\n\n    if (stringTagMap[type]) {\n      return stringTagMap[type](value, options);\n    }\n\n    return '';\n  };\n\n  var toString$1 = Object.prototype.toString; // eslint-disable-next-line complexity\n\n  function inspect(value, options) {\n    options = normaliseOptions(options);\n    options.inspect = inspect;\n    var _options = options,\n        customInspect = _options.customInspect;\n    var type = value === null ? 'null' : _typeof(value);\n\n    if (type === 'object') {\n      type = toString$1.call(value).slice(8, -1);\n    } // If it is a base value that we already support, then use Loupe's inspector\n\n\n    if (baseTypesMap[type]) {\n      return baseTypesMap[type](value, options);\n    } // If `options.customInspect` is set to true then try to use the custom inspector\n\n\n    if (customInspect && value) {\n      var output = inspectCustom(value, options, type);\n\n      if (output) {\n        if (typeof output === 'string') return output;\n        return inspect(output, options);\n      }\n    }\n\n    var proto = value ? Object.getPrototypeOf(value) : false; // If it's a plain Object then use Loupe's inspector\n\n    if (proto === Object.prototype || proto === null) {\n      return inspectObject(value, options);\n    } // Specifically account for HTMLElements\n    // eslint-disable-next-line no-undef\n\n\n    if (value && typeof HTMLElement === 'function' && value instanceof HTMLElement) {\n      return inspectHTML(value, options);\n    }\n\n    if ('constructor' in value) {\n      // If it is a class, inspect it like an object but add the constructor name\n      if (value.constructor !== Object) {\n        return inspectClass(value, options);\n      } // If it is an object with an anonymous prototype, display it as an object.\n\n\n      return inspectObject(value, options);\n    } // We have run out of options! Just stringify the value\n\n\n    return options.stylize(String(value), type);\n  }\n  function registerConstructor(constructor, inspector) {\n    if (constructorMap.has(constructor)) {\n      return false;\n    }\n\n    constructorMap.add(constructor, inspector);\n    return true;\n  }\n  function registerStringTag(stringTag, inspector) {\n    if (stringTag in stringTagMap) {\n      return false;\n    }\n\n    stringTagMap[stringTag] = inspector;\n    return true;\n  }\n  var custom = chaiInspect;\n\n  exports.custom = custom;\n  exports.default = inspect;\n  exports.inspect = inspect;\n  exports.registerConstructor = registerConstructor;\n  exports.registerStringTag = registerStringTag;\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n})));\n\n},{\"util\":undefined}],38:[function(require,module,exports){\n'use strict';\n\n/* !\n * Chai - pathval utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * @see https://github.com/logicalparadox/filtr\n * MIT Licensed\n */\n\n/**\n * ### .hasProperty(object, name)\n *\n * This allows checking whether an object has own\n * or inherited from prototype chain named property.\n *\n * Basically does the same thing as the `in`\n * operator but works properly with null/undefined values\n * and other primitives.\n *\n *     var obj = {\n *         arr: ['a', 'b', 'c']\n *       , str: 'Hello'\n *     }\n *\n * The following would be the results.\n *\n *     hasProperty(obj, 'str');  // true\n *     hasProperty(obj, 'constructor');  // true\n *     hasProperty(obj, 'bar');  // false\n *\n *     hasProperty(obj.str, 'length'); // true\n *     hasProperty(obj.str, 1);  // true\n *     hasProperty(obj.str, 5);  // false\n *\n *     hasProperty(obj.arr, 'length');  // true\n *     hasProperty(obj.arr, 2);  // true\n *     hasProperty(obj.arr, 3);  // false\n *\n * @param {Object} object\n * @param {String|Symbol} name\n * @returns {Boolean} whether it exists\n * @namespace Utils\n * @name hasProperty\n * @api public\n */\n\nfunction hasProperty(obj, name) {\n  if (typeof obj === 'undefined' || obj === null) {\n    return false;\n  }\n\n  // The `in` operator does not work with primitives.\n  return name in Object(obj);\n}\n\n/* !\n * ## parsePath(path)\n *\n * Helper function used to parse string object\n * paths. Use in conjunction with `internalGetPathValue`.\n *\n *      var parsed = parsePath('myobject.property.subprop');\n *\n * ### Paths:\n *\n * * Can be infinitely deep and nested.\n * * Arrays are also valid using the formal `myobject.document[3].property`.\n * * Literal dots and brackets (not delimiter) must be backslash-escaped.\n *\n * @param {String} path\n * @returns {Object} parsed\n * @api private\n */\n\nfunction parsePath(path) {\n  var str = path.replace(/([^\\\\])\\[/g, '$1.[');\n  var parts = str.match(/(\\\\\\.|[^.]+?)+/g);\n  return parts.map(function mapMatches(value) {\n    if (\n      value === 'constructor' ||\n      value === '__proto__' ||\n      value === 'prototype'\n    ) {\n      return {};\n    }\n    var regexp = /^\\[(\\d+)\\]$/;\n    var mArr = regexp.exec(value);\n    var parsed = null;\n    if (mArr) {\n      parsed = { i: parseFloat(mArr[1]) };\n    } else {\n      parsed = { p: value.replace(/\\\\([.[\\]])/g, '$1') };\n    }\n\n    return parsed;\n  });\n}\n\n/* !\n * ## internalGetPathValue(obj, parsed[, pathDepth])\n *\n * Helper companion function for `.parsePath` that returns\n * the value located at the parsed address.\n *\n *      var value = getPathValue(obj, parsed);\n *\n * @param {Object} object to search against\n * @param {Object} parsed definition from `parsePath`.\n * @param {Number} depth (nesting level) of the property we want to retrieve\n * @returns {Object|Undefined} value\n * @api private\n */\n\nfunction internalGetPathValue(obj, parsed, pathDepth) {\n  var temporaryValue = obj;\n  var res = null;\n  pathDepth = typeof pathDepth === 'undefined' ? parsed.length : pathDepth;\n\n  for (var i = 0; i < pathDepth; i++) {\n    var part = parsed[i];\n    if (temporaryValue) {\n      if (typeof part.p === 'undefined') {\n        temporaryValue = temporaryValue[part.i];\n      } else {\n        temporaryValue = temporaryValue[part.p];\n      }\n\n      if (i === pathDepth - 1) {\n        res = temporaryValue;\n      }\n    }\n  }\n\n  return res;\n}\n\n/* !\n * ## internalSetPathValue(obj, value, parsed)\n *\n * Companion function for `parsePath` that sets\n * the value located at a parsed address.\n *\n *  internalSetPathValue(obj, 'value', parsed);\n *\n * @param {Object} object to search and define on\n * @param {*} value to use upon set\n * @param {Object} parsed definition from `parsePath`\n * @api private\n */\n\nfunction internalSetPathValue(obj, val, parsed) {\n  var tempObj = obj;\n  var pathDepth = parsed.length;\n  var part = null;\n  // Here we iterate through every part of the path\n  for (var i = 0; i < pathDepth; i++) {\n    var propName = null;\n    var propVal = null;\n    part = parsed[i];\n\n    // If it's the last part of the path, we set the 'propName' value with the property name\n    if (i === pathDepth - 1) {\n      propName = typeof part.p === 'undefined' ? part.i : part.p;\n      // Now we set the property with the name held by 'propName' on object with the desired val\n      tempObj[propName] = val;\n    } else if (typeof part.p !== 'undefined' && tempObj[part.p]) {\n      tempObj = tempObj[part.p];\n    } else if (typeof part.i !== 'undefined' && tempObj[part.i]) {\n      tempObj = tempObj[part.i];\n    } else {\n      // If the obj doesn't have the property we create one with that name to define it\n      var next = parsed[i + 1];\n      // Here we set the name of the property which will be defined\n      propName = typeof part.p === 'undefined' ? part.i : part.p;\n      // Here we decide if this property will be an array or a new object\n      propVal = typeof next.p === 'undefined' ? [] : {};\n      tempObj[propName] = propVal;\n      tempObj = tempObj[propName];\n    }\n  }\n}\n\n/**\n * ### .getPathInfo(object, path)\n *\n * This allows the retrieval of property info in an\n * object given a string path.\n *\n * The path info consists of an object with the\n * following properties:\n *\n * * parent - The parent object of the property referenced by `path`\n * * name - The name of the final property, a number if it was an array indexer\n * * value - The value of the property, if it exists, otherwise `undefined`\n * * exists - Whether the property exists or not\n *\n * @param {Object} object\n * @param {String} path\n * @returns {Object} info\n * @namespace Utils\n * @name getPathInfo\n * @api public\n */\n\nfunction getPathInfo(obj, path) {\n  var parsed = parsePath(path);\n  var last = parsed[parsed.length - 1];\n  var info = {\n    parent:\n      parsed.length > 1 ?\n        internalGetPathValue(obj, parsed, parsed.length - 1) :\n        obj,\n    name: last.p || last.i,\n    value: internalGetPathValue(obj, parsed),\n  };\n  info.exists = hasProperty(info.parent, info.name);\n\n  return info;\n}\n\n/**\n * ### .getPathValue(object, path)\n *\n * This allows the retrieval of values in an\n * object given a string path.\n *\n *     var obj = {\n *         prop1: {\n *             arr: ['a', 'b', 'c']\n *           , str: 'Hello'\n *         }\n *       , prop2: {\n *             arr: [ { nested: 'Universe' } ]\n *           , str: 'Hello again!'\n *         }\n *     }\n *\n * The following would be the results.\n *\n *     getPathValue(obj, 'prop1.str'); // Hello\n *     getPathValue(obj, 'prop1.att[2]'); // b\n *     getPathValue(obj, 'prop2.arr[0].nested'); // Universe\n *\n * @param {Object} object\n * @param {String} path\n * @returns {Object} value or `undefined`\n * @namespace Utils\n * @name getPathValue\n * @api public\n */\n\nfunction getPathValue(obj, path) {\n  var info = getPathInfo(obj, path);\n  return info.value;\n}\n\n/**\n * ### .setPathValue(object, path, value)\n *\n * Define the value in an object at a given string path.\n *\n * ```js\n * var obj = {\n *     prop1: {\n *         arr: ['a', 'b', 'c']\n *       , str: 'Hello'\n *     }\n *   , prop2: {\n *         arr: [ { nested: 'Universe' } ]\n *       , str: 'Hello again!'\n *     }\n * };\n * ```\n *\n * The following would be acceptable.\n *\n * ```js\n * var properties = require('tea-properties');\n * properties.set(obj, 'prop1.str', 'Hello Universe!');\n * properties.set(obj, 'prop1.arr[2]', 'B');\n * properties.set(obj, 'prop2.arr[0].nested.value', { hello: 'universe' });\n * ```\n *\n * @param {Object} object\n * @param {String} path\n * @param {Mixed} value\n * @api private\n */\n\nfunction setPathValue(obj, path, val) {\n  var parsed = parsePath(path);\n  internalSetPathValue(obj, val, parsed);\n  return obj;\n}\n\nmodule.exports = {\n  hasProperty: hasProperty,\n  getPathInfo: getPathInfo,\n  getPathValue: getPathValue,\n  setPathValue: setPathValue,\n};\n\n},{}],39:[function(require,module,exports){\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n\ttypeof define === 'function' && define.amd ? define(factory) :\n\t(global.typeDetect = factory());\n}(this, (function () { 'use strict';\n\n/* !\n * type-detect\n * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\nvar promiseExists = typeof Promise === 'function';\n\n/* eslint-disable no-undef */\nvar globalObject = typeof self === 'object' ? self : global; // eslint-disable-line id-blacklist\n\nvar symbolExists = typeof Symbol !== 'undefined';\nvar mapExists = typeof Map !== 'undefined';\nvar setExists = typeof Set !== 'undefined';\nvar weakMapExists = typeof WeakMap !== 'undefined';\nvar weakSetExists = typeof WeakSet !== 'undefined';\nvar dataViewExists = typeof DataView !== 'undefined';\nvar symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';\nvar symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';\nvar setEntriesExists = setExists && typeof Set.prototype.entries === 'function';\nvar mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';\nvar setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());\nvar mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());\nvar arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';\nvar arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());\nvar stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function';\nvar stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());\nvar toStringLeftSliceLength = 8;\nvar toStringRightSliceLength = -1;\n/**\n * ### typeOf (obj)\n *\n * Uses `Object.prototype.toString` to determine the type of an object,\n * normalising behaviour across engine versions & well optimised.\n *\n * @param {Mixed} object\n * @return {String} object type\n * @api public\n */\nfunction typeDetect(obj) {\n  /* ! Speed optimisation\n   * Pre:\n   *   string literal     x 3,039,035 ops/sec ±1.62% (78 runs sampled)\n   *   boolean literal    x 1,424,138 ops/sec ±4.54% (75 runs sampled)\n   *   number literal     x 1,653,153 ops/sec ±1.91% (82 runs sampled)\n   *   undefined          x 9,978,660 ops/sec ±1.92% (75 runs sampled)\n   *   function           x 2,556,769 ops/sec ±1.73% (77 runs sampled)\n   * Post:\n   *   string literal     x 38,564,796 ops/sec ±1.15% (79 runs sampled)\n   *   boolean literal    x 31,148,940 ops/sec ±1.10% (79 runs sampled)\n   *   number literal     x 32,679,330 ops/sec ±1.90% (78 runs sampled)\n   *   undefined          x 32,363,368 ops/sec ±1.07% (82 runs sampled)\n   *   function           x 31,296,870 ops/sec ±0.96% (83 runs sampled)\n   */\n  var typeofObj = typeof obj;\n  if (typeofObj !== 'object') {\n    return typeofObj;\n  }\n\n  /* ! Speed optimisation\n   * Pre:\n   *   null               x 28,645,765 ops/sec ±1.17% (82 runs sampled)\n   * Post:\n   *   null               x 36,428,962 ops/sec ±1.37% (84 runs sampled)\n   */\n  if (obj === null) {\n    return 'null';\n  }\n\n  /* ! Spec Conformance\n   * Test: `Object.prototype.toString.call(window)``\n   *  - Node === \"[object global]\"\n   *  - Chrome === \"[object global]\"\n   *  - Firefox === \"[object Window]\"\n   *  - PhantomJS === \"[object Window]\"\n   *  - Safari === \"[object Window]\"\n   *  - IE 11 === \"[object Window]\"\n   *  - IE Edge === \"[object Window]\"\n   * Test: `Object.prototype.toString.call(this)``\n   *  - Chrome Worker === \"[object global]\"\n   *  - Firefox Worker === \"[object DedicatedWorkerGlobalScope]\"\n   *  - Safari Worker === \"[object DedicatedWorkerGlobalScope]\"\n   *  - IE 11 Worker === \"[object WorkerGlobalScope]\"\n   *  - IE Edge Worker === \"[object WorkerGlobalScope]\"\n   */\n  if (obj === globalObject) {\n    return 'global';\n  }\n\n  /* ! Speed optimisation\n   * Pre:\n   *   array literal      x 2,888,352 ops/sec ±0.67% (82 runs sampled)\n   * Post:\n   *   array literal      x 22,479,650 ops/sec ±0.96% (81 runs sampled)\n   */\n  if (\n    Array.isArray(obj) &&\n    (symbolToStringTagExists === false || !(Symbol.toStringTag in obj))\n  ) {\n    return 'Array';\n  }\n\n  // Not caching existence of `window` and related properties due to potential\n  // for `window` to be unset before tests in quasi-browser environments.\n  if (typeof window === 'object' && window !== null) {\n    /* ! Spec Conformance\n     * (https://html.spec.whatwg.org/multipage/browsers.html#location)\n     * WhatWG HTML$7.7.3 - The `Location` interface\n     * Test: `Object.prototype.toString.call(window.location)``\n     *  - IE <=11 === \"[object Object]\"\n     *  - IE Edge <=13 === \"[object Object]\"\n     */\n    if (typeof window.location === 'object' && obj === window.location) {\n      return 'Location';\n    }\n\n    /* ! Spec Conformance\n     * (https://html.spec.whatwg.org/#document)\n     * WhatWG HTML$3.1.1 - The `Document` object\n     * Note: Most browsers currently adher to the W3C DOM Level 2 spec\n     *       (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)\n     *       which suggests that browsers should use HTMLTableCellElement for\n     *       both TD and TH elements. WhatWG separates these.\n     *       WhatWG HTML states:\n     *         > For historical reasons, Window objects must also have a\n     *         > writable, configurable, non-enumerable property named\n     *         > HTMLDocument whose value is the Document interface object.\n     * Test: `Object.prototype.toString.call(document)``\n     *  - Chrome === \"[object HTMLDocument]\"\n     *  - Firefox === \"[object HTMLDocument]\"\n     *  - Safari === \"[object HTMLDocument]\"\n     *  - IE <=10 === \"[object Document]\"\n     *  - IE 11 === \"[object HTMLDocument]\"\n     *  - IE Edge <=13 === \"[object HTMLDocument]\"\n     */\n    if (typeof window.document === 'object' && obj === window.document) {\n      return 'Document';\n    }\n\n    if (typeof window.navigator === 'object') {\n      /* ! Spec Conformance\n       * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)\n       * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray\n       * Test: `Object.prototype.toString.call(navigator.mimeTypes)``\n       *  - IE <=10 === \"[object MSMimeTypesCollection]\"\n       */\n      if (typeof window.navigator.mimeTypes === 'object' &&\n          obj === window.navigator.mimeTypes) {\n        return 'MimeTypeArray';\n      }\n\n      /* ! Spec Conformance\n       * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)\n       * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray\n       * Test: `Object.prototype.toString.call(navigator.plugins)``\n       *  - IE <=10 === \"[object MSPluginsCollection]\"\n       */\n      if (typeof window.navigator.plugins === 'object' &&\n          obj === window.navigator.plugins) {\n        return 'PluginArray';\n      }\n    }\n\n    if ((typeof window.HTMLElement === 'function' ||\n        typeof window.HTMLElement === 'object') &&\n        obj instanceof window.HTMLElement) {\n      /* ! Spec Conformance\n      * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)\n      * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`\n      * Test: `Object.prototype.toString.call(document.createElement('blockquote'))``\n      *  - IE <=10 === \"[object HTMLBlockElement]\"\n      */\n      if (obj.tagName === 'BLOCKQUOTE') {\n        return 'HTMLQuoteElement';\n      }\n\n      /* ! Spec Conformance\n       * (https://html.spec.whatwg.org/#htmltabledatacellelement)\n       * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`\n       * Note: Most browsers currently adher to the W3C DOM Level 2 spec\n       *       (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)\n       *       which suggests that browsers should use HTMLTableCellElement for\n       *       both TD and TH elements. WhatWG separates these.\n       * Test: Object.prototype.toString.call(document.createElement('td'))\n       *  - Chrome === \"[object HTMLTableCellElement]\"\n       *  - Firefox === \"[object HTMLTableCellElement]\"\n       *  - Safari === \"[object HTMLTableCellElement]\"\n       */\n      if (obj.tagName === 'TD') {\n        return 'HTMLTableDataCellElement';\n      }\n\n      /* ! Spec Conformance\n       * (https://html.spec.whatwg.org/#htmltableheadercellelement)\n       * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`\n       * Note: Most browsers currently adher to the W3C DOM Level 2 spec\n       *       (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)\n       *       which suggests that browsers should use HTMLTableCellElement for\n       *       both TD and TH elements. WhatWG separates these.\n       * Test: Object.prototype.toString.call(document.createElement('th'))\n       *  - Chrome === \"[object HTMLTableCellElement]\"\n       *  - Firefox === \"[object HTMLTableCellElement]\"\n       *  - Safari === \"[object HTMLTableCellElement]\"\n       */\n      if (obj.tagName === 'TH') {\n        return 'HTMLTableHeaderCellElement';\n      }\n    }\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   Float64Array       x 625,644 ops/sec ±1.58% (80 runs sampled)\n  *   Float32Array       x 1,279,852 ops/sec ±2.91% (77 runs sampled)\n  *   Uint32Array        x 1,178,185 ops/sec ±1.95% (83 runs sampled)\n  *   Uint16Array        x 1,008,380 ops/sec ±2.25% (80 runs sampled)\n  *   Uint8Array         x 1,128,040 ops/sec ±2.11% (81 runs sampled)\n  *   Int32Array         x 1,170,119 ops/sec ±2.88% (80 runs sampled)\n  *   Int16Array         x 1,176,348 ops/sec ±5.79% (86 runs sampled)\n  *   Int8Array          x 1,058,707 ops/sec ±4.94% (77 runs sampled)\n  *   Uint8ClampedArray  x 1,110,633 ops/sec ±4.20% (80 runs sampled)\n  * Post:\n  *   Float64Array       x 7,105,671 ops/sec ±13.47% (64 runs sampled)\n  *   Float32Array       x 5,887,912 ops/sec ±1.46% (82 runs sampled)\n  *   Uint32Array        x 6,491,661 ops/sec ±1.76% (79 runs sampled)\n  *   Uint16Array        x 6,559,795 ops/sec ±1.67% (82 runs sampled)\n  *   Uint8Array         x 6,463,966 ops/sec ±1.43% (85 runs sampled)\n  *   Int32Array         x 5,641,841 ops/sec ±3.49% (81 runs sampled)\n  *   Int16Array         x 6,583,511 ops/sec ±1.98% (80 runs sampled)\n  *   Int8Array          x 6,606,078 ops/sec ±1.74% (81 runs sampled)\n  *   Uint8ClampedArray  x 6,602,224 ops/sec ±1.77% (83 runs sampled)\n  */\n  var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);\n  if (typeof stringTag === 'string') {\n    return stringTag;\n  }\n\n  var objPrototype = Object.getPrototypeOf(obj);\n  /* ! Speed optimisation\n  * Pre:\n  *   regex literal      x 1,772,385 ops/sec ±1.85% (77 runs sampled)\n  *   regex constructor  x 2,143,634 ops/sec ±2.46% (78 runs sampled)\n  * Post:\n  *   regex literal      x 3,928,009 ops/sec ±0.65% (78 runs sampled)\n  *   regex constructor  x 3,931,108 ops/sec ±0.58% (84 runs sampled)\n  */\n  if (objPrototype === RegExp.prototype) {\n    return 'RegExp';\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   date               x 2,130,074 ops/sec ±4.42% (68 runs sampled)\n  * Post:\n  *   date               x 3,953,779 ops/sec ±1.35% (77 runs sampled)\n  */\n  if (objPrototype === Date.prototype) {\n    return 'Date';\n  }\n\n  /* ! Spec Conformance\n   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)\n   * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be \"Promise\":\n   * Test: `Object.prototype.toString.call(Promise.resolve())``\n   *  - Chrome <=47 === \"[object Object]\"\n   *  - Edge <=20 === \"[object Object]\"\n   *  - Firefox 29-Latest === \"[object Promise]\"\n   *  - Safari 7.1-Latest === \"[object Promise]\"\n   */\n  if (promiseExists && objPrototype === Promise.prototype) {\n    return 'Promise';\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   set                x 2,222,186 ops/sec ±1.31% (82 runs sampled)\n  * Post:\n  *   set                x 4,545,879 ops/sec ±1.13% (83 runs sampled)\n  */\n  if (setExists && objPrototype === Set.prototype) {\n    return 'Set';\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   map                x 2,396,842 ops/sec ±1.59% (81 runs sampled)\n  * Post:\n  *   map                x 4,183,945 ops/sec ±6.59% (82 runs sampled)\n  */\n  if (mapExists && objPrototype === Map.prototype) {\n    return 'Map';\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   weakset            x 1,323,220 ops/sec ±2.17% (76 runs sampled)\n  * Post:\n  *   weakset            x 4,237,510 ops/sec ±2.01% (77 runs sampled)\n  */\n  if (weakSetExists && objPrototype === WeakSet.prototype) {\n    return 'WeakSet';\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   weakmap            x 1,500,260 ops/sec ±2.02% (78 runs sampled)\n  * Post:\n  *   weakmap            x 3,881,384 ops/sec ±1.45% (82 runs sampled)\n  */\n  if (weakMapExists && objPrototype === WeakMap.prototype) {\n    return 'WeakMap';\n  }\n\n  /* ! Spec Conformance\n   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)\n   * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be \"DataView\":\n   * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``\n   *  - Edge <=13 === \"[object Object]\"\n   */\n  if (dataViewExists && objPrototype === DataView.prototype) {\n    return 'DataView';\n  }\n\n  /* ! Spec Conformance\n   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)\n   * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be \"Map Iterator\":\n   * Test: `Object.prototype.toString.call(new Map().entries())``\n   *  - Edge <=13 === \"[object Object]\"\n   */\n  if (mapExists && objPrototype === mapIteratorPrototype) {\n    return 'Map Iterator';\n  }\n\n  /* ! Spec Conformance\n   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)\n   * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be \"Set Iterator\":\n   * Test: `Object.prototype.toString.call(new Set().entries())``\n   *  - Edge <=13 === \"[object Object]\"\n   */\n  if (setExists && objPrototype === setIteratorPrototype) {\n    return 'Set Iterator';\n  }\n\n  /* ! Spec Conformance\n   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)\n   * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be \"Array Iterator\":\n   * Test: `Object.prototype.toString.call([][Symbol.iterator]())``\n   *  - Edge <=13 === \"[object Object]\"\n   */\n  if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {\n    return 'Array Iterator';\n  }\n\n  /* ! Spec Conformance\n   * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)\n   * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be \"String Iterator\":\n   * Test: `Object.prototype.toString.call(''[Symbol.iterator]())``\n   *  - Edge <=13 === \"[object Object]\"\n   */\n  if (stringIteratorExists && objPrototype === stringIteratorPrototype) {\n    return 'String Iterator';\n  }\n\n  /* ! Speed optimisation\n  * Pre:\n  *   object from null   x 2,424,320 ops/sec ±1.67% (76 runs sampled)\n  * Post:\n  *   object from null   x 5,838,000 ops/sec ±0.99% (84 runs sampled)\n  */\n  if (objPrototype === null) {\n    return 'Object';\n  }\n\n  return Object\n    .prototype\n    .toString\n    .call(obj)\n    .slice(toStringLeftSliceLength, toStringRightSliceLength);\n}\n\nreturn typeDetect;\n\n})));\n\n},{}]},{},[1])(1)\n});\n"
  },
  {
    "path": "public/tests/lib/mocha/mocha.css",
    "content": "@charset \"utf-8\";\n\nbody {\n  margin:0;\n}\n\n#mocha {\n  font: 20px/1.5 \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  margin: 60px 50px;\n}\n\n#mocha ul,\n#mocha li {\n  margin: 0;\n  padding: 0;\n}\n\n#mocha ul {\n  list-style: none;\n}\n\n#mocha h1,\n#mocha h2 {\n  margin: 0;\n}\n\n#mocha h1 {\n  margin-top: 15px;\n  font-size: 1em;\n  font-weight: 200;\n}\n\n#mocha h1 a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha h1 a:hover {\n  text-decoration: underline;\n}\n\n#mocha .suite .suite h1 {\n  margin-top: 0;\n  font-size: .8em;\n}\n\n#mocha .hidden {\n  display: none;\n}\n\n#mocha h2 {\n  font-size: 12px;\n  font-weight: normal;\n  cursor: pointer;\n}\n\n#mocha .suite {\n  margin-left: 15px;\n}\n\n#mocha .test {\n  margin-left: 15px;\n  overflow: hidden;\n}\n\n#mocha .test.pending:hover h2::after {\n  content: '(pending)';\n  font-family: arial, sans-serif;\n}\n\n#mocha .test.pass.medium .duration {\n  background: #c09853;\n}\n\n#mocha .test.pass.slow .duration {\n  background: #b94a48;\n}\n\n#mocha .test.pass::before {\n  content: '✓';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #00d6b2;\n}\n\n#mocha .test.pass .duration {\n  font-size: 9px;\n  margin-left: 5px;\n  padding: 2px 5px;\n  color: #fff;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n  -ms-border-radius: 5px;\n  -o-border-radius: 5px;\n  border-radius: 5px;\n}\n\n#mocha .test.pass.fast .duration {\n  display: none;\n}\n\n#mocha .test.pending {\n  color: #0b97c4;\n}\n\n#mocha .test.pending::before {\n  content: '◦';\n  color: #0b97c4;\n}\n\n#mocha .test.fail {\n  color: #c00;\n}\n\n#mocha .test.fail pre {\n  color: black;\n}\n\n#mocha .test.fail::before {\n  content: '✖';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #c00;\n}\n\n#mocha .test pre.error {\n  color: #c00;\n  max-height: 300px;\n  overflow: auto;\n}\n\n#mocha .test .html-error {\n  overflow: auto;\n  color: black;\n  display: block;\n  float: left;\n  clear: left;\n  font: 12px/1.5 monaco, monospace;\n  margin: 5px;\n  padding: 15px;\n  border: 1px solid #eee;\n  max-width: 85%; /*(1)*/\n  max-width: -webkit-calc(100% - 42px);\n  max-width: -moz-calc(100% - 42px);\n  max-width: calc(100% - 42px); /*(2)*/\n  max-height: 300px;\n  word-wrap: break-word;\n  border-bottom-color: #ddd;\n  -webkit-box-shadow: 0 1px 3px #eee;\n  -moz-box-shadow: 0 1px 3px #eee;\n  box-shadow: 0 1px 3px #eee;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n}\n\n#mocha .test .html-error pre.error {\n  border: none;\n  -webkit-border-radius: 0;\n  -moz-border-radius: 0;\n  border-radius: 0;\n  -webkit-box-shadow: 0;\n  -moz-box-shadow: 0;\n  box-shadow: 0;\n  padding: 0;\n  margin: 0;\n  margin-top: 18px;\n  max-height: none;\n}\n\n/**\n * (1): approximate for browsers not supporting calc\n * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)\n *      ^^ seriously\n */\n#mocha .test pre {\n  display: block;\n  float: left;\n  clear: left;\n  font: 12px/1.5 monaco, monospace;\n  margin: 5px;\n  padding: 15px;\n  border: 1px solid #eee;\n  max-width: 85%; /*(1)*/\n  max-width: -webkit-calc(100% - 42px);\n  max-width: -moz-calc(100% - 42px);\n  max-width: calc(100% - 42px); /*(2)*/\n  word-wrap: break-word;\n  border-bottom-color: #ddd;\n  -webkit-box-shadow: 0 1px 3px #eee;\n  -moz-box-shadow: 0 1px 3px #eee;\n  box-shadow: 0 1px 3px #eee;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n}\n\n#mocha .test h2 {\n  position: relative;\n}\n\n#mocha .test a.replay {\n  position: absolute;\n  top: 3px;\n  right: 0;\n  text-decoration: none;\n  vertical-align: middle;\n  display: block;\n  width: 15px;\n  height: 15px;\n  line-height: 15px;\n  text-align: center;\n  background: #eee;\n  font-size: 15px;\n  -webkit-border-radius: 15px;\n  -moz-border-radius: 15px;\n  border-radius: 15px;\n  -webkit-transition:opacity 200ms;\n  -moz-transition:opacity 200ms;\n  -o-transition:opacity 200ms;\n  transition: opacity 200ms;\n  opacity: 0.3;\n  color: #888;\n}\n\n#mocha .test:hover a.replay {\n  opacity: 1;\n}\n\n#mocha-report.pass .test.fail {\n  display: none;\n}\n\n#mocha-report.fail .test.pass {\n  display: none;\n}\n\n#mocha-report.pending .test.pass,\n#mocha-report.pending .test.fail {\n  display: none;\n}\n#mocha-report.pending .test.pass.pending {\n  display: block;\n}\n\n#mocha-error {\n  color: #c00;\n  font-size: 1.5em;\n  font-weight: 100;\n  letter-spacing: 1px;\n}\n\n#mocha-stats {\n  position: fixed;\n  top: 15px;\n  right: 10px;\n  font-size: 12px;\n  margin: 0;\n  color: #888;\n  z-index: 1;\n}\n\n#mocha-stats .progress {\n  float: right;\n  padding-top: 0;\n\n  /**\n   * Set safe initial values, so mochas .progress does not inherit these\n   * properties from Bootstrap .progress (which causes .progress height to\n   * equal line height set in Bootstrap).\n   */\n  height: auto;\n  -webkit-box-shadow: none;\n  -moz-box-shadow: none;\n  box-shadow: none;\n  background-color: initial;\n}\n\n#mocha-stats em {\n  color: black;\n}\n\n#mocha-stats a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha-stats a:hover {\n  border-bottom: 1px solid #eee;\n}\n\n#mocha-stats li {\n  display: inline-block;\n  margin: 0 5px;\n  list-style: none;\n  padding-top: 11px;\n}\n\n#mocha-stats canvas {\n  width: 40px;\n  height: 40px;\n}\n\n#mocha code .comment { color: #ddd; }\n#mocha code .init { color: #2f6fad; }\n#mocha code .string { color: #5890ad; }\n#mocha code .keyword { color: #8a6343; }\n#mocha code .number { color: #2f6fad; }\n\n@media screen and (max-device-width: 480px) {\n  #mocha {\n    margin: 60px 0px;\n  }\n\n  #mocha #stats {\n    position: absolute;\n  }\n}\n"
  },
  {
    "path": "public/tests/lib/mocha/mocha.js",
    "content": "// mocha@9.2.2 transpiled to javascript ES5\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n\ttypeof define === 'function' && define.amd ? define(factory) :\n\t(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mocha = factory());\n})(this, (function () { 'use strict';\n\n\tvar regeneratorRuntime;\n\n\tvar commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n\n\tfunction createCommonjsModule(fn, basedir, module) {\n\t\treturn module = {\n\t\t  path: basedir,\n\t\t  exports: {},\n\t\t  require: function (path, base) {\n\t      return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);\n\t    }\n\t\t}, fn(module, module.exports), module.exports;\n\t}\n\n\tfunction getCjsExportFromNamespace (n) {\n\t\treturn n && n['default'] || n;\n\t}\n\n\tfunction commonjsRequire () {\n\t\tthrow new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');\n\t}\n\n\tvar check = function (it) {\n\t  return it && it.Math == Math && it;\n\t};\n\n\t// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\n\tvar global_1 =\n\t  // eslint-disable-next-line es/no-global-this -- safe\n\t  check(typeof globalThis == 'object' && globalThis) ||\n\t  check(typeof window == 'object' && window) ||\n\t  // eslint-disable-next-line no-restricted-globals -- safe\n\t  check(typeof self == 'object' && self) ||\n\t  check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||\n\t  // eslint-disable-next-line no-new-func -- fallback\n\t  (function () { return this; })() || Function('return this')();\n\n\tvar fails = function (exec) {\n\t  try {\n\t    return !!exec();\n\t  } catch (error) {\n\t    return true;\n\t  }\n\t};\n\n\t// Detect IE8's incomplete defineProperty implementation\n\tvar descriptors = !fails(function () {\n\t  // eslint-disable-next-line es/no-object-defineproperty -- required for testing\n\t  return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;\n\t});\n\n\tvar functionBindNative = !fails(function () {\n\t  var test = (function () { /* empty */ }).bind();\n\t  // eslint-disable-next-line no-prototype-builtins -- safe\n\t  return typeof test != 'function' || test.hasOwnProperty('prototype');\n\t});\n\n\tvar call$2 = Function.prototype.call;\n\n\tvar functionCall = functionBindNative ? call$2.bind(call$2) : function () {\n\t  return call$2.apply(call$2, arguments);\n\t};\n\n\tvar $propertyIsEnumerable$2 = {}.propertyIsEnumerable;\n\t// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\n\tvar getOwnPropertyDescriptor$3 = Object.getOwnPropertyDescriptor;\n\n\t// Nashorn ~ JDK8 bug\n\tvar NASHORN_BUG = getOwnPropertyDescriptor$3 && !$propertyIsEnumerable$2.call({ 1: 2 }, 1);\n\n\t// `Object.prototype.propertyIsEnumerable` method implementation\n\t// https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable\n\tvar f$8 = NASHORN_BUG ? function propertyIsEnumerable(V) {\n\t  var descriptor = getOwnPropertyDescriptor$3(this, V);\n\t  return !!descriptor && descriptor.enumerable;\n\t} : $propertyIsEnumerable$2;\n\n\tvar objectPropertyIsEnumerable = {\n\t\tf: f$8\n\t};\n\n\tvar createPropertyDescriptor = function (bitmap, value) {\n\t  return {\n\t    enumerable: !(bitmap & 1),\n\t    configurable: !(bitmap & 2),\n\t    writable: !(bitmap & 4),\n\t    value: value\n\t  };\n\t};\n\n\tvar FunctionPrototype$3 = Function.prototype;\n\tvar bind$2 = FunctionPrototype$3.bind;\n\tvar call$1 = FunctionPrototype$3.call;\n\tvar uncurryThis = functionBindNative && bind$2.bind(call$1, call$1);\n\n\tvar functionUncurryThis = functionBindNative ? function (fn) {\n\t  return fn && uncurryThis(fn);\n\t} : function (fn) {\n\t  return fn && function () {\n\t    return call$1.apply(fn, arguments);\n\t  };\n\t};\n\n\tvar toString$4 = functionUncurryThis({}.toString);\n\tvar stringSlice$8 = functionUncurryThis(''.slice);\n\n\tvar classofRaw = function (it) {\n\t  return stringSlice$8(toString$4(it), 8, -1);\n\t};\n\n\tvar Object$5 = global_1.Object;\n\tvar split = functionUncurryThis(''.split);\n\n\t// fallback for non-array-like ES3 and non-enumerable old V8 strings\n\tvar indexedObject = fails(function () {\n\t  // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346\n\t  // eslint-disable-next-line no-prototype-builtins -- safe\n\t  return !Object$5('z').propertyIsEnumerable(0);\n\t}) ? function (it) {\n\t  return classofRaw(it) == 'String' ? split(it, '') : Object$5(it);\n\t} : Object$5;\n\n\tvar TypeError$m = global_1.TypeError;\n\n\t// `RequireObjectCoercible` abstract operation\n\t// https://tc39.es/ecma262/#sec-requireobjectcoercible\n\tvar requireObjectCoercible = function (it) {\n\t  if (it == undefined) throw TypeError$m(\"Can't call method on \" + it);\n\t  return it;\n\t};\n\n\t// toObject with fallback for non-array-like ES3 strings\n\n\n\n\tvar toIndexedObject = function (it) {\n\t  return indexedObject(requireObjectCoercible(it));\n\t};\n\n\t// `IsCallable` abstract operation\n\t// https://tc39.es/ecma262/#sec-iscallable\n\tvar isCallable = function (argument) {\n\t  return typeof argument == 'function';\n\t};\n\n\tvar isObject$1 = function (it) {\n\t  return typeof it == 'object' ? it !== null : isCallable(it);\n\t};\n\n\tvar aFunction = function (argument) {\n\t  return isCallable(argument) ? argument : undefined;\n\t};\n\n\tvar getBuiltIn = function (namespace, method) {\n\t  return arguments.length < 2 ? aFunction(global_1[namespace]) : global_1[namespace] && global_1[namespace][method];\n\t};\n\n\tvar objectIsPrototypeOf = functionUncurryThis({}.isPrototypeOf);\n\n\tvar engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';\n\n\tvar process$5 = global_1.process;\n\tvar Deno = global_1.Deno;\n\tvar versions$2 = process$5 && process$5.versions || Deno && Deno.version;\n\tvar v8 = versions$2 && versions$2.v8;\n\tvar match, version$3;\n\n\tif (v8) {\n\t  match = v8.split('.');\n\t  // in old Chrome, versions of V8 isn't V8 = Chrome / 10\n\t  // but their correct versions are not interesting for us\n\t  version$3 = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]);\n\t}\n\n\t// BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`\n\t// so check `userAgent` even if `.v8` exists, but 0\n\tif (!version$3 && engineUserAgent) {\n\t  match = engineUserAgent.match(/Edge\\/(\\d+)/);\n\t  if (!match || match[1] >= 74) {\n\t    match = engineUserAgent.match(/Chrome\\/(\\d+)/);\n\t    if (match) version$3 = +match[1];\n\t  }\n\t}\n\n\tvar engineV8Version = version$3;\n\n\t/* eslint-disable es/no-symbol -- required for testing */\n\n\n\n\t// eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing\n\tvar nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {\n\t  var symbol = Symbol();\n\t  // Chrome 38 Symbol has incorrect toString conversion\n\t  // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances\n\t  return !String(symbol) || !(Object(symbol) instanceof Symbol) ||\n\t    // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances\n\t    !Symbol.sham && engineV8Version && engineV8Version < 41;\n\t});\n\n\t/* eslint-disable es/no-symbol -- required for testing */\n\n\n\tvar useSymbolAsUid = nativeSymbol\n\t  && !Symbol.sham\n\t  && typeof Symbol.iterator == 'symbol';\n\n\tvar Object$4 = global_1.Object;\n\n\tvar isSymbol$1 = useSymbolAsUid ? function (it) {\n\t  return typeof it == 'symbol';\n\t} : function (it) {\n\t  var $Symbol = getBuiltIn('Symbol');\n\t  return isCallable($Symbol) && objectIsPrototypeOf($Symbol.prototype, Object$4(it));\n\t};\n\n\tvar String$6 = global_1.String;\n\n\tvar tryToString = function (argument) {\n\t  try {\n\t    return String$6(argument);\n\t  } catch (error) {\n\t    return 'Object';\n\t  }\n\t};\n\n\tvar TypeError$l = global_1.TypeError;\n\n\t// `Assert: IsCallable(argument) is true`\n\tvar aCallable = function (argument) {\n\t  if (isCallable(argument)) return argument;\n\t  throw TypeError$l(tryToString(argument) + ' is not a function');\n\t};\n\n\t// `GetMethod` abstract operation\n\t// https://tc39.es/ecma262/#sec-getmethod\n\tvar getMethod = function (V, P) {\n\t  var func = V[P];\n\t  return func == null ? undefined : aCallable(func);\n\t};\n\n\tvar TypeError$k = global_1.TypeError;\n\n\t// `OrdinaryToPrimitive` abstract operation\n\t// https://tc39.es/ecma262/#sec-ordinarytoprimitive\n\tvar ordinaryToPrimitive = function (input, pref) {\n\t  var fn, val;\n\t  if (pref === 'string' && isCallable(fn = input.toString) && !isObject$1(val = functionCall(fn, input))) return val;\n\t  if (isCallable(fn = input.valueOf) && !isObject$1(val = functionCall(fn, input))) return val;\n\t  if (pref !== 'string' && isCallable(fn = input.toString) && !isObject$1(val = functionCall(fn, input))) return val;\n\t  throw TypeError$k(\"Can't convert object to primitive value\");\n\t};\n\n\t// eslint-disable-next-line es/no-object-defineproperty -- safe\n\tvar defineProperty$b = Object.defineProperty;\n\n\tvar setGlobal = function (key, value) {\n\t  try {\n\t    defineProperty$b(global_1, key, { value: value, configurable: true, writable: true });\n\t  } catch (error) {\n\t    global_1[key] = value;\n\t  } return value;\n\t};\n\n\tvar SHARED = '__core-js_shared__';\n\tvar store$1 = global_1[SHARED] || setGlobal(SHARED, {});\n\n\tvar sharedStore = store$1;\n\n\tvar shared = createCommonjsModule(function (module) {\n\t(module.exports = function (key, value) {\n\t  return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});\n\t})('versions', []).push({\n\t  version: '3.21.1',\n\t  mode: 'global',\n\t  copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',\n\t  license: 'https://github.com/zloirock/core-js/blob/v3.21.1/LICENSE',\n\t  source: 'https://github.com/zloirock/core-js'\n\t});\n\t});\n\n\tvar Object$3 = global_1.Object;\n\n\t// `ToObject` abstract operation\n\t// https://tc39.es/ecma262/#sec-toobject\n\tvar toObject = function (argument) {\n\t  return Object$3(requireObjectCoercible(argument));\n\t};\n\n\tvar hasOwnProperty$1 = functionUncurryThis({}.hasOwnProperty);\n\n\t// `HasOwnProperty` abstract operation\n\t// https://tc39.es/ecma262/#sec-hasownproperty\n\tvar hasOwnProperty_1 = Object.hasOwn || function hasOwn(it, key) {\n\t  return hasOwnProperty$1(toObject(it), key);\n\t};\n\n\tvar id = 0;\n\tvar postfix = Math.random();\n\tvar toString$3 = functionUncurryThis(1.0.toString);\n\n\tvar uid = function (key) {\n\t  return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString$3(++id + postfix, 36);\n\t};\n\n\tvar WellKnownSymbolsStore$1 = shared('wks');\n\tvar Symbol$1 = global_1.Symbol;\n\tvar symbolFor = Symbol$1 && Symbol$1['for'];\n\tvar createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;\n\n\tvar wellKnownSymbol = function (name) {\n\t  if (!hasOwnProperty_1(WellKnownSymbolsStore$1, name) || !(nativeSymbol || typeof WellKnownSymbolsStore$1[name] == 'string')) {\n\t    var description = 'Symbol.' + name;\n\t    if (nativeSymbol && hasOwnProperty_1(Symbol$1, name)) {\n\t      WellKnownSymbolsStore$1[name] = Symbol$1[name];\n\t    } else if (useSymbolAsUid && symbolFor) {\n\t      WellKnownSymbolsStore$1[name] = symbolFor(description);\n\t    } else {\n\t      WellKnownSymbolsStore$1[name] = createWellKnownSymbol(description);\n\t    }\n\t  } return WellKnownSymbolsStore$1[name];\n\t};\n\n\tvar TypeError$j = global_1.TypeError;\n\tvar TO_PRIMITIVE$1 = wellKnownSymbol('toPrimitive');\n\n\t// `ToPrimitive` abstract operation\n\t// https://tc39.es/ecma262/#sec-toprimitive\n\tvar toPrimitive = function (input, pref) {\n\t  if (!isObject$1(input) || isSymbol$1(input)) return input;\n\t  var exoticToPrim = getMethod(input, TO_PRIMITIVE$1);\n\t  var result;\n\t  if (exoticToPrim) {\n\t    if (pref === undefined) pref = 'default';\n\t    result = functionCall(exoticToPrim, input, pref);\n\t    if (!isObject$1(result) || isSymbol$1(result)) return result;\n\t    throw TypeError$j(\"Can't convert object to primitive value\");\n\t  }\n\t  if (pref === undefined) pref = 'number';\n\t  return ordinaryToPrimitive(input, pref);\n\t};\n\n\t// `ToPropertyKey` abstract operation\n\t// https://tc39.es/ecma262/#sec-topropertykey\n\tvar toPropertyKey = function (argument) {\n\t  var key = toPrimitive(argument, 'string');\n\t  return isSymbol$1(key) ? key : key + '';\n\t};\n\n\tvar document$3 = global_1.document;\n\t// typeof document.createElement is 'object' in old IE\n\tvar EXISTS$1 = isObject$1(document$3) && isObject$1(document$3.createElement);\n\n\tvar documentCreateElement = function (it) {\n\t  return EXISTS$1 ? document$3.createElement(it) : {};\n\t};\n\n\t// Thanks to IE8 for its funny defineProperty\n\tvar ie8DomDefine = !descriptors && !fails(function () {\n\t  // eslint-disable-next-line es/no-object-defineproperty -- required for testing\n\t  return Object.defineProperty(documentCreateElement('div'), 'a', {\n\t    get: function () { return 7; }\n\t  }).a != 7;\n\t});\n\n\t// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\n\tvar $getOwnPropertyDescriptor$2 = Object.getOwnPropertyDescriptor;\n\n\t// `Object.getOwnPropertyDescriptor` method\n\t// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor\n\tvar f$7 = descriptors ? $getOwnPropertyDescriptor$2 : function getOwnPropertyDescriptor(O, P) {\n\t  O = toIndexedObject(O);\n\t  P = toPropertyKey(P);\n\t  if (ie8DomDefine) try {\n\t    return $getOwnPropertyDescriptor$2(O, P);\n\t  } catch (error) { /* empty */ }\n\t  if (hasOwnProperty_1(O, P)) return createPropertyDescriptor(!functionCall(objectPropertyIsEnumerable.f, O, P), O[P]);\n\t};\n\n\tvar objectGetOwnPropertyDescriptor = {\n\t\tf: f$7\n\t};\n\n\t// V8 ~ Chrome 36-\n\t// https://bugs.chromium.org/p/v8/issues/detail?id=3334\n\tvar v8PrototypeDefineBug = descriptors && fails(function () {\n\t  // eslint-disable-next-line es/no-object-defineproperty -- required for testing\n\t  return Object.defineProperty(function () { /* empty */ }, 'prototype', {\n\t    value: 42,\n\t    writable: false\n\t  }).prototype != 42;\n\t});\n\n\tvar String$5 = global_1.String;\n\tvar TypeError$i = global_1.TypeError;\n\n\t// `Assert: Type(argument) is Object`\n\tvar anObject = function (argument) {\n\t  if (isObject$1(argument)) return argument;\n\t  throw TypeError$i(String$5(argument) + ' is not an object');\n\t};\n\n\tvar TypeError$h = global_1.TypeError;\n\t// eslint-disable-next-line es/no-object-defineproperty -- safe\n\tvar $defineProperty$1 = Object.defineProperty;\n\t// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\n\tvar $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;\n\tvar ENUMERABLE = 'enumerable';\n\tvar CONFIGURABLE$1 = 'configurable';\n\tvar WRITABLE = 'writable';\n\n\t// `Object.defineProperty` method\n\t// https://tc39.es/ecma262/#sec-object.defineproperty\n\tvar f$6 = descriptors ? v8PrototypeDefineBug ? function defineProperty(O, P, Attributes) {\n\t  anObject(O);\n\t  P = toPropertyKey(P);\n\t  anObject(Attributes);\n\t  if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {\n\t    var current = $getOwnPropertyDescriptor$1(O, P);\n\t    if (current && current[WRITABLE]) {\n\t      O[P] = Attributes.value;\n\t      Attributes = {\n\t        configurable: CONFIGURABLE$1 in Attributes ? Attributes[CONFIGURABLE$1] : current[CONFIGURABLE$1],\n\t        enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],\n\t        writable: false\n\t      };\n\t    }\n\t  } return $defineProperty$1(O, P, Attributes);\n\t} : $defineProperty$1 : function defineProperty(O, P, Attributes) {\n\t  anObject(O);\n\t  P = toPropertyKey(P);\n\t  anObject(Attributes);\n\t  if (ie8DomDefine) try {\n\t    return $defineProperty$1(O, P, Attributes);\n\t  } catch (error) { /* empty */ }\n\t  if ('get' in Attributes || 'set' in Attributes) throw TypeError$h('Accessors not supported');\n\t  if ('value' in Attributes) O[P] = Attributes.value;\n\t  return O;\n\t};\n\n\tvar objectDefineProperty = {\n\t\tf: f$6\n\t};\n\n\tvar createNonEnumerableProperty = descriptors ? function (object, key, value) {\n\t  return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));\n\t} : function (object, key, value) {\n\t  object[key] = value;\n\t  return object;\n\t};\n\n\tvar functionToString$1 = functionUncurryThis(Function.toString);\n\n\t// this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper\n\tif (!isCallable(sharedStore.inspectSource)) {\n\t  sharedStore.inspectSource = function (it) {\n\t    return functionToString$1(it);\n\t  };\n\t}\n\n\tvar inspectSource = sharedStore.inspectSource;\n\n\tvar WeakMap$1 = global_1.WeakMap;\n\n\tvar nativeWeakMap = isCallable(WeakMap$1) && /native code/.test(inspectSource(WeakMap$1));\n\n\tvar keys$4 = shared('keys');\n\n\tvar sharedKey = function (key) {\n\t  return keys$4[key] || (keys$4[key] = uid(key));\n\t};\n\n\tvar hiddenKeys$1 = {};\n\n\tvar OBJECT_ALREADY_INITIALIZED = 'Object already initialized';\n\tvar TypeError$g = global_1.TypeError;\n\tvar WeakMap = global_1.WeakMap;\n\tvar set$2, get$1, has;\n\n\tvar enforce = function (it) {\n\t  return has(it) ? get$1(it) : set$2(it, {});\n\t};\n\n\tvar getterFor = function (TYPE) {\n\t  return function (it) {\n\t    var state;\n\t    if (!isObject$1(it) || (state = get$1(it)).type !== TYPE) {\n\t      throw TypeError$g('Incompatible receiver, ' + TYPE + ' required');\n\t    } return state;\n\t  };\n\t};\n\n\tif (nativeWeakMap || sharedStore.state) {\n\t  var store = sharedStore.state || (sharedStore.state = new WeakMap());\n\t  var wmget = functionUncurryThis(store.get);\n\t  var wmhas = functionUncurryThis(store.has);\n\t  var wmset = functionUncurryThis(store.set);\n\t  set$2 = function (it, metadata) {\n\t    if (wmhas(store, it)) throw new TypeError$g(OBJECT_ALREADY_INITIALIZED);\n\t    metadata.facade = it;\n\t    wmset(store, it, metadata);\n\t    return metadata;\n\t  };\n\t  get$1 = function (it) {\n\t    return wmget(store, it) || {};\n\t  };\n\t  has = function (it) {\n\t    return wmhas(store, it);\n\t  };\n\t} else {\n\t  var STATE = sharedKey('state');\n\t  hiddenKeys$1[STATE] = true;\n\t  set$2 = function (it, metadata) {\n\t    if (hasOwnProperty_1(it, STATE)) throw new TypeError$g(OBJECT_ALREADY_INITIALIZED);\n\t    metadata.facade = it;\n\t    createNonEnumerableProperty(it, STATE, metadata);\n\t    return metadata;\n\t  };\n\t  get$1 = function (it) {\n\t    return hasOwnProperty_1(it, STATE) ? it[STATE] : {};\n\t  };\n\t  has = function (it) {\n\t    return hasOwnProperty_1(it, STATE);\n\t  };\n\t}\n\n\tvar internalState = {\n\t  set: set$2,\n\t  get: get$1,\n\t  has: has,\n\t  enforce: enforce,\n\t  getterFor: getterFor\n\t};\n\n\tvar FunctionPrototype$2 = Function.prototype;\n\t// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\n\tvar getDescriptor = descriptors && Object.getOwnPropertyDescriptor;\n\n\tvar EXISTS = hasOwnProperty_1(FunctionPrototype$2, 'name');\n\t// additional protection from minified / mangled / dropped function names\n\tvar PROPER = EXISTS && (function something() { /* empty */ }).name === 'something';\n\tvar CONFIGURABLE = EXISTS && (!descriptors || (descriptors && getDescriptor(FunctionPrototype$2, 'name').configurable));\n\n\tvar functionName = {\n\t  EXISTS: EXISTS,\n\t  PROPER: PROPER,\n\t  CONFIGURABLE: CONFIGURABLE\n\t};\n\n\tvar redefine = createCommonjsModule(function (module) {\n\tvar CONFIGURABLE_FUNCTION_NAME = functionName.CONFIGURABLE;\n\n\tvar getInternalState = internalState.get;\n\tvar enforceInternalState = internalState.enforce;\n\tvar TEMPLATE = String(String).split('String');\n\n\t(module.exports = function (O, key, value, options) {\n\t  var unsafe = options ? !!options.unsafe : false;\n\t  var simple = options ? !!options.enumerable : false;\n\t  var noTargetGet = options ? !!options.noTargetGet : false;\n\t  var name = options && options.name !== undefined ? options.name : key;\n\t  var state;\n\t  if (isCallable(value)) {\n\t    if (String(name).slice(0, 7) === 'Symbol(') {\n\t      name = '[' + String(name).replace(/^Symbol\\(([^)]*)\\)/, '$1') + ']';\n\t    }\n\t    if (!hasOwnProperty_1(value, 'name') || (CONFIGURABLE_FUNCTION_NAME && value.name !== name)) {\n\t      createNonEnumerableProperty(value, 'name', name);\n\t    }\n\t    state = enforceInternalState(value);\n\t    if (!state.source) {\n\t      state.source = TEMPLATE.join(typeof name == 'string' ? name : '');\n\t    }\n\t  }\n\t  if (O === global_1) {\n\t    if (simple) O[key] = value;\n\t    else setGlobal(key, value);\n\t    return;\n\t  } else if (!unsafe) {\n\t    delete O[key];\n\t  } else if (!noTargetGet && O[key]) {\n\t    simple = true;\n\t  }\n\t  if (simple) O[key] = value;\n\t  else createNonEnumerableProperty(O, key, value);\n\t// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative\n\t})(Function.prototype, 'toString', function toString() {\n\t  return isCallable(this) && getInternalState(this).source || inspectSource(this);\n\t});\n\t});\n\n\tvar ceil = Math.ceil;\n\tvar floor$6 = Math.floor;\n\n\t// `ToIntegerOrInfinity` abstract operation\n\t// https://tc39.es/ecma262/#sec-tointegerorinfinity\n\tvar toIntegerOrInfinity = function (argument) {\n\t  var number = +argument;\n\t  // eslint-disable-next-line no-self-compare -- safe\n\t  return number !== number || number === 0 ? 0 : (number > 0 ? floor$6 : ceil)(number);\n\t};\n\n\tvar max$4 = Math.max;\n\tvar min$7 = Math.min;\n\n\t// Helper for a popular repeating case of the spec:\n\t// Let integer be ? ToInteger(index).\n\t// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).\n\tvar toAbsoluteIndex = function (index, length) {\n\t  var integer = toIntegerOrInfinity(index);\n\t  return integer < 0 ? max$4(integer + length, 0) : min$7(integer, length);\n\t};\n\n\tvar min$6 = Math.min;\n\n\t// `ToLength` abstract operation\n\t// https://tc39.es/ecma262/#sec-tolength\n\tvar toLength = function (argument) {\n\t  return argument > 0 ? min$6(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991\n\t};\n\n\t// `LengthOfArrayLike` abstract operation\n\t// https://tc39.es/ecma262/#sec-lengthofarraylike\n\tvar lengthOfArrayLike = function (obj) {\n\t  return toLength(obj.length);\n\t};\n\n\t// `Array.prototype.{ indexOf, includes }` methods implementation\n\tvar createMethod$5 = function (IS_INCLUDES) {\n\t  return function ($this, el, fromIndex) {\n\t    var O = toIndexedObject($this);\n\t    var length = lengthOfArrayLike(O);\n\t    var index = toAbsoluteIndex(fromIndex, length);\n\t    var value;\n\t    // Array#includes uses SameValueZero equality algorithm\n\t    // eslint-disable-next-line no-self-compare -- NaN check\n\t    if (IS_INCLUDES && el != el) while (length > index) {\n\t      value = O[index++];\n\t      // eslint-disable-next-line no-self-compare -- NaN check\n\t      if (value != value) return true;\n\t    // Array#indexOf ignores holes, Array#includes - not\n\t    } else for (;length > index; index++) {\n\t      if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;\n\t    } return !IS_INCLUDES && -1;\n\t  };\n\t};\n\n\tvar arrayIncludes = {\n\t  // `Array.prototype.includes` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.includes\n\t  includes: createMethod$5(true),\n\t  // `Array.prototype.indexOf` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.indexof\n\t  indexOf: createMethod$5(false)\n\t};\n\n\tvar indexOf$2 = arrayIncludes.indexOf;\n\n\n\tvar push$6 = functionUncurryThis([].push);\n\n\tvar objectKeysInternal = function (object, names) {\n\t  var O = toIndexedObject(object);\n\t  var i = 0;\n\t  var result = [];\n\t  var key;\n\t  for (key in O) !hasOwnProperty_1(hiddenKeys$1, key) && hasOwnProperty_1(O, key) && push$6(result, key);\n\t  // Don't enum bug & hidden keys\n\t  while (names.length > i) if (hasOwnProperty_1(O, key = names[i++])) {\n\t    ~indexOf$2(result, key) || push$6(result, key);\n\t  }\n\t  return result;\n\t};\n\n\t// IE8- don't enum bug keys\n\tvar enumBugKeys = [\n\t  'constructor',\n\t  'hasOwnProperty',\n\t  'isPrototypeOf',\n\t  'propertyIsEnumerable',\n\t  'toLocaleString',\n\t  'toString',\n\t  'valueOf'\n\t];\n\n\tvar hiddenKeys = enumBugKeys.concat('length', 'prototype');\n\n\t// `Object.getOwnPropertyNames` method\n\t// https://tc39.es/ecma262/#sec-object.getownpropertynames\n\t// eslint-disable-next-line es/no-object-getownpropertynames -- safe\n\tvar f$5 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {\n\t  return objectKeysInternal(O, hiddenKeys);\n\t};\n\n\tvar objectGetOwnPropertyNames = {\n\t\tf: f$5\n\t};\n\n\t// eslint-disable-next-line es/no-object-getownpropertysymbols -- safe\n\tvar f$4 = Object.getOwnPropertySymbols;\n\n\tvar objectGetOwnPropertySymbols = {\n\t\tf: f$4\n\t};\n\n\tvar concat$2 = functionUncurryThis([].concat);\n\n\t// all object keys, includes non-enumerable and symbols\n\tvar ownKeys$1 = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {\n\t  var keys = objectGetOwnPropertyNames.f(anObject(it));\n\t  var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;\n\t  return getOwnPropertySymbols ? concat$2(keys, getOwnPropertySymbols(it)) : keys;\n\t};\n\n\tvar copyConstructorProperties = function (target, source, exceptions) {\n\t  var keys = ownKeys$1(source);\n\t  var defineProperty = objectDefineProperty.f;\n\t  var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;\n\t  for (var i = 0; i < keys.length; i++) {\n\t    var key = keys[i];\n\t    if (!hasOwnProperty_1(target, key) && !(exceptions && hasOwnProperty_1(exceptions, key))) {\n\t      defineProperty(target, key, getOwnPropertyDescriptor(source, key));\n\t    }\n\t  }\n\t};\n\n\tvar replacement = /#|\\.prototype\\./;\n\n\tvar isForced = function (feature, detection) {\n\t  var value = data[normalize$1(feature)];\n\t  return value == POLYFILL ? true\n\t    : value == NATIVE ? false\n\t    : isCallable(detection) ? fails(detection)\n\t    : !!detection;\n\t};\n\n\tvar normalize$1 = isForced.normalize = function (string) {\n\t  return String(string).replace(replacement, '.').toLowerCase();\n\t};\n\n\tvar data = isForced.data = {};\n\tvar NATIVE = isForced.NATIVE = 'N';\n\tvar POLYFILL = isForced.POLYFILL = 'P';\n\n\tvar isForced_1 = isForced;\n\n\tvar getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;\n\n\n\n\n\n\n\t/*\n\t  options.target      - name of the target object\n\t  options.global      - target is the global object\n\t  options.stat        - export as static methods of target\n\t  options.proto       - export as prototype methods of target\n\t  options.real        - real prototype method for the `pure` version\n\t  options.forced      - export even if the native feature is available\n\t  options.bind        - bind methods to the target, required for the `pure` version\n\t  options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version\n\t  options.unsafe      - use the simple assignment of property instead of delete + defineProperty\n\t  options.sham        - add a flag to not completely full polyfills\n\t  options.enumerable  - export as enumerable property\n\t  options.noTargetGet - prevent calling a getter on target\n\t  options.name        - the .name of the function if it does not match the key\n\t*/\n\tvar _export = function (options, source) {\n\t  var TARGET = options.target;\n\t  var GLOBAL = options.global;\n\t  var STATIC = options.stat;\n\t  var FORCED, target, key, targetProperty, sourceProperty, descriptor;\n\t  if (GLOBAL) {\n\t    target = global_1;\n\t  } else if (STATIC) {\n\t    target = global_1[TARGET] || setGlobal(TARGET, {});\n\t  } else {\n\t    target = (global_1[TARGET] || {}).prototype;\n\t  }\n\t  if (target) for (key in source) {\n\t    sourceProperty = source[key];\n\t    if (options.noTargetGet) {\n\t      descriptor = getOwnPropertyDescriptor$2(target, key);\n\t      targetProperty = descriptor && descriptor.value;\n\t    } else targetProperty = target[key];\n\t    FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);\n\t    // contained in target\n\t    if (!FORCED && targetProperty !== undefined) {\n\t      if (typeof sourceProperty == typeof targetProperty) continue;\n\t      copyConstructorProperties(sourceProperty, targetProperty);\n\t    }\n\t    // add a flag to not completely full polyfills\n\t    if (options.sham || (targetProperty && targetProperty.sham)) {\n\t      createNonEnumerableProperty(sourceProperty, 'sham', true);\n\t    }\n\t    // extend global\n\t    redefine(target, key, sourceProperty, options);\n\t  }\n\t};\n\n\t// `IsArray` abstract operation\n\t// https://tc39.es/ecma262/#sec-isarray\n\t// eslint-disable-next-line es/no-array-isarray -- safe\n\tvar isArray$3 = Array.isArray || function isArray(argument) {\n\t  return classofRaw(argument) == 'Array';\n\t};\n\n\tvar TO_STRING_TAG$4 = wellKnownSymbol('toStringTag');\n\tvar test$2 = {};\n\n\ttest$2[TO_STRING_TAG$4] = 'z';\n\n\tvar toStringTagSupport = String(test$2) === '[object z]';\n\n\tvar TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');\n\tvar Object$2 = global_1.Object;\n\n\t// ES3 wrong here\n\tvar CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';\n\n\t// fallback for IE11 Script Access Denied error\n\tvar tryGet = function (it, key) {\n\t  try {\n\t    return it[key];\n\t  } catch (error) { /* empty */ }\n\t};\n\n\t// getting tag from ES6+ `Object.prototype.toString`\n\tvar classof = toStringTagSupport ? classofRaw : function (it) {\n\t  var O, tag, result;\n\t  return it === undefined ? 'Undefined' : it === null ? 'Null'\n\t    // @@toStringTag case\n\t    : typeof (tag = tryGet(O = Object$2(it), TO_STRING_TAG$3)) == 'string' ? tag\n\t    // builtinTag case\n\t    : CORRECT_ARGUMENTS ? classofRaw(O)\n\t    // ES3 arguments fallback\n\t    : (result = classofRaw(O)) == 'Object' && isCallable(O.callee) ? 'Arguments' : result;\n\t};\n\n\tvar noop$2 = function () { /* empty */ };\n\tvar empty = [];\n\tvar construct = getBuiltIn('Reflect', 'construct');\n\tvar constructorRegExp = /^\\s*(?:class|function)\\b/;\n\tvar exec$2 = functionUncurryThis(constructorRegExp.exec);\n\tvar INCORRECT_TO_STRING = !constructorRegExp.exec(noop$2);\n\n\tvar isConstructorModern = function isConstructor(argument) {\n\t  if (!isCallable(argument)) return false;\n\t  try {\n\t    construct(noop$2, empty, argument);\n\t    return true;\n\t  } catch (error) {\n\t    return false;\n\t  }\n\t};\n\n\tvar isConstructorLegacy = function isConstructor(argument) {\n\t  if (!isCallable(argument)) return false;\n\t  switch (classof(argument)) {\n\t    case 'AsyncFunction':\n\t    case 'GeneratorFunction':\n\t    case 'AsyncGeneratorFunction': return false;\n\t  }\n\t  try {\n\t    // we can't check .prototype since constructors produced by .bind haven't it\n\t    // `Function#toString` throws on some built-it function in some legacy engines\n\t    // (for example, `DOMQuad` and similar in FF41-)\n\t    return INCORRECT_TO_STRING || !!exec$2(constructorRegExp, inspectSource(argument));\n\t  } catch (error) {\n\t    return true;\n\t  }\n\t};\n\n\tisConstructorLegacy.sham = true;\n\n\t// `IsConstructor` abstract operation\n\t// https://tc39.es/ecma262/#sec-isconstructor\n\tvar isConstructor = !construct || fails(function () {\n\t  var called;\n\t  return isConstructorModern(isConstructorModern.call)\n\t    || !isConstructorModern(Object)\n\t    || !isConstructorModern(function () { called = true; })\n\t    || called;\n\t}) ? isConstructorLegacy : isConstructorModern;\n\n\tvar SPECIES$6 = wellKnownSymbol('species');\n\tvar Array$7 = global_1.Array;\n\n\t// a part of `ArraySpeciesCreate` abstract operation\n\t// https://tc39.es/ecma262/#sec-arrayspeciescreate\n\tvar arraySpeciesConstructor = function (originalArray) {\n\t  var C;\n\t  if (isArray$3(originalArray)) {\n\t    C = originalArray.constructor;\n\t    // cross-realm fallback\n\t    if (isConstructor(C) && (C === Array$7 || isArray$3(C.prototype))) C = undefined;\n\t    else if (isObject$1(C)) {\n\t      C = C[SPECIES$6];\n\t      if (C === null) C = undefined;\n\t    }\n\t  } return C === undefined ? Array$7 : C;\n\t};\n\n\t// `ArraySpeciesCreate` abstract operation\n\t// https://tc39.es/ecma262/#sec-arrayspeciescreate\n\tvar arraySpeciesCreate = function (originalArray, length) {\n\t  return new (arraySpeciesConstructor(originalArray))(length === 0 ? 0 : length);\n\t};\n\n\tvar createProperty = function (object, key, value) {\n\t  var propertyKey = toPropertyKey(key);\n\t  if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));\n\t  else object[propertyKey] = value;\n\t};\n\n\tvar SPECIES$5 = wellKnownSymbol('species');\n\n\tvar arrayMethodHasSpeciesSupport = function (METHOD_NAME) {\n\t  // We can't use this feature detection in V8 since it causes\n\t  // deoptimization and serious performance degradation\n\t  // https://github.com/zloirock/core-js/issues/677\n\t  return engineV8Version >= 51 || !fails(function () {\n\t    var array = [];\n\t    var constructor = array.constructor = {};\n\t    constructor[SPECIES$5] = function () {\n\t      return { foo: 1 };\n\t    };\n\t    return array[METHOD_NAME](Boolean).foo !== 1;\n\t  });\n\t};\n\n\tvar HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport('splice');\n\n\tvar TypeError$f = global_1.TypeError;\n\tvar max$3 = Math.max;\n\tvar min$5 = Math.min;\n\tvar MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;\n\tvar MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';\n\n\t// `Array.prototype.splice` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.splice\n\t// with adding support of @@species\n\t_export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 }, {\n\t  splice: function splice(start, deleteCount /* , ...items */) {\n\t    var O = toObject(this);\n\t    var len = lengthOfArrayLike(O);\n\t    var actualStart = toAbsoluteIndex(start, len);\n\t    var argumentsLength = arguments.length;\n\t    var insertCount, actualDeleteCount, A, k, from, to;\n\t    if (argumentsLength === 0) {\n\t      insertCount = actualDeleteCount = 0;\n\t    } else if (argumentsLength === 1) {\n\t      insertCount = 0;\n\t      actualDeleteCount = len - actualStart;\n\t    } else {\n\t      insertCount = argumentsLength - 2;\n\t      actualDeleteCount = min$5(max$3(toIntegerOrInfinity(deleteCount), 0), len - actualStart);\n\t    }\n\t    if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {\n\t      throw TypeError$f(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);\n\t    }\n\t    A = arraySpeciesCreate(O, actualDeleteCount);\n\t    for (k = 0; k < actualDeleteCount; k++) {\n\t      from = actualStart + k;\n\t      if (from in O) createProperty(A, k, O[from]);\n\t    }\n\t    A.length = actualDeleteCount;\n\t    if (insertCount < actualDeleteCount) {\n\t      for (k = actualStart; k < len - actualDeleteCount; k++) {\n\t        from = k + actualDeleteCount;\n\t        to = k + insertCount;\n\t        if (from in O) O[to] = O[from];\n\t        else delete O[to];\n\t      }\n\t      for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];\n\t    } else if (insertCount > actualDeleteCount) {\n\t      for (k = len - actualDeleteCount; k > actualStart; k--) {\n\t        from = k + actualDeleteCount - 1;\n\t        to = k + insertCount - 1;\n\t        if (from in O) O[to] = O[from];\n\t        else delete O[to];\n\t      }\n\t    }\n\t    for (k = 0; k < insertCount; k++) {\n\t      O[k + actualStart] = arguments[k + 2];\n\t    }\n\t    O.length = len - actualDeleteCount + insertCount;\n\t    return A;\n\t  }\n\t});\n\n\t// `Object.prototype.toString` method implementation\n\t// https://tc39.es/ecma262/#sec-object.prototype.tostring\n\tvar objectToString$1 = toStringTagSupport ? {}.toString : function toString() {\n\t  return '[object ' + classof(this) + ']';\n\t};\n\n\t// `Object.prototype.toString` method\n\t// https://tc39.es/ecma262/#sec-object.prototype.tostring\n\tif (!toStringTagSupport) {\n\t  redefine(Object.prototype, 'toString', objectToString$1, { unsafe: true });\n\t}\n\n\t// iterable DOM collections\n\t// flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods\n\tvar domIterables = {\n\t  CSSRuleList: 0,\n\t  CSSStyleDeclaration: 0,\n\t  CSSValueList: 0,\n\t  ClientRectList: 0,\n\t  DOMRectList: 0,\n\t  DOMStringList: 0,\n\t  DOMTokenList: 1,\n\t  DataTransferItemList: 0,\n\t  FileList: 0,\n\t  HTMLAllCollection: 0,\n\t  HTMLCollection: 0,\n\t  HTMLFormElement: 0,\n\t  HTMLSelectElement: 0,\n\t  MediaList: 0,\n\t  MimeTypeArray: 0,\n\t  NamedNodeMap: 0,\n\t  NodeList: 1,\n\t  PaintRequestList: 0,\n\t  Plugin: 0,\n\t  PluginArray: 0,\n\t  SVGLengthList: 0,\n\t  SVGNumberList: 0,\n\t  SVGPathSegList: 0,\n\t  SVGPointList: 0,\n\t  SVGStringList: 0,\n\t  SVGTransformList: 0,\n\t  SourceBufferList: 0,\n\t  StyleSheetList: 0,\n\t  TextTrackCueList: 0,\n\t  TextTrackList: 0,\n\t  TouchList: 0\n\t};\n\n\t// in old WebKit versions, `element.classList` is not an instance of global `DOMTokenList`\n\n\n\tvar classList = documentCreateElement('span').classList;\n\tvar DOMTokenListPrototype = classList && classList.constructor && classList.constructor.prototype;\n\n\tvar domTokenListPrototype = DOMTokenListPrototype === Object.prototype ? undefined : DOMTokenListPrototype;\n\n\tvar bind$1 = functionUncurryThis(functionUncurryThis.bind);\n\n\t// optional / simple context binding\n\tvar functionBindContext = function (fn, that) {\n\t  aCallable(fn);\n\t  return that === undefined ? fn : functionBindNative ? bind$1(fn, that) : function (/* ...args */) {\n\t    return fn.apply(that, arguments);\n\t  };\n\t};\n\n\tvar push$5 = functionUncurryThis([].push);\n\n\t// `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterReject }` methods implementation\n\tvar createMethod$4 = function (TYPE) {\n\t  var IS_MAP = TYPE == 1;\n\t  var IS_FILTER = TYPE == 2;\n\t  var IS_SOME = TYPE == 3;\n\t  var IS_EVERY = TYPE == 4;\n\t  var IS_FIND_INDEX = TYPE == 6;\n\t  var IS_FILTER_REJECT = TYPE == 7;\n\t  var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;\n\t  return function ($this, callbackfn, that, specificCreate) {\n\t    var O = toObject($this);\n\t    var self = indexedObject(O);\n\t    var boundFunction = functionBindContext(callbackfn, that);\n\t    var length = lengthOfArrayLike(self);\n\t    var index = 0;\n\t    var create = specificCreate || arraySpeciesCreate;\n\t    var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_REJECT ? create($this, 0) : undefined;\n\t    var value, result;\n\t    for (;length > index; index++) if (NO_HOLES || index in self) {\n\t      value = self[index];\n\t      result = boundFunction(value, index, O);\n\t      if (TYPE) {\n\t        if (IS_MAP) target[index] = result; // map\n\t        else if (result) switch (TYPE) {\n\t          case 3: return true;              // some\n\t          case 5: return value;             // find\n\t          case 6: return index;             // findIndex\n\t          case 2: push$5(target, value);      // filter\n\t        } else switch (TYPE) {\n\t          case 4: return false;             // every\n\t          case 7: push$5(target, value);      // filterReject\n\t        }\n\t      }\n\t    }\n\t    return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;\n\t  };\n\t};\n\n\tvar arrayIteration = {\n\t  // `Array.prototype.forEach` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.foreach\n\t  forEach: createMethod$4(0),\n\t  // `Array.prototype.map` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.map\n\t  map: createMethod$4(1),\n\t  // `Array.prototype.filter` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.filter\n\t  filter: createMethod$4(2),\n\t  // `Array.prototype.some` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.some\n\t  some: createMethod$4(3),\n\t  // `Array.prototype.every` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.every\n\t  every: createMethod$4(4),\n\t  // `Array.prototype.find` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.find\n\t  find: createMethod$4(5),\n\t  // `Array.prototype.findIndex` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.findIndex\n\t  findIndex: createMethod$4(6),\n\t  // `Array.prototype.filterReject` method\n\t  // https://github.com/tc39/proposal-array-filtering\n\t  filterReject: createMethod$4(7)\n\t};\n\n\tvar arrayMethodIsStrict = function (METHOD_NAME, argument) {\n\t  var method = [][METHOD_NAME];\n\t  return !!method && fails(function () {\n\t    // eslint-disable-next-line no-useless-call -- required for testing\n\t    method.call(null, argument || function () { return 1; }, 1);\n\t  });\n\t};\n\n\tvar $forEach$2 = arrayIteration.forEach;\n\n\n\tvar STRICT_METHOD$3 = arrayMethodIsStrict('forEach');\n\n\t// `Array.prototype.forEach` method implementation\n\t// https://tc39.es/ecma262/#sec-array.prototype.foreach\n\tvar arrayForEach = !STRICT_METHOD$3 ? function forEach(callbackfn /* , thisArg */) {\n\t  return $forEach$2(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t// eslint-disable-next-line es/no-array-prototype-foreach -- safe\n\t} : [].forEach;\n\n\tvar handlePrototype$1 = function (CollectionPrototype) {\n\t  // some Chrome versions have non-configurable methods on DOMTokenList\n\t  if (CollectionPrototype && CollectionPrototype.forEach !== arrayForEach) try {\n\t    createNonEnumerableProperty(CollectionPrototype, 'forEach', arrayForEach);\n\t  } catch (error) {\n\t    CollectionPrototype.forEach = arrayForEach;\n\t  }\n\t};\n\n\tfor (var COLLECTION_NAME$1 in domIterables) {\n\t  if (domIterables[COLLECTION_NAME$1]) {\n\t    handlePrototype$1(global_1[COLLECTION_NAME$1] && global_1[COLLECTION_NAME$1].prototype);\n\t  }\n\t}\n\n\thandlePrototype$1(domTokenListPrototype);\n\n\tvar $filter$1 = arrayIteration.filter;\n\n\n\tvar HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('filter');\n\n\t// `Array.prototype.filter` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.filter\n\t// with adding support of @@species\n\t_export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 }, {\n\t  filter: function filter(callbackfn /* , thisArg */) {\n\t    return $filter$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t  }\n\t});\n\n\t// `Object.keys` method\n\t// https://tc39.es/ecma262/#sec-object.keys\n\t// eslint-disable-next-line es/no-object-keys -- safe\n\tvar objectKeys = Object.keys || function keys(O) {\n\t  return objectKeysInternal(O, enumBugKeys);\n\t};\n\n\tvar FAILS_ON_PRIMITIVES$5 = fails(function () { objectKeys(1); });\n\n\t// `Object.keys` method\n\t// https://tc39.es/ecma262/#sec-object.keys\n\t_export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$5 }, {\n\t  keys: function keys(it) {\n\t    return objectKeys(toObject(it));\n\t  }\n\t});\n\n\tvar String$4 = global_1.String;\n\n\tvar toString_1 = function (argument) {\n\t  if (classof(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');\n\t  return String$4(argument);\n\t};\n\n\t// `RegExp.prototype.flags` getter implementation\n\t// https://tc39.es/ecma262/#sec-get-regexp.prototype.flags\n\tvar regexpFlags = function () {\n\t  var that = anObject(this);\n\t  var result = '';\n\t  if (that.global) result += 'g';\n\t  if (that.ignoreCase) result += 'i';\n\t  if (that.multiline) result += 'm';\n\t  if (that.dotAll) result += 's';\n\t  if (that.unicode) result += 'u';\n\t  if (that.sticky) result += 'y';\n\t  return result;\n\t};\n\n\t// babel-minify and Closure Compiler transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError\n\tvar $RegExp$2 = global_1.RegExp;\n\n\tvar UNSUPPORTED_Y$3 = fails(function () {\n\t  var re = $RegExp$2('a', 'y');\n\t  re.lastIndex = 2;\n\t  return re.exec('abcd') != null;\n\t});\n\n\t// UC Browser bug\n\t// https://github.com/zloirock/core-js/issues/1008\n\tvar MISSED_STICKY$1 = UNSUPPORTED_Y$3 || fails(function () {\n\t  return !$RegExp$2('a', 'y').sticky;\n\t});\n\n\tvar BROKEN_CARET = UNSUPPORTED_Y$3 || fails(function () {\n\t  // https://bugzilla.mozilla.org/show_bug.cgi?id=773687\n\t  var re = $RegExp$2('^r', 'gy');\n\t  re.lastIndex = 2;\n\t  return re.exec('str') != null;\n\t});\n\n\tvar regexpStickyHelpers = {\n\t  BROKEN_CARET: BROKEN_CARET,\n\t  MISSED_STICKY: MISSED_STICKY$1,\n\t  UNSUPPORTED_Y: UNSUPPORTED_Y$3\n\t};\n\n\t// `Object.defineProperties` method\n\t// https://tc39.es/ecma262/#sec-object.defineproperties\n\t// eslint-disable-next-line es/no-object-defineproperties -- safe\n\tvar f$3 = descriptors && !v8PrototypeDefineBug ? Object.defineProperties : function defineProperties(O, Properties) {\n\t  anObject(O);\n\t  var props = toIndexedObject(Properties);\n\t  var keys = objectKeys(Properties);\n\t  var length = keys.length;\n\t  var index = 0;\n\t  var key;\n\t  while (length > index) objectDefineProperty.f(O, key = keys[index++], props[key]);\n\t  return O;\n\t};\n\n\tvar objectDefineProperties = {\n\t\tf: f$3\n\t};\n\n\tvar html$1 = getBuiltIn('document', 'documentElement');\n\n\t/* global ActiveXObject -- old IE, WSH */\n\n\n\n\n\n\n\n\n\tvar GT = '>';\n\tvar LT = '<';\n\tvar PROTOTYPE$2 = 'prototype';\n\tvar SCRIPT = 'script';\n\tvar IE_PROTO$1 = sharedKey('IE_PROTO');\n\n\tvar EmptyConstructor = function () { /* empty */ };\n\n\tvar scriptTag = function (content) {\n\t  return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;\n\t};\n\n\t// Create object with fake `null` prototype: use ActiveX Object with cleared prototype\n\tvar NullProtoObjectViaActiveX = function (activeXDocument) {\n\t  activeXDocument.write(scriptTag(''));\n\t  activeXDocument.close();\n\t  var temp = activeXDocument.parentWindow.Object;\n\t  activeXDocument = null; // avoid memory leak\n\t  return temp;\n\t};\n\n\t// Create object with fake `null` prototype: use iframe Object with cleared prototype\n\tvar NullProtoObjectViaIFrame = function () {\n\t  // Thrash, waste and sodomy: IE GC bug\n\t  var iframe = documentCreateElement('iframe');\n\t  var JS = 'java' + SCRIPT + ':';\n\t  var iframeDocument;\n\t  iframe.style.display = 'none';\n\t  html$1.appendChild(iframe);\n\t  // https://github.com/zloirock/core-js/issues/475\n\t  iframe.src = String(JS);\n\t  iframeDocument = iframe.contentWindow.document;\n\t  iframeDocument.open();\n\t  iframeDocument.write(scriptTag('document.F=Object'));\n\t  iframeDocument.close();\n\t  return iframeDocument.F;\n\t};\n\n\t// Check for document.domain and active x support\n\t// No need to use active x approach when document.domain is not set\n\t// see https://github.com/es-shims/es5-shim/issues/150\n\t// variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346\n\t// avoid IE GC bug\n\tvar activeXDocument;\n\tvar NullProtoObject = function () {\n\t  try {\n\t    activeXDocument = new ActiveXObject('htmlfile');\n\t  } catch (error) { /* ignore */ }\n\t  NullProtoObject = typeof document != 'undefined'\n\t    ? document.domain && activeXDocument\n\t      ? NullProtoObjectViaActiveX(activeXDocument) // old IE\n\t      : NullProtoObjectViaIFrame()\n\t    : NullProtoObjectViaActiveX(activeXDocument); // WSH\n\t  var length = enumBugKeys.length;\n\t  while (length--) delete NullProtoObject[PROTOTYPE$2][enumBugKeys[length]];\n\t  return NullProtoObject();\n\t};\n\n\thiddenKeys$1[IE_PROTO$1] = true;\n\n\t// `Object.create` method\n\t// https://tc39.es/ecma262/#sec-object.create\n\tvar objectCreate = Object.create || function create(O, Properties) {\n\t  var result;\n\t  if (O !== null) {\n\t    EmptyConstructor[PROTOTYPE$2] = anObject(O);\n\t    result = new EmptyConstructor();\n\t    EmptyConstructor[PROTOTYPE$2] = null;\n\t    // add \"__proto__\" for Object.getPrototypeOf polyfill\n\t    result[IE_PROTO$1] = O;\n\t  } else result = NullProtoObject();\n\t  return Properties === undefined ? result : objectDefineProperties.f(result, Properties);\n\t};\n\n\t// babel-minify and Closure Compiler transpiles RegExp('.', 's') -> /./s and it causes SyntaxError\n\tvar $RegExp$1 = global_1.RegExp;\n\n\tvar regexpUnsupportedDotAll = fails(function () {\n\t  var re = $RegExp$1('.', 's');\n\t  return !(re.dotAll && re.exec('\\n') && re.flags === 's');\n\t});\n\n\t// babel-minify and Closure Compiler transpiles RegExp('(?<a>b)', 'g') -> /(?<a>b)/g and it causes SyntaxError\n\tvar $RegExp = global_1.RegExp;\n\n\tvar regexpUnsupportedNcg = fails(function () {\n\t  var re = $RegExp('(?<a>b)', 'g');\n\t  return re.exec('b').groups.a !== 'b' ||\n\t    'b'.replace(re, '$<a>c') !== 'bc';\n\t});\n\n\t/* eslint-disable regexp/no-empty-capturing-group, regexp/no-empty-group, regexp/no-lazy-ends -- testing */\n\t/* eslint-disable regexp/no-useless-quantifier -- testing */\n\n\n\n\n\n\n\n\tvar getInternalState$5 = internalState.get;\n\n\n\n\tvar nativeReplace = shared('native-string-replace', String.prototype.replace);\n\tvar nativeExec = RegExp.prototype.exec;\n\tvar patchedExec = nativeExec;\n\tvar charAt$5 = functionUncurryThis(''.charAt);\n\tvar indexOf$1 = functionUncurryThis(''.indexOf);\n\tvar replace$4 = functionUncurryThis(''.replace);\n\tvar stringSlice$7 = functionUncurryThis(''.slice);\n\n\tvar UPDATES_LAST_INDEX_WRONG = (function () {\n\t  var re1 = /a/;\n\t  var re2 = /b*/g;\n\t  functionCall(nativeExec, re1, 'a');\n\t  functionCall(nativeExec, re2, 'a');\n\t  return re1.lastIndex !== 0 || re2.lastIndex !== 0;\n\t})();\n\n\tvar UNSUPPORTED_Y$2 = regexpStickyHelpers.BROKEN_CARET;\n\n\t// nonparticipating capturing group, copied from es5-shim's String#split patch.\n\tvar NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;\n\n\tvar PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$2 || regexpUnsupportedDotAll || regexpUnsupportedNcg;\n\n\tif (PATCH) {\n\t  patchedExec = function exec(string) {\n\t    var re = this;\n\t    var state = getInternalState$5(re);\n\t    var str = toString_1(string);\n\t    var raw = state.raw;\n\t    var result, reCopy, lastIndex, match, i, object, group;\n\n\t    if (raw) {\n\t      raw.lastIndex = re.lastIndex;\n\t      result = functionCall(patchedExec, raw, str);\n\t      re.lastIndex = raw.lastIndex;\n\t      return result;\n\t    }\n\n\t    var groups = state.groups;\n\t    var sticky = UNSUPPORTED_Y$2 && re.sticky;\n\t    var flags = functionCall(regexpFlags, re);\n\t    var source = re.source;\n\t    var charsAdded = 0;\n\t    var strCopy = str;\n\n\t    if (sticky) {\n\t      flags = replace$4(flags, 'y', '');\n\t      if (indexOf$1(flags, 'g') === -1) {\n\t        flags += 'g';\n\t      }\n\n\t      strCopy = stringSlice$7(str, re.lastIndex);\n\t      // Support anchored sticky behavior.\n\t      if (re.lastIndex > 0 && (!re.multiline || re.multiline && charAt$5(str, re.lastIndex - 1) !== '\\n')) {\n\t        source = '(?: ' + source + ')';\n\t        strCopy = ' ' + strCopy;\n\t        charsAdded++;\n\t      }\n\t      // ^(? + rx + ) is needed, in combination with some str slicing, to\n\t      // simulate the 'y' flag.\n\t      reCopy = new RegExp('^(?:' + source + ')', flags);\n\t    }\n\n\t    if (NPCG_INCLUDED) {\n\t      reCopy = new RegExp('^' + source + '$(?!\\\\s)', flags);\n\t    }\n\t    if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;\n\n\t    match = functionCall(nativeExec, sticky ? reCopy : re, strCopy);\n\n\t    if (sticky) {\n\t      if (match) {\n\t        match.input = stringSlice$7(match.input, charsAdded);\n\t        match[0] = stringSlice$7(match[0], charsAdded);\n\t        match.index = re.lastIndex;\n\t        re.lastIndex += match[0].length;\n\t      } else re.lastIndex = 0;\n\t    } else if (UPDATES_LAST_INDEX_WRONG && match) {\n\t      re.lastIndex = re.global ? match.index + match[0].length : lastIndex;\n\t    }\n\t    if (NPCG_INCLUDED && match && match.length > 1) {\n\t      // Fix browsers whose `exec` methods don't consistently return `undefined`\n\t      // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/\n\t      functionCall(nativeReplace, match[0], reCopy, function () {\n\t        for (i = 1; i < arguments.length - 2; i++) {\n\t          if (arguments[i] === undefined) match[i] = undefined;\n\t        }\n\t      });\n\t    }\n\n\t    if (match && groups) {\n\t      match.groups = object = objectCreate(null);\n\t      for (i = 0; i < groups.length; i++) {\n\t        group = groups[i];\n\t        object[group[0]] = match[group[1]];\n\t      }\n\t    }\n\n\t    return match;\n\t  };\n\t}\n\n\tvar regexpExec = patchedExec;\n\n\t// `RegExp.prototype.exec` method\n\t// https://tc39.es/ecma262/#sec-regexp.prototype.exec\n\t_export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {\n\t  exec: regexpExec\n\t});\n\n\t// TODO: Remove from `core-js@4` since it's moved to entry points\n\n\n\n\n\n\n\n\n\tvar SPECIES$4 = wellKnownSymbol('species');\n\tvar RegExpPrototype$2 = RegExp.prototype;\n\n\tvar fixRegexpWellKnownSymbolLogic = function (KEY, exec, FORCED, SHAM) {\n\t  var SYMBOL = wellKnownSymbol(KEY);\n\n\t  var DELEGATES_TO_SYMBOL = !fails(function () {\n\t    // String methods call symbol-named RegEp methods\n\t    var O = {};\n\t    O[SYMBOL] = function () { return 7; };\n\t    return ''[KEY](O) != 7;\n\t  });\n\n\t  var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {\n\t    // Symbol-named RegExp methods call .exec\n\t    var execCalled = false;\n\t    var re = /a/;\n\n\t    if (KEY === 'split') {\n\t      // We can't use real regex here since it causes deoptimization\n\t      // and serious performance degradation in V8\n\t      // https://github.com/zloirock/core-js/issues/306\n\t      re = {};\n\t      // RegExp[@@split] doesn't call the regex's exec method, but first creates\n\t      // a new one. We need to return the patched regex when creating the new one.\n\t      re.constructor = {};\n\t      re.constructor[SPECIES$4] = function () { return re; };\n\t      re.flags = '';\n\t      re[SYMBOL] = /./[SYMBOL];\n\t    }\n\n\t    re.exec = function () { execCalled = true; return null; };\n\n\t    re[SYMBOL]('');\n\t    return !execCalled;\n\t  });\n\n\t  if (\n\t    !DELEGATES_TO_SYMBOL ||\n\t    !DELEGATES_TO_EXEC ||\n\t    FORCED\n\t  ) {\n\t    var uncurriedNativeRegExpMethod = functionUncurryThis(/./[SYMBOL]);\n\t    var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {\n\t      var uncurriedNativeMethod = functionUncurryThis(nativeMethod);\n\t      var $exec = regexp.exec;\n\t      if ($exec === regexpExec || $exec === RegExpPrototype$2.exec) {\n\t        if (DELEGATES_TO_SYMBOL && !forceStringMethod) {\n\t          // The native String method already delegates to @@method (this\n\t          // polyfilled function), leasing to infinite recursion.\n\t          // We avoid it by directly calling the native @@method method.\n\t          return { done: true, value: uncurriedNativeRegExpMethod(regexp, str, arg2) };\n\t        }\n\t        return { done: true, value: uncurriedNativeMethod(str, regexp, arg2) };\n\t      }\n\t      return { done: false };\n\t    });\n\n\t    redefine(String.prototype, KEY, methods[0]);\n\t    redefine(RegExpPrototype$2, SYMBOL, methods[1]);\n\t  }\n\n\t  if (SHAM) createNonEnumerableProperty(RegExpPrototype$2[SYMBOL], 'sham', true);\n\t};\n\n\t// `SameValue` abstract operation\n\t// https://tc39.es/ecma262/#sec-samevalue\n\t// eslint-disable-next-line es/no-object-is -- safe\n\tvar sameValue = Object.is || function is(x, y) {\n\t  // eslint-disable-next-line no-self-compare -- NaN check\n\t  return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;\n\t};\n\n\tvar TypeError$e = global_1.TypeError;\n\n\t// `RegExpExec` abstract operation\n\t// https://tc39.es/ecma262/#sec-regexpexec\n\tvar regexpExecAbstract = function (R, S) {\n\t  var exec = R.exec;\n\t  if (isCallable(exec)) {\n\t    var result = functionCall(exec, R, S);\n\t    if (result !== null) anObject(result);\n\t    return result;\n\t  }\n\t  if (classofRaw(R) === 'RegExp') return functionCall(regexpExec, R, S);\n\t  throw TypeError$e('RegExp#exec called on incompatible receiver');\n\t};\n\n\t// @@search logic\n\tfixRegexpWellKnownSymbolLogic('search', function (SEARCH, nativeSearch, maybeCallNative) {\n\t  return [\n\t    // `String.prototype.search` method\n\t    // https://tc39.es/ecma262/#sec-string.prototype.search\n\t    function search(regexp) {\n\t      var O = requireObjectCoercible(this);\n\t      var searcher = regexp == undefined ? undefined : getMethod(regexp, SEARCH);\n\t      return searcher ? functionCall(searcher, regexp, O) : new RegExp(regexp)[SEARCH](toString_1(O));\n\t    },\n\t    // `RegExp.prototype[@@search]` method\n\t    // https://tc39.es/ecma262/#sec-regexp.prototype-@@search\n\t    function (string) {\n\t      var rx = anObject(this);\n\t      var S = toString_1(string);\n\t      var res = maybeCallNative(nativeSearch, rx, S);\n\n\t      if (res.done) return res.value;\n\n\t      var previousLastIndex = rx.lastIndex;\n\t      if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;\n\t      var result = regexpExecAbstract(rx, S);\n\t      if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;\n\t      return result === null ? -1 : result.index;\n\t    }\n\t  ];\n\t});\n\n\tvar IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');\n\tvar MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;\n\tvar MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';\n\tvar TypeError$d = global_1.TypeError;\n\n\t// We can't use this feature detection in V8 since it causes\n\t// deoptimization and serious performance degradation\n\t// https://github.com/zloirock/core-js/issues/679\n\tvar IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {\n\t  var array = [];\n\t  array[IS_CONCAT_SPREADABLE] = false;\n\t  return array.concat()[0] !== array;\n\t});\n\n\tvar SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');\n\n\tvar isConcatSpreadable = function (O) {\n\t  if (!isObject$1(O)) return false;\n\t  var spreadable = O[IS_CONCAT_SPREADABLE];\n\t  return spreadable !== undefined ? !!spreadable : isArray$3(O);\n\t};\n\n\tvar FORCED$7 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;\n\n\t// `Array.prototype.concat` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.concat\n\t// with adding support of @@isConcatSpreadable and @@species\n\t_export({ target: 'Array', proto: true, forced: FORCED$7 }, {\n\t  // eslint-disable-next-line no-unused-vars -- required for `.length`\n\t  concat: function concat(arg) {\n\t    var O = toObject(this);\n\t    var A = arraySpeciesCreate(O, 0);\n\t    var n = 0;\n\t    var i, k, length, len, E;\n\t    for (i = -1, length = arguments.length; i < length; i++) {\n\t      E = i === -1 ? O : arguments[i];\n\t      if (isConcatSpreadable(E)) {\n\t        len = lengthOfArrayLike(E);\n\t        if (n + len > MAX_SAFE_INTEGER) throw TypeError$d(MAXIMUM_ALLOWED_INDEX_EXCEEDED);\n\t        for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);\n\t      } else {\n\t        if (n >= MAX_SAFE_INTEGER) throw TypeError$d(MAXIMUM_ALLOWED_INDEX_EXCEEDED);\n\t        createProperty(A, n++, E);\n\t      }\n\t    }\n\t    A.length = n;\n\t    return A;\n\t  }\n\t});\n\n\tvar global$2 = typeof global$1 !== \"undefined\" ? global$1 : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {};\n\n\tvar global$1 = typeof global$2 !== \"undefined\" ? global$2 : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {};\n\n\t// based off https://github.com/defunctzombie/node-process/blob/master/browser.js\n\n\tfunction defaultSetTimout$1() {\n\t  throw new Error('setTimeout has not been defined');\n\t}\n\n\tfunction defaultClearTimeout$1() {\n\t  throw new Error('clearTimeout has not been defined');\n\t}\n\n\tvar cachedSetTimeout$1 = defaultSetTimout$1;\n\tvar cachedClearTimeout$1 = defaultClearTimeout$1;\n\n\tif (typeof global$1.setTimeout === 'function') {\n\t  cachedSetTimeout$1 = setTimeout;\n\t}\n\n\tif (typeof global$1.clearTimeout === 'function') {\n\t  cachedClearTimeout$1 = clearTimeout;\n\t}\n\n\tfunction runTimeout$1(fun) {\n\t  if (cachedSetTimeout$1 === setTimeout) {\n\t    //normal enviroments in sane situations\n\t    return setTimeout(fun, 0);\n\t  } // if setTimeout wasn't available but was latter defined\n\n\n\t  if ((cachedSetTimeout$1 === defaultSetTimout$1 || !cachedSetTimeout$1) && setTimeout) {\n\t    cachedSetTimeout$1 = setTimeout;\n\t    return setTimeout(fun, 0);\n\t  }\n\n\t  try {\n\t    // when when somebody has screwed with setTimeout but no I.E. maddness\n\t    return cachedSetTimeout$1(fun, 0);\n\t  } catch (e) {\n\t    try {\n\t      // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n\t      return cachedSetTimeout$1.call(null, fun, 0);\n\t    } catch (e) {\n\t      // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n\t      return cachedSetTimeout$1.call(this, fun, 0);\n\t    }\n\t  }\n\t}\n\n\tfunction runClearTimeout$1(marker) {\n\t  if (cachedClearTimeout$1 === clearTimeout) {\n\t    //normal enviroments in sane situations\n\t    return clearTimeout(marker);\n\t  } // if clearTimeout wasn't available but was latter defined\n\n\n\t  if ((cachedClearTimeout$1 === defaultClearTimeout$1 || !cachedClearTimeout$1) && clearTimeout) {\n\t    cachedClearTimeout$1 = clearTimeout;\n\t    return clearTimeout(marker);\n\t  }\n\n\t  try {\n\t    // when when somebody has screwed with setTimeout but no I.E. maddness\n\t    return cachedClearTimeout$1(marker);\n\t  } catch (e) {\n\t    try {\n\t      // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally\n\t      return cachedClearTimeout$1.call(null, marker);\n\t    } catch (e) {\n\t      // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n\t      // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n\t      return cachedClearTimeout$1.call(this, marker);\n\t    }\n\t  }\n\t}\n\n\tvar queue$3 = [];\n\tvar draining$1 = false;\n\tvar currentQueue$1;\n\tvar queueIndex$1 = -1;\n\n\tfunction cleanUpNextTick$1() {\n\t  if (!draining$1 || !currentQueue$1) {\n\t    return;\n\t  }\n\n\t  draining$1 = false;\n\n\t  if (currentQueue$1.length) {\n\t    queue$3 = currentQueue$1.concat(queue$3);\n\t  } else {\n\t    queueIndex$1 = -1;\n\t  }\n\n\t  if (queue$3.length) {\n\t    drainQueue$1();\n\t  }\n\t}\n\n\tfunction drainQueue$1() {\n\t  if (draining$1) {\n\t    return;\n\t  }\n\n\t  var timeout = runTimeout$1(cleanUpNextTick$1);\n\t  draining$1 = true;\n\t  var len = queue$3.length;\n\n\t  while (len) {\n\t    currentQueue$1 = queue$3;\n\t    queue$3 = [];\n\n\t    while (++queueIndex$1 < len) {\n\t      if (currentQueue$1) {\n\t        currentQueue$1[queueIndex$1].run();\n\t      }\n\t    }\n\n\t    queueIndex$1 = -1;\n\t    len = queue$3.length;\n\t  }\n\n\t  currentQueue$1 = null;\n\t  draining$1 = false;\n\t  runClearTimeout$1(timeout);\n\t}\n\n\tfunction nextTick$1(fun) {\n\t  var args = new Array(arguments.length - 1);\n\n\t  if (arguments.length > 1) {\n\t    for (var i = 1; i < arguments.length; i++) {\n\t      args[i - 1] = arguments[i];\n\t    }\n\t  }\n\n\t  queue$3.push(new Item$1(fun, args));\n\n\t  if (queue$3.length === 1 && !draining$1) {\n\t    runTimeout$1(drainQueue$1);\n\t  }\n\t} // v8 likes predictible objects\n\n\tfunction Item$1(fun, array) {\n\t  this.fun = fun;\n\t  this.array = array;\n\t}\n\n\tItem$1.prototype.run = function () {\n\t  this.fun.apply(null, this.array);\n\t};\n\n\tvar title$1 = 'browser';\n\tvar platform$1 = 'browser';\n\tvar browser$4 = true;\n\tvar env$1 = {};\n\tvar argv$1 = [];\n\tvar version$2 = ''; // empty string to avoid regexp issues\n\n\tvar versions$1 = {};\n\tvar release$1 = {};\n\tvar config$1 = {};\n\n\tfunction noop$1() {}\n\n\tvar on$1 = noop$1;\n\tvar addListener$1 = noop$1;\n\tvar once$1 = noop$1;\n\tvar off$1 = noop$1;\n\tvar removeListener$1 = noop$1;\n\tvar removeAllListeners$1 = noop$1;\n\tvar emit$1 = noop$1;\n\tfunction binding$1(name) {\n\t  throw new Error('process.binding is not supported');\n\t}\n\tfunction cwd$1() {\n\t  return '/';\n\t}\n\tfunction chdir$1(dir) {\n\t  throw new Error('process.chdir is not supported');\n\t}\n\tfunction umask$1() {\n\t  return 0;\n\t} // from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js\n\n\tvar performance$1 = global$1.performance || {};\n\n\tvar performanceNow$1 = performance$1.now || performance$1.mozNow || performance$1.msNow || performance$1.oNow || performance$1.webkitNow || function () {\n\t  return new Date().getTime();\n\t}; // generate timestamp or delta\n\t// see http://nodejs.org/api/process.html#process_process_hrtime\n\n\n\tfunction hrtime$1(previousTimestamp) {\n\t  var clocktime = performanceNow$1.call(performance$1) * 1e-3;\n\t  var seconds = Math.floor(clocktime);\n\t  var nanoseconds = Math.floor(clocktime % 1 * 1e9);\n\n\t  if (previousTimestamp) {\n\t    seconds = seconds - previousTimestamp[0];\n\t    nanoseconds = nanoseconds - previousTimestamp[1];\n\n\t    if (nanoseconds < 0) {\n\t      seconds--;\n\t      nanoseconds += 1e9;\n\t    }\n\t  }\n\n\t  return [seconds, nanoseconds];\n\t}\n\tvar startTime$1 = new Date();\n\tfunction uptime$1() {\n\t  var currentTime = new Date();\n\t  var dif = currentTime - startTime$1;\n\t  return dif / 1000;\n\t}\n\tvar process$4 = {\n\t  nextTick: nextTick$1,\n\t  title: title$1,\n\t  browser: browser$4,\n\t  env: env$1,\n\t  argv: argv$1,\n\t  version: version$2,\n\t  versions: versions$1,\n\t  on: on$1,\n\t  addListener: addListener$1,\n\t  once: once$1,\n\t  off: off$1,\n\t  removeListener: removeListener$1,\n\t  removeAllListeners: removeAllListeners$1,\n\t  emit: emit$1,\n\t  binding: binding$1,\n\t  cwd: cwd$1,\n\t  chdir: chdir$1,\n\t  umask: umask$1,\n\t  hrtime: hrtime$1,\n\t  platform: platform$1,\n\t  release: release$1,\n\t  config: config$1,\n\t  uptime: uptime$1\n\t};\n\n\tvar PROPER_FUNCTION_NAME$3 = functionName.PROPER;\n\n\n\n\n\n\n\n\tvar TO_STRING = 'toString';\n\tvar RegExpPrototype$1 = RegExp.prototype;\n\tvar n$ToString = RegExpPrototype$1[TO_STRING];\n\tvar getFlags$1 = functionUncurryThis(regexpFlags);\n\n\tvar NOT_GENERIC = fails(function () { return n$ToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });\n\t// FF44- RegExp#toString has a wrong name\n\tvar INCORRECT_NAME = PROPER_FUNCTION_NAME$3 && n$ToString.name != TO_STRING;\n\n\t// `RegExp.prototype.toString` method\n\t// https://tc39.es/ecma262/#sec-regexp.prototype.tostring\n\tif (NOT_GENERIC || INCORRECT_NAME) {\n\t  redefine(RegExp.prototype, TO_STRING, function toString() {\n\t    var R = anObject(this);\n\t    var p = toString_1(R.source);\n\t    var rf = R.flags;\n\t    var f = toString_1(rf === undefined && objectIsPrototypeOf(RegExpPrototype$1, R) && !('flags' in RegExpPrototype$1) ? getFlags$1(R) : rf);\n\t    return '/' + p + '/' + f;\n\t  }, { unsafe: true });\n\t}\n\n\tvar correctPrototypeGetter = !fails(function () {\n\t  function F() { /* empty */ }\n\t  F.prototype.constructor = null;\n\t  // eslint-disable-next-line es/no-object-getprototypeof -- required for testing\n\t  return Object.getPrototypeOf(new F()) !== F.prototype;\n\t});\n\n\tvar IE_PROTO = sharedKey('IE_PROTO');\n\tvar Object$1 = global_1.Object;\n\tvar ObjectPrototype$3 = Object$1.prototype;\n\n\t// `Object.getPrototypeOf` method\n\t// https://tc39.es/ecma262/#sec-object.getprototypeof\n\tvar objectGetPrototypeOf = correctPrototypeGetter ? Object$1.getPrototypeOf : function (O) {\n\t  var object = toObject(O);\n\t  if (hasOwnProperty_1(object, IE_PROTO)) return object[IE_PROTO];\n\t  var constructor = object.constructor;\n\t  if (isCallable(constructor) && object instanceof constructor) {\n\t    return constructor.prototype;\n\t  } return object instanceof Object$1 ? ObjectPrototype$3 : null;\n\t};\n\n\tvar FAILS_ON_PRIMITIVES$4 = fails(function () { objectGetPrototypeOf(1); });\n\n\t// `Object.getPrototypeOf` method\n\t// https://tc39.es/ecma262/#sec-object.getprototypeof\n\t_export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4, sham: !correctPrototypeGetter }, {\n\t  getPrototypeOf: function getPrototypeOf(it) {\n\t    return objectGetPrototypeOf(toObject(it));\n\t  }\n\t});\n\n\tvar FUNCTION_NAME_EXISTS = functionName.EXISTS;\n\n\tvar defineProperty$a = objectDefineProperty.f;\n\n\tvar FunctionPrototype$1 = Function.prototype;\n\tvar functionToString = functionUncurryThis(FunctionPrototype$1.toString);\n\tvar nameRE = /function\\b(?:\\s|\\/\\*[\\S\\s]*?\\*\\/|\\/\\/[^\\n\\r]*[\\n\\r]+)*([^\\s(/]*)/;\n\tvar regExpExec = functionUncurryThis(nameRE.exec);\n\tvar NAME$1 = 'name';\n\n\t// Function instances `.name` property\n\t// https://tc39.es/ecma262/#sec-function-instances-name\n\tif (descriptors && !FUNCTION_NAME_EXISTS) {\n\t  defineProperty$a(FunctionPrototype$1, NAME$1, {\n\t    configurable: true,\n\t    get: function () {\n\t      try {\n\t        return regExpExec(nameRE, functionToString(this))[1];\n\t      } catch (error) {\n\t        return '';\n\t      }\n\t    }\n\t  });\n\t}\n\n\t// `Reflect.ownKeys` method\n\t// https://tc39.es/ecma262/#sec-reflect.ownkeys\n\t_export({ target: 'Reflect', stat: true }, {\n\t  ownKeys: ownKeys$1\n\t});\n\n\tvar domain; // This constructor is used to store event handlers. Instantiating this is\n\t// faster than explicitly calling `Object.create(null)` to get a \"clean\" empty\n\t// object (tested with v8 v4.9).\n\n\tfunction EventHandlers() {}\n\n\tEventHandlers.prototype = Object.create(null);\n\n\tfunction EventEmitter$2() {\n\t  EventEmitter$2.init.call(this);\n\t}\n\t// require('events') === require('events').EventEmitter\n\n\tEventEmitter$2.EventEmitter = EventEmitter$2;\n\tEventEmitter$2.usingDomains = false;\n\tEventEmitter$2.prototype.domain = undefined;\n\tEventEmitter$2.prototype._events = undefined;\n\tEventEmitter$2.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are\n\t// added to it. This is a useful default which helps finding memory leaks.\n\n\tEventEmitter$2.defaultMaxListeners = 10;\n\n\tEventEmitter$2.init = function () {\n\t  this.domain = null;\n\n\t  if (EventEmitter$2.usingDomains) {\n\t    // if there is an active domain, then attach to it.\n\t    if (domain.active ) ;\n\t  }\n\n\t  if (!this._events || this._events === Object.getPrototypeOf(this)._events) {\n\t    this._events = new EventHandlers();\n\t    this._eventsCount = 0;\n\t  }\n\n\t  this._maxListeners = this._maxListeners || undefined;\n\t}; // Obviously not all Emitters should be limited to 10. This function allows\n\t// that to be increased. Set to zero for unlimited.\n\n\n\tEventEmitter$2.prototype.setMaxListeners = function setMaxListeners(n) {\n\t  if (typeof n !== 'number' || n < 0 || isNaN(n)) throw new TypeError('\"n\" argument must be a positive number');\n\t  this._maxListeners = n;\n\t  return this;\n\t};\n\n\tfunction $getMaxListeners(that) {\n\t  if (that._maxListeners === undefined) return EventEmitter$2.defaultMaxListeners;\n\t  return that._maxListeners;\n\t}\n\n\tEventEmitter$2.prototype.getMaxListeners = function getMaxListeners() {\n\t  return $getMaxListeners(this);\n\t}; // These standalone emit* functions are used to optimize calling of event\n\t// handlers for fast cases because emit() itself often has a variable number of\n\t// arguments and can be deoptimized because of that. These functions always have\n\t// the same number of arguments and thus do not get deoptimized, so the code\n\t// inside them can execute faster.\n\n\n\tfunction emitNone(handler, isFn, self) {\n\t  if (isFn) handler.call(self);else {\n\t    var len = handler.length;\n\t    var listeners = arrayClone(handler, len);\n\n\t    for (var i = 0; i < len; ++i) {\n\t      listeners[i].call(self);\n\t    }\n\t  }\n\t}\n\n\tfunction emitOne(handler, isFn, self, arg1) {\n\t  if (isFn) handler.call(self, arg1);else {\n\t    var len = handler.length;\n\t    var listeners = arrayClone(handler, len);\n\n\t    for (var i = 0; i < len; ++i) {\n\t      listeners[i].call(self, arg1);\n\t    }\n\t  }\n\t}\n\n\tfunction emitTwo(handler, isFn, self, arg1, arg2) {\n\t  if (isFn) handler.call(self, arg1, arg2);else {\n\t    var len = handler.length;\n\t    var listeners = arrayClone(handler, len);\n\n\t    for (var i = 0; i < len; ++i) {\n\t      listeners[i].call(self, arg1, arg2);\n\t    }\n\t  }\n\t}\n\n\tfunction emitThree(handler, isFn, self, arg1, arg2, arg3) {\n\t  if (isFn) handler.call(self, arg1, arg2, arg3);else {\n\t    var len = handler.length;\n\t    var listeners = arrayClone(handler, len);\n\n\t    for (var i = 0; i < len; ++i) {\n\t      listeners[i].call(self, arg1, arg2, arg3);\n\t    }\n\t  }\n\t}\n\n\tfunction emitMany(handler, isFn, self, args) {\n\t  if (isFn) handler.apply(self, args);else {\n\t    var len = handler.length;\n\t    var listeners = arrayClone(handler, len);\n\n\t    for (var i = 0; i < len; ++i) {\n\t      listeners[i].apply(self, args);\n\t    }\n\t  }\n\t}\n\n\tEventEmitter$2.prototype.emit = function emit(type) {\n\t  var er, handler, len, args, i, events, domain;\n\t  var doError = type === 'error';\n\t  events = this._events;\n\t  if (events) doError = doError && events.error == null;else if (!doError) return false;\n\t  domain = this.domain; // If there is no 'error' event listener then throw.\n\n\t  if (doError) {\n\t    er = arguments[1];\n\n\t    if (domain) {\n\t      if (!er) er = new Error('Uncaught, unspecified \"error\" event');\n\t      er.domainEmitter = this;\n\t      er.domain = domain;\n\t      er.domainThrown = false;\n\t      domain.emit('error', er);\n\t    } else if (er instanceof Error) {\n\t      throw er; // Unhandled 'error' event\n\t    } else {\n\t      // At least give some kind of context to the user\n\t      var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n\t      err.context = er;\n\t      throw err;\n\t    }\n\n\t    return false;\n\t  }\n\n\t  handler = events[type];\n\t  if (!handler) return false;\n\t  var isFn = typeof handler === 'function';\n\t  len = arguments.length;\n\n\t  switch (len) {\n\t    // fast cases\n\t    case 1:\n\t      emitNone(handler, isFn, this);\n\t      break;\n\n\t    case 2:\n\t      emitOne(handler, isFn, this, arguments[1]);\n\t      break;\n\n\t    case 3:\n\t      emitTwo(handler, isFn, this, arguments[1], arguments[2]);\n\t      break;\n\n\t    case 4:\n\t      emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);\n\t      break;\n\t    // slower\n\n\t    default:\n\t      args = new Array(len - 1);\n\n\t      for (i = 1; i < len; i++) {\n\t        args[i - 1] = arguments[i];\n\t      }\n\n\t      emitMany(handler, isFn, this, args);\n\t  }\n\t  return true;\n\t};\n\n\tfunction _addListener(target, type, listener, prepend) {\n\t  var m;\n\t  var events;\n\t  var existing;\n\t  if (typeof listener !== 'function') throw new TypeError('\"listener\" argument must be a function');\n\t  events = target._events;\n\n\t  if (!events) {\n\t    events = target._events = new EventHandlers();\n\t    target._eventsCount = 0;\n\t  } else {\n\t    // To avoid recursion in the case that type === \"newListener\"! Before\n\t    // adding it to the listeners, first emit \"newListener\".\n\t    if (events.newListener) {\n\t      target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the\n\t      // this._events to be assigned to a new object\n\n\t      events = target._events;\n\t    }\n\n\t    existing = events[type];\n\t  }\n\n\t  if (!existing) {\n\t    // Optimize the case of one listener. Don't need the extra array object.\n\t    existing = events[type] = listener;\n\t    ++target._eventsCount;\n\t  } else {\n\t    if (typeof existing === 'function') {\n\t      // Adding the second element, need to change to array.\n\t      existing = events[type] = prepend ? [listener, existing] : [existing, listener];\n\t    } else {\n\t      // If we've already got an array, just append.\n\t      if (prepend) {\n\t        existing.unshift(listener);\n\t      } else {\n\t        existing.push(listener);\n\t      }\n\t    } // Check for listener leak\n\n\n\t    if (!existing.warned) {\n\t      m = $getMaxListeners(target);\n\n\t      if (m && m > 0 && existing.length > m) {\n\t        existing.warned = true;\n\t        var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + type + ' listeners added. ' + 'Use emitter.setMaxListeners() to increase limit');\n\t        w.name = 'MaxListenersExceededWarning';\n\t        w.emitter = target;\n\t        w.type = type;\n\t        w.count = existing.length;\n\t        emitWarning$1(w);\n\t      }\n\t    }\n\t  }\n\n\t  return target;\n\t}\n\n\tfunction emitWarning$1(e) {\n\t  typeof console.warn === 'function' ? console.warn(e) : console.log(e);\n\t}\n\n\tEventEmitter$2.prototype.addListener = function addListener(type, listener) {\n\t  return _addListener(this, type, listener, false);\n\t};\n\n\tEventEmitter$2.prototype.on = EventEmitter$2.prototype.addListener;\n\n\tEventEmitter$2.prototype.prependListener = function prependListener(type, listener) {\n\t  return _addListener(this, type, listener, true);\n\t};\n\n\tfunction _onceWrap(target, type, listener) {\n\t  var fired = false;\n\n\t  function g() {\n\t    target.removeListener(type, g);\n\n\t    if (!fired) {\n\t      fired = true;\n\t      listener.apply(target, arguments);\n\t    }\n\t  }\n\n\t  g.listener = listener;\n\t  return g;\n\t}\n\n\tEventEmitter$2.prototype.once = function once(type, listener) {\n\t  if (typeof listener !== 'function') throw new TypeError('\"listener\" argument must be a function');\n\t  this.on(type, _onceWrap(this, type, listener));\n\t  return this;\n\t};\n\n\tEventEmitter$2.prototype.prependOnceListener = function prependOnceListener(type, listener) {\n\t  if (typeof listener !== 'function') throw new TypeError('\"listener\" argument must be a function');\n\t  this.prependListener(type, _onceWrap(this, type, listener));\n\t  return this;\n\t}; // emits a 'removeListener' event iff the listener was removed\n\n\n\tEventEmitter$2.prototype.removeListener = function removeListener(type, listener) {\n\t  var list, events, position, i, originalListener;\n\t  if (typeof listener !== 'function') throw new TypeError('\"listener\" argument must be a function');\n\t  events = this._events;\n\t  if (!events) return this;\n\t  list = events[type];\n\t  if (!list) return this;\n\n\t  if (list === listener || list.listener && list.listener === listener) {\n\t    if (--this._eventsCount === 0) this._events = new EventHandlers();else {\n\t      delete events[type];\n\t      if (events.removeListener) this.emit('removeListener', type, list.listener || listener);\n\t    }\n\t  } else if (typeof list !== 'function') {\n\t    position = -1;\n\n\t    for (i = list.length; i-- > 0;) {\n\t      if (list[i] === listener || list[i].listener && list[i].listener === listener) {\n\t        originalListener = list[i].listener;\n\t        position = i;\n\t        break;\n\t      }\n\t    }\n\n\t    if (position < 0) return this;\n\n\t    if (list.length === 1) {\n\t      list[0] = undefined;\n\n\t      if (--this._eventsCount === 0) {\n\t        this._events = new EventHandlers();\n\t        return this;\n\t      } else {\n\t        delete events[type];\n\t      }\n\t    } else {\n\t      spliceOne(list, position);\n\t    }\n\n\t    if (events.removeListener) this.emit('removeListener', type, originalListener || listener);\n\t  }\n\n\t  return this;\n\t};\n\n\tEventEmitter$2.prototype.removeAllListeners = function removeAllListeners(type) {\n\t  var listeners, events;\n\t  events = this._events;\n\t  if (!events) return this; // not listening for removeListener, no need to emit\n\n\t  if (!events.removeListener) {\n\t    if (arguments.length === 0) {\n\t      this._events = new EventHandlers();\n\t      this._eventsCount = 0;\n\t    } else if (events[type]) {\n\t      if (--this._eventsCount === 0) this._events = new EventHandlers();else delete events[type];\n\t    }\n\n\t    return this;\n\t  } // emit removeListener for all listeners on all events\n\n\n\t  if (arguments.length === 0) {\n\t    var keys = Object.keys(events);\n\n\t    for (var i = 0, key; i < keys.length; ++i) {\n\t      key = keys[i];\n\t      if (key === 'removeListener') continue;\n\t      this.removeAllListeners(key);\n\t    }\n\n\t    this.removeAllListeners('removeListener');\n\t    this._events = new EventHandlers();\n\t    this._eventsCount = 0;\n\t    return this;\n\t  }\n\n\t  listeners = events[type];\n\n\t  if (typeof listeners === 'function') {\n\t    this.removeListener(type, listeners);\n\t  } else if (listeners) {\n\t    // LIFO order\n\t    do {\n\t      this.removeListener(type, listeners[listeners.length - 1]);\n\t    } while (listeners[0]);\n\t  }\n\n\t  return this;\n\t};\n\n\tEventEmitter$2.prototype.listeners = function listeners(type) {\n\t  var evlistener;\n\t  var ret;\n\t  var events = this._events;\n\t  if (!events) ret = [];else {\n\t    evlistener = events[type];\n\t    if (!evlistener) ret = [];else if (typeof evlistener === 'function') ret = [evlistener.listener || evlistener];else ret = unwrapListeners(evlistener);\n\t  }\n\t  return ret;\n\t};\n\n\tEventEmitter$2.listenerCount = function (emitter, type) {\n\t  if (typeof emitter.listenerCount === 'function') {\n\t    return emitter.listenerCount(type);\n\t  } else {\n\t    return listenerCount$1.call(emitter, type);\n\t  }\n\t};\n\n\tEventEmitter$2.prototype.listenerCount = listenerCount$1;\n\n\tfunction listenerCount$1(type) {\n\t  var events = this._events;\n\n\t  if (events) {\n\t    var evlistener = events[type];\n\n\t    if (typeof evlistener === 'function') {\n\t      return 1;\n\t    } else if (evlistener) {\n\t      return evlistener.length;\n\t    }\n\t  }\n\n\t  return 0;\n\t}\n\n\tEventEmitter$2.prototype.eventNames = function eventNames() {\n\t  return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];\n\t}; // About 1.5x faster than the two-arg version of Array#splice().\n\n\n\tfunction spliceOne(list, index) {\n\t  for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) {\n\t    list[i] = list[k];\n\t  }\n\n\t  list.pop();\n\t}\n\n\tfunction arrayClone(arr, i) {\n\t  var copy = new Array(i);\n\n\t  while (i--) {\n\t    copy[i] = arr[i];\n\t  }\n\n\t  return copy;\n\t}\n\n\tfunction unwrapListeners(arr) {\n\t  var ret = new Array(arr.length);\n\n\t  for (var i = 0; i < ret.length; ++i) {\n\t    ret[i] = arr[i].listener || arr[i];\n\t  }\n\n\t  return ret;\n\t}\n\n\tfunction _asyncIterator(iterable) {\n\t  var method,\n\t      async,\n\t      sync,\n\t      retry = 2;\n\n\t  for (\"undefined\" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) {\n\t    if (async && null != (method = iterable[async])) return method.call(iterable);\n\t    if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable));\n\t    async = \"@@asyncIterator\", sync = \"@@iterator\";\n\t  }\n\n\t  throw new TypeError(\"Object is not async iterable\");\n\t}\n\n\tfunction AsyncFromSyncIterator(s) {\n\t  function AsyncFromSyncIteratorContinuation(r) {\n\t    if (Object(r) !== r) return Promise.reject(new TypeError(r + \" is not an object.\"));\n\t    var done = r.done;\n\t    return Promise.resolve(r.value).then(function (value) {\n\t      return {\n\t        value: value,\n\t        done: done\n\t      };\n\t    });\n\t  }\n\n\t  return AsyncFromSyncIterator = function (s) {\n\t    this.s = s, this.n = s.next;\n\t  }, AsyncFromSyncIterator.prototype = {\n\t    s: null,\n\t    n: null,\n\t    next: function () {\n\t      return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));\n\t    },\n\t    return: function (value) {\n\t      var ret = this.s.return;\n\t      return void 0 === ret ? Promise.resolve({\n\t        value: value,\n\t        done: !0\n\t      }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));\n\t    },\n\t    throw: function (value) {\n\t      var thr = this.s.return;\n\t      return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));\n\t    }\n\t  }, new AsyncFromSyncIterator(s);\n\t}\n\n\tfunction ownKeys(object, enumerableOnly) {\n\t  var keys = Object.keys(object);\n\n\t  if (Object.getOwnPropertySymbols) {\n\t    var symbols = Object.getOwnPropertySymbols(object);\n\t    enumerableOnly && (symbols = symbols.filter(function (sym) {\n\t      return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n\t    })), keys.push.apply(keys, symbols);\n\t  }\n\n\t  return keys;\n\t}\n\n\tfunction _objectSpread2(target) {\n\t  for (var i = 1; i < arguments.length; i++) {\n\t    var source = null != arguments[i] ? arguments[i] : {};\n\t    i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {\n\t      _defineProperty(target, key, source[key]);\n\t    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {\n\t      Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n\t    });\n\t  }\n\n\t  return target;\n\t}\n\n\tfunction _typeof(obj) {\n\t  \"@babel/helpers - typeof\";\n\n\t  return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) {\n\t    return typeof obj;\n\t  } : function (obj) {\n\t    return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n\t  }, _typeof(obj);\n\t}\n\n\tfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n\t  try {\n\t    var info = gen[key](arg);\n\t    var value = info.value;\n\t  } catch (error) {\n\t    reject(error);\n\t    return;\n\t  }\n\n\t  if (info.done) {\n\t    resolve(value);\n\t  } else {\n\t    Promise.resolve(value).then(_next, _throw);\n\t  }\n\t}\n\n\tfunction _asyncToGenerator(fn) {\n\t  return function () {\n\t    var self = this,\n\t        args = arguments;\n\t    return new Promise(function (resolve, reject) {\n\t      var gen = fn.apply(self, args);\n\n\t      function _next(value) {\n\t        asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value);\n\t      }\n\n\t      function _throw(err) {\n\t        asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err);\n\t      }\n\n\t      _next(undefined);\n\t    });\n\t  };\n\t}\n\n\tfunction _classCallCheck(instance, Constructor) {\n\t  if (!(instance instanceof Constructor)) {\n\t    throw new TypeError(\"Cannot call a class as a function\");\n\t  }\n\t}\n\n\tfunction _defineProperties(target, props) {\n\t  for (var i = 0; i < props.length; i++) {\n\t    var descriptor = props[i];\n\t    descriptor.enumerable = descriptor.enumerable || false;\n\t    descriptor.configurable = true;\n\t    if (\"value\" in descriptor) descriptor.writable = true;\n\t    Object.defineProperty(target, descriptor.key, descriptor);\n\t  }\n\t}\n\n\tfunction _createClass(Constructor, protoProps, staticProps) {\n\t  if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n\t  if (staticProps) _defineProperties(Constructor, staticProps);\n\t  Object.defineProperty(Constructor, \"prototype\", {\n\t    writable: false\n\t  });\n\t  return Constructor;\n\t}\n\n\tfunction _defineProperty(obj, key, value) {\n\t  if (key in obj) {\n\t    Object.defineProperty(obj, key, {\n\t      value: value,\n\t      enumerable: true,\n\t      configurable: true,\n\t      writable: true\n\t    });\n\t  } else {\n\t    obj[key] = value;\n\t  }\n\n\t  return obj;\n\t}\n\n\tfunction _inherits(subClass, superClass) {\n\t  if (typeof superClass !== \"function\" && superClass !== null) {\n\t    throw new TypeError(\"Super expression must either be null or a function\");\n\t  }\n\n\t  subClass.prototype = Object.create(superClass && superClass.prototype, {\n\t    constructor: {\n\t      value: subClass,\n\t      writable: true,\n\t      configurable: true\n\t    }\n\t  });\n\t  Object.defineProperty(subClass, \"prototype\", {\n\t    writable: false\n\t  });\n\t  if (superClass) _setPrototypeOf(subClass, superClass);\n\t}\n\n\tfunction _getPrototypeOf(o) {\n\t  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {\n\t    return o.__proto__ || Object.getPrototypeOf(o);\n\t  };\n\t  return _getPrototypeOf(o);\n\t}\n\n\tfunction _setPrototypeOf(o, p) {\n\t  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n\t    o.__proto__ = p;\n\t    return o;\n\t  };\n\n\t  return _setPrototypeOf(o, p);\n\t}\n\n\tfunction _isNativeReflectConstruct() {\n\t  if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n\t  if (Reflect.construct.sham) return false;\n\t  if (typeof Proxy === \"function\") return true;\n\n\t  try {\n\t    Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n\t    return true;\n\t  } catch (e) {\n\t    return false;\n\t  }\n\t}\n\n\tfunction _assertThisInitialized(self) {\n\t  if (self === void 0) {\n\t    throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n\t  }\n\n\t  return self;\n\t}\n\n\tfunction _possibleConstructorReturn(self, call) {\n\t  if (call && (typeof call === \"object\" || typeof call === \"function\")) {\n\t    return call;\n\t  } else if (call !== void 0) {\n\t    throw new TypeError(\"Derived constructors may only return object or undefined\");\n\t  }\n\n\t  return _assertThisInitialized(self);\n\t}\n\n\tfunction _createSuper(Derived) {\n\t  var hasNativeReflectConstruct = _isNativeReflectConstruct();\n\n\t  return function _createSuperInternal() {\n\t    var Super = _getPrototypeOf(Derived),\n\t        result;\n\n\t    if (hasNativeReflectConstruct) {\n\t      var NewTarget = _getPrototypeOf(this).constructor;\n\n\t      result = Reflect.construct(Super, arguments, NewTarget);\n\t    } else {\n\t      result = Super.apply(this, arguments);\n\t    }\n\n\t    return _possibleConstructorReturn(this, result);\n\t  };\n\t}\n\n\tfunction _toConsumableArray(arr) {\n\t  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();\n\t}\n\n\tfunction _arrayWithoutHoles(arr) {\n\t  if (Array.isArray(arr)) return _arrayLikeToArray(arr);\n\t}\n\n\tfunction _iterableToArray(iter) {\n\t  if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter);\n\t}\n\n\tfunction _unsupportedIterableToArray(o, minLen) {\n\t  if (!o) return;\n\t  if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n\t  var n = Object.prototype.toString.call(o).slice(8, -1);\n\t  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n\t}\n\n\tfunction _arrayLikeToArray(arr, len) {\n\t  if (len == null || len > arr.length) len = arr.length;\n\n\t  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n\t  return arr2;\n\t}\n\n\tfunction _nonIterableSpread() {\n\t  throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t}\n\n\tvar un$Join = functionUncurryThis([].join);\n\n\tvar ES3_STRINGS = indexedObject != Object;\n\tvar STRICT_METHOD$2 = arrayMethodIsStrict('join', ',');\n\n\t// `Array.prototype.join` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.join\n\t_export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$2 }, {\n\t  join: function join(separator) {\n\t    return un$Join(toIndexedObject(this), separator === undefined ? ',' : separator);\n\t  }\n\t});\n\n\tvar FunctionPrototype = Function.prototype;\n\tvar apply = FunctionPrototype.apply;\n\tvar call = FunctionPrototype.call;\n\n\t// eslint-disable-next-line es/no-reflect -- safe\n\tvar functionApply = typeof Reflect == 'object' && Reflect.apply || (functionBindNative ? call.bind(apply) : function () {\n\t  return call.apply(apply, arguments);\n\t});\n\n\tvar charAt$4 = functionUncurryThis(''.charAt);\n\tvar charCodeAt$1 = functionUncurryThis(''.charCodeAt);\n\tvar stringSlice$6 = functionUncurryThis(''.slice);\n\n\tvar createMethod$3 = function (CONVERT_TO_STRING) {\n\t  return function ($this, pos) {\n\t    var S = toString_1(requireObjectCoercible($this));\n\t    var position = toIntegerOrInfinity(pos);\n\t    var size = S.length;\n\t    var first, second;\n\t    if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;\n\t    first = charCodeAt$1(S, position);\n\t    return first < 0xD800 || first > 0xDBFF || position + 1 === size\n\t      || (second = charCodeAt$1(S, position + 1)) < 0xDC00 || second > 0xDFFF\n\t        ? CONVERT_TO_STRING\n\t          ? charAt$4(S, position)\n\t          : first\n\t        : CONVERT_TO_STRING\n\t          ? stringSlice$6(S, position, position + 2)\n\t          : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;\n\t  };\n\t};\n\n\tvar stringMultibyte = {\n\t  // `String.prototype.codePointAt` method\n\t  // https://tc39.es/ecma262/#sec-string.prototype.codepointat\n\t  codeAt: createMethod$3(false),\n\t  // `String.prototype.at` method\n\t  // https://github.com/mathiasbynens/String.prototype.at\n\t  charAt: createMethod$3(true)\n\t};\n\n\tvar charAt$3 = stringMultibyte.charAt;\n\n\t// `AdvanceStringIndex` abstract operation\n\t// https://tc39.es/ecma262/#sec-advancestringindex\n\tvar advanceStringIndex = function (S, index, unicode) {\n\t  return index + (unicode ? charAt$3(S, index).length : 1);\n\t};\n\n\tvar floor$5 = Math.floor;\n\tvar charAt$2 = functionUncurryThis(''.charAt);\n\tvar replace$3 = functionUncurryThis(''.replace);\n\tvar stringSlice$5 = functionUncurryThis(''.slice);\n\tvar SUBSTITUTION_SYMBOLS = /\\$([$&'`]|\\d{1,2}|<[^>]*>)/g;\n\tvar SUBSTITUTION_SYMBOLS_NO_NAMED = /\\$([$&'`]|\\d{1,2})/g;\n\n\t// `GetSubstitution` abstract operation\n\t// https://tc39.es/ecma262/#sec-getsubstitution\n\tvar getSubstitution = function (matched, str, position, captures, namedCaptures, replacement) {\n\t  var tailPos = position + matched.length;\n\t  var m = captures.length;\n\t  var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;\n\t  if (namedCaptures !== undefined) {\n\t    namedCaptures = toObject(namedCaptures);\n\t    symbols = SUBSTITUTION_SYMBOLS;\n\t  }\n\t  return replace$3(replacement, symbols, function (match, ch) {\n\t    var capture;\n\t    switch (charAt$2(ch, 0)) {\n\t      case '$': return '$';\n\t      case '&': return matched;\n\t      case '`': return stringSlice$5(str, 0, position);\n\t      case \"'\": return stringSlice$5(str, tailPos);\n\t      case '<':\n\t        capture = namedCaptures[stringSlice$5(ch, 1, -1)];\n\t        break;\n\t      default: // \\d\\d?\n\t        var n = +ch;\n\t        if (n === 0) return match;\n\t        if (n > m) {\n\t          var f = floor$5(n / 10);\n\t          if (f === 0) return match;\n\t          if (f <= m) return captures[f - 1] === undefined ? charAt$2(ch, 1) : captures[f - 1] + charAt$2(ch, 1);\n\t          return match;\n\t        }\n\t        capture = captures[n - 1];\n\t    }\n\t    return capture === undefined ? '' : capture;\n\t  });\n\t};\n\n\tvar REPLACE = wellKnownSymbol('replace');\n\tvar max$2 = Math.max;\n\tvar min$4 = Math.min;\n\tvar concat$1 = functionUncurryThis([].concat);\n\tvar push$4 = functionUncurryThis([].push);\n\tvar stringIndexOf$2 = functionUncurryThis(''.indexOf);\n\tvar stringSlice$4 = functionUncurryThis(''.slice);\n\n\tvar maybeToString = function (it) {\n\t  return it === undefined ? it : String(it);\n\t};\n\n\t// IE <= 11 replaces $0 with the whole match, as if it was $&\n\t// https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0\n\tvar REPLACE_KEEPS_$0 = (function () {\n\t  // eslint-disable-next-line regexp/prefer-escape-replacement-dollar-char -- required for testing\n\t  return 'a'.replace(/./, '$0') === '$0';\n\t})();\n\n\t// Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string\n\tvar REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {\n\t  if (/./[REPLACE]) {\n\t    return /./[REPLACE]('a', '$0') === '';\n\t  }\n\t  return false;\n\t})();\n\n\tvar REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {\n\t  var re = /./;\n\t  re.exec = function () {\n\t    var result = [];\n\t    result.groups = { a: '7' };\n\t    return result;\n\t  };\n\t  // eslint-disable-next-line regexp/no-useless-dollar-replacements -- false positive\n\t  return ''.replace(re, '$<a>') !== '7';\n\t});\n\n\t// @@replace logic\n\tfixRegexpWellKnownSymbolLogic('replace', function (_, nativeReplace, maybeCallNative) {\n\t  var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';\n\n\t  return [\n\t    // `String.prototype.replace` method\n\t    // https://tc39.es/ecma262/#sec-string.prototype.replace\n\t    function replace(searchValue, replaceValue) {\n\t      var O = requireObjectCoercible(this);\n\t      var replacer = searchValue == undefined ? undefined : getMethod(searchValue, REPLACE);\n\t      return replacer\n\t        ? functionCall(replacer, searchValue, O, replaceValue)\n\t        : functionCall(nativeReplace, toString_1(O), searchValue, replaceValue);\n\t    },\n\t    // `RegExp.prototype[@@replace]` method\n\t    // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace\n\t    function (string, replaceValue) {\n\t      var rx = anObject(this);\n\t      var S = toString_1(string);\n\n\t      if (\n\t        typeof replaceValue == 'string' &&\n\t        stringIndexOf$2(replaceValue, UNSAFE_SUBSTITUTE) === -1 &&\n\t        stringIndexOf$2(replaceValue, '$<') === -1\n\t      ) {\n\t        var res = maybeCallNative(nativeReplace, rx, S, replaceValue);\n\t        if (res.done) return res.value;\n\t      }\n\n\t      var functionalReplace = isCallable(replaceValue);\n\t      if (!functionalReplace) replaceValue = toString_1(replaceValue);\n\n\t      var global = rx.global;\n\t      if (global) {\n\t        var fullUnicode = rx.unicode;\n\t        rx.lastIndex = 0;\n\t      }\n\t      var results = [];\n\t      while (true) {\n\t        var result = regexpExecAbstract(rx, S);\n\t        if (result === null) break;\n\n\t        push$4(results, result);\n\t        if (!global) break;\n\n\t        var matchStr = toString_1(result[0]);\n\t        if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);\n\t      }\n\n\t      var accumulatedResult = '';\n\t      var nextSourcePosition = 0;\n\t      for (var i = 0; i < results.length; i++) {\n\t        result = results[i];\n\n\t        var matched = toString_1(result[0]);\n\t        var position = max$2(min$4(toIntegerOrInfinity(result.index), S.length), 0);\n\t        var captures = [];\n\t        // NOTE: This is equivalent to\n\t        //   captures = result.slice(1).map(maybeToString)\n\t        // but for some reason `nativeSlice.call(result, 1, result.length)` (called in\n\t        // the slice polyfill when slicing native arrays) \"doesn't work\" in safari 9 and\n\t        // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.\n\t        for (var j = 1; j < result.length; j++) push$4(captures, maybeToString(result[j]));\n\t        var namedCaptures = result.groups;\n\t        if (functionalReplace) {\n\t          var replacerArgs = concat$1([matched], captures, position, S);\n\t          if (namedCaptures !== undefined) push$4(replacerArgs, namedCaptures);\n\t          var replacement = toString_1(functionApply(replaceValue, undefined, replacerArgs));\n\t        } else {\n\t          replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);\n\t        }\n\t        if (position >= nextSourcePosition) {\n\t          accumulatedResult += stringSlice$4(S, nextSourcePosition, position) + replacement;\n\t          nextSourcePosition = position + matched.length;\n\t        }\n\t      }\n\t      return accumulatedResult + stringSlice$4(S, nextSourcePosition);\n\t    }\n\t  ];\n\t}, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);\n\n\tvar String$3 = global_1.String;\n\tvar TypeError$c = global_1.TypeError;\n\n\tvar aPossiblePrototype = function (argument) {\n\t  if (typeof argument == 'object' || isCallable(argument)) return argument;\n\t  throw TypeError$c(\"Can't set \" + String$3(argument) + ' as a prototype');\n\t};\n\n\t/* eslint-disable no-proto -- safe */\n\n\n\n\n\t// `Object.setPrototypeOf` method\n\t// https://tc39.es/ecma262/#sec-object.setprototypeof\n\t// Works with __proto__ only. Old v8 can't work with null proto objects.\n\t// eslint-disable-next-line es/no-object-setprototypeof -- safe\n\tvar objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {\n\t  var CORRECT_SETTER = false;\n\t  var test = {};\n\t  var setter;\n\t  try {\n\t    // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe\n\t    setter = functionUncurryThis(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set);\n\t    setter(test, []);\n\t    CORRECT_SETTER = test instanceof Array;\n\t  } catch (error) { /* empty */ }\n\t  return function setPrototypeOf(O, proto) {\n\t    anObject(O);\n\t    aPossiblePrototype(proto);\n\t    if (CORRECT_SETTER) setter(O, proto);\n\t    else O.__proto__ = proto;\n\t    return O;\n\t  };\n\t}() : undefined);\n\n\t// makes subclassing work correct for wrapped built-ins\n\tvar inheritIfRequired = function ($this, dummy, Wrapper) {\n\t  var NewTarget, NewTargetPrototype;\n\t  if (\n\t    // it can work only with native `setPrototypeOf`\n\t    objectSetPrototypeOf &&\n\t    // we haven't completely correct pre-ES6 way for getting `new.target`, so use this\n\t    isCallable(NewTarget = dummy.constructor) &&\n\t    NewTarget !== Wrapper &&\n\t    isObject$1(NewTargetPrototype = NewTarget.prototype) &&\n\t    NewTargetPrototype !== Wrapper.prototype\n\t  ) objectSetPrototypeOf($this, NewTargetPrototype);\n\t  return $this;\n\t};\n\n\t// `thisNumberValue` abstract operation\n\t// https://tc39.es/ecma262/#sec-thisnumbervalue\n\tvar thisNumberValue = functionUncurryThis(1.0.valueOf);\n\n\t// a string of all valid unicode whitespaces\n\tvar whitespaces = '\\u0009\\u000A\\u000B\\u000C\\u000D\\u0020\\u00A0\\u1680\\u2000\\u2001\\u2002' +\n\t  '\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF';\n\n\tvar replace$2 = functionUncurryThis(''.replace);\n\tvar whitespace = '[' + whitespaces + ']';\n\tvar ltrim = RegExp('^' + whitespace + whitespace + '*');\n\tvar rtrim = RegExp(whitespace + whitespace + '*$');\n\n\t// `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation\n\tvar createMethod$2 = function (TYPE) {\n\t  return function ($this) {\n\t    var string = toString_1(requireObjectCoercible($this));\n\t    if (TYPE & 1) string = replace$2(string, ltrim, '');\n\t    if (TYPE & 2) string = replace$2(string, rtrim, '');\n\t    return string;\n\t  };\n\t};\n\n\tvar stringTrim = {\n\t  // `String.prototype.{ trimLeft, trimStart }` methods\n\t  // https://tc39.es/ecma262/#sec-string.prototype.trimstart\n\t  start: createMethod$2(1),\n\t  // `String.prototype.{ trimRight, trimEnd }` methods\n\t  // https://tc39.es/ecma262/#sec-string.prototype.trimend\n\t  end: createMethod$2(2),\n\t  // `String.prototype.trim` method\n\t  // https://tc39.es/ecma262/#sec-string.prototype.trim\n\t  trim: createMethod$2(3)\n\t};\n\n\tvar getOwnPropertyNames$3 = objectGetOwnPropertyNames.f;\n\tvar getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;\n\tvar defineProperty$9 = objectDefineProperty.f;\n\n\tvar trim = stringTrim.trim;\n\n\tvar NUMBER = 'Number';\n\tvar NativeNumber = global_1[NUMBER];\n\tvar NumberPrototype = NativeNumber.prototype;\n\tvar TypeError$b = global_1.TypeError;\n\tvar arraySlice$1 = functionUncurryThis(''.slice);\n\tvar charCodeAt = functionUncurryThis(''.charCodeAt);\n\n\t// `ToNumeric` abstract operation\n\t// https://tc39.es/ecma262/#sec-tonumeric\n\tvar toNumeric = function (value) {\n\t  var primValue = toPrimitive(value, 'number');\n\t  return typeof primValue == 'bigint' ? primValue : toNumber(primValue);\n\t};\n\n\t// `ToNumber` abstract operation\n\t// https://tc39.es/ecma262/#sec-tonumber\n\tvar toNumber = function (argument) {\n\t  var it = toPrimitive(argument, 'number');\n\t  var first, third, radix, maxCode, digits, length, index, code;\n\t  if (isSymbol$1(it)) throw TypeError$b('Cannot convert a Symbol value to a number');\n\t  if (typeof it == 'string' && it.length > 2) {\n\t    it = trim(it);\n\t    first = charCodeAt(it, 0);\n\t    if (first === 43 || first === 45) {\n\t      third = charCodeAt(it, 2);\n\t      if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix\n\t    } else if (first === 48) {\n\t      switch (charCodeAt(it, 1)) {\n\t        case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i\n\t        case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i\n\t        default: return +it;\n\t      }\n\t      digits = arraySlice$1(it, 2);\n\t      length = digits.length;\n\t      for (index = 0; index < length; index++) {\n\t        code = charCodeAt(digits, index);\n\t        // parseInt parses a string to a first unavailable symbol\n\t        // but ToNumber should return NaN if a string contains unavailable symbols\n\t        if (code < 48 || code > maxCode) return NaN;\n\t      } return parseInt(digits, radix);\n\t    }\n\t  } return +it;\n\t};\n\n\t// `Number` constructor\n\t// https://tc39.es/ecma262/#sec-number-constructor\n\tif (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {\n\t  var NumberWrapper = function Number(value) {\n\t    var n = arguments.length < 1 ? 0 : NativeNumber(toNumeric(value));\n\t    var dummy = this;\n\t    // check on 1..constructor(foo) case\n\t    return objectIsPrototypeOf(NumberPrototype, dummy) && fails(function () { thisNumberValue(dummy); })\n\t      ? inheritIfRequired(Object(n), dummy, NumberWrapper) : n;\n\t  };\n\t  for (var keys$3 = descriptors ? getOwnPropertyNames$3(NativeNumber) : (\n\t    // ES3:\n\t    'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +\n\t    // ES2015 (in case, if modules with ES2015 Number statics required before):\n\t    'EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,' +\n\t    // ESNext\n\t    'fromString,range'\n\t  ).split(','), j$1 = 0, key$1; keys$3.length > j$1; j$1++) {\n\t    if (hasOwnProperty_1(NativeNumber, key$1 = keys$3[j$1]) && !hasOwnProperty_1(NumberWrapper, key$1)) {\n\t      defineProperty$9(NumberWrapper, key$1, getOwnPropertyDescriptor$1(NativeNumber, key$1));\n\t    }\n\t  }\n\t  NumberWrapper.prototype = NumberPrototype;\n\t  NumberPrototype.constructor = NumberWrapper;\n\t  redefine(global_1, NUMBER, NumberWrapper);\n\t}\n\n\tvar MATCH$2 = wellKnownSymbol('match');\n\n\t// `IsRegExp` abstract operation\n\t// https://tc39.es/ecma262/#sec-isregexp\n\tvar isRegexp = function (it) {\n\t  var isRegExp;\n\t  return isObject$1(it) && ((isRegExp = it[MATCH$2]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');\n\t};\n\n\tvar SPECIES$3 = wellKnownSymbol('species');\n\n\tvar setSpecies = function (CONSTRUCTOR_NAME) {\n\t  var Constructor = getBuiltIn(CONSTRUCTOR_NAME);\n\t  var defineProperty = objectDefineProperty.f;\n\n\t  if (descriptors && Constructor && !Constructor[SPECIES$3]) {\n\t    defineProperty(Constructor, SPECIES$3, {\n\t      configurable: true,\n\t      get: function () { return this; }\n\t    });\n\t  }\n\t};\n\n\tvar defineProperty$8 = objectDefineProperty.f;\n\tvar getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;\n\n\n\n\n\n\n\n\n\tvar enforceInternalState = internalState.enforce;\n\n\n\n\n\n\tvar MATCH$1 = wellKnownSymbol('match');\n\tvar NativeRegExp = global_1.RegExp;\n\tvar RegExpPrototype = NativeRegExp.prototype;\n\tvar SyntaxError = global_1.SyntaxError;\n\tvar getFlags = functionUncurryThis(regexpFlags);\n\tvar exec$1 = functionUncurryThis(RegExpPrototype.exec);\n\tvar charAt$1 = functionUncurryThis(''.charAt);\n\tvar replace$1 = functionUncurryThis(''.replace);\n\tvar stringIndexOf$1 = functionUncurryThis(''.indexOf);\n\tvar stringSlice$3 = functionUncurryThis(''.slice);\n\t// TODO: Use only propper RegExpIdentifierName\n\tvar IS_NCG = /^\\?<[^\\s\\d!#%&*+<=>@^][^\\s!#%&*+<=>@^]*>/;\n\tvar re1 = /a/g;\n\tvar re2 = /a/g;\n\n\t// \"new\" should create a new object, old webkit bug\n\tvar CORRECT_NEW = new NativeRegExp(re1) !== re1;\n\n\tvar MISSED_STICKY = regexpStickyHelpers.MISSED_STICKY;\n\tvar UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y;\n\n\tvar BASE_FORCED = descriptors &&\n\t  (!CORRECT_NEW || MISSED_STICKY || regexpUnsupportedDotAll || regexpUnsupportedNcg || fails(function () {\n\t    re2[MATCH$1] = false;\n\t    // RegExp constructor can alter flags and IsRegExp works correct with @@match\n\t    return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';\n\t  }));\n\n\tvar handleDotAll = function (string) {\n\t  var length = string.length;\n\t  var index = 0;\n\t  var result = '';\n\t  var brackets = false;\n\t  var chr;\n\t  for (; index <= length; index++) {\n\t    chr = charAt$1(string, index);\n\t    if (chr === '\\\\') {\n\t      result += chr + charAt$1(string, ++index);\n\t      continue;\n\t    }\n\t    if (!brackets && chr === '.') {\n\t      result += '[\\\\s\\\\S]';\n\t    } else {\n\t      if (chr === '[') {\n\t        brackets = true;\n\t      } else if (chr === ']') {\n\t        brackets = false;\n\t      } result += chr;\n\t    }\n\t  } return result;\n\t};\n\n\tvar handleNCG = function (string) {\n\t  var length = string.length;\n\t  var index = 0;\n\t  var result = '';\n\t  var named = [];\n\t  var names = {};\n\t  var brackets = false;\n\t  var ncg = false;\n\t  var groupid = 0;\n\t  var groupname = '';\n\t  var chr;\n\t  for (; index <= length; index++) {\n\t    chr = charAt$1(string, index);\n\t    if (chr === '\\\\') {\n\t      chr = chr + charAt$1(string, ++index);\n\t    } else if (chr === ']') {\n\t      brackets = false;\n\t    } else if (!brackets) switch (true) {\n\t      case chr === '[':\n\t        brackets = true;\n\t        break;\n\t      case chr === '(':\n\t        if (exec$1(IS_NCG, stringSlice$3(string, index + 1))) {\n\t          index += 2;\n\t          ncg = true;\n\t        }\n\t        result += chr;\n\t        groupid++;\n\t        continue;\n\t      case chr === '>' && ncg:\n\t        if (groupname === '' || hasOwnProperty_1(names, groupname)) {\n\t          throw new SyntaxError('Invalid capture group name');\n\t        }\n\t        names[groupname] = true;\n\t        named[named.length] = [groupname, groupid];\n\t        ncg = false;\n\t        groupname = '';\n\t        continue;\n\t    }\n\t    if (ncg) groupname += chr;\n\t    else result += chr;\n\t  } return [result, named];\n\t};\n\n\t// `RegExp` constructor\n\t// https://tc39.es/ecma262/#sec-regexp-constructor\n\tif (isForced_1('RegExp', BASE_FORCED)) {\n\t  var RegExpWrapper = function RegExp(pattern, flags) {\n\t    var thisIsRegExp = objectIsPrototypeOf(RegExpPrototype, this);\n\t    var patternIsRegExp = isRegexp(pattern);\n\t    var flagsAreUndefined = flags === undefined;\n\t    var groups = [];\n\t    var rawPattern = pattern;\n\t    var rawFlags, dotAll, sticky, handled, result, state;\n\n\t    if (!thisIsRegExp && patternIsRegExp && flagsAreUndefined && pattern.constructor === RegExpWrapper) {\n\t      return pattern;\n\t    }\n\n\t    if (patternIsRegExp || objectIsPrototypeOf(RegExpPrototype, pattern)) {\n\t      pattern = pattern.source;\n\t      if (flagsAreUndefined) flags = 'flags' in rawPattern ? rawPattern.flags : getFlags(rawPattern);\n\t    }\n\n\t    pattern = pattern === undefined ? '' : toString_1(pattern);\n\t    flags = flags === undefined ? '' : toString_1(flags);\n\t    rawPattern = pattern;\n\n\t    if (regexpUnsupportedDotAll && 'dotAll' in re1) {\n\t      dotAll = !!flags && stringIndexOf$1(flags, 's') > -1;\n\t      if (dotAll) flags = replace$1(flags, /s/g, '');\n\t    }\n\n\t    rawFlags = flags;\n\n\t    if (MISSED_STICKY && 'sticky' in re1) {\n\t      sticky = !!flags && stringIndexOf$1(flags, 'y') > -1;\n\t      if (sticky && UNSUPPORTED_Y$1) flags = replace$1(flags, /y/g, '');\n\t    }\n\n\t    if (regexpUnsupportedNcg) {\n\t      handled = handleNCG(pattern);\n\t      pattern = handled[0];\n\t      groups = handled[1];\n\t    }\n\n\t    result = inheritIfRequired(NativeRegExp(pattern, flags), thisIsRegExp ? this : RegExpPrototype, RegExpWrapper);\n\n\t    if (dotAll || sticky || groups.length) {\n\t      state = enforceInternalState(result);\n\t      if (dotAll) {\n\t        state.dotAll = true;\n\t        state.raw = RegExpWrapper(handleDotAll(pattern), rawFlags);\n\t      }\n\t      if (sticky) state.sticky = true;\n\t      if (groups.length) state.groups = groups;\n\t    }\n\n\t    if (pattern !== rawPattern) try {\n\t      // fails in old engines, but we have no alternatives for unsupported regex syntax\n\t      createNonEnumerableProperty(result, 'source', rawPattern === '' ? '(?:)' : rawPattern);\n\t    } catch (error) { /* empty */ }\n\n\t    return result;\n\t  };\n\n\t  var proxy = function (key) {\n\t    key in RegExpWrapper || defineProperty$8(RegExpWrapper, key, {\n\t      configurable: true,\n\t      get: function () { return NativeRegExp[key]; },\n\t      set: function (it) { NativeRegExp[key] = it; }\n\t    });\n\t  };\n\n\t  for (var keys$2 = getOwnPropertyNames$2(NativeRegExp), index = 0; keys$2.length > index;) {\n\t    proxy(keys$2[index++]);\n\t  }\n\n\t  RegExpPrototype.constructor = RegExpWrapper;\n\t  RegExpWrapper.prototype = RegExpPrototype;\n\t  redefine(global_1, 'RegExp', RegExpWrapper);\n\t}\n\n\t// https://tc39.es/ecma262/#sec-get-regexp-@@species\n\tsetSpecies('RegExp');\n\n\tvar Array$6 = global_1.Array;\n\tvar max$1 = Math.max;\n\n\tvar arraySliceSimple = function (O, start, end) {\n\t  var length = lengthOfArrayLike(O);\n\t  var k = toAbsoluteIndex(start, length);\n\t  var fin = toAbsoluteIndex(end === undefined ? length : end, length);\n\t  var result = Array$6(max$1(fin - k, 0));\n\t  for (var n = 0; k < fin; k++, n++) createProperty(result, n, O[k]);\n\t  result.length = n;\n\t  return result;\n\t};\n\n\t/* eslint-disable es/no-object-getownpropertynames -- safe */\n\n\n\tvar $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;\n\n\n\tvar windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames\n\t  ? Object.getOwnPropertyNames(window) : [];\n\n\tvar getWindowNames = function (it) {\n\t  try {\n\t    return $getOwnPropertyNames$1(it);\n\t  } catch (error) {\n\t    return arraySliceSimple(windowNames);\n\t  }\n\t};\n\n\t// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window\n\tvar f$2 = function getOwnPropertyNames(it) {\n\t  return windowNames && classofRaw(it) == 'Window'\n\t    ? getWindowNames(it)\n\t    : $getOwnPropertyNames$1(toIndexedObject(it));\n\t};\n\n\tvar objectGetOwnPropertyNamesExternal = {\n\t\tf: f$2\n\t};\n\n\tvar getOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;\n\n\t// eslint-disable-next-line es/no-object-getownpropertynames -- required for testing\n\tvar FAILS_ON_PRIMITIVES$3 = fails(function () { return !Object.getOwnPropertyNames(1); });\n\n\t// `Object.getOwnPropertyNames` method\n\t// https://tc39.es/ecma262/#sec-object.getownpropertynames\n\t_export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3 }, {\n\t  getOwnPropertyNames: getOwnPropertyNames$1\n\t});\n\n\tvar $map$1 = arrayIteration.map;\n\n\n\tvar HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('map');\n\n\t// `Array.prototype.map` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.map\n\t// with adding support of @@species\n\t_export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 }, {\n\t  map: function map(callbackfn /* , thisArg */) {\n\t    return $map$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t  }\n\t});\n\n\t// @@match logic\n\tfixRegexpWellKnownSymbolLogic('match', function (MATCH, nativeMatch, maybeCallNative) {\n\t  return [\n\t    // `String.prototype.match` method\n\t    // https://tc39.es/ecma262/#sec-string.prototype.match\n\t    function match(regexp) {\n\t      var O = requireObjectCoercible(this);\n\t      var matcher = regexp == undefined ? undefined : getMethod(regexp, MATCH);\n\t      return matcher ? functionCall(matcher, regexp, O) : new RegExp(regexp)[MATCH](toString_1(O));\n\t    },\n\t    // `RegExp.prototype[@@match]` method\n\t    // https://tc39.es/ecma262/#sec-regexp.prototype-@@match\n\t    function (string) {\n\t      var rx = anObject(this);\n\t      var S = toString_1(string);\n\t      var res = maybeCallNative(nativeMatch, rx, S);\n\n\t      if (res.done) return res.value;\n\n\t      if (!rx.global) return regexpExecAbstract(rx, S);\n\n\t      var fullUnicode = rx.unicode;\n\t      rx.lastIndex = 0;\n\t      var A = [];\n\t      var n = 0;\n\t      var result;\n\t      while ((result = regexpExecAbstract(rx, S)) !== null) {\n\t        var matchStr = toString_1(result[0]);\n\t        A[n] = matchStr;\n\t        if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);\n\t        n++;\n\t      }\n\t      return n === 0 ? null : A;\n\t    }\n\t  ];\n\t});\n\n\tvar nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;\n\n\n\tvar FAILS_ON_PRIMITIVES$2 = fails(function () { nativeGetOwnPropertyDescriptor$1(1); });\n\tvar FORCED$6 = !descriptors || FAILS_ON_PRIMITIVES$2;\n\n\t// `Object.getOwnPropertyDescriptor` method\n\t// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor\n\t_export({ target: 'Object', stat: true, forced: FORCED$6, sham: !descriptors }, {\n\t  getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {\n\t    return nativeGetOwnPropertyDescriptor$1(toIndexedObject(it), key);\n\t  }\n\t});\n\n\tvar TypeError$a = global_1.TypeError;\n\n\t// `Assert: IsConstructor(argument) is true`\n\tvar aConstructor = function (argument) {\n\t  if (isConstructor(argument)) return argument;\n\t  throw TypeError$a(tryToString(argument) + ' is not a constructor');\n\t};\n\n\tvar SPECIES$2 = wellKnownSymbol('species');\n\n\t// `SpeciesConstructor` abstract operation\n\t// https://tc39.es/ecma262/#sec-speciesconstructor\n\tvar speciesConstructor = function (O, defaultConstructor) {\n\t  var C = anObject(O).constructor;\n\t  var S;\n\t  return C === undefined || (S = anObject(C)[SPECIES$2]) == undefined ? defaultConstructor : aConstructor(S);\n\t};\n\n\tvar UNSUPPORTED_Y = regexpStickyHelpers.UNSUPPORTED_Y;\n\tvar MAX_UINT32 = 0xFFFFFFFF;\n\tvar min$3 = Math.min;\n\tvar $push = [].push;\n\tvar exec = functionUncurryThis(/./.exec);\n\tvar push$3 = functionUncurryThis($push);\n\tvar stringSlice$2 = functionUncurryThis(''.slice);\n\n\t// Chrome 51 has a buggy \"split\" implementation when RegExp#exec !== nativeExec\n\t// Weex JS has frozen built-in prototypes, so use try / catch wrapper\n\tvar SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {\n\t  // eslint-disable-next-line regexp/no-empty-group -- required for testing\n\t  var re = /(?:)/;\n\t  var originalExec = re.exec;\n\t  re.exec = function () { return originalExec.apply(this, arguments); };\n\t  var result = 'ab'.split(re);\n\t  return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';\n\t});\n\n\t// @@split logic\n\tfixRegexpWellKnownSymbolLogic('split', function (SPLIT, nativeSplit, maybeCallNative) {\n\t  var internalSplit;\n\t  if (\n\t    'abbc'.split(/(b)*/)[1] == 'c' ||\n\t    // eslint-disable-next-line regexp/no-empty-group -- required for testing\n\t    'test'.split(/(?:)/, -1).length != 4 ||\n\t    'ab'.split(/(?:ab)*/).length != 2 ||\n\t    '.'.split(/(.?)(.?)/).length != 4 ||\n\t    // eslint-disable-next-line regexp/no-empty-capturing-group, regexp/no-empty-group -- required for testing\n\t    '.'.split(/()()/).length > 1 ||\n\t    ''.split(/.?/).length\n\t  ) {\n\t    // based on es5-shim implementation, need to rework it\n\t    internalSplit = function (separator, limit) {\n\t      var string = toString_1(requireObjectCoercible(this));\n\t      var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;\n\t      if (lim === 0) return [];\n\t      if (separator === undefined) return [string];\n\t      // If `separator` is not a regex, use native split\n\t      if (!isRegexp(separator)) {\n\t        return functionCall(nativeSplit, string, separator, lim);\n\t      }\n\t      var output = [];\n\t      var flags = (separator.ignoreCase ? 'i' : '') +\n\t                  (separator.multiline ? 'm' : '') +\n\t                  (separator.unicode ? 'u' : '') +\n\t                  (separator.sticky ? 'y' : '');\n\t      var lastLastIndex = 0;\n\t      // Make `global` and avoid `lastIndex` issues by working with a copy\n\t      var separatorCopy = new RegExp(separator.source, flags + 'g');\n\t      var match, lastIndex, lastLength;\n\t      while (match = functionCall(regexpExec, separatorCopy, string)) {\n\t        lastIndex = separatorCopy.lastIndex;\n\t        if (lastIndex > lastLastIndex) {\n\t          push$3(output, stringSlice$2(string, lastLastIndex, match.index));\n\t          if (match.length > 1 && match.index < string.length) functionApply($push, output, arraySliceSimple(match, 1));\n\t          lastLength = match[0].length;\n\t          lastLastIndex = lastIndex;\n\t          if (output.length >= lim) break;\n\t        }\n\t        if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop\n\t      }\n\t      if (lastLastIndex === string.length) {\n\t        if (lastLength || !exec(separatorCopy, '')) push$3(output, '');\n\t      } else push$3(output, stringSlice$2(string, lastLastIndex));\n\t      return output.length > lim ? arraySliceSimple(output, 0, lim) : output;\n\t    };\n\t  // Chakra, V8\n\t  } else if ('0'.split(undefined, 0).length) {\n\t    internalSplit = function (separator, limit) {\n\t      return separator === undefined && limit === 0 ? [] : functionCall(nativeSplit, this, separator, limit);\n\t    };\n\t  } else internalSplit = nativeSplit;\n\n\t  return [\n\t    // `String.prototype.split` method\n\t    // https://tc39.es/ecma262/#sec-string.prototype.split\n\t    function split(separator, limit) {\n\t      var O = requireObjectCoercible(this);\n\t      var splitter = separator == undefined ? undefined : getMethod(separator, SPLIT);\n\t      return splitter\n\t        ? functionCall(splitter, separator, O, limit)\n\t        : functionCall(internalSplit, toString_1(O), separator, limit);\n\t    },\n\t    // `RegExp.prototype[@@split]` method\n\t    // https://tc39.es/ecma262/#sec-regexp.prototype-@@split\n\t    //\n\t    // NOTE: This cannot be properly polyfilled in engines that don't support\n\t    // the 'y' flag.\n\t    function (string, limit) {\n\t      var rx = anObject(this);\n\t      var S = toString_1(string);\n\t      var res = maybeCallNative(internalSplit, rx, S, limit, internalSplit !== nativeSplit);\n\n\t      if (res.done) return res.value;\n\n\t      var C = speciesConstructor(rx, RegExp);\n\n\t      var unicodeMatching = rx.unicode;\n\t      var flags = (rx.ignoreCase ? 'i' : '') +\n\t                  (rx.multiline ? 'm' : '') +\n\t                  (rx.unicode ? 'u' : '') +\n\t                  (UNSUPPORTED_Y ? 'g' : 'y');\n\n\t      // ^(? + rx + ) is needed, in combination with some S slicing, to\n\t      // simulate the 'y' flag.\n\t      var splitter = new C(UNSUPPORTED_Y ? '^(?:' + rx.source + ')' : rx, flags);\n\t      var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;\n\t      if (lim === 0) return [];\n\t      if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];\n\t      var p = 0;\n\t      var q = 0;\n\t      var A = [];\n\t      while (q < S.length) {\n\t        splitter.lastIndex = UNSUPPORTED_Y ? 0 : q;\n\t        var z = regexpExecAbstract(splitter, UNSUPPORTED_Y ? stringSlice$2(S, q) : S);\n\t        var e;\n\t        if (\n\t          z === null ||\n\t          (e = min$3(toLength(splitter.lastIndex + (UNSUPPORTED_Y ? q : 0)), S.length)) === p\n\t        ) {\n\t          q = advanceStringIndex(S, q, unicodeMatching);\n\t        } else {\n\t          push$3(A, stringSlice$2(S, p, q));\n\t          if (A.length === lim) return A;\n\t          for (var i = 1; i <= z.length - 1; i++) {\n\t            push$3(A, z[i]);\n\t            if (A.length === lim) return A;\n\t          }\n\t          q = p = e;\n\t        }\n\t      }\n\t      push$3(A, stringSlice$2(S, p));\n\t      return A;\n\t    }\n\t  ];\n\t}, !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC, UNSUPPORTED_Y);\n\n\tvar UNSCOPABLES = wellKnownSymbol('unscopables');\n\tvar ArrayPrototype$1 = Array.prototype;\n\n\t// Array.prototype[@@unscopables]\n\t// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables\n\tif (ArrayPrototype$1[UNSCOPABLES] == undefined) {\n\t  objectDefineProperty.f(ArrayPrototype$1, UNSCOPABLES, {\n\t    configurable: true,\n\t    value: objectCreate(null)\n\t  });\n\t}\n\n\t// add a key to Array.prototype[@@unscopables]\n\tvar addToUnscopables = function (key) {\n\t  ArrayPrototype$1[UNSCOPABLES][key] = true;\n\t};\n\n\tvar iterators = {};\n\n\tvar ITERATOR$6 = wellKnownSymbol('iterator');\n\tvar BUGGY_SAFARI_ITERATORS$1 = false;\n\n\t// `%IteratorPrototype%` object\n\t// https://tc39.es/ecma262/#sec-%iteratorprototype%-object\n\tvar IteratorPrototype$2, PrototypeOfArrayIteratorPrototype, arrayIterator;\n\n\t/* eslint-disable es/no-array-prototype-keys -- safe */\n\tif ([].keys) {\n\t  arrayIterator = [].keys();\n\t  // Safari 8 has buggy iterators w/o `next`\n\t  if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;\n\t  else {\n\t    PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));\n\t    if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$2 = PrototypeOfArrayIteratorPrototype;\n\t  }\n\t}\n\n\tvar NEW_ITERATOR_PROTOTYPE = IteratorPrototype$2 == undefined || fails(function () {\n\t  var test = {};\n\t  // FF44- legacy iterators case\n\t  return IteratorPrototype$2[ITERATOR$6].call(test) !== test;\n\t});\n\n\tif (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$2 = {};\n\n\t// `%IteratorPrototype%[@@iterator]()` method\n\t// https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator\n\tif (!isCallable(IteratorPrototype$2[ITERATOR$6])) {\n\t  redefine(IteratorPrototype$2, ITERATOR$6, function () {\n\t    return this;\n\t  });\n\t}\n\n\tvar iteratorsCore = {\n\t  IteratorPrototype: IteratorPrototype$2,\n\t  BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1\n\t};\n\n\tvar defineProperty$7 = objectDefineProperty.f;\n\n\n\n\tvar TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');\n\n\tvar setToStringTag = function (target, TAG, STATIC) {\n\t  if (target && !STATIC) target = target.prototype;\n\t  if (target && !hasOwnProperty_1(target, TO_STRING_TAG$2)) {\n\t    defineProperty$7(target, TO_STRING_TAG$2, { configurable: true, value: TAG });\n\t  }\n\t};\n\n\tvar IteratorPrototype$1 = iteratorsCore.IteratorPrototype;\n\n\n\n\n\n\tvar returnThis$1 = function () { return this; };\n\n\tvar createIteratorConstructor = function (IteratorConstructor, NAME, next, ENUMERABLE_NEXT) {\n\t  var TO_STRING_TAG = NAME + ' Iterator';\n\t  IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(+!ENUMERABLE_NEXT, next) });\n\t  setToStringTag(IteratorConstructor, TO_STRING_TAG, false);\n\t  iterators[TO_STRING_TAG] = returnThis$1;\n\t  return IteratorConstructor;\n\t};\n\n\tvar PROPER_FUNCTION_NAME$2 = functionName.PROPER;\n\tvar CONFIGURABLE_FUNCTION_NAME$1 = functionName.CONFIGURABLE;\n\tvar IteratorPrototype = iteratorsCore.IteratorPrototype;\n\tvar BUGGY_SAFARI_ITERATORS = iteratorsCore.BUGGY_SAFARI_ITERATORS;\n\tvar ITERATOR$5 = wellKnownSymbol('iterator');\n\tvar KEYS = 'keys';\n\tvar VALUES = 'values';\n\tvar ENTRIES = 'entries';\n\n\tvar returnThis = function () { return this; };\n\n\tvar defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {\n\t  createIteratorConstructor(IteratorConstructor, NAME, next);\n\n\t  var getIterationMethod = function (KIND) {\n\t    if (KIND === DEFAULT && defaultIterator) return defaultIterator;\n\t    if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];\n\t    switch (KIND) {\n\t      case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };\n\t      case VALUES: return function values() { return new IteratorConstructor(this, KIND); };\n\t      case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };\n\t    } return function () { return new IteratorConstructor(this); };\n\t  };\n\n\t  var TO_STRING_TAG = NAME + ' Iterator';\n\t  var INCORRECT_VALUES_NAME = false;\n\t  var IterablePrototype = Iterable.prototype;\n\t  var nativeIterator = IterablePrototype[ITERATOR$5]\n\t    || IterablePrototype['@@iterator']\n\t    || DEFAULT && IterablePrototype[DEFAULT];\n\t  var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);\n\t  var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;\n\t  var CurrentIteratorPrototype, methods, KEY;\n\n\t  // fix native\n\t  if (anyNativeIterator) {\n\t    CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));\n\t    if (CurrentIteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {\n\t      if (objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype) {\n\t        if (objectSetPrototypeOf) {\n\t          objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype);\n\t        } else if (!isCallable(CurrentIteratorPrototype[ITERATOR$5])) {\n\t          redefine(CurrentIteratorPrototype, ITERATOR$5, returnThis);\n\t        }\n\t      }\n\t      // Set @@toStringTag to native iterators\n\t      setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);\n\t    }\n\t  }\n\n\t  // fix Array.prototype.{ values, @@iterator }.name in V8 / FF\n\t  if (PROPER_FUNCTION_NAME$2 && DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {\n\t    if (CONFIGURABLE_FUNCTION_NAME$1) {\n\t      createNonEnumerableProperty(IterablePrototype, 'name', VALUES);\n\t    } else {\n\t      INCORRECT_VALUES_NAME = true;\n\t      defaultIterator = function values() { return functionCall(nativeIterator, this); };\n\t    }\n\t  }\n\n\t  // export additional methods\n\t  if (DEFAULT) {\n\t    methods = {\n\t      values: getIterationMethod(VALUES),\n\t      keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),\n\t      entries: getIterationMethod(ENTRIES)\n\t    };\n\t    if (FORCED) for (KEY in methods) {\n\t      if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {\n\t        redefine(IterablePrototype, KEY, methods[KEY]);\n\t      }\n\t    } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);\n\t  }\n\n\t  // define iterator\n\t  if (IterablePrototype[ITERATOR$5] !== defaultIterator) {\n\t    redefine(IterablePrototype, ITERATOR$5, defaultIterator, { name: DEFAULT });\n\t  }\n\t  iterators[NAME] = defaultIterator;\n\n\t  return methods;\n\t};\n\n\tvar defineProperty$6 = objectDefineProperty.f;\n\n\n\n\n\tvar ARRAY_ITERATOR = 'Array Iterator';\n\tvar setInternalState$5 = internalState.set;\n\tvar getInternalState$4 = internalState.getterFor(ARRAY_ITERATOR);\n\n\t// `Array.prototype.entries` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.entries\n\t// `Array.prototype.keys` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.keys\n\t// `Array.prototype.values` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.values\n\t// `Array.prototype[@@iterator]` method\n\t// https://tc39.es/ecma262/#sec-array.prototype-@@iterator\n\t// `CreateArrayIterator` internal method\n\t// https://tc39.es/ecma262/#sec-createarrayiterator\n\tvar es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {\n\t  setInternalState$5(this, {\n\t    type: ARRAY_ITERATOR,\n\t    target: toIndexedObject(iterated), // target\n\t    index: 0,                          // next index\n\t    kind: kind                         // kind\n\t  });\n\t// `%ArrayIteratorPrototype%.next` method\n\t// https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next\n\t}, function () {\n\t  var state = getInternalState$4(this);\n\t  var target = state.target;\n\t  var kind = state.kind;\n\t  var index = state.index++;\n\t  if (!target || index >= target.length) {\n\t    state.target = undefined;\n\t    return { value: undefined, done: true };\n\t  }\n\t  if (kind == 'keys') return { value: index, done: false };\n\t  if (kind == 'values') return { value: target[index], done: false };\n\t  return { value: [index, target[index]], done: false };\n\t}, 'values');\n\n\t// argumentsList[@@iterator] is %ArrayProto_values%\n\t// https://tc39.es/ecma262/#sec-createunmappedargumentsobject\n\t// https://tc39.es/ecma262/#sec-createmappedargumentsobject\n\tvar values = iterators.Arguments = iterators.Array;\n\n\t// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables\n\taddToUnscopables('keys');\n\taddToUnscopables('values');\n\taddToUnscopables('entries');\n\n\t// V8 ~ Chrome 45- bug\n\tif (descriptors && values.name !== 'values') try {\n\t  defineProperty$6(values, 'name', { value: 'values' });\n\t} catch (error) { /* empty */ }\n\n\tvar ITERATOR$4 = wellKnownSymbol('iterator');\n\tvar SAFE_CLOSING = false;\n\n\ttry {\n\t  var called = 0;\n\t  var iteratorWithReturn = {\n\t    next: function () {\n\t      return { done: !!called++ };\n\t    },\n\t    'return': function () {\n\t      SAFE_CLOSING = true;\n\t    }\n\t  };\n\t  iteratorWithReturn[ITERATOR$4] = function () {\n\t    return this;\n\t  };\n\t  // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing\n\t  Array.from(iteratorWithReturn, function () { throw 2; });\n\t} catch (error) { /* empty */ }\n\n\tvar checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {\n\t  if (!SKIP_CLOSING && !SAFE_CLOSING) return false;\n\t  var ITERATION_SUPPORT = false;\n\t  try {\n\t    var object = {};\n\t    object[ITERATOR$4] = function () {\n\t      return {\n\t        next: function () {\n\t          return { done: ITERATION_SUPPORT = true };\n\t        }\n\t      };\n\t    };\n\t    exec(object);\n\t  } catch (error) { /* empty */ }\n\t  return ITERATION_SUPPORT;\n\t};\n\n\t// eslint-disable-next-line es/no-typed-arrays -- safe\n\tvar arrayBufferNative = typeof ArrayBuffer != 'undefined' && typeof DataView != 'undefined';\n\n\tvar defineProperty$5 = objectDefineProperty.f;\n\n\n\n\n\n\n\tvar Int8Array$4 = global_1.Int8Array;\n\tvar Int8ArrayPrototype$1 = Int8Array$4 && Int8Array$4.prototype;\n\tvar Uint8ClampedArray$1 = global_1.Uint8ClampedArray;\n\tvar Uint8ClampedArrayPrototype = Uint8ClampedArray$1 && Uint8ClampedArray$1.prototype;\n\tvar TypedArray = Int8Array$4 && objectGetPrototypeOf(Int8Array$4);\n\tvar TypedArrayPrototype$1 = Int8ArrayPrototype$1 && objectGetPrototypeOf(Int8ArrayPrototype$1);\n\tvar ObjectPrototype$2 = Object.prototype;\n\tvar TypeError$9 = global_1.TypeError;\n\n\tvar TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');\n\tvar TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');\n\tvar TYPED_ARRAY_CONSTRUCTOR$1 = uid('TYPED_ARRAY_CONSTRUCTOR');\n\t// Fixing native typed arrays in Opera Presto crashes the browser, see #595\n\tvar NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferNative && !!objectSetPrototypeOf && classof(global_1.opera) !== 'Opera';\n\tvar TYPED_ARRAY_TAG_REQUIRED = false;\n\tvar NAME, Constructor, Prototype;\n\n\tvar TypedArrayConstructorsList = {\n\t  Int8Array: 1,\n\t  Uint8Array: 1,\n\t  Uint8ClampedArray: 1,\n\t  Int16Array: 2,\n\t  Uint16Array: 2,\n\t  Int32Array: 4,\n\t  Uint32Array: 4,\n\t  Float32Array: 4,\n\t  Float64Array: 8\n\t};\n\n\tvar BigIntArrayConstructorsList = {\n\t  BigInt64Array: 8,\n\t  BigUint64Array: 8\n\t};\n\n\tvar isView = function isView(it) {\n\t  if (!isObject$1(it)) return false;\n\t  var klass = classof(it);\n\t  return klass === 'DataView'\n\t    || hasOwnProperty_1(TypedArrayConstructorsList, klass)\n\t    || hasOwnProperty_1(BigIntArrayConstructorsList, klass);\n\t};\n\n\tvar isTypedArray = function (it) {\n\t  if (!isObject$1(it)) return false;\n\t  var klass = classof(it);\n\t  return hasOwnProperty_1(TypedArrayConstructorsList, klass)\n\t    || hasOwnProperty_1(BigIntArrayConstructorsList, klass);\n\t};\n\n\tvar aTypedArray$m = function (it) {\n\t  if (isTypedArray(it)) return it;\n\t  throw TypeError$9('Target is not a typed array');\n\t};\n\n\tvar aTypedArrayConstructor$2 = function (C) {\n\t  if (isCallable(C) && (!objectSetPrototypeOf || objectIsPrototypeOf(TypedArray, C))) return C;\n\t  throw TypeError$9(tryToString(C) + ' is not a typed array constructor');\n\t};\n\n\tvar exportTypedArrayMethod$n = function (KEY, property, forced, options) {\n\t  if (!descriptors) return;\n\t  if (forced) for (var ARRAY in TypedArrayConstructorsList) {\n\t    var TypedArrayConstructor = global_1[ARRAY];\n\t    if (TypedArrayConstructor && hasOwnProperty_1(TypedArrayConstructor.prototype, KEY)) try {\n\t      delete TypedArrayConstructor.prototype[KEY];\n\t    } catch (error) {\n\t      // old WebKit bug - some methods are non-configurable\n\t      try {\n\t        TypedArrayConstructor.prototype[KEY] = property;\n\t      } catch (error2) { /* empty */ }\n\t    }\n\t  }\n\t  if (!TypedArrayPrototype$1[KEY] || forced) {\n\t    redefine(TypedArrayPrototype$1, KEY, forced ? property\n\t      : NATIVE_ARRAY_BUFFER_VIEWS$1 && Int8ArrayPrototype$1[KEY] || property, options);\n\t  }\n\t};\n\n\tvar exportTypedArrayStaticMethod = function (KEY, property, forced) {\n\t  var ARRAY, TypedArrayConstructor;\n\t  if (!descriptors) return;\n\t  if (objectSetPrototypeOf) {\n\t    if (forced) for (ARRAY in TypedArrayConstructorsList) {\n\t      TypedArrayConstructor = global_1[ARRAY];\n\t      if (TypedArrayConstructor && hasOwnProperty_1(TypedArrayConstructor, KEY)) try {\n\t        delete TypedArrayConstructor[KEY];\n\t      } catch (error) { /* empty */ }\n\t    }\n\t    if (!TypedArray[KEY] || forced) {\n\t      // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable\n\t      try {\n\t        return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS$1 && TypedArray[KEY] || property);\n\t      } catch (error) { /* empty */ }\n\t    } else return;\n\t  }\n\t  for (ARRAY in TypedArrayConstructorsList) {\n\t    TypedArrayConstructor = global_1[ARRAY];\n\t    if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {\n\t      redefine(TypedArrayConstructor, KEY, property);\n\t    }\n\t  }\n\t};\n\n\tfor (NAME in TypedArrayConstructorsList) {\n\t  Constructor = global_1[NAME];\n\t  Prototype = Constructor && Constructor.prototype;\n\t  if (Prototype) createNonEnumerableProperty(Prototype, TYPED_ARRAY_CONSTRUCTOR$1, Constructor);\n\t  else NATIVE_ARRAY_BUFFER_VIEWS$1 = false;\n\t}\n\n\tfor (NAME in BigIntArrayConstructorsList) {\n\t  Constructor = global_1[NAME];\n\t  Prototype = Constructor && Constructor.prototype;\n\t  if (Prototype) createNonEnumerableProperty(Prototype, TYPED_ARRAY_CONSTRUCTOR$1, Constructor);\n\t}\n\n\t// WebKit bug - typed arrays constructors prototype is Object.prototype\n\tif (!NATIVE_ARRAY_BUFFER_VIEWS$1 || !isCallable(TypedArray) || TypedArray === Function.prototype) {\n\t  // eslint-disable-next-line no-shadow -- safe\n\t  TypedArray = function TypedArray() {\n\t    throw TypeError$9('Incorrect invocation');\n\t  };\n\t  if (NATIVE_ARRAY_BUFFER_VIEWS$1) for (NAME in TypedArrayConstructorsList) {\n\t    if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME], TypedArray);\n\t  }\n\t}\n\n\tif (!NATIVE_ARRAY_BUFFER_VIEWS$1 || !TypedArrayPrototype$1 || TypedArrayPrototype$1 === ObjectPrototype$2) {\n\t  TypedArrayPrototype$1 = TypedArray.prototype;\n\t  if (NATIVE_ARRAY_BUFFER_VIEWS$1) for (NAME in TypedArrayConstructorsList) {\n\t    if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME].prototype, TypedArrayPrototype$1);\n\t  }\n\t}\n\n\t// WebKit bug - one more object in Uint8ClampedArray prototype chain\n\tif (NATIVE_ARRAY_BUFFER_VIEWS$1 && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype$1) {\n\t  objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype$1);\n\t}\n\n\tif (descriptors && !hasOwnProperty_1(TypedArrayPrototype$1, TO_STRING_TAG$1)) {\n\t  TYPED_ARRAY_TAG_REQUIRED = true;\n\t  defineProperty$5(TypedArrayPrototype$1, TO_STRING_TAG$1, { get: function () {\n\t    return isObject$1(this) ? this[TYPED_ARRAY_TAG] : undefined;\n\t  } });\n\t  for (NAME in TypedArrayConstructorsList) if (global_1[NAME]) {\n\t    createNonEnumerableProperty(global_1[NAME], TYPED_ARRAY_TAG, NAME);\n\t  }\n\t}\n\n\tvar arrayBufferViewCore = {\n\t  NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS$1,\n\t  TYPED_ARRAY_CONSTRUCTOR: TYPED_ARRAY_CONSTRUCTOR$1,\n\t  TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQUIRED && TYPED_ARRAY_TAG,\n\t  aTypedArray: aTypedArray$m,\n\t  aTypedArrayConstructor: aTypedArrayConstructor$2,\n\t  exportTypedArrayMethod: exportTypedArrayMethod$n,\n\t  exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,\n\t  isView: isView,\n\t  isTypedArray: isTypedArray,\n\t  TypedArray: TypedArray,\n\t  TypedArrayPrototype: TypedArrayPrototype$1\n\t};\n\n\t/* eslint-disable no-new -- required for testing */\n\n\n\n\tvar NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;\n\n\tvar ArrayBuffer$2 = global_1.ArrayBuffer;\n\tvar Int8Array$3 = global_1.Int8Array;\n\n\tvar typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS || !fails(function () {\n\t  Int8Array$3(1);\n\t}) || !fails(function () {\n\t  new Int8Array$3(-1);\n\t}) || !checkCorrectnessOfIteration(function (iterable) {\n\t  new Int8Array$3();\n\t  new Int8Array$3(null);\n\t  new Int8Array$3(1.5);\n\t  new Int8Array$3(iterable);\n\t}, true) || fails(function () {\n\t  // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill\n\t  return new Int8Array$3(new ArrayBuffer$2(2), 1, undefined).length !== 1;\n\t});\n\n\tvar redefineAll = function (target, src, options) {\n\t  for (var key in src) redefine(target, key, src[key], options);\n\t  return target;\n\t};\n\n\tvar TypeError$8 = global_1.TypeError;\n\n\tvar anInstance = function (it, Prototype) {\n\t  if (objectIsPrototypeOf(Prototype, it)) return it;\n\t  throw TypeError$8('Incorrect invocation');\n\t};\n\n\tvar RangeError$7 = global_1.RangeError;\n\n\t// `ToIndex` abstract operation\n\t// https://tc39.es/ecma262/#sec-toindex\n\tvar toIndex = function (it) {\n\t  if (it === undefined) return 0;\n\t  var number = toIntegerOrInfinity(it);\n\t  var length = toLength(number);\n\t  if (number !== length) throw RangeError$7('Wrong length or index');\n\t  return length;\n\t};\n\n\t// IEEE754 conversions based on https://github.com/feross/ieee754\n\n\n\tvar Array$5 = global_1.Array;\n\tvar abs = Math.abs;\n\tvar pow$1 = Math.pow;\n\tvar floor$4 = Math.floor;\n\tvar log$2 = Math.log;\n\tvar LN2 = Math.LN2;\n\n\tvar pack = function (number, mantissaLength, bytes) {\n\t  var buffer = Array$5(bytes);\n\t  var exponentLength = bytes * 8 - mantissaLength - 1;\n\t  var eMax = (1 << exponentLength) - 1;\n\t  var eBias = eMax >> 1;\n\t  var rt = mantissaLength === 23 ? pow$1(2, -24) - pow$1(2, -77) : 0;\n\t  var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;\n\t  var index = 0;\n\t  var exponent, mantissa, c;\n\t  number = abs(number);\n\t  // eslint-disable-next-line no-self-compare -- NaN check\n\t  if (number != number || number === Infinity) {\n\t    // eslint-disable-next-line no-self-compare -- NaN check\n\t    mantissa = number != number ? 1 : 0;\n\t    exponent = eMax;\n\t  } else {\n\t    exponent = floor$4(log$2(number) / LN2);\n\t    c = pow$1(2, -exponent);\n\t    if (number * c < 1) {\n\t      exponent--;\n\t      c *= 2;\n\t    }\n\t    if (exponent + eBias >= 1) {\n\t      number += rt / c;\n\t    } else {\n\t      number += rt * pow$1(2, 1 - eBias);\n\t    }\n\t    if (number * c >= 2) {\n\t      exponent++;\n\t      c /= 2;\n\t    }\n\t    if (exponent + eBias >= eMax) {\n\t      mantissa = 0;\n\t      exponent = eMax;\n\t    } else if (exponent + eBias >= 1) {\n\t      mantissa = (number * c - 1) * pow$1(2, mantissaLength);\n\t      exponent = exponent + eBias;\n\t    } else {\n\t      mantissa = number * pow$1(2, eBias - 1) * pow$1(2, mantissaLength);\n\t      exponent = 0;\n\t    }\n\t  }\n\t  while (mantissaLength >= 8) {\n\t    buffer[index++] = mantissa & 255;\n\t    mantissa /= 256;\n\t    mantissaLength -= 8;\n\t  }\n\t  exponent = exponent << mantissaLength | mantissa;\n\t  exponentLength += mantissaLength;\n\t  while (exponentLength > 0) {\n\t    buffer[index++] = exponent & 255;\n\t    exponent /= 256;\n\t    exponentLength -= 8;\n\t  }\n\t  buffer[--index] |= sign * 128;\n\t  return buffer;\n\t};\n\n\tvar unpack = function (buffer, mantissaLength) {\n\t  var bytes = buffer.length;\n\t  var exponentLength = bytes * 8 - mantissaLength - 1;\n\t  var eMax = (1 << exponentLength) - 1;\n\t  var eBias = eMax >> 1;\n\t  var nBits = exponentLength - 7;\n\t  var index = bytes - 1;\n\t  var sign = buffer[index--];\n\t  var exponent = sign & 127;\n\t  var mantissa;\n\t  sign >>= 7;\n\t  while (nBits > 0) {\n\t    exponent = exponent * 256 + buffer[index--];\n\t    nBits -= 8;\n\t  }\n\t  mantissa = exponent & (1 << -nBits) - 1;\n\t  exponent >>= -nBits;\n\t  nBits += mantissaLength;\n\t  while (nBits > 0) {\n\t    mantissa = mantissa * 256 + buffer[index--];\n\t    nBits -= 8;\n\t  }\n\t  if (exponent === 0) {\n\t    exponent = 1 - eBias;\n\t  } else if (exponent === eMax) {\n\t    return mantissa ? NaN : sign ? -Infinity : Infinity;\n\t  } else {\n\t    mantissa = mantissa + pow$1(2, mantissaLength);\n\t    exponent = exponent - eBias;\n\t  } return (sign ? -1 : 1) * mantissa * pow$1(2, exponent - mantissaLength);\n\t};\n\n\tvar ieee754 = {\n\t  pack: pack,\n\t  unpack: unpack\n\t};\n\n\t// `Array.prototype.fill` method implementation\n\t// https://tc39.es/ecma262/#sec-array.prototype.fill\n\tvar arrayFill = function fill(value /* , start = 0, end = @length */) {\n\t  var O = toObject(this);\n\t  var length = lengthOfArrayLike(O);\n\t  var argumentsLength = arguments.length;\n\t  var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);\n\t  var end = argumentsLength > 2 ? arguments[2] : undefined;\n\t  var endPos = end === undefined ? length : toAbsoluteIndex(end, length);\n\t  while (endPos > index) O[index++] = value;\n\t  return O;\n\t};\n\n\tvar getOwnPropertyNames = objectGetOwnPropertyNames.f;\n\tvar defineProperty$4 = objectDefineProperty.f;\n\n\n\n\n\n\tvar PROPER_FUNCTION_NAME$1 = functionName.PROPER;\n\tvar CONFIGURABLE_FUNCTION_NAME = functionName.CONFIGURABLE;\n\tvar getInternalState$3 = internalState.get;\n\tvar setInternalState$4 = internalState.set;\n\tvar ARRAY_BUFFER$1 = 'ArrayBuffer';\n\tvar DATA_VIEW = 'DataView';\n\tvar PROTOTYPE$1 = 'prototype';\n\tvar WRONG_LENGTH = 'Wrong length';\n\tvar WRONG_INDEX = 'Wrong index';\n\tvar NativeArrayBuffer$1 = global_1[ARRAY_BUFFER$1];\n\tvar $ArrayBuffer = NativeArrayBuffer$1;\n\tvar ArrayBufferPrototype = $ArrayBuffer && $ArrayBuffer[PROTOTYPE$1];\n\tvar $DataView = global_1[DATA_VIEW];\n\tvar DataViewPrototype = $DataView && $DataView[PROTOTYPE$1];\n\tvar ObjectPrototype$1 = Object.prototype;\n\tvar Array$4 = global_1.Array;\n\tvar RangeError$6 = global_1.RangeError;\n\tvar fill = functionUncurryThis(arrayFill);\n\tvar reverse = functionUncurryThis([].reverse);\n\n\tvar packIEEE754 = ieee754.pack;\n\tvar unpackIEEE754 = ieee754.unpack;\n\n\tvar packInt8 = function (number) {\n\t  return [number & 0xFF];\n\t};\n\n\tvar packInt16 = function (number) {\n\t  return [number & 0xFF, number >> 8 & 0xFF];\n\t};\n\n\tvar packInt32 = function (number) {\n\t  return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];\n\t};\n\n\tvar unpackInt32 = function (buffer) {\n\t  return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];\n\t};\n\n\tvar packFloat32 = function (number) {\n\t  return packIEEE754(number, 23, 4);\n\t};\n\n\tvar packFloat64 = function (number) {\n\t  return packIEEE754(number, 52, 8);\n\t};\n\n\tvar addGetter = function (Constructor, key) {\n\t  defineProperty$4(Constructor[PROTOTYPE$1], key, { get: function () { return getInternalState$3(this)[key]; } });\n\t};\n\n\tvar get = function (view, count, index, isLittleEndian) {\n\t  var intIndex = toIndex(index);\n\t  var store = getInternalState$3(view);\n\t  if (intIndex + count > store.byteLength) throw RangeError$6(WRONG_INDEX);\n\t  var bytes = getInternalState$3(store.buffer).bytes;\n\t  var start = intIndex + store.byteOffset;\n\t  var pack = arraySliceSimple(bytes, start, start + count);\n\t  return isLittleEndian ? pack : reverse(pack);\n\t};\n\n\tvar set$1 = function (view, count, index, conversion, value, isLittleEndian) {\n\t  var intIndex = toIndex(index);\n\t  var store = getInternalState$3(view);\n\t  if (intIndex + count > store.byteLength) throw RangeError$6(WRONG_INDEX);\n\t  var bytes = getInternalState$3(store.buffer).bytes;\n\t  var start = intIndex + store.byteOffset;\n\t  var pack = conversion(+value);\n\t  for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];\n\t};\n\n\tif (!arrayBufferNative) {\n\t  $ArrayBuffer = function ArrayBuffer(length) {\n\t    anInstance(this, ArrayBufferPrototype);\n\t    var byteLength = toIndex(length);\n\t    setInternalState$4(this, {\n\t      bytes: fill(Array$4(byteLength), 0),\n\t      byteLength: byteLength\n\t    });\n\t    if (!descriptors) this.byteLength = byteLength;\n\t  };\n\n\t  ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE$1];\n\n\t  $DataView = function DataView(buffer, byteOffset, byteLength) {\n\t    anInstance(this, DataViewPrototype);\n\t    anInstance(buffer, ArrayBufferPrototype);\n\t    var bufferLength = getInternalState$3(buffer).byteLength;\n\t    var offset = toIntegerOrInfinity(byteOffset);\n\t    if (offset < 0 || offset > bufferLength) throw RangeError$6('Wrong offset');\n\t    byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);\n\t    if (offset + byteLength > bufferLength) throw RangeError$6(WRONG_LENGTH);\n\t    setInternalState$4(this, {\n\t      buffer: buffer,\n\t      byteLength: byteLength,\n\t      byteOffset: offset\n\t    });\n\t    if (!descriptors) {\n\t      this.buffer = buffer;\n\t      this.byteLength = byteLength;\n\t      this.byteOffset = offset;\n\t    }\n\t  };\n\n\t  DataViewPrototype = $DataView[PROTOTYPE$1];\n\n\t  if (descriptors) {\n\t    addGetter($ArrayBuffer, 'byteLength');\n\t    addGetter($DataView, 'buffer');\n\t    addGetter($DataView, 'byteLength');\n\t    addGetter($DataView, 'byteOffset');\n\t  }\n\n\t  redefineAll(DataViewPrototype, {\n\t    getInt8: function getInt8(byteOffset) {\n\t      return get(this, 1, byteOffset)[0] << 24 >> 24;\n\t    },\n\t    getUint8: function getUint8(byteOffset) {\n\t      return get(this, 1, byteOffset)[0];\n\t    },\n\t    getInt16: function getInt16(byteOffset /* , littleEndian */) {\n\t      var bytes = get(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);\n\t      return (bytes[1] << 8 | bytes[0]) << 16 >> 16;\n\t    },\n\t    getUint16: function getUint16(byteOffset /* , littleEndian */) {\n\t      var bytes = get(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);\n\t      return bytes[1] << 8 | bytes[0];\n\t    },\n\t    getInt32: function getInt32(byteOffset /* , littleEndian */) {\n\t      return unpackInt32(get(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));\n\t    },\n\t    getUint32: function getUint32(byteOffset /* , littleEndian */) {\n\t      return unpackInt32(get(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;\n\t    },\n\t    getFloat32: function getFloat32(byteOffset /* , littleEndian */) {\n\t      return unpackIEEE754(get(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);\n\t    },\n\t    getFloat64: function getFloat64(byteOffset /* , littleEndian */) {\n\t      return unpackIEEE754(get(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);\n\t    },\n\t    setInt8: function setInt8(byteOffset, value) {\n\t      set$1(this, 1, byteOffset, packInt8, value);\n\t    },\n\t    setUint8: function setUint8(byteOffset, value) {\n\t      set$1(this, 1, byteOffset, packInt8, value);\n\t    },\n\t    setInt16: function setInt16(byteOffset, value /* , littleEndian */) {\n\t      set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);\n\t    },\n\t    setUint16: function setUint16(byteOffset, value /* , littleEndian */) {\n\t      set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);\n\t    },\n\t    setInt32: function setInt32(byteOffset, value /* , littleEndian */) {\n\t      set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);\n\t    },\n\t    setUint32: function setUint32(byteOffset, value /* , littleEndian */) {\n\t      set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);\n\t    },\n\t    setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {\n\t      set$1(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);\n\t    },\n\t    setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {\n\t      set$1(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);\n\t    }\n\t  });\n\t} else {\n\t  var INCORRECT_ARRAY_BUFFER_NAME = PROPER_FUNCTION_NAME$1 && NativeArrayBuffer$1.name !== ARRAY_BUFFER$1;\n\t  /* eslint-disable no-new -- required for testing */\n\t  if (!fails(function () {\n\t    NativeArrayBuffer$1(1);\n\t  }) || !fails(function () {\n\t    new NativeArrayBuffer$1(-1);\n\t  }) || fails(function () {\n\t    new NativeArrayBuffer$1();\n\t    new NativeArrayBuffer$1(1.5);\n\t    new NativeArrayBuffer$1(NaN);\n\t    return INCORRECT_ARRAY_BUFFER_NAME && !CONFIGURABLE_FUNCTION_NAME;\n\t  })) {\n\t  /* eslint-enable no-new -- required for testing */\n\t    $ArrayBuffer = function ArrayBuffer(length) {\n\t      anInstance(this, ArrayBufferPrototype);\n\t      return new NativeArrayBuffer$1(toIndex(length));\n\t    };\n\n\t    $ArrayBuffer[PROTOTYPE$1] = ArrayBufferPrototype;\n\n\t    for (var keys$1 = getOwnPropertyNames(NativeArrayBuffer$1), j = 0, key; keys$1.length > j;) {\n\t      if (!((key = keys$1[j++]) in $ArrayBuffer)) {\n\t        createNonEnumerableProperty($ArrayBuffer, key, NativeArrayBuffer$1[key]);\n\t      }\n\t    }\n\n\t    ArrayBufferPrototype.constructor = $ArrayBuffer;\n\t  } else if (INCORRECT_ARRAY_BUFFER_NAME && CONFIGURABLE_FUNCTION_NAME) {\n\t    createNonEnumerableProperty(NativeArrayBuffer$1, 'name', ARRAY_BUFFER$1);\n\t  }\n\n\t  // WebKit bug - the same parent prototype for typed arrays and data view\n\t  if (objectSetPrototypeOf && objectGetPrototypeOf(DataViewPrototype) !== ObjectPrototype$1) {\n\t    objectSetPrototypeOf(DataViewPrototype, ObjectPrototype$1);\n\t  }\n\n\t  // iOS Safari 7.x bug\n\t  var testView = new $DataView(new $ArrayBuffer(2));\n\t  var $setInt8 = functionUncurryThis(DataViewPrototype.setInt8);\n\t  testView.setInt8(0, 2147483648);\n\t  testView.setInt8(1, 2147483649);\n\t  if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll(DataViewPrototype, {\n\t    setInt8: function setInt8(byteOffset, value) {\n\t      $setInt8(this, byteOffset, value << 24 >> 24);\n\t    },\n\t    setUint8: function setUint8(byteOffset, value) {\n\t      $setInt8(this, byteOffset, value << 24 >> 24);\n\t    }\n\t  }, { unsafe: true });\n\t}\n\n\tsetToStringTag($ArrayBuffer, ARRAY_BUFFER$1);\n\tsetToStringTag($DataView, DATA_VIEW);\n\n\tvar arrayBuffer = {\n\t  ArrayBuffer: $ArrayBuffer,\n\t  DataView: $DataView\n\t};\n\n\tvar floor$3 = Math.floor;\n\n\t// `IsIntegralNumber` abstract operation\n\t// https://tc39.es/ecma262/#sec-isintegralnumber\n\t// eslint-disable-next-line es/no-number-isinteger -- safe\n\tvar isIntegralNumber = Number.isInteger || function isInteger(it) {\n\t  return !isObject$1(it) && isFinite(it) && floor$3(it) === it;\n\t};\n\n\tvar RangeError$5 = global_1.RangeError;\n\n\tvar toPositiveInteger = function (it) {\n\t  var result = toIntegerOrInfinity(it);\n\t  if (result < 0) throw RangeError$5(\"The argument can't be less than 0\");\n\t  return result;\n\t};\n\n\tvar RangeError$4 = global_1.RangeError;\n\n\tvar toOffset = function (it, BYTES) {\n\t  var offset = toPositiveInteger(it);\n\t  if (offset % BYTES) throw RangeError$4('Wrong offset');\n\t  return offset;\n\t};\n\n\tvar ITERATOR$3 = wellKnownSymbol('iterator');\n\n\tvar getIteratorMethod = function (it) {\n\t  if (it != undefined) return getMethod(it, ITERATOR$3)\n\t    || getMethod(it, '@@iterator')\n\t    || iterators[classof(it)];\n\t};\n\n\tvar TypeError$7 = global_1.TypeError;\n\n\tvar getIterator = function (argument, usingIterator) {\n\t  var iteratorMethod = arguments.length < 2 ? getIteratorMethod(argument) : usingIterator;\n\t  if (aCallable(iteratorMethod)) return anObject(functionCall(iteratorMethod, argument));\n\t  throw TypeError$7(tryToString(argument) + ' is not iterable');\n\t};\n\n\tvar ITERATOR$2 = wellKnownSymbol('iterator');\n\tvar ArrayPrototype = Array.prototype;\n\n\t// check on default Array iterator\n\tvar isArrayIteratorMethod = function (it) {\n\t  return it !== undefined && (iterators.Array === it || ArrayPrototype[ITERATOR$2] === it);\n\t};\n\n\tvar aTypedArrayConstructor$1 = arrayBufferViewCore.aTypedArrayConstructor;\n\n\tvar typedArrayFrom = function from(source /* , mapfn, thisArg */) {\n\t  var C = aConstructor(this);\n\t  var O = toObject(source);\n\t  var argumentsLength = arguments.length;\n\t  var mapfn = argumentsLength > 1 ? arguments[1] : undefined;\n\t  var mapping = mapfn !== undefined;\n\t  var iteratorMethod = getIteratorMethod(O);\n\t  var i, length, result, step, iterator, next;\n\t  if (iteratorMethod && !isArrayIteratorMethod(iteratorMethod)) {\n\t    iterator = getIterator(O, iteratorMethod);\n\t    next = iterator.next;\n\t    O = [];\n\t    while (!(step = functionCall(next, iterator)).done) {\n\t      O.push(step.value);\n\t    }\n\t  }\n\t  if (mapping && argumentsLength > 2) {\n\t    mapfn = functionBindContext(mapfn, arguments[2]);\n\t  }\n\t  length = lengthOfArrayLike(O);\n\t  result = new (aTypedArrayConstructor$1(C))(length);\n\t  for (i = 0; length > i; i++) {\n\t    result[i] = mapping ? mapfn(O[i], i) : O[i];\n\t  }\n\t  return result;\n\t};\n\n\tvar typedArrayConstructor = createCommonjsModule(function (module) {\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\tvar getOwnPropertyNames = objectGetOwnPropertyNames.f;\n\n\tvar forEach = arrayIteration.forEach;\n\n\n\n\n\n\n\tvar getInternalState = internalState.get;\n\tvar setInternalState = internalState.set;\n\tvar nativeDefineProperty = objectDefineProperty.f;\n\tvar nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;\n\tvar round = Math.round;\n\tvar RangeError = global_1.RangeError;\n\tvar ArrayBuffer = arrayBuffer.ArrayBuffer;\n\tvar ArrayBufferPrototype = ArrayBuffer.prototype;\n\tvar DataView = arrayBuffer.DataView;\n\tvar NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;\n\tvar TYPED_ARRAY_CONSTRUCTOR = arrayBufferViewCore.TYPED_ARRAY_CONSTRUCTOR;\n\tvar TYPED_ARRAY_TAG = arrayBufferViewCore.TYPED_ARRAY_TAG;\n\tvar TypedArray = arrayBufferViewCore.TypedArray;\n\tvar TypedArrayPrototype = arrayBufferViewCore.TypedArrayPrototype;\n\tvar aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;\n\tvar isTypedArray = arrayBufferViewCore.isTypedArray;\n\tvar BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';\n\tvar WRONG_LENGTH = 'Wrong length';\n\n\tvar fromList = function (C, list) {\n\t  aTypedArrayConstructor(C);\n\t  var index = 0;\n\t  var length = list.length;\n\t  var result = new C(length);\n\t  while (length > index) result[index] = list[index++];\n\t  return result;\n\t};\n\n\tvar addGetter = function (it, key) {\n\t  nativeDefineProperty(it, key, { get: function () {\n\t    return getInternalState(this)[key];\n\t  } });\n\t};\n\n\tvar isArrayBuffer = function (it) {\n\t  var klass;\n\t  return objectIsPrototypeOf(ArrayBufferPrototype, it) || (klass = classof(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';\n\t};\n\n\tvar isTypedArrayIndex = function (target, key) {\n\t  return isTypedArray(target)\n\t    && !isSymbol$1(key)\n\t    && key in target\n\t    && isIntegralNumber(+key)\n\t    && key >= 0;\n\t};\n\n\tvar wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {\n\t  key = toPropertyKey(key);\n\t  return isTypedArrayIndex(target, key)\n\t    ? createPropertyDescriptor(2, target[key])\n\t    : nativeGetOwnPropertyDescriptor(target, key);\n\t};\n\n\tvar wrappedDefineProperty = function defineProperty(target, key, descriptor) {\n\t  key = toPropertyKey(key);\n\t  if (isTypedArrayIndex(target, key)\n\t    && isObject$1(descriptor)\n\t    && hasOwnProperty_1(descriptor, 'value')\n\t    && !hasOwnProperty_1(descriptor, 'get')\n\t    && !hasOwnProperty_1(descriptor, 'set')\n\t    // TODO: add validation descriptor w/o calling accessors\n\t    && !descriptor.configurable\n\t    && (!hasOwnProperty_1(descriptor, 'writable') || descriptor.writable)\n\t    && (!hasOwnProperty_1(descriptor, 'enumerable') || descriptor.enumerable)\n\t  ) {\n\t    target[key] = descriptor.value;\n\t    return target;\n\t  } return nativeDefineProperty(target, key, descriptor);\n\t};\n\n\tif (descriptors) {\n\t  if (!NATIVE_ARRAY_BUFFER_VIEWS) {\n\t    objectGetOwnPropertyDescriptor.f = wrappedGetOwnPropertyDescriptor;\n\t    objectDefineProperty.f = wrappedDefineProperty;\n\t    addGetter(TypedArrayPrototype, 'buffer');\n\t    addGetter(TypedArrayPrototype, 'byteOffset');\n\t    addGetter(TypedArrayPrototype, 'byteLength');\n\t    addGetter(TypedArrayPrototype, 'length');\n\t  }\n\n\t  _export({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {\n\t    getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,\n\t    defineProperty: wrappedDefineProperty\n\t  });\n\n\t  module.exports = function (TYPE, wrapper, CLAMPED) {\n\t    var BYTES = TYPE.match(/\\d+$/)[0] / 8;\n\t    var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';\n\t    var GETTER = 'get' + TYPE;\n\t    var SETTER = 'set' + TYPE;\n\t    var NativeTypedArrayConstructor = global_1[CONSTRUCTOR_NAME];\n\t    var TypedArrayConstructor = NativeTypedArrayConstructor;\n\t    var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;\n\t    var exported = {};\n\n\t    var getter = function (that, index) {\n\t      var data = getInternalState(that);\n\t      return data.view[GETTER](index * BYTES + data.byteOffset, true);\n\t    };\n\n\t    var setter = function (that, index, value) {\n\t      var data = getInternalState(that);\n\t      if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;\n\t      data.view[SETTER](index * BYTES + data.byteOffset, value, true);\n\t    };\n\n\t    var addElement = function (that, index) {\n\t      nativeDefineProperty(that, index, {\n\t        get: function () {\n\t          return getter(this, index);\n\t        },\n\t        set: function (value) {\n\t          return setter(this, index, value);\n\t        },\n\t        enumerable: true\n\t      });\n\t    };\n\n\t    if (!NATIVE_ARRAY_BUFFER_VIEWS) {\n\t      TypedArrayConstructor = wrapper(function (that, data, offset, $length) {\n\t        anInstance(that, TypedArrayConstructorPrototype);\n\t        var index = 0;\n\t        var byteOffset = 0;\n\t        var buffer, byteLength, length;\n\t        if (!isObject$1(data)) {\n\t          length = toIndex(data);\n\t          byteLength = length * BYTES;\n\t          buffer = new ArrayBuffer(byteLength);\n\t        } else if (isArrayBuffer(data)) {\n\t          buffer = data;\n\t          byteOffset = toOffset(offset, BYTES);\n\t          var $len = data.byteLength;\n\t          if ($length === undefined) {\n\t            if ($len % BYTES) throw RangeError(WRONG_LENGTH);\n\t            byteLength = $len - byteOffset;\n\t            if (byteLength < 0) throw RangeError(WRONG_LENGTH);\n\t          } else {\n\t            byteLength = toLength($length) * BYTES;\n\t            if (byteLength + byteOffset > $len) throw RangeError(WRONG_LENGTH);\n\t          }\n\t          length = byteLength / BYTES;\n\t        } else if (isTypedArray(data)) {\n\t          return fromList(TypedArrayConstructor, data);\n\t        } else {\n\t          return functionCall(typedArrayFrom, TypedArrayConstructor, data);\n\t        }\n\t        setInternalState(that, {\n\t          buffer: buffer,\n\t          byteOffset: byteOffset,\n\t          byteLength: byteLength,\n\t          length: length,\n\t          view: new DataView(buffer)\n\t        });\n\t        while (index < length) addElement(that, index++);\n\t      });\n\n\t      if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);\n\t      TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = objectCreate(TypedArrayPrototype);\n\t    } else if (typedArrayConstructorsRequireWrappers) {\n\t      TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {\n\t        anInstance(dummy, TypedArrayConstructorPrototype);\n\t        return inheritIfRequired(function () {\n\t          if (!isObject$1(data)) return new NativeTypedArrayConstructor(toIndex(data));\n\t          if (isArrayBuffer(data)) return $length !== undefined\n\t            ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES), $length)\n\t            : typedArrayOffset !== undefined\n\t              ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES))\n\t              : new NativeTypedArrayConstructor(data);\n\t          if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);\n\t          return functionCall(typedArrayFrom, TypedArrayConstructor, data);\n\t        }(), dummy, TypedArrayConstructor);\n\t      });\n\n\t      if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);\n\t      forEach(getOwnPropertyNames(NativeTypedArrayConstructor), function (key) {\n\t        if (!(key in TypedArrayConstructor)) {\n\t          createNonEnumerableProperty(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);\n\t        }\n\t      });\n\t      TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;\n\t    }\n\n\t    if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {\n\t      createNonEnumerableProperty(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);\n\t    }\n\n\t    createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_CONSTRUCTOR, TypedArrayConstructor);\n\n\t    if (TYPED_ARRAY_TAG) {\n\t      createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);\n\t    }\n\n\t    exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;\n\n\t    _export({\n\t      global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS\n\t    }, exported);\n\n\t    if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {\n\t      createNonEnumerableProperty(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);\n\t    }\n\n\t    if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {\n\t      createNonEnumerableProperty(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);\n\t    }\n\n\t    setSpecies(CONSTRUCTOR_NAME);\n\t  };\n\t} else module.exports = function () { /* empty */ };\n\t});\n\n\t// `Uint8Array` constructor\n\t// https://tc39.es/ecma262/#sec-typedarray-objects\n\ttypedArrayConstructor('Uint8', function (init) {\n\t  return function Uint8Array(data, byteOffset, length) {\n\t    return init(this, data, byteOffset, length);\n\t  };\n\t});\n\n\tvar min$2 = Math.min;\n\n\t// `Array.prototype.copyWithin` method implementation\n\t// https://tc39.es/ecma262/#sec-array.prototype.copywithin\n\t// eslint-disable-next-line es/no-array-prototype-copywithin -- safe\n\tvar arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {\n\t  var O = toObject(this);\n\t  var len = lengthOfArrayLike(O);\n\t  var to = toAbsoluteIndex(target, len);\n\t  var from = toAbsoluteIndex(start, len);\n\t  var end = arguments.length > 2 ? arguments[2] : undefined;\n\t  var count = min$2((end === undefined ? len : toAbsoluteIndex(end, len)) - from, len - to);\n\t  var inc = 1;\n\t  if (from < to && to < from + count) {\n\t    inc = -1;\n\t    from += count - 1;\n\t    to += count - 1;\n\t  }\n\t  while (count-- > 0) {\n\t    if (from in O) O[to] = O[from];\n\t    else delete O[to];\n\t    to += inc;\n\t    from += inc;\n\t  } return O;\n\t};\n\n\tvar u$ArrayCopyWithin = functionUncurryThis(arrayCopyWithin);\n\tvar aTypedArray$l = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$m = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.copyWithin` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin\n\texportTypedArrayMethod$m('copyWithin', function copyWithin(target, start /* , end */) {\n\t  return u$ArrayCopyWithin(aTypedArray$l(this), target, start, arguments.length > 2 ? arguments[2] : undefined);\n\t});\n\n\tvar $every = arrayIteration.every;\n\n\tvar aTypedArray$k = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$l = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.every` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.every\n\texportTypedArrayMethod$l('every', function every(callbackfn /* , thisArg */) {\n\t  return $every(aTypedArray$k(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar aTypedArray$j = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$k = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.fill` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill\n\texportTypedArrayMethod$k('fill', function fill(value /* , start, end */) {\n\t  var length = arguments.length;\n\t  return functionCall(\n\t    arrayFill,\n\t    aTypedArray$j(this),\n\t    value,\n\t    length > 1 ? arguments[1] : undefined,\n\t    length > 2 ? arguments[2] : undefined\n\t  );\n\t});\n\n\tvar arrayFromConstructorAndList = function (Constructor, list) {\n\t  var index = 0;\n\t  var length = lengthOfArrayLike(list);\n\t  var result = new Constructor(length);\n\t  while (length > index) result[index] = list[index++];\n\t  return result;\n\t};\n\n\tvar TYPED_ARRAY_CONSTRUCTOR = arrayBufferViewCore.TYPED_ARRAY_CONSTRUCTOR;\n\tvar aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;\n\n\t// a part of `TypedArraySpeciesCreate` abstract operation\n\t// https://tc39.es/ecma262/#typedarray-species-create\n\tvar typedArraySpeciesConstructor = function (originalArray) {\n\t  return aTypedArrayConstructor(speciesConstructor(originalArray, originalArray[TYPED_ARRAY_CONSTRUCTOR]));\n\t};\n\n\tvar typedArrayFromSpeciesAndList = function (instance, list) {\n\t  return arrayFromConstructorAndList(typedArraySpeciesConstructor(instance), list);\n\t};\n\n\tvar $filter = arrayIteration.filter;\n\n\n\tvar aTypedArray$i = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$j = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.filter` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter\n\texportTypedArrayMethod$j('filter', function filter(callbackfn /* , thisArg */) {\n\t  var list = $filter(aTypedArray$i(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t  return typedArrayFromSpeciesAndList(this, list);\n\t});\n\n\tvar $find = arrayIteration.find;\n\n\tvar aTypedArray$h = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$i = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.find` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.find\n\texportTypedArrayMethod$i('find', function find(predicate /* , thisArg */) {\n\t  return $find(aTypedArray$h(this), predicate, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar $findIndex = arrayIteration.findIndex;\n\n\tvar aTypedArray$g = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$h = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.findIndex` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex\n\texportTypedArrayMethod$h('findIndex', function findIndex(predicate /* , thisArg */) {\n\t  return $findIndex(aTypedArray$g(this), predicate, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar $forEach$1 = arrayIteration.forEach;\n\n\tvar aTypedArray$f = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$g = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.forEach` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach\n\texportTypedArrayMethod$g('forEach', function forEach(callbackfn /* , thisArg */) {\n\t  $forEach$1(aTypedArray$f(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar $includes$1 = arrayIncludes.includes;\n\n\tvar aTypedArray$e = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$f = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.includes` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes\n\texportTypedArrayMethod$f('includes', function includes(searchElement /* , fromIndex */) {\n\t  return $includes$1(aTypedArray$e(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar $indexOf = arrayIncludes.indexOf;\n\n\tvar aTypedArray$d = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$e = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.indexOf` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof\n\texportTypedArrayMethod$e('indexOf', function indexOf(searchElement /* , fromIndex */) {\n\t  return $indexOf(aTypedArray$d(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar ITERATOR$1 = wellKnownSymbol('iterator');\n\tvar Uint8Array$2 = global_1.Uint8Array;\n\tvar arrayValues = functionUncurryThis(es_array_iterator.values);\n\tvar arrayKeys = functionUncurryThis(es_array_iterator.keys);\n\tvar arrayEntries = functionUncurryThis(es_array_iterator.entries);\n\tvar aTypedArray$c = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$d = arrayBufferViewCore.exportTypedArrayMethod;\n\tvar TypedArrayPrototype = Uint8Array$2 && Uint8Array$2.prototype;\n\n\tvar GENERIC = !fails(function () {\n\t  TypedArrayPrototype[ITERATOR$1].call([1]);\n\t});\n\n\tvar ITERATOR_IS_VALUES = !!TypedArrayPrototype\n\t  && TypedArrayPrototype.values\n\t  && TypedArrayPrototype[ITERATOR$1] === TypedArrayPrototype.values\n\t  && TypedArrayPrototype.values.name === 'values';\n\n\tvar typedArrayValues = function values() {\n\t  return arrayValues(aTypedArray$c(this));\n\t};\n\n\t// `%TypedArray%.prototype.entries` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries\n\texportTypedArrayMethod$d('entries', function entries() {\n\t  return arrayEntries(aTypedArray$c(this));\n\t}, GENERIC);\n\t// `%TypedArray%.prototype.keys` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys\n\texportTypedArrayMethod$d('keys', function keys() {\n\t  return arrayKeys(aTypedArray$c(this));\n\t}, GENERIC);\n\t// `%TypedArray%.prototype.values` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.values\n\texportTypedArrayMethod$d('values', typedArrayValues, GENERIC || !ITERATOR_IS_VALUES, { name: 'values' });\n\t// `%TypedArray%.prototype[@@iterator]` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype-@@iterator\n\texportTypedArrayMethod$d(ITERATOR$1, typedArrayValues, GENERIC || !ITERATOR_IS_VALUES, { name: 'values' });\n\n\tvar aTypedArray$b = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$c = arrayBufferViewCore.exportTypedArrayMethod;\n\tvar $join = functionUncurryThis([].join);\n\n\t// `%TypedArray%.prototype.join` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.join\n\texportTypedArrayMethod$c('join', function join(separator) {\n\t  return $join(aTypedArray$b(this), separator);\n\t});\n\n\t/* eslint-disable es/no-array-prototype-lastindexof -- safe */\n\n\n\n\n\n\n\tvar min$1 = Math.min;\n\tvar $lastIndexOf = [].lastIndexOf;\n\tvar NEGATIVE_ZERO = !!$lastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0;\n\tvar STRICT_METHOD$1 = arrayMethodIsStrict('lastIndexOf');\n\tvar FORCED$5 = NEGATIVE_ZERO || !STRICT_METHOD$1;\n\n\t// `Array.prototype.lastIndexOf` method implementation\n\t// https://tc39.es/ecma262/#sec-array.prototype.lastindexof\n\tvar arrayLastIndexOf = FORCED$5 ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {\n\t  // convert -0 to +0\n\t  if (NEGATIVE_ZERO) return functionApply($lastIndexOf, this, arguments) || 0;\n\t  var O = toIndexedObject(this);\n\t  var length = lengthOfArrayLike(O);\n\t  var index = length - 1;\n\t  if (arguments.length > 1) index = min$1(index, toIntegerOrInfinity(arguments[1]));\n\t  if (index < 0) index = length + index;\n\t  for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;\n\t  return -1;\n\t} : $lastIndexOf;\n\n\tvar aTypedArray$a = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$b = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.lastIndexOf` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof\n\texportTypedArrayMethod$b('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {\n\t  var length = arguments.length;\n\t  return functionApply(arrayLastIndexOf, aTypedArray$a(this), length > 1 ? [searchElement, arguments[1]] : [searchElement]);\n\t});\n\n\tvar $map = arrayIteration.map;\n\n\n\tvar aTypedArray$9 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$a = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.map` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.map\n\texportTypedArrayMethod$a('map', function map(mapfn /* , thisArg */) {\n\t  return $map(aTypedArray$9(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {\n\t    return new (typedArraySpeciesConstructor(O))(length);\n\t  });\n\t});\n\n\tvar TypeError$6 = global_1.TypeError;\n\n\t// `Array.prototype.{ reduce, reduceRight }` methods implementation\n\tvar createMethod$1 = function (IS_RIGHT) {\n\t  return function (that, callbackfn, argumentsLength, memo) {\n\t    aCallable(callbackfn);\n\t    var O = toObject(that);\n\t    var self = indexedObject(O);\n\t    var length = lengthOfArrayLike(O);\n\t    var index = IS_RIGHT ? length - 1 : 0;\n\t    var i = IS_RIGHT ? -1 : 1;\n\t    if (argumentsLength < 2) while (true) {\n\t      if (index in self) {\n\t        memo = self[index];\n\t        index += i;\n\t        break;\n\t      }\n\t      index += i;\n\t      if (IS_RIGHT ? index < 0 : length <= index) {\n\t        throw TypeError$6('Reduce of empty array with no initial value');\n\t      }\n\t    }\n\t    for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {\n\t      memo = callbackfn(memo, self[index], index, O);\n\t    }\n\t    return memo;\n\t  };\n\t};\n\n\tvar arrayReduce = {\n\t  // `Array.prototype.reduce` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.reduce\n\t  left: createMethod$1(false),\n\t  // `Array.prototype.reduceRight` method\n\t  // https://tc39.es/ecma262/#sec-array.prototype.reduceright\n\t  right: createMethod$1(true)\n\t};\n\n\tvar $reduce = arrayReduce.left;\n\n\tvar aTypedArray$8 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$9 = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.reduce` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce\n\texportTypedArrayMethod$9('reduce', function reduce(callbackfn /* , initialValue */) {\n\t  var length = arguments.length;\n\t  return $reduce(aTypedArray$8(this), callbackfn, length, length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar $reduceRight = arrayReduce.right;\n\n\tvar aTypedArray$7 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$8 = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.reduceRicht` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright\n\texportTypedArrayMethod$8('reduceRight', function reduceRight(callbackfn /* , initialValue */) {\n\t  var length = arguments.length;\n\t  return $reduceRight(aTypedArray$7(this), callbackfn, length, length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar aTypedArray$6 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$7 = arrayBufferViewCore.exportTypedArrayMethod;\n\tvar floor$2 = Math.floor;\n\n\t// `%TypedArray%.prototype.reverse` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse\n\texportTypedArrayMethod$7('reverse', function reverse() {\n\t  var that = this;\n\t  var length = aTypedArray$6(that).length;\n\t  var middle = floor$2(length / 2);\n\t  var index = 0;\n\t  var value;\n\t  while (index < middle) {\n\t    value = that[index];\n\t    that[index++] = that[--length];\n\t    that[length] = value;\n\t  } return that;\n\t});\n\n\tvar RangeError$3 = global_1.RangeError;\n\tvar Int8Array$2 = global_1.Int8Array;\n\tvar Int8ArrayPrototype = Int8Array$2 && Int8Array$2.prototype;\n\tvar $set = Int8ArrayPrototype && Int8ArrayPrototype.set;\n\tvar aTypedArray$5 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$6 = arrayBufferViewCore.exportTypedArrayMethod;\n\n\tvar WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS = !fails(function () {\n\t  // eslint-disable-next-line es/no-typed-arrays -- required for testing\n\t  var array = new Uint8ClampedArray(2);\n\t  functionCall($set, array, { length: 1, 0: 3 }, 1);\n\t  return array[1] !== 3;\n\t});\n\n\t// https://bugs.chromium.org/p/v8/issues/detail?id=11294 and other\n\tvar TO_OBJECT_BUG = WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS && arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS && fails(function () {\n\t  var array = new Int8Array$2(2);\n\t  array.set(1);\n\t  array.set('2', 1);\n\t  return array[0] !== 0 || array[1] !== 2;\n\t});\n\n\t// `%TypedArray%.prototype.set` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set\n\texportTypedArrayMethod$6('set', function set(arrayLike /* , offset */) {\n\t  aTypedArray$5(this);\n\t  var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);\n\t  var src = toObject(arrayLike);\n\t  if (WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS) return functionCall($set, this, src, offset);\n\t  var length = this.length;\n\t  var len = lengthOfArrayLike(src);\n\t  var index = 0;\n\t  if (len + offset > length) throw RangeError$3('Wrong length');\n\t  while (index < len) this[offset + index] = src[index++];\n\t}, !WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS || TO_OBJECT_BUG);\n\n\tvar arraySlice = functionUncurryThis([].slice);\n\n\tvar aTypedArray$4 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$5 = arrayBufferViewCore.exportTypedArrayMethod;\n\n\tvar FORCED$4 = fails(function () {\n\t  // eslint-disable-next-line es/no-typed-arrays -- required for testing\n\t  new Int8Array(1).slice();\n\t});\n\n\t// `%TypedArray%.prototype.slice` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice\n\texportTypedArrayMethod$5('slice', function slice(start, end) {\n\t  var list = arraySlice(aTypedArray$4(this), start, end);\n\t  var C = typedArraySpeciesConstructor(this);\n\t  var index = 0;\n\t  var length = list.length;\n\t  var result = new C(length);\n\t  while (length > index) result[index] = list[index++];\n\t  return result;\n\t}, FORCED$4);\n\n\tvar $some = arrayIteration.some;\n\n\tvar aTypedArray$3 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$4 = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.some` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.some\n\texportTypedArrayMethod$4('some', function some(callbackfn /* , thisArg */) {\n\t  return $some(aTypedArray$3(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t});\n\n\tvar floor$1 = Math.floor;\n\n\tvar mergeSort = function (array, comparefn) {\n\t  var length = array.length;\n\t  var middle = floor$1(length / 2);\n\t  return length < 8 ? insertionSort(array, comparefn) : merge(\n\t    array,\n\t    mergeSort(arraySliceSimple(array, 0, middle), comparefn),\n\t    mergeSort(arraySliceSimple(array, middle), comparefn),\n\t    comparefn\n\t  );\n\t};\n\n\tvar insertionSort = function (array, comparefn) {\n\t  var length = array.length;\n\t  var i = 1;\n\t  var element, j;\n\n\t  while (i < length) {\n\t    j = i;\n\t    element = array[i];\n\t    while (j && comparefn(array[j - 1], element) > 0) {\n\t      array[j] = array[--j];\n\t    }\n\t    if (j !== i++) array[j] = element;\n\t  } return array;\n\t};\n\n\tvar merge = function (array, left, right, comparefn) {\n\t  var llength = left.length;\n\t  var rlength = right.length;\n\t  var lindex = 0;\n\t  var rindex = 0;\n\n\t  while (lindex < llength || rindex < rlength) {\n\t    array[lindex + rindex] = (lindex < llength && rindex < rlength)\n\t      ? comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]\n\t      : lindex < llength ? left[lindex++] : right[rindex++];\n\t  } return array;\n\t};\n\n\tvar arraySort = mergeSort;\n\n\tvar firefox = engineUserAgent.match(/firefox\\/(\\d+)/i);\n\n\tvar engineFfVersion = !!firefox && +firefox[1];\n\n\tvar engineIsIeOrEdge = /MSIE|Trident/.test(engineUserAgent);\n\n\tvar webkit = engineUserAgent.match(/AppleWebKit\\/(\\d+)\\./);\n\n\tvar engineWebkitVersion = !!webkit && +webkit[1];\n\n\tvar Array$3 = global_1.Array;\n\tvar aTypedArray$2 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$3 = arrayBufferViewCore.exportTypedArrayMethod;\n\tvar Uint16Array = global_1.Uint16Array;\n\tvar un$Sort$1 = Uint16Array && functionUncurryThis(Uint16Array.prototype.sort);\n\n\t// WebKit\n\tvar ACCEPT_INCORRECT_ARGUMENTS = !!un$Sort$1 && !(fails(function () {\n\t  un$Sort$1(new Uint16Array(2), null);\n\t}) && fails(function () {\n\t  un$Sort$1(new Uint16Array(2), {});\n\t}));\n\n\tvar STABLE_SORT$1 = !!un$Sort$1 && !fails(function () {\n\t  // feature detection can be too slow, so check engines versions\n\t  if (engineV8Version) return engineV8Version < 74;\n\t  if (engineFfVersion) return engineFfVersion < 67;\n\t  if (engineIsIeOrEdge) return true;\n\t  if (engineWebkitVersion) return engineWebkitVersion < 602;\n\n\t  var array = new Uint16Array(516);\n\t  var expected = Array$3(516);\n\t  var index, mod;\n\n\t  for (index = 0; index < 516; index++) {\n\t    mod = index % 4;\n\t    array[index] = 515 - index;\n\t    expected[index] = index - 2 * mod + 3;\n\t  }\n\n\t  un$Sort$1(array, function (a, b) {\n\t    return (a / 4 | 0) - (b / 4 | 0);\n\t  });\n\n\t  for (index = 0; index < 516; index++) {\n\t    if (array[index] !== expected[index]) return true;\n\t  }\n\t});\n\n\tvar getSortCompare$1 = function (comparefn) {\n\t  return function (x, y) {\n\t    if (comparefn !== undefined) return +comparefn(x, y) || 0;\n\t    // eslint-disable-next-line no-self-compare -- NaN check\n\t    if (y !== y) return -1;\n\t    // eslint-disable-next-line no-self-compare -- NaN check\n\t    if (x !== x) return 1;\n\t    if (x === 0 && y === 0) return 1 / x > 0 && 1 / y < 0 ? 1 : -1;\n\t    return x > y;\n\t  };\n\t};\n\n\t// `%TypedArray%.prototype.sort` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort\n\texportTypedArrayMethod$3('sort', function sort(comparefn) {\n\t  if (comparefn !== undefined) aCallable(comparefn);\n\t  if (STABLE_SORT$1) return un$Sort$1(this, comparefn);\n\n\t  return arraySort(aTypedArray$2(this), getSortCompare$1(comparefn));\n\t}, !STABLE_SORT$1 || ACCEPT_INCORRECT_ARGUMENTS);\n\n\tvar aTypedArray$1 = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$2 = arrayBufferViewCore.exportTypedArrayMethod;\n\n\t// `%TypedArray%.prototype.subarray` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray\n\texportTypedArrayMethod$2('subarray', function subarray(begin, end) {\n\t  var O = aTypedArray$1(this);\n\t  var length = O.length;\n\t  var beginIndex = toAbsoluteIndex(begin, length);\n\t  var C = typedArraySpeciesConstructor(O);\n\t  return new C(\n\t    O.buffer,\n\t    O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,\n\t    toLength((end === undefined ? length : toAbsoluteIndex(end, length)) - beginIndex)\n\t  );\n\t});\n\n\tvar Int8Array$1 = global_1.Int8Array;\n\tvar aTypedArray = arrayBufferViewCore.aTypedArray;\n\tvar exportTypedArrayMethod$1 = arrayBufferViewCore.exportTypedArrayMethod;\n\tvar $toLocaleString = [].toLocaleString;\n\n\t// iOS Safari 6.x fails here\n\tvar TO_LOCALE_STRING_BUG = !!Int8Array$1 && fails(function () {\n\t  $toLocaleString.call(new Int8Array$1(1));\n\t});\n\n\tvar FORCED$3 = fails(function () {\n\t  return [1, 2].toLocaleString() != new Int8Array$1([1, 2]).toLocaleString();\n\t}) || !fails(function () {\n\t  Int8Array$1.prototype.toLocaleString.call([1, 2]);\n\t});\n\n\t// `%TypedArray%.prototype.toLocaleString` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring\n\texportTypedArrayMethod$1('toLocaleString', function toLocaleString() {\n\t  return functionApply(\n\t    $toLocaleString,\n\t    TO_LOCALE_STRING_BUG ? arraySlice(aTypedArray(this)) : aTypedArray(this),\n\t    arraySlice(arguments)\n\t  );\n\t}, FORCED$3);\n\n\tvar exportTypedArrayMethod = arrayBufferViewCore.exportTypedArrayMethod;\n\n\n\n\n\tvar Uint8Array$1 = global_1.Uint8Array;\n\tvar Uint8ArrayPrototype = Uint8Array$1 && Uint8Array$1.prototype || {};\n\tvar arrayToString = [].toString;\n\tvar join$1 = functionUncurryThis([].join);\n\n\tif (fails(function () { arrayToString.call({}); })) {\n\t  arrayToString = function toString() {\n\t    return join$1(this);\n\t  };\n\t}\n\n\tvar IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;\n\n\t// `%TypedArray%.prototype.toString` method\n\t// https://tc39.es/ecma262/#sec-%typedarray%.prototype.tostring\n\texportTypedArrayMethod('toString', arrayToString, IS_NOT_ARRAY_METHOD);\n\n\tvar ARRAY_BUFFER = 'ArrayBuffer';\n\tvar ArrayBuffer$1 = arrayBuffer[ARRAY_BUFFER];\n\tvar NativeArrayBuffer = global_1[ARRAY_BUFFER];\n\n\t// `ArrayBuffer` constructor\n\t// https://tc39.es/ecma262/#sec-arraybuffer-constructor\n\t_export({ global: true, forced: NativeArrayBuffer !== ArrayBuffer$1 }, {\n\t  ArrayBuffer: ArrayBuffer$1\n\t});\n\n\tsetSpecies(ARRAY_BUFFER);\n\n\tvar f$1 = wellKnownSymbol;\n\n\tvar wellKnownSymbolWrapped = {\n\t\tf: f$1\n\t};\n\n\tvar path$1 = global_1;\n\n\tvar defineProperty$3 = objectDefineProperty.f;\n\n\tvar defineWellKnownSymbol = function (NAME) {\n\t  var Symbol = path$1.Symbol || (path$1.Symbol = {});\n\t  if (!hasOwnProperty_1(Symbol, NAME)) defineProperty$3(Symbol, NAME, {\n\t    value: wellKnownSymbolWrapped.f(NAME)\n\t  });\n\t};\n\n\tvar $forEach = arrayIteration.forEach;\n\n\tvar HIDDEN = sharedKey('hidden');\n\tvar SYMBOL = 'Symbol';\n\tvar PROTOTYPE = 'prototype';\n\tvar TO_PRIMITIVE = wellKnownSymbol('toPrimitive');\n\n\tvar setInternalState$3 = internalState.set;\n\tvar getInternalState$2 = internalState.getterFor(SYMBOL);\n\n\tvar ObjectPrototype = Object[PROTOTYPE];\n\tvar $Symbol = global_1.Symbol;\n\tvar SymbolPrototype$1 = $Symbol && $Symbol[PROTOTYPE];\n\tvar TypeError$5 = global_1.TypeError;\n\tvar QObject = global_1.QObject;\n\tvar $stringify = getBuiltIn('JSON', 'stringify');\n\tvar nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;\n\tvar nativeDefineProperty = objectDefineProperty.f;\n\tvar nativeGetOwnPropertyNames = objectGetOwnPropertyNamesExternal.f;\n\tvar nativePropertyIsEnumerable = objectPropertyIsEnumerable.f;\n\tvar push$2 = functionUncurryThis([].push);\n\n\tvar AllSymbols = shared('symbols');\n\tvar ObjectPrototypeSymbols = shared('op-symbols');\n\tvar StringToSymbolRegistry = shared('string-to-symbol-registry');\n\tvar SymbolToStringRegistry = shared('symbol-to-string-registry');\n\tvar WellKnownSymbolsStore = shared('wks');\n\n\t// Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173\n\tvar USE_SETTER = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild;\n\n\t// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687\n\tvar setSymbolDescriptor = descriptors && fails(function () {\n\t  return objectCreate(nativeDefineProperty({}, 'a', {\n\t    get: function () { return nativeDefineProperty(this, 'a', { value: 7 }).a; }\n\t  })).a != 7;\n\t}) ? function (O, P, Attributes) {\n\t  var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor(ObjectPrototype, P);\n\t  if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];\n\t  nativeDefineProperty(O, P, Attributes);\n\t  if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {\n\t    nativeDefineProperty(ObjectPrototype, P, ObjectPrototypeDescriptor);\n\t  }\n\t} : nativeDefineProperty;\n\n\tvar wrap = function (tag, description) {\n\t  var symbol = AllSymbols[tag] = objectCreate(SymbolPrototype$1);\n\t  setInternalState$3(symbol, {\n\t    type: SYMBOL,\n\t    tag: tag,\n\t    description: description\n\t  });\n\t  if (!descriptors) symbol.description = description;\n\t  return symbol;\n\t};\n\n\tvar $defineProperty = function defineProperty(O, P, Attributes) {\n\t  if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);\n\t  anObject(O);\n\t  var key = toPropertyKey(P);\n\t  anObject(Attributes);\n\t  if (hasOwnProperty_1(AllSymbols, key)) {\n\t    if (!Attributes.enumerable) {\n\t      if (!hasOwnProperty_1(O, HIDDEN)) nativeDefineProperty(O, HIDDEN, createPropertyDescriptor(1, {}));\n\t      O[HIDDEN][key] = true;\n\t    } else {\n\t      if (hasOwnProperty_1(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;\n\t      Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) });\n\t    } return setSymbolDescriptor(O, key, Attributes);\n\t  } return nativeDefineProperty(O, key, Attributes);\n\t};\n\n\tvar $defineProperties = function defineProperties(O, Properties) {\n\t  anObject(O);\n\t  var properties = toIndexedObject(Properties);\n\t  var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));\n\t  $forEach(keys, function (key) {\n\t    if (!descriptors || functionCall($propertyIsEnumerable$1, properties, key)) $defineProperty(O, key, properties[key]);\n\t  });\n\t  return O;\n\t};\n\n\tvar $create = function create(O, Properties) {\n\t  return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);\n\t};\n\n\tvar $propertyIsEnumerable$1 = function propertyIsEnumerable(V) {\n\t  var P = toPropertyKey(V);\n\t  var enumerable = functionCall(nativePropertyIsEnumerable, this, P);\n\t  if (this === ObjectPrototype && hasOwnProperty_1(AllSymbols, P) && !hasOwnProperty_1(ObjectPrototypeSymbols, P)) return false;\n\t  return enumerable || !hasOwnProperty_1(this, P) || !hasOwnProperty_1(AllSymbols, P) || hasOwnProperty_1(this, HIDDEN) && this[HIDDEN][P]\n\t    ? enumerable : true;\n\t};\n\n\tvar $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {\n\t  var it = toIndexedObject(O);\n\t  var key = toPropertyKey(P);\n\t  if (it === ObjectPrototype && hasOwnProperty_1(AllSymbols, key) && !hasOwnProperty_1(ObjectPrototypeSymbols, key)) return;\n\t  var descriptor = nativeGetOwnPropertyDescriptor(it, key);\n\t  if (descriptor && hasOwnProperty_1(AllSymbols, key) && !(hasOwnProperty_1(it, HIDDEN) && it[HIDDEN][key])) {\n\t    descriptor.enumerable = true;\n\t  }\n\t  return descriptor;\n\t};\n\n\tvar $getOwnPropertyNames = function getOwnPropertyNames(O) {\n\t  var names = nativeGetOwnPropertyNames(toIndexedObject(O));\n\t  var result = [];\n\t  $forEach(names, function (key) {\n\t    if (!hasOwnProperty_1(AllSymbols, key) && !hasOwnProperty_1(hiddenKeys$1, key)) push$2(result, key);\n\t  });\n\t  return result;\n\t};\n\n\tvar $getOwnPropertySymbols = function getOwnPropertySymbols(O) {\n\t  var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;\n\t  var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));\n\t  var result = [];\n\t  $forEach(names, function (key) {\n\t    if (hasOwnProperty_1(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || hasOwnProperty_1(ObjectPrototype, key))) {\n\t      push$2(result, AllSymbols[key]);\n\t    }\n\t  });\n\t  return result;\n\t};\n\n\t// `Symbol` constructor\n\t// https://tc39.es/ecma262/#sec-symbol-constructor\n\tif (!nativeSymbol) {\n\t  $Symbol = function Symbol() {\n\t    if (objectIsPrototypeOf(SymbolPrototype$1, this)) throw TypeError$5('Symbol is not a constructor');\n\t    var description = !arguments.length || arguments[0] === undefined ? undefined : toString_1(arguments[0]);\n\t    var tag = uid(description);\n\t    var setter = function (value) {\n\t      if (this === ObjectPrototype) functionCall(setter, ObjectPrototypeSymbols, value);\n\t      if (hasOwnProperty_1(this, HIDDEN) && hasOwnProperty_1(this[HIDDEN], tag)) this[HIDDEN][tag] = false;\n\t      setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));\n\t    };\n\t    if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, { configurable: true, set: setter });\n\t    return wrap(tag, description);\n\t  };\n\n\t  SymbolPrototype$1 = $Symbol[PROTOTYPE];\n\n\t  redefine(SymbolPrototype$1, 'toString', function toString() {\n\t    return getInternalState$2(this).tag;\n\t  });\n\n\t  redefine($Symbol, 'withoutSetter', function (description) {\n\t    return wrap(uid(description), description);\n\t  });\n\n\t  objectPropertyIsEnumerable.f = $propertyIsEnumerable$1;\n\t  objectDefineProperty.f = $defineProperty;\n\t  objectDefineProperties.f = $defineProperties;\n\t  objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;\n\t  objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;\n\t  objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;\n\n\t  wellKnownSymbolWrapped.f = function (name) {\n\t    return wrap(wellKnownSymbol(name), name);\n\t  };\n\n\t  if (descriptors) {\n\t    // https://github.com/tc39/proposal-Symbol-description\n\t    nativeDefineProperty(SymbolPrototype$1, 'description', {\n\t      configurable: true,\n\t      get: function description() {\n\t        return getInternalState$2(this).description;\n\t      }\n\t    });\n\t    {\n\t      redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable$1, { unsafe: true });\n\t    }\n\t  }\n\t}\n\n\t_export({ global: true, wrap: true, forced: !nativeSymbol, sham: !nativeSymbol }, {\n\t  Symbol: $Symbol\n\t});\n\n\t$forEach(objectKeys(WellKnownSymbolsStore), function (name) {\n\t  defineWellKnownSymbol(name);\n\t});\n\n\t_export({ target: SYMBOL, stat: true, forced: !nativeSymbol }, {\n\t  // `Symbol.for` method\n\t  // https://tc39.es/ecma262/#sec-symbol.for\n\t  'for': function (key) {\n\t    var string = toString_1(key);\n\t    if (hasOwnProperty_1(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];\n\t    var symbol = $Symbol(string);\n\t    StringToSymbolRegistry[string] = symbol;\n\t    SymbolToStringRegistry[symbol] = string;\n\t    return symbol;\n\t  },\n\t  // `Symbol.keyFor` method\n\t  // https://tc39.es/ecma262/#sec-symbol.keyfor\n\t  keyFor: function keyFor(sym) {\n\t    if (!isSymbol$1(sym)) throw TypeError$5(sym + ' is not a symbol');\n\t    if (hasOwnProperty_1(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];\n\t  },\n\t  useSetter: function () { USE_SETTER = true; },\n\t  useSimple: function () { USE_SETTER = false; }\n\t});\n\n\t_export({ target: 'Object', stat: true, forced: !nativeSymbol, sham: !descriptors }, {\n\t  // `Object.create` method\n\t  // https://tc39.es/ecma262/#sec-object.create\n\t  create: $create,\n\t  // `Object.defineProperty` method\n\t  // https://tc39.es/ecma262/#sec-object.defineproperty\n\t  defineProperty: $defineProperty,\n\t  // `Object.defineProperties` method\n\t  // https://tc39.es/ecma262/#sec-object.defineproperties\n\t  defineProperties: $defineProperties,\n\t  // `Object.getOwnPropertyDescriptor` method\n\t  // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors\n\t  getOwnPropertyDescriptor: $getOwnPropertyDescriptor\n\t});\n\n\t_export({ target: 'Object', stat: true, forced: !nativeSymbol }, {\n\t  // `Object.getOwnPropertyNames` method\n\t  // https://tc39.es/ecma262/#sec-object.getownpropertynames\n\t  getOwnPropertyNames: $getOwnPropertyNames,\n\t  // `Object.getOwnPropertySymbols` method\n\t  // https://tc39.es/ecma262/#sec-object.getownpropertysymbols\n\t  getOwnPropertySymbols: $getOwnPropertySymbols\n\t});\n\n\t// Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives\n\t// https://bugs.chromium.org/p/v8/issues/detail?id=3443\n\t_export({ target: 'Object', stat: true, forced: fails(function () { objectGetOwnPropertySymbols.f(1); }) }, {\n\t  getOwnPropertySymbols: function getOwnPropertySymbols(it) {\n\t    return objectGetOwnPropertySymbols.f(toObject(it));\n\t  }\n\t});\n\n\t// `JSON.stringify` method behavior with symbols\n\t// https://tc39.es/ecma262/#sec-json.stringify\n\tif ($stringify) {\n\t  var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {\n\t    var symbol = $Symbol();\n\t    // MS Edge converts symbol values to JSON as {}\n\t    return $stringify([symbol]) != '[null]'\n\t      // WebKit converts symbol values to JSON as null\n\t      || $stringify({ a: symbol }) != '{}'\n\t      // V8 throws on boxed symbols\n\t      || $stringify(Object(symbol)) != '{}';\n\t  });\n\n\t  _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {\n\t    // eslint-disable-next-line no-unused-vars -- required for `.length`\n\t    stringify: function stringify(it, replacer, space) {\n\t      var args = arraySlice(arguments);\n\t      var $replacer = replacer;\n\t      if (!isObject$1(replacer) && it === undefined || isSymbol$1(it)) return; // IE8 returns string on undefined\n\t      if (!isArray$3(replacer)) replacer = function (key, value) {\n\t        if (isCallable($replacer)) value = functionCall($replacer, this, key, value);\n\t        if (!isSymbol$1(value)) return value;\n\t      };\n\t      args[1] = replacer;\n\t      return functionApply($stringify, null, args);\n\t    }\n\t  });\n\t}\n\n\t// `Symbol.prototype[@@toPrimitive]` method\n\t// https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive\n\tif (!SymbolPrototype$1[TO_PRIMITIVE]) {\n\t  var valueOf = SymbolPrototype$1.valueOf;\n\t  // eslint-disable-next-line no-unused-vars -- required for .length\n\t  redefine(SymbolPrototype$1, TO_PRIMITIVE, function (hint) {\n\t    // TODO: improve hint logic\n\t    return functionCall(valueOf, this);\n\t  });\n\t}\n\t// `Symbol.prototype[@@toStringTag]` property\n\t// https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag\n\tsetToStringTag($Symbol, SYMBOL);\n\n\thiddenKeys$1[HIDDEN] = true;\n\n\tvar defineProperty$2 = objectDefineProperty.f;\n\n\n\tvar NativeSymbol = global_1.Symbol;\n\tvar SymbolPrototype = NativeSymbol && NativeSymbol.prototype;\n\n\tif (descriptors && isCallable(NativeSymbol) && (!('description' in SymbolPrototype) ||\n\t  // Safari 12 bug\n\t  NativeSymbol().description !== undefined\n\t)) {\n\t  var EmptyStringDescriptionStore = {};\n\t  // wrap Symbol constructor for correct work with undefined description\n\t  var SymbolWrapper = function Symbol() {\n\t    var description = arguments.length < 1 || arguments[0] === undefined ? undefined : toString_1(arguments[0]);\n\t    var result = objectIsPrototypeOf(SymbolPrototype, this)\n\t      ? new NativeSymbol(description)\n\t      // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'\n\t      : description === undefined ? NativeSymbol() : NativeSymbol(description);\n\t    if (description === '') EmptyStringDescriptionStore[result] = true;\n\t    return result;\n\t  };\n\n\t  copyConstructorProperties(SymbolWrapper, NativeSymbol);\n\t  SymbolWrapper.prototype = SymbolPrototype;\n\t  SymbolPrototype.constructor = SymbolWrapper;\n\n\t  var NATIVE_SYMBOL = String(NativeSymbol('test')) == 'Symbol(test)';\n\t  var symbolToString = functionUncurryThis(SymbolPrototype.toString);\n\t  var symbolValueOf = functionUncurryThis(SymbolPrototype.valueOf);\n\t  var regexp = /^Symbol\\((.*)\\)[^)]+$/;\n\t  var replace = functionUncurryThis(''.replace);\n\t  var stringSlice$1 = functionUncurryThis(''.slice);\n\n\t  defineProperty$2(SymbolPrototype, 'description', {\n\t    configurable: true,\n\t    get: function description() {\n\t      var symbol = symbolValueOf(this);\n\t      var string = symbolToString(symbol);\n\t      if (hasOwnProperty_1(EmptyStringDescriptionStore, symbol)) return '';\n\t      var desc = NATIVE_SYMBOL ? stringSlice$1(string, 7, -1) : replace(string, regexp, '$1');\n\t      return desc === '' ? undefined : desc;\n\t    }\n\t  });\n\n\t  _export({ global: true, forced: true }, {\n\t    Symbol: SymbolWrapper\n\t  });\n\t}\n\n\t// `Symbol.species` well-known symbol\n\t// https://tc39.es/ecma262/#sec-symbol.species\n\tdefineWellKnownSymbol('species');\n\n\t// `Array[@@species]` getter\n\t// https://tc39.es/ecma262/#sec-get-array-@@species\n\tsetSpecies('Array');\n\n\t// `Array.prototype.fill` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.fill\n\t_export({ target: 'Array', proto: true }, {\n\t  fill: arrayFill\n\t});\n\n\t// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables\n\taddToUnscopables('fill');\n\n\tvar HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('slice');\n\n\tvar SPECIES$1 = wellKnownSymbol('species');\n\tvar Array$2 = global_1.Array;\n\tvar max = Math.max;\n\n\t// `Array.prototype.slice` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.slice\n\t// fallback for not array-like ES3 strings and DOM objects\n\t_export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT }, {\n\t  slice: function slice(start, end) {\n\t    var O = toIndexedObject(this);\n\t    var length = lengthOfArrayLike(O);\n\t    var k = toAbsoluteIndex(start, length);\n\t    var fin = toAbsoluteIndex(end === undefined ? length : end, length);\n\t    // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible\n\t    var Constructor, result, n;\n\t    if (isArray$3(O)) {\n\t      Constructor = O.constructor;\n\t      // cross-realm fallback\n\t      if (isConstructor(Constructor) && (Constructor === Array$2 || isArray$3(Constructor.prototype))) {\n\t        Constructor = undefined;\n\t      } else if (isObject$1(Constructor)) {\n\t        Constructor = Constructor[SPECIES$1];\n\t        if (Constructor === null) Constructor = undefined;\n\t      }\n\t      if (Constructor === Array$2 || Constructor === undefined) {\n\t        return arraySlice(O, k, fin);\n\t      }\n\t    }\n\t    result = new (Constructor === undefined ? Array$2 : Constructor)(max(fin - k, 0));\n\t    for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);\n\t    result.length = n;\n\t    return result;\n\t  }\n\t});\n\n\tvar $includes = arrayIncludes.includes;\n\n\n\t// `Array.prototype.includes` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.includes\n\t_export({ target: 'Array', proto: true }, {\n\t  includes: function includes(el /* , fromIndex = 0 */) {\n\t    return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);\n\t  }\n\t});\n\n\t// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables\n\taddToUnscopables('includes');\n\n\tvar TypeError$4 = global_1.TypeError;\n\n\tvar notARegexp = function (it) {\n\t  if (isRegexp(it)) {\n\t    throw TypeError$4(\"The method doesn't accept regular expressions\");\n\t  } return it;\n\t};\n\n\tvar MATCH = wellKnownSymbol('match');\n\n\tvar correctIsRegexpLogic = function (METHOD_NAME) {\n\t  var regexp = /./;\n\t  try {\n\t    '/./'[METHOD_NAME](regexp);\n\t  } catch (error1) {\n\t    try {\n\t      regexp[MATCH] = false;\n\t      return '/./'[METHOD_NAME](regexp);\n\t    } catch (error2) { /* empty */ }\n\t  } return false;\n\t};\n\n\tvar stringIndexOf = functionUncurryThis(''.indexOf);\n\n\t// `String.prototype.includes` method\n\t// https://tc39.es/ecma262/#sec-string.prototype.includes\n\t_export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {\n\t  includes: function includes(searchString /* , position = 0 */) {\n\t    return !!~stringIndexOf(\n\t      toString_1(requireObjectCoercible(this)),\n\t      toString_1(notARegexp(searchString)),\n\t      arguments.length > 1 ? arguments[1] : undefined\n\t    );\n\t  }\n\t});\n\n\t// `URL.prototype.toJSON` method\n\t// https://url.spec.whatwg.org/#dom-url-tojson\n\t_export({ target: 'URL', proto: true, enumerable: true }, {\n\t  toJSON: function toJSON() {\n\t    return functionCall(URL.prototype.toString, this);\n\t  }\n\t});\n\n\tvar PROPER_FUNCTION_NAME = functionName.PROPER;\n\n\n\n\tvar non = '\\u200B\\u0085\\u180E';\n\n\t// check that a method works with the correct list\n\t// of whitespaces and has a correct name\n\tvar stringTrimForced = function (METHOD_NAME) {\n\t  return fails(function () {\n\t    return !!whitespaces[METHOD_NAME]()\n\t      || non[METHOD_NAME]() !== non\n\t      || (PROPER_FUNCTION_NAME && whitespaces[METHOD_NAME].name !== METHOD_NAME);\n\t  });\n\t};\n\n\tvar $trim = stringTrim.trim;\n\n\n\t// `String.prototype.trim` method\n\t// https://tc39.es/ecma262/#sec-string.prototype.trim\n\t_export({ target: 'String', proto: true, forced: stringTrimForced('trim') }, {\n\t  trim: function trim() {\n\t    return $trim(this);\n\t  }\n\t});\n\n\tvar lookup$1 = [];\n\tvar revLookup$1 = [];\n\tvar Arr$1 = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;\n\tvar inited$1 = false;\n\n\tfunction init$1() {\n\t  inited$1 = true;\n\t  var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n\t  for (var i = 0, len = code.length; i < len; ++i) {\n\t    lookup$1[i] = code[i];\n\t    revLookup$1[code.charCodeAt(i)] = i;\n\t  }\n\n\t  revLookup$1['-'.charCodeAt(0)] = 62;\n\t  revLookup$1['_'.charCodeAt(0)] = 63;\n\t}\n\n\tfunction toByteArray$1(b64) {\n\t  if (!inited$1) {\n\t    init$1();\n\t  }\n\n\t  var i, j, l, tmp, placeHolders, arr;\n\t  var len = b64.length;\n\n\t  if (len % 4 > 0) {\n\t    throw new Error('Invalid string. Length must be a multiple of 4');\n\t  } // the number of equal signs (place holders)\n\t  // if there are two placeholders, than the two characters before it\n\t  // represent one byte\n\t  // if there is only one, then the three characters before it represent 2 bytes\n\t  // this is just a cheap hack to not do indexOf twice\n\n\n\t  placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0; // base64 is 4/3 + up to two characters of the original data\n\n\t  arr = new Arr$1(len * 3 / 4 - placeHolders); // if there are placeholders, only get up to the last complete 4 chars\n\n\t  l = placeHolders > 0 ? len - 4 : len;\n\t  var L = 0;\n\n\t  for (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t    tmp = revLookup$1[b64.charCodeAt(i)] << 18 | revLookup$1[b64.charCodeAt(i + 1)] << 12 | revLookup$1[b64.charCodeAt(i + 2)] << 6 | revLookup$1[b64.charCodeAt(i + 3)];\n\t    arr[L++] = tmp >> 16 & 0xFF;\n\t    arr[L++] = tmp >> 8 & 0xFF;\n\t    arr[L++] = tmp & 0xFF;\n\t  }\n\n\t  if (placeHolders === 2) {\n\t    tmp = revLookup$1[b64.charCodeAt(i)] << 2 | revLookup$1[b64.charCodeAt(i + 1)] >> 4;\n\t    arr[L++] = tmp & 0xFF;\n\t  } else if (placeHolders === 1) {\n\t    tmp = revLookup$1[b64.charCodeAt(i)] << 10 | revLookup$1[b64.charCodeAt(i + 1)] << 4 | revLookup$1[b64.charCodeAt(i + 2)] >> 2;\n\t    arr[L++] = tmp >> 8 & 0xFF;\n\t    arr[L++] = tmp & 0xFF;\n\t  }\n\n\t  return arr;\n\t}\n\n\tfunction tripletToBase64$1(num) {\n\t  return lookup$1[num >> 18 & 0x3F] + lookup$1[num >> 12 & 0x3F] + lookup$1[num >> 6 & 0x3F] + lookup$1[num & 0x3F];\n\t}\n\n\tfunction encodeChunk$1(uint8, start, end) {\n\t  var tmp;\n\t  var output = [];\n\n\t  for (var i = start; i < end; i += 3) {\n\t    tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + uint8[i + 2];\n\t    output.push(tripletToBase64$1(tmp));\n\t  }\n\n\t  return output.join('');\n\t}\n\n\tfunction fromByteArray$1(uint8) {\n\t  if (!inited$1) {\n\t    init$1();\n\t  }\n\n\t  var tmp;\n\t  var len = uint8.length;\n\t  var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n\n\t  var output = '';\n\t  var parts = [];\n\t  var maxChunkLength = 16383; // must be multiple of 3\n\t  // go through the array every three bytes, we'll deal with trailing stuff later\n\n\t  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n\t    parts.push(encodeChunk$1(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));\n\t  } // pad the end with zeros, but make sure to not forget the extra bytes\n\n\n\t  if (extraBytes === 1) {\n\t    tmp = uint8[len - 1];\n\t    output += lookup$1[tmp >> 2];\n\t    output += lookup$1[tmp << 4 & 0x3F];\n\t    output += '==';\n\t  } else if (extraBytes === 2) {\n\t    tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n\t    output += lookup$1[tmp >> 10];\n\t    output += lookup$1[tmp >> 4 & 0x3F];\n\t    output += lookup$1[tmp << 2 & 0x3F];\n\t    output += '=';\n\t  }\n\n\t  parts.push(output);\n\t  return parts.join('');\n\t}\n\n\tfunction read$1(buffer, offset, isLE, mLen, nBytes) {\n\t  var e, m;\n\t  var eLen = nBytes * 8 - mLen - 1;\n\t  var eMax = (1 << eLen) - 1;\n\t  var eBias = eMax >> 1;\n\t  var nBits = -7;\n\t  var i = isLE ? nBytes - 1 : 0;\n\t  var d = isLE ? -1 : 1;\n\t  var s = buffer[offset + i];\n\t  i += d;\n\t  e = s & (1 << -nBits) - 1;\n\t  s >>= -nBits;\n\t  nBits += eLen;\n\n\t  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n\t  m = e & (1 << -nBits) - 1;\n\t  e >>= -nBits;\n\t  nBits += mLen;\n\n\t  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n\t  if (e === 0) {\n\t    e = 1 - eBias;\n\t  } else if (e === eMax) {\n\t    return m ? NaN : (s ? -1 : 1) * Infinity;\n\t  } else {\n\t    m = m + Math.pow(2, mLen);\n\t    e = e - eBias;\n\t  }\n\n\t  return (s ? -1 : 1) * m * Math.pow(2, e - mLen);\n\t}\n\tfunction write$1(buffer, value, offset, isLE, mLen, nBytes) {\n\t  var e, m, c;\n\t  var eLen = nBytes * 8 - mLen - 1;\n\t  var eMax = (1 << eLen) - 1;\n\t  var eBias = eMax >> 1;\n\t  var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;\n\t  var i = isLE ? 0 : nBytes - 1;\n\t  var d = isLE ? 1 : -1;\n\t  var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;\n\t  value = Math.abs(value);\n\n\t  if (isNaN(value) || value === Infinity) {\n\t    m = isNaN(value) ? 1 : 0;\n\t    e = eMax;\n\t  } else {\n\t    e = Math.floor(Math.log(value) / Math.LN2);\n\n\t    if (value * (c = Math.pow(2, -e)) < 1) {\n\t      e--;\n\t      c *= 2;\n\t    }\n\n\t    if (e + eBias >= 1) {\n\t      value += rt / c;\n\t    } else {\n\t      value += rt * Math.pow(2, 1 - eBias);\n\t    }\n\n\t    if (value * c >= 2) {\n\t      e++;\n\t      c /= 2;\n\t    }\n\n\t    if (e + eBias >= eMax) {\n\t      m = 0;\n\t      e = eMax;\n\t    } else if (e + eBias >= 1) {\n\t      m = (value * c - 1) * Math.pow(2, mLen);\n\t      e = e + eBias;\n\t    } else {\n\t      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);\n\t      e = 0;\n\t    }\n\t  }\n\n\t  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n\t  e = e << mLen | m;\n\t  eLen += mLen;\n\n\t  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n\t  buffer[offset + i - d] |= s * 128;\n\t}\n\n\tvar toString$2 = {}.toString;\n\tvar isArray$2 = Array.isArray || function (arr) {\n\t  return toString$2.call(arr) == '[object Array]';\n\t};\n\n\tvar INSPECT_MAX_BYTES$1 = 50;\n\t/**\n\t * If `Buffer.TYPED_ARRAY_SUPPORT`:\n\t *   === true    Use Uint8Array implementation (fastest)\n\t *   === false   Use Object implementation (most compatible, even IE6)\n\t *\n\t * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n\t * Opera 11.6+, iOS 4.2+.\n\t *\n\t * Due to various browser bugs, sometimes the Object implementation will be used even\n\t * when the browser supports typed arrays.\n\t *\n\t * Note:\n\t *\n\t *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n\t *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n\t *\n\t *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n\t *\n\t *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n\t *     incorrect length in some situations.\n\n\t * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n\t * get the Object implementation, which is slower but behaves correctly.\n\t */\n\n\tBuffer$1.TYPED_ARRAY_SUPPORT = global$1.TYPED_ARRAY_SUPPORT !== undefined ? global$1.TYPED_ARRAY_SUPPORT : true;\n\n\tfunction kMaxLength$1() {\n\t  return Buffer$1.TYPED_ARRAY_SUPPORT ? 0x7fffffff : 0x3fffffff;\n\t}\n\n\tfunction createBuffer$1(that, length) {\n\t  if (kMaxLength$1() < length) {\n\t    throw new RangeError('Invalid typed array length');\n\t  }\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    // Return an augmented `Uint8Array` instance, for best performance\n\t    that = new Uint8Array(length);\n\t    that.__proto__ = Buffer$1.prototype;\n\t  } else {\n\t    // Fallback: Return an object instance of the Buffer class\n\t    if (that === null) {\n\t      that = new Buffer$1(length);\n\t    }\n\n\t    that.length = length;\n\t  }\n\n\t  return that;\n\t}\n\t/**\n\t * The Buffer constructor returns instances of `Uint8Array` that have their\n\t * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n\t * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n\t * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n\t * returns a single octet.\n\t *\n\t * The `Uint8Array` prototype remains unmodified.\n\t */\n\n\n\tfunction Buffer$1(arg, encodingOrOffset, length) {\n\t  if (!Buffer$1.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer$1)) {\n\t    return new Buffer$1(arg, encodingOrOffset, length);\n\t  } // Common case.\n\n\n\t  if (typeof arg === 'number') {\n\t    if (typeof encodingOrOffset === 'string') {\n\t      throw new Error('If encoding is specified then the first argument must be a string');\n\t    }\n\n\t    return allocUnsafe$1(this, arg);\n\t  }\n\n\t  return from$1(this, arg, encodingOrOffset, length);\n\t}\n\tBuffer$1.poolSize = 8192; // not used by this implementation\n\t// TODO: Legacy, not needed anymore. Remove in next major version.\n\n\tBuffer$1._augment = function (arr) {\n\t  arr.__proto__ = Buffer$1.prototype;\n\t  return arr;\n\t};\n\n\tfunction from$1(that, value, encodingOrOffset, length) {\n\t  if (typeof value === 'number') {\n\t    throw new TypeError('\"value\" argument must not be a number');\n\t  }\n\n\t  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n\t    return fromArrayBuffer$1(that, value, encodingOrOffset, length);\n\t  }\n\n\t  if (typeof value === 'string') {\n\t    return fromString$1(that, value, encodingOrOffset);\n\t  }\n\n\t  return fromObject$1(that, value);\n\t}\n\t/**\n\t * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n\t * if value is a number.\n\t * Buffer.from(str[, encoding])\n\t * Buffer.from(array)\n\t * Buffer.from(buffer)\n\t * Buffer.from(arrayBuffer[, byteOffset[, length]])\n\t **/\n\n\n\tBuffer$1.from = function (value, encodingOrOffset, length) {\n\t  return from$1(null, value, encodingOrOffset, length);\n\t};\n\n\tif (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t  Buffer$1.prototype.__proto__ = Uint8Array.prototype;\n\t  Buffer$1.__proto__ = Uint8Array;\n\t}\n\n\tfunction assertSize$1(size) {\n\t  if (typeof size !== 'number') {\n\t    throw new TypeError('\"size\" argument must be a number');\n\t  } else if (size < 0) {\n\t    throw new RangeError('\"size\" argument must not be negative');\n\t  }\n\t}\n\n\tfunction alloc$1(that, size, fill, encoding) {\n\t  assertSize$1(size);\n\n\t  if (size <= 0) {\n\t    return createBuffer$1(that, size);\n\t  }\n\n\t  if (fill !== undefined) {\n\t    // Only pay attention to encoding if it's a string. This\n\t    // prevents accidentally sending in a number that would\n\t    // be interpretted as a start offset.\n\t    return typeof encoding === 'string' ? createBuffer$1(that, size).fill(fill, encoding) : createBuffer$1(that, size).fill(fill);\n\t  }\n\n\t  return createBuffer$1(that, size);\n\t}\n\t/**\n\t * Creates a new filled Buffer instance.\n\t * alloc(size[, fill[, encoding]])\n\t **/\n\n\n\tBuffer$1.alloc = function (size, fill, encoding) {\n\t  return alloc$1(null, size, fill, encoding);\n\t};\n\n\tfunction allocUnsafe$1(that, size) {\n\t  assertSize$1(size);\n\t  that = createBuffer$1(that, size < 0 ? 0 : checked$1(size) | 0);\n\n\t  if (!Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    for (var i = 0; i < size; ++i) {\n\t      that[i] = 0;\n\t    }\n\t  }\n\n\t  return that;\n\t}\n\t/**\n\t * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n\t * */\n\n\n\tBuffer$1.allocUnsafe = function (size) {\n\t  return allocUnsafe$1(null, size);\n\t};\n\t/**\n\t * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n\t */\n\n\n\tBuffer$1.allocUnsafeSlow = function (size) {\n\t  return allocUnsafe$1(null, size);\n\t};\n\n\tfunction fromString$1(that, string, encoding) {\n\t  if (typeof encoding !== 'string' || encoding === '') {\n\t    encoding = 'utf8';\n\t  }\n\n\t  if (!Buffer$1.isEncoding(encoding)) {\n\t    throw new TypeError('\"encoding\" must be a valid string encoding');\n\t  }\n\n\t  var length = byteLength$1(string, encoding) | 0;\n\t  that = createBuffer$1(that, length);\n\t  var actual = that.write(string, encoding);\n\n\t  if (actual !== length) {\n\t    // Writing a hex string, for example, that contains invalid characters will\n\t    // cause everything after the first invalid character to be ignored. (e.g.\n\t    // 'abxxcd' will be treated as 'ab')\n\t    that = that.slice(0, actual);\n\t  }\n\n\t  return that;\n\t}\n\n\tfunction fromArrayLike$1(that, array) {\n\t  var length = array.length < 0 ? 0 : checked$1(array.length) | 0;\n\t  that = createBuffer$1(that, length);\n\n\t  for (var i = 0; i < length; i += 1) {\n\t    that[i] = array[i] & 255;\n\t  }\n\n\t  return that;\n\t}\n\n\tfunction fromArrayBuffer$1(that, array, byteOffset, length) {\n\t  array.byteLength; // this throws if `array` is not a valid ArrayBuffer\n\n\t  if (byteOffset < 0 || array.byteLength < byteOffset) {\n\t    throw new RangeError('\\'offset\\' is out of bounds');\n\t  }\n\n\t  if (array.byteLength < byteOffset + (length || 0)) {\n\t    throw new RangeError('\\'length\\' is out of bounds');\n\t  }\n\n\t  if (byteOffset === undefined && length === undefined) {\n\t    array = new Uint8Array(array);\n\t  } else if (length === undefined) {\n\t    array = new Uint8Array(array, byteOffset);\n\t  } else {\n\t    array = new Uint8Array(array, byteOffset, length);\n\t  }\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    // Return an augmented `Uint8Array` instance, for best performance\n\t    that = array;\n\t    that.__proto__ = Buffer$1.prototype;\n\t  } else {\n\t    // Fallback: Return an object instance of the Buffer class\n\t    that = fromArrayLike$1(that, array);\n\t  }\n\n\t  return that;\n\t}\n\n\tfunction fromObject$1(that, obj) {\n\t  if (internalIsBuffer$1(obj)) {\n\t    var len = checked$1(obj.length) | 0;\n\t    that = createBuffer$1(that, len);\n\n\t    if (that.length === 0) {\n\t      return that;\n\t    }\n\n\t    obj.copy(that, 0, 0, len);\n\t    return that;\n\t  }\n\n\t  if (obj) {\n\t    if (typeof ArrayBuffer !== 'undefined' && obj.buffer instanceof ArrayBuffer || 'length' in obj) {\n\t      if (typeof obj.length !== 'number' || isnan$1(obj.length)) {\n\t        return createBuffer$1(that, 0);\n\t      }\n\n\t      return fromArrayLike$1(that, obj);\n\t    }\n\n\t    if (obj.type === 'Buffer' && isArray$2(obj.data)) {\n\t      return fromArrayLike$1(that, obj.data);\n\t    }\n\t  }\n\n\t  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.');\n\t}\n\n\tfunction checked$1(length) {\n\t  // Note: cannot use `length < kMaxLength()` here because that fails when\n\t  // length is NaN (which is otherwise coerced to zero.)\n\t  if (length >= kMaxLength$1()) {\n\t    throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + kMaxLength$1().toString(16) + ' bytes');\n\t  }\n\n\t  return length | 0;\n\t}\n\tBuffer$1.isBuffer = isBuffer$2;\n\n\tfunction internalIsBuffer$1(b) {\n\t  return !!(b != null && b._isBuffer);\n\t}\n\n\tBuffer$1.compare = function compare(a, b) {\n\t  if (!internalIsBuffer$1(a) || !internalIsBuffer$1(b)) {\n\t    throw new TypeError('Arguments must be Buffers');\n\t  }\n\n\t  if (a === b) return 0;\n\t  var x = a.length;\n\t  var y = b.length;\n\n\t  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n\t    if (a[i] !== b[i]) {\n\t      x = a[i];\n\t      y = b[i];\n\t      break;\n\t    }\n\t  }\n\n\t  if (x < y) return -1;\n\t  if (y < x) return 1;\n\t  return 0;\n\t};\n\n\tBuffer$1.isEncoding = function isEncoding(encoding) {\n\t  switch (String(encoding).toLowerCase()) {\n\t    case 'hex':\n\t    case 'utf8':\n\t    case 'utf-8':\n\t    case 'ascii':\n\t    case 'latin1':\n\t    case 'binary':\n\t    case 'base64':\n\t    case 'ucs2':\n\t    case 'ucs-2':\n\t    case 'utf16le':\n\t    case 'utf-16le':\n\t      return true;\n\n\t    default:\n\t      return false;\n\t  }\n\t};\n\n\tBuffer$1.concat = function concat(list, length) {\n\t  if (!isArray$2(list)) {\n\t    throw new TypeError('\"list\" argument must be an Array of Buffers');\n\t  }\n\n\t  if (list.length === 0) {\n\t    return Buffer$1.alloc(0);\n\t  }\n\n\t  var i;\n\n\t  if (length === undefined) {\n\t    length = 0;\n\n\t    for (i = 0; i < list.length; ++i) {\n\t      length += list[i].length;\n\t    }\n\t  }\n\n\t  var buffer = Buffer$1.allocUnsafe(length);\n\t  var pos = 0;\n\n\t  for (i = 0; i < list.length; ++i) {\n\t    var buf = list[i];\n\n\t    if (!internalIsBuffer$1(buf)) {\n\t      throw new TypeError('\"list\" argument must be an Array of Buffers');\n\t    }\n\n\t    buf.copy(buffer, pos);\n\t    pos += buf.length;\n\t  }\n\n\t  return buffer;\n\t};\n\n\tfunction byteLength$1(string, encoding) {\n\t  if (internalIsBuffer$1(string)) {\n\t    return string.length;\n\t  }\n\n\t  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n\t    return string.byteLength;\n\t  }\n\n\t  if (typeof string !== 'string') {\n\t    string = '' + string;\n\t  }\n\n\t  var len = string.length;\n\t  if (len === 0) return 0; // Use a for loop to avoid recursion\n\n\t  var loweredCase = false;\n\n\t  for (;;) {\n\t    switch (encoding) {\n\t      case 'ascii':\n\t      case 'latin1':\n\t      case 'binary':\n\t        return len;\n\n\t      case 'utf8':\n\t      case 'utf-8':\n\t      case undefined:\n\t        return utf8ToBytes$1(string).length;\n\n\t      case 'ucs2':\n\t      case 'ucs-2':\n\t      case 'utf16le':\n\t      case 'utf-16le':\n\t        return len * 2;\n\n\t      case 'hex':\n\t        return len >>> 1;\n\n\t      case 'base64':\n\t        return base64ToBytes$1(string).length;\n\n\t      default:\n\t        if (loweredCase) return utf8ToBytes$1(string).length; // assume utf8\n\n\t        encoding = ('' + encoding).toLowerCase();\n\t        loweredCase = true;\n\t    }\n\t  }\n\t}\n\n\tBuffer$1.byteLength = byteLength$1;\n\n\tfunction slowToString$1(encoding, start, end) {\n\t  var loweredCase = false; // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n\t  // property of a typed array.\n\t  // This behaves neither like String nor Uint8Array in that we set start/end\n\t  // to their upper/lower bounds if the value passed is out of range.\n\t  // undefined is handled specially as per ECMA-262 6th Edition,\n\t  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n\n\t  if (start === undefined || start < 0) {\n\t    start = 0;\n\t  } // Return early if start > this.length. Done here to prevent potential uint32\n\t  // coercion fail below.\n\n\n\t  if (start > this.length) {\n\t    return '';\n\t  }\n\n\t  if (end === undefined || end > this.length) {\n\t    end = this.length;\n\t  }\n\n\t  if (end <= 0) {\n\t    return '';\n\t  } // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n\n\n\t  end >>>= 0;\n\t  start >>>= 0;\n\n\t  if (end <= start) {\n\t    return '';\n\t  }\n\n\t  if (!encoding) encoding = 'utf8';\n\n\t  while (true) {\n\t    switch (encoding) {\n\t      case 'hex':\n\t        return hexSlice$1(this, start, end);\n\n\t      case 'utf8':\n\t      case 'utf-8':\n\t        return utf8Slice$1(this, start, end);\n\n\t      case 'ascii':\n\t        return asciiSlice$1(this, start, end);\n\n\t      case 'latin1':\n\t      case 'binary':\n\t        return latin1Slice$1(this, start, end);\n\n\t      case 'base64':\n\t        return base64Slice$1(this, start, end);\n\n\t      case 'ucs2':\n\t      case 'ucs-2':\n\t      case 'utf16le':\n\t      case 'utf-16le':\n\t        return utf16leSlice$1(this, start, end);\n\n\t      default:\n\t        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);\n\t        encoding = (encoding + '').toLowerCase();\n\t        loweredCase = true;\n\t    }\n\t  }\n\t} // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n\t// Buffer instances.\n\n\n\tBuffer$1.prototype._isBuffer = true;\n\n\tfunction swap$1(b, n, m) {\n\t  var i = b[n];\n\t  b[n] = b[m];\n\t  b[m] = i;\n\t}\n\n\tBuffer$1.prototype.swap16 = function swap16() {\n\t  var len = this.length;\n\n\t  if (len % 2 !== 0) {\n\t    throw new RangeError('Buffer size must be a multiple of 16-bits');\n\t  }\n\n\t  for (var i = 0; i < len; i += 2) {\n\t    swap$1(this, i, i + 1);\n\t  }\n\n\t  return this;\n\t};\n\n\tBuffer$1.prototype.swap32 = function swap32() {\n\t  var len = this.length;\n\n\t  if (len % 4 !== 0) {\n\t    throw new RangeError('Buffer size must be a multiple of 32-bits');\n\t  }\n\n\t  for (var i = 0; i < len; i += 4) {\n\t    swap$1(this, i, i + 3);\n\t    swap$1(this, i + 1, i + 2);\n\t  }\n\n\t  return this;\n\t};\n\n\tBuffer$1.prototype.swap64 = function swap64() {\n\t  var len = this.length;\n\n\t  if (len % 8 !== 0) {\n\t    throw new RangeError('Buffer size must be a multiple of 64-bits');\n\t  }\n\n\t  for (var i = 0; i < len; i += 8) {\n\t    swap$1(this, i, i + 7);\n\t    swap$1(this, i + 1, i + 6);\n\t    swap$1(this, i + 2, i + 5);\n\t    swap$1(this, i + 3, i + 4);\n\t  }\n\n\t  return this;\n\t};\n\n\tBuffer$1.prototype.toString = function toString() {\n\t  var length = this.length | 0;\n\t  if (length === 0) return '';\n\t  if (arguments.length === 0) return utf8Slice$1(this, 0, length);\n\t  return slowToString$1.apply(this, arguments);\n\t};\n\n\tBuffer$1.prototype.equals = function equals(b) {\n\t  if (!internalIsBuffer$1(b)) throw new TypeError('Argument must be a Buffer');\n\t  if (this === b) return true;\n\t  return Buffer$1.compare(this, b) === 0;\n\t};\n\n\tBuffer$1.prototype.inspect = function inspect() {\n\t  var str = '';\n\t  var max = INSPECT_MAX_BYTES$1;\n\n\t  if (this.length > 0) {\n\t    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');\n\t    if (this.length > max) str += ' ... ';\n\t  }\n\n\t  return '<Buffer ' + str + '>';\n\t};\n\n\tBuffer$1.prototype.compare = function compare(target, start, end, thisStart, thisEnd) {\n\t  if (!internalIsBuffer$1(target)) {\n\t    throw new TypeError('Argument must be a Buffer');\n\t  }\n\n\t  if (start === undefined) {\n\t    start = 0;\n\t  }\n\n\t  if (end === undefined) {\n\t    end = target ? target.length : 0;\n\t  }\n\n\t  if (thisStart === undefined) {\n\t    thisStart = 0;\n\t  }\n\n\t  if (thisEnd === undefined) {\n\t    thisEnd = this.length;\n\t  }\n\n\t  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n\t    throw new RangeError('out of range index');\n\t  }\n\n\t  if (thisStart >= thisEnd && start >= end) {\n\t    return 0;\n\t  }\n\n\t  if (thisStart >= thisEnd) {\n\t    return -1;\n\t  }\n\n\t  if (start >= end) {\n\t    return 1;\n\t  }\n\n\t  start >>>= 0;\n\t  end >>>= 0;\n\t  thisStart >>>= 0;\n\t  thisEnd >>>= 0;\n\t  if (this === target) return 0;\n\t  var x = thisEnd - thisStart;\n\t  var y = end - start;\n\t  var len = Math.min(x, y);\n\t  var thisCopy = this.slice(thisStart, thisEnd);\n\t  var targetCopy = target.slice(start, end);\n\n\t  for (var i = 0; i < len; ++i) {\n\t    if (thisCopy[i] !== targetCopy[i]) {\n\t      x = thisCopy[i];\n\t      y = targetCopy[i];\n\t      break;\n\t    }\n\t  }\n\n\t  if (x < y) return -1;\n\t  if (y < x) return 1;\n\t  return 0;\n\t}; // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n\t// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n\t//\n\t// Arguments:\n\t// - buffer - a Buffer to search\n\t// - val - a string, Buffer, or number\n\t// - byteOffset - an index into `buffer`; will be clamped to an int32\n\t// - encoding - an optional encoding, relevant is val is a string\n\t// - dir - true for indexOf, false for lastIndexOf\n\n\n\tfunction bidirectionalIndexOf$1(buffer, val, byteOffset, encoding, dir) {\n\t  // Empty buffer means no match\n\t  if (buffer.length === 0) return -1; // Normalize byteOffset\n\n\t  if (typeof byteOffset === 'string') {\n\t    encoding = byteOffset;\n\t    byteOffset = 0;\n\t  } else if (byteOffset > 0x7fffffff) {\n\t    byteOffset = 0x7fffffff;\n\t  } else if (byteOffset < -0x80000000) {\n\t    byteOffset = -0x80000000;\n\t  }\n\n\t  byteOffset = +byteOffset; // Coerce to Number.\n\n\t  if (isNaN(byteOffset)) {\n\t    // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n\t    byteOffset = dir ? 0 : buffer.length - 1;\n\t  } // Normalize byteOffset: negative offsets start from the end of the buffer\n\n\n\t  if (byteOffset < 0) byteOffset = buffer.length + byteOffset;\n\n\t  if (byteOffset >= buffer.length) {\n\t    if (dir) return -1;else byteOffset = buffer.length - 1;\n\t  } else if (byteOffset < 0) {\n\t    if (dir) byteOffset = 0;else return -1;\n\t  } // Normalize val\n\n\n\t  if (typeof val === 'string') {\n\t    val = Buffer$1.from(val, encoding);\n\t  } // Finally, search either indexOf (if dir is true) or lastIndexOf\n\n\n\t  if (internalIsBuffer$1(val)) {\n\t    // Special case: looking for empty string/buffer always fails\n\t    if (val.length === 0) {\n\t      return -1;\n\t    }\n\n\t    return arrayIndexOf$1(buffer, val, byteOffset, encoding, dir);\n\t  } else if (typeof val === 'number') {\n\t    val = val & 0xFF; // Search for a byte value [0-255]\n\n\t    if (Buffer$1.TYPED_ARRAY_SUPPORT && typeof Uint8Array.prototype.indexOf === 'function') {\n\t      if (dir) {\n\t        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset);\n\t      } else {\n\t        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset);\n\t      }\n\t    }\n\n\t    return arrayIndexOf$1(buffer, [val], byteOffset, encoding, dir);\n\t  }\n\n\t  throw new TypeError('val must be string, number or Buffer');\n\t}\n\n\tfunction arrayIndexOf$1(arr, val, byteOffset, encoding, dir) {\n\t  var indexSize = 1;\n\t  var arrLength = arr.length;\n\t  var valLength = val.length;\n\n\t  if (encoding !== undefined) {\n\t    encoding = String(encoding).toLowerCase();\n\n\t    if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') {\n\t      if (arr.length < 2 || val.length < 2) {\n\t        return -1;\n\t      }\n\n\t      indexSize = 2;\n\t      arrLength /= 2;\n\t      valLength /= 2;\n\t      byteOffset /= 2;\n\t    }\n\t  }\n\n\t  function read(buf, i) {\n\t    if (indexSize === 1) {\n\t      return buf[i];\n\t    } else {\n\t      return buf.readUInt16BE(i * indexSize);\n\t    }\n\t  }\n\n\t  var i;\n\n\t  if (dir) {\n\t    var foundIndex = -1;\n\n\t    for (i = byteOffset; i < arrLength; i++) {\n\t      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n\t        if (foundIndex === -1) foundIndex = i;\n\t        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize;\n\t      } else {\n\t        if (foundIndex !== -1) i -= i - foundIndex;\n\t        foundIndex = -1;\n\t      }\n\t    }\n\t  } else {\n\t    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;\n\n\t    for (i = byteOffset; i >= 0; i--) {\n\t      var found = true;\n\n\t      for (var j = 0; j < valLength; j++) {\n\t        if (read(arr, i + j) !== read(val, j)) {\n\t          found = false;\n\t          break;\n\t        }\n\t      }\n\n\t      if (found) return i;\n\t    }\n\t  }\n\n\t  return -1;\n\t}\n\n\tBuffer$1.prototype.includes = function includes(val, byteOffset, encoding) {\n\t  return this.indexOf(val, byteOffset, encoding) !== -1;\n\t};\n\n\tBuffer$1.prototype.indexOf = function indexOf(val, byteOffset, encoding) {\n\t  return bidirectionalIndexOf$1(this, val, byteOffset, encoding, true);\n\t};\n\n\tBuffer$1.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {\n\t  return bidirectionalIndexOf$1(this, val, byteOffset, encoding, false);\n\t};\n\n\tfunction hexWrite$1(buf, string, offset, length) {\n\t  offset = Number(offset) || 0;\n\t  var remaining = buf.length - offset;\n\n\t  if (!length) {\n\t    length = remaining;\n\t  } else {\n\t    length = Number(length);\n\n\t    if (length > remaining) {\n\t      length = remaining;\n\t    }\n\t  } // must be an even number of digits\n\n\n\t  var strLen = string.length;\n\t  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string');\n\n\t  if (length > strLen / 2) {\n\t    length = strLen / 2;\n\t  }\n\n\t  for (var i = 0; i < length; ++i) {\n\t    var parsed = parseInt(string.substr(i * 2, 2), 16);\n\t    if (isNaN(parsed)) return i;\n\t    buf[offset + i] = parsed;\n\t  }\n\n\t  return i;\n\t}\n\n\tfunction utf8Write$1(buf, string, offset, length) {\n\t  return blitBuffer$1(utf8ToBytes$1(string, buf.length - offset), buf, offset, length);\n\t}\n\n\tfunction asciiWrite$1(buf, string, offset, length) {\n\t  return blitBuffer$1(asciiToBytes$1(string), buf, offset, length);\n\t}\n\n\tfunction latin1Write$1(buf, string, offset, length) {\n\t  return asciiWrite$1(buf, string, offset, length);\n\t}\n\n\tfunction base64Write$1(buf, string, offset, length) {\n\t  return blitBuffer$1(base64ToBytes$1(string), buf, offset, length);\n\t}\n\n\tfunction ucs2Write$1(buf, string, offset, length) {\n\t  return blitBuffer$1(utf16leToBytes$1(string, buf.length - offset), buf, offset, length);\n\t}\n\n\tBuffer$1.prototype.write = function write(string, offset, length, encoding) {\n\t  // Buffer#write(string)\n\t  if (offset === undefined) {\n\t    encoding = 'utf8';\n\t    length = this.length;\n\t    offset = 0; // Buffer#write(string, encoding)\n\t  } else if (length === undefined && typeof offset === 'string') {\n\t    encoding = offset;\n\t    length = this.length;\n\t    offset = 0; // Buffer#write(string, offset[, length][, encoding])\n\t  } else if (isFinite(offset)) {\n\t    offset = offset | 0;\n\n\t    if (isFinite(length)) {\n\t      length = length | 0;\n\t      if (encoding === undefined) encoding = 'utf8';\n\t    } else {\n\t      encoding = length;\n\t      length = undefined;\n\t    } // legacy write(string, encoding, offset, length) - remove in v0.13\n\n\t  } else {\n\t    throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported');\n\t  }\n\n\t  var remaining = this.length - offset;\n\t  if (length === undefined || length > remaining) length = remaining;\n\n\t  if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) {\n\t    throw new RangeError('Attempt to write outside buffer bounds');\n\t  }\n\n\t  if (!encoding) encoding = 'utf8';\n\t  var loweredCase = false;\n\n\t  for (;;) {\n\t    switch (encoding) {\n\t      case 'hex':\n\t        return hexWrite$1(this, string, offset, length);\n\n\t      case 'utf8':\n\t      case 'utf-8':\n\t        return utf8Write$1(this, string, offset, length);\n\n\t      case 'ascii':\n\t        return asciiWrite$1(this, string, offset, length);\n\n\t      case 'latin1':\n\t      case 'binary':\n\t        return latin1Write$1(this, string, offset, length);\n\n\t      case 'base64':\n\t        // Warning: maxLength not taken into account in base64Write\n\t        return base64Write$1(this, string, offset, length);\n\n\t      case 'ucs2':\n\t      case 'ucs-2':\n\t      case 'utf16le':\n\t      case 'utf-16le':\n\t        return ucs2Write$1(this, string, offset, length);\n\n\t      default:\n\t        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);\n\t        encoding = ('' + encoding).toLowerCase();\n\t        loweredCase = true;\n\t    }\n\t  }\n\t};\n\n\tBuffer$1.prototype.toJSON = function toJSON() {\n\t  return {\n\t    type: 'Buffer',\n\t    data: Array.prototype.slice.call(this._arr || this, 0)\n\t  };\n\t};\n\n\tfunction base64Slice$1(buf, start, end) {\n\t  if (start === 0 && end === buf.length) {\n\t    return fromByteArray$1(buf);\n\t  } else {\n\t    return fromByteArray$1(buf.slice(start, end));\n\t  }\n\t}\n\n\tfunction utf8Slice$1(buf, start, end) {\n\t  end = Math.min(buf.length, end);\n\t  var res = [];\n\t  var i = start;\n\n\t  while (i < end) {\n\t    var firstByte = buf[i];\n\t    var codePoint = null;\n\t    var bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1;\n\n\t    if (i + bytesPerSequence <= end) {\n\t      var secondByte, thirdByte, fourthByte, tempCodePoint;\n\n\t      switch (bytesPerSequence) {\n\t        case 1:\n\t          if (firstByte < 0x80) {\n\t            codePoint = firstByte;\n\t          }\n\n\t          break;\n\n\t        case 2:\n\t          secondByte = buf[i + 1];\n\n\t          if ((secondByte & 0xC0) === 0x80) {\n\t            tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F;\n\n\t            if (tempCodePoint > 0x7F) {\n\t              codePoint = tempCodePoint;\n\t            }\n\t          }\n\n\t          break;\n\n\t        case 3:\n\t          secondByte = buf[i + 1];\n\t          thirdByte = buf[i + 2];\n\n\t          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n\t            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F;\n\n\t            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n\t              codePoint = tempCodePoint;\n\t            }\n\t          }\n\n\t          break;\n\n\t        case 4:\n\t          secondByte = buf[i + 1];\n\t          thirdByte = buf[i + 2];\n\t          fourthByte = buf[i + 3];\n\n\t          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n\t            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F;\n\n\t            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n\t              codePoint = tempCodePoint;\n\t            }\n\t          }\n\n\t      }\n\t    }\n\n\t    if (codePoint === null) {\n\t      // we did not generate a valid codePoint so insert a\n\t      // replacement char (U+FFFD) and advance only 1 byte\n\t      codePoint = 0xFFFD;\n\t      bytesPerSequence = 1;\n\t    } else if (codePoint > 0xFFFF) {\n\t      // encode to utf16 (surrogate pair dance)\n\t      codePoint -= 0x10000;\n\t      res.push(codePoint >>> 10 & 0x3FF | 0xD800);\n\t      codePoint = 0xDC00 | codePoint & 0x3FF;\n\t    }\n\n\t    res.push(codePoint);\n\t    i += bytesPerSequence;\n\t  }\n\n\t  return decodeCodePointsArray$1(res);\n\t} // Based on http://stackoverflow.com/a/22747272/680742, the browser with\n\t// the lowest limit is Chrome, with 0x10000 args.\n\t// We go 1 magnitude less, for safety\n\n\n\tvar MAX_ARGUMENTS_LENGTH$1 = 0x1000;\n\n\tfunction decodeCodePointsArray$1(codePoints) {\n\t  var len = codePoints.length;\n\n\t  if (len <= MAX_ARGUMENTS_LENGTH$1) {\n\t    return String.fromCharCode.apply(String, codePoints); // avoid extra slice()\n\t  } // Decode in chunks to avoid \"call stack size exceeded\".\n\n\n\t  var res = '';\n\t  var i = 0;\n\n\t  while (i < len) {\n\t    res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH$1));\n\t  }\n\n\t  return res;\n\t}\n\n\tfunction asciiSlice$1(buf, start, end) {\n\t  var ret = '';\n\t  end = Math.min(buf.length, end);\n\n\t  for (var i = start; i < end; ++i) {\n\t    ret += String.fromCharCode(buf[i] & 0x7F);\n\t  }\n\n\t  return ret;\n\t}\n\n\tfunction latin1Slice$1(buf, start, end) {\n\t  var ret = '';\n\t  end = Math.min(buf.length, end);\n\n\t  for (var i = start; i < end; ++i) {\n\t    ret += String.fromCharCode(buf[i]);\n\t  }\n\n\t  return ret;\n\t}\n\n\tfunction hexSlice$1(buf, start, end) {\n\t  var len = buf.length;\n\t  if (!start || start < 0) start = 0;\n\t  if (!end || end < 0 || end > len) end = len;\n\t  var out = '';\n\n\t  for (var i = start; i < end; ++i) {\n\t    out += toHex$1(buf[i]);\n\t  }\n\n\t  return out;\n\t}\n\n\tfunction utf16leSlice$1(buf, start, end) {\n\t  var bytes = buf.slice(start, end);\n\t  var res = '';\n\n\t  for (var i = 0; i < bytes.length; i += 2) {\n\t    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);\n\t  }\n\n\t  return res;\n\t}\n\n\tBuffer$1.prototype.slice = function slice(start, end) {\n\t  var len = this.length;\n\t  start = ~~start;\n\t  end = end === undefined ? len : ~~end;\n\n\t  if (start < 0) {\n\t    start += len;\n\t    if (start < 0) start = 0;\n\t  } else if (start > len) {\n\t    start = len;\n\t  }\n\n\t  if (end < 0) {\n\t    end += len;\n\t    if (end < 0) end = 0;\n\t  } else if (end > len) {\n\t    end = len;\n\t  }\n\n\t  if (end < start) end = start;\n\t  var newBuf;\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    newBuf = this.subarray(start, end);\n\t    newBuf.__proto__ = Buffer$1.prototype;\n\t  } else {\n\t    var sliceLen = end - start;\n\t    newBuf = new Buffer$1(sliceLen, undefined);\n\n\t    for (var i = 0; i < sliceLen; ++i) {\n\t      newBuf[i] = this[i + start];\n\t    }\n\t  }\n\n\t  return newBuf;\n\t};\n\t/*\n\t * Need to make sure that buffer isn't trying to write out of bounds.\n\t */\n\n\n\tfunction checkOffset$1(offset, ext, length) {\n\t  if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint');\n\t  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length');\n\t}\n\n\tBuffer$1.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\t  if (!noAssert) checkOffset$1(offset, byteLength, this.length);\n\t  var val = this[offset];\n\t  var mul = 1;\n\t  var i = 0;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    val += this[offset + i] * mul;\n\t  }\n\n\t  return val;\n\t};\n\n\tBuffer$1.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\n\t  if (!noAssert) {\n\t    checkOffset$1(offset, byteLength, this.length);\n\t  }\n\n\t  var val = this[offset + --byteLength];\n\t  var mul = 1;\n\n\t  while (byteLength > 0 && (mul *= 0x100)) {\n\t    val += this[offset + --byteLength] * mul;\n\t  }\n\n\t  return val;\n\t};\n\n\tBuffer$1.prototype.readUInt8 = function readUInt8(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 1, this.length);\n\t  return this[offset];\n\t};\n\n\tBuffer$1.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 2, this.length);\n\t  return this[offset] | this[offset + 1] << 8;\n\t};\n\n\tBuffer$1.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 2, this.length);\n\t  return this[offset] << 8 | this[offset + 1];\n\t};\n\n\tBuffer$1.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 4, this.length);\n\t  return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 0x1000000;\n\t};\n\n\tBuffer$1.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 4, this.length);\n\t  return this[offset] * 0x1000000 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]);\n\t};\n\n\tBuffer$1.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\t  if (!noAssert) checkOffset$1(offset, byteLength, this.length);\n\t  var val = this[offset];\n\t  var mul = 1;\n\t  var i = 0;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    val += this[offset + i] * mul;\n\t  }\n\n\t  mul *= 0x80;\n\t  if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n\t  return val;\n\t};\n\n\tBuffer$1.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\t  if (!noAssert) checkOffset$1(offset, byteLength, this.length);\n\t  var i = byteLength;\n\t  var mul = 1;\n\t  var val = this[offset + --i];\n\n\t  while (i > 0 && (mul *= 0x100)) {\n\t    val += this[offset + --i] * mul;\n\t  }\n\n\t  mul *= 0x80;\n\t  if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n\t  return val;\n\t};\n\n\tBuffer$1.prototype.readInt8 = function readInt8(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 1, this.length);\n\t  if (!(this[offset] & 0x80)) return this[offset];\n\t  return (0xff - this[offset] + 1) * -1;\n\t};\n\n\tBuffer$1.prototype.readInt16LE = function readInt16LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 2, this.length);\n\t  var val = this[offset] | this[offset + 1] << 8;\n\t  return val & 0x8000 ? val | 0xFFFF0000 : val;\n\t};\n\n\tBuffer$1.prototype.readInt16BE = function readInt16BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 2, this.length);\n\t  var val = this[offset + 1] | this[offset] << 8;\n\t  return val & 0x8000 ? val | 0xFFFF0000 : val;\n\t};\n\n\tBuffer$1.prototype.readInt32LE = function readInt32LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 4, this.length);\n\t  return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24;\n\t};\n\n\tBuffer$1.prototype.readInt32BE = function readInt32BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 4, this.length);\n\t  return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3];\n\t};\n\n\tBuffer$1.prototype.readFloatLE = function readFloatLE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 4, this.length);\n\t  return read$1(this, offset, true, 23, 4);\n\t};\n\n\tBuffer$1.prototype.readFloatBE = function readFloatBE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 4, this.length);\n\t  return read$1(this, offset, false, 23, 4);\n\t};\n\n\tBuffer$1.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 8, this.length);\n\t  return read$1(this, offset, true, 52, 8);\n\t};\n\n\tBuffer$1.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {\n\t  if (!noAssert) checkOffset$1(offset, 8, this.length);\n\t  return read$1(this, offset, false, 52, 8);\n\t};\n\n\tfunction checkInt$1(buf, value, offset, ext, max, min) {\n\t  if (!internalIsBuffer$1(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance');\n\t  if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds');\n\t  if (offset + ext > buf.length) throw new RangeError('Index out of range');\n\t}\n\n\tBuffer$1.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\n\t  if (!noAssert) {\n\t    var maxBytes = Math.pow(2, 8 * byteLength) - 1;\n\t    checkInt$1(this, value, offset, byteLength, maxBytes, 0);\n\t  }\n\n\t  var mul = 1;\n\t  var i = 0;\n\t  this[offset] = value & 0xFF;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    this[offset + i] = value / mul & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer$1.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\n\t  if (!noAssert) {\n\t    var maxBytes = Math.pow(2, 8 * byteLength) - 1;\n\t    checkInt$1(this, value, offset, byteLength, maxBytes, 0);\n\t  }\n\n\t  var i = byteLength - 1;\n\t  var mul = 1;\n\t  this[offset + i] = value & 0xFF;\n\n\t  while (--i >= 0 && (mul *= 0x100)) {\n\t    this[offset + i] = value / mul & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer$1.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 1, 0xff, 0);\n\t  if (!Buffer$1.TYPED_ARRAY_SUPPORT) value = Math.floor(value);\n\t  this[offset] = value & 0xff;\n\t  return offset + 1;\n\t};\n\n\tfunction objectWriteUInt16$1(buf, value, offset, littleEndian) {\n\t  if (value < 0) value = 0xffff + value + 1;\n\n\t  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n\t    buf[offset + i] = (value & 0xff << 8 * (littleEndian ? i : 1 - i)) >>> (littleEndian ? i : 1 - i) * 8;\n\t  }\n\t}\n\n\tBuffer$1.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 2, 0xffff, 0);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value & 0xff;\n\t    this[offset + 1] = value >>> 8;\n\t  } else {\n\t    objectWriteUInt16$1(this, value, offset, true);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tBuffer$1.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 2, 0xffff, 0);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 8;\n\t    this[offset + 1] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt16$1(this, value, offset, false);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tfunction objectWriteUInt32$1(buf, value, offset, littleEndian) {\n\t  if (value < 0) value = 0xffffffff + value + 1;\n\n\t  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n\t    buf[offset + i] = value >>> (littleEndian ? i : 3 - i) * 8 & 0xff;\n\t  }\n\t}\n\n\tBuffer$1.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 4, 0xffffffff, 0);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset + 3] = value >>> 24;\n\t    this[offset + 2] = value >>> 16;\n\t    this[offset + 1] = value >>> 8;\n\t    this[offset] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt32$1(this, value, offset, true);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tBuffer$1.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 4, 0xffffffff, 0);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 24;\n\t    this[offset + 1] = value >>> 16;\n\t    this[offset + 2] = value >>> 8;\n\t    this[offset + 3] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt32$1(this, value, offset, false);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tBuffer$1.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\n\t  if (!noAssert) {\n\t    var limit = Math.pow(2, 8 * byteLength - 1);\n\t    checkInt$1(this, value, offset, byteLength, limit - 1, -limit);\n\t  }\n\n\t  var i = 0;\n\t  var mul = 1;\n\t  var sub = 0;\n\t  this[offset] = value & 0xFF;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n\t      sub = 1;\n\t    }\n\n\t    this[offset + i] = (value / mul >> 0) - sub & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer$1.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\n\t  if (!noAssert) {\n\t    var limit = Math.pow(2, 8 * byteLength - 1);\n\t    checkInt$1(this, value, offset, byteLength, limit - 1, -limit);\n\t  }\n\n\t  var i = byteLength - 1;\n\t  var mul = 1;\n\t  var sub = 0;\n\t  this[offset + i] = value & 0xFF;\n\n\t  while (--i >= 0 && (mul *= 0x100)) {\n\t    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n\t      sub = 1;\n\t    }\n\n\t    this[offset + i] = (value / mul >> 0) - sub & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer$1.prototype.writeInt8 = function writeInt8(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 1, 0x7f, -0x80);\n\t  if (!Buffer$1.TYPED_ARRAY_SUPPORT) value = Math.floor(value);\n\t  if (value < 0) value = 0xff + value + 1;\n\t  this[offset] = value & 0xff;\n\t  return offset + 1;\n\t};\n\n\tBuffer$1.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 2, 0x7fff, -0x8000);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value & 0xff;\n\t    this[offset + 1] = value >>> 8;\n\t  } else {\n\t    objectWriteUInt16$1(this, value, offset, true);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tBuffer$1.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 2, 0x7fff, -0x8000);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 8;\n\t    this[offset + 1] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt16$1(this, value, offset, false);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tBuffer$1.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 4, 0x7fffffff, -0x80000000);\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value & 0xff;\n\t    this[offset + 1] = value >>> 8;\n\t    this[offset + 2] = value >>> 16;\n\t    this[offset + 3] = value >>> 24;\n\t  } else {\n\t    objectWriteUInt32$1(this, value, offset, true);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tBuffer$1.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt$1(this, value, offset, 4, 0x7fffffff, -0x80000000);\n\t  if (value < 0) value = 0xffffffff + value + 1;\n\n\t  if (Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 24;\n\t    this[offset + 1] = value >>> 16;\n\t    this[offset + 2] = value >>> 8;\n\t    this[offset + 3] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt32$1(this, value, offset, false);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tfunction checkIEEE754$1(buf, value, offset, ext, max, min) {\n\t  if (offset + ext > buf.length) throw new RangeError('Index out of range');\n\t  if (offset < 0) throw new RangeError('Index out of range');\n\t}\n\n\tfunction writeFloat$1(buf, value, offset, littleEndian, noAssert) {\n\t  if (!noAssert) {\n\t    checkIEEE754$1(buf, value, offset, 4);\n\t  }\n\n\t  write$1(buf, value, offset, littleEndian, 23, 4);\n\t  return offset + 4;\n\t}\n\n\tBuffer$1.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) {\n\t  return writeFloat$1(this, value, offset, true, noAssert);\n\t};\n\n\tBuffer$1.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) {\n\t  return writeFloat$1(this, value, offset, false, noAssert);\n\t};\n\n\tfunction writeDouble$1(buf, value, offset, littleEndian, noAssert) {\n\t  if (!noAssert) {\n\t    checkIEEE754$1(buf, value, offset, 8);\n\t  }\n\n\t  write$1(buf, value, offset, littleEndian, 52, 8);\n\t  return offset + 8;\n\t}\n\n\tBuffer$1.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) {\n\t  return writeDouble$1(this, value, offset, true, noAssert);\n\t};\n\n\tBuffer$1.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) {\n\t  return writeDouble$1(this, value, offset, false, noAssert);\n\t}; // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\n\n\n\tBuffer$1.prototype.copy = function copy(target, targetStart, start, end) {\n\t  if (!start) start = 0;\n\t  if (!end && end !== 0) end = this.length;\n\t  if (targetStart >= target.length) targetStart = target.length;\n\t  if (!targetStart) targetStart = 0;\n\t  if (end > 0 && end < start) end = start; // Copy 0 bytes; we're done\n\n\t  if (end === start) return 0;\n\t  if (target.length === 0 || this.length === 0) return 0; // Fatal error conditions\n\n\t  if (targetStart < 0) {\n\t    throw new RangeError('targetStart out of bounds');\n\t  }\n\n\t  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds');\n\t  if (end < 0) throw new RangeError('sourceEnd out of bounds'); // Are we oob?\n\n\t  if (end > this.length) end = this.length;\n\n\t  if (target.length - targetStart < end - start) {\n\t    end = target.length - targetStart + start;\n\t  }\n\n\t  var len = end - start;\n\t  var i;\n\n\t  if (this === target && start < targetStart && targetStart < end) {\n\t    // descending copy from end\n\t    for (i = len - 1; i >= 0; --i) {\n\t      target[i + targetStart] = this[i + start];\n\t    }\n\t  } else if (len < 1000 || !Buffer$1.TYPED_ARRAY_SUPPORT) {\n\t    // ascending copy from start\n\t    for (i = 0; i < len; ++i) {\n\t      target[i + targetStart] = this[i + start];\n\t    }\n\t  } else {\n\t    Uint8Array.prototype.set.call(target, this.subarray(start, start + len), targetStart);\n\t  }\n\n\t  return len;\n\t}; // Usage:\n\t//    buffer.fill(number[, offset[, end]])\n\t//    buffer.fill(buffer[, offset[, end]])\n\t//    buffer.fill(string[, offset[, end]][, encoding])\n\n\n\tBuffer$1.prototype.fill = function fill(val, start, end, encoding) {\n\t  // Handle string cases:\n\t  if (typeof val === 'string') {\n\t    if (typeof start === 'string') {\n\t      encoding = start;\n\t      start = 0;\n\t      end = this.length;\n\t    } else if (typeof end === 'string') {\n\t      encoding = end;\n\t      end = this.length;\n\t    }\n\n\t    if (val.length === 1) {\n\t      var code = val.charCodeAt(0);\n\n\t      if (code < 256) {\n\t        val = code;\n\t      }\n\t    }\n\n\t    if (encoding !== undefined && typeof encoding !== 'string') {\n\t      throw new TypeError('encoding must be a string');\n\t    }\n\n\t    if (typeof encoding === 'string' && !Buffer$1.isEncoding(encoding)) {\n\t      throw new TypeError('Unknown encoding: ' + encoding);\n\t    }\n\t  } else if (typeof val === 'number') {\n\t    val = val & 255;\n\t  } // Invalid ranges are not set to a default, so can range check early.\n\n\n\t  if (start < 0 || this.length < start || this.length < end) {\n\t    throw new RangeError('Out of range index');\n\t  }\n\n\t  if (end <= start) {\n\t    return this;\n\t  }\n\n\t  start = start >>> 0;\n\t  end = end === undefined ? this.length : end >>> 0;\n\t  if (!val) val = 0;\n\t  var i;\n\n\t  if (typeof val === 'number') {\n\t    for (i = start; i < end; ++i) {\n\t      this[i] = val;\n\t    }\n\t  } else {\n\t    var bytes = internalIsBuffer$1(val) ? val : utf8ToBytes$1(new Buffer$1(val, encoding).toString());\n\t    var len = bytes.length;\n\n\t    for (i = 0; i < end - start; ++i) {\n\t      this[i + start] = bytes[i % len];\n\t    }\n\t  }\n\n\t  return this;\n\t}; // HELPER FUNCTIONS\n\t// ================\n\n\n\tvar INVALID_BASE64_RE$1 = /[^+\\/0-9A-Za-z-_]/g;\n\n\tfunction base64clean$1(str) {\n\t  // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n\t  str = stringtrim$1(str).replace(INVALID_BASE64_RE$1, ''); // Node converts strings with length < 2 to ''\n\n\t  if (str.length < 2) return ''; // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n\n\t  while (str.length % 4 !== 0) {\n\t    str = str + '=';\n\t  }\n\n\t  return str;\n\t}\n\n\tfunction stringtrim$1(str) {\n\t  if (str.trim) return str.trim();\n\t  return str.replace(/^\\s+|\\s+$/g, '');\n\t}\n\n\tfunction toHex$1(n) {\n\t  if (n < 16) return '0' + n.toString(16);\n\t  return n.toString(16);\n\t}\n\n\tfunction utf8ToBytes$1(string, units) {\n\t  units = units || Infinity;\n\t  var codePoint;\n\t  var length = string.length;\n\t  var leadSurrogate = null;\n\t  var bytes = [];\n\n\t  for (var i = 0; i < length; ++i) {\n\t    codePoint = string.charCodeAt(i); // is surrogate component\n\n\t    if (codePoint > 0xD7FF && codePoint < 0xE000) {\n\t      // last char was a lead\n\t      if (!leadSurrogate) {\n\t        // no lead yet\n\t        if (codePoint > 0xDBFF) {\n\t          // unexpected trail\n\t          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t          continue;\n\t        } else if (i + 1 === length) {\n\t          // unpaired lead\n\t          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t          continue;\n\t        } // valid lead\n\n\n\t        leadSurrogate = codePoint;\n\t        continue;\n\t      } // 2 leads in a row\n\n\n\t      if (codePoint < 0xDC00) {\n\t        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t        leadSurrogate = codePoint;\n\t        continue;\n\t      } // valid surrogate pair\n\n\n\t      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;\n\t    } else if (leadSurrogate) {\n\t      // valid bmp char, but last char was a lead\n\t      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t    }\n\n\t    leadSurrogate = null; // encode utf8\n\n\t    if (codePoint < 0x80) {\n\t      if ((units -= 1) < 0) break;\n\t      bytes.push(codePoint);\n\t    } else if (codePoint < 0x800) {\n\t      if ((units -= 2) < 0) break;\n\t      bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80);\n\t    } else if (codePoint < 0x10000) {\n\t      if ((units -= 3) < 0) break;\n\t      bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);\n\t    } else if (codePoint < 0x110000) {\n\t      if ((units -= 4) < 0) break;\n\t      bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);\n\t    } else {\n\t      throw new Error('Invalid code point');\n\t    }\n\t  }\n\n\t  return bytes;\n\t}\n\n\tfunction asciiToBytes$1(str) {\n\t  var byteArray = [];\n\n\t  for (var i = 0; i < str.length; ++i) {\n\t    // Node's code seems to be doing this and not & 0x7F..\n\t    byteArray.push(str.charCodeAt(i) & 0xFF);\n\t  }\n\n\t  return byteArray;\n\t}\n\n\tfunction utf16leToBytes$1(str, units) {\n\t  var c, hi, lo;\n\t  var byteArray = [];\n\n\t  for (var i = 0; i < str.length; ++i) {\n\t    if ((units -= 2) < 0) break;\n\t    c = str.charCodeAt(i);\n\t    hi = c >> 8;\n\t    lo = c % 256;\n\t    byteArray.push(lo);\n\t    byteArray.push(hi);\n\t  }\n\n\t  return byteArray;\n\t}\n\n\tfunction base64ToBytes$1(str) {\n\t  return toByteArray$1(base64clean$1(str));\n\t}\n\n\tfunction blitBuffer$1(src, dst, offset, length) {\n\t  for (var i = 0; i < length; ++i) {\n\t    if (i + offset >= dst.length || i >= src.length) break;\n\t    dst[i + offset] = src[i];\n\t  }\n\n\t  return i;\n\t}\n\n\tfunction isnan$1(val) {\n\t  return val !== val; // eslint-disable-line no-self-compare\n\t} // the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence\n\t// The _isBuffer check is for Safari 5-7 support, because it's missing\n\t// Object.prototype.constructor. Remove this eventually\n\n\n\tfunction isBuffer$2(obj) {\n\t  return obj != null && (!!obj._isBuffer || isFastBuffer$1(obj) || isSlowBuffer$1(obj));\n\t}\n\n\tfunction isFastBuffer$1(obj) {\n\t  return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);\n\t} // For Node v0.10 support. Remove this eventually.\n\n\n\tfunction isSlowBuffer$1(obj) {\n\t  return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer$1(obj.slice(0, 0));\n\t}\n\n\t// based off https://github.com/defunctzombie/node-process/blob/master/browser.js\n\n\tfunction defaultSetTimout() {\n\t  throw new Error('setTimeout has not been defined');\n\t}\n\n\tfunction defaultClearTimeout() {\n\t  throw new Error('clearTimeout has not been defined');\n\t}\n\n\tvar cachedSetTimeout = defaultSetTimout;\n\tvar cachedClearTimeout = defaultClearTimeout;\n\n\tif (typeof global$1.setTimeout === 'function') {\n\t  cachedSetTimeout = setTimeout;\n\t}\n\n\tif (typeof global$1.clearTimeout === 'function') {\n\t  cachedClearTimeout = clearTimeout;\n\t}\n\n\tfunction runTimeout(fun) {\n\t  if (cachedSetTimeout === setTimeout) {\n\t    //normal enviroments in sane situations\n\t    return setTimeout(fun, 0);\n\t  } // if setTimeout wasn't available but was latter defined\n\n\n\t  if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n\t    cachedSetTimeout = setTimeout;\n\t    return setTimeout(fun, 0);\n\t  }\n\n\t  try {\n\t    // when when somebody has screwed with setTimeout but no I.E. maddness\n\t    return cachedSetTimeout(fun, 0);\n\t  } catch (e) {\n\t    try {\n\t      // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n\t      return cachedSetTimeout.call(null, fun, 0);\n\t    } catch (e) {\n\t      // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n\t      return cachedSetTimeout.call(this, fun, 0);\n\t    }\n\t  }\n\t}\n\n\tfunction runClearTimeout(marker) {\n\t  if (cachedClearTimeout === clearTimeout) {\n\t    //normal enviroments in sane situations\n\t    return clearTimeout(marker);\n\t  } // if clearTimeout wasn't available but was latter defined\n\n\n\t  if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n\t    cachedClearTimeout = clearTimeout;\n\t    return clearTimeout(marker);\n\t  }\n\n\t  try {\n\t    // when when somebody has screwed with setTimeout but no I.E. maddness\n\t    return cachedClearTimeout(marker);\n\t  } catch (e) {\n\t    try {\n\t      // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally\n\t      return cachedClearTimeout.call(null, marker);\n\t    } catch (e) {\n\t      // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n\t      // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n\t      return cachedClearTimeout.call(this, marker);\n\t    }\n\t  }\n\t}\n\n\tvar queue$2 = [];\n\tvar draining = false;\n\tvar currentQueue;\n\tvar queueIndex = -1;\n\n\tfunction cleanUpNextTick() {\n\t  if (!draining || !currentQueue) {\n\t    return;\n\t  }\n\n\t  draining = false;\n\n\t  if (currentQueue.length) {\n\t    queue$2 = currentQueue.concat(queue$2);\n\t  } else {\n\t    queueIndex = -1;\n\t  }\n\n\t  if (queue$2.length) {\n\t    drainQueue();\n\t  }\n\t}\n\n\tfunction drainQueue() {\n\t  if (draining) {\n\t    return;\n\t  }\n\n\t  var timeout = runTimeout(cleanUpNextTick);\n\t  draining = true;\n\t  var len = queue$2.length;\n\n\t  while (len) {\n\t    currentQueue = queue$2;\n\t    queue$2 = [];\n\n\t    while (++queueIndex < len) {\n\t      if (currentQueue) {\n\t        currentQueue[queueIndex].run();\n\t      }\n\t    }\n\n\t    queueIndex = -1;\n\t    len = queue$2.length;\n\t  }\n\n\t  currentQueue = null;\n\t  draining = false;\n\t  runClearTimeout(timeout);\n\t}\n\n\tfunction nextTick(fun) {\n\t  var args = new Array(arguments.length - 1);\n\n\t  if (arguments.length > 1) {\n\t    for (var i = 1; i < arguments.length; i++) {\n\t      args[i - 1] = arguments[i];\n\t    }\n\t  }\n\n\t  queue$2.push(new Item(fun, args));\n\n\t  if (queue$2.length === 1 && !draining) {\n\t    runTimeout(drainQueue);\n\t  }\n\t} // v8 likes predictible objects\n\n\n\tfunction Item(fun, array) {\n\t  this.fun = fun;\n\t  this.array = array;\n\t}\n\n\tItem.prototype.run = function () {\n\t  this.fun.apply(null, this.array);\n\t};\n\n\tvar title = 'browser';\n\tvar platform = 'browser';\n\tvar browser$3 = true;\n\tvar env = {};\n\tvar argv = [];\n\tvar version$1 = ''; // empty string to avoid regexp issues\n\n\tvar versions = {};\n\tvar release = {};\n\tvar config = {};\n\n\tfunction noop() {}\n\n\tvar on = noop;\n\tvar addListener = noop;\n\tvar once = noop;\n\tvar off = noop;\n\tvar removeListener = noop;\n\tvar removeAllListeners = noop;\n\tvar emit = noop;\n\n\tfunction binding(name) {\n\t  throw new Error('process.binding is not supported');\n\t}\n\n\tfunction cwd() {\n\t  return '/';\n\t}\n\n\tfunction chdir(dir) {\n\t  throw new Error('process.chdir is not supported');\n\t}\n\n\tfunction umask() {\n\t  return 0;\n\t} // from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js\n\n\n\tvar performance = global$1.performance || {};\n\n\tvar performanceNow = performance.now || performance.mozNow || performance.msNow || performance.oNow || performance.webkitNow || function () {\n\t  return new Date().getTime();\n\t}; // generate timestamp or delta\n\t// see http://nodejs.org/api/process.html#process_process_hrtime\n\n\n\tfunction hrtime(previousTimestamp) {\n\t  var clocktime = performanceNow.call(performance) * 1e-3;\n\t  var seconds = Math.floor(clocktime);\n\t  var nanoseconds = Math.floor(clocktime % 1 * 1e9);\n\n\t  if (previousTimestamp) {\n\t    seconds = seconds - previousTimestamp[0];\n\t    nanoseconds = nanoseconds - previousTimestamp[1];\n\n\t    if (nanoseconds < 0) {\n\t      seconds--;\n\t      nanoseconds += 1e9;\n\t    }\n\t  }\n\n\t  return [seconds, nanoseconds];\n\t}\n\n\tvar startTime = new Date();\n\n\tfunction uptime() {\n\t  var currentTime = new Date();\n\t  var dif = currentTime - startTime;\n\t  return dif / 1000;\n\t}\n\n\tvar browser$1$1 = {\n\t  nextTick: nextTick,\n\t  title: title,\n\t  browser: browser$3,\n\t  env: env,\n\t  argv: argv,\n\t  version: version$1,\n\t  versions: versions,\n\t  on: on,\n\t  addListener: addListener,\n\t  once: once,\n\t  off: off,\n\t  removeListener: removeListener,\n\t  removeAllListeners: removeAllListeners,\n\t  emit: emit,\n\t  binding: binding,\n\t  cwd: cwd,\n\t  chdir: chdir,\n\t  umask: umask,\n\t  hrtime: hrtime,\n\t  platform: platform,\n\t  release: release,\n\t  config: config,\n\t  uptime: uptime\n\t};\n\tvar process$3 = browser$1$1;\n\n\tvar inherits$2;\n\n\tif (typeof Object.create === 'function') {\n\t  inherits$2 = function inherits(ctor, superCtor) {\n\t    // implementation from standard node.js 'util' module\n\t    ctor.super_ = superCtor;\n\t    ctor.prototype = Object.create(superCtor.prototype, {\n\t      constructor: {\n\t        value: ctor,\n\t        enumerable: false,\n\t        writable: true,\n\t        configurable: true\n\t      }\n\t    });\n\t  };\n\t} else {\n\t  inherits$2 = function inherits(ctor, superCtor) {\n\t    ctor.super_ = superCtor;\n\n\t    var TempCtor = function TempCtor() {};\n\n\t    TempCtor.prototype = superCtor.prototype;\n\t    ctor.prototype = new TempCtor();\n\t    ctor.prototype.constructor = ctor;\n\t  };\n\t}\n\n\tvar inherits$3 = inherits$2;\n\n\tvar formatRegExp = /%[sdj%]/g;\n\tfunction format$1(f) {\n\t  if (!isString$1(f)) {\n\t    var objects = [];\n\n\t    for (var i = 0; i < arguments.length; i++) {\n\t      objects.push(inspect(arguments[i]));\n\t    }\n\n\t    return objects.join(' ');\n\t  }\n\n\t  var i = 1;\n\t  var args = arguments;\n\t  var len = args.length;\n\t  var str = String(f).replace(formatRegExp, function (x) {\n\t    if (x === '%%') return '%';\n\t    if (i >= len) return x;\n\n\t    switch (x) {\n\t      case '%s':\n\t        return String(args[i++]);\n\n\t      case '%d':\n\t        return Number(args[i++]);\n\n\t      case '%j':\n\t        try {\n\t          return JSON.stringify(args[i++]);\n\t        } catch (_) {\n\t          return '[Circular]';\n\t        }\n\n\t      default:\n\t        return x;\n\t    }\n\t  });\n\n\t  for (var x = args[i]; i < len; x = args[++i]) {\n\t    if (isNull(x) || !isObject(x)) {\n\t      str += ' ' + x;\n\t    } else {\n\t      str += ' ' + inspect(x);\n\t    }\n\t  }\n\n\t  return str;\n\t}\n\t// Returns a modified function which warns once by default.\n\t// If --no-deprecation is set, then it is a no-op.\n\n\tfunction deprecate$1(fn, msg) {\n\t  // Allow for deprecating things in the process of starting up.\n\t  if (isUndefined(global$1.process)) {\n\t    return function () {\n\t      return deprecate$1(fn, msg).apply(this, arguments);\n\t    };\n\t  }\n\n\t  if (process$3.noDeprecation === true) {\n\t    return fn;\n\t  }\n\n\t  var warned = false;\n\n\t  function deprecated() {\n\t    if (!warned) {\n\t      if (process$3.throwDeprecation) {\n\t        throw new Error(msg);\n\t      } else if (process$3.traceDeprecation) {\n\t        console.trace(msg);\n\t      } else {\n\t        console.error(msg);\n\t      }\n\n\t      warned = true;\n\t    }\n\n\t    return fn.apply(this, arguments);\n\t  }\n\n\t  return deprecated;\n\t}\n\tvar debugs = {};\n\tvar debugEnviron;\n\tfunction debuglog(set) {\n\t  if (isUndefined(debugEnviron)) debugEnviron = process$3.env.NODE_DEBUG || '';\n\t  set = set.toUpperCase();\n\n\t  if (!debugs[set]) {\n\t    if (new RegExp('\\\\b' + set + '\\\\b', 'i').test(debugEnviron)) {\n\t      var pid = 0;\n\n\t      debugs[set] = function () {\n\t        var msg = format$1.apply(null, arguments);\n\t        console.error('%s %d: %s', set, pid, msg);\n\t      };\n\t    } else {\n\t      debugs[set] = function () {};\n\t    }\n\t  }\n\n\t  return debugs[set];\n\t}\n\t/**\n\t * Echos the value of a value. Trys to print the value out\n\t * in the best way possible given the different types.\n\t *\n\t * @param {Object} obj The object to print out.\n\t * @param {Object} opts Optional options object that alters the output.\n\t */\n\n\t/* legacy: obj, showHidden, depth, colors*/\n\n\tfunction inspect(obj, opts) {\n\t  // default options\n\t  var ctx = {\n\t    seen: [],\n\t    stylize: stylizeNoColor\n\t  }; // legacy...\n\n\t  if (arguments.length >= 3) ctx.depth = arguments[2];\n\t  if (arguments.length >= 4) ctx.colors = arguments[3];\n\n\t  if (isBoolean(opts)) {\n\t    // legacy...\n\t    ctx.showHidden = opts;\n\t  } else if (opts) {\n\t    // got an \"options\" object\n\t    _extend(ctx, opts);\n\t  } // set default options\n\n\n\t  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;\n\t  if (isUndefined(ctx.depth)) ctx.depth = 2;\n\t  if (isUndefined(ctx.colors)) ctx.colors = false;\n\t  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;\n\t  if (ctx.colors) ctx.stylize = stylizeWithColor;\n\t  return formatValue(ctx, obj, ctx.depth);\n\t} // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics\n\n\tinspect.colors = {\n\t  'bold': [1, 22],\n\t  'italic': [3, 23],\n\t  'underline': [4, 24],\n\t  'inverse': [7, 27],\n\t  'white': [37, 39],\n\t  'grey': [90, 39],\n\t  'black': [30, 39],\n\t  'blue': [34, 39],\n\t  'cyan': [36, 39],\n\t  'green': [32, 39],\n\t  'magenta': [35, 39],\n\t  'red': [31, 39],\n\t  'yellow': [33, 39]\n\t}; // Don't use 'blue' not visible on cmd.exe\n\n\tinspect.styles = {\n\t  'special': 'cyan',\n\t  'number': 'yellow',\n\t  'boolean': 'yellow',\n\t  'undefined': 'grey',\n\t  'null': 'bold',\n\t  'string': 'green',\n\t  'date': 'magenta',\n\t  // \"name\": intentionally not styling\n\t  'regexp': 'red'\n\t};\n\n\tfunction stylizeWithColor(str, styleType) {\n\t  var style = inspect.styles[styleType];\n\n\t  if (style) {\n\t    return \"\\x1B[\" + inspect.colors[style][0] + 'm' + str + \"\\x1B[\" + inspect.colors[style][1] + 'm';\n\t  } else {\n\t    return str;\n\t  }\n\t}\n\n\tfunction stylizeNoColor(str, styleType) {\n\t  return str;\n\t}\n\n\tfunction arrayToHash(array) {\n\t  var hash = {};\n\t  array.forEach(function (val, idx) {\n\t    hash[val] = true;\n\t  });\n\t  return hash;\n\t}\n\n\tfunction formatValue(ctx, value, recurseTimes) {\n\t  // Provide a hook for user-specified inspect functions.\n\t  // Check that value is an object with an inspect function on it\n\t  if (ctx.customInspect && value && isFunction(value.inspect) && // Filter out the util module, it's inspect function is special\n\t  value.inspect !== inspect && // Also filter out any prototype objects using the circular check.\n\t  !(value.constructor && value.constructor.prototype === value)) {\n\t    var ret = value.inspect(recurseTimes, ctx);\n\n\t    if (!isString$1(ret)) {\n\t      ret = formatValue(ctx, ret, recurseTimes);\n\t    }\n\n\t    return ret;\n\t  } // Primitive types cannot have properties\n\n\n\t  var primitive = formatPrimitive(ctx, value);\n\n\t  if (primitive) {\n\t    return primitive;\n\t  } // Look up the keys of the object.\n\n\n\t  var keys = Object.keys(value);\n\t  var visibleKeys = arrayToHash(keys);\n\n\t  if (ctx.showHidden) {\n\t    keys = Object.getOwnPropertyNames(value);\n\t  } // IE doesn't make error fields non-enumerable\n\t  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx\n\n\n\t  if (isError$1(value) && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {\n\t    return formatError(value);\n\t  } // Some type of object without properties can be shortcutted.\n\n\n\t  if (keys.length === 0) {\n\t    if (isFunction(value)) {\n\t      var name = value.name ? ': ' + value.name : '';\n\t      return ctx.stylize('[Function' + name + ']', 'special');\n\t    }\n\n\t    if (isRegExp(value)) {\n\t      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n\t    }\n\n\t    if (isDate(value)) {\n\t      return ctx.stylize(Date.prototype.toString.call(value), 'date');\n\t    }\n\n\t    if (isError$1(value)) {\n\t      return formatError(value);\n\t    }\n\t  }\n\n\t  var base = '',\n\t      array = false,\n\t      braces = ['{', '}']; // Make Array say that they are Array\n\n\t  if (isArray$1(value)) {\n\t    array = true;\n\t    braces = ['[', ']'];\n\t  } // Make functions say that they are functions\n\n\n\t  if (isFunction(value)) {\n\t    var n = value.name ? ': ' + value.name : '';\n\t    base = ' [Function' + n + ']';\n\t  } // Make RegExps say that they are RegExps\n\n\n\t  if (isRegExp(value)) {\n\t    base = ' ' + RegExp.prototype.toString.call(value);\n\t  } // Make dates with properties first say the date\n\n\n\t  if (isDate(value)) {\n\t    base = ' ' + Date.prototype.toUTCString.call(value);\n\t  } // Make error with message first say the error\n\n\n\t  if (isError$1(value)) {\n\t    base = ' ' + formatError(value);\n\t  }\n\n\t  if (keys.length === 0 && (!array || value.length == 0)) {\n\t    return braces[0] + base + braces[1];\n\t  }\n\n\t  if (recurseTimes < 0) {\n\t    if (isRegExp(value)) {\n\t      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n\t    } else {\n\t      return ctx.stylize('[Object]', 'special');\n\t    }\n\t  }\n\n\t  ctx.seen.push(value);\n\t  var output;\n\n\t  if (array) {\n\t    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);\n\t  } else {\n\t    output = keys.map(function (key) {\n\t      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);\n\t    });\n\t  }\n\n\t  ctx.seen.pop();\n\t  return reduceToSingleString(output, base, braces);\n\t}\n\n\tfunction formatPrimitive(ctx, value) {\n\t  if (isUndefined(value)) return ctx.stylize('undefined', 'undefined');\n\n\t  if (isString$1(value)) {\n\t    var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '').replace(/'/g, \"\\\\'\").replace(/\\\\\"/g, '\"') + '\\'';\n\t    return ctx.stylize(simple, 'string');\n\t  }\n\n\t  if (isNumber(value)) return ctx.stylize('' + value, 'number');\n\t  if (isBoolean(value)) return ctx.stylize('' + value, 'boolean'); // For some reason typeof null is \"object\", so special case here.\n\n\t  if (isNull(value)) return ctx.stylize('null', 'null');\n\t}\n\n\tfunction formatError(value) {\n\t  return '[' + Error.prototype.toString.call(value) + ']';\n\t}\n\n\tfunction formatArray(ctx, value, recurseTimes, visibleKeys, keys) {\n\t  var output = [];\n\n\t  for (var i = 0, l = value.length; i < l; ++i) {\n\t    if (hasOwnProperty(value, String(i))) {\n\t      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), true));\n\t    } else {\n\t      output.push('');\n\t    }\n\t  }\n\n\t  keys.forEach(function (key) {\n\t    if (!key.match(/^\\d+$/)) {\n\t      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key, true));\n\t    }\n\t  });\n\t  return output;\n\t}\n\n\tfunction formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {\n\t  var name, str, desc;\n\t  desc = Object.getOwnPropertyDescriptor(value, key) || {\n\t    value: value[key]\n\t  };\n\n\t  if (desc.get) {\n\t    if (desc.set) {\n\t      str = ctx.stylize('[Getter/Setter]', 'special');\n\t    } else {\n\t      str = ctx.stylize('[Getter]', 'special');\n\t    }\n\t  } else {\n\t    if (desc.set) {\n\t      str = ctx.stylize('[Setter]', 'special');\n\t    }\n\t  }\n\n\t  if (!hasOwnProperty(visibleKeys, key)) {\n\t    name = '[' + key + ']';\n\t  }\n\n\t  if (!str) {\n\t    if (ctx.seen.indexOf(desc.value) < 0) {\n\t      if (isNull(recurseTimes)) {\n\t        str = formatValue(ctx, desc.value, null);\n\t      } else {\n\t        str = formatValue(ctx, desc.value, recurseTimes - 1);\n\t      }\n\n\t      if (str.indexOf('\\n') > -1) {\n\t        if (array) {\n\t          str = str.split('\\n').map(function (line) {\n\t            return '  ' + line;\n\t          }).join('\\n').substr(2);\n\t        } else {\n\t          str = '\\n' + str.split('\\n').map(function (line) {\n\t            return '   ' + line;\n\t          }).join('\\n');\n\t        }\n\t      }\n\t    } else {\n\t      str = ctx.stylize('[Circular]', 'special');\n\t    }\n\t  }\n\n\t  if (isUndefined(name)) {\n\t    if (array && key.match(/^\\d+$/)) {\n\t      return str;\n\t    }\n\n\t    name = JSON.stringify('' + key);\n\n\t    if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n\t      name = name.substr(1, name.length - 2);\n\t      name = ctx.stylize(name, 'name');\n\t    } else {\n\t      name = name.replace(/'/g, \"\\\\'\").replace(/\\\\\"/g, '\"').replace(/(^\"|\"$)/g, \"'\");\n\t      name = ctx.stylize(name, 'string');\n\t    }\n\t  }\n\n\t  return name + ': ' + str;\n\t}\n\n\tfunction reduceToSingleString(output, base, braces) {\n\t  var length = output.reduce(function (prev, cur) {\n\t    if (cur.indexOf('\\n') >= 0) ;\n\t    return prev + cur.replace(/\\u001b\\[\\d\\d?m/g, '').length + 1;\n\t  }, 0);\n\n\t  if (length > 60) {\n\t    return braces[0] + (base === '' ? '' : base + '\\n ') + ' ' + output.join(',\\n  ') + ' ' + braces[1];\n\t  }\n\n\t  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n\t} // NOTE: These type checking functions intentionally don't use `instanceof`\n\t// because it is fragile and can be easily faked with `Object.create()`.\n\n\n\tfunction isArray$1(ar) {\n\t  return Array.isArray(ar);\n\t}\n\tfunction isBoolean(arg) {\n\t  return typeof arg === 'boolean';\n\t}\n\tfunction isNull(arg) {\n\t  return arg === null;\n\t}\n\tfunction isNullOrUndefined(arg) {\n\t  return arg == null;\n\t}\n\tfunction isNumber(arg) {\n\t  return typeof arg === 'number';\n\t}\n\tfunction isString$1(arg) {\n\t  return typeof arg === 'string';\n\t}\n\tfunction isSymbol(arg) {\n\t  return _typeof(arg) === 'symbol';\n\t}\n\tfunction isUndefined(arg) {\n\t  return arg === void 0;\n\t}\n\tfunction isRegExp(re) {\n\t  return isObject(re) && objectToString(re) === '[object RegExp]';\n\t}\n\tfunction isObject(arg) {\n\t  return _typeof(arg) === 'object' && arg !== null;\n\t}\n\tfunction isDate(d) {\n\t  return isObject(d) && objectToString(d) === '[object Date]';\n\t}\n\tfunction isError$1(e) {\n\t  return isObject(e) && (objectToString(e) === '[object Error]' || e instanceof Error);\n\t}\n\tfunction isFunction(arg) {\n\t  return typeof arg === 'function';\n\t}\n\tfunction isPrimitive(arg) {\n\t  return arg === null || typeof arg === 'boolean' || typeof arg === 'number' || typeof arg === 'string' || _typeof(arg) === 'symbol' || // ES6 symbol\n\t  typeof arg === 'undefined';\n\t}\n\tfunction isBuffer$1(maybeBuf) {\n\t  return isBuffer$2(maybeBuf);\n\t}\n\n\tfunction objectToString(o) {\n\t  return Object.prototype.toString.call(o);\n\t}\n\n\tfunction pad(n) {\n\t  return n < 10 ? '0' + n.toString(10) : n.toString(10);\n\t}\n\n\tvar months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // 26 Feb 16:19:34\n\n\tfunction timestamp() {\n\t  var d = new Date();\n\t  var time = [pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds())].join(':');\n\t  return [d.getDate(), months[d.getMonth()], time].join(' ');\n\t} // log is just a thin wrapper to console.log that prepends a timestamp\n\n\n\tfunction log$1() {\n\t  console.log('%s - %s', timestamp(), format$1.apply(null, arguments));\n\t}\n\tfunction _extend(origin, add) {\n\t  // Don't do anything if add isn't an object\n\t  if (!add || !isObject(add)) return origin;\n\t  var keys = Object.keys(add);\n\t  var i = keys.length;\n\n\t  while (i--) {\n\t    origin[keys[i]] = add[keys[i]];\n\t  }\n\n\t  return origin;\n\t}\n\n\tfunction hasOwnProperty(obj, prop) {\n\t  return Object.prototype.hasOwnProperty.call(obj, prop);\n\t}\n\n\tvar util = {\n\t  inherits: inherits$3,\n\t  _extend: _extend,\n\t  log: log$1,\n\t  isBuffer: isBuffer$1,\n\t  isPrimitive: isPrimitive,\n\t  isFunction: isFunction,\n\t  isError: isError$1,\n\t  isDate: isDate,\n\t  isObject: isObject,\n\t  isRegExp: isRegExp,\n\t  isUndefined: isUndefined,\n\t  isSymbol: isSymbol,\n\t  isString: isString$1,\n\t  isNumber: isNumber,\n\t  isNullOrUndefined: isNullOrUndefined,\n\t  isNull: isNull,\n\t  isBoolean: isBoolean,\n\t  isArray: isArray$1,\n\t  inspect: inspect,\n\t  deprecate: deprecate$1,\n\t  format: format$1,\n\t  debuglog: debuglog\n\t};\n\n\tvar lookup = [];\n\tvar revLookup = [];\n\tvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;\n\tvar inited = false;\n\n\tfunction init() {\n\t  inited = true;\n\t  var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n\t  for (var i = 0, len = code.length; i < len; ++i) {\n\t    lookup[i] = code[i];\n\t    revLookup[code.charCodeAt(i)] = i;\n\t  }\n\n\t  revLookup['-'.charCodeAt(0)] = 62;\n\t  revLookup['_'.charCodeAt(0)] = 63;\n\t}\n\n\tfunction toByteArray(b64) {\n\t  if (!inited) {\n\t    init();\n\t  }\n\n\t  var i, j, l, tmp, placeHolders, arr;\n\t  var len = b64.length;\n\n\t  if (len % 4 > 0) {\n\t    throw new Error('Invalid string. Length must be a multiple of 4');\n\t  } // the number of equal signs (place holders)\n\t  // if there are two placeholders, than the two characters before it\n\t  // represent one byte\n\t  // if there is only one, then the three characters before it represent 2 bytes\n\t  // this is just a cheap hack to not do indexOf twice\n\n\n\t  placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0; // base64 is 4/3 + up to two characters of the original data\n\n\t  arr = new Arr(len * 3 / 4 - placeHolders); // if there are placeholders, only get up to the last complete 4 chars\n\n\t  l = placeHolders > 0 ? len - 4 : len;\n\t  var L = 0;\n\n\t  for (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t    tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];\n\t    arr[L++] = tmp >> 16 & 0xFF;\n\t    arr[L++] = tmp >> 8 & 0xFF;\n\t    arr[L++] = tmp & 0xFF;\n\t  }\n\n\t  if (placeHolders === 2) {\n\t    tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;\n\t    arr[L++] = tmp & 0xFF;\n\t  } else if (placeHolders === 1) {\n\t    tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;\n\t    arr[L++] = tmp >> 8 & 0xFF;\n\t    arr[L++] = tmp & 0xFF;\n\t  }\n\n\t  return arr;\n\t}\n\n\tfunction tripletToBase64(num) {\n\t  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];\n\t}\n\n\tfunction encodeChunk(uint8, start, end) {\n\t  var tmp;\n\t  var output = [];\n\n\t  for (var i = start; i < end; i += 3) {\n\t    tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + uint8[i + 2];\n\t    output.push(tripletToBase64(tmp));\n\t  }\n\n\t  return output.join('');\n\t}\n\n\tfunction fromByteArray(uint8) {\n\t  if (!inited) {\n\t    init();\n\t  }\n\n\t  var tmp;\n\t  var len = uint8.length;\n\t  var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n\n\t  var output = '';\n\t  var parts = [];\n\t  var maxChunkLength = 16383; // must be multiple of 3\n\t  // go through the array every three bytes, we'll deal with trailing stuff later\n\n\t  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n\t    parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));\n\t  } // pad the end with zeros, but make sure to not forget the extra bytes\n\n\n\t  if (extraBytes === 1) {\n\t    tmp = uint8[len - 1];\n\t    output += lookup[tmp >> 2];\n\t    output += lookup[tmp << 4 & 0x3F];\n\t    output += '==';\n\t  } else if (extraBytes === 2) {\n\t    tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n\t    output += lookup[tmp >> 10];\n\t    output += lookup[tmp >> 4 & 0x3F];\n\t    output += lookup[tmp << 2 & 0x3F];\n\t    output += '=';\n\t  }\n\n\t  parts.push(output);\n\t  return parts.join('');\n\t}\n\n\tfunction read(buffer, offset, isLE, mLen, nBytes) {\n\t  var e, m;\n\t  var eLen = nBytes * 8 - mLen - 1;\n\t  var eMax = (1 << eLen) - 1;\n\t  var eBias = eMax >> 1;\n\t  var nBits = -7;\n\t  var i = isLE ? nBytes - 1 : 0;\n\t  var d = isLE ? -1 : 1;\n\t  var s = buffer[offset + i];\n\t  i += d;\n\t  e = s & (1 << -nBits) - 1;\n\t  s >>= -nBits;\n\t  nBits += eLen;\n\n\t  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n\t  m = e & (1 << -nBits) - 1;\n\t  e >>= -nBits;\n\t  nBits += mLen;\n\n\t  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n\t  if (e === 0) {\n\t    e = 1 - eBias;\n\t  } else if (e === eMax) {\n\t    return m ? NaN : (s ? -1 : 1) * Infinity;\n\t  } else {\n\t    m = m + Math.pow(2, mLen);\n\t    e = e - eBias;\n\t  }\n\n\t  return (s ? -1 : 1) * m * Math.pow(2, e - mLen);\n\t}\n\n\tfunction write(buffer, value, offset, isLE, mLen, nBytes) {\n\t  var e, m, c;\n\t  var eLen = nBytes * 8 - mLen - 1;\n\t  var eMax = (1 << eLen) - 1;\n\t  var eBias = eMax >> 1;\n\t  var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;\n\t  var i = isLE ? 0 : nBytes - 1;\n\t  var d = isLE ? 1 : -1;\n\t  var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;\n\t  value = Math.abs(value);\n\n\t  if (isNaN(value) || value === Infinity) {\n\t    m = isNaN(value) ? 1 : 0;\n\t    e = eMax;\n\t  } else {\n\t    e = Math.floor(Math.log(value) / Math.LN2);\n\n\t    if (value * (c = Math.pow(2, -e)) < 1) {\n\t      e--;\n\t      c *= 2;\n\t    }\n\n\t    if (e + eBias >= 1) {\n\t      value += rt / c;\n\t    } else {\n\t      value += rt * Math.pow(2, 1 - eBias);\n\t    }\n\n\t    if (value * c >= 2) {\n\t      e++;\n\t      c /= 2;\n\t    }\n\n\t    if (e + eBias >= eMax) {\n\t      m = 0;\n\t      e = eMax;\n\t    } else if (e + eBias >= 1) {\n\t      m = (value * c - 1) * Math.pow(2, mLen);\n\t      e = e + eBias;\n\t    } else {\n\t      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);\n\t      e = 0;\n\t    }\n\t  }\n\n\t  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n\t  e = e << mLen | m;\n\t  eLen += mLen;\n\n\t  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n\t  buffer[offset + i - d] |= s * 128;\n\t}\n\n\tvar toString$1 = {}.toString;\n\n\tvar isArray = Array.isArray || function (arr) {\n\t  return toString$1.call(arr) == '[object Array]';\n\t};\n\t/*!\n\t * The buffer module from node.js, for the browser.\n\t *\n\t * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n\t * @license  MIT\n\t */\n\n\n\tvar INSPECT_MAX_BYTES = 50;\n\t/**\n\t * If `Buffer.TYPED_ARRAY_SUPPORT`:\n\t *   === true    Use Uint8Array implementation (fastest)\n\t *   === false   Use Object implementation (most compatible, even IE6)\n\t *\n\t * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n\t * Opera 11.6+, iOS 4.2+.\n\t *\n\t * Due to various browser bugs, sometimes the Object implementation will be used even\n\t * when the browser supports typed arrays.\n\t *\n\t * Note:\n\t *\n\t *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n\t *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n\t *\n\t *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n\t *\n\t *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n\t *     incorrect length in some situations.\n\n\t * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n\t * get the Object implementation, which is slower but behaves correctly.\n\t */\n\n\tBuffer.TYPED_ARRAY_SUPPORT = global$1.TYPED_ARRAY_SUPPORT !== undefined ? global$1.TYPED_ARRAY_SUPPORT : true;\n\n\tfunction kMaxLength() {\n\t  return Buffer.TYPED_ARRAY_SUPPORT ? 0x7fffffff : 0x3fffffff;\n\t}\n\n\tfunction createBuffer(that, length) {\n\t  if (kMaxLength() < length) {\n\t    throw new RangeError('Invalid typed array length');\n\t  }\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    // Return an augmented `Uint8Array` instance, for best performance\n\t    that = new Uint8Array(length);\n\t    that.__proto__ = Buffer.prototype;\n\t  } else {\n\t    // Fallback: Return an object instance of the Buffer class\n\t    if (that === null) {\n\t      that = new Buffer(length);\n\t    }\n\n\t    that.length = length;\n\t  }\n\n\t  return that;\n\t}\n\t/**\n\t * The Buffer constructor returns instances of `Uint8Array` that have their\n\t * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n\t * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n\t * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n\t * returns a single octet.\n\t *\n\t * The `Uint8Array` prototype remains unmodified.\n\t */\n\n\n\tfunction Buffer(arg, encodingOrOffset, length) {\n\t  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n\t    return new Buffer(arg, encodingOrOffset, length);\n\t  } // Common case.\n\n\n\t  if (typeof arg === 'number') {\n\t    if (typeof encodingOrOffset === 'string') {\n\t      throw new Error('If encoding is specified then the first argument must be a string');\n\t    }\n\n\t    return allocUnsafe(this, arg);\n\t  }\n\n\t  return from(this, arg, encodingOrOffset, length);\n\t}\n\n\tBuffer.poolSize = 8192; // not used by this implementation\n\t// TODO: Legacy, not needed anymore. Remove in next major version.\n\n\tBuffer._augment = function (arr) {\n\t  arr.__proto__ = Buffer.prototype;\n\t  return arr;\n\t};\n\n\tfunction from(that, value, encodingOrOffset, length) {\n\t  if (typeof value === 'number') {\n\t    throw new TypeError('\"value\" argument must not be a number');\n\t  }\n\n\t  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n\t    return fromArrayBuffer(that, value, encodingOrOffset, length);\n\t  }\n\n\t  if (typeof value === 'string') {\n\t    return fromString(that, value, encodingOrOffset);\n\t  }\n\n\t  return fromObject(that, value);\n\t}\n\t/**\n\t * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n\t * if value is a number.\n\t * Buffer.from(str[, encoding])\n\t * Buffer.from(array)\n\t * Buffer.from(buffer)\n\t * Buffer.from(arrayBuffer[, byteOffset[, length]])\n\t **/\n\n\n\tBuffer.from = function (value, encodingOrOffset, length) {\n\t  return from(null, value, encodingOrOffset, length);\n\t};\n\n\tif (Buffer.TYPED_ARRAY_SUPPORT) {\n\t  Buffer.prototype.__proto__ = Uint8Array.prototype;\n\t  Buffer.__proto__ = Uint8Array;\n\t}\n\n\tfunction assertSize(size) {\n\t  if (typeof size !== 'number') {\n\t    throw new TypeError('\"size\" argument must be a number');\n\t  } else if (size < 0) {\n\t    throw new RangeError('\"size\" argument must not be negative');\n\t  }\n\t}\n\n\tfunction alloc(that, size, fill, encoding) {\n\t  assertSize(size);\n\n\t  if (size <= 0) {\n\t    return createBuffer(that, size);\n\t  }\n\n\t  if (fill !== undefined) {\n\t    // Only pay attention to encoding if it's a string. This\n\t    // prevents accidentally sending in a number that would\n\t    // be interpretted as a start offset.\n\t    return typeof encoding === 'string' ? createBuffer(that, size).fill(fill, encoding) : createBuffer(that, size).fill(fill);\n\t  }\n\n\t  return createBuffer(that, size);\n\t}\n\t/**\n\t * Creates a new filled Buffer instance.\n\t * alloc(size[, fill[, encoding]])\n\t **/\n\n\n\tBuffer.alloc = function (size, fill, encoding) {\n\t  return alloc(null, size, fill, encoding);\n\t};\n\n\tfunction allocUnsafe(that, size) {\n\t  assertSize(size);\n\t  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0);\n\n\t  if (!Buffer.TYPED_ARRAY_SUPPORT) {\n\t    for (var i = 0; i < size; ++i) {\n\t      that[i] = 0;\n\t    }\n\t  }\n\n\t  return that;\n\t}\n\t/**\n\t * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n\t * */\n\n\n\tBuffer.allocUnsafe = function (size) {\n\t  return allocUnsafe(null, size);\n\t};\n\t/**\n\t * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n\t */\n\n\n\tBuffer.allocUnsafeSlow = function (size) {\n\t  return allocUnsafe(null, size);\n\t};\n\n\tfunction fromString(that, string, encoding) {\n\t  if (typeof encoding !== 'string' || encoding === '') {\n\t    encoding = 'utf8';\n\t  }\n\n\t  if (!Buffer.isEncoding(encoding)) {\n\t    throw new TypeError('\"encoding\" must be a valid string encoding');\n\t  }\n\n\t  var length = byteLength(string, encoding) | 0;\n\t  that = createBuffer(that, length);\n\t  var actual = that.write(string, encoding);\n\n\t  if (actual !== length) {\n\t    // Writing a hex string, for example, that contains invalid characters will\n\t    // cause everything after the first invalid character to be ignored. (e.g.\n\t    // 'abxxcd' will be treated as 'ab')\n\t    that = that.slice(0, actual);\n\t  }\n\n\t  return that;\n\t}\n\n\tfunction fromArrayLike(that, array) {\n\t  var length = array.length < 0 ? 0 : checked(array.length) | 0;\n\t  that = createBuffer(that, length);\n\n\t  for (var i = 0; i < length; i += 1) {\n\t    that[i] = array[i] & 255;\n\t  }\n\n\t  return that;\n\t}\n\n\tfunction fromArrayBuffer(that, array, byteOffset, length) {\n\t  array.byteLength; // this throws if `array` is not a valid ArrayBuffer\n\n\t  if (byteOffset < 0 || array.byteLength < byteOffset) {\n\t    throw new RangeError('\\'offset\\' is out of bounds');\n\t  }\n\n\t  if (array.byteLength < byteOffset + (length || 0)) {\n\t    throw new RangeError('\\'length\\' is out of bounds');\n\t  }\n\n\t  if (byteOffset === undefined && length === undefined) {\n\t    array = new Uint8Array(array);\n\t  } else if (length === undefined) {\n\t    array = new Uint8Array(array, byteOffset);\n\t  } else {\n\t    array = new Uint8Array(array, byteOffset, length);\n\t  }\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    // Return an augmented `Uint8Array` instance, for best performance\n\t    that = array;\n\t    that.__proto__ = Buffer.prototype;\n\t  } else {\n\t    // Fallback: Return an object instance of the Buffer class\n\t    that = fromArrayLike(that, array);\n\t  }\n\n\t  return that;\n\t}\n\n\tfunction fromObject(that, obj) {\n\t  if (internalIsBuffer(obj)) {\n\t    var len = checked(obj.length) | 0;\n\t    that = createBuffer(that, len);\n\n\t    if (that.length === 0) {\n\t      return that;\n\t    }\n\n\t    obj.copy(that, 0, 0, len);\n\t    return that;\n\t  }\n\n\t  if (obj) {\n\t    if (typeof ArrayBuffer !== 'undefined' && obj.buffer instanceof ArrayBuffer || 'length' in obj) {\n\t      if (typeof obj.length !== 'number' || isnan(obj.length)) {\n\t        return createBuffer(that, 0);\n\t      }\n\n\t      return fromArrayLike(that, obj);\n\t    }\n\n\t    if (obj.type === 'Buffer' && isArray(obj.data)) {\n\t      return fromArrayLike(that, obj.data);\n\t    }\n\t  }\n\n\t  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.');\n\t}\n\n\tfunction checked(length) {\n\t  // Note: cannot use `length < kMaxLength()` here because that fails when\n\t  // length is NaN (which is otherwise coerced to zero.)\n\t  if (length >= kMaxLength()) {\n\t    throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + kMaxLength().toString(16) + ' bytes');\n\t  }\n\n\t  return length | 0;\n\t}\n\n\tBuffer.isBuffer = isBuffer;\n\n\tfunction internalIsBuffer(b) {\n\t  return !!(b != null && b._isBuffer);\n\t}\n\n\tBuffer.compare = function compare(a, b) {\n\t  if (!internalIsBuffer(a) || !internalIsBuffer(b)) {\n\t    throw new TypeError('Arguments must be Buffers');\n\t  }\n\n\t  if (a === b) return 0;\n\t  var x = a.length;\n\t  var y = b.length;\n\n\t  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n\t    if (a[i] !== b[i]) {\n\t      x = a[i];\n\t      y = b[i];\n\t      break;\n\t    }\n\t  }\n\n\t  if (x < y) return -1;\n\t  if (y < x) return 1;\n\t  return 0;\n\t};\n\n\tBuffer.isEncoding = function isEncoding(encoding) {\n\t  switch (String(encoding).toLowerCase()) {\n\t    case 'hex':\n\t    case 'utf8':\n\t    case 'utf-8':\n\t    case 'ascii':\n\t    case 'latin1':\n\t    case 'binary':\n\t    case 'base64':\n\t    case 'ucs2':\n\t    case 'ucs-2':\n\t    case 'utf16le':\n\t    case 'utf-16le':\n\t      return true;\n\n\t    default:\n\t      return false;\n\t  }\n\t};\n\n\tBuffer.concat = function concat(list, length) {\n\t  if (!isArray(list)) {\n\t    throw new TypeError('\"list\" argument must be an Array of Buffers');\n\t  }\n\n\t  if (list.length === 0) {\n\t    return Buffer.alloc(0);\n\t  }\n\n\t  var i;\n\n\t  if (length === undefined) {\n\t    length = 0;\n\n\t    for (i = 0; i < list.length; ++i) {\n\t      length += list[i].length;\n\t    }\n\t  }\n\n\t  var buffer = Buffer.allocUnsafe(length);\n\t  var pos = 0;\n\n\t  for (i = 0; i < list.length; ++i) {\n\t    var buf = list[i];\n\n\t    if (!internalIsBuffer(buf)) {\n\t      throw new TypeError('\"list\" argument must be an Array of Buffers');\n\t    }\n\n\t    buf.copy(buffer, pos);\n\t    pos += buf.length;\n\t  }\n\n\t  return buffer;\n\t};\n\n\tfunction byteLength(string, encoding) {\n\t  if (internalIsBuffer(string)) {\n\t    return string.length;\n\t  }\n\n\t  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n\t    return string.byteLength;\n\t  }\n\n\t  if (typeof string !== 'string') {\n\t    string = '' + string;\n\t  }\n\n\t  var len = string.length;\n\t  if (len === 0) return 0; // Use a for loop to avoid recursion\n\n\t  var loweredCase = false;\n\n\t  for (;;) {\n\t    switch (encoding) {\n\t      case 'ascii':\n\t      case 'latin1':\n\t      case 'binary':\n\t        return len;\n\n\t      case 'utf8':\n\t      case 'utf-8':\n\t      case undefined:\n\t        return utf8ToBytes(string).length;\n\n\t      case 'ucs2':\n\t      case 'ucs-2':\n\t      case 'utf16le':\n\t      case 'utf-16le':\n\t        return len * 2;\n\n\t      case 'hex':\n\t        return len >>> 1;\n\n\t      case 'base64':\n\t        return base64ToBytes(string).length;\n\n\t      default:\n\t        if (loweredCase) return utf8ToBytes(string).length; // assume utf8\n\n\t        encoding = ('' + encoding).toLowerCase();\n\t        loweredCase = true;\n\t    }\n\t  }\n\t}\n\n\tBuffer.byteLength = byteLength;\n\n\tfunction slowToString(encoding, start, end) {\n\t  var loweredCase = false; // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n\t  // property of a typed array.\n\t  // This behaves neither like String nor Uint8Array in that we set start/end\n\t  // to their upper/lower bounds if the value passed is out of range.\n\t  // undefined is handled specially as per ECMA-262 6th Edition,\n\t  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n\n\t  if (start === undefined || start < 0) {\n\t    start = 0;\n\t  } // Return early if start > this.length. Done here to prevent potential uint32\n\t  // coercion fail below.\n\n\n\t  if (start > this.length) {\n\t    return '';\n\t  }\n\n\t  if (end === undefined || end > this.length) {\n\t    end = this.length;\n\t  }\n\n\t  if (end <= 0) {\n\t    return '';\n\t  } // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n\n\n\t  end >>>= 0;\n\t  start >>>= 0;\n\n\t  if (end <= start) {\n\t    return '';\n\t  }\n\n\t  if (!encoding) encoding = 'utf8';\n\n\t  while (true) {\n\t    switch (encoding) {\n\t      case 'hex':\n\t        return hexSlice(this, start, end);\n\n\t      case 'utf8':\n\t      case 'utf-8':\n\t        return utf8Slice(this, start, end);\n\n\t      case 'ascii':\n\t        return asciiSlice(this, start, end);\n\n\t      case 'latin1':\n\t      case 'binary':\n\t        return latin1Slice(this, start, end);\n\n\t      case 'base64':\n\t        return base64Slice(this, start, end);\n\n\t      case 'ucs2':\n\t      case 'ucs-2':\n\t      case 'utf16le':\n\t      case 'utf-16le':\n\t        return utf16leSlice(this, start, end);\n\n\t      default:\n\t        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);\n\t        encoding = (encoding + '').toLowerCase();\n\t        loweredCase = true;\n\t    }\n\t  }\n\t} // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n\t// Buffer instances.\n\n\n\tBuffer.prototype._isBuffer = true;\n\n\tfunction swap(b, n, m) {\n\t  var i = b[n];\n\t  b[n] = b[m];\n\t  b[m] = i;\n\t}\n\n\tBuffer.prototype.swap16 = function swap16() {\n\t  var len = this.length;\n\n\t  if (len % 2 !== 0) {\n\t    throw new RangeError('Buffer size must be a multiple of 16-bits');\n\t  }\n\n\t  for (var i = 0; i < len; i += 2) {\n\t    swap(this, i, i + 1);\n\t  }\n\n\t  return this;\n\t};\n\n\tBuffer.prototype.swap32 = function swap32() {\n\t  var len = this.length;\n\n\t  if (len % 4 !== 0) {\n\t    throw new RangeError('Buffer size must be a multiple of 32-bits');\n\t  }\n\n\t  for (var i = 0; i < len; i += 4) {\n\t    swap(this, i, i + 3);\n\t    swap(this, i + 1, i + 2);\n\t  }\n\n\t  return this;\n\t};\n\n\tBuffer.prototype.swap64 = function swap64() {\n\t  var len = this.length;\n\n\t  if (len % 8 !== 0) {\n\t    throw new RangeError('Buffer size must be a multiple of 64-bits');\n\t  }\n\n\t  for (var i = 0; i < len; i += 8) {\n\t    swap(this, i, i + 7);\n\t    swap(this, i + 1, i + 6);\n\t    swap(this, i + 2, i + 5);\n\t    swap(this, i + 3, i + 4);\n\t  }\n\n\t  return this;\n\t};\n\n\tBuffer.prototype.toString = function toString() {\n\t  var length = this.length | 0;\n\t  if (length === 0) return '';\n\t  if (arguments.length === 0) return utf8Slice(this, 0, length);\n\t  return slowToString.apply(this, arguments);\n\t};\n\n\tBuffer.prototype.equals = function equals(b) {\n\t  if (!internalIsBuffer(b)) throw new TypeError('Argument must be a Buffer');\n\t  if (this === b) return true;\n\t  return Buffer.compare(this, b) === 0;\n\t};\n\n\tBuffer.prototype.inspect = function inspect() {\n\t  var str = '';\n\t  var max = INSPECT_MAX_BYTES;\n\n\t  if (this.length > 0) {\n\t    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');\n\t    if (this.length > max) str += ' ... ';\n\t  }\n\n\t  return '<Buffer ' + str + '>';\n\t};\n\n\tBuffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) {\n\t  if (!internalIsBuffer(target)) {\n\t    throw new TypeError('Argument must be a Buffer');\n\t  }\n\n\t  if (start === undefined) {\n\t    start = 0;\n\t  }\n\n\t  if (end === undefined) {\n\t    end = target ? target.length : 0;\n\t  }\n\n\t  if (thisStart === undefined) {\n\t    thisStart = 0;\n\t  }\n\n\t  if (thisEnd === undefined) {\n\t    thisEnd = this.length;\n\t  }\n\n\t  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n\t    throw new RangeError('out of range index');\n\t  }\n\n\t  if (thisStart >= thisEnd && start >= end) {\n\t    return 0;\n\t  }\n\n\t  if (thisStart >= thisEnd) {\n\t    return -1;\n\t  }\n\n\t  if (start >= end) {\n\t    return 1;\n\t  }\n\n\t  start >>>= 0;\n\t  end >>>= 0;\n\t  thisStart >>>= 0;\n\t  thisEnd >>>= 0;\n\t  if (this === target) return 0;\n\t  var x = thisEnd - thisStart;\n\t  var y = end - start;\n\t  var len = Math.min(x, y);\n\t  var thisCopy = this.slice(thisStart, thisEnd);\n\t  var targetCopy = target.slice(start, end);\n\n\t  for (var i = 0; i < len; ++i) {\n\t    if (thisCopy[i] !== targetCopy[i]) {\n\t      x = thisCopy[i];\n\t      y = targetCopy[i];\n\t      break;\n\t    }\n\t  }\n\n\t  if (x < y) return -1;\n\t  if (y < x) return 1;\n\t  return 0;\n\t}; // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n\t// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n\t//\n\t// Arguments:\n\t// - buffer - a Buffer to search\n\t// - val - a string, Buffer, or number\n\t// - byteOffset - an index into `buffer`; will be clamped to an int32\n\t// - encoding - an optional encoding, relevant is val is a string\n\t// - dir - true for indexOf, false for lastIndexOf\n\n\n\tfunction bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {\n\t  // Empty buffer means no match\n\t  if (buffer.length === 0) return -1; // Normalize byteOffset\n\n\t  if (typeof byteOffset === 'string') {\n\t    encoding = byteOffset;\n\t    byteOffset = 0;\n\t  } else if (byteOffset > 0x7fffffff) {\n\t    byteOffset = 0x7fffffff;\n\t  } else if (byteOffset < -0x80000000) {\n\t    byteOffset = -0x80000000;\n\t  }\n\n\t  byteOffset = +byteOffset; // Coerce to Number.\n\n\t  if (isNaN(byteOffset)) {\n\t    // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n\t    byteOffset = dir ? 0 : buffer.length - 1;\n\t  } // Normalize byteOffset: negative offsets start from the end of the buffer\n\n\n\t  if (byteOffset < 0) byteOffset = buffer.length + byteOffset;\n\n\t  if (byteOffset >= buffer.length) {\n\t    if (dir) return -1;else byteOffset = buffer.length - 1;\n\t  } else if (byteOffset < 0) {\n\t    if (dir) byteOffset = 0;else return -1;\n\t  } // Normalize val\n\n\n\t  if (typeof val === 'string') {\n\t    val = Buffer.from(val, encoding);\n\t  } // Finally, search either indexOf (if dir is true) or lastIndexOf\n\n\n\t  if (internalIsBuffer(val)) {\n\t    // Special case: looking for empty string/buffer always fails\n\t    if (val.length === 0) {\n\t      return -1;\n\t    }\n\n\t    return arrayIndexOf(buffer, val, byteOffset, encoding, dir);\n\t  } else if (typeof val === 'number') {\n\t    val = val & 0xFF; // Search for a byte value [0-255]\n\n\t    if (Buffer.TYPED_ARRAY_SUPPORT && typeof Uint8Array.prototype.indexOf === 'function') {\n\t      if (dir) {\n\t        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset);\n\t      } else {\n\t        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset);\n\t      }\n\t    }\n\n\t    return arrayIndexOf(buffer, [val], byteOffset, encoding, dir);\n\t  }\n\n\t  throw new TypeError('val must be string, number or Buffer');\n\t}\n\n\tfunction arrayIndexOf(arr, val, byteOffset, encoding, dir) {\n\t  var indexSize = 1;\n\t  var arrLength = arr.length;\n\t  var valLength = val.length;\n\n\t  if (encoding !== undefined) {\n\t    encoding = String(encoding).toLowerCase();\n\n\t    if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') {\n\t      if (arr.length < 2 || val.length < 2) {\n\t        return -1;\n\t      }\n\n\t      indexSize = 2;\n\t      arrLength /= 2;\n\t      valLength /= 2;\n\t      byteOffset /= 2;\n\t    }\n\t  }\n\n\t  function read(buf, i) {\n\t    if (indexSize === 1) {\n\t      return buf[i];\n\t    } else {\n\t      return buf.readUInt16BE(i * indexSize);\n\t    }\n\t  }\n\n\t  var i;\n\n\t  if (dir) {\n\t    var foundIndex = -1;\n\n\t    for (i = byteOffset; i < arrLength; i++) {\n\t      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n\t        if (foundIndex === -1) foundIndex = i;\n\t        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize;\n\t      } else {\n\t        if (foundIndex !== -1) i -= i - foundIndex;\n\t        foundIndex = -1;\n\t      }\n\t    }\n\t  } else {\n\t    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;\n\n\t    for (i = byteOffset; i >= 0; i--) {\n\t      var found = true;\n\n\t      for (var j = 0; j < valLength; j++) {\n\t        if (read(arr, i + j) !== read(val, j)) {\n\t          found = false;\n\t          break;\n\t        }\n\t      }\n\n\t      if (found) return i;\n\t    }\n\t  }\n\n\t  return -1;\n\t}\n\n\tBuffer.prototype.includes = function includes(val, byteOffset, encoding) {\n\t  return this.indexOf(val, byteOffset, encoding) !== -1;\n\t};\n\n\tBuffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {\n\t  return bidirectionalIndexOf(this, val, byteOffset, encoding, true);\n\t};\n\n\tBuffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {\n\t  return bidirectionalIndexOf(this, val, byteOffset, encoding, false);\n\t};\n\n\tfunction hexWrite(buf, string, offset, length) {\n\t  offset = Number(offset) || 0;\n\t  var remaining = buf.length - offset;\n\n\t  if (!length) {\n\t    length = remaining;\n\t  } else {\n\t    length = Number(length);\n\n\t    if (length > remaining) {\n\t      length = remaining;\n\t    }\n\t  } // must be an even number of digits\n\n\n\t  var strLen = string.length;\n\t  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string');\n\n\t  if (length > strLen / 2) {\n\t    length = strLen / 2;\n\t  }\n\n\t  for (var i = 0; i < length; ++i) {\n\t    var parsed = parseInt(string.substr(i * 2, 2), 16);\n\t    if (isNaN(parsed)) return i;\n\t    buf[offset + i] = parsed;\n\t  }\n\n\t  return i;\n\t}\n\n\tfunction utf8Write(buf, string, offset, length) {\n\t  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length);\n\t}\n\n\tfunction asciiWrite(buf, string, offset, length) {\n\t  return blitBuffer(asciiToBytes(string), buf, offset, length);\n\t}\n\n\tfunction latin1Write(buf, string, offset, length) {\n\t  return asciiWrite(buf, string, offset, length);\n\t}\n\n\tfunction base64Write(buf, string, offset, length) {\n\t  return blitBuffer(base64ToBytes(string), buf, offset, length);\n\t}\n\n\tfunction ucs2Write(buf, string, offset, length) {\n\t  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length);\n\t}\n\n\tBuffer.prototype.write = function write(string, offset, length, encoding) {\n\t  // Buffer#write(string)\n\t  if (offset === undefined) {\n\t    encoding = 'utf8';\n\t    length = this.length;\n\t    offset = 0; // Buffer#write(string, encoding)\n\t  } else if (length === undefined && typeof offset === 'string') {\n\t    encoding = offset;\n\t    length = this.length;\n\t    offset = 0; // Buffer#write(string, offset[, length][, encoding])\n\t  } else if (isFinite(offset)) {\n\t    offset = offset | 0;\n\n\t    if (isFinite(length)) {\n\t      length = length | 0;\n\t      if (encoding === undefined) encoding = 'utf8';\n\t    } else {\n\t      encoding = length;\n\t      length = undefined;\n\t    } // legacy write(string, encoding, offset, length) - remove in v0.13\n\n\t  } else {\n\t    throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported');\n\t  }\n\n\t  var remaining = this.length - offset;\n\t  if (length === undefined || length > remaining) length = remaining;\n\n\t  if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) {\n\t    throw new RangeError('Attempt to write outside buffer bounds');\n\t  }\n\n\t  if (!encoding) encoding = 'utf8';\n\t  var loweredCase = false;\n\n\t  for (;;) {\n\t    switch (encoding) {\n\t      case 'hex':\n\t        return hexWrite(this, string, offset, length);\n\n\t      case 'utf8':\n\t      case 'utf-8':\n\t        return utf8Write(this, string, offset, length);\n\n\t      case 'ascii':\n\t        return asciiWrite(this, string, offset, length);\n\n\t      case 'latin1':\n\t      case 'binary':\n\t        return latin1Write(this, string, offset, length);\n\n\t      case 'base64':\n\t        // Warning: maxLength not taken into account in base64Write\n\t        return base64Write(this, string, offset, length);\n\n\t      case 'ucs2':\n\t      case 'ucs-2':\n\t      case 'utf16le':\n\t      case 'utf-16le':\n\t        return ucs2Write(this, string, offset, length);\n\n\t      default:\n\t        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);\n\t        encoding = ('' + encoding).toLowerCase();\n\t        loweredCase = true;\n\t    }\n\t  }\n\t};\n\n\tBuffer.prototype.toJSON = function toJSON() {\n\t  return {\n\t    type: 'Buffer',\n\t    data: Array.prototype.slice.call(this._arr || this, 0)\n\t  };\n\t};\n\n\tfunction base64Slice(buf, start, end) {\n\t  if (start === 0 && end === buf.length) {\n\t    return fromByteArray(buf);\n\t  } else {\n\t    return fromByteArray(buf.slice(start, end));\n\t  }\n\t}\n\n\tfunction utf8Slice(buf, start, end) {\n\t  end = Math.min(buf.length, end);\n\t  var res = [];\n\t  var i = start;\n\n\t  while (i < end) {\n\t    var firstByte = buf[i];\n\t    var codePoint = null;\n\t    var bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1;\n\n\t    if (i + bytesPerSequence <= end) {\n\t      var secondByte, thirdByte, fourthByte, tempCodePoint;\n\n\t      switch (bytesPerSequence) {\n\t        case 1:\n\t          if (firstByte < 0x80) {\n\t            codePoint = firstByte;\n\t          }\n\n\t          break;\n\n\t        case 2:\n\t          secondByte = buf[i + 1];\n\n\t          if ((secondByte & 0xC0) === 0x80) {\n\t            tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F;\n\n\t            if (tempCodePoint > 0x7F) {\n\t              codePoint = tempCodePoint;\n\t            }\n\t          }\n\n\t          break;\n\n\t        case 3:\n\t          secondByte = buf[i + 1];\n\t          thirdByte = buf[i + 2];\n\n\t          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n\t            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F;\n\n\t            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n\t              codePoint = tempCodePoint;\n\t            }\n\t          }\n\n\t          break;\n\n\t        case 4:\n\t          secondByte = buf[i + 1];\n\t          thirdByte = buf[i + 2];\n\t          fourthByte = buf[i + 3];\n\n\t          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n\t            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F;\n\n\t            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n\t              codePoint = tempCodePoint;\n\t            }\n\t          }\n\n\t      }\n\t    }\n\n\t    if (codePoint === null) {\n\t      // we did not generate a valid codePoint so insert a\n\t      // replacement char (U+FFFD) and advance only 1 byte\n\t      codePoint = 0xFFFD;\n\t      bytesPerSequence = 1;\n\t    } else if (codePoint > 0xFFFF) {\n\t      // encode to utf16 (surrogate pair dance)\n\t      codePoint -= 0x10000;\n\t      res.push(codePoint >>> 10 & 0x3FF | 0xD800);\n\t      codePoint = 0xDC00 | codePoint & 0x3FF;\n\t    }\n\n\t    res.push(codePoint);\n\t    i += bytesPerSequence;\n\t  }\n\n\t  return decodeCodePointsArray(res);\n\t} // Based on http://stackoverflow.com/a/22747272/680742, the browser with\n\t// the lowest limit is Chrome, with 0x10000 args.\n\t// We go 1 magnitude less, for safety\n\n\n\tvar MAX_ARGUMENTS_LENGTH = 0x1000;\n\n\tfunction decodeCodePointsArray(codePoints) {\n\t  var len = codePoints.length;\n\n\t  if (len <= MAX_ARGUMENTS_LENGTH) {\n\t    return String.fromCharCode.apply(String, codePoints); // avoid extra slice()\n\t  } // Decode in chunks to avoid \"call stack size exceeded\".\n\n\n\t  var res = '';\n\t  var i = 0;\n\n\t  while (i < len) {\n\t    res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH));\n\t  }\n\n\t  return res;\n\t}\n\n\tfunction asciiSlice(buf, start, end) {\n\t  var ret = '';\n\t  end = Math.min(buf.length, end);\n\n\t  for (var i = start; i < end; ++i) {\n\t    ret += String.fromCharCode(buf[i] & 0x7F);\n\t  }\n\n\t  return ret;\n\t}\n\n\tfunction latin1Slice(buf, start, end) {\n\t  var ret = '';\n\t  end = Math.min(buf.length, end);\n\n\t  for (var i = start; i < end; ++i) {\n\t    ret += String.fromCharCode(buf[i]);\n\t  }\n\n\t  return ret;\n\t}\n\n\tfunction hexSlice(buf, start, end) {\n\t  var len = buf.length;\n\t  if (!start || start < 0) start = 0;\n\t  if (!end || end < 0 || end > len) end = len;\n\t  var out = '';\n\n\t  for (var i = start; i < end; ++i) {\n\t    out += toHex(buf[i]);\n\t  }\n\n\t  return out;\n\t}\n\n\tfunction utf16leSlice(buf, start, end) {\n\t  var bytes = buf.slice(start, end);\n\t  var res = '';\n\n\t  for (var i = 0; i < bytes.length; i += 2) {\n\t    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);\n\t  }\n\n\t  return res;\n\t}\n\n\tBuffer.prototype.slice = function slice(start, end) {\n\t  var len = this.length;\n\t  start = ~~start;\n\t  end = end === undefined ? len : ~~end;\n\n\t  if (start < 0) {\n\t    start += len;\n\t    if (start < 0) start = 0;\n\t  } else if (start > len) {\n\t    start = len;\n\t  }\n\n\t  if (end < 0) {\n\t    end += len;\n\t    if (end < 0) end = 0;\n\t  } else if (end > len) {\n\t    end = len;\n\t  }\n\n\t  if (end < start) end = start;\n\t  var newBuf;\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    newBuf = this.subarray(start, end);\n\t    newBuf.__proto__ = Buffer.prototype;\n\t  } else {\n\t    var sliceLen = end - start;\n\t    newBuf = new Buffer(sliceLen, undefined);\n\n\t    for (var i = 0; i < sliceLen; ++i) {\n\t      newBuf[i] = this[i + start];\n\t    }\n\t  }\n\n\t  return newBuf;\n\t};\n\t/*\n\t * Need to make sure that buffer isn't trying to write out of bounds.\n\t */\n\n\n\tfunction checkOffset(offset, ext, length) {\n\t  if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint');\n\t  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length');\n\t}\n\n\tBuffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\t  if (!noAssert) checkOffset(offset, byteLength, this.length);\n\t  var val = this[offset];\n\t  var mul = 1;\n\t  var i = 0;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    val += this[offset + i] * mul;\n\t  }\n\n\t  return val;\n\t};\n\n\tBuffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\n\t  if (!noAssert) {\n\t    checkOffset(offset, byteLength, this.length);\n\t  }\n\n\t  var val = this[offset + --byteLength];\n\t  var mul = 1;\n\n\t  while (byteLength > 0 && (mul *= 0x100)) {\n\t    val += this[offset + --byteLength] * mul;\n\t  }\n\n\t  return val;\n\t};\n\n\tBuffer.prototype.readUInt8 = function readUInt8(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 1, this.length);\n\t  return this[offset];\n\t};\n\n\tBuffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 2, this.length);\n\t  return this[offset] | this[offset + 1] << 8;\n\t};\n\n\tBuffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 2, this.length);\n\t  return this[offset] << 8 | this[offset + 1];\n\t};\n\n\tBuffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 4, this.length);\n\t  return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 0x1000000;\n\t};\n\n\tBuffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 4, this.length);\n\t  return this[offset] * 0x1000000 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]);\n\t};\n\n\tBuffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\t  if (!noAssert) checkOffset(offset, byteLength, this.length);\n\t  var val = this[offset];\n\t  var mul = 1;\n\t  var i = 0;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    val += this[offset + i] * mul;\n\t  }\n\n\t  mul *= 0x80;\n\t  if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n\t  return val;\n\t};\n\n\tBuffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) {\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\t  if (!noAssert) checkOffset(offset, byteLength, this.length);\n\t  var i = byteLength;\n\t  var mul = 1;\n\t  var val = this[offset + --i];\n\n\t  while (i > 0 && (mul *= 0x100)) {\n\t    val += this[offset + --i] * mul;\n\t  }\n\n\t  mul *= 0x80;\n\t  if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n\t  return val;\n\t};\n\n\tBuffer.prototype.readInt8 = function readInt8(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 1, this.length);\n\t  if (!(this[offset] & 0x80)) return this[offset];\n\t  return (0xff - this[offset] + 1) * -1;\n\t};\n\n\tBuffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 2, this.length);\n\t  var val = this[offset] | this[offset + 1] << 8;\n\t  return val & 0x8000 ? val | 0xFFFF0000 : val;\n\t};\n\n\tBuffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 2, this.length);\n\t  var val = this[offset + 1] | this[offset] << 8;\n\t  return val & 0x8000 ? val | 0xFFFF0000 : val;\n\t};\n\n\tBuffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 4, this.length);\n\t  return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24;\n\t};\n\n\tBuffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 4, this.length);\n\t  return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3];\n\t};\n\n\tBuffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 4, this.length);\n\t  return read(this, offset, true, 23, 4);\n\t};\n\n\tBuffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 4, this.length);\n\t  return read(this, offset, false, 23, 4);\n\t};\n\n\tBuffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 8, this.length);\n\t  return read(this, offset, true, 52, 8);\n\t};\n\n\tBuffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {\n\t  if (!noAssert) checkOffset(offset, 8, this.length);\n\t  return read(this, offset, false, 52, 8);\n\t};\n\n\tfunction checkInt(buf, value, offset, ext, max, min) {\n\t  if (!internalIsBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance');\n\t  if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds');\n\t  if (offset + ext > buf.length) throw new RangeError('Index out of range');\n\t}\n\n\tBuffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\n\t  if (!noAssert) {\n\t    var maxBytes = Math.pow(2, 8 * byteLength) - 1;\n\t    checkInt(this, value, offset, byteLength, maxBytes, 0);\n\t  }\n\n\t  var mul = 1;\n\t  var i = 0;\n\t  this[offset] = value & 0xFF;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    this[offset + i] = value / mul & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  byteLength = byteLength | 0;\n\n\t  if (!noAssert) {\n\t    var maxBytes = Math.pow(2, 8 * byteLength) - 1;\n\t    checkInt(this, value, offset, byteLength, maxBytes, 0);\n\t  }\n\n\t  var i = byteLength - 1;\n\t  var mul = 1;\n\t  this[offset + i] = value & 0xFF;\n\n\t  while (--i >= 0 && (mul *= 0x100)) {\n\t    this[offset + i] = value / mul & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0);\n\t  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);\n\t  this[offset] = value & 0xff;\n\t  return offset + 1;\n\t};\n\n\tfunction objectWriteUInt16(buf, value, offset, littleEndian) {\n\t  if (value < 0) value = 0xffff + value + 1;\n\n\t  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n\t    buf[offset + i] = (value & 0xff << 8 * (littleEndian ? i : 1 - i)) >>> (littleEndian ? i : 1 - i) * 8;\n\t  }\n\t}\n\n\tBuffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value & 0xff;\n\t    this[offset + 1] = value >>> 8;\n\t  } else {\n\t    objectWriteUInt16(this, value, offset, true);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tBuffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 8;\n\t    this[offset + 1] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt16(this, value, offset, false);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tfunction objectWriteUInt32(buf, value, offset, littleEndian) {\n\t  if (value < 0) value = 0xffffffff + value + 1;\n\n\t  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n\t    buf[offset + i] = value >>> (littleEndian ? i : 3 - i) * 8 & 0xff;\n\t  }\n\t}\n\n\tBuffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset + 3] = value >>> 24;\n\t    this[offset + 2] = value >>> 16;\n\t    this[offset + 1] = value >>> 8;\n\t    this[offset] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt32(this, value, offset, true);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tBuffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 24;\n\t    this[offset + 1] = value >>> 16;\n\t    this[offset + 2] = value >>> 8;\n\t    this[offset + 3] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt32(this, value, offset, false);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tBuffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\n\t  if (!noAssert) {\n\t    var limit = Math.pow(2, 8 * byteLength - 1);\n\t    checkInt(this, value, offset, byteLength, limit - 1, -limit);\n\t  }\n\n\t  var i = 0;\n\t  var mul = 1;\n\t  var sub = 0;\n\t  this[offset] = value & 0xFF;\n\n\t  while (++i < byteLength && (mul *= 0x100)) {\n\t    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n\t      sub = 1;\n\t    }\n\n\t    this[offset + i] = (value / mul >> 0) - sub & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\n\t  if (!noAssert) {\n\t    var limit = Math.pow(2, 8 * byteLength - 1);\n\t    checkInt(this, value, offset, byteLength, limit - 1, -limit);\n\t  }\n\n\t  var i = byteLength - 1;\n\t  var mul = 1;\n\t  var sub = 0;\n\t  this[offset + i] = value & 0xFF;\n\n\t  while (--i >= 0 && (mul *= 0x100)) {\n\t    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n\t      sub = 1;\n\t    }\n\n\t    this[offset + i] = (value / mul >> 0) - sub & 0xFF;\n\t  }\n\n\t  return offset + byteLength;\n\t};\n\n\tBuffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);\n\t  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);\n\t  if (value < 0) value = 0xff + value + 1;\n\t  this[offset] = value & 0xff;\n\t  return offset + 1;\n\t};\n\n\tBuffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value & 0xff;\n\t    this[offset + 1] = value >>> 8;\n\t  } else {\n\t    objectWriteUInt16(this, value, offset, true);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tBuffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 8;\n\t    this[offset + 1] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt16(this, value, offset, false);\n\t  }\n\n\t  return offset + 2;\n\t};\n\n\tBuffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value & 0xff;\n\t    this[offset + 1] = value >>> 8;\n\t    this[offset + 2] = value >>> 16;\n\t    this[offset + 3] = value >>> 24;\n\t  } else {\n\t    objectWriteUInt32(this, value, offset, true);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tBuffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) {\n\t  value = +value;\n\t  offset = offset | 0;\n\t  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);\n\t  if (value < 0) value = 0xffffffff + value + 1;\n\n\t  if (Buffer.TYPED_ARRAY_SUPPORT) {\n\t    this[offset] = value >>> 24;\n\t    this[offset + 1] = value >>> 16;\n\t    this[offset + 2] = value >>> 8;\n\t    this[offset + 3] = value & 0xff;\n\t  } else {\n\t    objectWriteUInt32(this, value, offset, false);\n\t  }\n\n\t  return offset + 4;\n\t};\n\n\tfunction checkIEEE754(buf, value, offset, ext, max, min) {\n\t  if (offset + ext > buf.length) throw new RangeError('Index out of range');\n\t  if (offset < 0) throw new RangeError('Index out of range');\n\t}\n\n\tfunction writeFloat(buf, value, offset, littleEndian, noAssert) {\n\t  if (!noAssert) {\n\t    checkIEEE754(buf, value, offset, 4);\n\t  }\n\n\t  write(buf, value, offset, littleEndian, 23, 4);\n\t  return offset + 4;\n\t}\n\n\tBuffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) {\n\t  return writeFloat(this, value, offset, true, noAssert);\n\t};\n\n\tBuffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) {\n\t  return writeFloat(this, value, offset, false, noAssert);\n\t};\n\n\tfunction writeDouble(buf, value, offset, littleEndian, noAssert) {\n\t  if (!noAssert) {\n\t    checkIEEE754(buf, value, offset, 8);\n\t  }\n\n\t  write(buf, value, offset, littleEndian, 52, 8);\n\t  return offset + 8;\n\t}\n\n\tBuffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) {\n\t  return writeDouble(this, value, offset, true, noAssert);\n\t};\n\n\tBuffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) {\n\t  return writeDouble(this, value, offset, false, noAssert);\n\t}; // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\n\n\n\tBuffer.prototype.copy = function copy(target, targetStart, start, end) {\n\t  if (!start) start = 0;\n\t  if (!end && end !== 0) end = this.length;\n\t  if (targetStart >= target.length) targetStart = target.length;\n\t  if (!targetStart) targetStart = 0;\n\t  if (end > 0 && end < start) end = start; // Copy 0 bytes; we're done\n\n\t  if (end === start) return 0;\n\t  if (target.length === 0 || this.length === 0) return 0; // Fatal error conditions\n\n\t  if (targetStart < 0) {\n\t    throw new RangeError('targetStart out of bounds');\n\t  }\n\n\t  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds');\n\t  if (end < 0) throw new RangeError('sourceEnd out of bounds'); // Are we oob?\n\n\t  if (end > this.length) end = this.length;\n\n\t  if (target.length - targetStart < end - start) {\n\t    end = target.length - targetStart + start;\n\t  }\n\n\t  var len = end - start;\n\t  var i;\n\n\t  if (this === target && start < targetStart && targetStart < end) {\n\t    // descending copy from end\n\t    for (i = len - 1; i >= 0; --i) {\n\t      target[i + targetStart] = this[i + start];\n\t    }\n\t  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n\t    // ascending copy from start\n\t    for (i = 0; i < len; ++i) {\n\t      target[i + targetStart] = this[i + start];\n\t    }\n\t  } else {\n\t    Uint8Array.prototype.set.call(target, this.subarray(start, start + len), targetStart);\n\t  }\n\n\t  return len;\n\t}; // Usage:\n\t//    buffer.fill(number[, offset[, end]])\n\t//    buffer.fill(buffer[, offset[, end]])\n\t//    buffer.fill(string[, offset[, end]][, encoding])\n\n\n\tBuffer.prototype.fill = function fill(val, start, end, encoding) {\n\t  // Handle string cases:\n\t  if (typeof val === 'string') {\n\t    if (typeof start === 'string') {\n\t      encoding = start;\n\t      start = 0;\n\t      end = this.length;\n\t    } else if (typeof end === 'string') {\n\t      encoding = end;\n\t      end = this.length;\n\t    }\n\n\t    if (val.length === 1) {\n\t      var code = val.charCodeAt(0);\n\n\t      if (code < 256) {\n\t        val = code;\n\t      }\n\t    }\n\n\t    if (encoding !== undefined && typeof encoding !== 'string') {\n\t      throw new TypeError('encoding must be a string');\n\t    }\n\n\t    if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n\t      throw new TypeError('Unknown encoding: ' + encoding);\n\t    }\n\t  } else if (typeof val === 'number') {\n\t    val = val & 255;\n\t  } // Invalid ranges are not set to a default, so can range check early.\n\n\n\t  if (start < 0 || this.length < start || this.length < end) {\n\t    throw new RangeError('Out of range index');\n\t  }\n\n\t  if (end <= start) {\n\t    return this;\n\t  }\n\n\t  start = start >>> 0;\n\t  end = end === undefined ? this.length : end >>> 0;\n\t  if (!val) val = 0;\n\t  var i;\n\n\t  if (typeof val === 'number') {\n\t    for (i = start; i < end; ++i) {\n\t      this[i] = val;\n\t    }\n\t  } else {\n\t    var bytes = internalIsBuffer(val) ? val : utf8ToBytes(new Buffer(val, encoding).toString());\n\t    var len = bytes.length;\n\n\t    for (i = 0; i < end - start; ++i) {\n\t      this[i + start] = bytes[i % len];\n\t    }\n\t  }\n\n\t  return this;\n\t}; // HELPER FUNCTIONS\n\t// ================\n\n\n\tvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g;\n\n\tfunction base64clean(str) {\n\t  // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n\t  str = stringtrim(str).replace(INVALID_BASE64_RE, ''); // Node converts strings with length < 2 to ''\n\n\t  if (str.length < 2) return ''; // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n\n\t  while (str.length % 4 !== 0) {\n\t    str = str + '=';\n\t  }\n\n\t  return str;\n\t}\n\n\tfunction stringtrim(str) {\n\t  if (str.trim) return str.trim();\n\t  return str.replace(/^\\s+|\\s+$/g, '');\n\t}\n\n\tfunction toHex(n) {\n\t  if (n < 16) return '0' + n.toString(16);\n\t  return n.toString(16);\n\t}\n\n\tfunction utf8ToBytes(string, units) {\n\t  units = units || Infinity;\n\t  var codePoint;\n\t  var length = string.length;\n\t  var leadSurrogate = null;\n\t  var bytes = [];\n\n\t  for (var i = 0; i < length; ++i) {\n\t    codePoint = string.charCodeAt(i); // is surrogate component\n\n\t    if (codePoint > 0xD7FF && codePoint < 0xE000) {\n\t      // last char was a lead\n\t      if (!leadSurrogate) {\n\t        // no lead yet\n\t        if (codePoint > 0xDBFF) {\n\t          // unexpected trail\n\t          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t          continue;\n\t        } else if (i + 1 === length) {\n\t          // unpaired lead\n\t          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t          continue;\n\t        } // valid lead\n\n\n\t        leadSurrogate = codePoint;\n\t        continue;\n\t      } // 2 leads in a row\n\n\n\t      if (codePoint < 0xDC00) {\n\t        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t        leadSurrogate = codePoint;\n\t        continue;\n\t      } // valid surrogate pair\n\n\n\t      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;\n\t    } else if (leadSurrogate) {\n\t      // valid bmp char, but last char was a lead\n\t      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n\t    }\n\n\t    leadSurrogate = null; // encode utf8\n\n\t    if (codePoint < 0x80) {\n\t      if ((units -= 1) < 0) break;\n\t      bytes.push(codePoint);\n\t    } else if (codePoint < 0x800) {\n\t      if ((units -= 2) < 0) break;\n\t      bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80);\n\t    } else if (codePoint < 0x10000) {\n\t      if ((units -= 3) < 0) break;\n\t      bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);\n\t    } else if (codePoint < 0x110000) {\n\t      if ((units -= 4) < 0) break;\n\t      bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);\n\t    } else {\n\t      throw new Error('Invalid code point');\n\t    }\n\t  }\n\n\t  return bytes;\n\t}\n\n\tfunction asciiToBytes(str) {\n\t  var byteArray = [];\n\n\t  for (var i = 0; i < str.length; ++i) {\n\t    // Node's code seems to be doing this and not & 0x7F..\n\t    byteArray.push(str.charCodeAt(i) & 0xFF);\n\t  }\n\n\t  return byteArray;\n\t}\n\n\tfunction utf16leToBytes(str, units) {\n\t  var c, hi, lo;\n\t  var byteArray = [];\n\n\t  for (var i = 0; i < str.length; ++i) {\n\t    if ((units -= 2) < 0) break;\n\t    c = str.charCodeAt(i);\n\t    hi = c >> 8;\n\t    lo = c % 256;\n\t    byteArray.push(lo);\n\t    byteArray.push(hi);\n\t  }\n\n\t  return byteArray;\n\t}\n\n\tfunction base64ToBytes(str) {\n\t  return toByteArray(base64clean(str));\n\t}\n\n\tfunction blitBuffer(src, dst, offset, length) {\n\t  for (var i = 0; i < length; ++i) {\n\t    if (i + offset >= dst.length || i >= src.length) break;\n\t    dst[i + offset] = src[i];\n\t  }\n\n\t  return i;\n\t}\n\n\tfunction isnan(val) {\n\t  return val !== val; // eslint-disable-line no-self-compare\n\t} // the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence\n\t// The _isBuffer check is for Safari 5-7 support, because it's missing\n\t// Object.prototype.constructor. Remove this eventually\n\n\n\tfunction isBuffer(obj) {\n\t  return obj != null && (!!obj._isBuffer || isFastBuffer(obj) || isSlowBuffer(obj));\n\t}\n\n\tfunction isFastBuffer(obj) {\n\t  return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);\n\t} // For Node v0.10 support. Remove this eventually.\n\n\n\tfunction isSlowBuffer(obj) {\n\t  return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer(obj.slice(0, 0));\n\t}\n\n\tfunction BufferList() {\n\t  this.head = null;\n\t  this.tail = null;\n\t  this.length = 0;\n\t}\n\n\tBufferList.prototype.push = function (v) {\n\t  var entry = {\n\t    data: v,\n\t    next: null\n\t  };\n\t  if (this.length > 0) this.tail.next = entry;else this.head = entry;\n\t  this.tail = entry;\n\t  ++this.length;\n\t};\n\n\tBufferList.prototype.unshift = function (v) {\n\t  var entry = {\n\t    data: v,\n\t    next: this.head\n\t  };\n\t  if (this.length === 0) this.tail = entry;\n\t  this.head = entry;\n\t  ++this.length;\n\t};\n\n\tBufferList.prototype.shift = function () {\n\t  if (this.length === 0) return;\n\t  var ret = this.head.data;\n\t  if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;\n\t  --this.length;\n\t  return ret;\n\t};\n\n\tBufferList.prototype.clear = function () {\n\t  this.head = this.tail = null;\n\t  this.length = 0;\n\t};\n\n\tBufferList.prototype.join = function (s) {\n\t  if (this.length === 0) return '';\n\t  var p = this.head;\n\t  var ret = '' + p.data;\n\n\t  while (p = p.next) {\n\t    ret += s + p.data;\n\t  }\n\n\t  return ret;\n\t};\n\n\tBufferList.prototype.concat = function (n) {\n\t  if (this.length === 0) return Buffer.alloc(0);\n\t  if (this.length === 1) return this.head.data;\n\t  var ret = Buffer.allocUnsafe(n >>> 0);\n\t  var p = this.head;\n\t  var i = 0;\n\n\t  while (p) {\n\t    p.data.copy(ret, i);\n\t    i += p.data.length;\n\t    p = p.next;\n\t  }\n\n\t  return ret;\n\t};\n\n\tvar isBufferEncoding = Buffer.isEncoding || function (encoding) {\n\t  switch (encoding && encoding.toLowerCase()) {\n\t    case 'hex':\n\t    case 'utf8':\n\t    case 'utf-8':\n\t    case 'ascii':\n\t    case 'binary':\n\t    case 'base64':\n\t    case 'ucs2':\n\t    case 'ucs-2':\n\t    case 'utf16le':\n\t    case 'utf-16le':\n\t    case 'raw':\n\t      return true;\n\n\t    default:\n\t      return false;\n\t  }\n\t};\n\n\tfunction assertEncoding(encoding) {\n\t  if (encoding && !isBufferEncoding(encoding)) {\n\t    throw new Error('Unknown encoding: ' + encoding);\n\t  }\n\t} // StringDecoder provides an interface for efficiently splitting a series of\n\t// buffers into a series of JS strings without breaking apart multi-byte\n\t// characters. CESU-8 is handled as part of the UTF-8 encoding.\n\t//\n\t// @TODO Handling all encodings inside a single object makes it very difficult\n\t// to reason about this code, so it should be split up in the future.\n\t// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code\n\t// points as used by CESU-8.\n\n\n\tfunction StringDecoder(encoding) {\n\t  this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');\n\t  assertEncoding(encoding);\n\n\t  switch (this.encoding) {\n\t    case 'utf8':\n\t      // CESU-8 represents each of Surrogate Pair by 3-bytes\n\t      this.surrogateSize = 3;\n\t      break;\n\n\t    case 'ucs2':\n\t    case 'utf16le':\n\t      // UTF-16 represents each of Surrogate Pair by 2-bytes\n\t      this.surrogateSize = 2;\n\t      this.detectIncompleteChar = utf16DetectIncompleteChar;\n\t      break;\n\n\t    case 'base64':\n\t      // Base-64 stores 3 bytes in 4 chars, and pads the remainder.\n\t      this.surrogateSize = 3;\n\t      this.detectIncompleteChar = base64DetectIncompleteChar;\n\t      break;\n\n\t    default:\n\t      this.write = passThroughWrite;\n\t      return;\n\t  } // Enough space to store all bytes of a single character. UTF-8 needs 4\n\t  // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate).\n\n\n\t  this.charBuffer = new Buffer(6); // Number of bytes received for the current incomplete multi-byte character.\n\n\t  this.charReceived = 0; // Number of bytes expected for the current incomplete multi-byte character.\n\n\t  this.charLength = 0;\n\t}\n\t// guaranteed to not contain any partial multi-byte characters. Any partial\n\t// character found at the end of the buffer is buffered up, and will be\n\t// returned when calling write again with the remaining bytes.\n\t//\n\t// Note: Converting a Buffer containing an orphan surrogate to a String\n\t// currently works, but converting a String to a Buffer (via `new Buffer`, or\n\t// Buffer#write) will replace incomplete surrogates with the unicode\n\t// replacement character. See https://codereview.chromium.org/121173009/ .\n\n\tStringDecoder.prototype.write = function (buffer) {\n\t  var charStr = ''; // if our last write ended with an incomplete multibyte character\n\n\t  while (this.charLength) {\n\t    // determine how many remaining bytes this buffer has to offer for this char\n\t    var available = buffer.length >= this.charLength - this.charReceived ? this.charLength - this.charReceived : buffer.length; // add the new bytes to the char buffer\n\n\t    buffer.copy(this.charBuffer, this.charReceived, 0, available);\n\t    this.charReceived += available;\n\n\t    if (this.charReceived < this.charLength) {\n\t      // still not enough chars in this buffer? wait for more ...\n\t      return '';\n\t    } // remove bytes belonging to the current character from the buffer\n\n\n\t    buffer = buffer.slice(available, buffer.length); // get the character that was split\n\n\t    charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character\n\n\t    var charCode = charStr.charCodeAt(charStr.length - 1);\n\n\t    if (charCode >= 0xD800 && charCode <= 0xDBFF) {\n\t      this.charLength += this.surrogateSize;\n\t      charStr = '';\n\t      continue;\n\t    }\n\n\t    this.charReceived = this.charLength = 0; // if there are no more bytes in this buffer, just emit our char\n\n\t    if (buffer.length === 0) {\n\t      return charStr;\n\t    }\n\n\t    break;\n\t  } // determine and set charLength / charReceived\n\n\n\t  this.detectIncompleteChar(buffer);\n\t  var end = buffer.length;\n\n\t  if (this.charLength) {\n\t    // buffer the incomplete character bytes we got\n\t    buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end);\n\t    end -= this.charReceived;\n\t  }\n\n\t  charStr += buffer.toString(this.encoding, 0, end);\n\t  var end = charStr.length - 1;\n\t  var charCode = charStr.charCodeAt(end); // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character\n\n\t  if (charCode >= 0xD800 && charCode <= 0xDBFF) {\n\t    var size = this.surrogateSize;\n\t    this.charLength += size;\n\t    this.charReceived += size;\n\t    this.charBuffer.copy(this.charBuffer, size, 0, size);\n\t    buffer.copy(this.charBuffer, 0, 0, size);\n\t    return charStr.substring(0, end);\n\t  } // or just emit the charStr\n\n\n\t  return charStr;\n\t}; // detectIncompleteChar determines if there is an incomplete UTF-8 character at\n\t// the end of the given buffer. If so, it sets this.charLength to the byte\n\t// length that character, and sets this.charReceived to the number of bytes\n\t// that are available for this character.\n\n\n\tStringDecoder.prototype.detectIncompleteChar = function (buffer) {\n\t  // determine how many bytes we have to check at the end of this buffer\n\t  var i = buffer.length >= 3 ? 3 : buffer.length; // Figure out if one of the last i bytes of our buffer announces an\n\t  // incomplete char.\n\n\t  for (; i > 0; i--) {\n\t    var c = buffer[buffer.length - i]; // See http://en.wikipedia.org/wiki/UTF-8#Description\n\t    // 110XXXXX\n\n\t    if (i == 1 && c >> 5 == 0x06) {\n\t      this.charLength = 2;\n\t      break;\n\t    } // 1110XXXX\n\n\n\t    if (i <= 2 && c >> 4 == 0x0E) {\n\t      this.charLength = 3;\n\t      break;\n\t    } // 11110XXX\n\n\n\t    if (i <= 3 && c >> 3 == 0x1E) {\n\t      this.charLength = 4;\n\t      break;\n\t    }\n\t  }\n\n\t  this.charReceived = i;\n\t};\n\n\tStringDecoder.prototype.end = function (buffer) {\n\t  var res = '';\n\t  if (buffer && buffer.length) res = this.write(buffer);\n\n\t  if (this.charReceived) {\n\t    var cr = this.charReceived;\n\t    var buf = this.charBuffer;\n\t    var enc = this.encoding;\n\t    res += buf.slice(0, cr).toString(enc);\n\t  }\n\n\t  return res;\n\t};\n\n\tfunction passThroughWrite(buffer) {\n\t  return buffer.toString(this.encoding);\n\t}\n\n\tfunction utf16DetectIncompleteChar(buffer) {\n\t  this.charReceived = buffer.length % 2;\n\t  this.charLength = this.charReceived ? 2 : 0;\n\t}\n\n\tfunction base64DetectIncompleteChar(buffer) {\n\t  this.charReceived = buffer.length % 3;\n\t  this.charLength = this.charReceived ? 3 : 0;\n\t}\n\n\tReadable.ReadableState = ReadableState;\n\tvar debug$2 = debuglog('stream');\n\tinherits$3(Readable, EventEmitter$2);\n\n\tfunction prependListener(emitter, event, fn) {\n\t  // Sadly this is not cacheable as some libraries bundle their own\n\t  // event emitter implementation with them.\n\t  if (typeof emitter.prependListener === 'function') {\n\t    return emitter.prependListener(event, fn);\n\t  } else {\n\t    // This is a hack to make sure that our error handler is attached before any\n\t    // userland ones.  NEVER DO THIS. This is here only because this code needs\n\t    // to continue to work with older versions of Node.js that do not include\n\t    // the prependListener() method. The goal is to eventually remove this hack.\n\t    if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n\t  }\n\t}\n\n\tfunction listenerCount(emitter, type) {\n\t  return emitter.listeners(type).length;\n\t}\n\n\tfunction ReadableState(options, stream) {\n\t  options = options || {}; // object stream flag. Used to make read(n) ignore n and to\n\t  // make all the buffer merging and length checks go away\n\n\t  this.objectMode = !!options.objectMode;\n\t  if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer\n\t  // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n\n\t  var hwm = options.highWaterMark;\n\t  var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\t  this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; // cast to ints.\n\n\t  this.highWaterMark = ~~this.highWaterMark; // A linked list is used to store data chunks instead of an array because the\n\t  // linked list can remove elements from the beginning faster than\n\t  // array.shift()\n\n\t  this.buffer = new BufferList();\n\t  this.length = 0;\n\t  this.pipes = null;\n\t  this.pipesCount = 0;\n\t  this.flowing = null;\n\t  this.ended = false;\n\t  this.endEmitted = false;\n\t  this.reading = false; // a flag to be able to tell if the onwrite cb is called immediately,\n\t  // or on a later tick.  We set this to true at first, because any\n\t  // actions that shouldn't happen until \"later\" should generally also\n\t  // not happen before the first write call.\n\n\t  this.sync = true; // whenever we return null, then we set a flag to say\n\t  // that we're awaiting a 'readable' event emission.\n\n\t  this.needReadable = false;\n\t  this.emittedReadable = false;\n\t  this.readableListening = false;\n\t  this.resumeScheduled = false; // Crypto is kind of old and crusty.  Historically, its default string\n\t  // encoding is 'binary' so we have to make this configurable.\n\t  // Everything else in the universe uses 'utf8', though.\n\n\t  this.defaultEncoding = options.defaultEncoding || 'utf8'; // when piping, we only care about 'readable' events that happen\n\t  // after read()ing all the bytes and not getting any pushback.\n\n\t  this.ranOut = false; // the number of writers that are awaiting a drain event in .pipe()s\n\n\t  this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled\n\n\t  this.readingMore = false;\n\t  this.decoder = null;\n\t  this.encoding = null;\n\n\t  if (options.encoding) {\n\t    this.decoder = new StringDecoder(options.encoding);\n\t    this.encoding = options.encoding;\n\t  }\n\t}\n\tfunction Readable(options) {\n\t  if (!(this instanceof Readable)) return new Readable(options);\n\t  this._readableState = new ReadableState(options, this); // legacy\n\n\t  this.readable = true;\n\t  if (options && typeof options.read === 'function') this._read = options.read;\n\t  EventEmitter$2.call(this);\n\t} // Manually shove something into the read() buffer.\n\t// This returns true if the highWaterMark has not been hit yet,\n\t// similar to how Writable.write() returns true if you should\n\t// write() some more.\n\n\tReadable.prototype.push = function (chunk, encoding) {\n\t  var state = this._readableState;\n\n\t  if (!state.objectMode && typeof chunk === 'string') {\n\t    encoding = encoding || state.defaultEncoding;\n\n\t    if (encoding !== state.encoding) {\n\t      chunk = Buffer$1.from(chunk, encoding);\n\t      encoding = '';\n\t    }\n\t  }\n\n\t  return readableAddChunk(this, state, chunk, encoding, false);\n\t}; // Unshift should *always* be something directly out of read()\n\n\n\tReadable.prototype.unshift = function (chunk) {\n\t  var state = this._readableState;\n\t  return readableAddChunk(this, state, chunk, '', true);\n\t};\n\n\tReadable.prototype.isPaused = function () {\n\t  return this._readableState.flowing === false;\n\t};\n\n\tfunction readableAddChunk(stream, state, chunk, encoding, addToFront) {\n\t  var er = chunkInvalid(state, chunk);\n\n\t  if (er) {\n\t    stream.emit('error', er);\n\t  } else if (chunk === null) {\n\t    state.reading = false;\n\t    onEofChunk(stream, state);\n\t  } else if (state.objectMode || chunk && chunk.length > 0) {\n\t    if (state.ended && !addToFront) {\n\t      var e = new Error('stream.push() after EOF');\n\t      stream.emit('error', e);\n\t    } else if (state.endEmitted && addToFront) {\n\t      var _e = new Error('stream.unshift() after end event');\n\n\t      stream.emit('error', _e);\n\t    } else {\n\t      var skipAdd;\n\n\t      if (state.decoder && !addToFront && !encoding) {\n\t        chunk = state.decoder.write(chunk);\n\t        skipAdd = !state.objectMode && chunk.length === 0;\n\t      }\n\n\t      if (!addToFront) state.reading = false; // Don't add to the buffer if we've decoded to an empty string chunk and\n\t      // we're not in object mode\n\n\t      if (!skipAdd) {\n\t        // if we want the data now, just emit it.\n\t        if (state.flowing && state.length === 0 && !state.sync) {\n\t          stream.emit('data', chunk);\n\t          stream.read(0);\n\t        } else {\n\t          // update the buffer info.\n\t          state.length += state.objectMode ? 1 : chunk.length;\n\t          if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n\t          if (state.needReadable) emitReadable(stream);\n\t        }\n\t      }\n\n\t      maybeReadMore(stream, state);\n\t    }\n\t  } else if (!addToFront) {\n\t    state.reading = false;\n\t  }\n\n\t  return needMoreData(state);\n\t} // if it's past the high water mark, we can push in some more.\n\t// Also, if we have no data yet, we can stand some\n\t// more bytes.  This is to work around cases where hwm=0,\n\t// such as the repl.  Also, if the push() triggered a\n\t// readable event, and the user called read(largeNumber) such that\n\t// needReadable was set, then we ought to push more, so that another\n\t// 'readable' event will be triggered.\n\n\n\tfunction needMoreData(state) {\n\t  return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);\n\t} // backwards compatibility.\n\n\n\tReadable.prototype.setEncoding = function (enc) {\n\t  this._readableState.decoder = new StringDecoder(enc);\n\t  this._readableState.encoding = enc;\n\t  return this;\n\t}; // Don't raise the hwm > 8MB\n\n\n\tvar MAX_HWM = 0x800000;\n\n\tfunction computeNewHighWaterMark(n) {\n\t  if (n >= MAX_HWM) {\n\t    n = MAX_HWM;\n\t  } else {\n\t    // Get the next highest power of 2 to prevent increasing hwm excessively in\n\t    // tiny amounts\n\t    n--;\n\t    n |= n >>> 1;\n\t    n |= n >>> 2;\n\t    n |= n >>> 4;\n\t    n |= n >>> 8;\n\t    n |= n >>> 16;\n\t    n++;\n\t  }\n\n\t  return n;\n\t} // This function is designed to be inlinable, so please take care when making\n\t// changes to the function body.\n\n\n\tfunction howMuchToRead(n, state) {\n\t  if (n <= 0 || state.length === 0 && state.ended) return 0;\n\t  if (state.objectMode) return 1;\n\n\t  if (n !== n) {\n\t    // Only flow one buffer at a time\n\t    if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n\t  } // If we're asking for more than the current hwm, then raise the hwm.\n\n\n\t  if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n\t  if (n <= state.length) return n; // Don't have enough\n\n\t  if (!state.ended) {\n\t    state.needReadable = true;\n\t    return 0;\n\t  }\n\n\t  return state.length;\n\t} // you can override either this method, or the async _read(n) below.\n\n\n\tReadable.prototype.read = function (n) {\n\t  debug$2('read', n);\n\t  n = parseInt(n, 10);\n\t  var state = this._readableState;\n\t  var nOrig = n;\n\t  if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we\n\t  // already have a bunch of data in the buffer, then just trigger\n\t  // the 'readable' event and move on.\n\n\t  if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {\n\t    debug$2('read: emitReadable', state.length, state.ended);\n\t    if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n\t    return null;\n\t  }\n\n\t  n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up.\n\n\t  if (n === 0 && state.ended) {\n\t    if (state.length === 0) endReadable(this);\n\t    return null;\n\t  } // All the actual chunk generation logic needs to be\n\t  // *below* the call to _read.  The reason is that in certain\n\t  // synthetic stream cases, such as passthrough streams, _read\n\t  // may be a completely synchronous operation which may change\n\t  // the state of the read buffer, providing enough data when\n\t  // before there was *not* enough.\n\t  //\n\t  // So, the steps are:\n\t  // 1. Figure out what the state of things will be after we do\n\t  // a read from the buffer.\n\t  //\n\t  // 2. If that resulting state will trigger a _read, then call _read.\n\t  // Note that this may be asynchronous, or synchronous.  Yes, it is\n\t  // deeply ugly to write APIs this way, but that still doesn't mean\n\t  // that the Readable class should behave improperly, as streams are\n\t  // designed to be sync/async agnostic.\n\t  // Take note if the _read call is sync or async (ie, if the read call\n\t  // has returned yet), so that we know whether or not it's safe to emit\n\t  // 'readable' etc.\n\t  //\n\t  // 3. Actually pull the requested chunks out of the buffer and return.\n\t  // if we need a readable event, then we need to do some reading.\n\n\n\t  var doRead = state.needReadable;\n\t  debug$2('need readable', doRead); // if we currently have less than the highWaterMark, then also read some\n\n\t  if (state.length === 0 || state.length - n < state.highWaterMark) {\n\t    doRead = true;\n\t    debug$2('length less than watermark', doRead);\n\t  } // however, if we've ended, then there's no point, and if we're already\n\t  // reading, then it's unnecessary.\n\n\n\t  if (state.ended || state.reading) {\n\t    doRead = false;\n\t    debug$2('reading or ended', doRead);\n\t  } else if (doRead) {\n\t    debug$2('do read');\n\t    state.reading = true;\n\t    state.sync = true; // if the length is currently zero, then we *need* a readable event.\n\n\t    if (state.length === 0) state.needReadable = true; // call internal read method\n\n\t    this._read(state.highWaterMark);\n\n\t    state.sync = false; // If _read pushed data synchronously, then `reading` will be false,\n\t    // and we need to re-evaluate how much data we can return to the user.\n\n\t    if (!state.reading) n = howMuchToRead(nOrig, state);\n\t  }\n\n\t  var ret;\n\t  if (n > 0) ret = fromList(n, state);else ret = null;\n\n\t  if (ret === null) {\n\t    state.needReadable = true;\n\t    n = 0;\n\t  } else {\n\t    state.length -= n;\n\t  }\n\n\t  if (state.length === 0) {\n\t    // If we have nothing in the buffer, then we want to know\n\t    // as soon as we *do* get something into the buffer.\n\t    if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick.\n\n\t    if (nOrig !== n && state.ended) endReadable(this);\n\t  }\n\n\t  if (ret !== null) this.emit('data', ret);\n\t  return ret;\n\t};\n\n\tfunction chunkInvalid(state, chunk) {\n\t  var er = null;\n\n\t  if (!isBuffer$2(chunk) && typeof chunk !== 'string' && chunk !== null && chunk !== undefined && !state.objectMode) {\n\t    er = new TypeError('Invalid non-string/buffer chunk');\n\t  }\n\n\t  return er;\n\t}\n\n\tfunction onEofChunk(stream, state) {\n\t  if (state.ended) return;\n\n\t  if (state.decoder) {\n\t    var chunk = state.decoder.end();\n\n\t    if (chunk && chunk.length) {\n\t      state.buffer.push(chunk);\n\t      state.length += state.objectMode ? 1 : chunk.length;\n\t    }\n\t  }\n\n\t  state.ended = true; // emit 'readable' now to make sure it gets picked up.\n\n\t  emitReadable(stream);\n\t} // Don't emit readable right away in sync mode, because this can trigger\n\t// another read() call => stack overflow.  This way, it might trigger\n\t// a nextTick recursion warning, but that's not so bad.\n\n\n\tfunction emitReadable(stream) {\n\t  var state = stream._readableState;\n\t  state.needReadable = false;\n\n\t  if (!state.emittedReadable) {\n\t    debug$2('emitReadable', state.flowing);\n\t    state.emittedReadable = true;\n\t    if (state.sync) nextTick(emitReadable_, stream);else emitReadable_(stream);\n\t  }\n\t}\n\n\tfunction emitReadable_(stream) {\n\t  debug$2('emit readable');\n\t  stream.emit('readable');\n\t  flow(stream);\n\t} // at this point, the user has presumably seen the 'readable' event,\n\t// and called read() to consume some data.  that may have triggered\n\t// in turn another _read(n) call, in which case reading = true if\n\t// it's in progress.\n\t// However, if we're not ended, or reading, and the length < hwm,\n\t// then go ahead and try to read some more preemptively.\n\n\n\tfunction maybeReadMore(stream, state) {\n\t  if (!state.readingMore) {\n\t    state.readingMore = true;\n\t    nextTick(maybeReadMore_, stream, state);\n\t  }\n\t}\n\n\tfunction maybeReadMore_(stream, state) {\n\t  var len = state.length;\n\n\t  while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {\n\t    debug$2('maybeReadMore read 0');\n\t    stream.read(0);\n\t    if (len === state.length) // didn't get any data, stop spinning.\n\t      break;else len = state.length;\n\t  }\n\n\t  state.readingMore = false;\n\t} // abstract method.  to be overridden in specific implementation classes.\n\t// call cb(er, data) where data is <= n in length.\n\t// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n\t// arbitrary, and perhaps not very meaningful.\n\n\n\tReadable.prototype._read = function (n) {\n\t  this.emit('error', new Error('not implemented'));\n\t};\n\n\tReadable.prototype.pipe = function (dest, pipeOpts) {\n\t  var src = this;\n\t  var state = this._readableState;\n\n\t  switch (state.pipesCount) {\n\t    case 0:\n\t      state.pipes = dest;\n\t      break;\n\n\t    case 1:\n\t      state.pipes = [state.pipes, dest];\n\t      break;\n\n\t    default:\n\t      state.pipes.push(dest);\n\t      break;\n\t  }\n\n\t  state.pipesCount += 1;\n\t  debug$2('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n\t  var doEnd = !pipeOpts || pipeOpts.end !== false;\n\t  var endFn = doEnd ? onend : cleanup;\n\t  if (state.endEmitted) nextTick(endFn);else src.once('end', endFn);\n\t  dest.on('unpipe', onunpipe);\n\n\t  function onunpipe(readable) {\n\t    debug$2('onunpipe');\n\n\t    if (readable === src) {\n\t      cleanup();\n\t    }\n\t  }\n\n\t  function onend() {\n\t    debug$2('onend');\n\t    dest.end();\n\t  } // when the dest drains, it reduces the awaitDrain counter\n\t  // on the source.  This would be more elegant with a .once()\n\t  // handler in flow(), but adding and removing repeatedly is\n\t  // too slow.\n\n\n\t  var ondrain = pipeOnDrain(src);\n\t  dest.on('drain', ondrain);\n\t  var cleanedUp = false;\n\n\t  function cleanup() {\n\t    debug$2('cleanup'); // cleanup event handlers once the pipe is broken\n\n\t    dest.removeListener('close', onclose);\n\t    dest.removeListener('finish', onfinish);\n\t    dest.removeListener('drain', ondrain);\n\t    dest.removeListener('error', onerror);\n\t    dest.removeListener('unpipe', onunpipe);\n\t    src.removeListener('end', onend);\n\t    src.removeListener('end', cleanup);\n\t    src.removeListener('data', ondata);\n\t    cleanedUp = true; // if the reader is waiting for a drain event from this\n\t    // specific writer, then it would cause it to never start\n\t    // flowing again.\n\t    // So, if this is awaiting a drain, then we just call it now.\n\t    // If we don't know, then assume that we are waiting for one.\n\n\t    if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n\t  } // If the user pushes more data while we're writing to dest then we'll end up\n\t  // in ondata again. However, we only want to increase awaitDrain once because\n\t  // dest will only emit one 'drain' event for the multiple writes.\n\t  // => Introduce a guard on increasing awaitDrain.\n\n\n\t  var increasedAwaitDrain = false;\n\t  src.on('data', ondata);\n\n\t  function ondata(chunk) {\n\t    debug$2('ondata');\n\t    increasedAwaitDrain = false;\n\t    var ret = dest.write(chunk);\n\n\t    if (false === ret && !increasedAwaitDrain) {\n\t      // If the user unpiped during `dest.write()`, it is possible\n\t      // to get stuck in a permanently paused state if that write\n\t      // also returned false.\n\t      // => Check whether `dest` is still a piping destination.\n\t      if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n\t        debug$2('false write response, pause', src._readableState.awaitDrain);\n\t        src._readableState.awaitDrain++;\n\t        increasedAwaitDrain = true;\n\t      }\n\n\t      src.pause();\n\t    }\n\t  } // if the dest has an error, then stop piping into it.\n\t  // however, don't suppress the throwing behavior for this.\n\n\n\t  function onerror(er) {\n\t    debug$2('onerror', er);\n\t    unpipe();\n\t    dest.removeListener('error', onerror);\n\t    if (listenerCount(dest, 'error') === 0) dest.emit('error', er);\n\t  } // Make sure our error handler is attached before userland ones.\n\n\n\t  prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once.\n\n\t  function onclose() {\n\t    dest.removeListener('finish', onfinish);\n\t    unpipe();\n\t  }\n\n\t  dest.once('close', onclose);\n\n\t  function onfinish() {\n\t    debug$2('onfinish');\n\t    dest.removeListener('close', onclose);\n\t    unpipe();\n\t  }\n\n\t  dest.once('finish', onfinish);\n\n\t  function unpipe() {\n\t    debug$2('unpipe');\n\t    src.unpipe(dest);\n\t  } // tell the dest that it's being piped to\n\n\n\t  dest.emit('pipe', src); // start the flow if it hasn't been started already.\n\n\t  if (!state.flowing) {\n\t    debug$2('pipe resume');\n\t    src.resume();\n\t  }\n\n\t  return dest;\n\t};\n\n\tfunction pipeOnDrain(src) {\n\t  return function () {\n\t    var state = src._readableState;\n\t    debug$2('pipeOnDrain', state.awaitDrain);\n\t    if (state.awaitDrain) state.awaitDrain--;\n\n\t    if (state.awaitDrain === 0 && src.listeners('data').length) {\n\t      state.flowing = true;\n\t      flow(src);\n\t    }\n\t  };\n\t}\n\n\tReadable.prototype.unpipe = function (dest) {\n\t  var state = this._readableState; // if we're not piping anywhere, then do nothing.\n\n\t  if (state.pipesCount === 0) return this; // just one destination.  most common case.\n\n\t  if (state.pipesCount === 1) {\n\t    // passed in one, but it's not the right one.\n\t    if (dest && dest !== state.pipes) return this;\n\t    if (!dest) dest = state.pipes; // got a match.\n\n\t    state.pipes = null;\n\t    state.pipesCount = 0;\n\t    state.flowing = false;\n\t    if (dest) dest.emit('unpipe', this);\n\t    return this;\n\t  } // slow case. multiple pipe destinations.\n\n\n\t  if (!dest) {\n\t    // remove all.\n\t    var dests = state.pipes;\n\t    var len = state.pipesCount;\n\t    state.pipes = null;\n\t    state.pipesCount = 0;\n\t    state.flowing = false;\n\n\t    for (var _i = 0; _i < len; _i++) {\n\t      dests[_i].emit('unpipe', this);\n\t    }\n\n\t    return this;\n\t  } // try to find the right one.\n\n\n\t  var i = indexOf(state.pipes, dest);\n\t  if (i === -1) return this;\n\t  state.pipes.splice(i, 1);\n\t  state.pipesCount -= 1;\n\t  if (state.pipesCount === 1) state.pipes = state.pipes[0];\n\t  dest.emit('unpipe', this);\n\t  return this;\n\t}; // set up data events if they are asked for\n\t// Ensure readable listeners eventually get something\n\n\n\tReadable.prototype.on = function (ev, fn) {\n\t  var res = EventEmitter$2.prototype.on.call(this, ev, fn);\n\n\t  if (ev === 'data') {\n\t    // Start flowing on next tick if stream isn't explicitly paused\n\t    if (this._readableState.flowing !== false) this.resume();\n\t  } else if (ev === 'readable') {\n\t    var state = this._readableState;\n\n\t    if (!state.endEmitted && !state.readableListening) {\n\t      state.readableListening = state.needReadable = true;\n\t      state.emittedReadable = false;\n\n\t      if (!state.reading) {\n\t        nextTick(nReadingNextTick, this);\n\t      } else if (state.length) {\n\t        emitReadable(this);\n\t      }\n\t    }\n\t  }\n\n\t  return res;\n\t};\n\n\tReadable.prototype.addListener = Readable.prototype.on;\n\n\tfunction nReadingNextTick(self) {\n\t  debug$2('readable nexttick read 0');\n\t  self.read(0);\n\t} // pause() and resume() are remnants of the legacy readable stream API\n\t// If the user uses them, then switch into old mode.\n\n\n\tReadable.prototype.resume = function () {\n\t  var state = this._readableState;\n\n\t  if (!state.flowing) {\n\t    debug$2('resume');\n\t    state.flowing = true;\n\t    resume(this, state);\n\t  }\n\n\t  return this;\n\t};\n\n\tfunction resume(stream, state) {\n\t  if (!state.resumeScheduled) {\n\t    state.resumeScheduled = true;\n\t    nextTick(resume_, stream, state);\n\t  }\n\t}\n\n\tfunction resume_(stream, state) {\n\t  if (!state.reading) {\n\t    debug$2('resume read 0');\n\t    stream.read(0);\n\t  }\n\n\t  state.resumeScheduled = false;\n\t  state.awaitDrain = 0;\n\t  stream.emit('resume');\n\t  flow(stream);\n\t  if (state.flowing && !state.reading) stream.read(0);\n\t}\n\n\tReadable.prototype.pause = function () {\n\t  debug$2('call pause flowing=%j', this._readableState.flowing);\n\n\t  if (false !== this._readableState.flowing) {\n\t    debug$2('pause');\n\t    this._readableState.flowing = false;\n\t    this.emit('pause');\n\t  }\n\n\t  return this;\n\t};\n\n\tfunction flow(stream) {\n\t  var state = stream._readableState;\n\t  debug$2('flow', state.flowing);\n\n\t  while (state.flowing && stream.read() !== null) {}\n\t} // wrap an old-style stream as the async data source.\n\t// This is *not* part of the readable stream interface.\n\t// It is an ugly unfortunate mess of history.\n\n\n\tReadable.prototype.wrap = function (stream) {\n\t  var state = this._readableState;\n\t  var paused = false;\n\t  var self = this;\n\t  stream.on('end', function () {\n\t    debug$2('wrapped end');\n\n\t    if (state.decoder && !state.ended) {\n\t      var chunk = state.decoder.end();\n\t      if (chunk && chunk.length) self.push(chunk);\n\t    }\n\n\t    self.push(null);\n\t  });\n\t  stream.on('data', function (chunk) {\n\t    debug$2('wrapped data');\n\t    if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode\n\n\t    if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\t    var ret = self.push(chunk);\n\n\t    if (!ret) {\n\t      paused = true;\n\t      stream.pause();\n\t    }\n\t  }); // proxy all the other methods.\n\t  // important when wrapping filters and duplexes.\n\n\t  for (var i in stream) {\n\t    if (this[i] === undefined && typeof stream[i] === 'function') {\n\t      this[i] = function (method) {\n\t        return function () {\n\t          return stream[method].apply(stream, arguments);\n\t        };\n\t      }(i);\n\t    }\n\t  } // proxy certain important events.\n\n\n\t  var events = ['error', 'close', 'destroy', 'pause', 'resume'];\n\t  forEach(events, function (ev) {\n\t    stream.on(ev, self.emit.bind(self, ev));\n\t  }); // when we try to consume some more bytes, simply unpause the\n\t  // underlying stream.\n\n\t  self._read = function (n) {\n\t    debug$2('wrapped _read', n);\n\n\t    if (paused) {\n\t      paused = false;\n\t      stream.resume();\n\t    }\n\t  };\n\n\t  return self;\n\t}; // exposed for testing purposes only.\n\n\n\tReadable._fromList = fromList; // Pluck off n bytes from an array of buffers.\n\t// Length is the combined lengths of all the buffers in the list.\n\t// This function is designed to be inlinable, so please take care when making\n\t// changes to the function body.\n\n\tfunction fromList(n, state) {\n\t  // nothing buffered\n\t  if (state.length === 0) return null;\n\t  var ret;\n\t  if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n\t    // read it all, truncate the list\n\t    if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);\n\t    state.buffer.clear();\n\t  } else {\n\t    // read part of list\n\t    ret = fromListPartial(n, state.buffer, state.decoder);\n\t  }\n\t  return ret;\n\t} // Extracts only enough buffered data to satisfy the amount requested.\n\t// This function is designed to be inlinable, so please take care when making\n\t// changes to the function body.\n\n\n\tfunction fromListPartial(n, list, hasStrings) {\n\t  var ret;\n\n\t  if (n < list.head.data.length) {\n\t    // slice is the same for buffers and strings\n\t    ret = list.head.data.slice(0, n);\n\t    list.head.data = list.head.data.slice(n);\n\t  } else if (n === list.head.data.length) {\n\t    // first chunk is a perfect match\n\t    ret = list.shift();\n\t  } else {\n\t    // result spans more than one buffer\n\t    ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);\n\t  }\n\n\t  return ret;\n\t} // Copies a specified amount of characters from the list of buffered data\n\t// chunks.\n\t// This function is designed to be inlinable, so please take care when making\n\t// changes to the function body.\n\n\n\tfunction copyFromBufferString(n, list) {\n\t  var p = list.head;\n\t  var c = 1;\n\t  var ret = p.data;\n\t  n -= ret.length;\n\n\t  while (p = p.next) {\n\t    var str = p.data;\n\t    var nb = n > str.length ? str.length : n;\n\t    if (nb === str.length) ret += str;else ret += str.slice(0, n);\n\t    n -= nb;\n\n\t    if (n === 0) {\n\t      if (nb === str.length) {\n\t        ++c;\n\t        if (p.next) list.head = p.next;else list.head = list.tail = null;\n\t      } else {\n\t        list.head = p;\n\t        p.data = str.slice(nb);\n\t      }\n\n\t      break;\n\t    }\n\n\t    ++c;\n\t  }\n\n\t  list.length -= c;\n\t  return ret;\n\t} // Copies a specified amount of bytes from the list of buffered data chunks.\n\t// This function is designed to be inlinable, so please take care when making\n\t// changes to the function body.\n\n\n\tfunction copyFromBuffer(n, list) {\n\t  var ret = Buffer$1.allocUnsafe(n);\n\t  var p = list.head;\n\t  var c = 1;\n\t  p.data.copy(ret);\n\t  n -= p.data.length;\n\n\t  while (p = p.next) {\n\t    var buf = p.data;\n\t    var nb = n > buf.length ? buf.length : n;\n\t    buf.copy(ret, ret.length - n, 0, nb);\n\t    n -= nb;\n\n\t    if (n === 0) {\n\t      if (nb === buf.length) {\n\t        ++c;\n\t        if (p.next) list.head = p.next;else list.head = list.tail = null;\n\t      } else {\n\t        list.head = p;\n\t        p.data = buf.slice(nb);\n\t      }\n\n\t      break;\n\t    }\n\n\t    ++c;\n\t  }\n\n\t  list.length -= c;\n\t  return ret;\n\t}\n\n\tfunction endReadable(stream) {\n\t  var state = stream._readableState; // If we get here before consuming all the bytes, then that is a\n\t  // bug in node.  Should never happen.\n\n\t  if (state.length > 0) throw new Error('\"endReadable()\" called on non-empty stream');\n\n\t  if (!state.endEmitted) {\n\t    state.ended = true;\n\t    nextTick(endReadableNT, state, stream);\n\t  }\n\t}\n\n\tfunction endReadableNT(state, stream) {\n\t  // Check that we didn't get one last unshift.\n\t  if (!state.endEmitted && state.length === 0) {\n\t    state.endEmitted = true;\n\t    stream.readable = false;\n\t    stream.emit('end');\n\t  }\n\t}\n\n\tfunction forEach(xs, f) {\n\t  for (var i = 0, l = xs.length; i < l; i++) {\n\t    f(xs[i], i);\n\t  }\n\t}\n\n\tfunction indexOf(xs, x) {\n\t  for (var i = 0, l = xs.length; i < l; i++) {\n\t    if (xs[i] === x) return i;\n\t  }\n\n\t  return -1;\n\t}\n\n\t// A bit simpler than readable streams.\n\tWritable.WritableState = WritableState;\n\tinherits$3(Writable, EventEmitter$2);\n\n\tfunction nop() {}\n\n\tfunction WriteReq(chunk, encoding, cb) {\n\t  this.chunk = chunk;\n\t  this.encoding = encoding;\n\t  this.callback = cb;\n\t  this.next = null;\n\t}\n\n\tfunction WritableState(options, stream) {\n\t  Object.defineProperty(this, 'buffer', {\n\t    get: deprecate$1(function () {\n\t      return this.getBuffer();\n\t    }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.')\n\t  });\n\t  options = options || {}; // object stream flag to indicate whether or not this stream\n\t  // contains buffers or objects.\n\n\t  this.objectMode = !!options.objectMode;\n\t  if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false\n\t  // Note: 0 is a valid value, means that we always return false if\n\t  // the entire buffer is not flushed immediately on write()\n\n\t  var hwm = options.highWaterMark;\n\t  var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\t  this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; // cast to ints.\n\n\t  this.highWaterMark = ~~this.highWaterMark;\n\t  this.needDrain = false; // at the start of calling end()\n\n\t  this.ending = false; // when end() has been called, and returned\n\n\t  this.ended = false; // when 'finish' is emitted\n\n\t  this.finished = false; // should we decode strings into buffers before passing to _write?\n\t  // this is here so that some node-core streams can optimize string\n\t  // handling at a lower level.\n\n\t  var noDecode = options.decodeStrings === false;\n\t  this.decodeStrings = !noDecode; // Crypto is kind of old and crusty.  Historically, its default string\n\t  // encoding is 'binary' so we have to make this configurable.\n\t  // Everything else in the universe uses 'utf8', though.\n\n\t  this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement\n\t  // of how much we're waiting to get pushed to some underlying\n\t  // socket or file.\n\n\t  this.length = 0; // a flag to see when we're in the middle of a write.\n\n\t  this.writing = false; // when true all writes will be buffered until .uncork() call\n\n\t  this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately,\n\t  // or on a later tick.  We set this to true at first, because any\n\t  // actions that shouldn't happen until \"later\" should generally also\n\t  // not happen before the first write call.\n\n\t  this.sync = true; // a flag to know if we're processing previously buffered items, which\n\t  // may call the _write() callback in the same tick, so that we don't\n\t  // end up in an overlapped onwrite situation.\n\n\t  this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb)\n\n\t  this.onwrite = function (er) {\n\t    onwrite(stream, er);\n\t  }; // the callback that the user supplies to write(chunk,encoding,cb)\n\n\n\t  this.writecb = null; // the amount that is being written when _write is called.\n\n\t  this.writelen = 0;\n\t  this.bufferedRequest = null;\n\t  this.lastBufferedRequest = null; // number of pending user-supplied write callbacks\n\t  // this must be 0 before 'finish' can be emitted\n\n\t  this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs\n\t  // This is relevant for synchronous Transform streams\n\n\t  this.prefinished = false; // True if the error was already emitted and should not be thrown again\n\n\t  this.errorEmitted = false; // count buffered requests\n\n\t  this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always\n\t  // one allocated and free to use, and we maintain at most two\n\n\t  this.corkedRequestsFree = new CorkedRequest(this);\n\t}\n\n\tWritableState.prototype.getBuffer = function writableStateGetBuffer() {\n\t  var current = this.bufferedRequest;\n\t  var out = [];\n\n\t  while (current) {\n\t    out.push(current);\n\t    current = current.next;\n\t  }\n\n\t  return out;\n\t};\n\tfunction Writable(options) {\n\t  // Writable ctor is applied to Duplexes, though they're not\n\t  // instanceof Writable, they're instanceof Readable.\n\t  if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options);\n\t  this._writableState = new WritableState(options, this); // legacy.\n\n\t  this.writable = true;\n\n\t  if (options) {\n\t    if (typeof options.write === 'function') this._write = options.write;\n\t    if (typeof options.writev === 'function') this._writev = options.writev;\n\t  }\n\n\t  EventEmitter$2.call(this);\n\t} // Otherwise people can pipe Writable streams, which is just wrong.\n\n\tWritable.prototype.pipe = function () {\n\t  this.emit('error', new Error('Cannot pipe, not readable'));\n\t};\n\n\tfunction writeAfterEnd(stream, cb) {\n\t  var er = new Error('write after end'); // TODO: defer error events consistently everywhere, not just the cb\n\n\t  stream.emit('error', er);\n\t  nextTick(cb, er);\n\t} // If we get something that is not a buffer, string, null, or undefined,\n\t// and we're not in objectMode, then that's an error.\n\t// Otherwise stream chunks are all considered to be of length=1, and the\n\t// watermarks determine how many objects to keep in the buffer, rather than\n\t// how many bytes or characters.\n\n\n\tfunction validChunk(stream, state, chunk, cb) {\n\t  var valid = true;\n\t  var er = false; // Always throw error if a null is written\n\t  // if we are not in object mode then throw\n\t  // if it is not a buffer, string, or undefined.\n\n\t  if (chunk === null) {\n\t    er = new TypeError('May not write null values to stream');\n\t  } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n\t    er = new TypeError('Invalid non-string/buffer chunk');\n\t  }\n\n\t  if (er) {\n\t    stream.emit('error', er);\n\t    nextTick(cb, er);\n\t    valid = false;\n\t  }\n\n\t  return valid;\n\t}\n\n\tWritable.prototype.write = function (chunk, encoding, cb) {\n\t  var state = this._writableState;\n\t  var ret = false;\n\n\t  if (typeof encoding === 'function') {\n\t    cb = encoding;\n\t    encoding = null;\n\t  }\n\n\t  if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n\t  if (typeof cb !== 'function') cb = nop;\n\t  if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) {\n\t    state.pendingcb++;\n\t    ret = writeOrBuffer(this, state, chunk, encoding, cb);\n\t  }\n\t  return ret;\n\t};\n\n\tWritable.prototype.cork = function () {\n\t  var state = this._writableState;\n\t  state.corked++;\n\t};\n\n\tWritable.prototype.uncork = function () {\n\t  var state = this._writableState;\n\n\t  if (state.corked) {\n\t    state.corked--;\n\t    if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n\t  }\n\t};\n\n\tWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n\t  // node::ParseEncoding() requires lower case.\n\t  if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n\t  if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);\n\t  this._writableState.defaultEncoding = encoding;\n\t  return this;\n\t};\n\n\tfunction decodeChunk(state, chunk, encoding) {\n\t  if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n\t    chunk = Buffer.from(chunk, encoding);\n\t  }\n\n\t  return chunk;\n\t} // if we're already writing something, then just put this\n\t// in the queue, and wait our turn.  Otherwise, call _write\n\t// If we return false, then we need a drain event, so set that flag.\n\n\n\tfunction writeOrBuffer(stream, state, chunk, encoding, cb) {\n\t  chunk = decodeChunk(state, chunk, encoding);\n\t  if (Buffer.isBuffer(chunk)) encoding = 'buffer';\n\t  var len = state.objectMode ? 1 : chunk.length;\n\t  state.length += len;\n\t  var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false.\n\n\t  if (!ret) state.needDrain = true;\n\n\t  if (state.writing || state.corked) {\n\t    var last = state.lastBufferedRequest;\n\t    state.lastBufferedRequest = new WriteReq(chunk, encoding, cb);\n\n\t    if (last) {\n\t      last.next = state.lastBufferedRequest;\n\t    } else {\n\t      state.bufferedRequest = state.lastBufferedRequest;\n\t    }\n\n\t    state.bufferedRequestCount += 1;\n\t  } else {\n\t    doWrite(stream, state, false, len, chunk, encoding, cb);\n\t  }\n\n\t  return ret;\n\t}\n\n\tfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n\t  state.writelen = len;\n\t  state.writecb = cb;\n\t  state.writing = true;\n\t  state.sync = true;\n\t  if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n\t  state.sync = false;\n\t}\n\n\tfunction onwriteError(stream, state, sync, er, cb) {\n\t  --state.pendingcb;\n\t  if (sync) nextTick(cb, er);else cb(er);\n\t  stream._writableState.errorEmitted = true;\n\t  stream.emit('error', er);\n\t}\n\n\tfunction onwriteStateUpdate(state) {\n\t  state.writing = false;\n\t  state.writecb = null;\n\t  state.length -= state.writelen;\n\t  state.writelen = 0;\n\t}\n\n\tfunction onwrite(stream, er) {\n\t  var state = stream._writableState;\n\t  var sync = state.sync;\n\t  var cb = state.writecb;\n\t  onwriteStateUpdate(state);\n\t  if (er) onwriteError(stream, state, sync, er, cb);else {\n\t    // Check if we're actually ready to finish, but don't emit yet\n\t    var finished = needFinish(state);\n\n\t    if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n\t      clearBuffer(stream, state);\n\t    }\n\n\t    if (sync) {\n\t      /*<replacement>*/\n\t      nextTick(afterWrite, stream, state, finished, cb);\n\t      /*</replacement>*/\n\t    } else {\n\t      afterWrite(stream, state, finished, cb);\n\t    }\n\t  }\n\t}\n\n\tfunction afterWrite(stream, state, finished, cb) {\n\t  if (!finished) onwriteDrain(stream, state);\n\t  state.pendingcb--;\n\t  cb();\n\t  finishMaybe(stream, state);\n\t} // Must force callback to be called on nextTick, so that we don't\n\t// emit 'drain' before the write() consumer gets the 'false' return\n\t// value, and has a chance to attach a 'drain' listener.\n\n\n\tfunction onwriteDrain(stream, state) {\n\t  if (state.length === 0 && state.needDrain) {\n\t    state.needDrain = false;\n\t    stream.emit('drain');\n\t  }\n\t} // if there's something in the buffer waiting, then process it\n\n\n\tfunction clearBuffer(stream, state) {\n\t  state.bufferProcessing = true;\n\t  var entry = state.bufferedRequest;\n\n\t  if (stream._writev && entry && entry.next) {\n\t    // Fast case, write everything using _writev()\n\t    var l = state.bufferedRequestCount;\n\t    var buffer = new Array(l);\n\t    var holder = state.corkedRequestsFree;\n\t    holder.entry = entry;\n\t    var count = 0;\n\n\t    while (entry) {\n\t      buffer[count] = entry;\n\t      entry = entry.next;\n\t      count += 1;\n\t    }\n\n\t    doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time\n\t    // as the hot path ends with doWrite\n\n\t    state.pendingcb++;\n\t    state.lastBufferedRequest = null;\n\n\t    if (holder.next) {\n\t      state.corkedRequestsFree = holder.next;\n\t      holder.next = null;\n\t    } else {\n\t      state.corkedRequestsFree = new CorkedRequest(state);\n\t    }\n\t  } else {\n\t    // Slow case, write chunks one-by-one\n\t    while (entry) {\n\t      var chunk = entry.chunk;\n\t      var encoding = entry.encoding;\n\t      var cb = entry.callback;\n\t      var len = state.objectMode ? 1 : chunk.length;\n\t      doWrite(stream, state, false, len, chunk, encoding, cb);\n\t      entry = entry.next; // if we didn't call the onwrite immediately, then\n\t      // it means that we need to wait until it does.\n\t      // also, that means that the chunk and cb are currently\n\t      // being processed, so move the buffer counter past them.\n\n\t      if (state.writing) {\n\t        break;\n\t      }\n\t    }\n\n\t    if (entry === null) state.lastBufferedRequest = null;\n\t  }\n\n\t  state.bufferedRequestCount = 0;\n\t  state.bufferedRequest = entry;\n\t  state.bufferProcessing = false;\n\t}\n\n\tWritable.prototype._write = function (chunk, encoding, cb) {\n\t  cb(new Error('not implemented'));\n\t};\n\n\tWritable.prototype._writev = null;\n\n\tWritable.prototype.end = function (chunk, encoding, cb) {\n\t  var state = this._writableState;\n\n\t  if (typeof chunk === 'function') {\n\t    cb = chunk;\n\t    chunk = null;\n\t    encoding = null;\n\t  } else if (typeof encoding === 'function') {\n\t    cb = encoding;\n\t    encoding = null;\n\t  }\n\n\t  if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks\n\n\t  if (state.corked) {\n\t    state.corked = 1;\n\t    this.uncork();\n\t  } // ignore unnecessary end() calls.\n\n\n\t  if (!state.ending && !state.finished) endWritable(this, state, cb);\n\t};\n\n\tfunction needFinish(state) {\n\t  return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n\t}\n\n\tfunction prefinish(stream, state) {\n\t  if (!state.prefinished) {\n\t    state.prefinished = true;\n\t    stream.emit('prefinish');\n\t  }\n\t}\n\n\tfunction finishMaybe(stream, state) {\n\t  var need = needFinish(state);\n\n\t  if (need) {\n\t    if (state.pendingcb === 0) {\n\t      prefinish(stream, state);\n\t      state.finished = true;\n\t      stream.emit('finish');\n\t    } else {\n\t      prefinish(stream, state);\n\t    }\n\t  }\n\n\t  return need;\n\t}\n\n\tfunction endWritable(stream, state, cb) {\n\t  state.ending = true;\n\t  finishMaybe(stream, state);\n\n\t  if (cb) {\n\t    if (state.finished) nextTick(cb);else stream.once('finish', cb);\n\t  }\n\n\t  state.ended = true;\n\t  stream.writable = false;\n\t} // It seems a linked list but it is not\n\t// there will be only 2 of these for each stream\n\n\n\tfunction CorkedRequest(state) {\n\t  var _this = this;\n\n\t  this.next = null;\n\t  this.entry = null;\n\n\t  this.finish = function (err) {\n\t    var entry = _this.entry;\n\t    _this.entry = null;\n\n\t    while (entry) {\n\t      var cb = entry.callback;\n\t      state.pendingcb--;\n\t      cb(err);\n\t      entry = entry.next;\n\t    }\n\n\t    if (state.corkedRequestsFree) {\n\t      state.corkedRequestsFree.next = _this;\n\t    } else {\n\t      state.corkedRequestsFree = _this;\n\t    }\n\t  };\n\t}\n\n\tinherits$3(Duplex, Readable);\n\tvar keys = Object.keys(Writable.prototype);\n\n\tfor (var v = 0; v < keys.length; v++) {\n\t  var method = keys[v];\n\t  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n\t}\n\tfunction Duplex(options) {\n\t  if (!(this instanceof Duplex)) return new Duplex(options);\n\t  Readable.call(this, options);\n\t  Writable.call(this, options);\n\t  if (options && options.readable === false) this.readable = false;\n\t  if (options && options.writable === false) this.writable = false;\n\t  this.allowHalfOpen = true;\n\t  if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;\n\t  this.once('end', onend);\n\t} // the no-half-open enforcer\n\n\tfunction onend() {\n\t  // if we allow half-open state, or if the writable side ended,\n\t  // then we're ok.\n\t  if (this.allowHalfOpen || this._writableState.ended) return; // no more data can be written.\n\t  // But allow more writes to happen in this tick.\n\n\t  nextTick(onEndNT, this);\n\t}\n\n\tfunction onEndNT(self) {\n\t  self.end();\n\t}\n\n\t// a transform stream is a readable/writable stream where you do\n\tinherits$3(Transform, Duplex);\n\n\tfunction TransformState(stream) {\n\t  this.afterTransform = function (er, data) {\n\t    return afterTransform(stream, er, data);\n\t  };\n\n\t  this.needTransform = false;\n\t  this.transforming = false;\n\t  this.writecb = null;\n\t  this.writechunk = null;\n\t  this.writeencoding = null;\n\t}\n\n\tfunction afterTransform(stream, er, data) {\n\t  var ts = stream._transformState;\n\t  ts.transforming = false;\n\t  var cb = ts.writecb;\n\t  if (!cb) return stream.emit('error', new Error('no writecb in Transform class'));\n\t  ts.writechunk = null;\n\t  ts.writecb = null;\n\t  if (data !== null && data !== undefined) stream.push(data);\n\t  cb(er);\n\t  var rs = stream._readableState;\n\t  rs.reading = false;\n\n\t  if (rs.needReadable || rs.length < rs.highWaterMark) {\n\t    stream._read(rs.highWaterMark);\n\t  }\n\t}\n\tfunction Transform(options) {\n\t  if (!(this instanceof Transform)) return new Transform(options);\n\t  Duplex.call(this, options);\n\t  this._transformState = new TransformState(this); // when the writable side finishes, then flush out anything remaining.\n\n\t  var stream = this; // start out asking for a readable event once data is transformed.\n\n\t  this._readableState.needReadable = true; // we have implemented the _read method, and done the other things\n\t  // that Readable wants before the first _read call, so unset the\n\t  // sync guard flag.\n\n\t  this._readableState.sync = false;\n\n\t  if (options) {\n\t    if (typeof options.transform === 'function') this._transform = options.transform;\n\t    if (typeof options.flush === 'function') this._flush = options.flush;\n\t  }\n\n\t  this.once('prefinish', function () {\n\t    if (typeof this._flush === 'function') this._flush(function (er) {\n\t      done(stream, er);\n\t    });else done(stream);\n\t  });\n\t}\n\n\tTransform.prototype.push = function (chunk, encoding) {\n\t  this._transformState.needTransform = false;\n\t  return Duplex.prototype.push.call(this, chunk, encoding);\n\t}; // This is the part where you do stuff!\n\t// override this function in implementation classes.\n\t// 'chunk' is an input chunk.\n\t//\n\t// Call `push(newChunk)` to pass along transformed output\n\t// to the readable side.  You may call 'push' zero or more times.\n\t//\n\t// Call `cb(err)` when you are done with this chunk.  If you pass\n\t// an error, then that'll put the hurt on the whole operation.  If you\n\t// never call cb(), then you'll never get another chunk.\n\n\n\tTransform.prototype._transform = function (chunk, encoding, cb) {\n\t  throw new Error('Not implemented');\n\t};\n\n\tTransform.prototype._write = function (chunk, encoding, cb) {\n\t  var ts = this._transformState;\n\t  ts.writecb = cb;\n\t  ts.writechunk = chunk;\n\t  ts.writeencoding = encoding;\n\n\t  if (!ts.transforming) {\n\t    var rs = this._readableState;\n\t    if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n\t  }\n\t}; // Doesn't matter what the args are here.\n\t// _transform does all the work.\n\t// That we got here means that the readable side wants more data.\n\n\n\tTransform.prototype._read = function (n) {\n\t  var ts = this._transformState;\n\n\t  if (ts.writechunk !== null && ts.writecb && !ts.transforming) {\n\t    ts.transforming = true;\n\n\t    this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n\t  } else {\n\t    // mark that we need a transform, so that any data that comes in\n\t    // will get processed, now that we've asked for it.\n\t    ts.needTransform = true;\n\t  }\n\t};\n\n\tfunction done(stream, er) {\n\t  if (er) return stream.emit('error', er); // if there's nothing in the write buffer, then that means\n\t  // that nothing more will ever be provided\n\n\t  var ws = stream._writableState;\n\t  var ts = stream._transformState;\n\t  if (ws.length) throw new Error('Calling transform done when ws.length != 0');\n\t  if (ts.transforming) throw new Error('Calling transform done when still transforming');\n\t  return stream.push(null);\n\t}\n\n\tinherits$3(PassThrough, Transform);\n\tfunction PassThrough(options) {\n\t  if (!(this instanceof PassThrough)) return new PassThrough(options);\n\t  Transform.call(this, options);\n\t}\n\n\tPassThrough.prototype._transform = function (chunk, encoding, cb) {\n\t  cb(null, chunk);\n\t};\n\n\tinherits$3(Stream, EventEmitter$2);\n\tStream.Readable = Readable;\n\tStream.Writable = Writable;\n\tStream.Duplex = Duplex;\n\tStream.Transform = Transform;\n\tStream.PassThrough = PassThrough; // Backwards-compat with node 0.4.x\n\n\tStream.Stream = Stream;\n\t// part of this class) is overridden in the Readable class.\n\n\tfunction Stream() {\n\t  EventEmitter$2.call(this);\n\t}\n\n\tStream.prototype.pipe = function (dest, options) {\n\t  var source = this;\n\n\t  function ondata(chunk) {\n\t    if (dest.writable) {\n\t      if (false === dest.write(chunk) && source.pause) {\n\t        source.pause();\n\t      }\n\t    }\n\t  }\n\n\t  source.on('data', ondata);\n\n\t  function ondrain() {\n\t    if (source.readable && source.resume) {\n\t      source.resume();\n\t    }\n\t  }\n\n\t  dest.on('drain', ondrain); // If the 'end' option is not supplied, dest.end() will be called when\n\t  // source gets the 'end' or 'close' events.  Only dest.end() once.\n\n\t  if (!dest._isStdio && (!options || options.end !== false)) {\n\t    source.on('end', onend);\n\t    source.on('close', onclose);\n\t  }\n\n\t  var didOnEnd = false;\n\n\t  function onend() {\n\t    if (didOnEnd) return;\n\t    didOnEnd = true;\n\t    dest.end();\n\t  }\n\n\t  function onclose() {\n\t    if (didOnEnd) return;\n\t    didOnEnd = true;\n\t    if (typeof dest.destroy === 'function') dest.destroy();\n\t  } // don't leave dangling pipes when there are errors.\n\n\n\t  function onerror(er) {\n\t    cleanup();\n\n\t    if (EventEmitter$2.listenerCount(this, 'error') === 0) {\n\t      throw er; // Unhandled stream error in pipe.\n\t    }\n\t  }\n\n\t  source.on('error', onerror);\n\t  dest.on('error', onerror); // remove all the event listeners that were added.\n\n\t  function cleanup() {\n\t    source.removeListener('data', ondata);\n\t    dest.removeListener('drain', ondrain);\n\t    source.removeListener('end', onend);\n\t    source.removeListener('close', onclose);\n\t    source.removeListener('error', onerror);\n\t    dest.removeListener('error', onerror);\n\t    source.removeListener('end', cleanup);\n\t    source.removeListener('close', cleanup);\n\t    dest.removeListener('close', cleanup);\n\t  }\n\n\t  source.on('end', cleanup);\n\t  source.on('close', cleanup);\n\t  dest.on('close', cleanup);\n\t  dest.emit('pipe', source); // Allow for unix-like usage: A.pipe(B).pipe(C)\n\n\t  return dest;\n\t};\n\n\tvar WritableStream = Stream.Writable;\n\tvar inherits$1 = util.inherits;\n\tvar browserStdout = BrowserStdout;\n\tinherits$1(BrowserStdout, WritableStream);\n\n\tfunction BrowserStdout(opts) {\n\t  if (!(this instanceof BrowserStdout)) return new BrowserStdout(opts);\n\t  opts = opts || {};\n\t  WritableStream.call(this, opts);\n\t  this.label = opts.label !== undefined ? opts.label : 'stdout';\n\t}\n\n\tBrowserStdout.prototype._write = function (chunks, encoding, cb) {\n\t  var output = chunks.toString ? chunks.toString() : chunks;\n\n\t  if (this.label === false) {\n\t    console.log(output);\n\t  } else {\n\t    console.log(this.label + ':', output);\n\t  }\n\n\t  nextTick$1(cb);\n\t};\n\n\tvar parseQuery = function parseQuery(qs) {\n\t  return qs.replace('?', '').split('&').reduce(function (obj, pair) {\n\t    var i = pair.indexOf('=');\n\t    var key = pair.slice(0, i);\n\t    var val = pair.slice(++i); // Due to how the URLSearchParams API treats spaces\n\n\t    obj[key] = decodeURIComponent(val.replace(/\\+/g, '%20'));\n\t    return obj;\n\t  }, {});\n\t};\n\n\tfunction highlight(js) {\n\t  return js.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\\/\\/(.*)/gm, '<span class=\"comment\">//$1</span>').replace(/('.*?')/gm, '<span class=\"string\">$1</span>').replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>').replace(/(\\d+)/gm, '<span class=\"number\">$1</span>').replace(/\\bnew[ \\t]+(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>').replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>');\n\t}\n\t/**\n\t * Highlight the contents of tag `name`.\n\t *\n\t * @private\n\t * @param {string} name\n\t */\n\n\n\tvar highlightTags = function highlightTags(name) {\n\t  var code = document.getElementById('mocha').getElementsByTagName(name);\n\n\t  for (var i = 0, len = code.length; i < len; ++i) {\n\t    code[i].innerHTML = highlight(code[i].innerHTML);\n\t  }\n\t};\n\n\t// `Symbol.iterator` well-known symbol\n\t// https://tc39.es/ecma262/#sec-symbol.iterator\n\tdefineWellKnownSymbol('iterator');\n\n\tvar charAt = stringMultibyte.charAt;\n\n\n\n\n\tvar STRING_ITERATOR = 'String Iterator';\n\tvar setInternalState$2 = internalState.set;\n\tvar getInternalState$1 = internalState.getterFor(STRING_ITERATOR);\n\n\t// `String.prototype[@@iterator]` method\n\t// https://tc39.es/ecma262/#sec-string.prototype-@@iterator\n\tdefineIterator(String, 'String', function (iterated) {\n\t  setInternalState$2(this, {\n\t    type: STRING_ITERATOR,\n\t    string: toString_1(iterated),\n\t    index: 0\n\t  });\n\t// `%StringIteratorPrototype%.next` method\n\t// https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next\n\t}, function next() {\n\t  var state = getInternalState$1(this);\n\t  var string = state.string;\n\t  var index = state.index;\n\t  var point;\n\t  if (index >= string.length) return { value: undefined, done: true };\n\t  point = charAt(string, index);\n\t  state.index += point.length;\n\t  return { value: point, done: false };\n\t});\n\n\tvar ITERATOR = wellKnownSymbol('iterator');\n\tvar TO_STRING_TAG = wellKnownSymbol('toStringTag');\n\tvar ArrayValues = es_array_iterator.values;\n\n\tvar handlePrototype = function (CollectionPrototype, COLLECTION_NAME) {\n\t  if (CollectionPrototype) {\n\t    // some Chrome versions have non-configurable methods on DOMTokenList\n\t    if (CollectionPrototype[ITERATOR] !== ArrayValues) try {\n\t      createNonEnumerableProperty(CollectionPrototype, ITERATOR, ArrayValues);\n\t    } catch (error) {\n\t      CollectionPrototype[ITERATOR] = ArrayValues;\n\t    }\n\t    if (!CollectionPrototype[TO_STRING_TAG]) {\n\t      createNonEnumerableProperty(CollectionPrototype, TO_STRING_TAG, COLLECTION_NAME);\n\t    }\n\t    if (domIterables[COLLECTION_NAME]) for (var METHOD_NAME in es_array_iterator) {\n\t      // some Chrome versions have non-configurable methods on DOMTokenList\n\t      if (CollectionPrototype[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {\n\t        createNonEnumerableProperty(CollectionPrototype, METHOD_NAME, es_array_iterator[METHOD_NAME]);\n\t      } catch (error) {\n\t        CollectionPrototype[METHOD_NAME] = es_array_iterator[METHOD_NAME];\n\t      }\n\t    }\n\t  }\n\t};\n\n\tfor (var COLLECTION_NAME in domIterables) {\n\t  handlePrototype(global_1[COLLECTION_NAME] && global_1[COLLECTION_NAME].prototype, COLLECTION_NAME);\n\t}\n\n\thandlePrototype(domTokenListPrototype, 'DOMTokenList');\n\n\t// `Symbol.asyncIterator` well-known symbol\n\t// https://tc39.es/ecma262/#sec-symbol.asynciterator\n\tdefineWellKnownSymbol('asyncIterator');\n\n\t// `Symbol.toStringTag` well-known symbol\n\t// https://tc39.es/ecma262/#sec-symbol.tostringtag\n\tdefineWellKnownSymbol('toStringTag');\n\n\t// JSON[@@toStringTag] property\n\t// https://tc39.es/ecma262/#sec-json-@@tostringtag\n\tsetToStringTag(global_1.JSON, 'JSON', true);\n\n\t// Math[@@toStringTag] property\n\t// https://tc39.es/ecma262/#sec-math-@@tostringtag\n\tsetToStringTag(Math, 'Math', true);\n\n\tvar nativePromiseConstructor = global_1.Promise;\n\n\tvar iteratorClose = function (iterator, kind, value) {\n\t  var innerResult, innerError;\n\t  anObject(iterator);\n\t  try {\n\t    innerResult = getMethod(iterator, 'return');\n\t    if (!innerResult) {\n\t      if (kind === 'throw') throw value;\n\t      return value;\n\t    }\n\t    innerResult = functionCall(innerResult, iterator);\n\t  } catch (error) {\n\t    innerError = true;\n\t    innerResult = error;\n\t  }\n\t  if (kind === 'throw') throw value;\n\t  if (innerError) throw innerResult;\n\t  anObject(innerResult);\n\t  return value;\n\t};\n\n\tvar TypeError$3 = global_1.TypeError;\n\n\tvar Result = function (stopped, result) {\n\t  this.stopped = stopped;\n\t  this.result = result;\n\t};\n\n\tvar ResultPrototype = Result.prototype;\n\n\tvar iterate = function (iterable, unboundFunction, options) {\n\t  var that = options && options.that;\n\t  var AS_ENTRIES = !!(options && options.AS_ENTRIES);\n\t  var IS_ITERATOR = !!(options && options.IS_ITERATOR);\n\t  var INTERRUPTED = !!(options && options.INTERRUPTED);\n\t  var fn = functionBindContext(unboundFunction, that);\n\t  var iterator, iterFn, index, length, result, next, step;\n\n\t  var stop = function (condition) {\n\t    if (iterator) iteratorClose(iterator, 'normal', condition);\n\t    return new Result(true, condition);\n\t  };\n\n\t  var callFn = function (value) {\n\t    if (AS_ENTRIES) {\n\t      anObject(value);\n\t      return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);\n\t    } return INTERRUPTED ? fn(value, stop) : fn(value);\n\t  };\n\n\t  if (IS_ITERATOR) {\n\t    iterator = iterable;\n\t  } else {\n\t    iterFn = getIteratorMethod(iterable);\n\t    if (!iterFn) throw TypeError$3(tryToString(iterable) + ' is not iterable');\n\t    // optimisation for array iterators\n\t    if (isArrayIteratorMethod(iterFn)) {\n\t      for (index = 0, length = lengthOfArrayLike(iterable); length > index; index++) {\n\t        result = callFn(iterable[index]);\n\t        if (result && objectIsPrototypeOf(ResultPrototype, result)) return result;\n\t      } return new Result(false);\n\t    }\n\t    iterator = getIterator(iterable, iterFn);\n\t  }\n\n\t  next = iterator.next;\n\t  while (!(step = functionCall(next, iterator)).done) {\n\t    try {\n\t      result = callFn(step.value);\n\t    } catch (error) {\n\t      iteratorClose(iterator, 'throw', error);\n\t    }\n\t    if (typeof result == 'object' && result && objectIsPrototypeOf(ResultPrototype, result)) return result;\n\t  } return new Result(false);\n\t};\n\n\tvar TypeError$2 = global_1.TypeError;\n\n\tvar validateArgumentsLength = function (passed, required) {\n\t  if (passed < required) throw TypeError$2('Not enough arguments');\n\t  return passed;\n\t};\n\n\tvar engineIsIos = /(?:ipad|iphone|ipod).*applewebkit/i.test(engineUserAgent);\n\n\tvar engineIsNode = classofRaw(global_1.process) == 'process';\n\n\tvar set = global_1.setImmediate;\n\tvar clear = global_1.clearImmediate;\n\tvar process$2 = global_1.process;\n\tvar Dispatch = global_1.Dispatch;\n\tvar Function$1 = global_1.Function;\n\tvar MessageChannel = global_1.MessageChannel;\n\tvar String$2 = global_1.String;\n\tvar counter = 0;\n\tvar queue$1 = {};\n\tvar ONREADYSTATECHANGE = 'onreadystatechange';\n\tvar location$1, defer, channel, port;\n\n\ttry {\n\t  // Deno throws a ReferenceError on `location` access without `--location` flag\n\t  location$1 = global_1.location;\n\t} catch (error) { /* empty */ }\n\n\tvar run = function (id) {\n\t  if (hasOwnProperty_1(queue$1, id)) {\n\t    var fn = queue$1[id];\n\t    delete queue$1[id];\n\t    fn();\n\t  }\n\t};\n\n\tvar runner$1 = function (id) {\n\t  return function () {\n\t    run(id);\n\t  };\n\t};\n\n\tvar listener = function (event) {\n\t  run(event.data);\n\t};\n\n\tvar post = function (id) {\n\t  // old engines have not location.origin\n\t  global_1.postMessage(String$2(id), location$1.protocol + '//' + location$1.host);\n\t};\n\n\t// Node.js 0.9+ & IE10+ has setImmediate, otherwise:\n\tif (!set || !clear) {\n\t  set = function setImmediate(handler) {\n\t    validateArgumentsLength(arguments.length, 1);\n\t    var fn = isCallable(handler) ? handler : Function$1(handler);\n\t    var args = arraySlice(arguments, 1);\n\t    queue$1[++counter] = function () {\n\t      functionApply(fn, undefined, args);\n\t    };\n\t    defer(counter);\n\t    return counter;\n\t  };\n\t  clear = function clearImmediate(id) {\n\t    delete queue$1[id];\n\t  };\n\t  // Node.js 0.8-\n\t  if (engineIsNode) {\n\t    defer = function (id) {\n\t      process$2.nextTick(runner$1(id));\n\t    };\n\t  // Sphere (JS game engine) Dispatch API\n\t  } else if (Dispatch && Dispatch.now) {\n\t    defer = function (id) {\n\t      Dispatch.now(runner$1(id));\n\t    };\n\t  // Browsers with MessageChannel, includes WebWorkers\n\t  // except iOS - https://github.com/zloirock/core-js/issues/624\n\t  } else if (MessageChannel && !engineIsIos) {\n\t    channel = new MessageChannel();\n\t    port = channel.port2;\n\t    channel.port1.onmessage = listener;\n\t    defer = functionBindContext(port.postMessage, port);\n\t  // Browsers with postMessage, skip WebWorkers\n\t  // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'\n\t  } else if (\n\t    global_1.addEventListener &&\n\t    isCallable(global_1.postMessage) &&\n\t    !global_1.importScripts &&\n\t    location$1 && location$1.protocol !== 'file:' &&\n\t    !fails(post)\n\t  ) {\n\t    defer = post;\n\t    global_1.addEventListener('message', listener, false);\n\t  // IE8-\n\t  } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {\n\t    defer = function (id) {\n\t      html$1.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {\n\t        html$1.removeChild(this);\n\t        run(id);\n\t      };\n\t    };\n\t  // Rest old browsers\n\t  } else {\n\t    defer = function (id) {\n\t      setTimeout(runner$1(id), 0);\n\t    };\n\t  }\n\t}\n\n\tvar task$1 = {\n\t  set: set,\n\t  clear: clear\n\t};\n\n\tvar engineIsIosPebble = /ipad|iphone|ipod/i.test(engineUserAgent) && global_1.Pebble !== undefined;\n\n\tvar engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(engineUserAgent);\n\n\tvar getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;\n\tvar macrotask = task$1.set;\n\n\n\n\n\n\tvar MutationObserver = global_1.MutationObserver || global_1.WebKitMutationObserver;\n\tvar document$2 = global_1.document;\n\tvar process$1 = global_1.process;\n\tvar Promise$1 = global_1.Promise;\n\t// Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`\n\tvar queueMicrotaskDescriptor = getOwnPropertyDescriptor(global_1, 'queueMicrotask');\n\tvar queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;\n\n\tvar flush, head, last, notify$2, toggle, node, promise, then;\n\n\t// modern engines have queueMicrotask method\n\tif (!queueMicrotask) {\n\t  flush = function () {\n\t    var parent, fn;\n\t    if (engineIsNode && (parent = process$1.domain)) parent.exit();\n\t    while (head) {\n\t      fn = head.fn;\n\t      head = head.next;\n\t      try {\n\t        fn();\n\t      } catch (error) {\n\t        if (head) notify$2();\n\t        else last = undefined;\n\t        throw error;\n\t      }\n\t    } last = undefined;\n\t    if (parent) parent.enter();\n\t  };\n\n\t  // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339\n\t  // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898\n\t  if (!engineIsIos && !engineIsNode && !engineIsWebosWebkit && MutationObserver && document$2) {\n\t    toggle = true;\n\t    node = document$2.createTextNode('');\n\t    new MutationObserver(flush).observe(node, { characterData: true });\n\t    notify$2 = function () {\n\t      node.data = toggle = !toggle;\n\t    };\n\t  // environments with maybe non-completely correct, but existent Promise\n\t  } else if (!engineIsIosPebble && Promise$1 && Promise$1.resolve) {\n\t    // Promise.resolve without an argument throws an error in LG WebOS 2\n\t    promise = Promise$1.resolve(undefined);\n\t    // workaround of WebKit ~ iOS Safari 10.1 bug\n\t    promise.constructor = Promise$1;\n\t    then = functionBindContext(promise.then, promise);\n\t    notify$2 = function () {\n\t      then(flush);\n\t    };\n\t  // Node.js without promises\n\t  } else if (engineIsNode) {\n\t    notify$2 = function () {\n\t      process$1.nextTick(flush);\n\t    };\n\t  // for other environments - macrotask based on:\n\t  // - setImmediate\n\t  // - MessageChannel\n\t  // - window.postMessag\n\t  // - onreadystatechange\n\t  // - setTimeout\n\t  } else {\n\t    // strange IE + webpack dev server bug - use .bind(global)\n\t    macrotask = functionBindContext(macrotask, global_1);\n\t    notify$2 = function () {\n\t      macrotask(flush);\n\t    };\n\t  }\n\t}\n\n\tvar microtask = queueMicrotask || function (fn) {\n\t  var task = { fn: fn, next: undefined };\n\t  if (last) last.next = task;\n\t  if (!head) {\n\t    head = task;\n\t    notify$2();\n\t  } last = task;\n\t};\n\n\tvar PromiseCapability = function (C) {\n\t  var resolve, reject;\n\t  this.promise = new C(function ($$resolve, $$reject) {\n\t    if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');\n\t    resolve = $$resolve;\n\t    reject = $$reject;\n\t  });\n\t  this.resolve = aCallable(resolve);\n\t  this.reject = aCallable(reject);\n\t};\n\n\t// `NewPromiseCapability` abstract operation\n\t// https://tc39.es/ecma262/#sec-newpromisecapability\n\tvar f = function (C) {\n\t  return new PromiseCapability(C);\n\t};\n\n\tvar newPromiseCapability$1 = {\n\t\tf: f\n\t};\n\n\tvar promiseResolve = function (C, x) {\n\t  anObject(C);\n\t  if (isObject$1(x) && x.constructor === C) return x;\n\t  var promiseCapability = newPromiseCapability$1.f(C);\n\t  var resolve = promiseCapability.resolve;\n\t  resolve(x);\n\t  return promiseCapability.promise;\n\t};\n\n\tvar hostReportErrors = function (a, b) {\n\t  var console = global_1.console;\n\t  if (console && console.error) {\n\t    arguments.length == 1 ? console.error(a) : console.error(a, b);\n\t  }\n\t};\n\n\tvar perform = function (exec) {\n\t  try {\n\t    return { error: false, value: exec() };\n\t  } catch (error) {\n\t    return { error: true, value: error };\n\t  }\n\t};\n\n\tvar Queue = function () {\n\t  this.head = null;\n\t  this.tail = null;\n\t};\n\n\tQueue.prototype = {\n\t  add: function (item) {\n\t    var entry = { item: item, next: null };\n\t    if (this.head) this.tail.next = entry;\n\t    else this.head = entry;\n\t    this.tail = entry;\n\t  },\n\t  get: function () {\n\t    var entry = this.head;\n\t    if (entry) {\n\t      this.head = entry.next;\n\t      if (this.tail === entry) this.tail = null;\n\t      return entry.item;\n\t    }\n\t  }\n\t};\n\n\tvar queue = Queue;\n\n\tvar engineIsBrowser = typeof window == 'object';\n\n\tvar task = task$1.set;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\tvar SPECIES = wellKnownSymbol('species');\n\tvar PROMISE = 'Promise';\n\n\tvar getInternalState = internalState.getterFor(PROMISE);\n\tvar setInternalState$1 = internalState.set;\n\tvar getInternalPromiseState = internalState.getterFor(PROMISE);\n\tvar NativePromisePrototype = nativePromiseConstructor && nativePromiseConstructor.prototype;\n\tvar PromiseConstructor = nativePromiseConstructor;\n\tvar PromisePrototype = NativePromisePrototype;\n\tvar TypeError$1 = global_1.TypeError;\n\tvar document$1 = global_1.document;\n\tvar process = global_1.process;\n\tvar newPromiseCapability = newPromiseCapability$1.f;\n\tvar newGenericPromiseCapability = newPromiseCapability;\n\n\tvar DISPATCH_EVENT = !!(document$1 && document$1.createEvent && global_1.dispatchEvent);\n\tvar NATIVE_REJECTION_EVENT = isCallable(global_1.PromiseRejectionEvent);\n\tvar UNHANDLED_REJECTION = 'unhandledrejection';\n\tvar REJECTION_HANDLED = 'rejectionhandled';\n\tvar PENDING = 0;\n\tvar FULFILLED = 1;\n\tvar REJECTED = 2;\n\tvar HANDLED = 1;\n\tvar UNHANDLED = 2;\n\tvar SUBCLASSING = false;\n\n\tvar Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;\n\n\tvar FORCED$2 = isForced_1(PROMISE, function () {\n\t  var PROMISE_CONSTRUCTOR_SOURCE = inspectSource(PromiseConstructor);\n\t  var GLOBAL_CORE_JS_PROMISE = PROMISE_CONSTRUCTOR_SOURCE !== String(PromiseConstructor);\n\t  // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables\n\t  // https://bugs.chromium.org/p/chromium/issues/detail?id=830565\n\t  // We can't detect it synchronously, so just check versions\n\t  if (!GLOBAL_CORE_JS_PROMISE && engineV8Version === 66) return true;\n\t  // We can't use @@species feature detection in V8 since it causes\n\t  // deoptimization and performance degradation\n\t  // https://github.com/zloirock/core-js/issues/679\n\t  if (engineV8Version >= 51 && /native code/.test(PROMISE_CONSTRUCTOR_SOURCE)) return false;\n\t  // Detect correctness of subclassing with @@species support\n\t  var promise = new PromiseConstructor(function (resolve) { resolve(1); });\n\t  var FakePromise = function (exec) {\n\t    exec(function () { /* empty */ }, function () { /* empty */ });\n\t  };\n\t  var constructor = promise.constructor = {};\n\t  constructor[SPECIES] = FakePromise;\n\t  SUBCLASSING = promise.then(function () { /* empty */ }) instanceof FakePromise;\n\t  if (!SUBCLASSING) return true;\n\t  // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test\n\t  return !GLOBAL_CORE_JS_PROMISE && engineIsBrowser && !NATIVE_REJECTION_EVENT;\n\t});\n\n\tvar INCORRECT_ITERATION$1 = FORCED$2 || !checkCorrectnessOfIteration(function (iterable) {\n\t  PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });\n\t});\n\n\t// helpers\n\tvar isThenable = function (it) {\n\t  var then;\n\t  return isObject$1(it) && isCallable(then = it.then) ? then : false;\n\t};\n\n\tvar callReaction = function (reaction, state) {\n\t  var value = state.value;\n\t  var ok = state.state == FULFILLED;\n\t  var handler = ok ? reaction.ok : reaction.fail;\n\t  var resolve = reaction.resolve;\n\t  var reject = reaction.reject;\n\t  var domain = reaction.domain;\n\t  var result, then, exited;\n\t  try {\n\t    if (handler) {\n\t      if (!ok) {\n\t        if (state.rejection === UNHANDLED) onHandleUnhandled(state);\n\t        state.rejection = HANDLED;\n\t      }\n\t      if (handler === true) result = value;\n\t      else {\n\t        if (domain) domain.enter();\n\t        result = handler(value); // can throw\n\t        if (domain) {\n\t          domain.exit();\n\t          exited = true;\n\t        }\n\t      }\n\t      if (result === reaction.promise) {\n\t        reject(TypeError$1('Promise-chain cycle'));\n\t      } else if (then = isThenable(result)) {\n\t        functionCall(then, result, resolve, reject);\n\t      } else resolve(result);\n\t    } else reject(value);\n\t  } catch (error) {\n\t    if (domain && !exited) domain.exit();\n\t    reject(error);\n\t  }\n\t};\n\n\tvar notify$1 = function (state, isReject) {\n\t  if (state.notified) return;\n\t  state.notified = true;\n\t  microtask(function () {\n\t    var reactions = state.reactions;\n\t    var reaction;\n\t    while (reaction = reactions.get()) {\n\t      callReaction(reaction, state);\n\t    }\n\t    state.notified = false;\n\t    if (isReject && !state.rejection) onUnhandled(state);\n\t  });\n\t};\n\n\tvar dispatchEvent = function (name, promise, reason) {\n\t  var event, handler;\n\t  if (DISPATCH_EVENT) {\n\t    event = document$1.createEvent('Event');\n\t    event.promise = promise;\n\t    event.reason = reason;\n\t    event.initEvent(name, false, true);\n\t    global_1.dispatchEvent(event);\n\t  } else event = { promise: promise, reason: reason };\n\t  if (!NATIVE_REJECTION_EVENT && (handler = global_1['on' + name])) handler(event);\n\t  else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);\n\t};\n\n\tvar onUnhandled = function (state) {\n\t  functionCall(task, global_1, function () {\n\t    var promise = state.facade;\n\t    var value = state.value;\n\t    var IS_UNHANDLED = isUnhandled(state);\n\t    var result;\n\t    if (IS_UNHANDLED) {\n\t      result = perform(function () {\n\t        if (engineIsNode) {\n\t          process.emit('unhandledRejection', value, promise);\n\t        } else dispatchEvent(UNHANDLED_REJECTION, promise, value);\n\t      });\n\t      // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should\n\t      state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;\n\t      if (result.error) throw result.value;\n\t    }\n\t  });\n\t};\n\n\tvar isUnhandled = function (state) {\n\t  return state.rejection !== HANDLED && !state.parent;\n\t};\n\n\tvar onHandleUnhandled = function (state) {\n\t  functionCall(task, global_1, function () {\n\t    var promise = state.facade;\n\t    if (engineIsNode) {\n\t      process.emit('rejectionHandled', promise);\n\t    } else dispatchEvent(REJECTION_HANDLED, promise, state.value);\n\t  });\n\t};\n\n\tvar bind = function (fn, state, unwrap) {\n\t  return function (value) {\n\t    fn(state, value, unwrap);\n\t  };\n\t};\n\n\tvar internalReject = function (state, value, unwrap) {\n\t  if (state.done) return;\n\t  state.done = true;\n\t  if (unwrap) state = unwrap;\n\t  state.value = value;\n\t  state.state = REJECTED;\n\t  notify$1(state, true);\n\t};\n\n\tvar internalResolve = function (state, value, unwrap) {\n\t  if (state.done) return;\n\t  state.done = true;\n\t  if (unwrap) state = unwrap;\n\t  try {\n\t    if (state.facade === value) throw TypeError$1(\"Promise can't be resolved itself\");\n\t    var then = isThenable(value);\n\t    if (then) {\n\t      microtask(function () {\n\t        var wrapper = { done: false };\n\t        try {\n\t          functionCall(then, value,\n\t            bind(internalResolve, wrapper, state),\n\t            bind(internalReject, wrapper, state)\n\t          );\n\t        } catch (error) {\n\t          internalReject(wrapper, error, state);\n\t        }\n\t      });\n\t    } else {\n\t      state.value = value;\n\t      state.state = FULFILLED;\n\t      notify$1(state, false);\n\t    }\n\t  } catch (error) {\n\t    internalReject({ done: false }, error, state);\n\t  }\n\t};\n\n\t// constructor polyfill\n\tif (FORCED$2) {\n\t  // 25.4.3.1 Promise(executor)\n\t  PromiseConstructor = function Promise(executor) {\n\t    anInstance(this, PromisePrototype);\n\t    aCallable(executor);\n\t    functionCall(Internal, this);\n\t    var state = getInternalState(this);\n\t    try {\n\t      executor(bind(internalResolve, state), bind(internalReject, state));\n\t    } catch (error) {\n\t      internalReject(state, error);\n\t    }\n\t  };\n\t  PromisePrototype = PromiseConstructor.prototype;\n\t  // eslint-disable-next-line no-unused-vars -- required for `.length`\n\t  Internal = function Promise(executor) {\n\t    setInternalState$1(this, {\n\t      type: PROMISE,\n\t      done: false,\n\t      notified: false,\n\t      parent: false,\n\t      reactions: new queue(),\n\t      rejection: false,\n\t      state: PENDING,\n\t      value: undefined\n\t    });\n\t  };\n\t  Internal.prototype = redefineAll(PromisePrototype, {\n\t    // `Promise.prototype.then` method\n\t    // https://tc39.es/ecma262/#sec-promise.prototype.then\n\t    // eslint-disable-next-line unicorn/no-thenable -- safe\n\t    then: function then(onFulfilled, onRejected) {\n\t      var state = getInternalPromiseState(this);\n\t      var reaction = newPromiseCapability(speciesConstructor(this, PromiseConstructor));\n\t      state.parent = true;\n\t      reaction.ok = isCallable(onFulfilled) ? onFulfilled : true;\n\t      reaction.fail = isCallable(onRejected) && onRejected;\n\t      reaction.domain = engineIsNode ? process.domain : undefined;\n\t      if (state.state == PENDING) state.reactions.add(reaction);\n\t      else microtask(function () {\n\t        callReaction(reaction, state);\n\t      });\n\t      return reaction.promise;\n\t    },\n\t    // `Promise.prototype.catch` method\n\t    // https://tc39.es/ecma262/#sec-promise.prototype.catch\n\t    'catch': function (onRejected) {\n\t      return this.then(undefined, onRejected);\n\t    }\n\t  });\n\t  OwnPromiseCapability = function () {\n\t    var promise = new Internal();\n\t    var state = getInternalState(promise);\n\t    this.promise = promise;\n\t    this.resolve = bind(internalResolve, state);\n\t    this.reject = bind(internalReject, state);\n\t  };\n\t  newPromiseCapability$1.f = newPromiseCapability = function (C) {\n\t    return C === PromiseConstructor || C === PromiseWrapper\n\t      ? new OwnPromiseCapability(C)\n\t      : newGenericPromiseCapability(C);\n\t  };\n\n\t  if (isCallable(nativePromiseConstructor) && NativePromisePrototype !== Object.prototype) {\n\t    nativeThen = NativePromisePrototype.then;\n\n\t    if (!SUBCLASSING) {\n\t      // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs\n\t      redefine(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {\n\t        var that = this;\n\t        return new PromiseConstructor(function (resolve, reject) {\n\t          functionCall(nativeThen, that, resolve, reject);\n\t        }).then(onFulfilled, onRejected);\n\t      // https://github.com/zloirock/core-js/issues/640\n\t      }, { unsafe: true });\n\n\t      // makes sure that native promise-based APIs `Promise#catch` properly works with patched `Promise#then`\n\t      redefine(NativePromisePrototype, 'catch', PromisePrototype['catch'], { unsafe: true });\n\t    }\n\n\t    // make `.constructor === Promise` work for native promise-based APIs\n\t    try {\n\t      delete NativePromisePrototype.constructor;\n\t    } catch (error) { /* empty */ }\n\n\t    // make `instanceof Promise` work for native promise-based APIs\n\t    if (objectSetPrototypeOf) {\n\t      objectSetPrototypeOf(NativePromisePrototype, PromisePrototype);\n\t    }\n\t  }\n\t}\n\n\t_export({ global: true, wrap: true, forced: FORCED$2 }, {\n\t  Promise: PromiseConstructor\n\t});\n\n\tsetToStringTag(PromiseConstructor, PROMISE, false);\n\tsetSpecies(PROMISE);\n\n\tPromiseWrapper = getBuiltIn(PROMISE);\n\n\t// statics\n\t_export({ target: PROMISE, stat: true, forced: FORCED$2 }, {\n\t  // `Promise.reject` method\n\t  // https://tc39.es/ecma262/#sec-promise.reject\n\t  reject: function reject(r) {\n\t    var capability = newPromiseCapability(this);\n\t    functionCall(capability.reject, undefined, r);\n\t    return capability.promise;\n\t  }\n\t});\n\n\t_export({ target: PROMISE, stat: true, forced: FORCED$2 }, {\n\t  // `Promise.resolve` method\n\t  // https://tc39.es/ecma262/#sec-promise.resolve\n\t  resolve: function resolve(x) {\n\t    return promiseResolve(this, x);\n\t  }\n\t});\n\n\t_export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {\n\t  // `Promise.all` method\n\t  // https://tc39.es/ecma262/#sec-promise.all\n\t  all: function all(iterable) {\n\t    var C = this;\n\t    var capability = newPromiseCapability(C);\n\t    var resolve = capability.resolve;\n\t    var reject = capability.reject;\n\t    var result = perform(function () {\n\t      var $promiseResolve = aCallable(C.resolve);\n\t      var values = [];\n\t      var counter = 0;\n\t      var remaining = 1;\n\t      iterate(iterable, function (promise) {\n\t        var index = counter++;\n\t        var alreadyCalled = false;\n\t        remaining++;\n\t        functionCall($promiseResolve, C, promise).then(function (value) {\n\t          if (alreadyCalled) return;\n\t          alreadyCalled = true;\n\t          values[index] = value;\n\t          --remaining || resolve(values);\n\t        }, reject);\n\t      });\n\t      --remaining || resolve(values);\n\t    });\n\t    if (result.error) reject(result.value);\n\t    return capability.promise;\n\t  },\n\t  // `Promise.race` method\n\t  // https://tc39.es/ecma262/#sec-promise.race\n\t  race: function race(iterable) {\n\t    var C = this;\n\t    var capability = newPromiseCapability(C);\n\t    var reject = capability.reject;\n\t    var result = perform(function () {\n\t      var $promiseResolve = aCallable(C.resolve);\n\t      iterate(iterable, function (promise) {\n\t        functionCall($promiseResolve, C, promise).then(capability.resolve, reject);\n\t      });\n\t    });\n\t    if (result.error) reject(result.value);\n\t    return capability.promise;\n\t  }\n\t});\n\n\tcreateCommonjsModule(function (module) {\n\t  /**\n\t   * Copyright (c) 2014-present, Facebook, Inc.\n\t   *\n\t   * This source code is licensed under the MIT license found in the\n\t   * LICENSE file in the root directory of this source tree.\n\t   */\n\t  var runtime = function (exports) {\n\n\t    var Op = Object.prototype;\n\t    var hasOwn = Op.hasOwnProperty;\n\t    var undefined$1; // More compressible than void 0.\n\n\t    var $Symbol = typeof Symbol === \"function\" ? Symbol : {};\n\t    var iteratorSymbol = $Symbol.iterator || \"@@iterator\";\n\t    var asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\";\n\t    var toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n\n\t    function define(obj, key, value) {\n\t      Object.defineProperty(obj, key, {\n\t        value: value,\n\t        enumerable: true,\n\t        configurable: true,\n\t        writable: true\n\t      });\n\t      return obj[key];\n\t    }\n\n\t    try {\n\t      // IE 8 has a broken Object.defineProperty that only works on DOM objects.\n\t      define({}, \"\");\n\t    } catch (err) {\n\t      define = function define(obj, key, value) {\n\t        return obj[key] = value;\n\t      };\n\t    }\n\n\t    function wrap(innerFn, outerFn, self, tryLocsList) {\n\t      // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.\n\t      var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;\n\t      var generator = Object.create(protoGenerator.prototype);\n\t      var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,\n\t      // .throw, and .return methods.\n\n\t      generator._invoke = makeInvokeMethod(innerFn, self, context);\n\t      return generator;\n\t    }\n\n\t    exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion\n\t    // record like context.tryEntries[i].completion. This interface could\n\t    // have been (and was previously) designed to take a closure to be\n\t    // invoked without arguments, but in all the cases we care about we\n\t    // already have an existing method we want to call, so there's no need\n\t    // to create a new function object. We can even get away with assuming\n\t    // the method takes exactly one argument, since that happens to be true\n\t    // in every case, so we don't have to touch the arguments object. The\n\t    // only additional allocation required is the completion record, which\n\t    // has a stable shape and so hopefully should be cheap to allocate.\n\n\t    function tryCatch(fn, obj, arg) {\n\t      try {\n\t        return {\n\t          type: \"normal\",\n\t          arg: fn.call(obj, arg)\n\t        };\n\t      } catch (err) {\n\t        return {\n\t          type: \"throw\",\n\t          arg: err\n\t        };\n\t      }\n\t    }\n\n\t    var GenStateSuspendedStart = \"suspendedStart\";\n\t    var GenStateSuspendedYield = \"suspendedYield\";\n\t    var GenStateExecuting = \"executing\";\n\t    var GenStateCompleted = \"completed\"; // Returning this object from the innerFn has the same effect as\n\t    // breaking out of the dispatch switch statement.\n\n\t    var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and\n\t    // .constructor.prototype properties for functions that return Generator\n\t    // objects. For full spec compliance, you may wish to configure your\n\t    // minifier not to mangle the names of these two functions.\n\n\t    function Generator() {}\n\n\t    function GeneratorFunction() {}\n\n\t    function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that\n\t    // don't natively support it.\n\n\n\t    var IteratorPrototype = {};\n\n\t    IteratorPrototype[iteratorSymbol] = function () {\n\t      return this;\n\t    };\n\n\t    var getProto = Object.getPrototypeOf;\n\t    var NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n\n\t    if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {\n\t      // This environment has a native %IteratorPrototype%; use it instead\n\t      // of the polyfill.\n\t      IteratorPrototype = NativeIteratorPrototype;\n\t    }\n\n\t    var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);\n\t    GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;\n\t    GeneratorFunctionPrototype.constructor = GeneratorFunction;\n\t    GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, \"GeneratorFunction\"); // Helper for defining the .next, .throw, and .return methods of the\n\t    // Iterator interface in terms of a single ._invoke method.\n\n\t    function defineIteratorMethods(prototype) {\n\t      [\"next\", \"throw\", \"return\"].forEach(function (method) {\n\t        define(prototype, method, function (arg) {\n\t          return this._invoke(method, arg);\n\t        });\n\t      });\n\t    }\n\n\t    exports.isGeneratorFunction = function (genFun) {\n\t      var ctor = typeof genFun === \"function\" && genFun.constructor;\n\t      return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can\n\t      // do is to check its .name property.\n\t      (ctor.displayName || ctor.name) === \"GeneratorFunction\" : false;\n\t    };\n\n\t    exports.mark = function (genFun) {\n\t      if (Object.setPrototypeOf) {\n\t        Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);\n\t      } else {\n\t        genFun.__proto__ = GeneratorFunctionPrototype;\n\t        define(genFun, toStringTagSymbol, \"GeneratorFunction\");\n\t      }\n\n\t      genFun.prototype = Object.create(Gp);\n\t      return genFun;\n\t    }; // Within the body of any async function, `await x` is transformed to\n\t    // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test\n\t    // `hasOwn.call(value, \"__await\")` to determine if the yielded value is\n\t    // meant to be awaited.\n\n\n\t    exports.awrap = function (arg) {\n\t      return {\n\t        __await: arg\n\t      };\n\t    };\n\n\t    function AsyncIterator(generator, PromiseImpl) {\n\t      function invoke(method, arg, resolve, reject) {\n\t        var record = tryCatch(generator[method], generator, arg);\n\n\t        if (record.type === \"throw\") {\n\t          reject(record.arg);\n\t        } else {\n\t          var result = record.arg;\n\t          var value = result.value;\n\n\t          if (value && _typeof(value) === \"object\" && hasOwn.call(value, \"__await\")) {\n\t            return PromiseImpl.resolve(value.__await).then(function (value) {\n\t              invoke(\"next\", value, resolve, reject);\n\t            }, function (err) {\n\t              invoke(\"throw\", err, resolve, reject);\n\t            });\n\t          }\n\n\t          return PromiseImpl.resolve(value).then(function (unwrapped) {\n\t            // When a yielded Promise is resolved, its final value becomes\n\t            // the .value of the Promise<{value,done}> result for the\n\t            // current iteration.\n\t            result.value = unwrapped;\n\t            resolve(result);\n\t          }, function (error) {\n\t            // If a rejected Promise was yielded, throw the rejection back\n\t            // into the async generator function so it can be handled there.\n\t            return invoke(\"throw\", error, resolve, reject);\n\t          });\n\t        }\n\t      }\n\n\t      var previousPromise;\n\n\t      function enqueue(method, arg) {\n\t        function callInvokeWithMethodAndArg() {\n\t          return new PromiseImpl(function (resolve, reject) {\n\t            invoke(method, arg, resolve, reject);\n\t          });\n\t        }\n\n\t        return previousPromise = // If enqueue has been called before, then we want to wait until\n\t        // all previous Promises have been resolved before calling invoke,\n\t        // so that results are always delivered in the correct order. If\n\t        // enqueue has not been called before, then it is important to\n\t        // call invoke immediately, without waiting on a callback to fire,\n\t        // so that the async generator function has the opportunity to do\n\t        // any necessary setup in a predictable way. This predictability\n\t        // is why the Promise constructor synchronously invokes its\n\t        // executor callback, and why async functions synchronously\n\t        // execute code before the first await. Since we implement simple\n\t        // async functions in terms of async generators, it is especially\n\t        // important to get this right, even though it requires care.\n\t        previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later\n\t        // invocations of the iterator.\n\t        callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();\n\t      } // Define the unified helper method that is used to implement .next,\n\t      // .throw, and .return (see defineIteratorMethods).\n\n\n\t      this._invoke = enqueue;\n\t    }\n\n\t    defineIteratorMethods(AsyncIterator.prototype);\n\n\t    AsyncIterator.prototype[asyncIteratorSymbol] = function () {\n\t      return this;\n\t    };\n\n\t    exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of\n\t    // AsyncIterator objects; they just return a Promise for the value of\n\t    // the final result produced by the iterator.\n\n\t    exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {\n\t      if (PromiseImpl === void 0) PromiseImpl = Promise;\n\t      var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);\n\t      return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.\n\t      : iter.next().then(function (result) {\n\t        return result.done ? result.value : iter.next();\n\t      });\n\t    };\n\n\t    function makeInvokeMethod(innerFn, self, context) {\n\t      var state = GenStateSuspendedStart;\n\t      return function invoke(method, arg) {\n\t        if (state === GenStateExecuting) {\n\t          throw new Error(\"Generator is already running\");\n\t        }\n\n\t        if (state === GenStateCompleted) {\n\t          if (method === \"throw\") {\n\t            throw arg;\n\t          } // Be forgiving, per 25.3.3.3.3 of the spec:\n\t          // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume\n\n\n\t          return doneResult();\n\t        }\n\n\t        context.method = method;\n\t        context.arg = arg;\n\n\t        while (true) {\n\t          var delegate = context.delegate;\n\n\t          if (delegate) {\n\t            var delegateResult = maybeInvokeDelegate(delegate, context);\n\n\t            if (delegateResult) {\n\t              if (delegateResult === ContinueSentinel) continue;\n\t              return delegateResult;\n\t            }\n\t          }\n\n\t          if (context.method === \"next\") {\n\t            // Setting context._sent for legacy support of Babel's\n\t            // function.sent implementation.\n\t            context.sent = context._sent = context.arg;\n\t          } else if (context.method === \"throw\") {\n\t            if (state === GenStateSuspendedStart) {\n\t              state = GenStateCompleted;\n\t              throw context.arg;\n\t            }\n\n\t            context.dispatchException(context.arg);\n\t          } else if (context.method === \"return\") {\n\t            context.abrupt(\"return\", context.arg);\n\t          }\n\n\t          state = GenStateExecuting;\n\t          var record = tryCatch(innerFn, self, context);\n\n\t          if (record.type === \"normal\") {\n\t            // If an exception is thrown from innerFn, we leave state ===\n\t            // GenStateExecuting and loop back for another invocation.\n\t            state = context.done ? GenStateCompleted : GenStateSuspendedYield;\n\n\t            if (record.arg === ContinueSentinel) {\n\t              continue;\n\t            }\n\n\t            return {\n\t              value: record.arg,\n\t              done: context.done\n\t            };\n\t          } else if (record.type === \"throw\") {\n\t            state = GenStateCompleted; // Dispatch the exception by looping back around to the\n\t            // context.dispatchException(context.arg) call above.\n\n\t            context.method = \"throw\";\n\t            context.arg = record.arg;\n\t          }\n\t        }\n\t      };\n\t    } // Call delegate.iterator[context.method](context.arg) and handle the\n\t    // result, either by returning a { value, done } result from the\n\t    // delegate iterator, or by modifying context.method and context.arg,\n\t    // setting context.delegate to null, and returning the ContinueSentinel.\n\n\n\t    function maybeInvokeDelegate(delegate, context) {\n\t      var method = delegate.iterator[context.method];\n\n\t      if (method === undefined$1) {\n\t        // A .throw or .return when the delegate iterator has no .throw\n\t        // method always terminates the yield* loop.\n\t        context.delegate = null;\n\n\t        if (context.method === \"throw\") {\n\t          // Note: [\"return\"] must be used for ES3 parsing compatibility.\n\t          if (delegate.iterator[\"return\"]) {\n\t            // If the delegate iterator has a return method, give it a\n\t            // chance to clean up.\n\t            context.method = \"return\";\n\t            context.arg = undefined$1;\n\t            maybeInvokeDelegate(delegate, context);\n\n\t            if (context.method === \"throw\") {\n\t              // If maybeInvokeDelegate(context) changed context.method from\n\t              // \"return\" to \"throw\", let that override the TypeError below.\n\t              return ContinueSentinel;\n\t            }\n\t          }\n\n\t          context.method = \"throw\";\n\t          context.arg = new TypeError(\"The iterator does not provide a 'throw' method\");\n\t        }\n\n\t        return ContinueSentinel;\n\t      }\n\n\t      var record = tryCatch(method, delegate.iterator, context.arg);\n\n\t      if (record.type === \"throw\") {\n\t        context.method = \"throw\";\n\t        context.arg = record.arg;\n\t        context.delegate = null;\n\t        return ContinueSentinel;\n\t      }\n\n\t      var info = record.arg;\n\n\t      if (!info) {\n\t        context.method = \"throw\";\n\t        context.arg = new TypeError(\"iterator result is not an object\");\n\t        context.delegate = null;\n\t        return ContinueSentinel;\n\t      }\n\n\t      if (info.done) {\n\t        // Assign the result of the finished delegate to the temporary\n\t        // variable specified by delegate.resultName (see delegateYield).\n\t        context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).\n\n\t        context.next = delegate.nextLoc; // If context.method was \"throw\" but the delegate handled the\n\t        // exception, let the outer generator proceed normally. If\n\t        // context.method was \"next\", forget context.arg since it has been\n\t        // \"consumed\" by the delegate iterator. If context.method was\n\t        // \"return\", allow the original .return call to continue in the\n\t        // outer generator.\n\n\t        if (context.method !== \"return\") {\n\t          context.method = \"next\";\n\t          context.arg = undefined$1;\n\t        }\n\t      } else {\n\t        // Re-yield the result returned by the delegate method.\n\t        return info;\n\t      } // The delegate iterator is finished, so forget it and continue with\n\t      // the outer generator.\n\n\n\t      context.delegate = null;\n\t      return ContinueSentinel;\n\t    } // Define Generator.prototype.{next,throw,return} in terms of the\n\t    // unified ._invoke helper method.\n\n\n\t    defineIteratorMethods(Gp);\n\t    define(Gp, toStringTagSymbol, \"Generator\"); // A Generator should always return itself as the iterator object when the\n\t    // @@iterator function is called on it. Some browsers' implementations of the\n\t    // iterator prototype chain incorrectly implement this, causing the Generator\n\t    // object to not be returned from this call. This ensures that doesn't happen.\n\t    // See https://github.com/facebook/regenerator/issues/274 for more details.\n\n\t    Gp[iteratorSymbol] = function () {\n\t      return this;\n\t    };\n\n\t    Gp.toString = function () {\n\t      return \"[object Generator]\";\n\t    };\n\n\t    function pushTryEntry(locs) {\n\t      var entry = {\n\t        tryLoc: locs[0]\n\t      };\n\n\t      if (1 in locs) {\n\t        entry.catchLoc = locs[1];\n\t      }\n\n\t      if (2 in locs) {\n\t        entry.finallyLoc = locs[2];\n\t        entry.afterLoc = locs[3];\n\t      }\n\n\t      this.tryEntries.push(entry);\n\t    }\n\n\t    function resetTryEntry(entry) {\n\t      var record = entry.completion || {};\n\t      record.type = \"normal\";\n\t      delete record.arg;\n\t      entry.completion = record;\n\t    }\n\n\t    function Context(tryLocsList) {\n\t      // The root entry object (effectively a try statement without a catch\n\t      // or a finally block) gives us a place to store values thrown from\n\t      // locations where there is no enclosing try statement.\n\t      this.tryEntries = [{\n\t        tryLoc: \"root\"\n\t      }];\n\t      tryLocsList.forEach(pushTryEntry, this);\n\t      this.reset(true);\n\t    }\n\n\t    exports.keys = function (object) {\n\t      var keys = [];\n\n\t      for (var key in object) {\n\t        keys.push(key);\n\t      }\n\n\t      keys.reverse(); // Rather than returning an object with a next method, we keep\n\t      // things simple and return the next function itself.\n\n\t      return function next() {\n\t        while (keys.length) {\n\t          var key = keys.pop();\n\n\t          if (key in object) {\n\t            next.value = key;\n\t            next.done = false;\n\t            return next;\n\t          }\n\t        } // To avoid creating an additional object, we just hang the .value\n\t        // and .done properties off the next function object itself. This\n\t        // also ensures that the minifier will not anonymize the function.\n\n\n\t        next.done = true;\n\t        return next;\n\t      };\n\t    };\n\n\t    function values(iterable) {\n\t      if (iterable) {\n\t        var iteratorMethod = iterable[iteratorSymbol];\n\n\t        if (iteratorMethod) {\n\t          return iteratorMethod.call(iterable);\n\t        }\n\n\t        if (typeof iterable.next === \"function\") {\n\t          return iterable;\n\t        }\n\n\t        if (!isNaN(iterable.length)) {\n\t          var i = -1,\n\t              next = function next() {\n\t            while (++i < iterable.length) {\n\t              if (hasOwn.call(iterable, i)) {\n\t                next.value = iterable[i];\n\t                next.done = false;\n\t                return next;\n\t              }\n\t            }\n\n\t            next.value = undefined$1;\n\t            next.done = true;\n\t            return next;\n\t          };\n\n\t          return next.next = next;\n\t        }\n\t      } // Return an iterator with no values.\n\n\n\t      return {\n\t        next: doneResult\n\t      };\n\t    }\n\n\t    exports.values = values;\n\n\t    function doneResult() {\n\t      return {\n\t        value: undefined$1,\n\t        done: true\n\t      };\n\t    }\n\n\t    Context.prototype = {\n\t      constructor: Context,\n\t      reset: function reset(skipTempReset) {\n\t        this.prev = 0;\n\t        this.next = 0; // Resetting context._sent for legacy support of Babel's\n\t        // function.sent implementation.\n\n\t        this.sent = this._sent = undefined$1;\n\t        this.done = false;\n\t        this.delegate = null;\n\t        this.method = \"next\";\n\t        this.arg = undefined$1;\n\t        this.tryEntries.forEach(resetTryEntry);\n\n\t        if (!skipTempReset) {\n\t          for (var name in this) {\n\t            // Not sure about the optimal order of these conditions:\n\t            if (name.charAt(0) === \"t\" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {\n\t              this[name] = undefined$1;\n\t            }\n\t          }\n\t        }\n\t      },\n\t      stop: function stop() {\n\t        this.done = true;\n\t        var rootEntry = this.tryEntries[0];\n\t        var rootRecord = rootEntry.completion;\n\n\t        if (rootRecord.type === \"throw\") {\n\t          throw rootRecord.arg;\n\t        }\n\n\t        return this.rval;\n\t      },\n\t      dispatchException: function dispatchException(exception) {\n\t        if (this.done) {\n\t          throw exception;\n\t        }\n\n\t        var context = this;\n\n\t        function handle(loc, caught) {\n\t          record.type = \"throw\";\n\t          record.arg = exception;\n\t          context.next = loc;\n\n\t          if (caught) {\n\t            // If the dispatched exception was caught by a catch block,\n\t            // then let that catch block handle the exception normally.\n\t            context.method = \"next\";\n\t            context.arg = undefined$1;\n\t          }\n\n\t          return !!caught;\n\t        }\n\n\t        for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t          var entry = this.tryEntries[i];\n\t          var record = entry.completion;\n\n\t          if (entry.tryLoc === \"root\") {\n\t            // Exception thrown outside of any try block that could handle\n\t            // it, so set the completion value of the entire function to\n\t            // throw the exception.\n\t            return handle(\"end\");\n\t          }\n\n\t          if (entry.tryLoc <= this.prev) {\n\t            var hasCatch = hasOwn.call(entry, \"catchLoc\");\n\t            var hasFinally = hasOwn.call(entry, \"finallyLoc\");\n\n\t            if (hasCatch && hasFinally) {\n\t              if (this.prev < entry.catchLoc) {\n\t                return handle(entry.catchLoc, true);\n\t              } else if (this.prev < entry.finallyLoc) {\n\t                return handle(entry.finallyLoc);\n\t              }\n\t            } else if (hasCatch) {\n\t              if (this.prev < entry.catchLoc) {\n\t                return handle(entry.catchLoc, true);\n\t              }\n\t            } else if (hasFinally) {\n\t              if (this.prev < entry.finallyLoc) {\n\t                return handle(entry.finallyLoc);\n\t              }\n\t            } else {\n\t              throw new Error(\"try statement without catch or finally\");\n\t            }\n\t          }\n\t        }\n\t      },\n\t      abrupt: function abrupt(type, arg) {\n\t        for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t          var entry = this.tryEntries[i];\n\n\t          if (entry.tryLoc <= this.prev && hasOwn.call(entry, \"finallyLoc\") && this.prev < entry.finallyLoc) {\n\t            var finallyEntry = entry;\n\t            break;\n\t          }\n\t        }\n\n\t        if (finallyEntry && (type === \"break\" || type === \"continue\") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {\n\t          // Ignore the finally entry if control is not jumping to a\n\t          // location outside the try/catch block.\n\t          finallyEntry = null;\n\t        }\n\n\t        var record = finallyEntry ? finallyEntry.completion : {};\n\t        record.type = type;\n\t        record.arg = arg;\n\n\t        if (finallyEntry) {\n\t          this.method = \"next\";\n\t          this.next = finallyEntry.finallyLoc;\n\t          return ContinueSentinel;\n\t        }\n\n\t        return this.complete(record);\n\t      },\n\t      complete: function complete(record, afterLoc) {\n\t        if (record.type === \"throw\") {\n\t          throw record.arg;\n\t        }\n\n\t        if (record.type === \"break\" || record.type === \"continue\") {\n\t          this.next = record.arg;\n\t        } else if (record.type === \"return\") {\n\t          this.rval = this.arg = record.arg;\n\t          this.method = \"return\";\n\t          this.next = \"end\";\n\t        } else if (record.type === \"normal\" && afterLoc) {\n\t          this.next = afterLoc;\n\t        }\n\n\t        return ContinueSentinel;\n\t      },\n\t      finish: function finish(finallyLoc) {\n\t        for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t          var entry = this.tryEntries[i];\n\n\t          if (entry.finallyLoc === finallyLoc) {\n\t            this.complete(entry.completion, entry.afterLoc);\n\t            resetTryEntry(entry);\n\t            return ContinueSentinel;\n\t          }\n\t        }\n\t      },\n\t      \"catch\": function _catch(tryLoc) {\n\t        for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n\t          var entry = this.tryEntries[i];\n\n\t          if (entry.tryLoc === tryLoc) {\n\t            var record = entry.completion;\n\n\t            if (record.type === \"throw\") {\n\t              var thrown = record.arg;\n\t              resetTryEntry(entry);\n\t            }\n\n\t            return thrown;\n\t          }\n\t        } // The context.catch method must only be called with a location\n\t        // argument that corresponds to a known catch block.\n\n\n\t        throw new Error(\"illegal catch attempt\");\n\t      },\n\t      delegateYield: function delegateYield(iterable, resultName, nextLoc) {\n\t        this.delegate = {\n\t          iterator: values(iterable),\n\t          resultName: resultName,\n\t          nextLoc: nextLoc\n\t        };\n\n\t        if (this.method === \"next\") {\n\t          // Deliberately forget the last sent value so that we don't\n\t          // accidentally pass it on to the delegate.\n\t          this.arg = undefined$1;\n\t        }\n\n\t        return ContinueSentinel;\n\t      }\n\t    }; // Regardless of whether this script is executing as a CommonJS module\n\t    // or not, return the runtime object so that we can declare the variable\n\t    // regeneratorRuntime in the outer scope, which allows this module to be\n\t    // injected easily by `bin/regenerator --include-runtime script.js`.\n\n\t    return exports;\n\t  }( // If this script is executing as a CommonJS module, use module.exports\n\t  // as the regeneratorRuntime namespace. Otherwise create a new empty\n\t  // object. Either way, the resulting object will be used to initialize\n\t  // the regeneratorRuntime variable at the top of this file.\n\t  module.exports );\n\n\t  try {\n\t    regeneratorRuntime = runtime;\n\t  } catch (accidentalStrictMode) {\n\t    // This module should not be running in strict mode, so the above\n\t    // assignment should always work unless something is misconfigured. Just\n\t    // in case runtime.js accidentally runs in strict mode, we can escape\n\t    // strict mode using a global Function call. This could conceivably fail\n\t    // if a Content Security Policy forbids using Function, but in that case\n\t    // the proper solution is to fix the accidental strict mode problem. If\n\t    // you've misconfigured your bundler to force strict mode and applied a\n\t    // CSP to forbid Function, and you're not willing to fix either of those\n\t    // problems, please detail your unique predicament in a GitHub issue.\n\t    Function(\"r\", \"regeneratorRuntime = r\")(runtime);\n\t  }\n\t});\n\n\tvar escapeStringRegexp = function escapeStringRegexp(string) {\n\t  if (typeof string !== 'string') {\n\t    throw new TypeError('Expected a string');\n\t  } // Escape characters with special meaning either inside or outside character sets.\n\t  // Use a simple backslash escape when it’s always valid, and a \\unnnn escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.\n\n\n\t  return string.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d');\n\t};\n\n\t// Copyright Joyent, Inc. and other Node contributors.\n\t//\n\t// Permission is hereby granted, free of charge, to any person obtaining a\n\t// copy of this software and associated documentation files (the\n\t// \"Software\"), to deal in the Software without restriction, including\n\t// without limitation the rights to use, copy, modify, merge, publish,\n\t// distribute, sublicense, and/or sell copies of the Software, and to permit\n\t// persons to whom the Software is furnished to do so, subject to the\n\t// following conditions:\n\t//\n\t// The above copyright notice and this permission notice shall be included\n\t// in all copies or substantial portions of the Software.\n\t//\n\t// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n\t// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n\t// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n\t// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n\t// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n\t// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n\t// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\t// resolves . and .. elements in a path array with directory names there\n\t// must be no slashes, empty elements, or device names (c:\\) in the array\n\t// (so also no leading and trailing slashes - it does not distinguish\n\t// relative and absolute paths)\n\tfunction normalizeArray(parts, allowAboveRoot) {\n\t  // if the path tries to go above the root, `up` ends up > 0\n\t  var up = 0;\n\n\t  for (var i = parts.length - 1; i >= 0; i--) {\n\t    var last = parts[i];\n\n\t    if (last === '.') {\n\t      parts.splice(i, 1);\n\t    } else if (last === '..') {\n\t      parts.splice(i, 1);\n\t      up++;\n\t    } else if (up) {\n\t      parts.splice(i, 1);\n\t      up--;\n\t    }\n\t  } // if the path is allowed to go above the root, restore leading ..s\n\n\n\t  if (allowAboveRoot) {\n\t    for (; up--; up) {\n\t      parts.unshift('..');\n\t    }\n\t  }\n\n\t  return parts;\n\t} // Split a filename into [root, dir, basename, ext], unix version\n\t// 'root' is just a slash, or nothing.\n\n\n\tvar splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/;\n\n\tvar splitPath = function splitPath(filename) {\n\t  return splitPathRe.exec(filename).slice(1);\n\t}; // path.resolve([from ...], to)\n\t// posix version\n\n\n\tfunction resolve() {\n\t  var resolvedPath = '',\n\t      resolvedAbsolute = false;\n\n\t  for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n\t    var path = i >= 0 ? arguments[i] : '/'; // Skip empty and invalid entries\n\n\t    if (typeof path !== 'string') {\n\t      throw new TypeError('Arguments to path.resolve must be strings');\n\t    } else if (!path) {\n\t      continue;\n\t    }\n\n\t    resolvedPath = path + '/' + resolvedPath;\n\t    resolvedAbsolute = path.charAt(0) === '/';\n\t  } // At this point the path should be resolved to a full absolute path, but\n\t  // handle relative paths to be safe (might happen when process.cwd() fails)\n\t  // Normalize the path\n\n\n\t  resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function (p) {\n\t    return !!p;\n\t  }), !resolvedAbsolute).join('/');\n\t  return (resolvedAbsolute ? '/' : '') + resolvedPath || '.';\n\t}\n\t// posix version\n\n\tfunction normalize(path) {\n\t  var isPathAbsolute = isAbsolute(path),\n\t      trailingSlash = substr(path, -1) === '/'; // Normalize the path\n\n\t  path = normalizeArray(filter(path.split('/'), function (p) {\n\t    return !!p;\n\t  }), !isPathAbsolute).join('/');\n\n\t  if (!path && !isPathAbsolute) {\n\t    path = '.';\n\t  }\n\n\t  if (path && trailingSlash) {\n\t    path += '/';\n\t  }\n\n\t  return (isPathAbsolute ? '/' : '') + path;\n\t}\n\n\tfunction isAbsolute(path) {\n\t  return path.charAt(0) === '/';\n\t} // posix version\n\n\tfunction join() {\n\t  var paths = Array.prototype.slice.call(arguments, 0);\n\t  return normalize(filter(paths, function (p, index) {\n\t    if (typeof p !== 'string') {\n\t      throw new TypeError('Arguments to path.join must be strings');\n\t    }\n\n\t    return p;\n\t  }).join('/'));\n\t} // path.relative(from, to)\n\t// posix version\n\n\tfunction relative(from, to) {\n\t  from = resolve(from).substr(1);\n\t  to = resolve(to).substr(1);\n\n\t  function trim(arr) {\n\t    var start = 0;\n\n\t    for (; start < arr.length; start++) {\n\t      if (arr[start] !== '') break;\n\t    }\n\n\t    var end = arr.length - 1;\n\n\t    for (; end >= 0; end--) {\n\t      if (arr[end] !== '') break;\n\t    }\n\n\t    if (start > end) return [];\n\t    return arr.slice(start, end - start + 1);\n\t  }\n\n\t  var fromParts = trim(from.split('/'));\n\t  var toParts = trim(to.split('/'));\n\t  var length = Math.min(fromParts.length, toParts.length);\n\t  var samePartsLength = length;\n\n\t  for (var i = 0; i < length; i++) {\n\t    if (fromParts[i] !== toParts[i]) {\n\t      samePartsLength = i;\n\t      break;\n\t    }\n\t  }\n\n\t  var outputParts = [];\n\n\t  for (var i = samePartsLength; i < fromParts.length; i++) {\n\t    outputParts.push('..');\n\t  }\n\n\t  outputParts = outputParts.concat(toParts.slice(samePartsLength));\n\t  return outputParts.join('/');\n\t}\n\tvar sep = '/';\n\tvar delimiter = ':';\n\tfunction dirname(path) {\n\t  var result = splitPath(path),\n\t      root = result[0],\n\t      dir = result[1];\n\n\t  if (!root && !dir) {\n\t    // No dirname whatsoever\n\t    return '.';\n\t  }\n\n\t  if (dir) {\n\t    // It has a dirname, strip trailing slash\n\t    dir = dir.substr(0, dir.length - 1);\n\t  }\n\n\t  return root + dir;\n\t}\n\tfunction basename(path, ext) {\n\t  var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows?\n\n\t  if (ext && f.substr(-1 * ext.length) === ext) {\n\t    f = f.substr(0, f.length - ext.length);\n\t  }\n\n\t  return f;\n\t}\n\tfunction extname(path) {\n\t  return splitPath(path)[3];\n\t}\n\tvar path = {\n\t  extname: extname,\n\t  basename: basename,\n\t  dirname: dirname,\n\t  sep: sep,\n\t  delimiter: delimiter,\n\t  relative: relative,\n\t  join: join,\n\t  isAbsolute: isAbsolute,\n\t  normalize: normalize,\n\t  resolve: resolve\n\t};\n\n\tfunction filter(xs, f) {\n\t  if (xs.filter) return xs.filter(f);\n\t  var res = [];\n\n\t  for (var i = 0; i < xs.length; i++) {\n\t    if (f(xs[i], i, xs)) res.push(xs[i]);\n\t  }\n\n\t  return res;\n\t} // String.prototype.substr - negative index don't work in IE8\n\n\n\tvar substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) {\n\t  return str.substr(start, len);\n\t} : function (str, start, len) {\n\t  if (start < 0) start = str.length + start;\n\t  return str.substr(start, len);\n\t};\n\n\t// call something on iterator step with safe closing on error\n\tvar callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {\n\t  try {\n\t    return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);\n\t  } catch (error) {\n\t    iteratorClose(iterator, 'throw', error);\n\t  }\n\t};\n\n\tvar Array$1 = global_1.Array;\n\n\t// `Array.from` method implementation\n\t// https://tc39.es/ecma262/#sec-array.from\n\tvar arrayFrom = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {\n\t  var O = toObject(arrayLike);\n\t  var IS_CONSTRUCTOR = isConstructor(this);\n\t  var argumentsLength = arguments.length;\n\t  var mapfn = argumentsLength > 1 ? arguments[1] : undefined;\n\t  var mapping = mapfn !== undefined;\n\t  if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined);\n\t  var iteratorMethod = getIteratorMethod(O);\n\t  var index = 0;\n\t  var length, result, step, iterator, next, value;\n\t  // if the target is not iterable or it's an array with the default iterator - use a simple case\n\t  if (iteratorMethod && !(this == Array$1 && isArrayIteratorMethod(iteratorMethod))) {\n\t    iterator = getIterator(O, iteratorMethod);\n\t    next = iterator.next;\n\t    result = IS_CONSTRUCTOR ? new this() : [];\n\t    for (;!(step = functionCall(next, iterator)).done; index++) {\n\t      value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;\n\t      createProperty(result, index, value);\n\t    }\n\t  } else {\n\t    length = lengthOfArrayLike(O);\n\t    result = IS_CONSTRUCTOR ? new this(length) : Array$1(length);\n\t    for (;length > index; index++) {\n\t      value = mapping ? mapfn(O[index], index) : O[index];\n\t      createProperty(result, index, value);\n\t    }\n\t  }\n\t  result.length = index;\n\t  return result;\n\t};\n\n\tvar INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {\n\t  // eslint-disable-next-line es/no-array-from -- required for testing\n\t  Array.from(iterable);\n\t});\n\n\t// `Array.from` method\n\t// https://tc39.es/ecma262/#sec-array.from\n\t_export({ target: 'Array', stat: true, forced: INCORRECT_ITERATION }, {\n\t  from: arrayFrom\n\t});\n\n\tvar test$1 = [];\n\tvar un$Sort = functionUncurryThis(test$1.sort);\n\tvar push$1 = functionUncurryThis(test$1.push);\n\n\t// IE8-\n\tvar FAILS_ON_UNDEFINED = fails(function () {\n\t  test$1.sort(undefined);\n\t});\n\t// V8 bug\n\tvar FAILS_ON_NULL = fails(function () {\n\t  test$1.sort(null);\n\t});\n\t// Old WebKit\n\tvar STRICT_METHOD = arrayMethodIsStrict('sort');\n\n\tvar STABLE_SORT = !fails(function () {\n\t  // feature detection can be too slow, so check engines versions\n\t  if (engineV8Version) return engineV8Version < 70;\n\t  if (engineFfVersion && engineFfVersion > 3) return;\n\t  if (engineIsIeOrEdge) return true;\n\t  if (engineWebkitVersion) return engineWebkitVersion < 603;\n\n\t  var result = '';\n\t  var code, chr, value, index;\n\n\t  // generate an array with more 512 elements (Chakra and old V8 fails only in this case)\n\t  for (code = 65; code < 76; code++) {\n\t    chr = String.fromCharCode(code);\n\n\t    switch (code) {\n\t      case 66: case 69: case 70: case 72: value = 3; break;\n\t      case 68: case 71: value = 4; break;\n\t      default: value = 2;\n\t    }\n\n\t    for (index = 0; index < 47; index++) {\n\t      test$1.push({ k: chr + index, v: value });\n\t    }\n\t  }\n\n\t  test$1.sort(function (a, b) { return b.v - a.v; });\n\n\t  for (index = 0; index < test$1.length; index++) {\n\t    chr = test$1[index].k.charAt(0);\n\t    if (result.charAt(result.length - 1) !== chr) result += chr;\n\t  }\n\n\t  return result !== 'DGBEFHACIJK';\n\t});\n\n\tvar FORCED$1 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD || !STABLE_SORT;\n\n\tvar getSortCompare = function (comparefn) {\n\t  return function (x, y) {\n\t    if (y === undefined) return -1;\n\t    if (x === undefined) return 1;\n\t    if (comparefn !== undefined) return +comparefn(x, y) || 0;\n\t    return toString_1(x) > toString_1(y) ? 1 : -1;\n\t  };\n\t};\n\n\t// `Array.prototype.sort` method\n\t// https://tc39.es/ecma262/#sec-array.prototype.sort\n\t_export({ target: 'Array', proto: true, forced: FORCED$1 }, {\n\t  sort: function sort(comparefn) {\n\t    if (comparefn !== undefined) aCallable(comparefn);\n\n\t    var array = toObject(this);\n\n\t    if (STABLE_SORT) return comparefn === undefined ? un$Sort(array) : un$Sort(array, comparefn);\n\n\t    var items = [];\n\t    var arrayLength = lengthOfArrayLike(array);\n\t    var itemsLength, index;\n\n\t    for (index = 0; index < arrayLength; index++) {\n\t      if (index in array) push$1(items, array[index]);\n\t    }\n\n\t    arraySort(items, getSortCompare(comparefn));\n\n\t    itemsLength = items.length;\n\t    index = 0;\n\n\t    while (index < itemsLength) array[index] = items[index++];\n\t    while (index < arrayLength) delete array[index++];\n\n\t    return array;\n\t  }\n\t});\n\n\tvar diff$1 = createCommonjsModule(function (module, exports) {\n\t  (function (global, factory) {\n\t    factory(exports) ;\n\t  })(commonjsGlobal, function (exports) {\n\n\t    function Diff() {}\n\n\t    Diff.prototype = {\n\t      diff: function diff(oldString, newString) {\n\t        var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\t        var callback = options.callback;\n\n\t        if (typeof options === 'function') {\n\t          callback = options;\n\t          options = {};\n\t        }\n\n\t        this.options = options;\n\t        var self = this;\n\n\t        function done(value) {\n\t          if (callback) {\n\t            setTimeout(function () {\n\t              callback(undefined, value);\n\t            }, 0);\n\t            return true;\n\t          } else {\n\t            return value;\n\t          }\n\t        } // Allow subclasses to massage the input prior to running\n\n\n\t        oldString = this.castInput(oldString);\n\t        newString = this.castInput(newString);\n\t        oldString = this.removeEmpty(this.tokenize(oldString));\n\t        newString = this.removeEmpty(this.tokenize(newString));\n\t        var newLen = newString.length,\n\t            oldLen = oldString.length;\n\t        var editLength = 1;\n\t        var maxEditLength = newLen + oldLen;\n\t        var bestPath = [{\n\t          newPos: -1,\n\t          components: []\n\t        }]; // Seed editLength = 0, i.e. the content starts with the same values\n\n\t        var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);\n\n\t        if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n\t          // Identity per the equality and tokenizer\n\t          return done([{\n\t            value: this.join(newString),\n\t            count: newString.length\n\t          }]);\n\t        } // Main worker method. checks all permutations of a given edit length for acceptance.\n\n\n\t        function execEditLength() {\n\t          for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {\n\t            var basePath = void 0;\n\n\t            var addPath = bestPath[diagonalPath - 1],\n\t                removePath = bestPath[diagonalPath + 1],\n\t                _oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n\n\t            if (addPath) {\n\t              // No one else is going to attempt to use this value, clear it\n\t              bestPath[diagonalPath - 1] = undefined;\n\t            }\n\n\t            var canAdd = addPath && addPath.newPos + 1 < newLen,\n\t                canRemove = removePath && 0 <= _oldPos && _oldPos < oldLen;\n\n\t            if (!canAdd && !canRemove) {\n\t              // If this path is a terminal then prune\n\t              bestPath[diagonalPath] = undefined;\n\t              continue;\n\t            } // Select the diagonal that we want to branch from. We select the prior\n\t            // path whose position in the new string is the farthest from the origin\n\t            // and does not pass the bounds of the diff graph\n\n\n\t            if (!canAdd || canRemove && addPath.newPos < removePath.newPos) {\n\t              basePath = clonePath(removePath);\n\t              self.pushComponent(basePath.components, undefined, true);\n\t            } else {\n\t              basePath = addPath; // No need to clone, we've pulled it from the list\n\n\t              basePath.newPos++;\n\t              self.pushComponent(basePath.components, true, undefined);\n\t            }\n\n\t            _oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); // If we have hit the end of both strings, then we are done\n\n\t            if (basePath.newPos + 1 >= newLen && _oldPos + 1 >= oldLen) {\n\t              return done(buildValues(self, basePath.components, newString, oldString, self.useLongestToken));\n\t            } else {\n\t              // Otherwise track this path as a potential candidate and continue.\n\t              bestPath[diagonalPath] = basePath;\n\t            }\n\t          }\n\n\t          editLength++;\n\t        } // Performs the length of edit iteration. Is a bit fugly as this has to support the\n\t        // sync and async mode which is never fun. Loops over execEditLength until a value\n\t        // is produced.\n\n\n\t        if (callback) {\n\t          (function exec() {\n\t            setTimeout(function () {\n\t              // This should not happen, but we want to be safe.\n\n\t              /* istanbul ignore next */\n\t              if (editLength > maxEditLength) {\n\t                return callback();\n\t              }\n\n\t              if (!execEditLength()) {\n\t                exec();\n\t              }\n\t            }, 0);\n\t          })();\n\t        } else {\n\t          while (editLength <= maxEditLength) {\n\t            var ret = execEditLength();\n\n\t            if (ret) {\n\t              return ret;\n\t            }\n\t          }\n\t        }\n\t      },\n\t      pushComponent: function pushComponent(components, added, removed) {\n\t        var last = components[components.length - 1];\n\n\t        if (last && last.added === added && last.removed === removed) {\n\t          // We need to clone here as the component clone operation is just\n\t          // as shallow array clone\n\t          components[components.length - 1] = {\n\t            count: last.count + 1,\n\t            added: added,\n\t            removed: removed\n\t          };\n\t        } else {\n\t          components.push({\n\t            count: 1,\n\t            added: added,\n\t            removed: removed\n\t          });\n\t        }\n\t      },\n\t      extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) {\n\t        var newLen = newString.length,\n\t            oldLen = oldString.length,\n\t            newPos = basePath.newPos,\n\t            oldPos = newPos - diagonalPath,\n\t            commonCount = 0;\n\n\t        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) {\n\t          newPos++;\n\t          oldPos++;\n\t          commonCount++;\n\t        }\n\n\t        if (commonCount) {\n\t          basePath.components.push({\n\t            count: commonCount\n\t          });\n\t        }\n\n\t        basePath.newPos = newPos;\n\t        return oldPos;\n\t      },\n\t      equals: function equals(left, right) {\n\t        if (this.options.comparator) {\n\t          return this.options.comparator(left, right);\n\t        } else {\n\t          return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase();\n\t        }\n\t      },\n\t      removeEmpty: function removeEmpty(array) {\n\t        var ret = [];\n\n\t        for (var i = 0; i < array.length; i++) {\n\t          if (array[i]) {\n\t            ret.push(array[i]);\n\t          }\n\t        }\n\n\t        return ret;\n\t      },\n\t      castInput: function castInput(value) {\n\t        return value;\n\t      },\n\t      tokenize: function tokenize(value) {\n\t        return value.split('');\n\t      },\n\t      join: function join(chars) {\n\t        return chars.join('');\n\t      }\n\t    };\n\n\t    function buildValues(diff, components, newString, oldString, useLongestToken) {\n\t      var componentPos = 0,\n\t          componentLen = components.length,\n\t          newPos = 0,\n\t          oldPos = 0;\n\n\t      for (; componentPos < componentLen; componentPos++) {\n\t        var component = components[componentPos];\n\n\t        if (!component.removed) {\n\t          if (!component.added && useLongestToken) {\n\t            var value = newString.slice(newPos, newPos + component.count);\n\t            value = value.map(function (value, i) {\n\t              var oldValue = oldString[oldPos + i];\n\t              return oldValue.length > value.length ? oldValue : value;\n\t            });\n\t            component.value = diff.join(value);\n\t          } else {\n\t            component.value = diff.join(newString.slice(newPos, newPos + component.count));\n\t          }\n\n\t          newPos += component.count; // Common case\n\n\t          if (!component.added) {\n\t            oldPos += component.count;\n\t          }\n\t        } else {\n\t          component.value = diff.join(oldString.slice(oldPos, oldPos + component.count));\n\t          oldPos += component.count; // Reverse add and remove so removes are output first to match common convention\n\t          // The diffing algorithm is tied to add then remove output and this is the simplest\n\t          // route to get the desired output with minimal overhead.\n\n\t          if (componentPos && components[componentPos - 1].added) {\n\t            var tmp = components[componentPos - 1];\n\t            components[componentPos - 1] = components[componentPos];\n\t            components[componentPos] = tmp;\n\t          }\n\t        }\n\t      } // Special case handle for when one terminal is ignored (i.e. whitespace).\n\t      // For this case we merge the terminal into the prior string and drop the change.\n\t      // This is only available for string mode.\n\n\n\t      var lastComponent = components[componentLen - 1];\n\n\t      if (componentLen > 1 && typeof lastComponent.value === 'string' && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) {\n\t        components[componentLen - 2].value += lastComponent.value;\n\t        components.pop();\n\t      }\n\n\t      return components;\n\t    }\n\n\t    function clonePath(path) {\n\t      return {\n\t        newPos: path.newPos,\n\t        components: path.components.slice(0)\n\t      };\n\t    }\n\n\t    var characterDiff = new Diff();\n\n\t    function diffChars(oldStr, newStr, options) {\n\t      return characterDiff.diff(oldStr, newStr, options);\n\t    }\n\n\t    function generateOptions(options, defaults) {\n\t      if (typeof options === 'function') {\n\t        defaults.callback = options;\n\t      } else if (options) {\n\t        for (var name in options) {\n\t          /* istanbul ignore else */\n\t          if (options.hasOwnProperty(name)) {\n\t            defaults[name] = options[name];\n\t          }\n\t        }\n\t      }\n\n\t      return defaults;\n\t    } //\n\t    // Ranges and exceptions:\n\t    // Latin-1 Supplement, 0080–00FF\n\t    //  - U+00D7  × Multiplication sign\n\t    //  - U+00F7  ÷ Division sign\n\t    // Latin Extended-A, 0100–017F\n\t    // Latin Extended-B, 0180–024F\n\t    // IPA Extensions, 0250–02AF\n\t    // Spacing Modifier Letters, 02B0–02FF\n\t    //  - U+02C7  ˇ &#711;  Caron\n\t    //  - U+02D8  ˘ &#728;  Breve\n\t    //  - U+02D9  ˙ &#729;  Dot Above\n\t    //  - U+02DA  ˚ &#730;  Ring Above\n\t    //  - U+02DB  ˛ &#731;  Ogonek\n\t    //  - U+02DC  ˜ &#732;  Small Tilde\n\t    //  - U+02DD  ˝ &#733;  Double Acute Accent\n\t    // Latin Extended Additional, 1E00–1EFF\n\n\n\t    var extendedWordChars = /^[A-Za-z\\xC0-\\u02C6\\u02C8-\\u02D7\\u02DE-\\u02FF\\u1E00-\\u1EFF]+$/;\n\t    var reWhitespace = /\\S/;\n\t    var wordDiff = new Diff();\n\n\t    wordDiff.equals = function (left, right) {\n\t      if (this.options.ignoreCase) {\n\t        left = left.toLowerCase();\n\t        right = right.toLowerCase();\n\t      }\n\n\t      return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right);\n\t    };\n\n\t    wordDiff.tokenize = function (value) {\n\t      // All whitespace symbols except newline group into one token, each newline - in separate token\n\t      var tokens = value.split(/([^\\S\\r\\n]+|[()[\\]{}'\"\\r\\n]|\\b)/); // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set.\n\n\t      for (var i = 0; i < tokens.length - 1; i++) {\n\t        // If we have an empty string in the next field and we have only word chars before and after, merge\n\t        if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) {\n\t          tokens[i] += tokens[i + 2];\n\t          tokens.splice(i + 1, 2);\n\t          i--;\n\t        }\n\t      }\n\n\t      return tokens;\n\t    };\n\n\t    function diffWords(oldStr, newStr, options) {\n\t      options = generateOptions(options, {\n\t        ignoreWhitespace: true\n\t      });\n\t      return wordDiff.diff(oldStr, newStr, options);\n\t    }\n\n\t    function diffWordsWithSpace(oldStr, newStr, options) {\n\t      return wordDiff.diff(oldStr, newStr, options);\n\t    }\n\n\t    var lineDiff = new Diff();\n\n\t    lineDiff.tokenize = function (value) {\n\t      var retLines = [],\n\t          linesAndNewlines = value.split(/(\\n|\\r\\n)/); // Ignore the final empty token that occurs if the string ends with a new line\n\n\t      if (!linesAndNewlines[linesAndNewlines.length - 1]) {\n\t        linesAndNewlines.pop();\n\t      } // Merge the content and line separators into single tokens\n\n\n\t      for (var i = 0; i < linesAndNewlines.length; i++) {\n\t        var line = linesAndNewlines[i];\n\n\t        if (i % 2 && !this.options.newlineIsToken) {\n\t          retLines[retLines.length - 1] += line;\n\t        } else {\n\t          if (this.options.ignoreWhitespace) {\n\t            line = line.trim();\n\t          }\n\n\t          retLines.push(line);\n\t        }\n\t      }\n\n\t      return retLines;\n\t    };\n\n\t    function diffLines(oldStr, newStr, callback) {\n\t      return lineDiff.diff(oldStr, newStr, callback);\n\t    }\n\n\t    function diffTrimmedLines(oldStr, newStr, callback) {\n\t      var options = generateOptions(callback, {\n\t        ignoreWhitespace: true\n\t      });\n\t      return lineDiff.diff(oldStr, newStr, options);\n\t    }\n\n\t    var sentenceDiff = new Diff();\n\n\t    sentenceDiff.tokenize = function (value) {\n\t      return value.split(/(\\S.+?[.!?])(?=\\s+|$)/);\n\t    };\n\n\t    function diffSentences(oldStr, newStr, callback) {\n\t      return sentenceDiff.diff(oldStr, newStr, callback);\n\t    }\n\n\t    var cssDiff = new Diff();\n\n\t    cssDiff.tokenize = function (value) {\n\t      return value.split(/([{}:;,]|\\s+)/);\n\t    };\n\n\t    function diffCss(oldStr, newStr, callback) {\n\t      return cssDiff.diff(oldStr, newStr, callback);\n\t    }\n\n\t    function _typeof(obj) {\n\t      \"@babel/helpers - typeof\";\n\n\t      if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n\t        _typeof = function _typeof(obj) {\n\t          return typeof obj;\n\t        };\n\t      } else {\n\t        _typeof = function _typeof(obj) {\n\t          return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n\t        };\n\t      }\n\n\t      return _typeof(obj);\n\t    }\n\n\t    function _toConsumableArray(arr) {\n\t      return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();\n\t    }\n\n\t    function _arrayWithoutHoles(arr) {\n\t      if (Array.isArray(arr)) return _arrayLikeToArray(arr);\n\t    }\n\n\t    function _iterableToArray(iter) {\n\t      if (typeof Symbol !== \"undefined\" && Symbol.iterator in Object(iter)) return Array.from(iter);\n\t    }\n\n\t    function _unsupportedIterableToArray(o, minLen) {\n\t      if (!o) return;\n\t      if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n\t      var n = Object.prototype.toString.call(o).slice(8, -1);\n\t      if (n === \"Object\" && o.constructor) n = o.constructor.name;\n\t      if (n === \"Map\" || n === \"Set\") return Array.from(o);\n\t      if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n\t    }\n\n\t    function _arrayLikeToArray(arr, len) {\n\t      if (len == null || len > arr.length) len = arr.length;\n\n\t      for (var i = 0, arr2 = new Array(len); i < len; i++) {\n\t        arr2[i] = arr[i];\n\t      }\n\n\t      return arr2;\n\t    }\n\n\t    function _nonIterableSpread() {\n\t      throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n\t    }\n\n\t    var objectPrototypeToString = Object.prototype.toString;\n\t    var jsonDiff = new Diff(); // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a\n\t    // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output:\n\n\t    jsonDiff.useLongestToken = true;\n\t    jsonDiff.tokenize = lineDiff.tokenize;\n\n\t    jsonDiff.castInput = function (value) {\n\t      var _this$options = this.options,\n\t          undefinedReplacement = _this$options.undefinedReplacement,\n\t          _this$options$stringi = _this$options.stringifyReplacer,\n\t          stringifyReplacer = _this$options$stringi === void 0 ? function (k, v) {\n\t        return typeof v === 'undefined' ? undefinedReplacement : v;\n\t      } : _this$options$stringi;\n\t      return typeof value === 'string' ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, '  ');\n\t    };\n\n\t    jsonDiff.equals = function (left, right) {\n\t      return Diff.prototype.equals.call(jsonDiff, left.replace(/,([\\r\\n])/g, '$1'), right.replace(/,([\\r\\n])/g, '$1'));\n\t    };\n\n\t    function diffJson(oldObj, newObj, options) {\n\t      return jsonDiff.diff(oldObj, newObj, options);\n\t    } // This function handles the presence of circular references by bailing out when encountering an\n\t    // object that is already on the \"stack\" of items being processed. Accepts an optional replacer\n\n\n\t    function canonicalize(obj, stack, replacementStack, replacer, key) {\n\t      stack = stack || [];\n\t      replacementStack = replacementStack || [];\n\n\t      if (replacer) {\n\t        obj = replacer(key, obj);\n\t      }\n\n\t      var i;\n\n\t      for (i = 0; i < stack.length; i += 1) {\n\t        if (stack[i] === obj) {\n\t          return replacementStack[i];\n\t        }\n\t      }\n\n\t      var canonicalizedObj;\n\n\t      if ('[object Array]' === objectPrototypeToString.call(obj)) {\n\t        stack.push(obj);\n\t        canonicalizedObj = new Array(obj.length);\n\t        replacementStack.push(canonicalizedObj);\n\n\t        for (i = 0; i < obj.length; i += 1) {\n\t          canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key);\n\t        }\n\n\t        stack.pop();\n\t        replacementStack.pop();\n\t        return canonicalizedObj;\n\t      }\n\n\t      if (obj && obj.toJSON) {\n\t        obj = obj.toJSON();\n\t      }\n\n\t      if (_typeof(obj) === 'object' && obj !== null) {\n\t        stack.push(obj);\n\t        canonicalizedObj = {};\n\t        replacementStack.push(canonicalizedObj);\n\n\t        var sortedKeys = [],\n\t            _key;\n\n\t        for (_key in obj) {\n\t          /* istanbul ignore else */\n\t          if (obj.hasOwnProperty(_key)) {\n\t            sortedKeys.push(_key);\n\t          }\n\t        }\n\n\t        sortedKeys.sort();\n\n\t        for (i = 0; i < sortedKeys.length; i += 1) {\n\t          _key = sortedKeys[i];\n\t          canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key);\n\t        }\n\n\t        stack.pop();\n\t        replacementStack.pop();\n\t      } else {\n\t        canonicalizedObj = obj;\n\t      }\n\n\t      return canonicalizedObj;\n\t    }\n\n\t    var arrayDiff = new Diff();\n\n\t    arrayDiff.tokenize = function (value) {\n\t      return value.slice();\n\t    };\n\n\t    arrayDiff.join = arrayDiff.removeEmpty = function (value) {\n\t      return value;\n\t    };\n\n\t    function diffArrays(oldArr, newArr, callback) {\n\t      return arrayDiff.diff(oldArr, newArr, callback);\n\t    }\n\n\t    function parsePatch(uniDiff) {\n\t      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\t      var diffstr = uniDiff.split(/\\r\\n|[\\n\\v\\f\\r\\x85]/),\n\t          delimiters = uniDiff.match(/\\r\\n|[\\n\\v\\f\\r\\x85]/g) || [],\n\t          list = [],\n\t          i = 0;\n\n\t      function parseIndex() {\n\t        var index = {};\n\t        list.push(index); // Parse diff metadata\n\n\t        while (i < diffstr.length) {\n\t          var line = diffstr[i]; // File header found, end parsing diff metadata\n\n\t          if (/^(\\-\\-\\-|\\+\\+\\+|@@)\\s/.test(line)) {\n\t            break;\n\t          } // Diff index\n\n\n\t          var header = /^(?:Index:|diff(?: -r \\w+)+)\\s+(.+?)\\s*$/.exec(line);\n\n\t          if (header) {\n\t            index.index = header[1];\n\t          }\n\n\t          i++;\n\t        } // Parse file headers if they are defined. Unified diff requires them, but\n\t        // there's no technical issues to have an isolated hunk without file header\n\n\n\t        parseFileHeader(index);\n\t        parseFileHeader(index); // Parse hunks\n\n\t        index.hunks = [];\n\n\t        while (i < diffstr.length) {\n\t          var _line = diffstr[i];\n\n\t          if (/^(Index:|diff|\\-\\-\\-|\\+\\+\\+)\\s/.test(_line)) {\n\t            break;\n\t          } else if (/^@@/.test(_line)) {\n\t            index.hunks.push(parseHunk());\n\t          } else if (_line && options.strict) {\n\t            // Ignore unexpected content unless in strict mode\n\t            throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line));\n\t          } else {\n\t            i++;\n\t          }\n\t        }\n\t      } // Parses the --- and +++ headers, if none are found, no lines\n\t      // are consumed.\n\n\n\t      function parseFileHeader(index) {\n\t        var fileHeader = /^(---|\\+\\+\\+)\\s+(.*)$/.exec(diffstr[i]);\n\n\t        if (fileHeader) {\n\t          var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new';\n\t          var data = fileHeader[2].split('\\t', 2);\n\t          var fileName = data[0].replace(/\\\\\\\\/g, '\\\\');\n\n\t          if (/^\".*\"$/.test(fileName)) {\n\t            fileName = fileName.substr(1, fileName.length - 2);\n\t          }\n\n\t          index[keyPrefix + 'FileName'] = fileName;\n\t          index[keyPrefix + 'Header'] = (data[1] || '').trim();\n\t          i++;\n\t        }\n\t      } // Parses a hunk\n\t      // This assumes that we are at the start of a hunk.\n\n\n\t      function parseHunk() {\n\t        var chunkHeaderIndex = i,\n\t            chunkHeaderLine = diffstr[i++],\n\t            chunkHeader = chunkHeaderLine.split(/@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/);\n\t        var hunk = {\n\t          oldStart: +chunkHeader[1],\n\t          oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],\n\t          newStart: +chunkHeader[3],\n\t          newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],\n\t          lines: [],\n\t          linedelimiters: []\n\t        }; // Unified Diff Format quirk: If the chunk size is 0,\n\t        // the first number is one lower than one would expect.\n\t        // https://www.artima.com/weblogs/viewpost.jsp?thread=164293\n\n\t        if (hunk.oldLines === 0) {\n\t          hunk.oldStart += 1;\n\t        }\n\n\t        if (hunk.newLines === 0) {\n\t          hunk.newStart += 1;\n\t        }\n\n\t        var addCount = 0,\n\t            removeCount = 0;\n\n\t        for (; i < diffstr.length; i++) {\n\t          // Lines starting with '---' could be mistaken for the \"remove line\" operation\n\t          // But they could be the header for the next file. Therefore prune such cases out.\n\t          if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) {\n\t            break;\n\t          }\n\n\t          var operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? ' ' : diffstr[i][0];\n\n\t          if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\\\') {\n\t            hunk.lines.push(diffstr[i]);\n\t            hunk.linedelimiters.push(delimiters[i] || '\\n');\n\n\t            if (operation === '+') {\n\t              addCount++;\n\t            } else if (operation === '-') {\n\t              removeCount++;\n\t            } else if (operation === ' ') {\n\t              addCount++;\n\t              removeCount++;\n\t            }\n\t          } else {\n\t            break;\n\t          }\n\t        } // Handle the empty block count case\n\n\n\t        if (!addCount && hunk.newLines === 1) {\n\t          hunk.newLines = 0;\n\t        }\n\n\t        if (!removeCount && hunk.oldLines === 1) {\n\t          hunk.oldLines = 0;\n\t        } // Perform optional sanity checking\n\n\n\t        if (options.strict) {\n\t          if (addCount !== hunk.newLines) {\n\t            throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));\n\t          }\n\n\t          if (removeCount !== hunk.oldLines) {\n\t            throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));\n\t          }\n\t        }\n\n\t        return hunk;\n\t      }\n\n\t      while (i < diffstr.length) {\n\t        parseIndex();\n\t      }\n\n\t      return list;\n\t    } // Iterator that traverses in the range of [min, max], stepping\n\t    // by distance from a given start position. I.e. for [0, 4], with\n\t    // start of 2, this will iterate 2, 3, 1, 4, 0.\n\n\n\t    function distanceIterator(start, minLine, maxLine) {\n\t      var wantForward = true,\n\t          backwardExhausted = false,\n\t          forwardExhausted = false,\n\t          localOffset = 1;\n\t      return function iterator() {\n\t        if (wantForward && !forwardExhausted) {\n\t          if (backwardExhausted) {\n\t            localOffset++;\n\t          } else {\n\t            wantForward = false;\n\t          } // Check if trying to fit beyond text length, and if not, check it fits\n\t          // after offset location (or desired location on first iteration)\n\n\n\t          if (start + localOffset <= maxLine) {\n\t            return localOffset;\n\t          }\n\n\t          forwardExhausted = true;\n\t        }\n\n\t        if (!backwardExhausted) {\n\t          if (!forwardExhausted) {\n\t            wantForward = true;\n\t          } // Check if trying to fit before text beginning, and if not, check it fits\n\t          // before offset location\n\n\n\t          if (minLine <= start - localOffset) {\n\t            return -localOffset++;\n\t          }\n\n\t          backwardExhausted = true;\n\t          return iterator();\n\t        } // We tried to fit hunk before text beginning and beyond text length, then\n\t        // hunk can't fit on the text. Return undefined\n\n\t      };\n\t    }\n\n\t    function applyPatch(source, uniDiff) {\n\t      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n\t      if (typeof uniDiff === 'string') {\n\t        uniDiff = parsePatch(uniDiff);\n\t      }\n\n\t      if (Array.isArray(uniDiff)) {\n\t        if (uniDiff.length > 1) {\n\t          throw new Error('applyPatch only works with a single input.');\n\t        }\n\n\t        uniDiff = uniDiff[0];\n\t      } // Apply the diff to the input\n\n\n\t      var lines = source.split(/\\r\\n|[\\n\\v\\f\\r\\x85]/),\n\t          delimiters = source.match(/\\r\\n|[\\n\\v\\f\\r\\x85]/g) || [],\n\t          hunks = uniDiff.hunks,\n\t          compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) {\n\t        return line === patchContent;\n\t      },\n\t          errorCount = 0,\n\t          fuzzFactor = options.fuzzFactor || 0,\n\t          minLine = 0,\n\t          offset = 0,\n\t          removeEOFNL,\n\t          addEOFNL;\n\t      /**\n\t       * Checks if the hunk exactly fits on the provided location\n\t       */\n\n\n\t      function hunkFits(hunk, toPos) {\n\t        for (var j = 0; j < hunk.lines.length; j++) {\n\t          var line = hunk.lines[j],\n\t              operation = line.length > 0 ? line[0] : ' ',\n\t              content = line.length > 0 ? line.substr(1) : line;\n\n\t          if (operation === ' ' || operation === '-') {\n\t            // Context sanity check\n\t            if (!compareLine(toPos + 1, lines[toPos], operation, content)) {\n\t              errorCount++;\n\n\t              if (errorCount > fuzzFactor) {\n\t                return false;\n\t              }\n\t            }\n\n\t            toPos++;\n\t          }\n\t        }\n\n\t        return true;\n\t      } // Search best fit offsets for each hunk based on the previous ones\n\n\n\t      for (var i = 0; i < hunks.length; i++) {\n\t        var hunk = hunks[i],\n\t            maxLine = lines.length - hunk.oldLines,\n\t            localOffset = 0,\n\t            toPos = offset + hunk.oldStart - 1;\n\t        var iterator = distanceIterator(toPos, minLine, maxLine);\n\n\t        for (; localOffset !== undefined; localOffset = iterator()) {\n\t          if (hunkFits(hunk, toPos + localOffset)) {\n\t            hunk.offset = offset += localOffset;\n\t            break;\n\t          }\n\t        }\n\n\t        if (localOffset === undefined) {\n\t          return false;\n\t        } // Set lower text limit to end of the current hunk, so next ones don't try\n\t        // to fit over already patched text\n\n\n\t        minLine = hunk.offset + hunk.oldStart + hunk.oldLines;\n\t      } // Apply patch hunks\n\n\n\t      var diffOffset = 0;\n\n\t      for (var _i = 0; _i < hunks.length; _i++) {\n\t        var _hunk = hunks[_i],\n\t            _toPos = _hunk.oldStart + _hunk.offset + diffOffset - 1;\n\n\t        diffOffset += _hunk.newLines - _hunk.oldLines;\n\n\t        for (var j = 0; j < _hunk.lines.length; j++) {\n\t          var line = _hunk.lines[j],\n\t              operation = line.length > 0 ? line[0] : ' ',\n\t              content = line.length > 0 ? line.substr(1) : line,\n\t              delimiter = _hunk.linedelimiters[j];\n\n\t          if (operation === ' ') {\n\t            _toPos++;\n\t          } else if (operation === '-') {\n\t            lines.splice(_toPos, 1);\n\t            delimiters.splice(_toPos, 1);\n\t            /* istanbul ignore else */\n\t          } else if (operation === '+') {\n\t            lines.splice(_toPos, 0, content);\n\t            delimiters.splice(_toPos, 0, delimiter);\n\t            _toPos++;\n\t          } else if (operation === '\\\\') {\n\t            var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null;\n\n\t            if (previousOperation === '+') {\n\t              removeEOFNL = true;\n\t            } else if (previousOperation === '-') {\n\t              addEOFNL = true;\n\t            }\n\t          }\n\t        }\n\t      } // Handle EOFNL insertion/removal\n\n\n\t      if (removeEOFNL) {\n\t        while (!lines[lines.length - 1]) {\n\t          lines.pop();\n\t          delimiters.pop();\n\t        }\n\t      } else if (addEOFNL) {\n\t        lines.push('');\n\t        delimiters.push('\\n');\n\t      }\n\n\t      for (var _k = 0; _k < lines.length - 1; _k++) {\n\t        lines[_k] = lines[_k] + delimiters[_k];\n\t      }\n\n\t      return lines.join('');\n\t    } // Wrapper that supports multiple file patches via callbacks.\n\n\n\t    function applyPatches(uniDiff, options) {\n\t      if (typeof uniDiff === 'string') {\n\t        uniDiff = parsePatch(uniDiff);\n\t      }\n\n\t      var currentIndex = 0;\n\n\t      function processIndex() {\n\t        var index = uniDiff[currentIndex++];\n\n\t        if (!index) {\n\t          return options.complete();\n\t        }\n\n\t        options.loadFile(index, function (err, data) {\n\t          if (err) {\n\t            return options.complete(err);\n\t          }\n\n\t          var updatedContent = applyPatch(data, index, options);\n\t          options.patched(index, updatedContent, function (err) {\n\t            if (err) {\n\t              return options.complete(err);\n\t            }\n\n\t            processIndex();\n\t          });\n\t        });\n\t      }\n\n\t      processIndex();\n\t    }\n\n\t    function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {\n\t      if (!options) {\n\t        options = {};\n\t      }\n\n\t      if (typeof options.context === 'undefined') {\n\t        options.context = 4;\n\t      }\n\n\t      var diff = diffLines(oldStr, newStr, options);\n\t      diff.push({\n\t        value: '',\n\t        lines: []\n\t      }); // Append an empty value to make cleanup easier\n\n\t      function contextLines(lines) {\n\t        return lines.map(function (entry) {\n\t          return ' ' + entry;\n\t        });\n\t      }\n\n\t      var hunks = [];\n\t      var oldRangeStart = 0,\n\t          newRangeStart = 0,\n\t          curRange = [],\n\t          oldLine = 1,\n\t          newLine = 1;\n\n\t      var _loop = function _loop(i) {\n\t        var current = diff[i],\n\t            lines = current.lines || current.value.replace(/\\n$/, '').split('\\n');\n\t        current.lines = lines;\n\n\t        if (current.added || current.removed) {\n\t          var _curRange; // If we have previous context, start with that\n\n\n\t          if (!oldRangeStart) {\n\t            var prev = diff[i - 1];\n\t            oldRangeStart = oldLine;\n\t            newRangeStart = newLine;\n\n\t            if (prev) {\n\t              curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : [];\n\t              oldRangeStart -= curRange.length;\n\t              newRangeStart -= curRange.length;\n\t            }\n\t          } // Output our changes\n\n\n\t          (_curRange = curRange).push.apply(_curRange, _toConsumableArray(lines.map(function (entry) {\n\t            return (current.added ? '+' : '-') + entry;\n\t          }))); // Track the updated file position\n\n\n\t          if (current.added) {\n\t            newLine += lines.length;\n\t          } else {\n\t            oldLine += lines.length;\n\t          }\n\t        } else {\n\t          // Identical context lines. Track line changes\n\t          if (oldRangeStart) {\n\t            // Close out any changes that have been output (or join overlapping)\n\t            if (lines.length <= options.context * 2 && i < diff.length - 2) {\n\t              var _curRange2; // Overlapping\n\n\n\t              (_curRange2 = curRange).push.apply(_curRange2, _toConsumableArray(contextLines(lines)));\n\t            } else {\n\t              var _curRange3; // end the range and output\n\n\n\t              var contextSize = Math.min(lines.length, options.context);\n\n\t              (_curRange3 = curRange).push.apply(_curRange3, _toConsumableArray(contextLines(lines.slice(0, contextSize))));\n\n\t              var hunk = {\n\t                oldStart: oldRangeStart,\n\t                oldLines: oldLine - oldRangeStart + contextSize,\n\t                newStart: newRangeStart,\n\t                newLines: newLine - newRangeStart + contextSize,\n\t                lines: curRange\n\t              };\n\n\t              if (i >= diff.length - 2 && lines.length <= options.context) {\n\t                // EOF is inside this hunk\n\t                var oldEOFNewline = /\\n$/.test(oldStr);\n\t                var newEOFNewline = /\\n$/.test(newStr);\n\t                var noNlBeforeAdds = lines.length == 0 && curRange.length > hunk.oldLines;\n\n\t                if (!oldEOFNewline && noNlBeforeAdds && oldStr.length > 0) {\n\t                  // special case: old has no eol and no trailing context; no-nl can end up before adds\n\t                  // however, if the old file is empty, do not output the no-nl line\n\t                  curRange.splice(hunk.oldLines, 0, '\\\\ No newline at end of file');\n\t                }\n\n\t                if (!oldEOFNewline && !noNlBeforeAdds || !newEOFNewline) {\n\t                  curRange.push('\\\\ No newline at end of file');\n\t                }\n\t              }\n\n\t              hunks.push(hunk);\n\t              oldRangeStart = 0;\n\t              newRangeStart = 0;\n\t              curRange = [];\n\t            }\n\t          }\n\n\t          oldLine += lines.length;\n\t          newLine += lines.length;\n\t        }\n\t      };\n\n\t      for (var i = 0; i < diff.length; i++) {\n\t        _loop(i);\n\t      }\n\n\t      return {\n\t        oldFileName: oldFileName,\n\t        newFileName: newFileName,\n\t        oldHeader: oldHeader,\n\t        newHeader: newHeader,\n\t        hunks: hunks\n\t      };\n\t    }\n\n\t    function formatPatch(diff) {\n\t      var ret = [];\n\n\t      if (diff.oldFileName == diff.newFileName) {\n\t        ret.push('Index: ' + diff.oldFileName);\n\t      }\n\n\t      ret.push('===================================================================');\n\t      ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\\t' + diff.oldHeader));\n\t      ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\\t' + diff.newHeader));\n\n\t      for (var i = 0; i < diff.hunks.length; i++) {\n\t        var hunk = diff.hunks[i]; // Unified Diff Format quirk: If the chunk size is 0,\n\t        // the first number is one lower than one would expect.\n\t        // https://www.artima.com/weblogs/viewpost.jsp?thread=164293\n\n\t        if (hunk.oldLines === 0) {\n\t          hunk.oldStart -= 1;\n\t        }\n\n\t        if (hunk.newLines === 0) {\n\t          hunk.newStart -= 1;\n\t        }\n\n\t        ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@');\n\t        ret.push.apply(ret, hunk.lines);\n\t      }\n\n\t      return ret.join('\\n') + '\\n';\n\t    }\n\n\t    function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {\n\t      return formatPatch(structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options));\n\t    }\n\n\t    function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) {\n\t      return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options);\n\t    }\n\n\t    function arrayEqual(a, b) {\n\t      if (a.length !== b.length) {\n\t        return false;\n\t      }\n\n\t      return arrayStartsWith(a, b);\n\t    }\n\n\t    function arrayStartsWith(array, start) {\n\t      if (start.length > array.length) {\n\t        return false;\n\t      }\n\n\t      for (var i = 0; i < start.length; i++) {\n\t        if (start[i] !== array[i]) {\n\t          return false;\n\t        }\n\t      }\n\n\t      return true;\n\t    }\n\n\t    function calcLineCount(hunk) {\n\t      var _calcOldNewLineCount = calcOldNewLineCount(hunk.lines),\n\t          oldLines = _calcOldNewLineCount.oldLines,\n\t          newLines = _calcOldNewLineCount.newLines;\n\n\t      if (oldLines !== undefined) {\n\t        hunk.oldLines = oldLines;\n\t      } else {\n\t        delete hunk.oldLines;\n\t      }\n\n\t      if (newLines !== undefined) {\n\t        hunk.newLines = newLines;\n\t      } else {\n\t        delete hunk.newLines;\n\t      }\n\t    }\n\n\t    function merge(mine, theirs, base) {\n\t      mine = loadPatch(mine, base);\n\t      theirs = loadPatch(theirs, base);\n\t      var ret = {}; // For index we just let it pass through as it doesn't have any necessary meaning.\n\t      // Leaving sanity checks on this to the API consumer that may know more about the\n\t      // meaning in their own context.\n\n\t      if (mine.index || theirs.index) {\n\t        ret.index = mine.index || theirs.index;\n\t      }\n\n\t      if (mine.newFileName || theirs.newFileName) {\n\t        if (!fileNameChanged(mine)) {\n\t          // No header or no change in ours, use theirs (and ours if theirs does not exist)\n\t          ret.oldFileName = theirs.oldFileName || mine.oldFileName;\n\t          ret.newFileName = theirs.newFileName || mine.newFileName;\n\t          ret.oldHeader = theirs.oldHeader || mine.oldHeader;\n\t          ret.newHeader = theirs.newHeader || mine.newHeader;\n\t        } else if (!fileNameChanged(theirs)) {\n\t          // No header or no change in theirs, use ours\n\t          ret.oldFileName = mine.oldFileName;\n\t          ret.newFileName = mine.newFileName;\n\t          ret.oldHeader = mine.oldHeader;\n\t          ret.newHeader = mine.newHeader;\n\t        } else {\n\t          // Both changed... figure it out\n\t          ret.oldFileName = selectField(ret, mine.oldFileName, theirs.oldFileName);\n\t          ret.newFileName = selectField(ret, mine.newFileName, theirs.newFileName);\n\t          ret.oldHeader = selectField(ret, mine.oldHeader, theirs.oldHeader);\n\t          ret.newHeader = selectField(ret, mine.newHeader, theirs.newHeader);\n\t        }\n\t      }\n\n\t      ret.hunks = [];\n\t      var mineIndex = 0,\n\t          theirsIndex = 0,\n\t          mineOffset = 0,\n\t          theirsOffset = 0;\n\n\t      while (mineIndex < mine.hunks.length || theirsIndex < theirs.hunks.length) {\n\t        var mineCurrent = mine.hunks[mineIndex] || {\n\t          oldStart: Infinity\n\t        },\n\t            theirsCurrent = theirs.hunks[theirsIndex] || {\n\t          oldStart: Infinity\n\t        };\n\n\t        if (hunkBefore(mineCurrent, theirsCurrent)) {\n\t          // This patch does not overlap with any of the others, yay.\n\t          ret.hunks.push(cloneHunk(mineCurrent, mineOffset));\n\t          mineIndex++;\n\t          theirsOffset += mineCurrent.newLines - mineCurrent.oldLines;\n\t        } else if (hunkBefore(theirsCurrent, mineCurrent)) {\n\t          // This patch does not overlap with any of the others, yay.\n\t          ret.hunks.push(cloneHunk(theirsCurrent, theirsOffset));\n\t          theirsIndex++;\n\t          mineOffset += theirsCurrent.newLines - theirsCurrent.oldLines;\n\t        } else {\n\t          // Overlap, merge as best we can\n\t          var mergedHunk = {\n\t            oldStart: Math.min(mineCurrent.oldStart, theirsCurrent.oldStart),\n\t            oldLines: 0,\n\t            newStart: Math.min(mineCurrent.newStart + mineOffset, theirsCurrent.oldStart + theirsOffset),\n\t            newLines: 0,\n\t            lines: []\n\t          };\n\t          mergeLines(mergedHunk, mineCurrent.oldStart, mineCurrent.lines, theirsCurrent.oldStart, theirsCurrent.lines);\n\t          theirsIndex++;\n\t          mineIndex++;\n\t          ret.hunks.push(mergedHunk);\n\t        }\n\t      }\n\n\t      return ret;\n\t    }\n\n\t    function loadPatch(param, base) {\n\t      if (typeof param === 'string') {\n\t        if (/^@@/m.test(param) || /^Index:/m.test(param)) {\n\t          return parsePatch(param)[0];\n\t        }\n\n\t        if (!base) {\n\t          throw new Error('Must provide a base reference or pass in a patch');\n\t        }\n\n\t        return structuredPatch(undefined, undefined, base, param);\n\t      }\n\n\t      return param;\n\t    }\n\n\t    function fileNameChanged(patch) {\n\t      return patch.newFileName && patch.newFileName !== patch.oldFileName;\n\t    }\n\n\t    function selectField(index, mine, theirs) {\n\t      if (mine === theirs) {\n\t        return mine;\n\t      } else {\n\t        index.conflict = true;\n\t        return {\n\t          mine: mine,\n\t          theirs: theirs\n\t        };\n\t      }\n\t    }\n\n\t    function hunkBefore(test, check) {\n\t      return test.oldStart < check.oldStart && test.oldStart + test.oldLines < check.oldStart;\n\t    }\n\n\t    function cloneHunk(hunk, offset) {\n\t      return {\n\t        oldStart: hunk.oldStart,\n\t        oldLines: hunk.oldLines,\n\t        newStart: hunk.newStart + offset,\n\t        newLines: hunk.newLines,\n\t        lines: hunk.lines\n\t      };\n\t    }\n\n\t    function mergeLines(hunk, mineOffset, mineLines, theirOffset, theirLines) {\n\t      // This will generally result in a conflicted hunk, but there are cases where the context\n\t      // is the only overlap where we can successfully merge the content here.\n\t      var mine = {\n\t        offset: mineOffset,\n\t        lines: mineLines,\n\t        index: 0\n\t      },\n\t          their = {\n\t        offset: theirOffset,\n\t        lines: theirLines,\n\t        index: 0\n\t      }; // Handle any leading content\n\n\t      insertLeading(hunk, mine, their);\n\t      insertLeading(hunk, their, mine); // Now in the overlap content. Scan through and select the best changes from each.\n\n\t      while (mine.index < mine.lines.length && their.index < their.lines.length) {\n\t        var mineCurrent = mine.lines[mine.index],\n\t            theirCurrent = their.lines[their.index];\n\n\t        if ((mineCurrent[0] === '-' || mineCurrent[0] === '+') && (theirCurrent[0] === '-' || theirCurrent[0] === '+')) {\n\t          // Both modified ...\n\t          mutualChange(hunk, mine, their);\n\t        } else if (mineCurrent[0] === '+' && theirCurrent[0] === ' ') {\n\t          var _hunk$lines; // Mine inserted\n\n\n\t          (_hunk$lines = hunk.lines).push.apply(_hunk$lines, _toConsumableArray(collectChange(mine)));\n\t        } else if (theirCurrent[0] === '+' && mineCurrent[0] === ' ') {\n\t          var _hunk$lines2; // Theirs inserted\n\n\n\t          (_hunk$lines2 = hunk.lines).push.apply(_hunk$lines2, _toConsumableArray(collectChange(their)));\n\t        } else if (mineCurrent[0] === '-' && theirCurrent[0] === ' ') {\n\t          // Mine removed or edited\n\t          removal(hunk, mine, their);\n\t        } else if (theirCurrent[0] === '-' && mineCurrent[0] === ' ') {\n\t          // Their removed or edited\n\t          removal(hunk, their, mine, true);\n\t        } else if (mineCurrent === theirCurrent) {\n\t          // Context identity\n\t          hunk.lines.push(mineCurrent);\n\t          mine.index++;\n\t          their.index++;\n\t        } else {\n\t          // Context mismatch\n\t          conflict(hunk, collectChange(mine), collectChange(their));\n\t        }\n\t      } // Now push anything that may be remaining\n\n\n\t      insertTrailing(hunk, mine);\n\t      insertTrailing(hunk, their);\n\t      calcLineCount(hunk);\n\t    }\n\n\t    function mutualChange(hunk, mine, their) {\n\t      var myChanges = collectChange(mine),\n\t          theirChanges = collectChange(their);\n\n\t      if (allRemoves(myChanges) && allRemoves(theirChanges)) {\n\t        // Special case for remove changes that are supersets of one another\n\t        if (arrayStartsWith(myChanges, theirChanges) && skipRemoveSuperset(their, myChanges, myChanges.length - theirChanges.length)) {\n\t          var _hunk$lines3;\n\n\t          (_hunk$lines3 = hunk.lines).push.apply(_hunk$lines3, _toConsumableArray(myChanges));\n\n\t          return;\n\t        } else if (arrayStartsWith(theirChanges, myChanges) && skipRemoveSuperset(mine, theirChanges, theirChanges.length - myChanges.length)) {\n\t          var _hunk$lines4;\n\n\t          (_hunk$lines4 = hunk.lines).push.apply(_hunk$lines4, _toConsumableArray(theirChanges));\n\n\t          return;\n\t        }\n\t      } else if (arrayEqual(myChanges, theirChanges)) {\n\t        var _hunk$lines5;\n\n\t        (_hunk$lines5 = hunk.lines).push.apply(_hunk$lines5, _toConsumableArray(myChanges));\n\n\t        return;\n\t      }\n\n\t      conflict(hunk, myChanges, theirChanges);\n\t    }\n\n\t    function removal(hunk, mine, their, swap) {\n\t      var myChanges = collectChange(mine),\n\t          theirChanges = collectContext(their, myChanges);\n\n\t      if (theirChanges.merged) {\n\t        var _hunk$lines6;\n\n\t        (_hunk$lines6 = hunk.lines).push.apply(_hunk$lines6, _toConsumableArray(theirChanges.merged));\n\t      } else {\n\t        conflict(hunk, swap ? theirChanges : myChanges, swap ? myChanges : theirChanges);\n\t      }\n\t    }\n\n\t    function conflict(hunk, mine, their) {\n\t      hunk.conflict = true;\n\t      hunk.lines.push({\n\t        conflict: true,\n\t        mine: mine,\n\t        theirs: their\n\t      });\n\t    }\n\n\t    function insertLeading(hunk, insert, their) {\n\t      while (insert.offset < their.offset && insert.index < insert.lines.length) {\n\t        var line = insert.lines[insert.index++];\n\t        hunk.lines.push(line);\n\t        insert.offset++;\n\t      }\n\t    }\n\n\t    function insertTrailing(hunk, insert) {\n\t      while (insert.index < insert.lines.length) {\n\t        var line = insert.lines[insert.index++];\n\t        hunk.lines.push(line);\n\t      }\n\t    }\n\n\t    function collectChange(state) {\n\t      var ret = [],\n\t          operation = state.lines[state.index][0];\n\n\t      while (state.index < state.lines.length) {\n\t        var line = state.lines[state.index]; // Group additions that are immediately after subtractions and treat them as one \"atomic\" modify change.\n\n\t        if (operation === '-' && line[0] === '+') {\n\t          operation = '+';\n\t        }\n\n\t        if (operation === line[0]) {\n\t          ret.push(line);\n\t          state.index++;\n\t        } else {\n\t          break;\n\t        }\n\t      }\n\n\t      return ret;\n\t    }\n\n\t    function collectContext(state, matchChanges) {\n\t      var changes = [],\n\t          merged = [],\n\t          matchIndex = 0,\n\t          contextChanges = false,\n\t          conflicted = false;\n\n\t      while (matchIndex < matchChanges.length && state.index < state.lines.length) {\n\t        var change = state.lines[state.index],\n\t            match = matchChanges[matchIndex]; // Once we've hit our add, then we are done\n\n\t        if (match[0] === '+') {\n\t          break;\n\t        }\n\n\t        contextChanges = contextChanges || change[0] !== ' ';\n\t        merged.push(match);\n\t        matchIndex++; // Consume any additions in the other block as a conflict to attempt\n\t        // to pull in the remaining context after this\n\n\t        if (change[0] === '+') {\n\t          conflicted = true;\n\n\t          while (change[0] === '+') {\n\t            changes.push(change);\n\t            change = state.lines[++state.index];\n\t          }\n\t        }\n\n\t        if (match.substr(1) === change.substr(1)) {\n\t          changes.push(change);\n\t          state.index++;\n\t        } else {\n\t          conflicted = true;\n\t        }\n\t      }\n\n\t      if ((matchChanges[matchIndex] || '')[0] === '+' && contextChanges) {\n\t        conflicted = true;\n\t      }\n\n\t      if (conflicted) {\n\t        return changes;\n\t      }\n\n\t      while (matchIndex < matchChanges.length) {\n\t        merged.push(matchChanges[matchIndex++]);\n\t      }\n\n\t      return {\n\t        merged: merged,\n\t        changes: changes\n\t      };\n\t    }\n\n\t    function allRemoves(changes) {\n\t      return changes.reduce(function (prev, change) {\n\t        return prev && change[0] === '-';\n\t      }, true);\n\t    }\n\n\t    function skipRemoveSuperset(state, removeChanges, delta) {\n\t      for (var i = 0; i < delta; i++) {\n\t        var changeContent = removeChanges[removeChanges.length - delta + i].substr(1);\n\n\t        if (state.lines[state.index + i] !== ' ' + changeContent) {\n\t          return false;\n\t        }\n\t      }\n\n\t      state.index += delta;\n\t      return true;\n\t    }\n\n\t    function calcOldNewLineCount(lines) {\n\t      var oldLines = 0;\n\t      var newLines = 0;\n\t      lines.forEach(function (line) {\n\t        if (typeof line !== 'string') {\n\t          var myCount = calcOldNewLineCount(line.mine);\n\t          var theirCount = calcOldNewLineCount(line.theirs);\n\n\t          if (oldLines !== undefined) {\n\t            if (myCount.oldLines === theirCount.oldLines) {\n\t              oldLines += myCount.oldLines;\n\t            } else {\n\t              oldLines = undefined;\n\t            }\n\t          }\n\n\t          if (newLines !== undefined) {\n\t            if (myCount.newLines === theirCount.newLines) {\n\t              newLines += myCount.newLines;\n\t            } else {\n\t              newLines = undefined;\n\t            }\n\t          }\n\t        } else {\n\t          if (newLines !== undefined && (line[0] === '+' || line[0] === ' ')) {\n\t            newLines++;\n\t          }\n\n\t          if (oldLines !== undefined && (line[0] === '-' || line[0] === ' ')) {\n\t            oldLines++;\n\t          }\n\t        }\n\t      });\n\t      return {\n\t        oldLines: oldLines,\n\t        newLines: newLines\n\t      };\n\t    } // See: http://code.google.com/p/google-diff-match-patch/wiki/API\n\n\n\t    function convertChangesToDMP(changes) {\n\t      var ret = [],\n\t          change,\n\t          operation;\n\n\t      for (var i = 0; i < changes.length; i++) {\n\t        change = changes[i];\n\n\t        if (change.added) {\n\t          operation = 1;\n\t        } else if (change.removed) {\n\t          operation = -1;\n\t        } else {\n\t          operation = 0;\n\t        }\n\n\t        ret.push([operation, change.value]);\n\t      }\n\n\t      return ret;\n\t    }\n\n\t    function convertChangesToXML(changes) {\n\t      var ret = [];\n\n\t      for (var i = 0; i < changes.length; i++) {\n\t        var change = changes[i];\n\n\t        if (change.added) {\n\t          ret.push('<ins>');\n\t        } else if (change.removed) {\n\t          ret.push('<del>');\n\t        }\n\n\t        ret.push(escapeHTML(change.value));\n\n\t        if (change.added) {\n\t          ret.push('</ins>');\n\t        } else if (change.removed) {\n\t          ret.push('</del>');\n\t        }\n\t      }\n\n\t      return ret.join('');\n\t    }\n\n\t    function escapeHTML(s) {\n\t      var n = s;\n\t      n = n.replace(/&/g, '&amp;');\n\t      n = n.replace(/</g, '&lt;');\n\t      n = n.replace(/>/g, '&gt;');\n\t      n = n.replace(/\"/g, '&quot;');\n\t      return n;\n\t    }\n\n\t    exports.Diff = Diff;\n\t    exports.applyPatch = applyPatch;\n\t    exports.applyPatches = applyPatches;\n\t    exports.canonicalize = canonicalize;\n\t    exports.convertChangesToDMP = convertChangesToDMP;\n\t    exports.convertChangesToXML = convertChangesToXML;\n\t    exports.createPatch = createPatch;\n\t    exports.createTwoFilesPatch = createTwoFilesPatch;\n\t    exports.diffArrays = diffArrays;\n\t    exports.diffChars = diffChars;\n\t    exports.diffCss = diffCss;\n\t    exports.diffJson = diffJson;\n\t    exports.diffLines = diffLines;\n\t    exports.diffSentences = diffSentences;\n\t    exports.diffTrimmedLines = diffTrimmedLines;\n\t    exports.diffWords = diffWords;\n\t    exports.diffWordsWithSpace = diffWordsWithSpace;\n\t    exports.merge = merge;\n\t    exports.parsePatch = parsePatch;\n\t    exports.structuredPatch = structuredPatch;\n\t    Object.defineProperty(exports, '__esModule', {\n\t      value: true\n\t    });\n\t  });\n\t});\n\n\t/**\n\t * Helpers.\n\t */\n\tvar s$1 = 1000;\n\tvar m$1 = s$1 * 60;\n\tvar h$1 = m$1 * 60;\n\tvar d$1 = h$1 * 24;\n\tvar w$1 = d$1 * 7;\n\tvar y$1 = d$1 * 365.25;\n\t/**\n\t * Parse or format the given `val`.\n\t *\n\t * Options:\n\t *\n\t *  - `long` verbose formatting [false]\n\t *\n\t * @param {String|Number} val\n\t * @param {Object} [options]\n\t * @throws {Error} throw an error if val is not a non-empty string or a number\n\t * @return {String|Number}\n\t * @api public\n\t */\n\n\tvar ms$1 = function ms(val, options) {\n\t  options = options || {};\n\n\t  var type = _typeof(val);\n\n\t  if (type === 'string' && val.length > 0) {\n\t    return parse$1(val);\n\t  } else if (type === 'number' && isFinite(val)) {\n\t    return options[\"long\"] ? fmtLong$1(val) : fmtShort$1(val);\n\t  }\n\n\t  throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val));\n\t};\n\t/**\n\t * Parse the given `str` and return milliseconds.\n\t *\n\t * @param {String} str\n\t * @return {Number}\n\t * @api private\n\t */\n\n\n\tfunction parse$1(str) {\n\t  str = String(str);\n\n\t  if (str.length > 100) {\n\t    return;\n\t  }\n\n\t  var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);\n\n\t  if (!match) {\n\t    return;\n\t  }\n\n\t  var n = parseFloat(match[1]);\n\t  var type = (match[2] || 'ms').toLowerCase();\n\n\t  switch (type) {\n\t    case 'years':\n\t    case 'year':\n\t    case 'yrs':\n\t    case 'yr':\n\t    case 'y':\n\t      return n * y$1;\n\n\t    case 'weeks':\n\t    case 'week':\n\t    case 'w':\n\t      return n * w$1;\n\n\t    case 'days':\n\t    case 'day':\n\t    case 'd':\n\t      return n * d$1;\n\n\t    case 'hours':\n\t    case 'hour':\n\t    case 'hrs':\n\t    case 'hr':\n\t    case 'h':\n\t      return n * h$1;\n\n\t    case 'minutes':\n\t    case 'minute':\n\t    case 'mins':\n\t    case 'min':\n\t    case 'm':\n\t      return n * m$1;\n\n\t    case 'seconds':\n\t    case 'second':\n\t    case 'secs':\n\t    case 'sec':\n\t    case 's':\n\t      return n * s$1;\n\n\t    case 'milliseconds':\n\t    case 'millisecond':\n\t    case 'msecs':\n\t    case 'msec':\n\t    case 'ms':\n\t      return n;\n\n\t    default:\n\t      return undefined;\n\t  }\n\t}\n\t/**\n\t * Short format for `ms`.\n\t *\n\t * @param {Number} ms\n\t * @return {String}\n\t * @api private\n\t */\n\n\n\tfunction fmtShort$1(ms) {\n\t  var msAbs = Math.abs(ms);\n\n\t  if (msAbs >= d$1) {\n\t    return Math.round(ms / d$1) + 'd';\n\t  }\n\n\t  if (msAbs >= h$1) {\n\t    return Math.round(ms / h$1) + 'h';\n\t  }\n\n\t  if (msAbs >= m$1) {\n\t    return Math.round(ms / m$1) + 'm';\n\t  }\n\n\t  if (msAbs >= s$1) {\n\t    return Math.round(ms / s$1) + 's';\n\t  }\n\n\t  return ms + 'ms';\n\t}\n\t/**\n\t * Long format for `ms`.\n\t *\n\t * @param {Number} ms\n\t * @return {String}\n\t * @api private\n\t */\n\n\n\tfunction fmtLong$1(ms) {\n\t  var msAbs = Math.abs(ms);\n\n\t  if (msAbs >= d$1) {\n\t    return plural$1(ms, msAbs, d$1, 'day');\n\t  }\n\n\t  if (msAbs >= h$1) {\n\t    return plural$1(ms, msAbs, h$1, 'hour');\n\t  }\n\n\t  if (msAbs >= m$1) {\n\t    return plural$1(ms, msAbs, m$1, 'minute');\n\t  }\n\n\t  if (msAbs >= s$1) {\n\t    return plural$1(ms, msAbs, s$1, 'second');\n\t  }\n\n\t  return ms + ' ms';\n\t}\n\t/**\n\t * Pluralization helper.\n\t */\n\n\n\tfunction plural$1(ms, msAbs, n, name) {\n\t  var isPlural = msAbs >= n * 1.5;\n\t  return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n\t}\n\n\t// FF26- bug: ArrayBuffers are non-extensible, but Object.isExtensible does not report it\n\n\n\tvar arrayBufferNonExtensible = fails(function () {\n\t  if (typeof ArrayBuffer == 'function') {\n\t    var buffer = new ArrayBuffer(8);\n\t    // eslint-disable-next-line es/no-object-isextensible, es/no-object-defineproperty -- safe\n\t    if (Object.isExtensible(buffer)) Object.defineProperty(buffer, 'a', { value: 8 });\n\t  }\n\t});\n\n\t// eslint-disable-next-line es/no-object-isextensible -- safe\n\tvar $isExtensible = Object.isExtensible;\n\tvar FAILS_ON_PRIMITIVES$1 = fails(function () { $isExtensible(1); });\n\n\t// `Object.isExtensible` method\n\t// https://tc39.es/ecma262/#sec-object.isextensible\n\tvar objectIsExtensible = (FAILS_ON_PRIMITIVES$1 || arrayBufferNonExtensible) ? function isExtensible(it) {\n\t  if (!isObject$1(it)) return false;\n\t  if (arrayBufferNonExtensible && classofRaw(it) == 'ArrayBuffer') return false;\n\t  return $isExtensible ? $isExtensible(it) : true;\n\t} : $isExtensible;\n\n\tvar freezing = !fails(function () {\n\t  // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing\n\t  return Object.isExtensible(Object.preventExtensions({}));\n\t});\n\n\tvar internalMetadata = createCommonjsModule(function (module) {\n\tvar defineProperty = objectDefineProperty.f;\n\n\n\n\n\n\n\tvar REQUIRED = false;\n\tvar METADATA = uid('meta');\n\tvar id = 0;\n\n\tvar setMetadata = function (it) {\n\t  defineProperty(it, METADATA, { value: {\n\t    objectID: 'O' + id++, // object ID\n\t    weakData: {}          // weak collections IDs\n\t  } });\n\t};\n\n\tvar fastKey = function (it, create) {\n\t  // return a primitive with prefix\n\t  if (!isObject$1(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;\n\t  if (!hasOwnProperty_1(it, METADATA)) {\n\t    // can't set metadata to uncaught frozen object\n\t    if (!objectIsExtensible(it)) return 'F';\n\t    // not necessary to add metadata\n\t    if (!create) return 'E';\n\t    // add missing metadata\n\t    setMetadata(it);\n\t  // return object ID\n\t  } return it[METADATA].objectID;\n\t};\n\n\tvar getWeakData = function (it, create) {\n\t  if (!hasOwnProperty_1(it, METADATA)) {\n\t    // can't set metadata to uncaught frozen object\n\t    if (!objectIsExtensible(it)) return true;\n\t    // not necessary to add metadata\n\t    if (!create) return false;\n\t    // add missing metadata\n\t    setMetadata(it);\n\t  // return the store of weak collections IDs\n\t  } return it[METADATA].weakData;\n\t};\n\n\t// add metadata on freeze-family methods calling\n\tvar onFreeze = function (it) {\n\t  if (freezing && REQUIRED && objectIsExtensible(it) && !hasOwnProperty_1(it, METADATA)) setMetadata(it);\n\t  return it;\n\t};\n\n\tvar enable = function () {\n\t  meta.enable = function () { /* empty */ };\n\t  REQUIRED = true;\n\t  var getOwnPropertyNames = objectGetOwnPropertyNames.f;\n\t  var splice = functionUncurryThis([].splice);\n\t  var test = {};\n\t  test[METADATA] = 1;\n\n\t  // prevent exposing of metadata key\n\t  if (getOwnPropertyNames(test).length) {\n\t    objectGetOwnPropertyNames.f = function (it) {\n\t      var result = getOwnPropertyNames(it);\n\t      for (var i = 0, length = result.length; i < length; i++) {\n\t        if (result[i] === METADATA) {\n\t          splice(result, i, 1);\n\t          break;\n\t        }\n\t      } return result;\n\t    };\n\n\t    _export({ target: 'Object', stat: true, forced: true }, {\n\t      getOwnPropertyNames: objectGetOwnPropertyNamesExternal.f\n\t    });\n\t  }\n\t};\n\n\tvar meta = module.exports = {\n\t  enable: enable,\n\t  fastKey: fastKey,\n\t  getWeakData: getWeakData,\n\t  onFreeze: onFreeze\n\t};\n\n\thiddenKeys$1[METADATA] = true;\n\t});\n\n\tvar collection = function (CONSTRUCTOR_NAME, wrapper, common) {\n\t  var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;\n\t  var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;\n\t  var ADDER = IS_MAP ? 'set' : 'add';\n\t  var NativeConstructor = global_1[CONSTRUCTOR_NAME];\n\t  var NativePrototype = NativeConstructor && NativeConstructor.prototype;\n\t  var Constructor = NativeConstructor;\n\t  var exported = {};\n\n\t  var fixMethod = function (KEY) {\n\t    var uncurriedNativeMethod = functionUncurryThis(NativePrototype[KEY]);\n\t    redefine(NativePrototype, KEY,\n\t      KEY == 'add' ? function add(value) {\n\t        uncurriedNativeMethod(this, value === 0 ? 0 : value);\n\t        return this;\n\t      } : KEY == 'delete' ? function (key) {\n\t        return IS_WEAK && !isObject$1(key) ? false : uncurriedNativeMethod(this, key === 0 ? 0 : key);\n\t      } : KEY == 'get' ? function get(key) {\n\t        return IS_WEAK && !isObject$1(key) ? undefined : uncurriedNativeMethod(this, key === 0 ? 0 : key);\n\t      } : KEY == 'has' ? function has(key) {\n\t        return IS_WEAK && !isObject$1(key) ? false : uncurriedNativeMethod(this, key === 0 ? 0 : key);\n\t      } : function set(key, value) {\n\t        uncurriedNativeMethod(this, key === 0 ? 0 : key, value);\n\t        return this;\n\t      }\n\t    );\n\t  };\n\n\t  var REPLACE = isForced_1(\n\t    CONSTRUCTOR_NAME,\n\t    !isCallable(NativeConstructor) || !(IS_WEAK || NativePrototype.forEach && !fails(function () {\n\t      new NativeConstructor().entries().next();\n\t    }))\n\t  );\n\n\t  if (REPLACE) {\n\t    // create collection constructor\n\t    Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);\n\t    internalMetadata.enable();\n\t  } else if (isForced_1(CONSTRUCTOR_NAME, true)) {\n\t    var instance = new Constructor();\n\t    // early implementations not supports chaining\n\t    var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;\n\t    // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false\n\t    var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });\n\t    // most early implementations doesn't supports iterables, most modern - not close it correctly\n\t    // eslint-disable-next-line no-new -- required for testing\n\t    var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });\n\t    // for early implementations -0 and +0 not the same\n\t    var BUGGY_ZERO = !IS_WEAK && fails(function () {\n\t      // V8 ~ Chromium 42- fails only with 5+ elements\n\t      var $instance = new NativeConstructor();\n\t      var index = 5;\n\t      while (index--) $instance[ADDER](index, index);\n\t      return !$instance.has(-0);\n\t    });\n\n\t    if (!ACCEPT_ITERABLES) {\n\t      Constructor = wrapper(function (dummy, iterable) {\n\t        anInstance(dummy, NativePrototype);\n\t        var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);\n\t        if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });\n\t        return that;\n\t      });\n\t      Constructor.prototype = NativePrototype;\n\t      NativePrototype.constructor = Constructor;\n\t    }\n\n\t    if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {\n\t      fixMethod('delete');\n\t      fixMethod('has');\n\t      IS_MAP && fixMethod('get');\n\t    }\n\n\t    if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);\n\n\t    // weak collections should not contains .clear method\n\t    if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;\n\t  }\n\n\t  exported[CONSTRUCTOR_NAME] = Constructor;\n\t  _export({ global: true, forced: Constructor != NativeConstructor }, exported);\n\n\t  setToStringTag(Constructor, CONSTRUCTOR_NAME);\n\n\t  if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);\n\n\t  return Constructor;\n\t};\n\n\tvar defineProperty$1 = objectDefineProperty.f;\n\n\n\n\n\n\n\n\n\tvar fastKey = internalMetadata.fastKey;\n\n\n\tvar setInternalState = internalState.set;\n\tvar internalStateGetterFor = internalState.getterFor;\n\n\tvar collectionStrong = {\n\t  getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {\n\t    var Constructor = wrapper(function (that, iterable) {\n\t      anInstance(that, Prototype);\n\t      setInternalState(that, {\n\t        type: CONSTRUCTOR_NAME,\n\t        index: objectCreate(null),\n\t        first: undefined,\n\t        last: undefined,\n\t        size: 0\n\t      });\n\t      if (!descriptors) that.size = 0;\n\t      if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });\n\t    });\n\n\t    var Prototype = Constructor.prototype;\n\n\t    var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);\n\n\t    var define = function (that, key, value) {\n\t      var state = getInternalState(that);\n\t      var entry = getEntry(that, key);\n\t      var previous, index;\n\t      // change existing entry\n\t      if (entry) {\n\t        entry.value = value;\n\t      // create new entry\n\t      } else {\n\t        state.last = entry = {\n\t          index: index = fastKey(key, true),\n\t          key: key,\n\t          value: value,\n\t          previous: previous = state.last,\n\t          next: undefined,\n\t          removed: false\n\t        };\n\t        if (!state.first) state.first = entry;\n\t        if (previous) previous.next = entry;\n\t        if (descriptors) state.size++;\n\t        else that.size++;\n\t        // add to index\n\t        if (index !== 'F') state.index[index] = entry;\n\t      } return that;\n\t    };\n\n\t    var getEntry = function (that, key) {\n\t      var state = getInternalState(that);\n\t      // fast case\n\t      var index = fastKey(key);\n\t      var entry;\n\t      if (index !== 'F') return state.index[index];\n\t      // frozen object case\n\t      for (entry = state.first; entry; entry = entry.next) {\n\t        if (entry.key == key) return entry;\n\t      }\n\t    };\n\n\t    redefineAll(Prototype, {\n\t      // `{ Map, Set }.prototype.clear()` methods\n\t      // https://tc39.es/ecma262/#sec-map.prototype.clear\n\t      // https://tc39.es/ecma262/#sec-set.prototype.clear\n\t      clear: function clear() {\n\t        var that = this;\n\t        var state = getInternalState(that);\n\t        var data = state.index;\n\t        var entry = state.first;\n\t        while (entry) {\n\t          entry.removed = true;\n\t          if (entry.previous) entry.previous = entry.previous.next = undefined;\n\t          delete data[entry.index];\n\t          entry = entry.next;\n\t        }\n\t        state.first = state.last = undefined;\n\t        if (descriptors) state.size = 0;\n\t        else that.size = 0;\n\t      },\n\t      // `{ Map, Set }.prototype.delete(key)` methods\n\t      // https://tc39.es/ecma262/#sec-map.prototype.delete\n\t      // https://tc39.es/ecma262/#sec-set.prototype.delete\n\t      'delete': function (key) {\n\t        var that = this;\n\t        var state = getInternalState(that);\n\t        var entry = getEntry(that, key);\n\t        if (entry) {\n\t          var next = entry.next;\n\t          var prev = entry.previous;\n\t          delete state.index[entry.index];\n\t          entry.removed = true;\n\t          if (prev) prev.next = next;\n\t          if (next) next.previous = prev;\n\t          if (state.first == entry) state.first = next;\n\t          if (state.last == entry) state.last = prev;\n\t          if (descriptors) state.size--;\n\t          else that.size--;\n\t        } return !!entry;\n\t      },\n\t      // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods\n\t      // https://tc39.es/ecma262/#sec-map.prototype.foreach\n\t      // https://tc39.es/ecma262/#sec-set.prototype.foreach\n\t      forEach: function forEach(callbackfn /* , that = undefined */) {\n\t        var state = getInternalState(this);\n\t        var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined);\n\t        var entry;\n\t        while (entry = entry ? entry.next : state.first) {\n\t          boundFunction(entry.value, entry.key, this);\n\t          // revert to the last existing entry\n\t          while (entry && entry.removed) entry = entry.previous;\n\t        }\n\t      },\n\t      // `{ Map, Set}.prototype.has(key)` methods\n\t      // https://tc39.es/ecma262/#sec-map.prototype.has\n\t      // https://tc39.es/ecma262/#sec-set.prototype.has\n\t      has: function has(key) {\n\t        return !!getEntry(this, key);\n\t      }\n\t    });\n\n\t    redefineAll(Prototype, IS_MAP ? {\n\t      // `Map.prototype.get(key)` method\n\t      // https://tc39.es/ecma262/#sec-map.prototype.get\n\t      get: function get(key) {\n\t        var entry = getEntry(this, key);\n\t        return entry && entry.value;\n\t      },\n\t      // `Map.prototype.set(key, value)` method\n\t      // https://tc39.es/ecma262/#sec-map.prototype.set\n\t      set: function set(key, value) {\n\t        return define(this, key === 0 ? 0 : key, value);\n\t      }\n\t    } : {\n\t      // `Set.prototype.add(value)` method\n\t      // https://tc39.es/ecma262/#sec-set.prototype.add\n\t      add: function add(value) {\n\t        return define(this, value = value === 0 ? 0 : value, value);\n\t      }\n\t    });\n\t    if (descriptors) defineProperty$1(Prototype, 'size', {\n\t      get: function () {\n\t        return getInternalState(this).size;\n\t      }\n\t    });\n\t    return Constructor;\n\t  },\n\t  setStrong: function (Constructor, CONSTRUCTOR_NAME, IS_MAP) {\n\t    var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';\n\t    var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);\n\t    var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);\n\t    // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods\n\t    // https://tc39.es/ecma262/#sec-map.prototype.entries\n\t    // https://tc39.es/ecma262/#sec-map.prototype.keys\n\t    // https://tc39.es/ecma262/#sec-map.prototype.values\n\t    // https://tc39.es/ecma262/#sec-map.prototype-@@iterator\n\t    // https://tc39.es/ecma262/#sec-set.prototype.entries\n\t    // https://tc39.es/ecma262/#sec-set.prototype.keys\n\t    // https://tc39.es/ecma262/#sec-set.prototype.values\n\t    // https://tc39.es/ecma262/#sec-set.prototype-@@iterator\n\t    defineIterator(Constructor, CONSTRUCTOR_NAME, function (iterated, kind) {\n\t      setInternalState(this, {\n\t        type: ITERATOR_NAME,\n\t        target: iterated,\n\t        state: getInternalCollectionState(iterated),\n\t        kind: kind,\n\t        last: undefined\n\t      });\n\t    }, function () {\n\t      var state = getInternalIteratorState(this);\n\t      var kind = state.kind;\n\t      var entry = state.last;\n\t      // revert to the last existing entry\n\t      while (entry && entry.removed) entry = entry.previous;\n\t      // get next entry\n\t      if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {\n\t        // or finish the iteration\n\t        state.target = undefined;\n\t        return { value: undefined, done: true };\n\t      }\n\t      // return step by kind\n\t      if (kind == 'keys') return { value: entry.key, done: false };\n\t      if (kind == 'values') return { value: entry.value, done: false };\n\t      return { value: [entry.key, entry.value], done: false };\n\t    }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);\n\n\t    // `{ Map, Set }.prototype[@@species]` accessors\n\t    // https://tc39.es/ecma262/#sec-get-map-@@species\n\t    // https://tc39.es/ecma262/#sec-get-set-@@species\n\t    setSpecies(CONSTRUCTOR_NAME);\n\t  }\n\t};\n\n\t// `Set` constructor\n\t// https://tc39.es/ecma262/#sec-set-objects\n\tcollection('Set', function (init) {\n\t  return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };\n\t}, collectionStrong);\n\n\t// eslint-disable-next-line es/no-object-assign -- safe\n\tvar $assign = Object.assign;\n\t// eslint-disable-next-line es/no-object-defineproperty -- required for testing\n\tvar defineProperty = Object.defineProperty;\n\tvar concat = functionUncurryThis([].concat);\n\n\t// `Object.assign` method\n\t// https://tc39.es/ecma262/#sec-object.assign\n\tvar objectAssign = !$assign || fails(function () {\n\t  // should have correct order of operations (Edge bug)\n\t  if (descriptors && $assign({ b: 1 }, $assign(defineProperty({}, 'a', {\n\t    enumerable: true,\n\t    get: function () {\n\t      defineProperty(this, 'b', {\n\t        value: 3,\n\t        enumerable: false\n\t      });\n\t    }\n\t  }), { b: 2 })).b !== 1) return true;\n\t  // should work with symbols and should have deterministic property order (V8 bug)\n\t  var A = {};\n\t  var B = {};\n\t  // eslint-disable-next-line es/no-symbol -- safe\n\t  var symbol = Symbol();\n\t  var alphabet = 'abcdefghijklmnopqrst';\n\t  A[symbol] = 7;\n\t  alphabet.split('').forEach(function (chr) { B[chr] = chr; });\n\t  return $assign({}, A)[symbol] != 7 || objectKeys($assign({}, B)).join('') != alphabet;\n\t}) ? function assign(target, source) { // eslint-disable-line no-unused-vars -- required for `.length`\n\t  var T = toObject(target);\n\t  var argumentsLength = arguments.length;\n\t  var index = 1;\n\t  var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;\n\t  var propertyIsEnumerable = objectPropertyIsEnumerable.f;\n\t  while (argumentsLength > index) {\n\t    var S = indexedObject(arguments[index++]);\n\t    var keys = getOwnPropertySymbols ? concat(objectKeys(S), getOwnPropertySymbols(S)) : objectKeys(S);\n\t    var length = keys.length;\n\t    var j = 0;\n\t    var key;\n\t    while (length > j) {\n\t      key = keys[j++];\n\t      if (!descriptors || functionCall(propertyIsEnumerable, S, key)) T[key] = S[key];\n\t    }\n\t  } return T;\n\t} : $assign;\n\n\t// `Object.assign` method\n\t// https://tc39.es/ecma262/#sec-object.assign\n\t// eslint-disable-next-line es/no-object-assign -- required for testing\n\t_export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {\n\t  assign: objectAssign\n\t});\n\n\tvar onFreeze = internalMetadata.onFreeze;\n\n\t// eslint-disable-next-line es/no-object-freeze -- safe\n\tvar $freeze = Object.freeze;\n\tvar FAILS_ON_PRIMITIVES = fails(function () { $freeze(1); });\n\n\t// `Object.freeze` method\n\t// https://tc39.es/ecma262/#sec-object.freeze\n\t_export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES, sham: !freezing }, {\n\t  freeze: function freeze(it) {\n\t    return $freeze && isObject$1(it) ? $freeze(onFreeze(it)) : it;\n\t  }\n\t});\n\n\tvar browser$2 = true;\n\n\tvar urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';\n\n\tvar customAlphabet = function customAlphabet(alphabet) {\n\t  var defaultSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 21;\n\t  return function () {\n\t    var size = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultSize;\n\t    var id = '';\n\t    var i = size;\n\n\t    while (i--) {\n\t      id += alphabet[Math.random() * alphabet.length | 0];\n\t    }\n\n\t    return id;\n\t  };\n\t};\n\n\tvar nanoid = function nanoid() {\n\t  var size = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 21;\n\t  var id = '';\n\t  var i = size;\n\n\t  while (i--) {\n\t    id += urlAlphabet[Math.random() * 64 | 0];\n\t  }\n\n\t  return id;\n\t};\n\n\tvar nonSecure = /*#__PURE__*/Object.freeze({\n\t\t__proto__: null,\n\t\tnanoid: nanoid,\n\t\tcustomAlphabet: customAlphabet\n\t});\n\n\tvar he = createCommonjsModule(function (module, exports) {\n\n\t  (function (root) {\n\t    // Detect free variables `exports`.\n\t    var freeExports = exports; // Detect free variable `module`.\n\n\t    var freeModule = module && module.exports == freeExports && module; // Detect free variable `global`, from Node.js or Browserified code,\n\t    // and use it as `root`.\n\n\t    var freeGlobal = _typeof(commonjsGlobal) == 'object' && commonjsGlobal;\n\n\t    if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {\n\t      root = freeGlobal;\n\t    }\n\t    /*--------------------------------------------------------------------------*/\n\t    // All astral symbols.\n\n\n\t    var regexAstralSymbols = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g; // All ASCII symbols (not just printable ASCII) except those listed in the\n\t    // first column of the overrides table.\n\t    // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides\n\n\t    var regexAsciiWhitelist = /[\\x01-\\x7F]/g; // All BMP symbols that are not ASCII newlines, printable ASCII symbols, or\n\t    // code points listed in the first column of the overrides table on\n\t    // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides.\n\n\t    var regexBmpWhitelist = /[\\x01-\\t\\x0B\\f\\x0E-\\x1F\\x7F\\x81\\x8D\\x8F\\x90\\x9D\\xA0-\\uFFFF]/g;\n\t    var regexEncodeNonAscii = /<\\u20D2|=\\u20E5|>\\u20D2|\\u205F\\u200A|\\u219D\\u0338|\\u2202\\u0338|\\u2220\\u20D2|\\u2229\\uFE00|\\u222A\\uFE00|\\u223C\\u20D2|\\u223D\\u0331|\\u223E\\u0333|\\u2242\\u0338|\\u224B\\u0338|\\u224D\\u20D2|\\u224E\\u0338|\\u224F\\u0338|\\u2250\\u0338|\\u2261\\u20E5|\\u2264\\u20D2|\\u2265\\u20D2|\\u2266\\u0338|\\u2267\\u0338|\\u2268\\uFE00|\\u2269\\uFE00|\\u226A\\u0338|\\u226A\\u20D2|\\u226B\\u0338|\\u226B\\u20D2|\\u227F\\u0338|\\u2282\\u20D2|\\u2283\\u20D2|\\u228A\\uFE00|\\u228B\\uFE00|\\u228F\\u0338|\\u2290\\u0338|\\u2293\\uFE00|\\u2294\\uFE00|\\u22B4\\u20D2|\\u22B5\\u20D2|\\u22D8\\u0338|\\u22D9\\u0338|\\u22DA\\uFE00|\\u22DB\\uFE00|\\u22F5\\u0338|\\u22F9\\u0338|\\u2933\\u0338|\\u29CF\\u0338|\\u29D0\\u0338|\\u2A6D\\u0338|\\u2A70\\u0338|\\u2A7D\\u0338|\\u2A7E\\u0338|\\u2AA1\\u0338|\\u2AA2\\u0338|\\u2AAC\\uFE00|\\u2AAD\\uFE00|\\u2AAF\\u0338|\\u2AB0\\u0338|\\u2AC5\\u0338|\\u2AC6\\u0338|\\u2ACB\\uFE00|\\u2ACC\\uFE00|\\u2AFD\\u20E5|[\\xA0-\\u0113\\u0116-\\u0122\\u0124-\\u012B\\u012E-\\u014D\\u0150-\\u017E\\u0192\\u01B5\\u01F5\\u0237\\u02C6\\u02C7\\u02D8-\\u02DD\\u0311\\u0391-\\u03A1\\u03A3-\\u03A9\\u03B1-\\u03C9\\u03D1\\u03D2\\u03D5\\u03D6\\u03DC\\u03DD\\u03F0\\u03F1\\u03F5\\u03F6\\u0401-\\u040C\\u040E-\\u044F\\u0451-\\u045C\\u045E\\u045F\\u2002-\\u2005\\u2007-\\u2010\\u2013-\\u2016\\u2018-\\u201A\\u201C-\\u201E\\u2020-\\u2022\\u2025\\u2026\\u2030-\\u2035\\u2039\\u203A\\u203E\\u2041\\u2043\\u2044\\u204F\\u2057\\u205F-\\u2063\\u20AC\\u20DB\\u20DC\\u2102\\u2105\\u210A-\\u2113\\u2115-\\u211E\\u2122\\u2124\\u2127-\\u2129\\u212C\\u212D\\u212F-\\u2131\\u2133-\\u2138\\u2145-\\u2148\\u2153-\\u215E\\u2190-\\u219B\\u219D-\\u21A7\\u21A9-\\u21AE\\u21B0-\\u21B3\\u21B5-\\u21B7\\u21BA-\\u21DB\\u21DD\\u21E4\\u21E5\\u21F5\\u21FD-\\u2205\\u2207-\\u2209\\u220B\\u220C\\u220F-\\u2214\\u2216-\\u2218\\u221A\\u221D-\\u2238\\u223A-\\u2257\\u2259\\u225A\\u225C\\u225F-\\u2262\\u2264-\\u228B\\u228D-\\u229B\\u229D-\\u22A5\\u22A7-\\u22B0\\u22B2-\\u22BB\\u22BD-\\u22DB\\u22DE-\\u22E3\\u22E6-\\u22F7\\u22F9-\\u22FE\\u2305\\u2306\\u2308-\\u2310\\u2312\\u2313\\u2315\\u2316\\u231C-\\u231F\\u2322\\u2323\\u232D\\u232E\\u2336\\u233D\\u233F\\u237C\\u23B0\\u23B1\\u23B4-\\u23B6\\u23DC-\\u23DF\\u23E2\\u23E7\\u2423\\u24C8\\u2500\\u2502\\u250C\\u2510\\u2514\\u2518\\u251C\\u2524\\u252C\\u2534\\u253C\\u2550-\\u256C\\u2580\\u2584\\u2588\\u2591-\\u2593\\u25A1\\u25AA\\u25AB\\u25AD\\u25AE\\u25B1\\u25B3-\\u25B5\\u25B8\\u25B9\\u25BD-\\u25BF\\u25C2\\u25C3\\u25CA\\u25CB\\u25EC\\u25EF\\u25F8-\\u25FC\\u2605\\u2606\\u260E\\u2640\\u2642\\u2660\\u2663\\u2665\\u2666\\u266A\\u266D-\\u266F\\u2713\\u2717\\u2720\\u2736\\u2758\\u2772\\u2773\\u27C8\\u27C9\\u27E6-\\u27ED\\u27F5-\\u27FA\\u27FC\\u27FF\\u2902-\\u2905\\u290C-\\u2913\\u2916\\u2919-\\u2920\\u2923-\\u292A\\u2933\\u2935-\\u2939\\u293C\\u293D\\u2945\\u2948-\\u294B\\u294E-\\u2976\\u2978\\u2979\\u297B-\\u297F\\u2985\\u2986\\u298B-\\u2996\\u299A\\u299C\\u299D\\u29A4-\\u29B7\\u29B9\\u29BB\\u29BC\\u29BE-\\u29C5\\u29C9\\u29CD-\\u29D0\\u29DC-\\u29DE\\u29E3-\\u29E5\\u29EB\\u29F4\\u29F6\\u2A00-\\u2A02\\u2A04\\u2A06\\u2A0C\\u2A0D\\u2A10-\\u2A17\\u2A22-\\u2A27\\u2A29\\u2A2A\\u2A2D-\\u2A31\\u2A33-\\u2A3C\\u2A3F\\u2A40\\u2A42-\\u2A4D\\u2A50\\u2A53-\\u2A58\\u2A5A-\\u2A5D\\u2A5F\\u2A66\\u2A6A\\u2A6D-\\u2A75\\u2A77-\\u2A9A\\u2A9D-\\u2AA2\\u2AA4-\\u2AB0\\u2AB3-\\u2AC8\\u2ACB\\u2ACC\\u2ACF-\\u2ADB\\u2AE4\\u2AE6-\\u2AE9\\u2AEB-\\u2AF3\\u2AFD\\uFB00-\\uFB04]|\\uD835[\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDCCF\\uDD04\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDD6B]/g;\n\t    var encodeMap = {\n\t      '\\xAD': 'shy',\n\t      \"\\u200C\": 'zwnj',\n\t      \"\\u200D\": 'zwj',\n\t      \"\\u200E\": 'lrm',\n\t      \"\\u2063\": 'ic',\n\t      \"\\u2062\": 'it',\n\t      \"\\u2061\": 'af',\n\t      \"\\u200F\": 'rlm',\n\t      \"\\u200B\": 'ZeroWidthSpace',\n\t      \"\\u2060\": 'NoBreak',\n\t      \"\\u0311\": 'DownBreve',\n\t      \"\\u20DB\": 'tdot',\n\t      \"\\u20DC\": 'DotDot',\n\t      '\\t': 'Tab',\n\t      '\\n': 'NewLine',\n\t      \"\\u2008\": 'puncsp',\n\t      \"\\u205F\": 'MediumSpace',\n\t      \"\\u2009\": 'thinsp',\n\t      \"\\u200A\": 'hairsp',\n\t      \"\\u2004\": 'emsp13',\n\t      \"\\u2002\": 'ensp',\n\t      \"\\u2005\": 'emsp14',\n\t      \"\\u2003\": 'emsp',\n\t      \"\\u2007\": 'numsp',\n\t      '\\xA0': 'nbsp',\n\t      \"\\u205F\\u200A\": 'ThickSpace',\n\t      \"\\u203E\": 'oline',\n\t      '_': 'lowbar',\n\t      \"\\u2010\": 'dash',\n\t      \"\\u2013\": 'ndash',\n\t      \"\\u2014\": 'mdash',\n\t      \"\\u2015\": 'horbar',\n\t      ',': 'comma',\n\t      ';': 'semi',\n\t      \"\\u204F\": 'bsemi',\n\t      ':': 'colon',\n\t      \"\\u2A74\": 'Colone',\n\t      '!': 'excl',\n\t      '\\xA1': 'iexcl',\n\t      '?': 'quest',\n\t      '\\xBF': 'iquest',\n\t      '.': 'period',\n\t      \"\\u2025\": 'nldr',\n\t      \"\\u2026\": 'mldr',\n\t      '\\xB7': 'middot',\n\t      '\\'': 'apos',\n\t      \"\\u2018\": 'lsquo',\n\t      \"\\u2019\": 'rsquo',\n\t      \"\\u201A\": 'sbquo',\n\t      \"\\u2039\": 'lsaquo',\n\t      \"\\u203A\": 'rsaquo',\n\t      '\"': 'quot',\n\t      \"\\u201C\": 'ldquo',\n\t      \"\\u201D\": 'rdquo',\n\t      \"\\u201E\": 'bdquo',\n\t      '\\xAB': 'laquo',\n\t      '\\xBB': 'raquo',\n\t      '(': 'lpar',\n\t      ')': 'rpar',\n\t      '[': 'lsqb',\n\t      ']': 'rsqb',\n\t      '{': 'lcub',\n\t      '}': 'rcub',\n\t      \"\\u2308\": 'lceil',\n\t      \"\\u2309\": 'rceil',\n\t      \"\\u230A\": 'lfloor',\n\t      \"\\u230B\": 'rfloor',\n\t      \"\\u2985\": 'lopar',\n\t      \"\\u2986\": 'ropar',\n\t      \"\\u298B\": 'lbrke',\n\t      \"\\u298C\": 'rbrke',\n\t      \"\\u298D\": 'lbrkslu',\n\t      \"\\u298E\": 'rbrksld',\n\t      \"\\u298F\": 'lbrksld',\n\t      \"\\u2990\": 'rbrkslu',\n\t      \"\\u2991\": 'langd',\n\t      \"\\u2992\": 'rangd',\n\t      \"\\u2993\": 'lparlt',\n\t      \"\\u2994\": 'rpargt',\n\t      \"\\u2995\": 'gtlPar',\n\t      \"\\u2996\": 'ltrPar',\n\t      \"\\u27E6\": 'lobrk',\n\t      \"\\u27E7\": 'robrk',\n\t      \"\\u27E8\": 'lang',\n\t      \"\\u27E9\": 'rang',\n\t      \"\\u27EA\": 'Lang',\n\t      \"\\u27EB\": 'Rang',\n\t      \"\\u27EC\": 'loang',\n\t      \"\\u27ED\": 'roang',\n\t      \"\\u2772\": 'lbbrk',\n\t      \"\\u2773\": 'rbbrk',\n\t      \"\\u2016\": 'Vert',\n\t      '\\xA7': 'sect',\n\t      '\\xB6': 'para',\n\t      '@': 'commat',\n\t      '*': 'ast',\n\t      '/': 'sol',\n\t      'undefined': null,\n\t      '&': 'amp',\n\t      '#': 'num',\n\t      '%': 'percnt',\n\t      \"\\u2030\": 'permil',\n\t      \"\\u2031\": 'pertenk',\n\t      \"\\u2020\": 'dagger',\n\t      \"\\u2021\": 'Dagger',\n\t      \"\\u2022\": 'bull',\n\t      \"\\u2043\": 'hybull',\n\t      \"\\u2032\": 'prime',\n\t      \"\\u2033\": 'Prime',\n\t      \"\\u2034\": 'tprime',\n\t      \"\\u2057\": 'qprime',\n\t      \"\\u2035\": 'bprime',\n\t      \"\\u2041\": 'caret',\n\t      '`': 'grave',\n\t      '\\xB4': 'acute',\n\t      \"\\u02DC\": 'tilde',\n\t      '^': 'Hat',\n\t      '\\xAF': 'macr',\n\t      \"\\u02D8\": 'breve',\n\t      \"\\u02D9\": 'dot',\n\t      '\\xA8': 'die',\n\t      \"\\u02DA\": 'ring',\n\t      \"\\u02DD\": 'dblac',\n\t      '\\xB8': 'cedil',\n\t      \"\\u02DB\": 'ogon',\n\t      \"\\u02C6\": 'circ',\n\t      \"\\u02C7\": 'caron',\n\t      '\\xB0': 'deg',\n\t      '\\xA9': 'copy',\n\t      '\\xAE': 'reg',\n\t      \"\\u2117\": 'copysr',\n\t      \"\\u2118\": 'wp',\n\t      \"\\u211E\": 'rx',\n\t      \"\\u2127\": 'mho',\n\t      \"\\u2129\": 'iiota',\n\t      \"\\u2190\": 'larr',\n\t      \"\\u219A\": 'nlarr',\n\t      \"\\u2192\": 'rarr',\n\t      \"\\u219B\": 'nrarr',\n\t      \"\\u2191\": 'uarr',\n\t      \"\\u2193\": 'darr',\n\t      \"\\u2194\": 'harr',\n\t      \"\\u21AE\": 'nharr',\n\t      \"\\u2195\": 'varr',\n\t      \"\\u2196\": 'nwarr',\n\t      \"\\u2197\": 'nearr',\n\t      \"\\u2198\": 'searr',\n\t      \"\\u2199\": 'swarr',\n\t      \"\\u219D\": 'rarrw',\n\t      \"\\u219D\\u0338\": 'nrarrw',\n\t      \"\\u219E\": 'Larr',\n\t      \"\\u219F\": 'Uarr',\n\t      \"\\u21A0\": 'Rarr',\n\t      \"\\u21A1\": 'Darr',\n\t      \"\\u21A2\": 'larrtl',\n\t      \"\\u21A3\": 'rarrtl',\n\t      \"\\u21A4\": 'mapstoleft',\n\t      \"\\u21A5\": 'mapstoup',\n\t      \"\\u21A6\": 'map',\n\t      \"\\u21A7\": 'mapstodown',\n\t      \"\\u21A9\": 'larrhk',\n\t      \"\\u21AA\": 'rarrhk',\n\t      \"\\u21AB\": 'larrlp',\n\t      \"\\u21AC\": 'rarrlp',\n\t      \"\\u21AD\": 'harrw',\n\t      \"\\u21B0\": 'lsh',\n\t      \"\\u21B1\": 'rsh',\n\t      \"\\u21B2\": 'ldsh',\n\t      \"\\u21B3\": 'rdsh',\n\t      \"\\u21B5\": 'crarr',\n\t      \"\\u21B6\": 'cularr',\n\t      \"\\u21B7\": 'curarr',\n\t      \"\\u21BA\": 'olarr',\n\t      \"\\u21BB\": 'orarr',\n\t      \"\\u21BC\": 'lharu',\n\t      \"\\u21BD\": 'lhard',\n\t      \"\\u21BE\": 'uharr',\n\t      \"\\u21BF\": 'uharl',\n\t      \"\\u21C0\": 'rharu',\n\t      \"\\u21C1\": 'rhard',\n\t      \"\\u21C2\": 'dharr',\n\t      \"\\u21C3\": 'dharl',\n\t      \"\\u21C4\": 'rlarr',\n\t      \"\\u21C5\": 'udarr',\n\t      \"\\u21C6\": 'lrarr',\n\t      \"\\u21C7\": 'llarr',\n\t      \"\\u21C8\": 'uuarr',\n\t      \"\\u21C9\": 'rrarr',\n\t      \"\\u21CA\": 'ddarr',\n\t      \"\\u21CB\": 'lrhar',\n\t      \"\\u21CC\": 'rlhar',\n\t      \"\\u21D0\": 'lArr',\n\t      \"\\u21CD\": 'nlArr',\n\t      \"\\u21D1\": 'uArr',\n\t      \"\\u21D2\": 'rArr',\n\t      \"\\u21CF\": 'nrArr',\n\t      \"\\u21D3\": 'dArr',\n\t      \"\\u21D4\": 'iff',\n\t      \"\\u21CE\": 'nhArr',\n\t      \"\\u21D5\": 'vArr',\n\t      \"\\u21D6\": 'nwArr',\n\t      \"\\u21D7\": 'neArr',\n\t      \"\\u21D8\": 'seArr',\n\t      \"\\u21D9\": 'swArr',\n\t      \"\\u21DA\": 'lAarr',\n\t      \"\\u21DB\": 'rAarr',\n\t      \"\\u21DD\": 'zigrarr',\n\t      \"\\u21E4\": 'larrb',\n\t      \"\\u21E5\": 'rarrb',\n\t      \"\\u21F5\": 'duarr',\n\t      \"\\u21FD\": 'loarr',\n\t      \"\\u21FE\": 'roarr',\n\t      \"\\u21FF\": 'hoarr',\n\t      \"\\u2200\": 'forall',\n\t      \"\\u2201\": 'comp',\n\t      \"\\u2202\": 'part',\n\t      \"\\u2202\\u0338\": 'npart',\n\t      \"\\u2203\": 'exist',\n\t      \"\\u2204\": 'nexist',\n\t      \"\\u2205\": 'empty',\n\t      \"\\u2207\": 'Del',\n\t      \"\\u2208\": 'in',\n\t      \"\\u2209\": 'notin',\n\t      \"\\u220B\": 'ni',\n\t      \"\\u220C\": 'notni',\n\t      \"\\u03F6\": 'bepsi',\n\t      \"\\u220F\": 'prod',\n\t      \"\\u2210\": 'coprod',\n\t      \"\\u2211\": 'sum',\n\t      '+': 'plus',\n\t      '\\xB1': 'pm',\n\t      '\\xF7': 'div',\n\t      '\\xD7': 'times',\n\t      '<': 'lt',\n\t      \"\\u226E\": 'nlt',\n\t      \"<\\u20D2\": 'nvlt',\n\t      '=': 'equals',\n\t      \"\\u2260\": 'ne',\n\t      \"=\\u20E5\": 'bne',\n\t      \"\\u2A75\": 'Equal',\n\t      '>': 'gt',\n\t      \"\\u226F\": 'ngt',\n\t      \">\\u20D2\": 'nvgt',\n\t      '\\xAC': 'not',\n\t      '|': 'vert',\n\t      '\\xA6': 'brvbar',\n\t      \"\\u2212\": 'minus',\n\t      \"\\u2213\": 'mp',\n\t      \"\\u2214\": 'plusdo',\n\t      \"\\u2044\": 'frasl',\n\t      \"\\u2216\": 'setmn',\n\t      \"\\u2217\": 'lowast',\n\t      \"\\u2218\": 'compfn',\n\t      \"\\u221A\": 'Sqrt',\n\t      \"\\u221D\": 'prop',\n\t      \"\\u221E\": 'infin',\n\t      \"\\u221F\": 'angrt',\n\t      \"\\u2220\": 'ang',\n\t      \"\\u2220\\u20D2\": 'nang',\n\t      \"\\u2221\": 'angmsd',\n\t      \"\\u2222\": 'angsph',\n\t      \"\\u2223\": 'mid',\n\t      \"\\u2224\": 'nmid',\n\t      \"\\u2225\": 'par',\n\t      \"\\u2226\": 'npar',\n\t      \"\\u2227\": 'and',\n\t      \"\\u2228\": 'or',\n\t      \"\\u2229\": 'cap',\n\t      \"\\u2229\\uFE00\": 'caps',\n\t      \"\\u222A\": 'cup',\n\t      \"\\u222A\\uFE00\": 'cups',\n\t      \"\\u222B\": 'int',\n\t      \"\\u222C\": 'Int',\n\t      \"\\u222D\": 'tint',\n\t      \"\\u2A0C\": 'qint',\n\t      \"\\u222E\": 'oint',\n\t      \"\\u222F\": 'Conint',\n\t      \"\\u2230\": 'Cconint',\n\t      \"\\u2231\": 'cwint',\n\t      \"\\u2232\": 'cwconint',\n\t      \"\\u2233\": 'awconint',\n\t      \"\\u2234\": 'there4',\n\t      \"\\u2235\": 'becaus',\n\t      \"\\u2236\": 'ratio',\n\t      \"\\u2237\": 'Colon',\n\t      \"\\u2238\": 'minusd',\n\t      \"\\u223A\": 'mDDot',\n\t      \"\\u223B\": 'homtht',\n\t      \"\\u223C\": 'sim',\n\t      \"\\u2241\": 'nsim',\n\t      \"\\u223C\\u20D2\": 'nvsim',\n\t      \"\\u223D\": 'bsim',\n\t      \"\\u223D\\u0331\": 'race',\n\t      \"\\u223E\": 'ac',\n\t      \"\\u223E\\u0333\": 'acE',\n\t      \"\\u223F\": 'acd',\n\t      \"\\u2240\": 'wr',\n\t      \"\\u2242\": 'esim',\n\t      \"\\u2242\\u0338\": 'nesim',\n\t      \"\\u2243\": 'sime',\n\t      \"\\u2244\": 'nsime',\n\t      \"\\u2245\": 'cong',\n\t      \"\\u2247\": 'ncong',\n\t      \"\\u2246\": 'simne',\n\t      \"\\u2248\": 'ap',\n\t      \"\\u2249\": 'nap',\n\t      \"\\u224A\": 'ape',\n\t      \"\\u224B\": 'apid',\n\t      \"\\u224B\\u0338\": 'napid',\n\t      \"\\u224C\": 'bcong',\n\t      \"\\u224D\": 'CupCap',\n\t      \"\\u226D\": 'NotCupCap',\n\t      \"\\u224D\\u20D2\": 'nvap',\n\t      \"\\u224E\": 'bump',\n\t      \"\\u224E\\u0338\": 'nbump',\n\t      \"\\u224F\": 'bumpe',\n\t      \"\\u224F\\u0338\": 'nbumpe',\n\t      \"\\u2250\": 'doteq',\n\t      \"\\u2250\\u0338\": 'nedot',\n\t      \"\\u2251\": 'eDot',\n\t      \"\\u2252\": 'efDot',\n\t      \"\\u2253\": 'erDot',\n\t      \"\\u2254\": 'colone',\n\t      \"\\u2255\": 'ecolon',\n\t      \"\\u2256\": 'ecir',\n\t      \"\\u2257\": 'cire',\n\t      \"\\u2259\": 'wedgeq',\n\t      \"\\u225A\": 'veeeq',\n\t      \"\\u225C\": 'trie',\n\t      \"\\u225F\": 'equest',\n\t      \"\\u2261\": 'equiv',\n\t      \"\\u2262\": 'nequiv',\n\t      \"\\u2261\\u20E5\": 'bnequiv',\n\t      \"\\u2264\": 'le',\n\t      \"\\u2270\": 'nle',\n\t      \"\\u2264\\u20D2\": 'nvle',\n\t      \"\\u2265\": 'ge',\n\t      \"\\u2271\": 'nge',\n\t      \"\\u2265\\u20D2\": 'nvge',\n\t      \"\\u2266\": 'lE',\n\t      \"\\u2266\\u0338\": 'nlE',\n\t      \"\\u2267\": 'gE',\n\t      \"\\u2267\\u0338\": 'ngE',\n\t      \"\\u2268\\uFE00\": 'lvnE',\n\t      \"\\u2268\": 'lnE',\n\t      \"\\u2269\": 'gnE',\n\t      \"\\u2269\\uFE00\": 'gvnE',\n\t      \"\\u226A\": 'll',\n\t      \"\\u226A\\u0338\": 'nLtv',\n\t      \"\\u226A\\u20D2\": 'nLt',\n\t      \"\\u226B\": 'gg',\n\t      \"\\u226B\\u0338\": 'nGtv',\n\t      \"\\u226B\\u20D2\": 'nGt',\n\t      \"\\u226C\": 'twixt',\n\t      \"\\u2272\": 'lsim',\n\t      \"\\u2274\": 'nlsim',\n\t      \"\\u2273\": 'gsim',\n\t      \"\\u2275\": 'ngsim',\n\t      \"\\u2276\": 'lg',\n\t      \"\\u2278\": 'ntlg',\n\t      \"\\u2277\": 'gl',\n\t      \"\\u2279\": 'ntgl',\n\t      \"\\u227A\": 'pr',\n\t      \"\\u2280\": 'npr',\n\t      \"\\u227B\": 'sc',\n\t      \"\\u2281\": 'nsc',\n\t      \"\\u227C\": 'prcue',\n\t      \"\\u22E0\": 'nprcue',\n\t      \"\\u227D\": 'sccue',\n\t      \"\\u22E1\": 'nsccue',\n\t      \"\\u227E\": 'prsim',\n\t      \"\\u227F\": 'scsim',\n\t      \"\\u227F\\u0338\": 'NotSucceedsTilde',\n\t      \"\\u2282\": 'sub',\n\t      \"\\u2284\": 'nsub',\n\t      \"\\u2282\\u20D2\": 'vnsub',\n\t      \"\\u2283\": 'sup',\n\t      \"\\u2285\": 'nsup',\n\t      \"\\u2283\\u20D2\": 'vnsup',\n\t      \"\\u2286\": 'sube',\n\t      \"\\u2288\": 'nsube',\n\t      \"\\u2287\": 'supe',\n\t      \"\\u2289\": 'nsupe',\n\t      \"\\u228A\\uFE00\": 'vsubne',\n\t      \"\\u228A\": 'subne',\n\t      \"\\u228B\\uFE00\": 'vsupne',\n\t      \"\\u228B\": 'supne',\n\t      \"\\u228D\": 'cupdot',\n\t      \"\\u228E\": 'uplus',\n\t      \"\\u228F\": 'sqsub',\n\t      \"\\u228F\\u0338\": 'NotSquareSubset',\n\t      \"\\u2290\": 'sqsup',\n\t      \"\\u2290\\u0338\": 'NotSquareSuperset',\n\t      \"\\u2291\": 'sqsube',\n\t      \"\\u22E2\": 'nsqsube',\n\t      \"\\u2292\": 'sqsupe',\n\t      \"\\u22E3\": 'nsqsupe',\n\t      \"\\u2293\": 'sqcap',\n\t      \"\\u2293\\uFE00\": 'sqcaps',\n\t      \"\\u2294\": 'sqcup',\n\t      \"\\u2294\\uFE00\": 'sqcups',\n\t      \"\\u2295\": 'oplus',\n\t      \"\\u2296\": 'ominus',\n\t      \"\\u2297\": 'otimes',\n\t      \"\\u2298\": 'osol',\n\t      \"\\u2299\": 'odot',\n\t      \"\\u229A\": 'ocir',\n\t      \"\\u229B\": 'oast',\n\t      \"\\u229D\": 'odash',\n\t      \"\\u229E\": 'plusb',\n\t      \"\\u229F\": 'minusb',\n\t      \"\\u22A0\": 'timesb',\n\t      \"\\u22A1\": 'sdotb',\n\t      \"\\u22A2\": 'vdash',\n\t      \"\\u22AC\": 'nvdash',\n\t      \"\\u22A3\": 'dashv',\n\t      \"\\u22A4\": 'top',\n\t      \"\\u22A5\": 'bot',\n\t      \"\\u22A7\": 'models',\n\t      \"\\u22A8\": 'vDash',\n\t      \"\\u22AD\": 'nvDash',\n\t      \"\\u22A9\": 'Vdash',\n\t      \"\\u22AE\": 'nVdash',\n\t      \"\\u22AA\": 'Vvdash',\n\t      \"\\u22AB\": 'VDash',\n\t      \"\\u22AF\": 'nVDash',\n\t      \"\\u22B0\": 'prurel',\n\t      \"\\u22B2\": 'vltri',\n\t      \"\\u22EA\": 'nltri',\n\t      \"\\u22B3\": 'vrtri',\n\t      \"\\u22EB\": 'nrtri',\n\t      \"\\u22B4\": 'ltrie',\n\t      \"\\u22EC\": 'nltrie',\n\t      \"\\u22B4\\u20D2\": 'nvltrie',\n\t      \"\\u22B5\": 'rtrie',\n\t      \"\\u22ED\": 'nrtrie',\n\t      \"\\u22B5\\u20D2\": 'nvrtrie',\n\t      \"\\u22B6\": 'origof',\n\t      \"\\u22B7\": 'imof',\n\t      \"\\u22B8\": 'mumap',\n\t      \"\\u22B9\": 'hercon',\n\t      \"\\u22BA\": 'intcal',\n\t      \"\\u22BB\": 'veebar',\n\t      \"\\u22BD\": 'barvee',\n\t      \"\\u22BE\": 'angrtvb',\n\t      \"\\u22BF\": 'lrtri',\n\t      \"\\u22C0\": 'Wedge',\n\t      \"\\u22C1\": 'Vee',\n\t      \"\\u22C2\": 'xcap',\n\t      \"\\u22C3\": 'xcup',\n\t      \"\\u22C4\": 'diam',\n\t      \"\\u22C5\": 'sdot',\n\t      \"\\u22C6\": 'Star',\n\t      \"\\u22C7\": 'divonx',\n\t      \"\\u22C8\": 'bowtie',\n\t      \"\\u22C9\": 'ltimes',\n\t      \"\\u22CA\": 'rtimes',\n\t      \"\\u22CB\": 'lthree',\n\t      \"\\u22CC\": 'rthree',\n\t      \"\\u22CD\": 'bsime',\n\t      \"\\u22CE\": 'cuvee',\n\t      \"\\u22CF\": 'cuwed',\n\t      \"\\u22D0\": 'Sub',\n\t      \"\\u22D1\": 'Sup',\n\t      \"\\u22D2\": 'Cap',\n\t      \"\\u22D3\": 'Cup',\n\t      \"\\u22D4\": 'fork',\n\t      \"\\u22D5\": 'epar',\n\t      \"\\u22D6\": 'ltdot',\n\t      \"\\u22D7\": 'gtdot',\n\t      \"\\u22D8\": 'Ll',\n\t      \"\\u22D8\\u0338\": 'nLl',\n\t      \"\\u22D9\": 'Gg',\n\t      \"\\u22D9\\u0338\": 'nGg',\n\t      \"\\u22DA\\uFE00\": 'lesg',\n\t      \"\\u22DA\": 'leg',\n\t      \"\\u22DB\": 'gel',\n\t      \"\\u22DB\\uFE00\": 'gesl',\n\t      \"\\u22DE\": 'cuepr',\n\t      \"\\u22DF\": 'cuesc',\n\t      \"\\u22E6\": 'lnsim',\n\t      \"\\u22E7\": 'gnsim',\n\t      \"\\u22E8\": 'prnsim',\n\t      \"\\u22E9\": 'scnsim',\n\t      \"\\u22EE\": 'vellip',\n\t      \"\\u22EF\": 'ctdot',\n\t      \"\\u22F0\": 'utdot',\n\t      \"\\u22F1\": 'dtdot',\n\t      \"\\u22F2\": 'disin',\n\t      \"\\u22F3\": 'isinsv',\n\t      \"\\u22F4\": 'isins',\n\t      \"\\u22F5\": 'isindot',\n\t      \"\\u22F5\\u0338\": 'notindot',\n\t      \"\\u22F6\": 'notinvc',\n\t      \"\\u22F7\": 'notinvb',\n\t      \"\\u22F9\": 'isinE',\n\t      \"\\u22F9\\u0338\": 'notinE',\n\t      \"\\u22FA\": 'nisd',\n\t      \"\\u22FB\": 'xnis',\n\t      \"\\u22FC\": 'nis',\n\t      \"\\u22FD\": 'notnivc',\n\t      \"\\u22FE\": 'notnivb',\n\t      \"\\u2305\": 'barwed',\n\t      \"\\u2306\": 'Barwed',\n\t      \"\\u230C\": 'drcrop',\n\t      \"\\u230D\": 'dlcrop',\n\t      \"\\u230E\": 'urcrop',\n\t      \"\\u230F\": 'ulcrop',\n\t      \"\\u2310\": 'bnot',\n\t      \"\\u2312\": 'profline',\n\t      \"\\u2313\": 'profsurf',\n\t      \"\\u2315\": 'telrec',\n\t      \"\\u2316\": 'target',\n\t      \"\\u231C\": 'ulcorn',\n\t      \"\\u231D\": 'urcorn',\n\t      \"\\u231E\": 'dlcorn',\n\t      \"\\u231F\": 'drcorn',\n\t      \"\\u2322\": 'frown',\n\t      \"\\u2323\": 'smile',\n\t      \"\\u232D\": 'cylcty',\n\t      \"\\u232E\": 'profalar',\n\t      \"\\u2336\": 'topbot',\n\t      \"\\u233D\": 'ovbar',\n\t      \"\\u233F\": 'solbar',\n\t      \"\\u237C\": 'angzarr',\n\t      \"\\u23B0\": 'lmoust',\n\t      \"\\u23B1\": 'rmoust',\n\t      \"\\u23B4\": 'tbrk',\n\t      \"\\u23B5\": 'bbrk',\n\t      \"\\u23B6\": 'bbrktbrk',\n\t      \"\\u23DC\": 'OverParenthesis',\n\t      \"\\u23DD\": 'UnderParenthesis',\n\t      \"\\u23DE\": 'OverBrace',\n\t      \"\\u23DF\": 'UnderBrace',\n\t      \"\\u23E2\": 'trpezium',\n\t      \"\\u23E7\": 'elinters',\n\t      \"\\u2423\": 'blank',\n\t      \"\\u2500\": 'boxh',\n\t      \"\\u2502\": 'boxv',\n\t      \"\\u250C\": 'boxdr',\n\t      \"\\u2510\": 'boxdl',\n\t      \"\\u2514\": 'boxur',\n\t      \"\\u2518\": 'boxul',\n\t      \"\\u251C\": 'boxvr',\n\t      \"\\u2524\": 'boxvl',\n\t      \"\\u252C\": 'boxhd',\n\t      \"\\u2534\": 'boxhu',\n\t      \"\\u253C\": 'boxvh',\n\t      \"\\u2550\": 'boxH',\n\t      \"\\u2551\": 'boxV',\n\t      \"\\u2552\": 'boxdR',\n\t      \"\\u2553\": 'boxDr',\n\t      \"\\u2554\": 'boxDR',\n\t      \"\\u2555\": 'boxdL',\n\t      \"\\u2556\": 'boxDl',\n\t      \"\\u2557\": 'boxDL',\n\t      \"\\u2558\": 'boxuR',\n\t      \"\\u2559\": 'boxUr',\n\t      \"\\u255A\": 'boxUR',\n\t      \"\\u255B\": 'boxuL',\n\t      \"\\u255C\": 'boxUl',\n\t      \"\\u255D\": 'boxUL',\n\t      \"\\u255E\": 'boxvR',\n\t      \"\\u255F\": 'boxVr',\n\t      \"\\u2560\": 'boxVR',\n\t      \"\\u2561\": 'boxvL',\n\t      \"\\u2562\": 'boxVl',\n\t      \"\\u2563\": 'boxVL',\n\t      \"\\u2564\": 'boxHd',\n\t      \"\\u2565\": 'boxhD',\n\t      \"\\u2566\": 'boxHD',\n\t      \"\\u2567\": 'boxHu',\n\t      \"\\u2568\": 'boxhU',\n\t      \"\\u2569\": 'boxHU',\n\t      \"\\u256A\": 'boxvH',\n\t      \"\\u256B\": 'boxVh',\n\t      \"\\u256C\": 'boxVH',\n\t      \"\\u2580\": 'uhblk',\n\t      \"\\u2584\": 'lhblk',\n\t      \"\\u2588\": 'block',\n\t      \"\\u2591\": 'blk14',\n\t      \"\\u2592\": 'blk12',\n\t      \"\\u2593\": 'blk34',\n\t      \"\\u25A1\": 'squ',\n\t      \"\\u25AA\": 'squf',\n\t      \"\\u25AB\": 'EmptyVerySmallSquare',\n\t      \"\\u25AD\": 'rect',\n\t      \"\\u25AE\": 'marker',\n\t      \"\\u25B1\": 'fltns',\n\t      \"\\u25B3\": 'xutri',\n\t      \"\\u25B4\": 'utrif',\n\t      \"\\u25B5\": 'utri',\n\t      \"\\u25B8\": 'rtrif',\n\t      \"\\u25B9\": 'rtri',\n\t      \"\\u25BD\": 'xdtri',\n\t      \"\\u25BE\": 'dtrif',\n\t      \"\\u25BF\": 'dtri',\n\t      \"\\u25C2\": 'ltrif',\n\t      \"\\u25C3\": 'ltri',\n\t      \"\\u25CA\": 'loz',\n\t      \"\\u25CB\": 'cir',\n\t      \"\\u25EC\": 'tridot',\n\t      \"\\u25EF\": 'xcirc',\n\t      \"\\u25F8\": 'ultri',\n\t      \"\\u25F9\": 'urtri',\n\t      \"\\u25FA\": 'lltri',\n\t      \"\\u25FB\": 'EmptySmallSquare',\n\t      \"\\u25FC\": 'FilledSmallSquare',\n\t      \"\\u2605\": 'starf',\n\t      \"\\u2606\": 'star',\n\t      \"\\u260E\": 'phone',\n\t      \"\\u2640\": 'female',\n\t      \"\\u2642\": 'male',\n\t      \"\\u2660\": 'spades',\n\t      \"\\u2663\": 'clubs',\n\t      \"\\u2665\": 'hearts',\n\t      \"\\u2666\": 'diams',\n\t      \"\\u266A\": 'sung',\n\t      \"\\u2713\": 'check',\n\t      \"\\u2717\": 'cross',\n\t      \"\\u2720\": 'malt',\n\t      \"\\u2736\": 'sext',\n\t      \"\\u2758\": 'VerticalSeparator',\n\t      \"\\u27C8\": 'bsolhsub',\n\t      \"\\u27C9\": 'suphsol',\n\t      \"\\u27F5\": 'xlarr',\n\t      \"\\u27F6\": 'xrarr',\n\t      \"\\u27F7\": 'xharr',\n\t      \"\\u27F8\": 'xlArr',\n\t      \"\\u27F9\": 'xrArr',\n\t      \"\\u27FA\": 'xhArr',\n\t      \"\\u27FC\": 'xmap',\n\t      \"\\u27FF\": 'dzigrarr',\n\t      \"\\u2902\": 'nvlArr',\n\t      \"\\u2903\": 'nvrArr',\n\t      \"\\u2904\": 'nvHarr',\n\t      \"\\u2905\": 'Map',\n\t      \"\\u290C\": 'lbarr',\n\t      \"\\u290D\": 'rbarr',\n\t      \"\\u290E\": 'lBarr',\n\t      \"\\u290F\": 'rBarr',\n\t      \"\\u2910\": 'RBarr',\n\t      \"\\u2911\": 'DDotrahd',\n\t      \"\\u2912\": 'UpArrowBar',\n\t      \"\\u2913\": 'DownArrowBar',\n\t      \"\\u2916\": 'Rarrtl',\n\t      \"\\u2919\": 'latail',\n\t      \"\\u291A\": 'ratail',\n\t      \"\\u291B\": 'lAtail',\n\t      \"\\u291C\": 'rAtail',\n\t      \"\\u291D\": 'larrfs',\n\t      \"\\u291E\": 'rarrfs',\n\t      \"\\u291F\": 'larrbfs',\n\t      \"\\u2920\": 'rarrbfs',\n\t      \"\\u2923\": 'nwarhk',\n\t      \"\\u2924\": 'nearhk',\n\t      \"\\u2925\": 'searhk',\n\t      \"\\u2926\": 'swarhk',\n\t      \"\\u2927\": 'nwnear',\n\t      \"\\u2928\": 'toea',\n\t      \"\\u2929\": 'tosa',\n\t      \"\\u292A\": 'swnwar',\n\t      \"\\u2933\": 'rarrc',\n\t      \"\\u2933\\u0338\": 'nrarrc',\n\t      \"\\u2935\": 'cudarrr',\n\t      \"\\u2936\": 'ldca',\n\t      \"\\u2937\": 'rdca',\n\t      \"\\u2938\": 'cudarrl',\n\t      \"\\u2939\": 'larrpl',\n\t      \"\\u293C\": 'curarrm',\n\t      \"\\u293D\": 'cularrp',\n\t      \"\\u2945\": 'rarrpl',\n\t      \"\\u2948\": 'harrcir',\n\t      \"\\u2949\": 'Uarrocir',\n\t      \"\\u294A\": 'lurdshar',\n\t      \"\\u294B\": 'ldrushar',\n\t      \"\\u294E\": 'LeftRightVector',\n\t      \"\\u294F\": 'RightUpDownVector',\n\t      \"\\u2950\": 'DownLeftRightVector',\n\t      \"\\u2951\": 'LeftUpDownVector',\n\t      \"\\u2952\": 'LeftVectorBar',\n\t      \"\\u2953\": 'RightVectorBar',\n\t      \"\\u2954\": 'RightUpVectorBar',\n\t      \"\\u2955\": 'RightDownVectorBar',\n\t      \"\\u2956\": 'DownLeftVectorBar',\n\t      \"\\u2957\": 'DownRightVectorBar',\n\t      \"\\u2958\": 'LeftUpVectorBar',\n\t      \"\\u2959\": 'LeftDownVectorBar',\n\t      \"\\u295A\": 'LeftTeeVector',\n\t      \"\\u295B\": 'RightTeeVector',\n\t      \"\\u295C\": 'RightUpTeeVector',\n\t      \"\\u295D\": 'RightDownTeeVector',\n\t      \"\\u295E\": 'DownLeftTeeVector',\n\t      \"\\u295F\": 'DownRightTeeVector',\n\t      \"\\u2960\": 'LeftUpTeeVector',\n\t      \"\\u2961\": 'LeftDownTeeVector',\n\t      \"\\u2962\": 'lHar',\n\t      \"\\u2963\": 'uHar',\n\t      \"\\u2964\": 'rHar',\n\t      \"\\u2965\": 'dHar',\n\t      \"\\u2966\": 'luruhar',\n\t      \"\\u2967\": 'ldrdhar',\n\t      \"\\u2968\": 'ruluhar',\n\t      \"\\u2969\": 'rdldhar',\n\t      \"\\u296A\": 'lharul',\n\t      \"\\u296B\": 'llhard',\n\t      \"\\u296C\": 'rharul',\n\t      \"\\u296D\": 'lrhard',\n\t      \"\\u296E\": 'udhar',\n\t      \"\\u296F\": 'duhar',\n\t      \"\\u2970\": 'RoundImplies',\n\t      \"\\u2971\": 'erarr',\n\t      \"\\u2972\": 'simrarr',\n\t      \"\\u2973\": 'larrsim',\n\t      \"\\u2974\": 'rarrsim',\n\t      \"\\u2975\": 'rarrap',\n\t      \"\\u2976\": 'ltlarr',\n\t      \"\\u2978\": 'gtrarr',\n\t      \"\\u2979\": 'subrarr',\n\t      \"\\u297B\": 'suplarr',\n\t      \"\\u297C\": 'lfisht',\n\t      \"\\u297D\": 'rfisht',\n\t      \"\\u297E\": 'ufisht',\n\t      \"\\u297F\": 'dfisht',\n\t      \"\\u299A\": 'vzigzag',\n\t      \"\\u299C\": 'vangrt',\n\t      \"\\u299D\": 'angrtvbd',\n\t      \"\\u29A4\": 'ange',\n\t      \"\\u29A5\": 'range',\n\t      \"\\u29A6\": 'dwangle',\n\t      \"\\u29A7\": 'uwangle',\n\t      \"\\u29A8\": 'angmsdaa',\n\t      \"\\u29A9\": 'angmsdab',\n\t      \"\\u29AA\": 'angmsdac',\n\t      \"\\u29AB\": 'angmsdad',\n\t      \"\\u29AC\": 'angmsdae',\n\t      \"\\u29AD\": 'angmsdaf',\n\t      \"\\u29AE\": 'angmsdag',\n\t      \"\\u29AF\": 'angmsdah',\n\t      \"\\u29B0\": 'bemptyv',\n\t      \"\\u29B1\": 'demptyv',\n\t      \"\\u29B2\": 'cemptyv',\n\t      \"\\u29B3\": 'raemptyv',\n\t      \"\\u29B4\": 'laemptyv',\n\t      \"\\u29B5\": 'ohbar',\n\t      \"\\u29B6\": 'omid',\n\t      \"\\u29B7\": 'opar',\n\t      \"\\u29B9\": 'operp',\n\t      \"\\u29BB\": 'olcross',\n\t      \"\\u29BC\": 'odsold',\n\t      \"\\u29BE\": 'olcir',\n\t      \"\\u29BF\": 'ofcir',\n\t      \"\\u29C0\": 'olt',\n\t      \"\\u29C1\": 'ogt',\n\t      \"\\u29C2\": 'cirscir',\n\t      \"\\u29C3\": 'cirE',\n\t      \"\\u29C4\": 'solb',\n\t      \"\\u29C5\": 'bsolb',\n\t      \"\\u29C9\": 'boxbox',\n\t      \"\\u29CD\": 'trisb',\n\t      \"\\u29CE\": 'rtriltri',\n\t      \"\\u29CF\": 'LeftTriangleBar',\n\t      \"\\u29CF\\u0338\": 'NotLeftTriangleBar',\n\t      \"\\u29D0\": 'RightTriangleBar',\n\t      \"\\u29D0\\u0338\": 'NotRightTriangleBar',\n\t      \"\\u29DC\": 'iinfin',\n\t      \"\\u29DD\": 'infintie',\n\t      \"\\u29DE\": 'nvinfin',\n\t      \"\\u29E3\": 'eparsl',\n\t      \"\\u29E4\": 'smeparsl',\n\t      \"\\u29E5\": 'eqvparsl',\n\t      \"\\u29EB\": 'lozf',\n\t      \"\\u29F4\": 'RuleDelayed',\n\t      \"\\u29F6\": 'dsol',\n\t      \"\\u2A00\": 'xodot',\n\t      \"\\u2A01\": 'xoplus',\n\t      \"\\u2A02\": 'xotime',\n\t      \"\\u2A04\": 'xuplus',\n\t      \"\\u2A06\": 'xsqcup',\n\t      \"\\u2A0D\": 'fpartint',\n\t      \"\\u2A10\": 'cirfnint',\n\t      \"\\u2A11\": 'awint',\n\t      \"\\u2A12\": 'rppolint',\n\t      \"\\u2A13\": 'scpolint',\n\t      \"\\u2A14\": 'npolint',\n\t      \"\\u2A15\": 'pointint',\n\t      \"\\u2A16\": 'quatint',\n\t      \"\\u2A17\": 'intlarhk',\n\t      \"\\u2A22\": 'pluscir',\n\t      \"\\u2A23\": 'plusacir',\n\t      \"\\u2A24\": 'simplus',\n\t      \"\\u2A25\": 'plusdu',\n\t      \"\\u2A26\": 'plussim',\n\t      \"\\u2A27\": 'plustwo',\n\t      \"\\u2A29\": 'mcomma',\n\t      \"\\u2A2A\": 'minusdu',\n\t      \"\\u2A2D\": 'loplus',\n\t      \"\\u2A2E\": 'roplus',\n\t      \"\\u2A2F\": 'Cross',\n\t      \"\\u2A30\": 'timesd',\n\t      \"\\u2A31\": 'timesbar',\n\t      \"\\u2A33\": 'smashp',\n\t      \"\\u2A34\": 'lotimes',\n\t      \"\\u2A35\": 'rotimes',\n\t      \"\\u2A36\": 'otimesas',\n\t      \"\\u2A37\": 'Otimes',\n\t      \"\\u2A38\": 'odiv',\n\t      \"\\u2A39\": 'triplus',\n\t      \"\\u2A3A\": 'triminus',\n\t      \"\\u2A3B\": 'tritime',\n\t      \"\\u2A3C\": 'iprod',\n\t      \"\\u2A3F\": 'amalg',\n\t      \"\\u2A40\": 'capdot',\n\t      \"\\u2A42\": 'ncup',\n\t      \"\\u2A43\": 'ncap',\n\t      \"\\u2A44\": 'capand',\n\t      \"\\u2A45\": 'cupor',\n\t      \"\\u2A46\": 'cupcap',\n\t      \"\\u2A47\": 'capcup',\n\t      \"\\u2A48\": 'cupbrcap',\n\t      \"\\u2A49\": 'capbrcup',\n\t      \"\\u2A4A\": 'cupcup',\n\t      \"\\u2A4B\": 'capcap',\n\t      \"\\u2A4C\": 'ccups',\n\t      \"\\u2A4D\": 'ccaps',\n\t      \"\\u2A50\": 'ccupssm',\n\t      \"\\u2A53\": 'And',\n\t      \"\\u2A54\": 'Or',\n\t      \"\\u2A55\": 'andand',\n\t      \"\\u2A56\": 'oror',\n\t      \"\\u2A57\": 'orslope',\n\t      \"\\u2A58\": 'andslope',\n\t      \"\\u2A5A\": 'andv',\n\t      \"\\u2A5B\": 'orv',\n\t      \"\\u2A5C\": 'andd',\n\t      \"\\u2A5D\": 'ord',\n\t      \"\\u2A5F\": 'wedbar',\n\t      \"\\u2A66\": 'sdote',\n\t      \"\\u2A6A\": 'simdot',\n\t      \"\\u2A6D\": 'congdot',\n\t      \"\\u2A6D\\u0338\": 'ncongdot',\n\t      \"\\u2A6E\": 'easter',\n\t      \"\\u2A6F\": 'apacir',\n\t      \"\\u2A70\": 'apE',\n\t      \"\\u2A70\\u0338\": 'napE',\n\t      \"\\u2A71\": 'eplus',\n\t      \"\\u2A72\": 'pluse',\n\t      \"\\u2A73\": 'Esim',\n\t      \"\\u2A77\": 'eDDot',\n\t      \"\\u2A78\": 'equivDD',\n\t      \"\\u2A79\": 'ltcir',\n\t      \"\\u2A7A\": 'gtcir',\n\t      \"\\u2A7B\": 'ltquest',\n\t      \"\\u2A7C\": 'gtquest',\n\t      \"\\u2A7D\": 'les',\n\t      \"\\u2A7D\\u0338\": 'nles',\n\t      \"\\u2A7E\": 'ges',\n\t      \"\\u2A7E\\u0338\": 'nges',\n\t      \"\\u2A7F\": 'lesdot',\n\t      \"\\u2A80\": 'gesdot',\n\t      \"\\u2A81\": 'lesdoto',\n\t      \"\\u2A82\": 'gesdoto',\n\t      \"\\u2A83\": 'lesdotor',\n\t      \"\\u2A84\": 'gesdotol',\n\t      \"\\u2A85\": 'lap',\n\t      \"\\u2A86\": 'gap',\n\t      \"\\u2A87\": 'lne',\n\t      \"\\u2A88\": 'gne',\n\t      \"\\u2A89\": 'lnap',\n\t      \"\\u2A8A\": 'gnap',\n\t      \"\\u2A8B\": 'lEg',\n\t      \"\\u2A8C\": 'gEl',\n\t      \"\\u2A8D\": 'lsime',\n\t      \"\\u2A8E\": 'gsime',\n\t      \"\\u2A8F\": 'lsimg',\n\t      \"\\u2A90\": 'gsiml',\n\t      \"\\u2A91\": 'lgE',\n\t      \"\\u2A92\": 'glE',\n\t      \"\\u2A93\": 'lesges',\n\t      \"\\u2A94\": 'gesles',\n\t      \"\\u2A95\": 'els',\n\t      \"\\u2A96\": 'egs',\n\t      \"\\u2A97\": 'elsdot',\n\t      \"\\u2A98\": 'egsdot',\n\t      \"\\u2A99\": 'el',\n\t      \"\\u2A9A\": 'eg',\n\t      \"\\u2A9D\": 'siml',\n\t      \"\\u2A9E\": 'simg',\n\t      \"\\u2A9F\": 'simlE',\n\t      \"\\u2AA0\": 'simgE',\n\t      \"\\u2AA1\": 'LessLess',\n\t      \"\\u2AA1\\u0338\": 'NotNestedLessLess',\n\t      \"\\u2AA2\": 'GreaterGreater',\n\t      \"\\u2AA2\\u0338\": 'NotNestedGreaterGreater',\n\t      \"\\u2AA4\": 'glj',\n\t      \"\\u2AA5\": 'gla',\n\t      \"\\u2AA6\": 'ltcc',\n\t      \"\\u2AA7\": 'gtcc',\n\t      \"\\u2AA8\": 'lescc',\n\t      \"\\u2AA9\": 'gescc',\n\t      \"\\u2AAA\": 'smt',\n\t      \"\\u2AAB\": 'lat',\n\t      \"\\u2AAC\": 'smte',\n\t      \"\\u2AAC\\uFE00\": 'smtes',\n\t      \"\\u2AAD\": 'late',\n\t      \"\\u2AAD\\uFE00\": 'lates',\n\t      \"\\u2AAE\": 'bumpE',\n\t      \"\\u2AAF\": 'pre',\n\t      \"\\u2AAF\\u0338\": 'npre',\n\t      \"\\u2AB0\": 'sce',\n\t      \"\\u2AB0\\u0338\": 'nsce',\n\t      \"\\u2AB3\": 'prE',\n\t      \"\\u2AB4\": 'scE',\n\t      \"\\u2AB5\": 'prnE',\n\t      \"\\u2AB6\": 'scnE',\n\t      \"\\u2AB7\": 'prap',\n\t      \"\\u2AB8\": 'scap',\n\t      \"\\u2AB9\": 'prnap',\n\t      \"\\u2ABA\": 'scnap',\n\t      \"\\u2ABB\": 'Pr',\n\t      \"\\u2ABC\": 'Sc',\n\t      \"\\u2ABD\": 'subdot',\n\t      \"\\u2ABE\": 'supdot',\n\t      \"\\u2ABF\": 'subplus',\n\t      \"\\u2AC0\": 'supplus',\n\t      \"\\u2AC1\": 'submult',\n\t      \"\\u2AC2\": 'supmult',\n\t      \"\\u2AC3\": 'subedot',\n\t      \"\\u2AC4\": 'supedot',\n\t      \"\\u2AC5\": 'subE',\n\t      \"\\u2AC5\\u0338\": 'nsubE',\n\t      \"\\u2AC6\": 'supE',\n\t      \"\\u2AC6\\u0338\": 'nsupE',\n\t      \"\\u2AC7\": 'subsim',\n\t      \"\\u2AC8\": 'supsim',\n\t      \"\\u2ACB\\uFE00\": 'vsubnE',\n\t      \"\\u2ACB\": 'subnE',\n\t      \"\\u2ACC\\uFE00\": 'vsupnE',\n\t      \"\\u2ACC\": 'supnE',\n\t      \"\\u2ACF\": 'csub',\n\t      \"\\u2AD0\": 'csup',\n\t      \"\\u2AD1\": 'csube',\n\t      \"\\u2AD2\": 'csupe',\n\t      \"\\u2AD3\": 'subsup',\n\t      \"\\u2AD4\": 'supsub',\n\t      \"\\u2AD5\": 'subsub',\n\t      \"\\u2AD6\": 'supsup',\n\t      \"\\u2AD7\": 'suphsub',\n\t      \"\\u2AD8\": 'supdsub',\n\t      \"\\u2AD9\": 'forkv',\n\t      \"\\u2ADA\": 'topfork',\n\t      \"\\u2ADB\": 'mlcp',\n\t      \"\\u2AE4\": 'Dashv',\n\t      \"\\u2AE6\": 'Vdashl',\n\t      \"\\u2AE7\": 'Barv',\n\t      \"\\u2AE8\": 'vBar',\n\t      \"\\u2AE9\": 'vBarv',\n\t      \"\\u2AEB\": 'Vbar',\n\t      \"\\u2AEC\": 'Not',\n\t      \"\\u2AED\": 'bNot',\n\t      \"\\u2AEE\": 'rnmid',\n\t      \"\\u2AEF\": 'cirmid',\n\t      \"\\u2AF0\": 'midcir',\n\t      \"\\u2AF1\": 'topcir',\n\t      \"\\u2AF2\": 'nhpar',\n\t      \"\\u2AF3\": 'parsim',\n\t      \"\\u2AFD\": 'parsl',\n\t      \"\\u2AFD\\u20E5\": 'nparsl',\n\t      \"\\u266D\": 'flat',\n\t      \"\\u266E\": 'natur',\n\t      \"\\u266F\": 'sharp',\n\t      '\\xA4': 'curren',\n\t      '\\xA2': 'cent',\n\t      '$': 'dollar',\n\t      '\\xA3': 'pound',\n\t      '\\xA5': 'yen',\n\t      \"\\u20AC\": 'euro',\n\t      '\\xB9': 'sup1',\n\t      '\\xBD': 'half',\n\t      \"\\u2153\": 'frac13',\n\t      '\\xBC': 'frac14',\n\t      \"\\u2155\": 'frac15',\n\t      \"\\u2159\": 'frac16',\n\t      \"\\u215B\": 'frac18',\n\t      '\\xB2': 'sup2',\n\t      \"\\u2154\": 'frac23',\n\t      \"\\u2156\": 'frac25',\n\t      '\\xB3': 'sup3',\n\t      '\\xBE': 'frac34',\n\t      \"\\u2157\": 'frac35',\n\t      \"\\u215C\": 'frac38',\n\t      \"\\u2158\": 'frac45',\n\t      \"\\u215A\": 'frac56',\n\t      \"\\u215D\": 'frac58',\n\t      \"\\u215E\": 'frac78',\n\t      \"\\uD835\\uDCB6\": 'ascr',\n\t      \"\\uD835\\uDD52\": 'aopf',\n\t      \"\\uD835\\uDD1E\": 'afr',\n\t      \"\\uD835\\uDD38\": 'Aopf',\n\t      \"\\uD835\\uDD04\": 'Afr',\n\t      \"\\uD835\\uDC9C\": 'Ascr',\n\t      '\\xAA': 'ordf',\n\t      '\\xE1': 'aacute',\n\t      '\\xC1': 'Aacute',\n\t      '\\xE0': 'agrave',\n\t      '\\xC0': 'Agrave',\n\t      \"\\u0103\": 'abreve',\n\t      \"\\u0102\": 'Abreve',\n\t      '\\xE2': 'acirc',\n\t      '\\xC2': 'Acirc',\n\t      '\\xE5': 'aring',\n\t      '\\xC5': 'angst',\n\t      '\\xE4': 'auml',\n\t      '\\xC4': 'Auml',\n\t      '\\xE3': 'atilde',\n\t      '\\xC3': 'Atilde',\n\t      \"\\u0105\": 'aogon',\n\t      \"\\u0104\": 'Aogon',\n\t      \"\\u0101\": 'amacr',\n\t      \"\\u0100\": 'Amacr',\n\t      '\\xE6': 'aelig',\n\t      '\\xC6': 'AElig',\n\t      \"\\uD835\\uDCB7\": 'bscr',\n\t      \"\\uD835\\uDD53\": 'bopf',\n\t      \"\\uD835\\uDD1F\": 'bfr',\n\t      \"\\uD835\\uDD39\": 'Bopf',\n\t      \"\\u212C\": 'Bscr',\n\t      \"\\uD835\\uDD05\": 'Bfr',\n\t      \"\\uD835\\uDD20\": 'cfr',\n\t      \"\\uD835\\uDCB8\": 'cscr',\n\t      \"\\uD835\\uDD54\": 'copf',\n\t      \"\\u212D\": 'Cfr',\n\t      \"\\uD835\\uDC9E\": 'Cscr',\n\t      \"\\u2102\": 'Copf',\n\t      \"\\u0107\": 'cacute',\n\t      \"\\u0106\": 'Cacute',\n\t      \"\\u0109\": 'ccirc',\n\t      \"\\u0108\": 'Ccirc',\n\t      \"\\u010D\": 'ccaron',\n\t      \"\\u010C\": 'Ccaron',\n\t      \"\\u010B\": 'cdot',\n\t      \"\\u010A\": 'Cdot',\n\t      '\\xE7': 'ccedil',\n\t      '\\xC7': 'Ccedil',\n\t      \"\\u2105\": 'incare',\n\t      \"\\uD835\\uDD21\": 'dfr',\n\t      \"\\u2146\": 'dd',\n\t      \"\\uD835\\uDD55\": 'dopf',\n\t      \"\\uD835\\uDCB9\": 'dscr',\n\t      \"\\uD835\\uDC9F\": 'Dscr',\n\t      \"\\uD835\\uDD07\": 'Dfr',\n\t      \"\\u2145\": 'DD',\n\t      \"\\uD835\\uDD3B\": 'Dopf',\n\t      \"\\u010F\": 'dcaron',\n\t      \"\\u010E\": 'Dcaron',\n\t      \"\\u0111\": 'dstrok',\n\t      \"\\u0110\": 'Dstrok',\n\t      '\\xF0': 'eth',\n\t      '\\xD0': 'ETH',\n\t      \"\\u2147\": 'ee',\n\t      \"\\u212F\": 'escr',\n\t      \"\\uD835\\uDD22\": 'efr',\n\t      \"\\uD835\\uDD56\": 'eopf',\n\t      \"\\u2130\": 'Escr',\n\t      \"\\uD835\\uDD08\": 'Efr',\n\t      \"\\uD835\\uDD3C\": 'Eopf',\n\t      '\\xE9': 'eacute',\n\t      '\\xC9': 'Eacute',\n\t      '\\xE8': 'egrave',\n\t      '\\xC8': 'Egrave',\n\t      '\\xEA': 'ecirc',\n\t      '\\xCA': 'Ecirc',\n\t      \"\\u011B\": 'ecaron',\n\t      \"\\u011A\": 'Ecaron',\n\t      '\\xEB': 'euml',\n\t      '\\xCB': 'Euml',\n\t      \"\\u0117\": 'edot',\n\t      \"\\u0116\": 'Edot',\n\t      \"\\u0119\": 'eogon',\n\t      \"\\u0118\": 'Eogon',\n\t      \"\\u0113\": 'emacr',\n\t      \"\\u0112\": 'Emacr',\n\t      \"\\uD835\\uDD23\": 'ffr',\n\t      \"\\uD835\\uDD57\": 'fopf',\n\t      \"\\uD835\\uDCBB\": 'fscr',\n\t      \"\\uD835\\uDD09\": 'Ffr',\n\t      \"\\uD835\\uDD3D\": 'Fopf',\n\t      \"\\u2131\": 'Fscr',\n\t      \"\\uFB00\": 'fflig',\n\t      \"\\uFB03\": 'ffilig',\n\t      \"\\uFB04\": 'ffllig',\n\t      \"\\uFB01\": 'filig',\n\t      'fj': 'fjlig',\n\t      \"\\uFB02\": 'fllig',\n\t      \"\\u0192\": 'fnof',\n\t      \"\\u210A\": 'gscr',\n\t      \"\\uD835\\uDD58\": 'gopf',\n\t      \"\\uD835\\uDD24\": 'gfr',\n\t      \"\\uD835\\uDCA2\": 'Gscr',\n\t      \"\\uD835\\uDD3E\": 'Gopf',\n\t      \"\\uD835\\uDD0A\": 'Gfr',\n\t      \"\\u01F5\": 'gacute',\n\t      \"\\u011F\": 'gbreve',\n\t      \"\\u011E\": 'Gbreve',\n\t      \"\\u011D\": 'gcirc',\n\t      \"\\u011C\": 'Gcirc',\n\t      \"\\u0121\": 'gdot',\n\t      \"\\u0120\": 'Gdot',\n\t      \"\\u0122\": 'Gcedil',\n\t      \"\\uD835\\uDD25\": 'hfr',\n\t      \"\\u210E\": 'planckh',\n\t      \"\\uD835\\uDCBD\": 'hscr',\n\t      \"\\uD835\\uDD59\": 'hopf',\n\t      \"\\u210B\": 'Hscr',\n\t      \"\\u210C\": 'Hfr',\n\t      \"\\u210D\": 'Hopf',\n\t      \"\\u0125\": 'hcirc',\n\t      \"\\u0124\": 'Hcirc',\n\t      \"\\u210F\": 'hbar',\n\t      \"\\u0127\": 'hstrok',\n\t      \"\\u0126\": 'Hstrok',\n\t      \"\\uD835\\uDD5A\": 'iopf',\n\t      \"\\uD835\\uDD26\": 'ifr',\n\t      \"\\uD835\\uDCBE\": 'iscr',\n\t      \"\\u2148\": 'ii',\n\t      \"\\uD835\\uDD40\": 'Iopf',\n\t      \"\\u2110\": 'Iscr',\n\t      \"\\u2111\": 'Im',\n\t      '\\xED': 'iacute',\n\t      '\\xCD': 'Iacute',\n\t      '\\xEC': 'igrave',\n\t      '\\xCC': 'Igrave',\n\t      '\\xEE': 'icirc',\n\t      '\\xCE': 'Icirc',\n\t      '\\xEF': 'iuml',\n\t      '\\xCF': 'Iuml',\n\t      \"\\u0129\": 'itilde',\n\t      \"\\u0128\": 'Itilde',\n\t      \"\\u0130\": 'Idot',\n\t      \"\\u012F\": 'iogon',\n\t      \"\\u012E\": 'Iogon',\n\t      \"\\u012B\": 'imacr',\n\t      \"\\u012A\": 'Imacr',\n\t      \"\\u0133\": 'ijlig',\n\t      \"\\u0132\": 'IJlig',\n\t      \"\\u0131\": 'imath',\n\t      \"\\uD835\\uDCBF\": 'jscr',\n\t      \"\\uD835\\uDD5B\": 'jopf',\n\t      \"\\uD835\\uDD27\": 'jfr',\n\t      \"\\uD835\\uDCA5\": 'Jscr',\n\t      \"\\uD835\\uDD0D\": 'Jfr',\n\t      \"\\uD835\\uDD41\": 'Jopf',\n\t      \"\\u0135\": 'jcirc',\n\t      \"\\u0134\": 'Jcirc',\n\t      \"\\u0237\": 'jmath',\n\t      \"\\uD835\\uDD5C\": 'kopf',\n\t      \"\\uD835\\uDCC0\": 'kscr',\n\t      \"\\uD835\\uDD28\": 'kfr',\n\t      \"\\uD835\\uDCA6\": 'Kscr',\n\t      \"\\uD835\\uDD42\": 'Kopf',\n\t      \"\\uD835\\uDD0E\": 'Kfr',\n\t      \"\\u0137\": 'kcedil',\n\t      \"\\u0136\": 'Kcedil',\n\t      \"\\uD835\\uDD29\": 'lfr',\n\t      \"\\uD835\\uDCC1\": 'lscr',\n\t      \"\\u2113\": 'ell',\n\t      \"\\uD835\\uDD5D\": 'lopf',\n\t      \"\\u2112\": 'Lscr',\n\t      \"\\uD835\\uDD0F\": 'Lfr',\n\t      \"\\uD835\\uDD43\": 'Lopf',\n\t      \"\\u013A\": 'lacute',\n\t      \"\\u0139\": 'Lacute',\n\t      \"\\u013E\": 'lcaron',\n\t      \"\\u013D\": 'Lcaron',\n\t      \"\\u013C\": 'lcedil',\n\t      \"\\u013B\": 'Lcedil',\n\t      \"\\u0142\": 'lstrok',\n\t      \"\\u0141\": 'Lstrok',\n\t      \"\\u0140\": 'lmidot',\n\t      \"\\u013F\": 'Lmidot',\n\t      \"\\uD835\\uDD2A\": 'mfr',\n\t      \"\\uD835\\uDD5E\": 'mopf',\n\t      \"\\uD835\\uDCC2\": 'mscr',\n\t      \"\\uD835\\uDD10\": 'Mfr',\n\t      \"\\uD835\\uDD44\": 'Mopf',\n\t      \"\\u2133\": 'Mscr',\n\t      \"\\uD835\\uDD2B\": 'nfr',\n\t      \"\\uD835\\uDD5F\": 'nopf',\n\t      \"\\uD835\\uDCC3\": 'nscr',\n\t      \"\\u2115\": 'Nopf',\n\t      \"\\uD835\\uDCA9\": 'Nscr',\n\t      \"\\uD835\\uDD11\": 'Nfr',\n\t      \"\\u0144\": 'nacute',\n\t      \"\\u0143\": 'Nacute',\n\t      \"\\u0148\": 'ncaron',\n\t      \"\\u0147\": 'Ncaron',\n\t      '\\xF1': 'ntilde',\n\t      '\\xD1': 'Ntilde',\n\t      \"\\u0146\": 'ncedil',\n\t      \"\\u0145\": 'Ncedil',\n\t      \"\\u2116\": 'numero',\n\t      \"\\u014B\": 'eng',\n\t      \"\\u014A\": 'ENG',\n\t      \"\\uD835\\uDD60\": 'oopf',\n\t      \"\\uD835\\uDD2C\": 'ofr',\n\t      \"\\u2134\": 'oscr',\n\t      \"\\uD835\\uDCAA\": 'Oscr',\n\t      \"\\uD835\\uDD12\": 'Ofr',\n\t      \"\\uD835\\uDD46\": 'Oopf',\n\t      '\\xBA': 'ordm',\n\t      '\\xF3': 'oacute',\n\t      '\\xD3': 'Oacute',\n\t      '\\xF2': 'ograve',\n\t      '\\xD2': 'Ograve',\n\t      '\\xF4': 'ocirc',\n\t      '\\xD4': 'Ocirc',\n\t      '\\xF6': 'ouml',\n\t      '\\xD6': 'Ouml',\n\t      \"\\u0151\": 'odblac',\n\t      \"\\u0150\": 'Odblac',\n\t      '\\xF5': 'otilde',\n\t      '\\xD5': 'Otilde',\n\t      '\\xF8': 'oslash',\n\t      '\\xD8': 'Oslash',\n\t      \"\\u014D\": 'omacr',\n\t      \"\\u014C\": 'Omacr',\n\t      \"\\u0153\": 'oelig',\n\t      \"\\u0152\": 'OElig',\n\t      \"\\uD835\\uDD2D\": 'pfr',\n\t      \"\\uD835\\uDCC5\": 'pscr',\n\t      \"\\uD835\\uDD61\": 'popf',\n\t      \"\\u2119\": 'Popf',\n\t      \"\\uD835\\uDD13\": 'Pfr',\n\t      \"\\uD835\\uDCAB\": 'Pscr',\n\t      \"\\uD835\\uDD62\": 'qopf',\n\t      \"\\uD835\\uDD2E\": 'qfr',\n\t      \"\\uD835\\uDCC6\": 'qscr',\n\t      \"\\uD835\\uDCAC\": 'Qscr',\n\t      \"\\uD835\\uDD14\": 'Qfr',\n\t      \"\\u211A\": 'Qopf',\n\t      \"\\u0138\": 'kgreen',\n\t      \"\\uD835\\uDD2F\": 'rfr',\n\t      \"\\uD835\\uDD63\": 'ropf',\n\t      \"\\uD835\\uDCC7\": 'rscr',\n\t      \"\\u211B\": 'Rscr',\n\t      \"\\u211C\": 'Re',\n\t      \"\\u211D\": 'Ropf',\n\t      \"\\u0155\": 'racute',\n\t      \"\\u0154\": 'Racute',\n\t      \"\\u0159\": 'rcaron',\n\t      \"\\u0158\": 'Rcaron',\n\t      \"\\u0157\": 'rcedil',\n\t      \"\\u0156\": 'Rcedil',\n\t      \"\\uD835\\uDD64\": 'sopf',\n\t      \"\\uD835\\uDCC8\": 'sscr',\n\t      \"\\uD835\\uDD30\": 'sfr',\n\t      \"\\uD835\\uDD4A\": 'Sopf',\n\t      \"\\uD835\\uDD16\": 'Sfr',\n\t      \"\\uD835\\uDCAE\": 'Sscr',\n\t      \"\\u24C8\": 'oS',\n\t      \"\\u015B\": 'sacute',\n\t      \"\\u015A\": 'Sacute',\n\t      \"\\u015D\": 'scirc',\n\t      \"\\u015C\": 'Scirc',\n\t      \"\\u0161\": 'scaron',\n\t      \"\\u0160\": 'Scaron',\n\t      \"\\u015F\": 'scedil',\n\t      \"\\u015E\": 'Scedil',\n\t      '\\xDF': 'szlig',\n\t      \"\\uD835\\uDD31\": 'tfr',\n\t      \"\\uD835\\uDCC9\": 'tscr',\n\t      \"\\uD835\\uDD65\": 'topf',\n\t      \"\\uD835\\uDCAF\": 'Tscr',\n\t      \"\\uD835\\uDD17\": 'Tfr',\n\t      \"\\uD835\\uDD4B\": 'Topf',\n\t      \"\\u0165\": 'tcaron',\n\t      \"\\u0164\": 'Tcaron',\n\t      \"\\u0163\": 'tcedil',\n\t      \"\\u0162\": 'Tcedil',\n\t      \"\\u2122\": 'trade',\n\t      \"\\u0167\": 'tstrok',\n\t      \"\\u0166\": 'Tstrok',\n\t      \"\\uD835\\uDCCA\": 'uscr',\n\t      \"\\uD835\\uDD66\": 'uopf',\n\t      \"\\uD835\\uDD32\": 'ufr',\n\t      \"\\uD835\\uDD4C\": 'Uopf',\n\t      \"\\uD835\\uDD18\": 'Ufr',\n\t      \"\\uD835\\uDCB0\": 'Uscr',\n\t      '\\xFA': 'uacute',\n\t      '\\xDA': 'Uacute',\n\t      '\\xF9': 'ugrave',\n\t      '\\xD9': 'Ugrave',\n\t      \"\\u016D\": 'ubreve',\n\t      \"\\u016C\": 'Ubreve',\n\t      '\\xFB': 'ucirc',\n\t      '\\xDB': 'Ucirc',\n\t      \"\\u016F\": 'uring',\n\t      \"\\u016E\": 'Uring',\n\t      '\\xFC': 'uuml',\n\t      '\\xDC': 'Uuml',\n\t      \"\\u0171\": 'udblac',\n\t      \"\\u0170\": 'Udblac',\n\t      \"\\u0169\": 'utilde',\n\t      \"\\u0168\": 'Utilde',\n\t      \"\\u0173\": 'uogon',\n\t      \"\\u0172\": 'Uogon',\n\t      \"\\u016B\": 'umacr',\n\t      \"\\u016A\": 'Umacr',\n\t      \"\\uD835\\uDD33\": 'vfr',\n\t      \"\\uD835\\uDD67\": 'vopf',\n\t      \"\\uD835\\uDCCB\": 'vscr',\n\t      \"\\uD835\\uDD19\": 'Vfr',\n\t      \"\\uD835\\uDD4D\": 'Vopf',\n\t      \"\\uD835\\uDCB1\": 'Vscr',\n\t      \"\\uD835\\uDD68\": 'wopf',\n\t      \"\\uD835\\uDCCC\": 'wscr',\n\t      \"\\uD835\\uDD34\": 'wfr',\n\t      \"\\uD835\\uDCB2\": 'Wscr',\n\t      \"\\uD835\\uDD4E\": 'Wopf',\n\t      \"\\uD835\\uDD1A\": 'Wfr',\n\t      \"\\u0175\": 'wcirc',\n\t      \"\\u0174\": 'Wcirc',\n\t      \"\\uD835\\uDD35\": 'xfr',\n\t      \"\\uD835\\uDCCD\": 'xscr',\n\t      \"\\uD835\\uDD69\": 'xopf',\n\t      \"\\uD835\\uDD4F\": 'Xopf',\n\t      \"\\uD835\\uDD1B\": 'Xfr',\n\t      \"\\uD835\\uDCB3\": 'Xscr',\n\t      \"\\uD835\\uDD36\": 'yfr',\n\t      \"\\uD835\\uDCCE\": 'yscr',\n\t      \"\\uD835\\uDD6A\": 'yopf',\n\t      \"\\uD835\\uDCB4\": 'Yscr',\n\t      \"\\uD835\\uDD1C\": 'Yfr',\n\t      \"\\uD835\\uDD50\": 'Yopf',\n\t      '\\xFD': 'yacute',\n\t      '\\xDD': 'Yacute',\n\t      \"\\u0177\": 'ycirc',\n\t      \"\\u0176\": 'Ycirc',\n\t      '\\xFF': 'yuml',\n\t      \"\\u0178\": 'Yuml',\n\t      \"\\uD835\\uDCCF\": 'zscr',\n\t      \"\\uD835\\uDD37\": 'zfr',\n\t      \"\\uD835\\uDD6B\": 'zopf',\n\t      \"\\u2128\": 'Zfr',\n\t      \"\\u2124\": 'Zopf',\n\t      \"\\uD835\\uDCB5\": 'Zscr',\n\t      \"\\u017A\": 'zacute',\n\t      \"\\u0179\": 'Zacute',\n\t      \"\\u017E\": 'zcaron',\n\t      \"\\u017D\": 'Zcaron',\n\t      \"\\u017C\": 'zdot',\n\t      \"\\u017B\": 'Zdot',\n\t      \"\\u01B5\": 'imped',\n\t      '\\xFE': 'thorn',\n\t      '\\xDE': 'THORN',\n\t      \"\\u0149\": 'napos',\n\t      \"\\u03B1\": 'alpha',\n\t      \"\\u0391\": 'Alpha',\n\t      \"\\u03B2\": 'beta',\n\t      \"\\u0392\": 'Beta',\n\t      \"\\u03B3\": 'gamma',\n\t      \"\\u0393\": 'Gamma',\n\t      \"\\u03B4\": 'delta',\n\t      \"\\u0394\": 'Delta',\n\t      \"\\u03B5\": 'epsi',\n\t      \"\\u03F5\": 'epsiv',\n\t      \"\\u0395\": 'Epsilon',\n\t      \"\\u03DD\": 'gammad',\n\t      \"\\u03DC\": 'Gammad',\n\t      \"\\u03B6\": 'zeta',\n\t      \"\\u0396\": 'Zeta',\n\t      \"\\u03B7\": 'eta',\n\t      \"\\u0397\": 'Eta',\n\t      \"\\u03B8\": 'theta',\n\t      \"\\u03D1\": 'thetav',\n\t      \"\\u0398\": 'Theta',\n\t      \"\\u03B9\": 'iota',\n\t      \"\\u0399\": 'Iota',\n\t      \"\\u03BA\": 'kappa',\n\t      \"\\u03F0\": 'kappav',\n\t      \"\\u039A\": 'Kappa',\n\t      \"\\u03BB\": 'lambda',\n\t      \"\\u039B\": 'Lambda',\n\t      \"\\u03BC\": 'mu',\n\t      '\\xB5': 'micro',\n\t      \"\\u039C\": 'Mu',\n\t      \"\\u03BD\": 'nu',\n\t      \"\\u039D\": 'Nu',\n\t      \"\\u03BE\": 'xi',\n\t      \"\\u039E\": 'Xi',\n\t      \"\\u03BF\": 'omicron',\n\t      \"\\u039F\": 'Omicron',\n\t      \"\\u03C0\": 'pi',\n\t      \"\\u03D6\": 'piv',\n\t      \"\\u03A0\": 'Pi',\n\t      \"\\u03C1\": 'rho',\n\t      \"\\u03F1\": 'rhov',\n\t      \"\\u03A1\": 'Rho',\n\t      \"\\u03C3\": 'sigma',\n\t      \"\\u03A3\": 'Sigma',\n\t      \"\\u03C2\": 'sigmaf',\n\t      \"\\u03C4\": 'tau',\n\t      \"\\u03A4\": 'Tau',\n\t      \"\\u03C5\": 'upsi',\n\t      \"\\u03A5\": 'Upsilon',\n\t      \"\\u03D2\": 'Upsi',\n\t      \"\\u03C6\": 'phi',\n\t      \"\\u03D5\": 'phiv',\n\t      \"\\u03A6\": 'Phi',\n\t      \"\\u03C7\": 'chi',\n\t      \"\\u03A7\": 'Chi',\n\t      \"\\u03C8\": 'psi',\n\t      \"\\u03A8\": 'Psi',\n\t      \"\\u03C9\": 'omega',\n\t      \"\\u03A9\": 'ohm',\n\t      \"\\u0430\": 'acy',\n\t      \"\\u0410\": 'Acy',\n\t      \"\\u0431\": 'bcy',\n\t      \"\\u0411\": 'Bcy',\n\t      \"\\u0432\": 'vcy',\n\t      \"\\u0412\": 'Vcy',\n\t      \"\\u0433\": 'gcy',\n\t      \"\\u0413\": 'Gcy',\n\t      \"\\u0453\": 'gjcy',\n\t      \"\\u0403\": 'GJcy',\n\t      \"\\u0434\": 'dcy',\n\t      \"\\u0414\": 'Dcy',\n\t      \"\\u0452\": 'djcy',\n\t      \"\\u0402\": 'DJcy',\n\t      \"\\u0435\": 'iecy',\n\t      \"\\u0415\": 'IEcy',\n\t      \"\\u0451\": 'iocy',\n\t      \"\\u0401\": 'IOcy',\n\t      \"\\u0454\": 'jukcy',\n\t      \"\\u0404\": 'Jukcy',\n\t      \"\\u0436\": 'zhcy',\n\t      \"\\u0416\": 'ZHcy',\n\t      \"\\u0437\": 'zcy',\n\t      \"\\u0417\": 'Zcy',\n\t      \"\\u0455\": 'dscy',\n\t      \"\\u0405\": 'DScy',\n\t      \"\\u0438\": 'icy',\n\t      \"\\u0418\": 'Icy',\n\t      \"\\u0456\": 'iukcy',\n\t      \"\\u0406\": 'Iukcy',\n\t      \"\\u0457\": 'yicy',\n\t      \"\\u0407\": 'YIcy',\n\t      \"\\u0439\": 'jcy',\n\t      \"\\u0419\": 'Jcy',\n\t      \"\\u0458\": 'jsercy',\n\t      \"\\u0408\": 'Jsercy',\n\t      \"\\u043A\": 'kcy',\n\t      \"\\u041A\": 'Kcy',\n\t      \"\\u045C\": 'kjcy',\n\t      \"\\u040C\": 'KJcy',\n\t      \"\\u043B\": 'lcy',\n\t      \"\\u041B\": 'Lcy',\n\t      \"\\u0459\": 'ljcy',\n\t      \"\\u0409\": 'LJcy',\n\t      \"\\u043C\": 'mcy',\n\t      \"\\u041C\": 'Mcy',\n\t      \"\\u043D\": 'ncy',\n\t      \"\\u041D\": 'Ncy',\n\t      \"\\u045A\": 'njcy',\n\t      \"\\u040A\": 'NJcy',\n\t      \"\\u043E\": 'ocy',\n\t      \"\\u041E\": 'Ocy',\n\t      \"\\u043F\": 'pcy',\n\t      \"\\u041F\": 'Pcy',\n\t      \"\\u0440\": 'rcy',\n\t      \"\\u0420\": 'Rcy',\n\t      \"\\u0441\": 'scy',\n\t      \"\\u0421\": 'Scy',\n\t      \"\\u0442\": 'tcy',\n\t      \"\\u0422\": 'Tcy',\n\t      \"\\u045B\": 'tshcy',\n\t      \"\\u040B\": 'TSHcy',\n\t      \"\\u0443\": 'ucy',\n\t      \"\\u0423\": 'Ucy',\n\t      \"\\u045E\": 'ubrcy',\n\t      \"\\u040E\": 'Ubrcy',\n\t      \"\\u0444\": 'fcy',\n\t      \"\\u0424\": 'Fcy',\n\t      \"\\u0445\": 'khcy',\n\t      \"\\u0425\": 'KHcy',\n\t      \"\\u0446\": 'tscy',\n\t      \"\\u0426\": 'TScy',\n\t      \"\\u0447\": 'chcy',\n\t      \"\\u0427\": 'CHcy',\n\t      \"\\u045F\": 'dzcy',\n\t      \"\\u040F\": 'DZcy',\n\t      \"\\u0448\": 'shcy',\n\t      \"\\u0428\": 'SHcy',\n\t      \"\\u0449\": 'shchcy',\n\t      \"\\u0429\": 'SHCHcy',\n\t      \"\\u044A\": 'hardcy',\n\t      \"\\u042A\": 'HARDcy',\n\t      \"\\u044B\": 'ycy',\n\t      \"\\u042B\": 'Ycy',\n\t      \"\\u044C\": 'softcy',\n\t      \"\\u042C\": 'SOFTcy',\n\t      \"\\u044D\": 'ecy',\n\t      \"\\u042D\": 'Ecy',\n\t      \"\\u044E\": 'yucy',\n\t      \"\\u042E\": 'YUcy',\n\t      \"\\u044F\": 'yacy',\n\t      \"\\u042F\": 'YAcy',\n\t      \"\\u2135\": 'aleph',\n\t      \"\\u2136\": 'beth',\n\t      \"\\u2137\": 'gimel',\n\t      \"\\u2138\": 'daleth'\n\t    };\n\t    var regexEscape = /[\"&'<>`]/g;\n\t    var escapeMap = {\n\t      '\"': '&quot;',\n\t      '&': '&amp;',\n\t      '\\'': '&#x27;',\n\t      '<': '&lt;',\n\t      // See https://mathiasbynens.be/notes/ambiguous-ampersands: in HTML, the\n\t      // following is not strictly necessary unless it’s part of a tag or an\n\t      // unquoted attribute value. We’re only escaping it to support those\n\t      // situations, and for XML support.\n\t      '>': '&gt;',\n\t      // In Internet Explorer ≤ 8, the backtick character can be used\n\t      // to break out of (un)quoted attribute values or HTML comments.\n\t      // See http://html5sec.org/#102, http://html5sec.org/#108, and\n\t      // http://html5sec.org/#133.\n\t      '`': '&#x60;'\n\t    };\n\t    var regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/;\n\t    var regexInvalidRawCodePoint = /[\\0-\\x08\\x0B\\x0E-\\x1F\\x7F-\\x9F\\uFDD0-\\uFDEF\\uFFFE\\uFFFF]|[\\uD83F\\uD87F\\uD8BF\\uD8FF\\uD93F\\uD97F\\uD9BF\\uD9FF\\uDA3F\\uDA7F\\uDABF\\uDAFF\\uDB3F\\uDB7F\\uDBBF\\uDBFF][\\uDFFE\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/;\n\t    var regexDecode = /&(CounterClockwiseContourIntegral|DoubleLongLeftRightArrow|ClockwiseContourIntegral|NotNestedGreaterGreater|NotSquareSupersetEqual|DiacriticalDoubleAcute|NotRightTriangleEqual|NotSucceedsSlantEqual|NotPrecedesSlantEqual|CloseCurlyDoubleQuote|NegativeVeryThinSpace|DoubleContourIntegral|FilledVerySmallSquare|CapitalDifferentialD|OpenCurlyDoubleQuote|EmptyVerySmallSquare|NestedGreaterGreater|DoubleLongRightArrow|NotLeftTriangleEqual|NotGreaterSlantEqual|ReverseUpEquilibrium|DoubleLeftRightArrow|NotSquareSubsetEqual|NotDoubleVerticalBar|RightArrowLeftArrow|NotGreaterFullEqual|NotRightTriangleBar|SquareSupersetEqual|DownLeftRightVector|DoubleLongLeftArrow|leftrightsquigarrow|LeftArrowRightArrow|NegativeMediumSpace|blacktriangleright|RightDownVectorBar|PrecedesSlantEqual|RightDoubleBracket|SucceedsSlantEqual|NotLeftTriangleBar|RightTriangleEqual|SquareIntersection|RightDownTeeVector|ReverseEquilibrium|NegativeThickSpace|longleftrightarrow|Longleftrightarrow|LongLeftRightArrow|DownRightTeeVector|DownRightVectorBar|GreaterSlantEqual|SquareSubsetEqual|LeftDownVectorBar|LeftDoubleBracket|VerticalSeparator|rightleftharpoons|NotGreaterGreater|NotSquareSuperset|blacktriangleleft|blacktriangledown|NegativeThinSpace|LeftDownTeeVector|NotLessSlantEqual|leftrightharpoons|DoubleUpDownArrow|DoubleVerticalBar|LeftTriangleEqual|FilledSmallSquare|twoheadrightarrow|NotNestedLessLess|DownLeftTeeVector|DownLeftVectorBar|RightAngleBracket|NotTildeFullEqual|NotReverseElement|RightUpDownVector|DiacriticalTilde|NotSucceedsTilde|circlearrowright|NotPrecedesEqual|rightharpoondown|DoubleRightArrow|NotSucceedsEqual|NonBreakingSpace|NotRightTriangle|LessEqualGreater|RightUpTeeVector|LeftAngleBracket|GreaterFullEqual|DownArrowUpArrow|RightUpVectorBar|twoheadleftarrow|GreaterEqualLess|downharpoonright|RightTriangleBar|ntrianglerighteq|NotSupersetEqual|LeftUpDownVector|DiacriticalAcute|rightrightarrows|vartriangleright|UpArrowDownArrow|DiacriticalGrave|UnderParenthesis|EmptySmallSquare|LeftUpVectorBar|leftrightarrows|DownRightVector|downharpoonleft|trianglerighteq|ShortRightArrow|OverParenthesis|DoubleLeftArrow|DoubleDownArrow|NotSquareSubset|bigtriangledown|ntrianglelefteq|UpperRightArrow|curvearrowright|vartriangleleft|NotLeftTriangle|nleftrightarrow|LowerRightArrow|NotHumpDownHump|NotGreaterTilde|rightthreetimes|LeftUpTeeVector|NotGreaterEqual|straightepsilon|LeftTriangleBar|rightsquigarrow|ContourIntegral|rightleftarrows|CloseCurlyQuote|RightDownVector|LeftRightVector|nLeftrightarrow|leftharpoondown|circlearrowleft|SquareSuperset|OpenCurlyQuote|hookrightarrow|HorizontalLine|DiacriticalDot|NotLessGreater|ntriangleright|DoubleRightTee|InvisibleComma|InvisibleTimes|LowerLeftArrow|DownLeftVector|NotSubsetEqual|curvearrowleft|trianglelefteq|NotVerticalBar|TildeFullEqual|downdownarrows|NotGreaterLess|RightTeeVector|ZeroWidthSpace|looparrowright|LongRightArrow|doublebarwedge|ShortLeftArrow|ShortDownArrow|RightVectorBar|GreaterGreater|ReverseElement|rightharpoonup|LessSlantEqual|leftthreetimes|upharpoonright|rightarrowtail|LeftDownVector|Longrightarrow|NestedLessLess|UpperLeftArrow|nshortparallel|leftleftarrows|leftrightarrow|Leftrightarrow|LeftRightArrow|longrightarrow|upharpoonleft|RightArrowBar|ApplyFunction|LeftTeeVector|leftarrowtail|NotEqualTilde|varsubsetneqq|varsupsetneqq|RightTeeArrow|SucceedsEqual|SucceedsTilde|LeftVectorBar|SupersetEqual|hookleftarrow|DifferentialD|VerticalTilde|VeryThinSpace|blacktriangle|bigtriangleup|LessFullEqual|divideontimes|leftharpoonup|UpEquilibrium|ntriangleleft|RightTriangle|measuredangle|shortparallel|longleftarrow|Longleftarrow|LongLeftArrow|DoubleLeftTee|Poincareplane|PrecedesEqual|triangleright|DoubleUpArrow|RightUpVector|fallingdotseq|looparrowleft|PrecedesTilde|NotTildeEqual|NotTildeTilde|smallsetminus|Proportional|triangleleft|triangledown|UnderBracket|NotHumpEqual|exponentiale|ExponentialE|NotLessTilde|HilbertSpace|RightCeiling|blacklozenge|varsupsetneq|HumpDownHump|GreaterEqual|VerticalLine|LeftTeeArrow|NotLessEqual|DownTeeArrow|LeftTriangle|varsubsetneq|Intersection|NotCongruent|DownArrowBar|LeftUpVector|LeftArrowBar|risingdotseq|GreaterTilde|RoundImplies|SquareSubset|ShortUpArrow|NotSuperset|quaternions|precnapprox|backepsilon|preccurlyeq|OverBracket|blacksquare|MediumSpace|VerticalBar|circledcirc|circleddash|CircleMinus|CircleTimes|LessGreater|curlyeqprec|curlyeqsucc|diamondsuit|UpDownArrow|Updownarrow|RuleDelayed|Rrightarrow|updownarrow|RightVector|nRightarrow|nrightarrow|eqslantless|LeftCeiling|Equilibrium|SmallCircle|expectation|NotSucceeds|thickapprox|GreaterLess|SquareUnion|NotPrecedes|NotLessLess|straightphi|succnapprox|succcurlyeq|SubsetEqual|sqsupseteq|Proportion|Laplacetrf|ImaginaryI|supsetneqq|NotGreater|gtreqqless|NotElement|ThickSpace|TildeEqual|TildeTilde|Fouriertrf|rmoustache|EqualTilde|eqslantgtr|UnderBrace|LeftVector|UpArrowBar|nLeftarrow|nsubseteqq|subsetneqq|nsupseteqq|nleftarrow|succapprox|lessapprox|UpTeeArrow|upuparrows|curlywedge|lesseqqgtr|varepsilon|varnothing|RightFloor|complement|CirclePlus|sqsubseteq|Lleftarrow|circledast|RightArrow|Rightarrow|rightarrow|lmoustache|Bernoullis|precapprox|mapstoleft|mapstodown|longmapsto|dotsquare|downarrow|DoubleDot|nsubseteq|supsetneq|leftarrow|nsupseteq|subsetneq|ThinSpace|ngeqslant|subseteqq|HumpEqual|NotSubset|triangleq|NotCupCap|lesseqgtr|heartsuit|TripleDot|Leftarrow|Coproduct|Congruent|varpropto|complexes|gvertneqq|LeftArrow|LessTilde|supseteqq|MinusPlus|CircleDot|nleqslant|NotExists|gtreqless|nparallel|UnionPlus|LeftFloor|checkmark|CenterDot|centerdot|Mellintrf|gtrapprox|bigotimes|OverBrace|spadesuit|therefore|pitchfork|rationals|PlusMinus|Backslash|Therefore|DownBreve|backsimeq|backprime|DownArrow|nshortmid|Downarrow|lvertneqq|eqvparsl|imagline|imagpart|infintie|integers|Integral|intercal|LessLess|Uarrocir|intlarhk|sqsupset|angmsdaf|sqsubset|llcorner|vartheta|cupbrcap|lnapprox|Superset|SuchThat|succnsim|succneqq|angmsdag|biguplus|curlyvee|trpezium|Succeeds|NotTilde|bigwedge|angmsdah|angrtvbd|triminus|cwconint|fpartint|lrcorner|smeparsl|subseteq|urcorner|lurdshar|laemptyv|DDotrahd|approxeq|ldrushar|awconint|mapstoup|backcong|shortmid|triangle|geqslant|gesdotol|timesbar|circledR|circledS|setminus|multimap|naturals|scpolint|ncongdot|RightTee|boxminus|gnapprox|boxtimes|andslope|thicksim|angmsdaa|varsigma|cirfnint|rtriltri|angmsdab|rppolint|angmsdac|barwedge|drbkarow|clubsuit|thetasym|bsolhsub|capbrcup|dzigrarr|doteqdot|DotEqual|dotminus|UnderBar|NotEqual|realpart|otimesas|ulcorner|hksearow|hkswarow|parallel|PartialD|elinters|emptyset|plusacir|bbrktbrk|angmsdad|pointint|bigoplus|angmsdae|Precedes|bigsqcup|varkappa|notindot|supseteq|precneqq|precnsim|profalar|profline|profsurf|leqslant|lesdotor|raemptyv|subplus|notnivb|notnivc|subrarr|zigrarr|vzigzag|submult|subedot|Element|between|cirscir|larrbfs|larrsim|lotimes|lbrksld|lbrkslu|lozenge|ldrdhar|dbkarow|bigcirc|epsilon|simrarr|simplus|ltquest|Epsilon|luruhar|gtquest|maltese|npolint|eqcolon|npreceq|bigodot|ddagger|gtrless|bnequiv|harrcir|ddotseq|equivDD|backsim|demptyv|nsqsube|nsqsupe|Upsilon|nsubset|upsilon|minusdu|nsucceq|swarrow|nsupset|coloneq|searrow|boxplus|napprox|natural|asympeq|alefsym|congdot|nearrow|bigstar|diamond|supplus|tritime|LeftTee|nvinfin|triplus|NewLine|nvltrie|nvrtrie|nwarrow|nexists|Diamond|ruluhar|Implies|supmult|angzarr|suplarr|suphsub|questeq|because|digamma|Because|olcross|bemptyv|omicron|Omicron|rotimes|NoBreak|intprod|angrtvb|orderof|uwangle|suphsol|lesdoto|orslope|DownTee|realine|cudarrl|rdldhar|OverBar|supedot|lessdot|supdsub|topfork|succsim|rbrkslu|rbrksld|pertenk|cudarrr|isindot|planckh|lessgtr|pluscir|gesdoto|plussim|plustwo|lesssim|cularrp|rarrsim|Cayleys|notinva|notinvb|notinvc|UpArrow|Uparrow|uparrow|NotLess|dwangle|precsim|Product|curarrm|Cconint|dotplus|rarrbfs|ccupssm|Cedilla|cemptyv|notniva|quatint|frac35|frac38|frac45|frac56|frac58|frac78|tridot|xoplus|gacute|gammad|Gammad|lfisht|lfloor|bigcup|sqsupe|gbreve|Gbreve|lharul|sqsube|sqcups|Gcedil|apacir|llhard|lmidot|Lmidot|lmoust|andand|sqcaps|approx|Abreve|spades|circeq|tprime|divide|topcir|Assign|topbot|gesdot|divonx|xuplus|timesd|gesles|atilde|solbar|SOFTcy|loplus|timesb|lowast|lowbar|dlcorn|dlcrop|softcy|dollar|lparlt|thksim|lrhard|Atilde|lsaquo|smashp|bigvee|thinsp|wreath|bkarow|lsquor|lstrok|Lstrok|lthree|ltimes|ltlarr|DotDot|simdot|ltrPar|weierp|xsqcup|angmsd|sigmav|sigmaf|zeetrf|Zcaron|zcaron|mapsto|vsupne|thetav|cirmid|marker|mcomma|Zacute|vsubnE|there4|gtlPar|vsubne|bottom|gtrarr|SHCHcy|shchcy|midast|midcir|middot|minusb|minusd|gtrdot|bowtie|sfrown|mnplus|models|colone|seswar|Colone|mstpos|searhk|gtrsim|nacute|Nacute|boxbox|telrec|hairsp|Tcedil|nbumpe|scnsim|ncaron|Ncaron|ncedil|Ncedil|hamilt|Scedil|nearhk|hardcy|HARDcy|tcedil|Tcaron|commat|nequiv|nesear|tcaron|target|hearts|nexist|varrho|scedil|Scaron|scaron|hellip|Sacute|sacute|hercon|swnwar|compfn|rtimes|rthree|rsquor|rsaquo|zacute|wedgeq|homtht|barvee|barwed|Barwed|rpargt|horbar|conint|swarhk|roplus|nltrie|hslash|hstrok|Hstrok|rmoust|Conint|bprime|hybull|hyphen|iacute|Iacute|supsup|supsub|supsim|varphi|coprod|brvbar|agrave|Supset|supset|igrave|Igrave|notinE|Agrave|iiiint|iinfin|copysr|wedbar|Verbar|vangrt|becaus|incare|verbar|inodot|bullet|drcorn|intcal|drcrop|cularr|vellip|Utilde|bumpeq|cupcap|dstrok|Dstrok|CupCap|cupcup|cupdot|eacute|Eacute|supdot|iquest|easter|ecaron|Ecaron|ecolon|isinsv|utilde|itilde|Itilde|curarr|succeq|Bumpeq|cacute|ulcrop|nparsl|Cacute|nprcue|egrave|Egrave|nrarrc|nrarrw|subsup|subsub|nrtrie|jsercy|nsccue|Jsercy|kappav|kcedil|Kcedil|subsim|ulcorn|nsimeq|egsdot|veebar|kgreen|capand|elsdot|Subset|subset|curren|aacute|lacute|Lacute|emptyv|ntilde|Ntilde|lagran|lambda|Lambda|capcap|Ugrave|langle|subdot|emsp13|numero|emsp14|nvdash|nvDash|nVdash|nVDash|ugrave|ufisht|nvHarr|larrfs|nvlArr|larrhk|larrlp|larrpl|nvrArr|Udblac|nwarhk|larrtl|nwnear|oacute|Oacute|latail|lAtail|sstarf|lbrace|odblac|Odblac|lbrack|udblac|odsold|eparsl|lcaron|Lcaron|ograve|Ograve|lcedil|Lcedil|Aacute|ssmile|ssetmn|squarf|ldquor|capcup|ominus|cylcty|rharul|eqcirc|dagger|rfloor|rfisht|Dagger|daleth|equals|origof|capdot|equest|dcaron|Dcaron|rdquor|oslash|Oslash|otilde|Otilde|otimes|Otimes|urcrop|Ubreve|ubreve|Yacute|Uacute|uacute|Rcedil|rcedil|urcorn|parsim|Rcaron|Vdashl|rcaron|Tstrok|percnt|period|permil|Exists|yacute|rbrack|rbrace|phmmat|ccaron|Ccaron|planck|ccedil|plankv|tstrok|female|plusdo|plusdu|ffilig|plusmn|ffllig|Ccedil|rAtail|dfisht|bernou|ratail|Rarrtl|rarrtl|angsph|rarrpl|rarrlp|rarrhk|xwedge|xotime|forall|ForAll|Vvdash|vsupnE|preceq|bigcap|frac12|frac13|frac14|primes|rarrfs|prnsim|frac15|Square|frac16|square|lesdot|frac18|frac23|propto|prurel|rarrap|rangle|puncsp|frac25|Racute|qprime|racute|lesges|frac34|abreve|AElig|eqsim|utdot|setmn|urtri|Equal|Uring|seArr|uring|searr|dashv|Dashv|mumap|nabla|iogon|Iogon|sdote|sdotb|scsim|napid|napos|equiv|natur|Acirc|dblac|erarr|nbump|iprod|erDot|ucirc|awint|esdot|angrt|ncong|isinE|scnap|Scirc|scirc|ndash|isins|Ubrcy|nearr|neArr|isinv|nedot|ubrcy|acute|Ycirc|iukcy|Iukcy|xutri|nesim|caret|jcirc|Jcirc|caron|twixt|ddarr|sccue|exist|jmath|sbquo|ngeqq|angst|ccaps|lceil|ngsim|UpTee|delta|Delta|rtrif|nharr|nhArr|nhpar|rtrie|jukcy|Jukcy|kappa|rsquo|Kappa|nlarr|nlArr|TSHcy|rrarr|aogon|Aogon|fflig|xrarr|tshcy|ccirc|nleqq|filig|upsih|nless|dharl|nlsim|fjlig|ropar|nltri|dharr|robrk|roarr|fllig|fltns|roang|rnmid|subnE|subne|lAarr|trisb|Ccirc|acirc|ccups|blank|VDash|forkv|Vdash|langd|cedil|blk12|blk14|laquo|strns|diams|notin|vDash|larrb|blk34|block|disin|uplus|vdash|vBarv|aelig|starf|Wedge|check|xrArr|lates|lbarr|lBarr|notni|lbbrk|bcong|frasl|lbrke|frown|vrtri|vprop|vnsup|gamma|Gamma|wedge|xodot|bdquo|srarr|doteq|ldquo|boxdl|boxdL|gcirc|Gcirc|boxDl|boxDL|boxdr|boxdR|boxDr|TRADE|trade|rlhar|boxDR|vnsub|npart|vltri|rlarr|boxhd|boxhD|nprec|gescc|nrarr|nrArr|boxHd|boxHD|boxhu|boxhU|nrtri|boxHu|clubs|boxHU|times|colon|Colon|gimel|xlArr|Tilde|nsime|tilde|nsmid|nspar|THORN|thorn|xlarr|nsube|nsubE|thkap|xhArr|comma|nsucc|boxul|boxuL|nsupe|nsupE|gneqq|gnsim|boxUl|boxUL|grave|boxur|boxuR|boxUr|boxUR|lescc|angle|bepsi|boxvh|varpi|boxvH|numsp|Theta|gsime|gsiml|theta|boxVh|boxVH|boxvl|gtcir|gtdot|boxvL|boxVl|boxVL|crarr|cross|Cross|nvsim|boxvr|nwarr|nwArr|sqsup|dtdot|Uogon|lhard|lharu|dtrif|ocirc|Ocirc|lhblk|duarr|odash|sqsub|Hacek|sqcup|llarr|duhar|oelig|OElig|ofcir|boxvR|uogon|lltri|boxVr|csube|uuarr|ohbar|csupe|ctdot|olarr|olcir|harrw|oline|sqcap|omacr|Omacr|omega|Omega|boxVR|aleph|lneqq|lnsim|loang|loarr|rharu|lobrk|hcirc|operp|oplus|rhard|Hcirc|orarr|Union|order|ecirc|Ecirc|cuepr|szlig|cuesc|breve|reals|eDDot|Breve|hoarr|lopar|utrif|rdquo|Umacr|umacr|efDot|swArr|ultri|alpha|rceil|ovbar|swarr|Wcirc|wcirc|smtes|smile|bsemi|lrarr|aring|parsl|lrhar|bsime|uhblk|lrtri|cupor|Aring|uharr|uharl|slarr|rbrke|bsolb|lsime|rbbrk|RBarr|lsimg|phone|rBarr|rbarr|icirc|lsquo|Icirc|emacr|Emacr|ratio|simne|plusb|simlE|simgE|simeq|pluse|ltcir|ltdot|empty|xharr|xdtri|iexcl|Alpha|ltrie|rarrw|pound|ltrif|xcirc|bumpe|prcue|bumpE|asymp|amacr|cuvee|Sigma|sigma|iiint|udhar|iiota|ijlig|IJlig|supnE|imacr|Imacr|prime|Prime|image|prnap|eogon|Eogon|rarrc|mdash|mDDot|cuwed|imath|supne|imped|Amacr|udarr|prsim|micro|rarrb|cwint|raquo|infin|eplus|range|rangd|Ucirc|radic|minus|amalg|veeeq|rAarr|epsiv|ycirc|quest|sharp|quot|zwnj|Qscr|race|qscr|Qopf|qopf|qint|rang|Rang|Zscr|zscr|Zopf|zopf|rarr|rArr|Rarr|Pscr|pscr|prop|prod|prnE|prec|ZHcy|zhcy|prap|Zeta|zeta|Popf|popf|Zdot|plus|zdot|Yuml|yuml|phiv|YUcy|yucy|Yscr|yscr|perp|Yopf|yopf|part|para|YIcy|Ouml|rcub|yicy|YAcy|rdca|ouml|osol|Oscr|rdsh|yacy|real|oscr|xvee|andd|rect|andv|Xscr|oror|ordm|ordf|xscr|ange|aopf|Aopf|rHar|Xopf|opar|Oopf|xopf|xnis|rhov|oopf|omid|xmap|oint|apid|apos|ogon|ascr|Ascr|odot|odiv|xcup|xcap|ocir|oast|nvlt|nvle|nvgt|nvge|nvap|Wscr|wscr|auml|ntlg|ntgl|nsup|nsub|nsim|Nscr|nscr|nsce|Wopf|ring|npre|wopf|npar|Auml|Barv|bbrk|Nopf|nopf|nmid|nLtv|beta|ropf|Ropf|Beta|beth|nles|rpar|nleq|bnot|bNot|nldr|NJcy|rscr|Rscr|Vscr|vscr|rsqb|njcy|bopf|nisd|Bopf|rtri|Vopf|nGtv|ngtr|vopf|boxh|boxH|boxv|nges|ngeq|boxV|bscr|scap|Bscr|bsim|Vert|vert|bsol|bull|bump|caps|cdot|ncup|scnE|ncap|nbsp|napE|Cdot|cent|sdot|Vbar|nang|vBar|chcy|Mscr|mscr|sect|semi|CHcy|Mopf|mopf|sext|circ|cire|mldr|mlcp|cirE|comp|shcy|SHcy|vArr|varr|cong|copf|Copf|copy|COPY|malt|male|macr|lvnE|cscr|ltri|sime|ltcc|simg|Cscr|siml|csub|Uuml|lsqb|lsim|uuml|csup|Lscr|lscr|utri|smid|lpar|cups|smte|lozf|darr|Lopf|Uscr|solb|lopf|sopf|Sopf|lneq|uscr|spar|dArr|lnap|Darr|dash|Sqrt|LJcy|ljcy|lHar|dHar|Upsi|upsi|diam|lesg|djcy|DJcy|leqq|dopf|Dopf|dscr|Dscr|dscy|ldsh|ldca|squf|DScy|sscr|Sscr|dsol|lcub|late|star|Star|Uopf|Larr|lArr|larr|uopf|dtri|dzcy|sube|subE|Lang|lang|Kscr|kscr|Kopf|kopf|KJcy|kjcy|KHcy|khcy|DZcy|ecir|edot|eDot|Jscr|jscr|succ|Jopf|jopf|Edot|uHar|emsp|ensp|Iuml|iuml|eopf|isin|Iscr|iscr|Eopf|epar|sung|epsi|escr|sup1|sup2|sup3|Iota|iota|supe|supE|Iopf|iopf|IOcy|iocy|Escr|esim|Esim|imof|Uarr|QUOT|uArr|uarr|euml|IEcy|iecy|Idot|Euml|euro|excl|Hscr|hscr|Hopf|hopf|TScy|tscy|Tscr|hbar|tscr|flat|tbrk|fnof|hArr|harr|half|fopf|Fopf|tdot|gvnE|fork|trie|gtcc|fscr|Fscr|gdot|gsim|Gscr|gscr|Gopf|gopf|gneq|Gdot|tosa|gnap|Topf|topf|geqq|toea|GJcy|gjcy|tint|gesl|mid|Sfr|ggg|top|ges|gla|glE|glj|geq|gne|gEl|gel|gnE|Gcy|gcy|gap|Tfr|tfr|Tcy|tcy|Hat|Tau|Ffr|tau|Tab|hfr|Hfr|ffr|Fcy|fcy|icy|Icy|iff|ETH|eth|ifr|Ifr|Eta|eta|int|Int|Sup|sup|ucy|Ucy|Sum|sum|jcy|ENG|ufr|Ufr|eng|Jcy|jfr|els|ell|egs|Efr|efr|Jfr|uml|kcy|Kcy|Ecy|ecy|kfr|Kfr|lap|Sub|sub|lat|lcy|Lcy|leg|Dot|dot|lEg|leq|les|squ|div|die|lfr|Lfr|lgE|Dfr|dfr|Del|deg|Dcy|dcy|lne|lnE|sol|loz|smt|Cup|lrm|cup|lsh|Lsh|sim|shy|map|Map|mcy|Mcy|mfr|Mfr|mho|gfr|Gfr|sfr|cir|Chi|chi|nap|Cfr|vcy|Vcy|cfr|Scy|scy|ncy|Ncy|vee|Vee|Cap|cap|nfr|scE|sce|Nfr|nge|ngE|nGg|vfr|Vfr|ngt|bot|nGt|nis|niv|Rsh|rsh|nle|nlE|bne|Bfr|bfr|nLl|nlt|nLt|Bcy|bcy|not|Not|rlm|wfr|Wfr|npr|nsc|num|ocy|ast|Ocy|ofr|xfr|Xfr|Ofr|ogt|ohm|apE|olt|Rho|ape|rho|Rfr|rfr|ord|REG|ang|reg|orv|And|and|AMP|Rcy|amp|Afr|ycy|Ycy|yen|yfr|Yfr|rcy|par|pcy|Pcy|pfr|Pfr|phi|Phi|afr|Acy|acy|zcy|Zcy|piv|acE|acd|zfr|Zfr|pre|prE|psi|Psi|qfr|Qfr|zwj|Or|ge|Gg|gt|gg|el|oS|lt|Lt|LT|Re|lg|gl|eg|ne|Im|it|le|DD|wp|wr|nu|Nu|dd|lE|Sc|sc|pi|Pi|ee|af|ll|Ll|rx|gE|xi|pm|Xi|ic|pr|Pr|in|ni|mp|mu|ac|Mu|or|ap|Gt|GT|ii);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)(?!;)([=a-zA-Z0-9]?)|&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g;\n\t    var decodeMap = {\n\t      'aacute': '\\xE1',\n\t      'Aacute': '\\xC1',\n\t      'abreve': \"\\u0103\",\n\t      'Abreve': \"\\u0102\",\n\t      'ac': \"\\u223E\",\n\t      'acd': \"\\u223F\",\n\t      'acE': \"\\u223E\\u0333\",\n\t      'acirc': '\\xE2',\n\t      'Acirc': '\\xC2',\n\t      'acute': '\\xB4',\n\t      'acy': \"\\u0430\",\n\t      'Acy': \"\\u0410\",\n\t      'aelig': '\\xE6',\n\t      'AElig': '\\xC6',\n\t      'af': \"\\u2061\",\n\t      'afr': \"\\uD835\\uDD1E\",\n\t      'Afr': \"\\uD835\\uDD04\",\n\t      'agrave': '\\xE0',\n\t      'Agrave': '\\xC0',\n\t      'alefsym': \"\\u2135\",\n\t      'aleph': \"\\u2135\",\n\t      'alpha': \"\\u03B1\",\n\t      'Alpha': \"\\u0391\",\n\t      'amacr': \"\\u0101\",\n\t      'Amacr': \"\\u0100\",\n\t      'amalg': \"\\u2A3F\",\n\t      'amp': '&',\n\t      'AMP': '&',\n\t      'and': \"\\u2227\",\n\t      'And': \"\\u2A53\",\n\t      'andand': \"\\u2A55\",\n\t      'andd': \"\\u2A5C\",\n\t      'andslope': \"\\u2A58\",\n\t      'andv': \"\\u2A5A\",\n\t      'ang': \"\\u2220\",\n\t      'ange': \"\\u29A4\",\n\t      'angle': \"\\u2220\",\n\t      'angmsd': \"\\u2221\",\n\t      'angmsdaa': \"\\u29A8\",\n\t      'angmsdab': \"\\u29A9\",\n\t      'angmsdac': \"\\u29AA\",\n\t      'angmsdad': \"\\u29AB\",\n\t      'angmsdae': \"\\u29AC\",\n\t      'angmsdaf': \"\\u29AD\",\n\t      'angmsdag': \"\\u29AE\",\n\t      'angmsdah': \"\\u29AF\",\n\t      'angrt': \"\\u221F\",\n\t      'angrtvb': \"\\u22BE\",\n\t      'angrtvbd': \"\\u299D\",\n\t      'angsph': \"\\u2222\",\n\t      'angst': '\\xC5',\n\t      'angzarr': \"\\u237C\",\n\t      'aogon': \"\\u0105\",\n\t      'Aogon': \"\\u0104\",\n\t      'aopf': \"\\uD835\\uDD52\",\n\t      'Aopf': \"\\uD835\\uDD38\",\n\t      'ap': \"\\u2248\",\n\t      'apacir': \"\\u2A6F\",\n\t      'ape': \"\\u224A\",\n\t      'apE': \"\\u2A70\",\n\t      'apid': \"\\u224B\",\n\t      'apos': '\\'',\n\t      'ApplyFunction': \"\\u2061\",\n\t      'approx': \"\\u2248\",\n\t      'approxeq': \"\\u224A\",\n\t      'aring': '\\xE5',\n\t      'Aring': '\\xC5',\n\t      'ascr': \"\\uD835\\uDCB6\",\n\t      'Ascr': \"\\uD835\\uDC9C\",\n\t      'Assign': \"\\u2254\",\n\t      'ast': '*',\n\t      'asymp': \"\\u2248\",\n\t      'asympeq': \"\\u224D\",\n\t      'atilde': '\\xE3',\n\t      'Atilde': '\\xC3',\n\t      'auml': '\\xE4',\n\t      'Auml': '\\xC4',\n\t      'awconint': \"\\u2233\",\n\t      'awint': \"\\u2A11\",\n\t      'backcong': \"\\u224C\",\n\t      'backepsilon': \"\\u03F6\",\n\t      'backprime': \"\\u2035\",\n\t      'backsim': \"\\u223D\",\n\t      'backsimeq': \"\\u22CD\",\n\t      'Backslash': \"\\u2216\",\n\t      'Barv': \"\\u2AE7\",\n\t      'barvee': \"\\u22BD\",\n\t      'barwed': \"\\u2305\",\n\t      'Barwed': \"\\u2306\",\n\t      'barwedge': \"\\u2305\",\n\t      'bbrk': \"\\u23B5\",\n\t      'bbrktbrk': \"\\u23B6\",\n\t      'bcong': \"\\u224C\",\n\t      'bcy': \"\\u0431\",\n\t      'Bcy': \"\\u0411\",\n\t      'bdquo': \"\\u201E\",\n\t      'becaus': \"\\u2235\",\n\t      'because': \"\\u2235\",\n\t      'Because': \"\\u2235\",\n\t      'bemptyv': \"\\u29B0\",\n\t      'bepsi': \"\\u03F6\",\n\t      'bernou': \"\\u212C\",\n\t      'Bernoullis': \"\\u212C\",\n\t      'beta': \"\\u03B2\",\n\t      'Beta': \"\\u0392\",\n\t      'beth': \"\\u2136\",\n\t      'between': \"\\u226C\",\n\t      'bfr': \"\\uD835\\uDD1F\",\n\t      'Bfr': \"\\uD835\\uDD05\",\n\t      'bigcap': \"\\u22C2\",\n\t      'bigcirc': \"\\u25EF\",\n\t      'bigcup': \"\\u22C3\",\n\t      'bigodot': \"\\u2A00\",\n\t      'bigoplus': \"\\u2A01\",\n\t      'bigotimes': \"\\u2A02\",\n\t      'bigsqcup': \"\\u2A06\",\n\t      'bigstar': \"\\u2605\",\n\t      'bigtriangledown': \"\\u25BD\",\n\t      'bigtriangleup': \"\\u25B3\",\n\t      'biguplus': \"\\u2A04\",\n\t      'bigvee': \"\\u22C1\",\n\t      'bigwedge': \"\\u22C0\",\n\t      'bkarow': \"\\u290D\",\n\t      'blacklozenge': \"\\u29EB\",\n\t      'blacksquare': \"\\u25AA\",\n\t      'blacktriangle': \"\\u25B4\",\n\t      'blacktriangledown': \"\\u25BE\",\n\t      'blacktriangleleft': \"\\u25C2\",\n\t      'blacktriangleright': \"\\u25B8\",\n\t      'blank': \"\\u2423\",\n\t      'blk12': \"\\u2592\",\n\t      'blk14': \"\\u2591\",\n\t      'blk34': \"\\u2593\",\n\t      'block': \"\\u2588\",\n\t      'bne': \"=\\u20E5\",\n\t      'bnequiv': \"\\u2261\\u20E5\",\n\t      'bnot': \"\\u2310\",\n\t      'bNot': \"\\u2AED\",\n\t      'bopf': \"\\uD835\\uDD53\",\n\t      'Bopf': \"\\uD835\\uDD39\",\n\t      'bot': \"\\u22A5\",\n\t      'bottom': \"\\u22A5\",\n\t      'bowtie': \"\\u22C8\",\n\t      'boxbox': \"\\u29C9\",\n\t      'boxdl': \"\\u2510\",\n\t      'boxdL': \"\\u2555\",\n\t      'boxDl': \"\\u2556\",\n\t      'boxDL': \"\\u2557\",\n\t      'boxdr': \"\\u250C\",\n\t      'boxdR': \"\\u2552\",\n\t      'boxDr': \"\\u2553\",\n\t      'boxDR': \"\\u2554\",\n\t      'boxh': \"\\u2500\",\n\t      'boxH': \"\\u2550\",\n\t      'boxhd': \"\\u252C\",\n\t      'boxhD': \"\\u2565\",\n\t      'boxHd': \"\\u2564\",\n\t      'boxHD': \"\\u2566\",\n\t      'boxhu': \"\\u2534\",\n\t      'boxhU': \"\\u2568\",\n\t      'boxHu': \"\\u2567\",\n\t      'boxHU': \"\\u2569\",\n\t      'boxminus': \"\\u229F\",\n\t      'boxplus': \"\\u229E\",\n\t      'boxtimes': \"\\u22A0\",\n\t      'boxul': \"\\u2518\",\n\t      'boxuL': \"\\u255B\",\n\t      'boxUl': \"\\u255C\",\n\t      'boxUL': \"\\u255D\",\n\t      'boxur': \"\\u2514\",\n\t      'boxuR': \"\\u2558\",\n\t      'boxUr': \"\\u2559\",\n\t      'boxUR': \"\\u255A\",\n\t      'boxv': \"\\u2502\",\n\t      'boxV': \"\\u2551\",\n\t      'boxvh': \"\\u253C\",\n\t      'boxvH': \"\\u256A\",\n\t      'boxVh': \"\\u256B\",\n\t      'boxVH': \"\\u256C\",\n\t      'boxvl': \"\\u2524\",\n\t      'boxvL': \"\\u2561\",\n\t      'boxVl': \"\\u2562\",\n\t      'boxVL': \"\\u2563\",\n\t      'boxvr': \"\\u251C\",\n\t      'boxvR': \"\\u255E\",\n\t      'boxVr': \"\\u255F\",\n\t      'boxVR': \"\\u2560\",\n\t      'bprime': \"\\u2035\",\n\t      'breve': \"\\u02D8\",\n\t      'Breve': \"\\u02D8\",\n\t      'brvbar': '\\xA6',\n\t      'bscr': \"\\uD835\\uDCB7\",\n\t      'Bscr': \"\\u212C\",\n\t      'bsemi': \"\\u204F\",\n\t      'bsim': \"\\u223D\",\n\t      'bsime': \"\\u22CD\",\n\t      'bsol': '\\\\',\n\t      'bsolb': \"\\u29C5\",\n\t      'bsolhsub': \"\\u27C8\",\n\t      'bull': \"\\u2022\",\n\t      'bullet': \"\\u2022\",\n\t      'bump': \"\\u224E\",\n\t      'bumpe': \"\\u224F\",\n\t      'bumpE': \"\\u2AAE\",\n\t      'bumpeq': \"\\u224F\",\n\t      'Bumpeq': \"\\u224E\",\n\t      'cacute': \"\\u0107\",\n\t      'Cacute': \"\\u0106\",\n\t      'cap': \"\\u2229\",\n\t      'Cap': \"\\u22D2\",\n\t      'capand': \"\\u2A44\",\n\t      'capbrcup': \"\\u2A49\",\n\t      'capcap': \"\\u2A4B\",\n\t      'capcup': \"\\u2A47\",\n\t      'capdot': \"\\u2A40\",\n\t      'CapitalDifferentialD': \"\\u2145\",\n\t      'caps': \"\\u2229\\uFE00\",\n\t      'caret': \"\\u2041\",\n\t      'caron': \"\\u02C7\",\n\t      'Cayleys': \"\\u212D\",\n\t      'ccaps': \"\\u2A4D\",\n\t      'ccaron': \"\\u010D\",\n\t      'Ccaron': \"\\u010C\",\n\t      'ccedil': '\\xE7',\n\t      'Ccedil': '\\xC7',\n\t      'ccirc': \"\\u0109\",\n\t      'Ccirc': \"\\u0108\",\n\t      'Cconint': \"\\u2230\",\n\t      'ccups': \"\\u2A4C\",\n\t      'ccupssm': \"\\u2A50\",\n\t      'cdot': \"\\u010B\",\n\t      'Cdot': \"\\u010A\",\n\t      'cedil': '\\xB8',\n\t      'Cedilla': '\\xB8',\n\t      'cemptyv': \"\\u29B2\",\n\t      'cent': '\\xA2',\n\t      'centerdot': '\\xB7',\n\t      'CenterDot': '\\xB7',\n\t      'cfr': \"\\uD835\\uDD20\",\n\t      'Cfr': \"\\u212D\",\n\t      'chcy': \"\\u0447\",\n\t      'CHcy': \"\\u0427\",\n\t      'check': \"\\u2713\",\n\t      'checkmark': \"\\u2713\",\n\t      'chi': \"\\u03C7\",\n\t      'Chi': \"\\u03A7\",\n\t      'cir': \"\\u25CB\",\n\t      'circ': \"\\u02C6\",\n\t      'circeq': \"\\u2257\",\n\t      'circlearrowleft': \"\\u21BA\",\n\t      'circlearrowright': \"\\u21BB\",\n\t      'circledast': \"\\u229B\",\n\t      'circledcirc': \"\\u229A\",\n\t      'circleddash': \"\\u229D\",\n\t      'CircleDot': \"\\u2299\",\n\t      'circledR': '\\xAE',\n\t      'circledS': \"\\u24C8\",\n\t      'CircleMinus': \"\\u2296\",\n\t      'CirclePlus': \"\\u2295\",\n\t      'CircleTimes': \"\\u2297\",\n\t      'cire': \"\\u2257\",\n\t      'cirE': \"\\u29C3\",\n\t      'cirfnint': \"\\u2A10\",\n\t      'cirmid': \"\\u2AEF\",\n\t      'cirscir': \"\\u29C2\",\n\t      'ClockwiseContourIntegral': \"\\u2232\",\n\t      'CloseCurlyDoubleQuote': \"\\u201D\",\n\t      'CloseCurlyQuote': \"\\u2019\",\n\t      'clubs': \"\\u2663\",\n\t      'clubsuit': \"\\u2663\",\n\t      'colon': ':',\n\t      'Colon': \"\\u2237\",\n\t      'colone': \"\\u2254\",\n\t      'Colone': \"\\u2A74\",\n\t      'coloneq': \"\\u2254\",\n\t      'comma': ',',\n\t      'commat': '@',\n\t      'comp': \"\\u2201\",\n\t      'compfn': \"\\u2218\",\n\t      'complement': \"\\u2201\",\n\t      'complexes': \"\\u2102\",\n\t      'cong': \"\\u2245\",\n\t      'congdot': \"\\u2A6D\",\n\t      'Congruent': \"\\u2261\",\n\t      'conint': \"\\u222E\",\n\t      'Conint': \"\\u222F\",\n\t      'ContourIntegral': \"\\u222E\",\n\t      'copf': \"\\uD835\\uDD54\",\n\t      'Copf': \"\\u2102\",\n\t      'coprod': \"\\u2210\",\n\t      'Coproduct': \"\\u2210\",\n\t      'copy': '\\xA9',\n\t      'COPY': '\\xA9',\n\t      'copysr': \"\\u2117\",\n\t      'CounterClockwiseContourIntegral': \"\\u2233\",\n\t      'crarr': \"\\u21B5\",\n\t      'cross': \"\\u2717\",\n\t      'Cross': \"\\u2A2F\",\n\t      'cscr': \"\\uD835\\uDCB8\",\n\t      'Cscr': \"\\uD835\\uDC9E\",\n\t      'csub': \"\\u2ACF\",\n\t      'csube': \"\\u2AD1\",\n\t      'csup': \"\\u2AD0\",\n\t      'csupe': \"\\u2AD2\",\n\t      'ctdot': \"\\u22EF\",\n\t      'cudarrl': \"\\u2938\",\n\t      'cudarrr': \"\\u2935\",\n\t      'cuepr': \"\\u22DE\",\n\t      'cuesc': \"\\u22DF\",\n\t      'cularr': \"\\u21B6\",\n\t      'cularrp': \"\\u293D\",\n\t      'cup': \"\\u222A\",\n\t      'Cup': \"\\u22D3\",\n\t      'cupbrcap': \"\\u2A48\",\n\t      'cupcap': \"\\u2A46\",\n\t      'CupCap': \"\\u224D\",\n\t      'cupcup': \"\\u2A4A\",\n\t      'cupdot': \"\\u228D\",\n\t      'cupor': \"\\u2A45\",\n\t      'cups': \"\\u222A\\uFE00\",\n\t      'curarr': \"\\u21B7\",\n\t      'curarrm': \"\\u293C\",\n\t      'curlyeqprec': \"\\u22DE\",\n\t      'curlyeqsucc': \"\\u22DF\",\n\t      'curlyvee': \"\\u22CE\",\n\t      'curlywedge': \"\\u22CF\",\n\t      'curren': '\\xA4',\n\t      'curvearrowleft': \"\\u21B6\",\n\t      'curvearrowright': \"\\u21B7\",\n\t      'cuvee': \"\\u22CE\",\n\t      'cuwed': \"\\u22CF\",\n\t      'cwconint': \"\\u2232\",\n\t      'cwint': \"\\u2231\",\n\t      'cylcty': \"\\u232D\",\n\t      'dagger': \"\\u2020\",\n\t      'Dagger': \"\\u2021\",\n\t      'daleth': \"\\u2138\",\n\t      'darr': \"\\u2193\",\n\t      'dArr': \"\\u21D3\",\n\t      'Darr': \"\\u21A1\",\n\t      'dash': \"\\u2010\",\n\t      'dashv': \"\\u22A3\",\n\t      'Dashv': \"\\u2AE4\",\n\t      'dbkarow': \"\\u290F\",\n\t      'dblac': \"\\u02DD\",\n\t      'dcaron': \"\\u010F\",\n\t      'Dcaron': \"\\u010E\",\n\t      'dcy': \"\\u0434\",\n\t      'Dcy': \"\\u0414\",\n\t      'dd': \"\\u2146\",\n\t      'DD': \"\\u2145\",\n\t      'ddagger': \"\\u2021\",\n\t      'ddarr': \"\\u21CA\",\n\t      'DDotrahd': \"\\u2911\",\n\t      'ddotseq': \"\\u2A77\",\n\t      'deg': '\\xB0',\n\t      'Del': \"\\u2207\",\n\t      'delta': \"\\u03B4\",\n\t      'Delta': \"\\u0394\",\n\t      'demptyv': \"\\u29B1\",\n\t      'dfisht': \"\\u297F\",\n\t      'dfr': \"\\uD835\\uDD21\",\n\t      'Dfr': \"\\uD835\\uDD07\",\n\t      'dHar': \"\\u2965\",\n\t      'dharl': \"\\u21C3\",\n\t      'dharr': \"\\u21C2\",\n\t      'DiacriticalAcute': '\\xB4',\n\t      'DiacriticalDot': \"\\u02D9\",\n\t      'DiacriticalDoubleAcute': \"\\u02DD\",\n\t      'DiacriticalGrave': '`',\n\t      'DiacriticalTilde': \"\\u02DC\",\n\t      'diam': \"\\u22C4\",\n\t      'diamond': \"\\u22C4\",\n\t      'Diamond': \"\\u22C4\",\n\t      'diamondsuit': \"\\u2666\",\n\t      'diams': \"\\u2666\",\n\t      'die': '\\xA8',\n\t      'DifferentialD': \"\\u2146\",\n\t      'digamma': \"\\u03DD\",\n\t      'disin': \"\\u22F2\",\n\t      'div': '\\xF7',\n\t      'divide': '\\xF7',\n\t      'divideontimes': \"\\u22C7\",\n\t      'divonx': \"\\u22C7\",\n\t      'djcy': \"\\u0452\",\n\t      'DJcy': \"\\u0402\",\n\t      'dlcorn': \"\\u231E\",\n\t      'dlcrop': \"\\u230D\",\n\t      'dollar': '$',\n\t      'dopf': \"\\uD835\\uDD55\",\n\t      'Dopf': \"\\uD835\\uDD3B\",\n\t      'dot': \"\\u02D9\",\n\t      'Dot': '\\xA8',\n\t      'DotDot': \"\\u20DC\",\n\t      'doteq': \"\\u2250\",\n\t      'doteqdot': \"\\u2251\",\n\t      'DotEqual': \"\\u2250\",\n\t      'dotminus': \"\\u2238\",\n\t      'dotplus': \"\\u2214\",\n\t      'dotsquare': \"\\u22A1\",\n\t      'doublebarwedge': \"\\u2306\",\n\t      'DoubleContourIntegral': \"\\u222F\",\n\t      'DoubleDot': '\\xA8',\n\t      'DoubleDownArrow': \"\\u21D3\",\n\t      'DoubleLeftArrow': \"\\u21D0\",\n\t      'DoubleLeftRightArrow': \"\\u21D4\",\n\t      'DoubleLeftTee': \"\\u2AE4\",\n\t      'DoubleLongLeftArrow': \"\\u27F8\",\n\t      'DoubleLongLeftRightArrow': \"\\u27FA\",\n\t      'DoubleLongRightArrow': \"\\u27F9\",\n\t      'DoubleRightArrow': \"\\u21D2\",\n\t      'DoubleRightTee': \"\\u22A8\",\n\t      'DoubleUpArrow': \"\\u21D1\",\n\t      'DoubleUpDownArrow': \"\\u21D5\",\n\t      'DoubleVerticalBar': \"\\u2225\",\n\t      'downarrow': \"\\u2193\",\n\t      'Downarrow': \"\\u21D3\",\n\t      'DownArrow': \"\\u2193\",\n\t      'DownArrowBar': \"\\u2913\",\n\t      'DownArrowUpArrow': \"\\u21F5\",\n\t      'DownBreve': \"\\u0311\",\n\t      'downdownarrows': \"\\u21CA\",\n\t      'downharpoonleft': \"\\u21C3\",\n\t      'downharpoonright': \"\\u21C2\",\n\t      'DownLeftRightVector': \"\\u2950\",\n\t      'DownLeftTeeVector': \"\\u295E\",\n\t      'DownLeftVector': \"\\u21BD\",\n\t      'DownLeftVectorBar': \"\\u2956\",\n\t      'DownRightTeeVector': \"\\u295F\",\n\t      'DownRightVector': \"\\u21C1\",\n\t      'DownRightVectorBar': \"\\u2957\",\n\t      'DownTee': \"\\u22A4\",\n\t      'DownTeeArrow': \"\\u21A7\",\n\t      'drbkarow': \"\\u2910\",\n\t      'drcorn': \"\\u231F\",\n\t      'drcrop': \"\\u230C\",\n\t      'dscr': \"\\uD835\\uDCB9\",\n\t      'Dscr': \"\\uD835\\uDC9F\",\n\t      'dscy': \"\\u0455\",\n\t      'DScy': \"\\u0405\",\n\t      'dsol': \"\\u29F6\",\n\t      'dstrok': \"\\u0111\",\n\t      'Dstrok': \"\\u0110\",\n\t      'dtdot': \"\\u22F1\",\n\t      'dtri': \"\\u25BF\",\n\t      'dtrif': \"\\u25BE\",\n\t      'duarr': \"\\u21F5\",\n\t      'duhar': \"\\u296F\",\n\t      'dwangle': \"\\u29A6\",\n\t      'dzcy': \"\\u045F\",\n\t      'DZcy': \"\\u040F\",\n\t      'dzigrarr': \"\\u27FF\",\n\t      'eacute': '\\xE9',\n\t      'Eacute': '\\xC9',\n\t      'easter': \"\\u2A6E\",\n\t      'ecaron': \"\\u011B\",\n\t      'Ecaron': \"\\u011A\",\n\t      'ecir': \"\\u2256\",\n\t      'ecirc': '\\xEA',\n\t      'Ecirc': '\\xCA',\n\t      'ecolon': \"\\u2255\",\n\t      'ecy': \"\\u044D\",\n\t      'Ecy': \"\\u042D\",\n\t      'eDDot': \"\\u2A77\",\n\t      'edot': \"\\u0117\",\n\t      'eDot': \"\\u2251\",\n\t      'Edot': \"\\u0116\",\n\t      'ee': \"\\u2147\",\n\t      'efDot': \"\\u2252\",\n\t      'efr': \"\\uD835\\uDD22\",\n\t      'Efr': \"\\uD835\\uDD08\",\n\t      'eg': \"\\u2A9A\",\n\t      'egrave': '\\xE8',\n\t      'Egrave': '\\xC8',\n\t      'egs': \"\\u2A96\",\n\t      'egsdot': \"\\u2A98\",\n\t      'el': \"\\u2A99\",\n\t      'Element': \"\\u2208\",\n\t      'elinters': \"\\u23E7\",\n\t      'ell': \"\\u2113\",\n\t      'els': \"\\u2A95\",\n\t      'elsdot': \"\\u2A97\",\n\t      'emacr': \"\\u0113\",\n\t      'Emacr': \"\\u0112\",\n\t      'empty': \"\\u2205\",\n\t      'emptyset': \"\\u2205\",\n\t      'EmptySmallSquare': \"\\u25FB\",\n\t      'emptyv': \"\\u2205\",\n\t      'EmptyVerySmallSquare': \"\\u25AB\",\n\t      'emsp': \"\\u2003\",\n\t      'emsp13': \"\\u2004\",\n\t      'emsp14': \"\\u2005\",\n\t      'eng': \"\\u014B\",\n\t      'ENG': \"\\u014A\",\n\t      'ensp': \"\\u2002\",\n\t      'eogon': \"\\u0119\",\n\t      'Eogon': \"\\u0118\",\n\t      'eopf': \"\\uD835\\uDD56\",\n\t      'Eopf': \"\\uD835\\uDD3C\",\n\t      'epar': \"\\u22D5\",\n\t      'eparsl': \"\\u29E3\",\n\t      'eplus': \"\\u2A71\",\n\t      'epsi': \"\\u03B5\",\n\t      'epsilon': \"\\u03B5\",\n\t      'Epsilon': \"\\u0395\",\n\t      'epsiv': \"\\u03F5\",\n\t      'eqcirc': \"\\u2256\",\n\t      'eqcolon': \"\\u2255\",\n\t      'eqsim': \"\\u2242\",\n\t      'eqslantgtr': \"\\u2A96\",\n\t      'eqslantless': \"\\u2A95\",\n\t      'Equal': \"\\u2A75\",\n\t      'equals': '=',\n\t      'EqualTilde': \"\\u2242\",\n\t      'equest': \"\\u225F\",\n\t      'Equilibrium': \"\\u21CC\",\n\t      'equiv': \"\\u2261\",\n\t      'equivDD': \"\\u2A78\",\n\t      'eqvparsl': \"\\u29E5\",\n\t      'erarr': \"\\u2971\",\n\t      'erDot': \"\\u2253\",\n\t      'escr': \"\\u212F\",\n\t      'Escr': \"\\u2130\",\n\t      'esdot': \"\\u2250\",\n\t      'esim': \"\\u2242\",\n\t      'Esim': \"\\u2A73\",\n\t      'eta': \"\\u03B7\",\n\t      'Eta': \"\\u0397\",\n\t      'eth': '\\xF0',\n\t      'ETH': '\\xD0',\n\t      'euml': '\\xEB',\n\t      'Euml': '\\xCB',\n\t      'euro': \"\\u20AC\",\n\t      'excl': '!',\n\t      'exist': \"\\u2203\",\n\t      'Exists': \"\\u2203\",\n\t      'expectation': \"\\u2130\",\n\t      'exponentiale': \"\\u2147\",\n\t      'ExponentialE': \"\\u2147\",\n\t      'fallingdotseq': \"\\u2252\",\n\t      'fcy': \"\\u0444\",\n\t      'Fcy': \"\\u0424\",\n\t      'female': \"\\u2640\",\n\t      'ffilig': \"\\uFB03\",\n\t      'fflig': \"\\uFB00\",\n\t      'ffllig': \"\\uFB04\",\n\t      'ffr': \"\\uD835\\uDD23\",\n\t      'Ffr': \"\\uD835\\uDD09\",\n\t      'filig': \"\\uFB01\",\n\t      'FilledSmallSquare': \"\\u25FC\",\n\t      'FilledVerySmallSquare': \"\\u25AA\",\n\t      'fjlig': 'fj',\n\t      'flat': \"\\u266D\",\n\t      'fllig': \"\\uFB02\",\n\t      'fltns': \"\\u25B1\",\n\t      'fnof': \"\\u0192\",\n\t      'fopf': \"\\uD835\\uDD57\",\n\t      'Fopf': \"\\uD835\\uDD3D\",\n\t      'forall': \"\\u2200\",\n\t      'ForAll': \"\\u2200\",\n\t      'fork': \"\\u22D4\",\n\t      'forkv': \"\\u2AD9\",\n\t      'Fouriertrf': \"\\u2131\",\n\t      'fpartint': \"\\u2A0D\",\n\t      'frac12': '\\xBD',\n\t      'frac13': \"\\u2153\",\n\t      'frac14': '\\xBC',\n\t      'frac15': \"\\u2155\",\n\t      'frac16': \"\\u2159\",\n\t      'frac18': \"\\u215B\",\n\t      'frac23': \"\\u2154\",\n\t      'frac25': \"\\u2156\",\n\t      'frac34': '\\xBE',\n\t      'frac35': \"\\u2157\",\n\t      'frac38': \"\\u215C\",\n\t      'frac45': \"\\u2158\",\n\t      'frac56': \"\\u215A\",\n\t      'frac58': \"\\u215D\",\n\t      'frac78': \"\\u215E\",\n\t      'frasl': \"\\u2044\",\n\t      'frown': \"\\u2322\",\n\t      'fscr': \"\\uD835\\uDCBB\",\n\t      'Fscr': \"\\u2131\",\n\t      'gacute': \"\\u01F5\",\n\t      'gamma': \"\\u03B3\",\n\t      'Gamma': \"\\u0393\",\n\t      'gammad': \"\\u03DD\",\n\t      'Gammad': \"\\u03DC\",\n\t      'gap': \"\\u2A86\",\n\t      'gbreve': \"\\u011F\",\n\t      'Gbreve': \"\\u011E\",\n\t      'Gcedil': \"\\u0122\",\n\t      'gcirc': \"\\u011D\",\n\t      'Gcirc': \"\\u011C\",\n\t      'gcy': \"\\u0433\",\n\t      'Gcy': \"\\u0413\",\n\t      'gdot': \"\\u0121\",\n\t      'Gdot': \"\\u0120\",\n\t      'ge': \"\\u2265\",\n\t      'gE': \"\\u2267\",\n\t      'gel': \"\\u22DB\",\n\t      'gEl': \"\\u2A8C\",\n\t      'geq': \"\\u2265\",\n\t      'geqq': \"\\u2267\",\n\t      'geqslant': \"\\u2A7E\",\n\t      'ges': \"\\u2A7E\",\n\t      'gescc': \"\\u2AA9\",\n\t      'gesdot': \"\\u2A80\",\n\t      'gesdoto': \"\\u2A82\",\n\t      'gesdotol': \"\\u2A84\",\n\t      'gesl': \"\\u22DB\\uFE00\",\n\t      'gesles': \"\\u2A94\",\n\t      'gfr': \"\\uD835\\uDD24\",\n\t      'Gfr': \"\\uD835\\uDD0A\",\n\t      'gg': \"\\u226B\",\n\t      'Gg': \"\\u22D9\",\n\t      'ggg': \"\\u22D9\",\n\t      'gimel': \"\\u2137\",\n\t      'gjcy': \"\\u0453\",\n\t      'GJcy': \"\\u0403\",\n\t      'gl': \"\\u2277\",\n\t      'gla': \"\\u2AA5\",\n\t      'glE': \"\\u2A92\",\n\t      'glj': \"\\u2AA4\",\n\t      'gnap': \"\\u2A8A\",\n\t      'gnapprox': \"\\u2A8A\",\n\t      'gne': \"\\u2A88\",\n\t      'gnE': \"\\u2269\",\n\t      'gneq': \"\\u2A88\",\n\t      'gneqq': \"\\u2269\",\n\t      'gnsim': \"\\u22E7\",\n\t      'gopf': \"\\uD835\\uDD58\",\n\t      'Gopf': \"\\uD835\\uDD3E\",\n\t      'grave': '`',\n\t      'GreaterEqual': \"\\u2265\",\n\t      'GreaterEqualLess': \"\\u22DB\",\n\t      'GreaterFullEqual': \"\\u2267\",\n\t      'GreaterGreater': \"\\u2AA2\",\n\t      'GreaterLess': \"\\u2277\",\n\t      'GreaterSlantEqual': \"\\u2A7E\",\n\t      'GreaterTilde': \"\\u2273\",\n\t      'gscr': \"\\u210A\",\n\t      'Gscr': \"\\uD835\\uDCA2\",\n\t      'gsim': \"\\u2273\",\n\t      'gsime': \"\\u2A8E\",\n\t      'gsiml': \"\\u2A90\",\n\t      'gt': '>',\n\t      'Gt': \"\\u226B\",\n\t      'GT': '>',\n\t      'gtcc': \"\\u2AA7\",\n\t      'gtcir': \"\\u2A7A\",\n\t      'gtdot': \"\\u22D7\",\n\t      'gtlPar': \"\\u2995\",\n\t      'gtquest': \"\\u2A7C\",\n\t      'gtrapprox': \"\\u2A86\",\n\t      'gtrarr': \"\\u2978\",\n\t      'gtrdot': \"\\u22D7\",\n\t      'gtreqless': \"\\u22DB\",\n\t      'gtreqqless': \"\\u2A8C\",\n\t      'gtrless': \"\\u2277\",\n\t      'gtrsim': \"\\u2273\",\n\t      'gvertneqq': \"\\u2269\\uFE00\",\n\t      'gvnE': \"\\u2269\\uFE00\",\n\t      'Hacek': \"\\u02C7\",\n\t      'hairsp': \"\\u200A\",\n\t      'half': '\\xBD',\n\t      'hamilt': \"\\u210B\",\n\t      'hardcy': \"\\u044A\",\n\t      'HARDcy': \"\\u042A\",\n\t      'harr': \"\\u2194\",\n\t      'hArr': \"\\u21D4\",\n\t      'harrcir': \"\\u2948\",\n\t      'harrw': \"\\u21AD\",\n\t      'Hat': '^',\n\t      'hbar': \"\\u210F\",\n\t      'hcirc': \"\\u0125\",\n\t      'Hcirc': \"\\u0124\",\n\t      'hearts': \"\\u2665\",\n\t      'heartsuit': \"\\u2665\",\n\t      'hellip': \"\\u2026\",\n\t      'hercon': \"\\u22B9\",\n\t      'hfr': \"\\uD835\\uDD25\",\n\t      'Hfr': \"\\u210C\",\n\t      'HilbertSpace': \"\\u210B\",\n\t      'hksearow': \"\\u2925\",\n\t      'hkswarow': \"\\u2926\",\n\t      'hoarr': \"\\u21FF\",\n\t      'homtht': \"\\u223B\",\n\t      'hookleftarrow': \"\\u21A9\",\n\t      'hookrightarrow': \"\\u21AA\",\n\t      'hopf': \"\\uD835\\uDD59\",\n\t      'Hopf': \"\\u210D\",\n\t      'horbar': \"\\u2015\",\n\t      'HorizontalLine': \"\\u2500\",\n\t      'hscr': \"\\uD835\\uDCBD\",\n\t      'Hscr': \"\\u210B\",\n\t      'hslash': \"\\u210F\",\n\t      'hstrok': \"\\u0127\",\n\t      'Hstrok': \"\\u0126\",\n\t      'HumpDownHump': \"\\u224E\",\n\t      'HumpEqual': \"\\u224F\",\n\t      'hybull': \"\\u2043\",\n\t      'hyphen': \"\\u2010\",\n\t      'iacute': '\\xED',\n\t      'Iacute': '\\xCD',\n\t      'ic': \"\\u2063\",\n\t      'icirc': '\\xEE',\n\t      'Icirc': '\\xCE',\n\t      'icy': \"\\u0438\",\n\t      'Icy': \"\\u0418\",\n\t      'Idot': \"\\u0130\",\n\t      'iecy': \"\\u0435\",\n\t      'IEcy': \"\\u0415\",\n\t      'iexcl': '\\xA1',\n\t      'iff': \"\\u21D4\",\n\t      'ifr': \"\\uD835\\uDD26\",\n\t      'Ifr': \"\\u2111\",\n\t      'igrave': '\\xEC',\n\t      'Igrave': '\\xCC',\n\t      'ii': \"\\u2148\",\n\t      'iiiint': \"\\u2A0C\",\n\t      'iiint': \"\\u222D\",\n\t      'iinfin': \"\\u29DC\",\n\t      'iiota': \"\\u2129\",\n\t      'ijlig': \"\\u0133\",\n\t      'IJlig': \"\\u0132\",\n\t      'Im': \"\\u2111\",\n\t      'imacr': \"\\u012B\",\n\t      'Imacr': \"\\u012A\",\n\t      'image': \"\\u2111\",\n\t      'ImaginaryI': \"\\u2148\",\n\t      'imagline': \"\\u2110\",\n\t      'imagpart': \"\\u2111\",\n\t      'imath': \"\\u0131\",\n\t      'imof': \"\\u22B7\",\n\t      'imped': \"\\u01B5\",\n\t      'Implies': \"\\u21D2\",\n\t      'in': \"\\u2208\",\n\t      'incare': \"\\u2105\",\n\t      'infin': \"\\u221E\",\n\t      'infintie': \"\\u29DD\",\n\t      'inodot': \"\\u0131\",\n\t      'int': \"\\u222B\",\n\t      'Int': \"\\u222C\",\n\t      'intcal': \"\\u22BA\",\n\t      'integers': \"\\u2124\",\n\t      'Integral': \"\\u222B\",\n\t      'intercal': \"\\u22BA\",\n\t      'Intersection': \"\\u22C2\",\n\t      'intlarhk': \"\\u2A17\",\n\t      'intprod': \"\\u2A3C\",\n\t      'InvisibleComma': \"\\u2063\",\n\t      'InvisibleTimes': \"\\u2062\",\n\t      'iocy': \"\\u0451\",\n\t      'IOcy': \"\\u0401\",\n\t      'iogon': \"\\u012F\",\n\t      'Iogon': \"\\u012E\",\n\t      'iopf': \"\\uD835\\uDD5A\",\n\t      'Iopf': \"\\uD835\\uDD40\",\n\t      'iota': \"\\u03B9\",\n\t      'Iota': \"\\u0399\",\n\t      'iprod': \"\\u2A3C\",\n\t      'iquest': '\\xBF',\n\t      'iscr': \"\\uD835\\uDCBE\",\n\t      'Iscr': \"\\u2110\",\n\t      'isin': \"\\u2208\",\n\t      'isindot': \"\\u22F5\",\n\t      'isinE': \"\\u22F9\",\n\t      'isins': \"\\u22F4\",\n\t      'isinsv': \"\\u22F3\",\n\t      'isinv': \"\\u2208\",\n\t      'it': \"\\u2062\",\n\t      'itilde': \"\\u0129\",\n\t      'Itilde': \"\\u0128\",\n\t      'iukcy': \"\\u0456\",\n\t      'Iukcy': \"\\u0406\",\n\t      'iuml': '\\xEF',\n\t      'Iuml': '\\xCF',\n\t      'jcirc': \"\\u0135\",\n\t      'Jcirc': \"\\u0134\",\n\t      'jcy': \"\\u0439\",\n\t      'Jcy': \"\\u0419\",\n\t      'jfr': \"\\uD835\\uDD27\",\n\t      'Jfr': \"\\uD835\\uDD0D\",\n\t      'jmath': \"\\u0237\",\n\t      'jopf': \"\\uD835\\uDD5B\",\n\t      'Jopf': \"\\uD835\\uDD41\",\n\t      'jscr': \"\\uD835\\uDCBF\",\n\t      'Jscr': \"\\uD835\\uDCA5\",\n\t      'jsercy': \"\\u0458\",\n\t      'Jsercy': \"\\u0408\",\n\t      'jukcy': \"\\u0454\",\n\t      'Jukcy': \"\\u0404\",\n\t      'kappa': \"\\u03BA\",\n\t      'Kappa': \"\\u039A\",\n\t      'kappav': \"\\u03F0\",\n\t      'kcedil': \"\\u0137\",\n\t      'Kcedil': \"\\u0136\",\n\t      'kcy': \"\\u043A\",\n\t      'Kcy': \"\\u041A\",\n\t      'kfr': \"\\uD835\\uDD28\",\n\t      'Kfr': \"\\uD835\\uDD0E\",\n\t      'kgreen': \"\\u0138\",\n\t      'khcy': \"\\u0445\",\n\t      'KHcy': \"\\u0425\",\n\t      'kjcy': \"\\u045C\",\n\t      'KJcy': \"\\u040C\",\n\t      'kopf': \"\\uD835\\uDD5C\",\n\t      'Kopf': \"\\uD835\\uDD42\",\n\t      'kscr': \"\\uD835\\uDCC0\",\n\t      'Kscr': \"\\uD835\\uDCA6\",\n\t      'lAarr': \"\\u21DA\",\n\t      'lacute': \"\\u013A\",\n\t      'Lacute': \"\\u0139\",\n\t      'laemptyv': \"\\u29B4\",\n\t      'lagran': \"\\u2112\",\n\t      'lambda': \"\\u03BB\",\n\t      'Lambda': \"\\u039B\",\n\t      'lang': \"\\u27E8\",\n\t      'Lang': \"\\u27EA\",\n\t      'langd': \"\\u2991\",\n\t      'langle': \"\\u27E8\",\n\t      'lap': \"\\u2A85\",\n\t      'Laplacetrf': \"\\u2112\",\n\t      'laquo': '\\xAB',\n\t      'larr': \"\\u2190\",\n\t      'lArr': \"\\u21D0\",\n\t      'Larr': \"\\u219E\",\n\t      'larrb': \"\\u21E4\",\n\t      'larrbfs': \"\\u291F\",\n\t      'larrfs': \"\\u291D\",\n\t      'larrhk': \"\\u21A9\",\n\t      'larrlp': \"\\u21AB\",\n\t      'larrpl': \"\\u2939\",\n\t      'larrsim': \"\\u2973\",\n\t      'larrtl': \"\\u21A2\",\n\t      'lat': \"\\u2AAB\",\n\t      'latail': \"\\u2919\",\n\t      'lAtail': \"\\u291B\",\n\t      'late': \"\\u2AAD\",\n\t      'lates': \"\\u2AAD\\uFE00\",\n\t      'lbarr': \"\\u290C\",\n\t      'lBarr': \"\\u290E\",\n\t      'lbbrk': \"\\u2772\",\n\t      'lbrace': '{',\n\t      'lbrack': '[',\n\t      'lbrke': \"\\u298B\",\n\t      'lbrksld': \"\\u298F\",\n\t      'lbrkslu': \"\\u298D\",\n\t      'lcaron': \"\\u013E\",\n\t      'Lcaron': \"\\u013D\",\n\t      'lcedil': \"\\u013C\",\n\t      'Lcedil': \"\\u013B\",\n\t      'lceil': \"\\u2308\",\n\t      'lcub': '{',\n\t      'lcy': \"\\u043B\",\n\t      'Lcy': \"\\u041B\",\n\t      'ldca': \"\\u2936\",\n\t      'ldquo': \"\\u201C\",\n\t      'ldquor': \"\\u201E\",\n\t      'ldrdhar': \"\\u2967\",\n\t      'ldrushar': \"\\u294B\",\n\t      'ldsh': \"\\u21B2\",\n\t      'le': \"\\u2264\",\n\t      'lE': \"\\u2266\",\n\t      'LeftAngleBracket': \"\\u27E8\",\n\t      'leftarrow': \"\\u2190\",\n\t      'Leftarrow': \"\\u21D0\",\n\t      'LeftArrow': \"\\u2190\",\n\t      'LeftArrowBar': \"\\u21E4\",\n\t      'LeftArrowRightArrow': \"\\u21C6\",\n\t      'leftarrowtail': \"\\u21A2\",\n\t      'LeftCeiling': \"\\u2308\",\n\t      'LeftDoubleBracket': \"\\u27E6\",\n\t      'LeftDownTeeVector': \"\\u2961\",\n\t      'LeftDownVector': \"\\u21C3\",\n\t      'LeftDownVectorBar': \"\\u2959\",\n\t      'LeftFloor': \"\\u230A\",\n\t      'leftharpoondown': \"\\u21BD\",\n\t      'leftharpoonup': \"\\u21BC\",\n\t      'leftleftarrows': \"\\u21C7\",\n\t      'leftrightarrow': \"\\u2194\",\n\t      'Leftrightarrow': \"\\u21D4\",\n\t      'LeftRightArrow': \"\\u2194\",\n\t      'leftrightarrows': \"\\u21C6\",\n\t      'leftrightharpoons': \"\\u21CB\",\n\t      'leftrightsquigarrow': \"\\u21AD\",\n\t      'LeftRightVector': \"\\u294E\",\n\t      'LeftTee': \"\\u22A3\",\n\t      'LeftTeeArrow': \"\\u21A4\",\n\t      'LeftTeeVector': \"\\u295A\",\n\t      'leftthreetimes': \"\\u22CB\",\n\t      'LeftTriangle': \"\\u22B2\",\n\t      'LeftTriangleBar': \"\\u29CF\",\n\t      'LeftTriangleEqual': \"\\u22B4\",\n\t      'LeftUpDownVector': \"\\u2951\",\n\t      'LeftUpTeeVector': \"\\u2960\",\n\t      'LeftUpVector': \"\\u21BF\",\n\t      'LeftUpVectorBar': \"\\u2958\",\n\t      'LeftVector': \"\\u21BC\",\n\t      'LeftVectorBar': \"\\u2952\",\n\t      'leg': \"\\u22DA\",\n\t      'lEg': \"\\u2A8B\",\n\t      'leq': \"\\u2264\",\n\t      'leqq': \"\\u2266\",\n\t      'leqslant': \"\\u2A7D\",\n\t      'les': \"\\u2A7D\",\n\t      'lescc': \"\\u2AA8\",\n\t      'lesdot': \"\\u2A7F\",\n\t      'lesdoto': \"\\u2A81\",\n\t      'lesdotor': \"\\u2A83\",\n\t      'lesg': \"\\u22DA\\uFE00\",\n\t      'lesges': \"\\u2A93\",\n\t      'lessapprox': \"\\u2A85\",\n\t      'lessdot': \"\\u22D6\",\n\t      'lesseqgtr': \"\\u22DA\",\n\t      'lesseqqgtr': \"\\u2A8B\",\n\t      'LessEqualGreater': \"\\u22DA\",\n\t      'LessFullEqual': \"\\u2266\",\n\t      'LessGreater': \"\\u2276\",\n\t      'lessgtr': \"\\u2276\",\n\t      'LessLess': \"\\u2AA1\",\n\t      'lesssim': \"\\u2272\",\n\t      'LessSlantEqual': \"\\u2A7D\",\n\t      'LessTilde': \"\\u2272\",\n\t      'lfisht': \"\\u297C\",\n\t      'lfloor': \"\\u230A\",\n\t      'lfr': \"\\uD835\\uDD29\",\n\t      'Lfr': \"\\uD835\\uDD0F\",\n\t      'lg': \"\\u2276\",\n\t      'lgE': \"\\u2A91\",\n\t      'lHar': \"\\u2962\",\n\t      'lhard': \"\\u21BD\",\n\t      'lharu': \"\\u21BC\",\n\t      'lharul': \"\\u296A\",\n\t      'lhblk': \"\\u2584\",\n\t      'ljcy': \"\\u0459\",\n\t      'LJcy': \"\\u0409\",\n\t      'll': \"\\u226A\",\n\t      'Ll': \"\\u22D8\",\n\t      'llarr': \"\\u21C7\",\n\t      'llcorner': \"\\u231E\",\n\t      'Lleftarrow': \"\\u21DA\",\n\t      'llhard': \"\\u296B\",\n\t      'lltri': \"\\u25FA\",\n\t      'lmidot': \"\\u0140\",\n\t      'Lmidot': \"\\u013F\",\n\t      'lmoust': \"\\u23B0\",\n\t      'lmoustache': \"\\u23B0\",\n\t      'lnap': \"\\u2A89\",\n\t      'lnapprox': \"\\u2A89\",\n\t      'lne': \"\\u2A87\",\n\t      'lnE': \"\\u2268\",\n\t      'lneq': \"\\u2A87\",\n\t      'lneqq': \"\\u2268\",\n\t      'lnsim': \"\\u22E6\",\n\t      'loang': \"\\u27EC\",\n\t      'loarr': \"\\u21FD\",\n\t      'lobrk': \"\\u27E6\",\n\t      'longleftarrow': \"\\u27F5\",\n\t      'Longleftarrow': \"\\u27F8\",\n\t      'LongLeftArrow': \"\\u27F5\",\n\t      'longleftrightarrow': \"\\u27F7\",\n\t      'Longleftrightarrow': \"\\u27FA\",\n\t      'LongLeftRightArrow': \"\\u27F7\",\n\t      'longmapsto': \"\\u27FC\",\n\t      'longrightarrow': \"\\u27F6\",\n\t      'Longrightarrow': \"\\u27F9\",\n\t      'LongRightArrow': \"\\u27F6\",\n\t      'looparrowleft': \"\\u21AB\",\n\t      'looparrowright': \"\\u21AC\",\n\t      'lopar': \"\\u2985\",\n\t      'lopf': \"\\uD835\\uDD5D\",\n\t      'Lopf': \"\\uD835\\uDD43\",\n\t      'loplus': \"\\u2A2D\",\n\t      'lotimes': \"\\u2A34\",\n\t      'lowast': \"\\u2217\",\n\t      'lowbar': '_',\n\t      'LowerLeftArrow': \"\\u2199\",\n\t      'LowerRightArrow': \"\\u2198\",\n\t      'loz': \"\\u25CA\",\n\t      'lozenge': \"\\u25CA\",\n\t      'lozf': \"\\u29EB\",\n\t      'lpar': '(',\n\t      'lparlt': \"\\u2993\",\n\t      'lrarr': \"\\u21C6\",\n\t      'lrcorner': \"\\u231F\",\n\t      'lrhar': \"\\u21CB\",\n\t      'lrhard': \"\\u296D\",\n\t      'lrm': \"\\u200E\",\n\t      'lrtri': \"\\u22BF\",\n\t      'lsaquo': \"\\u2039\",\n\t      'lscr': \"\\uD835\\uDCC1\",\n\t      'Lscr': \"\\u2112\",\n\t      'lsh': \"\\u21B0\",\n\t      'Lsh': \"\\u21B0\",\n\t      'lsim': \"\\u2272\",\n\t      'lsime': \"\\u2A8D\",\n\t      'lsimg': \"\\u2A8F\",\n\t      'lsqb': '[',\n\t      'lsquo': \"\\u2018\",\n\t      'lsquor': \"\\u201A\",\n\t      'lstrok': \"\\u0142\",\n\t      'Lstrok': \"\\u0141\",\n\t      'lt': '<',\n\t      'Lt': \"\\u226A\",\n\t      'LT': '<',\n\t      'ltcc': \"\\u2AA6\",\n\t      'ltcir': \"\\u2A79\",\n\t      'ltdot': \"\\u22D6\",\n\t      'lthree': \"\\u22CB\",\n\t      'ltimes': \"\\u22C9\",\n\t      'ltlarr': \"\\u2976\",\n\t      'ltquest': \"\\u2A7B\",\n\t      'ltri': \"\\u25C3\",\n\t      'ltrie': \"\\u22B4\",\n\t      'ltrif': \"\\u25C2\",\n\t      'ltrPar': \"\\u2996\",\n\t      'lurdshar': \"\\u294A\",\n\t      'luruhar': \"\\u2966\",\n\t      'lvertneqq': \"\\u2268\\uFE00\",\n\t      'lvnE': \"\\u2268\\uFE00\",\n\t      'macr': '\\xAF',\n\t      'male': \"\\u2642\",\n\t      'malt': \"\\u2720\",\n\t      'maltese': \"\\u2720\",\n\t      'map': \"\\u21A6\",\n\t      'Map': \"\\u2905\",\n\t      'mapsto': \"\\u21A6\",\n\t      'mapstodown': \"\\u21A7\",\n\t      'mapstoleft': \"\\u21A4\",\n\t      'mapstoup': \"\\u21A5\",\n\t      'marker': \"\\u25AE\",\n\t      'mcomma': \"\\u2A29\",\n\t      'mcy': \"\\u043C\",\n\t      'Mcy': \"\\u041C\",\n\t      'mdash': \"\\u2014\",\n\t      'mDDot': \"\\u223A\",\n\t      'measuredangle': \"\\u2221\",\n\t      'MediumSpace': \"\\u205F\",\n\t      'Mellintrf': \"\\u2133\",\n\t      'mfr': \"\\uD835\\uDD2A\",\n\t      'Mfr': \"\\uD835\\uDD10\",\n\t      'mho': \"\\u2127\",\n\t      'micro': '\\xB5',\n\t      'mid': \"\\u2223\",\n\t      'midast': '*',\n\t      'midcir': \"\\u2AF0\",\n\t      'middot': '\\xB7',\n\t      'minus': \"\\u2212\",\n\t      'minusb': \"\\u229F\",\n\t      'minusd': \"\\u2238\",\n\t      'minusdu': \"\\u2A2A\",\n\t      'MinusPlus': \"\\u2213\",\n\t      'mlcp': \"\\u2ADB\",\n\t      'mldr': \"\\u2026\",\n\t      'mnplus': \"\\u2213\",\n\t      'models': \"\\u22A7\",\n\t      'mopf': \"\\uD835\\uDD5E\",\n\t      'Mopf': \"\\uD835\\uDD44\",\n\t      'mp': \"\\u2213\",\n\t      'mscr': \"\\uD835\\uDCC2\",\n\t      'Mscr': \"\\u2133\",\n\t      'mstpos': \"\\u223E\",\n\t      'mu': \"\\u03BC\",\n\t      'Mu': \"\\u039C\",\n\t      'multimap': \"\\u22B8\",\n\t      'mumap': \"\\u22B8\",\n\t      'nabla': \"\\u2207\",\n\t      'nacute': \"\\u0144\",\n\t      'Nacute': \"\\u0143\",\n\t      'nang': \"\\u2220\\u20D2\",\n\t      'nap': \"\\u2249\",\n\t      'napE': \"\\u2A70\\u0338\",\n\t      'napid': \"\\u224B\\u0338\",\n\t      'napos': \"\\u0149\",\n\t      'napprox': \"\\u2249\",\n\t      'natur': \"\\u266E\",\n\t      'natural': \"\\u266E\",\n\t      'naturals': \"\\u2115\",\n\t      'nbsp': '\\xA0',\n\t      'nbump': \"\\u224E\\u0338\",\n\t      'nbumpe': \"\\u224F\\u0338\",\n\t      'ncap': \"\\u2A43\",\n\t      'ncaron': \"\\u0148\",\n\t      'Ncaron': \"\\u0147\",\n\t      'ncedil': \"\\u0146\",\n\t      'Ncedil': \"\\u0145\",\n\t      'ncong': \"\\u2247\",\n\t      'ncongdot': \"\\u2A6D\\u0338\",\n\t      'ncup': \"\\u2A42\",\n\t      'ncy': \"\\u043D\",\n\t      'Ncy': \"\\u041D\",\n\t      'ndash': \"\\u2013\",\n\t      'ne': \"\\u2260\",\n\t      'nearhk': \"\\u2924\",\n\t      'nearr': \"\\u2197\",\n\t      'neArr': \"\\u21D7\",\n\t      'nearrow': \"\\u2197\",\n\t      'nedot': \"\\u2250\\u0338\",\n\t      'NegativeMediumSpace': \"\\u200B\",\n\t      'NegativeThickSpace': \"\\u200B\",\n\t      'NegativeThinSpace': \"\\u200B\",\n\t      'NegativeVeryThinSpace': \"\\u200B\",\n\t      'nequiv': \"\\u2262\",\n\t      'nesear': \"\\u2928\",\n\t      'nesim': \"\\u2242\\u0338\",\n\t      'NestedGreaterGreater': \"\\u226B\",\n\t      'NestedLessLess': \"\\u226A\",\n\t      'NewLine': '\\n',\n\t      'nexist': \"\\u2204\",\n\t      'nexists': \"\\u2204\",\n\t      'nfr': \"\\uD835\\uDD2B\",\n\t      'Nfr': \"\\uD835\\uDD11\",\n\t      'nge': \"\\u2271\",\n\t      'ngE': \"\\u2267\\u0338\",\n\t      'ngeq': \"\\u2271\",\n\t      'ngeqq': \"\\u2267\\u0338\",\n\t      'ngeqslant': \"\\u2A7E\\u0338\",\n\t      'nges': \"\\u2A7E\\u0338\",\n\t      'nGg': \"\\u22D9\\u0338\",\n\t      'ngsim': \"\\u2275\",\n\t      'ngt': \"\\u226F\",\n\t      'nGt': \"\\u226B\\u20D2\",\n\t      'ngtr': \"\\u226F\",\n\t      'nGtv': \"\\u226B\\u0338\",\n\t      'nharr': \"\\u21AE\",\n\t      'nhArr': \"\\u21CE\",\n\t      'nhpar': \"\\u2AF2\",\n\t      'ni': \"\\u220B\",\n\t      'nis': \"\\u22FC\",\n\t      'nisd': \"\\u22FA\",\n\t      'niv': \"\\u220B\",\n\t      'njcy': \"\\u045A\",\n\t      'NJcy': \"\\u040A\",\n\t      'nlarr': \"\\u219A\",\n\t      'nlArr': \"\\u21CD\",\n\t      'nldr': \"\\u2025\",\n\t      'nle': \"\\u2270\",\n\t      'nlE': \"\\u2266\\u0338\",\n\t      'nleftarrow': \"\\u219A\",\n\t      'nLeftarrow': \"\\u21CD\",\n\t      'nleftrightarrow': \"\\u21AE\",\n\t      'nLeftrightarrow': \"\\u21CE\",\n\t      'nleq': \"\\u2270\",\n\t      'nleqq': \"\\u2266\\u0338\",\n\t      'nleqslant': \"\\u2A7D\\u0338\",\n\t      'nles': \"\\u2A7D\\u0338\",\n\t      'nless': \"\\u226E\",\n\t      'nLl': \"\\u22D8\\u0338\",\n\t      'nlsim': \"\\u2274\",\n\t      'nlt': \"\\u226E\",\n\t      'nLt': \"\\u226A\\u20D2\",\n\t      'nltri': \"\\u22EA\",\n\t      'nltrie': \"\\u22EC\",\n\t      'nLtv': \"\\u226A\\u0338\",\n\t      'nmid': \"\\u2224\",\n\t      'NoBreak': \"\\u2060\",\n\t      'NonBreakingSpace': '\\xA0',\n\t      'nopf': \"\\uD835\\uDD5F\",\n\t      'Nopf': \"\\u2115\",\n\t      'not': '\\xAC',\n\t      'Not': \"\\u2AEC\",\n\t      'NotCongruent': \"\\u2262\",\n\t      'NotCupCap': \"\\u226D\",\n\t      'NotDoubleVerticalBar': \"\\u2226\",\n\t      'NotElement': \"\\u2209\",\n\t      'NotEqual': \"\\u2260\",\n\t      'NotEqualTilde': \"\\u2242\\u0338\",\n\t      'NotExists': \"\\u2204\",\n\t      'NotGreater': \"\\u226F\",\n\t      'NotGreaterEqual': \"\\u2271\",\n\t      'NotGreaterFullEqual': \"\\u2267\\u0338\",\n\t      'NotGreaterGreater': \"\\u226B\\u0338\",\n\t      'NotGreaterLess': \"\\u2279\",\n\t      'NotGreaterSlantEqual': \"\\u2A7E\\u0338\",\n\t      'NotGreaterTilde': \"\\u2275\",\n\t      'NotHumpDownHump': \"\\u224E\\u0338\",\n\t      'NotHumpEqual': \"\\u224F\\u0338\",\n\t      'notin': \"\\u2209\",\n\t      'notindot': \"\\u22F5\\u0338\",\n\t      'notinE': \"\\u22F9\\u0338\",\n\t      'notinva': \"\\u2209\",\n\t      'notinvb': \"\\u22F7\",\n\t      'notinvc': \"\\u22F6\",\n\t      'NotLeftTriangle': \"\\u22EA\",\n\t      'NotLeftTriangleBar': \"\\u29CF\\u0338\",\n\t      'NotLeftTriangleEqual': \"\\u22EC\",\n\t      'NotLess': \"\\u226E\",\n\t      'NotLessEqual': \"\\u2270\",\n\t      'NotLessGreater': \"\\u2278\",\n\t      'NotLessLess': \"\\u226A\\u0338\",\n\t      'NotLessSlantEqual': \"\\u2A7D\\u0338\",\n\t      'NotLessTilde': \"\\u2274\",\n\t      'NotNestedGreaterGreater': \"\\u2AA2\\u0338\",\n\t      'NotNestedLessLess': \"\\u2AA1\\u0338\",\n\t      'notni': \"\\u220C\",\n\t      'notniva': \"\\u220C\",\n\t      'notnivb': \"\\u22FE\",\n\t      'notnivc': \"\\u22FD\",\n\t      'NotPrecedes': \"\\u2280\",\n\t      'NotPrecedesEqual': \"\\u2AAF\\u0338\",\n\t      'NotPrecedesSlantEqual': \"\\u22E0\",\n\t      'NotReverseElement': \"\\u220C\",\n\t      'NotRightTriangle': \"\\u22EB\",\n\t      'NotRightTriangleBar': \"\\u29D0\\u0338\",\n\t      'NotRightTriangleEqual': \"\\u22ED\",\n\t      'NotSquareSubset': \"\\u228F\\u0338\",\n\t      'NotSquareSubsetEqual': \"\\u22E2\",\n\t      'NotSquareSuperset': \"\\u2290\\u0338\",\n\t      'NotSquareSupersetEqual': \"\\u22E3\",\n\t      'NotSubset': \"\\u2282\\u20D2\",\n\t      'NotSubsetEqual': \"\\u2288\",\n\t      'NotSucceeds': \"\\u2281\",\n\t      'NotSucceedsEqual': \"\\u2AB0\\u0338\",\n\t      'NotSucceedsSlantEqual': \"\\u22E1\",\n\t      'NotSucceedsTilde': \"\\u227F\\u0338\",\n\t      'NotSuperset': \"\\u2283\\u20D2\",\n\t      'NotSupersetEqual': \"\\u2289\",\n\t      'NotTilde': \"\\u2241\",\n\t      'NotTildeEqual': \"\\u2244\",\n\t      'NotTildeFullEqual': \"\\u2247\",\n\t      'NotTildeTilde': \"\\u2249\",\n\t      'NotVerticalBar': \"\\u2224\",\n\t      'npar': \"\\u2226\",\n\t      'nparallel': \"\\u2226\",\n\t      'nparsl': \"\\u2AFD\\u20E5\",\n\t      'npart': \"\\u2202\\u0338\",\n\t      'npolint': \"\\u2A14\",\n\t      'npr': \"\\u2280\",\n\t      'nprcue': \"\\u22E0\",\n\t      'npre': \"\\u2AAF\\u0338\",\n\t      'nprec': \"\\u2280\",\n\t      'npreceq': \"\\u2AAF\\u0338\",\n\t      'nrarr': \"\\u219B\",\n\t      'nrArr': \"\\u21CF\",\n\t      'nrarrc': \"\\u2933\\u0338\",\n\t      'nrarrw': \"\\u219D\\u0338\",\n\t      'nrightarrow': \"\\u219B\",\n\t      'nRightarrow': \"\\u21CF\",\n\t      'nrtri': \"\\u22EB\",\n\t      'nrtrie': \"\\u22ED\",\n\t      'nsc': \"\\u2281\",\n\t      'nsccue': \"\\u22E1\",\n\t      'nsce': \"\\u2AB0\\u0338\",\n\t      'nscr': \"\\uD835\\uDCC3\",\n\t      'Nscr': \"\\uD835\\uDCA9\",\n\t      'nshortmid': \"\\u2224\",\n\t      'nshortparallel': \"\\u2226\",\n\t      'nsim': \"\\u2241\",\n\t      'nsime': \"\\u2244\",\n\t      'nsimeq': \"\\u2244\",\n\t      'nsmid': \"\\u2224\",\n\t      'nspar': \"\\u2226\",\n\t      'nsqsube': \"\\u22E2\",\n\t      'nsqsupe': \"\\u22E3\",\n\t      'nsub': \"\\u2284\",\n\t      'nsube': \"\\u2288\",\n\t      'nsubE': \"\\u2AC5\\u0338\",\n\t      'nsubset': \"\\u2282\\u20D2\",\n\t      'nsubseteq': \"\\u2288\",\n\t      'nsubseteqq': \"\\u2AC5\\u0338\",\n\t      'nsucc': \"\\u2281\",\n\t      'nsucceq': \"\\u2AB0\\u0338\",\n\t      'nsup': \"\\u2285\",\n\t      'nsupe': \"\\u2289\",\n\t      'nsupE': \"\\u2AC6\\u0338\",\n\t      'nsupset': \"\\u2283\\u20D2\",\n\t      'nsupseteq': \"\\u2289\",\n\t      'nsupseteqq': \"\\u2AC6\\u0338\",\n\t      'ntgl': \"\\u2279\",\n\t      'ntilde': '\\xF1',\n\t      'Ntilde': '\\xD1',\n\t      'ntlg': \"\\u2278\",\n\t      'ntriangleleft': \"\\u22EA\",\n\t      'ntrianglelefteq': \"\\u22EC\",\n\t      'ntriangleright': \"\\u22EB\",\n\t      'ntrianglerighteq': \"\\u22ED\",\n\t      'nu': \"\\u03BD\",\n\t      'Nu': \"\\u039D\",\n\t      'num': '#',\n\t      'numero': \"\\u2116\",\n\t      'numsp': \"\\u2007\",\n\t      'nvap': \"\\u224D\\u20D2\",\n\t      'nvdash': \"\\u22AC\",\n\t      'nvDash': \"\\u22AD\",\n\t      'nVdash': \"\\u22AE\",\n\t      'nVDash': \"\\u22AF\",\n\t      'nvge': \"\\u2265\\u20D2\",\n\t      'nvgt': \">\\u20D2\",\n\t      'nvHarr': \"\\u2904\",\n\t      'nvinfin': \"\\u29DE\",\n\t      'nvlArr': \"\\u2902\",\n\t      'nvle': \"\\u2264\\u20D2\",\n\t      'nvlt': \"<\\u20D2\",\n\t      'nvltrie': \"\\u22B4\\u20D2\",\n\t      'nvrArr': \"\\u2903\",\n\t      'nvrtrie': \"\\u22B5\\u20D2\",\n\t      'nvsim': \"\\u223C\\u20D2\",\n\t      'nwarhk': \"\\u2923\",\n\t      'nwarr': \"\\u2196\",\n\t      'nwArr': \"\\u21D6\",\n\t      'nwarrow': \"\\u2196\",\n\t      'nwnear': \"\\u2927\",\n\t      'oacute': '\\xF3',\n\t      'Oacute': '\\xD3',\n\t      'oast': \"\\u229B\",\n\t      'ocir': \"\\u229A\",\n\t      'ocirc': '\\xF4',\n\t      'Ocirc': '\\xD4',\n\t      'ocy': \"\\u043E\",\n\t      'Ocy': \"\\u041E\",\n\t      'odash': \"\\u229D\",\n\t      'odblac': \"\\u0151\",\n\t      'Odblac': \"\\u0150\",\n\t      'odiv': \"\\u2A38\",\n\t      'odot': \"\\u2299\",\n\t      'odsold': \"\\u29BC\",\n\t      'oelig': \"\\u0153\",\n\t      'OElig': \"\\u0152\",\n\t      'ofcir': \"\\u29BF\",\n\t      'ofr': \"\\uD835\\uDD2C\",\n\t      'Ofr': \"\\uD835\\uDD12\",\n\t      'ogon': \"\\u02DB\",\n\t      'ograve': '\\xF2',\n\t      'Ograve': '\\xD2',\n\t      'ogt': \"\\u29C1\",\n\t      'ohbar': \"\\u29B5\",\n\t      'ohm': \"\\u03A9\",\n\t      'oint': \"\\u222E\",\n\t      'olarr': \"\\u21BA\",\n\t      'olcir': \"\\u29BE\",\n\t      'olcross': \"\\u29BB\",\n\t      'oline': \"\\u203E\",\n\t      'olt': \"\\u29C0\",\n\t      'omacr': \"\\u014D\",\n\t      'Omacr': \"\\u014C\",\n\t      'omega': \"\\u03C9\",\n\t      'Omega': \"\\u03A9\",\n\t      'omicron': \"\\u03BF\",\n\t      'Omicron': \"\\u039F\",\n\t      'omid': \"\\u29B6\",\n\t      'ominus': \"\\u2296\",\n\t      'oopf': \"\\uD835\\uDD60\",\n\t      'Oopf': \"\\uD835\\uDD46\",\n\t      'opar': \"\\u29B7\",\n\t      'OpenCurlyDoubleQuote': \"\\u201C\",\n\t      'OpenCurlyQuote': \"\\u2018\",\n\t      'operp': \"\\u29B9\",\n\t      'oplus': \"\\u2295\",\n\t      'or': \"\\u2228\",\n\t      'Or': \"\\u2A54\",\n\t      'orarr': \"\\u21BB\",\n\t      'ord': \"\\u2A5D\",\n\t      'order': \"\\u2134\",\n\t      'orderof': \"\\u2134\",\n\t      'ordf': '\\xAA',\n\t      'ordm': '\\xBA',\n\t      'origof': \"\\u22B6\",\n\t      'oror': \"\\u2A56\",\n\t      'orslope': \"\\u2A57\",\n\t      'orv': \"\\u2A5B\",\n\t      'oS': \"\\u24C8\",\n\t      'oscr': \"\\u2134\",\n\t      'Oscr': \"\\uD835\\uDCAA\",\n\t      'oslash': '\\xF8',\n\t      'Oslash': '\\xD8',\n\t      'osol': \"\\u2298\",\n\t      'otilde': '\\xF5',\n\t      'Otilde': '\\xD5',\n\t      'otimes': \"\\u2297\",\n\t      'Otimes': \"\\u2A37\",\n\t      'otimesas': \"\\u2A36\",\n\t      'ouml': '\\xF6',\n\t      'Ouml': '\\xD6',\n\t      'ovbar': \"\\u233D\",\n\t      'OverBar': \"\\u203E\",\n\t      'OverBrace': \"\\u23DE\",\n\t      'OverBracket': \"\\u23B4\",\n\t      'OverParenthesis': \"\\u23DC\",\n\t      'par': \"\\u2225\",\n\t      'para': '\\xB6',\n\t      'parallel': \"\\u2225\",\n\t      'parsim': \"\\u2AF3\",\n\t      'parsl': \"\\u2AFD\",\n\t      'part': \"\\u2202\",\n\t      'PartialD': \"\\u2202\",\n\t      'pcy': \"\\u043F\",\n\t      'Pcy': \"\\u041F\",\n\t      'percnt': '%',\n\t      'period': '.',\n\t      'permil': \"\\u2030\",\n\t      'perp': \"\\u22A5\",\n\t      'pertenk': \"\\u2031\",\n\t      'pfr': \"\\uD835\\uDD2D\",\n\t      'Pfr': \"\\uD835\\uDD13\",\n\t      'phi': \"\\u03C6\",\n\t      'Phi': \"\\u03A6\",\n\t      'phiv': \"\\u03D5\",\n\t      'phmmat': \"\\u2133\",\n\t      'phone': \"\\u260E\",\n\t      'pi': \"\\u03C0\",\n\t      'Pi': \"\\u03A0\",\n\t      'pitchfork': \"\\u22D4\",\n\t      'piv': \"\\u03D6\",\n\t      'planck': \"\\u210F\",\n\t      'planckh': \"\\u210E\",\n\t      'plankv': \"\\u210F\",\n\t      'plus': '+',\n\t      'plusacir': \"\\u2A23\",\n\t      'plusb': \"\\u229E\",\n\t      'pluscir': \"\\u2A22\",\n\t      'plusdo': \"\\u2214\",\n\t      'plusdu': \"\\u2A25\",\n\t      'pluse': \"\\u2A72\",\n\t      'PlusMinus': '\\xB1',\n\t      'plusmn': '\\xB1',\n\t      'plussim': \"\\u2A26\",\n\t      'plustwo': \"\\u2A27\",\n\t      'pm': '\\xB1',\n\t      'Poincareplane': \"\\u210C\",\n\t      'pointint': \"\\u2A15\",\n\t      'popf': \"\\uD835\\uDD61\",\n\t      'Popf': \"\\u2119\",\n\t      'pound': '\\xA3',\n\t      'pr': \"\\u227A\",\n\t      'Pr': \"\\u2ABB\",\n\t      'prap': \"\\u2AB7\",\n\t      'prcue': \"\\u227C\",\n\t      'pre': \"\\u2AAF\",\n\t      'prE': \"\\u2AB3\",\n\t      'prec': \"\\u227A\",\n\t      'precapprox': \"\\u2AB7\",\n\t      'preccurlyeq': \"\\u227C\",\n\t      'Precedes': \"\\u227A\",\n\t      'PrecedesEqual': \"\\u2AAF\",\n\t      'PrecedesSlantEqual': \"\\u227C\",\n\t      'PrecedesTilde': \"\\u227E\",\n\t      'preceq': \"\\u2AAF\",\n\t      'precnapprox': \"\\u2AB9\",\n\t      'precneqq': \"\\u2AB5\",\n\t      'precnsim': \"\\u22E8\",\n\t      'precsim': \"\\u227E\",\n\t      'prime': \"\\u2032\",\n\t      'Prime': \"\\u2033\",\n\t      'primes': \"\\u2119\",\n\t      'prnap': \"\\u2AB9\",\n\t      'prnE': \"\\u2AB5\",\n\t      'prnsim': \"\\u22E8\",\n\t      'prod': \"\\u220F\",\n\t      'Product': \"\\u220F\",\n\t      'profalar': \"\\u232E\",\n\t      'profline': \"\\u2312\",\n\t      'profsurf': \"\\u2313\",\n\t      'prop': \"\\u221D\",\n\t      'Proportion': \"\\u2237\",\n\t      'Proportional': \"\\u221D\",\n\t      'propto': \"\\u221D\",\n\t      'prsim': \"\\u227E\",\n\t      'prurel': \"\\u22B0\",\n\t      'pscr': \"\\uD835\\uDCC5\",\n\t      'Pscr': \"\\uD835\\uDCAB\",\n\t      'psi': \"\\u03C8\",\n\t      'Psi': \"\\u03A8\",\n\t      'puncsp': \"\\u2008\",\n\t      'qfr': \"\\uD835\\uDD2E\",\n\t      'Qfr': \"\\uD835\\uDD14\",\n\t      'qint': \"\\u2A0C\",\n\t      'qopf': \"\\uD835\\uDD62\",\n\t      'Qopf': \"\\u211A\",\n\t      'qprime': \"\\u2057\",\n\t      'qscr': \"\\uD835\\uDCC6\",\n\t      'Qscr': \"\\uD835\\uDCAC\",\n\t      'quaternions': \"\\u210D\",\n\t      'quatint': \"\\u2A16\",\n\t      'quest': '?',\n\t      'questeq': \"\\u225F\",\n\t      'quot': '\"',\n\t      'QUOT': '\"',\n\t      'rAarr': \"\\u21DB\",\n\t      'race': \"\\u223D\\u0331\",\n\t      'racute': \"\\u0155\",\n\t      'Racute': \"\\u0154\",\n\t      'radic': \"\\u221A\",\n\t      'raemptyv': \"\\u29B3\",\n\t      'rang': \"\\u27E9\",\n\t      'Rang': \"\\u27EB\",\n\t      'rangd': \"\\u2992\",\n\t      'range': \"\\u29A5\",\n\t      'rangle': \"\\u27E9\",\n\t      'raquo': '\\xBB',\n\t      'rarr': \"\\u2192\",\n\t      'rArr': \"\\u21D2\",\n\t      'Rarr': \"\\u21A0\",\n\t      'rarrap': \"\\u2975\",\n\t      'rarrb': \"\\u21E5\",\n\t      'rarrbfs': \"\\u2920\",\n\t      'rarrc': \"\\u2933\",\n\t      'rarrfs': \"\\u291E\",\n\t      'rarrhk': \"\\u21AA\",\n\t      'rarrlp': \"\\u21AC\",\n\t      'rarrpl': \"\\u2945\",\n\t      'rarrsim': \"\\u2974\",\n\t      'rarrtl': \"\\u21A3\",\n\t      'Rarrtl': \"\\u2916\",\n\t      'rarrw': \"\\u219D\",\n\t      'ratail': \"\\u291A\",\n\t      'rAtail': \"\\u291C\",\n\t      'ratio': \"\\u2236\",\n\t      'rationals': \"\\u211A\",\n\t      'rbarr': \"\\u290D\",\n\t      'rBarr': \"\\u290F\",\n\t      'RBarr': \"\\u2910\",\n\t      'rbbrk': \"\\u2773\",\n\t      'rbrace': '}',\n\t      'rbrack': ']',\n\t      'rbrke': \"\\u298C\",\n\t      'rbrksld': \"\\u298E\",\n\t      'rbrkslu': \"\\u2990\",\n\t      'rcaron': \"\\u0159\",\n\t      'Rcaron': \"\\u0158\",\n\t      'rcedil': \"\\u0157\",\n\t      'Rcedil': \"\\u0156\",\n\t      'rceil': \"\\u2309\",\n\t      'rcub': '}',\n\t      'rcy': \"\\u0440\",\n\t      'Rcy': \"\\u0420\",\n\t      'rdca': \"\\u2937\",\n\t      'rdldhar': \"\\u2969\",\n\t      'rdquo': \"\\u201D\",\n\t      'rdquor': \"\\u201D\",\n\t      'rdsh': \"\\u21B3\",\n\t      'Re': \"\\u211C\",\n\t      'real': \"\\u211C\",\n\t      'realine': \"\\u211B\",\n\t      'realpart': \"\\u211C\",\n\t      'reals': \"\\u211D\",\n\t      'rect': \"\\u25AD\",\n\t      'reg': '\\xAE',\n\t      'REG': '\\xAE',\n\t      'ReverseElement': \"\\u220B\",\n\t      'ReverseEquilibrium': \"\\u21CB\",\n\t      'ReverseUpEquilibrium': \"\\u296F\",\n\t      'rfisht': \"\\u297D\",\n\t      'rfloor': \"\\u230B\",\n\t      'rfr': \"\\uD835\\uDD2F\",\n\t      'Rfr': \"\\u211C\",\n\t      'rHar': \"\\u2964\",\n\t      'rhard': \"\\u21C1\",\n\t      'rharu': \"\\u21C0\",\n\t      'rharul': \"\\u296C\",\n\t      'rho': \"\\u03C1\",\n\t      'Rho': \"\\u03A1\",\n\t      'rhov': \"\\u03F1\",\n\t      'RightAngleBracket': \"\\u27E9\",\n\t      'rightarrow': \"\\u2192\",\n\t      'Rightarrow': \"\\u21D2\",\n\t      'RightArrow': \"\\u2192\",\n\t      'RightArrowBar': \"\\u21E5\",\n\t      'RightArrowLeftArrow': \"\\u21C4\",\n\t      'rightarrowtail': \"\\u21A3\",\n\t      'RightCeiling': \"\\u2309\",\n\t      'RightDoubleBracket': \"\\u27E7\",\n\t      'RightDownTeeVector': \"\\u295D\",\n\t      'RightDownVector': \"\\u21C2\",\n\t      'RightDownVectorBar': \"\\u2955\",\n\t      'RightFloor': \"\\u230B\",\n\t      'rightharpoondown': \"\\u21C1\",\n\t      'rightharpoonup': \"\\u21C0\",\n\t      'rightleftarrows': \"\\u21C4\",\n\t      'rightleftharpoons': \"\\u21CC\",\n\t      'rightrightarrows': \"\\u21C9\",\n\t      'rightsquigarrow': \"\\u219D\",\n\t      'RightTee': \"\\u22A2\",\n\t      'RightTeeArrow': \"\\u21A6\",\n\t      'RightTeeVector': \"\\u295B\",\n\t      'rightthreetimes': \"\\u22CC\",\n\t      'RightTriangle': \"\\u22B3\",\n\t      'RightTriangleBar': \"\\u29D0\",\n\t      'RightTriangleEqual': \"\\u22B5\",\n\t      'RightUpDownVector': \"\\u294F\",\n\t      'RightUpTeeVector': \"\\u295C\",\n\t      'RightUpVector': \"\\u21BE\",\n\t      'RightUpVectorBar': \"\\u2954\",\n\t      'RightVector': \"\\u21C0\",\n\t      'RightVectorBar': \"\\u2953\",\n\t      'ring': \"\\u02DA\",\n\t      'risingdotseq': \"\\u2253\",\n\t      'rlarr': \"\\u21C4\",\n\t      'rlhar': \"\\u21CC\",\n\t      'rlm': \"\\u200F\",\n\t      'rmoust': \"\\u23B1\",\n\t      'rmoustache': \"\\u23B1\",\n\t      'rnmid': \"\\u2AEE\",\n\t      'roang': \"\\u27ED\",\n\t      'roarr': \"\\u21FE\",\n\t      'robrk': \"\\u27E7\",\n\t      'ropar': \"\\u2986\",\n\t      'ropf': \"\\uD835\\uDD63\",\n\t      'Ropf': \"\\u211D\",\n\t      'roplus': \"\\u2A2E\",\n\t      'rotimes': \"\\u2A35\",\n\t      'RoundImplies': \"\\u2970\",\n\t      'rpar': ')',\n\t      'rpargt': \"\\u2994\",\n\t      'rppolint': \"\\u2A12\",\n\t      'rrarr': \"\\u21C9\",\n\t      'Rrightarrow': \"\\u21DB\",\n\t      'rsaquo': \"\\u203A\",\n\t      'rscr': \"\\uD835\\uDCC7\",\n\t      'Rscr': \"\\u211B\",\n\t      'rsh': \"\\u21B1\",\n\t      'Rsh': \"\\u21B1\",\n\t      'rsqb': ']',\n\t      'rsquo': \"\\u2019\",\n\t      'rsquor': \"\\u2019\",\n\t      'rthree': \"\\u22CC\",\n\t      'rtimes': \"\\u22CA\",\n\t      'rtri': \"\\u25B9\",\n\t      'rtrie': \"\\u22B5\",\n\t      'rtrif': \"\\u25B8\",\n\t      'rtriltri': \"\\u29CE\",\n\t      'RuleDelayed': \"\\u29F4\",\n\t      'ruluhar': \"\\u2968\",\n\t      'rx': \"\\u211E\",\n\t      'sacute': \"\\u015B\",\n\t      'Sacute': \"\\u015A\",\n\t      'sbquo': \"\\u201A\",\n\t      'sc': \"\\u227B\",\n\t      'Sc': \"\\u2ABC\",\n\t      'scap': \"\\u2AB8\",\n\t      'scaron': \"\\u0161\",\n\t      'Scaron': \"\\u0160\",\n\t      'sccue': \"\\u227D\",\n\t      'sce': \"\\u2AB0\",\n\t      'scE': \"\\u2AB4\",\n\t      'scedil': \"\\u015F\",\n\t      'Scedil': \"\\u015E\",\n\t      'scirc': \"\\u015D\",\n\t      'Scirc': \"\\u015C\",\n\t      'scnap': \"\\u2ABA\",\n\t      'scnE': \"\\u2AB6\",\n\t      'scnsim': \"\\u22E9\",\n\t      'scpolint': \"\\u2A13\",\n\t      'scsim': \"\\u227F\",\n\t      'scy': \"\\u0441\",\n\t      'Scy': \"\\u0421\",\n\t      'sdot': \"\\u22C5\",\n\t      'sdotb': \"\\u22A1\",\n\t      'sdote': \"\\u2A66\",\n\t      'searhk': \"\\u2925\",\n\t      'searr': \"\\u2198\",\n\t      'seArr': \"\\u21D8\",\n\t      'searrow': \"\\u2198\",\n\t      'sect': '\\xA7',\n\t      'semi': ';',\n\t      'seswar': \"\\u2929\",\n\t      'setminus': \"\\u2216\",\n\t      'setmn': \"\\u2216\",\n\t      'sext': \"\\u2736\",\n\t      'sfr': \"\\uD835\\uDD30\",\n\t      'Sfr': \"\\uD835\\uDD16\",\n\t      'sfrown': \"\\u2322\",\n\t      'sharp': \"\\u266F\",\n\t      'shchcy': \"\\u0449\",\n\t      'SHCHcy': \"\\u0429\",\n\t      'shcy': \"\\u0448\",\n\t      'SHcy': \"\\u0428\",\n\t      'ShortDownArrow': \"\\u2193\",\n\t      'ShortLeftArrow': \"\\u2190\",\n\t      'shortmid': \"\\u2223\",\n\t      'shortparallel': \"\\u2225\",\n\t      'ShortRightArrow': \"\\u2192\",\n\t      'ShortUpArrow': \"\\u2191\",\n\t      'shy': '\\xAD',\n\t      'sigma': \"\\u03C3\",\n\t      'Sigma': \"\\u03A3\",\n\t      'sigmaf': \"\\u03C2\",\n\t      'sigmav': \"\\u03C2\",\n\t      'sim': \"\\u223C\",\n\t      'simdot': \"\\u2A6A\",\n\t      'sime': \"\\u2243\",\n\t      'simeq': \"\\u2243\",\n\t      'simg': \"\\u2A9E\",\n\t      'simgE': \"\\u2AA0\",\n\t      'siml': \"\\u2A9D\",\n\t      'simlE': \"\\u2A9F\",\n\t      'simne': \"\\u2246\",\n\t      'simplus': \"\\u2A24\",\n\t      'simrarr': \"\\u2972\",\n\t      'slarr': \"\\u2190\",\n\t      'SmallCircle': \"\\u2218\",\n\t      'smallsetminus': \"\\u2216\",\n\t      'smashp': \"\\u2A33\",\n\t      'smeparsl': \"\\u29E4\",\n\t      'smid': \"\\u2223\",\n\t      'smile': \"\\u2323\",\n\t      'smt': \"\\u2AAA\",\n\t      'smte': \"\\u2AAC\",\n\t      'smtes': \"\\u2AAC\\uFE00\",\n\t      'softcy': \"\\u044C\",\n\t      'SOFTcy': \"\\u042C\",\n\t      'sol': '/',\n\t      'solb': \"\\u29C4\",\n\t      'solbar': \"\\u233F\",\n\t      'sopf': \"\\uD835\\uDD64\",\n\t      'Sopf': \"\\uD835\\uDD4A\",\n\t      'spades': \"\\u2660\",\n\t      'spadesuit': \"\\u2660\",\n\t      'spar': \"\\u2225\",\n\t      'sqcap': \"\\u2293\",\n\t      'sqcaps': \"\\u2293\\uFE00\",\n\t      'sqcup': \"\\u2294\",\n\t      'sqcups': \"\\u2294\\uFE00\",\n\t      'Sqrt': \"\\u221A\",\n\t      'sqsub': \"\\u228F\",\n\t      'sqsube': \"\\u2291\",\n\t      'sqsubset': \"\\u228F\",\n\t      'sqsubseteq': \"\\u2291\",\n\t      'sqsup': \"\\u2290\",\n\t      'sqsupe': \"\\u2292\",\n\t      'sqsupset': \"\\u2290\",\n\t      'sqsupseteq': \"\\u2292\",\n\t      'squ': \"\\u25A1\",\n\t      'square': \"\\u25A1\",\n\t      'Square': \"\\u25A1\",\n\t      'SquareIntersection': \"\\u2293\",\n\t      'SquareSubset': \"\\u228F\",\n\t      'SquareSubsetEqual': \"\\u2291\",\n\t      'SquareSuperset': \"\\u2290\",\n\t      'SquareSupersetEqual': \"\\u2292\",\n\t      'SquareUnion': \"\\u2294\",\n\t      'squarf': \"\\u25AA\",\n\t      'squf': \"\\u25AA\",\n\t      'srarr': \"\\u2192\",\n\t      'sscr': \"\\uD835\\uDCC8\",\n\t      'Sscr': \"\\uD835\\uDCAE\",\n\t      'ssetmn': \"\\u2216\",\n\t      'ssmile': \"\\u2323\",\n\t      'sstarf': \"\\u22C6\",\n\t      'star': \"\\u2606\",\n\t      'Star': \"\\u22C6\",\n\t      'starf': \"\\u2605\",\n\t      'straightepsilon': \"\\u03F5\",\n\t      'straightphi': \"\\u03D5\",\n\t      'strns': '\\xAF',\n\t      'sub': \"\\u2282\",\n\t      'Sub': \"\\u22D0\",\n\t      'subdot': \"\\u2ABD\",\n\t      'sube': \"\\u2286\",\n\t      'subE': \"\\u2AC5\",\n\t      'subedot': \"\\u2AC3\",\n\t      'submult': \"\\u2AC1\",\n\t      'subne': \"\\u228A\",\n\t      'subnE': \"\\u2ACB\",\n\t      'subplus': \"\\u2ABF\",\n\t      'subrarr': \"\\u2979\",\n\t      'subset': \"\\u2282\",\n\t      'Subset': \"\\u22D0\",\n\t      'subseteq': \"\\u2286\",\n\t      'subseteqq': \"\\u2AC5\",\n\t      'SubsetEqual': \"\\u2286\",\n\t      'subsetneq': \"\\u228A\",\n\t      'subsetneqq': \"\\u2ACB\",\n\t      'subsim': \"\\u2AC7\",\n\t      'subsub': \"\\u2AD5\",\n\t      'subsup': \"\\u2AD3\",\n\t      'succ': \"\\u227B\",\n\t      'succapprox': \"\\u2AB8\",\n\t      'succcurlyeq': \"\\u227D\",\n\t      'Succeeds': \"\\u227B\",\n\t      'SucceedsEqual': \"\\u2AB0\",\n\t      'SucceedsSlantEqual': \"\\u227D\",\n\t      'SucceedsTilde': \"\\u227F\",\n\t      'succeq': \"\\u2AB0\",\n\t      'succnapprox': \"\\u2ABA\",\n\t      'succneqq': \"\\u2AB6\",\n\t      'succnsim': \"\\u22E9\",\n\t      'succsim': \"\\u227F\",\n\t      'SuchThat': \"\\u220B\",\n\t      'sum': \"\\u2211\",\n\t      'Sum': \"\\u2211\",\n\t      'sung': \"\\u266A\",\n\t      'sup': \"\\u2283\",\n\t      'Sup': \"\\u22D1\",\n\t      'sup1': '\\xB9',\n\t      'sup2': '\\xB2',\n\t      'sup3': '\\xB3',\n\t      'supdot': \"\\u2ABE\",\n\t      'supdsub': \"\\u2AD8\",\n\t      'supe': \"\\u2287\",\n\t      'supE': \"\\u2AC6\",\n\t      'supedot': \"\\u2AC4\",\n\t      'Superset': \"\\u2283\",\n\t      'SupersetEqual': \"\\u2287\",\n\t      'suphsol': \"\\u27C9\",\n\t      'suphsub': \"\\u2AD7\",\n\t      'suplarr': \"\\u297B\",\n\t      'supmult': \"\\u2AC2\",\n\t      'supne': \"\\u228B\",\n\t      'supnE': \"\\u2ACC\",\n\t      'supplus': \"\\u2AC0\",\n\t      'supset': \"\\u2283\",\n\t      'Supset': \"\\u22D1\",\n\t      'supseteq': \"\\u2287\",\n\t      'supseteqq': \"\\u2AC6\",\n\t      'supsetneq': \"\\u228B\",\n\t      'supsetneqq': \"\\u2ACC\",\n\t      'supsim': \"\\u2AC8\",\n\t      'supsub': \"\\u2AD4\",\n\t      'supsup': \"\\u2AD6\",\n\t      'swarhk': \"\\u2926\",\n\t      'swarr': \"\\u2199\",\n\t      'swArr': \"\\u21D9\",\n\t      'swarrow': \"\\u2199\",\n\t      'swnwar': \"\\u292A\",\n\t      'szlig': '\\xDF',\n\t      'Tab': '\\t',\n\t      'target': \"\\u2316\",\n\t      'tau': \"\\u03C4\",\n\t      'Tau': \"\\u03A4\",\n\t      'tbrk': \"\\u23B4\",\n\t      'tcaron': \"\\u0165\",\n\t      'Tcaron': \"\\u0164\",\n\t      'tcedil': \"\\u0163\",\n\t      'Tcedil': \"\\u0162\",\n\t      'tcy': \"\\u0442\",\n\t      'Tcy': \"\\u0422\",\n\t      'tdot': \"\\u20DB\",\n\t      'telrec': \"\\u2315\",\n\t      'tfr': \"\\uD835\\uDD31\",\n\t      'Tfr': \"\\uD835\\uDD17\",\n\t      'there4': \"\\u2234\",\n\t      'therefore': \"\\u2234\",\n\t      'Therefore': \"\\u2234\",\n\t      'theta': \"\\u03B8\",\n\t      'Theta': \"\\u0398\",\n\t      'thetasym': \"\\u03D1\",\n\t      'thetav': \"\\u03D1\",\n\t      'thickapprox': \"\\u2248\",\n\t      'thicksim': \"\\u223C\",\n\t      'ThickSpace': \"\\u205F\\u200A\",\n\t      'thinsp': \"\\u2009\",\n\t      'ThinSpace': \"\\u2009\",\n\t      'thkap': \"\\u2248\",\n\t      'thksim': \"\\u223C\",\n\t      'thorn': '\\xFE',\n\t      'THORN': '\\xDE',\n\t      'tilde': \"\\u02DC\",\n\t      'Tilde': \"\\u223C\",\n\t      'TildeEqual': \"\\u2243\",\n\t      'TildeFullEqual': \"\\u2245\",\n\t      'TildeTilde': \"\\u2248\",\n\t      'times': '\\xD7',\n\t      'timesb': \"\\u22A0\",\n\t      'timesbar': \"\\u2A31\",\n\t      'timesd': \"\\u2A30\",\n\t      'tint': \"\\u222D\",\n\t      'toea': \"\\u2928\",\n\t      'top': \"\\u22A4\",\n\t      'topbot': \"\\u2336\",\n\t      'topcir': \"\\u2AF1\",\n\t      'topf': \"\\uD835\\uDD65\",\n\t      'Topf': \"\\uD835\\uDD4B\",\n\t      'topfork': \"\\u2ADA\",\n\t      'tosa': \"\\u2929\",\n\t      'tprime': \"\\u2034\",\n\t      'trade': \"\\u2122\",\n\t      'TRADE': \"\\u2122\",\n\t      'triangle': \"\\u25B5\",\n\t      'triangledown': \"\\u25BF\",\n\t      'triangleleft': \"\\u25C3\",\n\t      'trianglelefteq': \"\\u22B4\",\n\t      'triangleq': \"\\u225C\",\n\t      'triangleright': \"\\u25B9\",\n\t      'trianglerighteq': \"\\u22B5\",\n\t      'tridot': \"\\u25EC\",\n\t      'trie': \"\\u225C\",\n\t      'triminus': \"\\u2A3A\",\n\t      'TripleDot': \"\\u20DB\",\n\t      'triplus': \"\\u2A39\",\n\t      'trisb': \"\\u29CD\",\n\t      'tritime': \"\\u2A3B\",\n\t      'trpezium': \"\\u23E2\",\n\t      'tscr': \"\\uD835\\uDCC9\",\n\t      'Tscr': \"\\uD835\\uDCAF\",\n\t      'tscy': \"\\u0446\",\n\t      'TScy': \"\\u0426\",\n\t      'tshcy': \"\\u045B\",\n\t      'TSHcy': \"\\u040B\",\n\t      'tstrok': \"\\u0167\",\n\t      'Tstrok': \"\\u0166\",\n\t      'twixt': \"\\u226C\",\n\t      'twoheadleftarrow': \"\\u219E\",\n\t      'twoheadrightarrow': \"\\u21A0\",\n\t      'uacute': '\\xFA',\n\t      'Uacute': '\\xDA',\n\t      'uarr': \"\\u2191\",\n\t      'uArr': \"\\u21D1\",\n\t      'Uarr': \"\\u219F\",\n\t      'Uarrocir': \"\\u2949\",\n\t      'ubrcy': \"\\u045E\",\n\t      'Ubrcy': \"\\u040E\",\n\t      'ubreve': \"\\u016D\",\n\t      'Ubreve': \"\\u016C\",\n\t      'ucirc': '\\xFB',\n\t      'Ucirc': '\\xDB',\n\t      'ucy': \"\\u0443\",\n\t      'Ucy': \"\\u0423\",\n\t      'udarr': \"\\u21C5\",\n\t      'udblac': \"\\u0171\",\n\t      'Udblac': \"\\u0170\",\n\t      'udhar': \"\\u296E\",\n\t      'ufisht': \"\\u297E\",\n\t      'ufr': \"\\uD835\\uDD32\",\n\t      'Ufr': \"\\uD835\\uDD18\",\n\t      'ugrave': '\\xF9',\n\t      'Ugrave': '\\xD9',\n\t      'uHar': \"\\u2963\",\n\t      'uharl': \"\\u21BF\",\n\t      'uharr': \"\\u21BE\",\n\t      'uhblk': \"\\u2580\",\n\t      'ulcorn': \"\\u231C\",\n\t      'ulcorner': \"\\u231C\",\n\t      'ulcrop': \"\\u230F\",\n\t      'ultri': \"\\u25F8\",\n\t      'umacr': \"\\u016B\",\n\t      'Umacr': \"\\u016A\",\n\t      'uml': '\\xA8',\n\t      'UnderBar': '_',\n\t      'UnderBrace': \"\\u23DF\",\n\t      'UnderBracket': \"\\u23B5\",\n\t      'UnderParenthesis': \"\\u23DD\",\n\t      'Union': \"\\u22C3\",\n\t      'UnionPlus': \"\\u228E\",\n\t      'uogon': \"\\u0173\",\n\t      'Uogon': \"\\u0172\",\n\t      'uopf': \"\\uD835\\uDD66\",\n\t      'Uopf': \"\\uD835\\uDD4C\",\n\t      'uparrow': \"\\u2191\",\n\t      'Uparrow': \"\\u21D1\",\n\t      'UpArrow': \"\\u2191\",\n\t      'UpArrowBar': \"\\u2912\",\n\t      'UpArrowDownArrow': \"\\u21C5\",\n\t      'updownarrow': \"\\u2195\",\n\t      'Updownarrow': \"\\u21D5\",\n\t      'UpDownArrow': \"\\u2195\",\n\t      'UpEquilibrium': \"\\u296E\",\n\t      'upharpoonleft': \"\\u21BF\",\n\t      'upharpoonright': \"\\u21BE\",\n\t      'uplus': \"\\u228E\",\n\t      'UpperLeftArrow': \"\\u2196\",\n\t      'UpperRightArrow': \"\\u2197\",\n\t      'upsi': \"\\u03C5\",\n\t      'Upsi': \"\\u03D2\",\n\t      'upsih': \"\\u03D2\",\n\t      'upsilon': \"\\u03C5\",\n\t      'Upsilon': \"\\u03A5\",\n\t      'UpTee': \"\\u22A5\",\n\t      'UpTeeArrow': \"\\u21A5\",\n\t      'upuparrows': \"\\u21C8\",\n\t      'urcorn': \"\\u231D\",\n\t      'urcorner': \"\\u231D\",\n\t      'urcrop': \"\\u230E\",\n\t      'uring': \"\\u016F\",\n\t      'Uring': \"\\u016E\",\n\t      'urtri': \"\\u25F9\",\n\t      'uscr': \"\\uD835\\uDCCA\",\n\t      'Uscr': \"\\uD835\\uDCB0\",\n\t      'utdot': \"\\u22F0\",\n\t      'utilde': \"\\u0169\",\n\t      'Utilde': \"\\u0168\",\n\t      'utri': \"\\u25B5\",\n\t      'utrif': \"\\u25B4\",\n\t      'uuarr': \"\\u21C8\",\n\t      'uuml': '\\xFC',\n\t      'Uuml': '\\xDC',\n\t      'uwangle': \"\\u29A7\",\n\t      'vangrt': \"\\u299C\",\n\t      'varepsilon': \"\\u03F5\",\n\t      'varkappa': \"\\u03F0\",\n\t      'varnothing': \"\\u2205\",\n\t      'varphi': \"\\u03D5\",\n\t      'varpi': \"\\u03D6\",\n\t      'varpropto': \"\\u221D\",\n\t      'varr': \"\\u2195\",\n\t      'vArr': \"\\u21D5\",\n\t      'varrho': \"\\u03F1\",\n\t      'varsigma': \"\\u03C2\",\n\t      'varsubsetneq': \"\\u228A\\uFE00\",\n\t      'varsubsetneqq': \"\\u2ACB\\uFE00\",\n\t      'varsupsetneq': \"\\u228B\\uFE00\",\n\t      'varsupsetneqq': \"\\u2ACC\\uFE00\",\n\t      'vartheta': \"\\u03D1\",\n\t      'vartriangleleft': \"\\u22B2\",\n\t      'vartriangleright': \"\\u22B3\",\n\t      'vBar': \"\\u2AE8\",\n\t      'Vbar': \"\\u2AEB\",\n\t      'vBarv': \"\\u2AE9\",\n\t      'vcy': \"\\u0432\",\n\t      'Vcy': \"\\u0412\",\n\t      'vdash': \"\\u22A2\",\n\t      'vDash': \"\\u22A8\",\n\t      'Vdash': \"\\u22A9\",\n\t      'VDash': \"\\u22AB\",\n\t      'Vdashl': \"\\u2AE6\",\n\t      'vee': \"\\u2228\",\n\t      'Vee': \"\\u22C1\",\n\t      'veebar': \"\\u22BB\",\n\t      'veeeq': \"\\u225A\",\n\t      'vellip': \"\\u22EE\",\n\t      'verbar': '|',\n\t      'Verbar': \"\\u2016\",\n\t      'vert': '|',\n\t      'Vert': \"\\u2016\",\n\t      'VerticalBar': \"\\u2223\",\n\t      'VerticalLine': '|',\n\t      'VerticalSeparator': \"\\u2758\",\n\t      'VerticalTilde': \"\\u2240\",\n\t      'VeryThinSpace': \"\\u200A\",\n\t      'vfr': \"\\uD835\\uDD33\",\n\t      'Vfr': \"\\uD835\\uDD19\",\n\t      'vltri': \"\\u22B2\",\n\t      'vnsub': \"\\u2282\\u20D2\",\n\t      'vnsup': \"\\u2283\\u20D2\",\n\t      'vopf': \"\\uD835\\uDD67\",\n\t      'Vopf': \"\\uD835\\uDD4D\",\n\t      'vprop': \"\\u221D\",\n\t      'vrtri': \"\\u22B3\",\n\t      'vscr': \"\\uD835\\uDCCB\",\n\t      'Vscr': \"\\uD835\\uDCB1\",\n\t      'vsubne': \"\\u228A\\uFE00\",\n\t      'vsubnE': \"\\u2ACB\\uFE00\",\n\t      'vsupne': \"\\u228B\\uFE00\",\n\t      'vsupnE': \"\\u2ACC\\uFE00\",\n\t      'Vvdash': \"\\u22AA\",\n\t      'vzigzag': \"\\u299A\",\n\t      'wcirc': \"\\u0175\",\n\t      'Wcirc': \"\\u0174\",\n\t      'wedbar': \"\\u2A5F\",\n\t      'wedge': \"\\u2227\",\n\t      'Wedge': \"\\u22C0\",\n\t      'wedgeq': \"\\u2259\",\n\t      'weierp': \"\\u2118\",\n\t      'wfr': \"\\uD835\\uDD34\",\n\t      'Wfr': \"\\uD835\\uDD1A\",\n\t      'wopf': \"\\uD835\\uDD68\",\n\t      'Wopf': \"\\uD835\\uDD4E\",\n\t      'wp': \"\\u2118\",\n\t      'wr': \"\\u2240\",\n\t      'wreath': \"\\u2240\",\n\t      'wscr': \"\\uD835\\uDCCC\",\n\t      'Wscr': \"\\uD835\\uDCB2\",\n\t      'xcap': \"\\u22C2\",\n\t      'xcirc': \"\\u25EF\",\n\t      'xcup': \"\\u22C3\",\n\t      'xdtri': \"\\u25BD\",\n\t      'xfr': \"\\uD835\\uDD35\",\n\t      'Xfr': \"\\uD835\\uDD1B\",\n\t      'xharr': \"\\u27F7\",\n\t      'xhArr': \"\\u27FA\",\n\t      'xi': \"\\u03BE\",\n\t      'Xi': \"\\u039E\",\n\t      'xlarr': \"\\u27F5\",\n\t      'xlArr': \"\\u27F8\",\n\t      'xmap': \"\\u27FC\",\n\t      'xnis': \"\\u22FB\",\n\t      'xodot': \"\\u2A00\",\n\t      'xopf': \"\\uD835\\uDD69\",\n\t      'Xopf': \"\\uD835\\uDD4F\",\n\t      'xoplus': \"\\u2A01\",\n\t      'xotime': \"\\u2A02\",\n\t      'xrarr': \"\\u27F6\",\n\t      'xrArr': \"\\u27F9\",\n\t      'xscr': \"\\uD835\\uDCCD\",\n\t      'Xscr': \"\\uD835\\uDCB3\",\n\t      'xsqcup': \"\\u2A06\",\n\t      'xuplus': \"\\u2A04\",\n\t      'xutri': \"\\u25B3\",\n\t      'xvee': \"\\u22C1\",\n\t      'xwedge': \"\\u22C0\",\n\t      'yacute': '\\xFD',\n\t      'Yacute': '\\xDD',\n\t      'yacy': \"\\u044F\",\n\t      'YAcy': \"\\u042F\",\n\t      'ycirc': \"\\u0177\",\n\t      'Ycirc': \"\\u0176\",\n\t      'ycy': \"\\u044B\",\n\t      'Ycy': \"\\u042B\",\n\t      'yen': '\\xA5',\n\t      'yfr': \"\\uD835\\uDD36\",\n\t      'Yfr': \"\\uD835\\uDD1C\",\n\t      'yicy': \"\\u0457\",\n\t      'YIcy': \"\\u0407\",\n\t      'yopf': \"\\uD835\\uDD6A\",\n\t      'Yopf': \"\\uD835\\uDD50\",\n\t      'yscr': \"\\uD835\\uDCCE\",\n\t      'Yscr': \"\\uD835\\uDCB4\",\n\t      'yucy': \"\\u044E\",\n\t      'YUcy': \"\\u042E\",\n\t      'yuml': '\\xFF',\n\t      'Yuml': \"\\u0178\",\n\t      'zacute': \"\\u017A\",\n\t      'Zacute': \"\\u0179\",\n\t      'zcaron': \"\\u017E\",\n\t      'Zcaron': \"\\u017D\",\n\t      'zcy': \"\\u0437\",\n\t      'Zcy': \"\\u0417\",\n\t      'zdot': \"\\u017C\",\n\t      'Zdot': \"\\u017B\",\n\t      'zeetrf': \"\\u2128\",\n\t      'ZeroWidthSpace': \"\\u200B\",\n\t      'zeta': \"\\u03B6\",\n\t      'Zeta': \"\\u0396\",\n\t      'zfr': \"\\uD835\\uDD37\",\n\t      'Zfr': \"\\u2128\",\n\t      'zhcy': \"\\u0436\",\n\t      'ZHcy': \"\\u0416\",\n\t      'zigrarr': \"\\u21DD\",\n\t      'zopf': \"\\uD835\\uDD6B\",\n\t      'Zopf': \"\\u2124\",\n\t      'zscr': \"\\uD835\\uDCCF\",\n\t      'Zscr': \"\\uD835\\uDCB5\",\n\t      'zwj': \"\\u200D\",\n\t      'zwnj': \"\\u200C\"\n\t    };\n\t    var decodeMapLegacy = {\n\t      'aacute': '\\xE1',\n\t      'Aacute': '\\xC1',\n\t      'acirc': '\\xE2',\n\t      'Acirc': '\\xC2',\n\t      'acute': '\\xB4',\n\t      'aelig': '\\xE6',\n\t      'AElig': '\\xC6',\n\t      'agrave': '\\xE0',\n\t      'Agrave': '\\xC0',\n\t      'amp': '&',\n\t      'AMP': '&',\n\t      'aring': '\\xE5',\n\t      'Aring': '\\xC5',\n\t      'atilde': '\\xE3',\n\t      'Atilde': '\\xC3',\n\t      'auml': '\\xE4',\n\t      'Auml': '\\xC4',\n\t      'brvbar': '\\xA6',\n\t      'ccedil': '\\xE7',\n\t      'Ccedil': '\\xC7',\n\t      'cedil': '\\xB8',\n\t      'cent': '\\xA2',\n\t      'copy': '\\xA9',\n\t      'COPY': '\\xA9',\n\t      'curren': '\\xA4',\n\t      'deg': '\\xB0',\n\t      'divide': '\\xF7',\n\t      'eacute': '\\xE9',\n\t      'Eacute': '\\xC9',\n\t      'ecirc': '\\xEA',\n\t      'Ecirc': '\\xCA',\n\t      'egrave': '\\xE8',\n\t      'Egrave': '\\xC8',\n\t      'eth': '\\xF0',\n\t      'ETH': '\\xD0',\n\t      'euml': '\\xEB',\n\t      'Euml': '\\xCB',\n\t      'frac12': '\\xBD',\n\t      'frac14': '\\xBC',\n\t      'frac34': '\\xBE',\n\t      'gt': '>',\n\t      'GT': '>',\n\t      'iacute': '\\xED',\n\t      'Iacute': '\\xCD',\n\t      'icirc': '\\xEE',\n\t      'Icirc': '\\xCE',\n\t      'iexcl': '\\xA1',\n\t      'igrave': '\\xEC',\n\t      'Igrave': '\\xCC',\n\t      'iquest': '\\xBF',\n\t      'iuml': '\\xEF',\n\t      'Iuml': '\\xCF',\n\t      'laquo': '\\xAB',\n\t      'lt': '<',\n\t      'LT': '<',\n\t      'macr': '\\xAF',\n\t      'micro': '\\xB5',\n\t      'middot': '\\xB7',\n\t      'nbsp': '\\xA0',\n\t      'not': '\\xAC',\n\t      'ntilde': '\\xF1',\n\t      'Ntilde': '\\xD1',\n\t      'oacute': '\\xF3',\n\t      'Oacute': '\\xD3',\n\t      'ocirc': '\\xF4',\n\t      'Ocirc': '\\xD4',\n\t      'ograve': '\\xF2',\n\t      'Ograve': '\\xD2',\n\t      'ordf': '\\xAA',\n\t      'ordm': '\\xBA',\n\t      'oslash': '\\xF8',\n\t      'Oslash': '\\xD8',\n\t      'otilde': '\\xF5',\n\t      'Otilde': '\\xD5',\n\t      'ouml': '\\xF6',\n\t      'Ouml': '\\xD6',\n\t      'para': '\\xB6',\n\t      'plusmn': '\\xB1',\n\t      'pound': '\\xA3',\n\t      'quot': '\"',\n\t      'QUOT': '\"',\n\t      'raquo': '\\xBB',\n\t      'reg': '\\xAE',\n\t      'REG': '\\xAE',\n\t      'sect': '\\xA7',\n\t      'shy': '\\xAD',\n\t      'sup1': '\\xB9',\n\t      'sup2': '\\xB2',\n\t      'sup3': '\\xB3',\n\t      'szlig': '\\xDF',\n\t      'thorn': '\\xFE',\n\t      'THORN': '\\xDE',\n\t      'times': '\\xD7',\n\t      'uacute': '\\xFA',\n\t      'Uacute': '\\xDA',\n\t      'ucirc': '\\xFB',\n\t      'Ucirc': '\\xDB',\n\t      'ugrave': '\\xF9',\n\t      'Ugrave': '\\xD9',\n\t      'uml': '\\xA8',\n\t      'uuml': '\\xFC',\n\t      'Uuml': '\\xDC',\n\t      'yacute': '\\xFD',\n\t      'Yacute': '\\xDD',\n\t      'yen': '\\xA5',\n\t      'yuml': '\\xFF'\n\t    };\n\t    var decodeMapNumeric = {\n\t      '0': \"\\uFFFD\",\n\t      '128': \"\\u20AC\",\n\t      '130': \"\\u201A\",\n\t      '131': \"\\u0192\",\n\t      '132': \"\\u201E\",\n\t      '133': \"\\u2026\",\n\t      '134': \"\\u2020\",\n\t      '135': \"\\u2021\",\n\t      '136': \"\\u02C6\",\n\t      '137': \"\\u2030\",\n\t      '138': \"\\u0160\",\n\t      '139': \"\\u2039\",\n\t      '140': \"\\u0152\",\n\t      '142': \"\\u017D\",\n\t      '145': \"\\u2018\",\n\t      '146': \"\\u2019\",\n\t      '147': \"\\u201C\",\n\t      '148': \"\\u201D\",\n\t      '149': \"\\u2022\",\n\t      '150': \"\\u2013\",\n\t      '151': \"\\u2014\",\n\t      '152': \"\\u02DC\",\n\t      '153': \"\\u2122\",\n\t      '154': \"\\u0161\",\n\t      '155': \"\\u203A\",\n\t      '156': \"\\u0153\",\n\t      '158': \"\\u017E\",\n\t      '159': \"\\u0178\"\n\t    };\n\t    var invalidReferenceCodePoints = [1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 64976, 64977, 64978, 64979, 64980, 64981, 64982, 64983, 64984, 64985, 64986, 64987, 64988, 64989, 64990, 64991, 64992, 64993, 64994, 64995, 64996, 64997, 64998, 64999, 65000, 65001, 65002, 65003, 65004, 65005, 65006, 65007, 65534, 65535, 131070, 131071, 196606, 196607, 262142, 262143, 327678, 327679, 393214, 393215, 458750, 458751, 524286, 524287, 589822, 589823, 655358, 655359, 720894, 720895, 786430, 786431, 851966, 851967, 917502, 917503, 983038, 983039, 1048574, 1048575, 1114110, 1114111];\n\t    /*--------------------------------------------------------------------------*/\n\n\t    var stringFromCharCode = String.fromCharCode;\n\t    var object = {};\n\t    var hasOwnProperty = object.hasOwnProperty;\n\n\t    var has = function has(object, propertyName) {\n\t      return hasOwnProperty.call(object, propertyName);\n\t    };\n\n\t    var contains = function contains(array, value) {\n\t      var index = -1;\n\t      var length = array.length;\n\n\t      while (++index < length) {\n\t        if (array[index] == value) {\n\t          return true;\n\t        }\n\t      }\n\n\t      return false;\n\t    };\n\n\t    var merge = function merge(options, defaults) {\n\t      if (!options) {\n\t        return defaults;\n\t      }\n\n\t      var result = {};\n\t      var key;\n\n\t      for (key in defaults) {\n\t        // A `hasOwnProperty` check is not needed here, since only recognized\n\t        // option names are used anyway. Any others are ignored.\n\t        result[key] = has(options, key) ? options[key] : defaults[key];\n\t      }\n\n\t      return result;\n\t    }; // Modified version of `ucs2encode`; see https://mths.be/punycode.\n\n\n\t    var codePointToSymbol = function codePointToSymbol(codePoint, strict) {\n\t      var output = '';\n\n\t      if (codePoint >= 0xD800 && codePoint <= 0xDFFF || codePoint > 0x10FFFF) {\n\t        // See issue #4:\n\t        // “Otherwise, if the number is in the range 0xD800 to 0xDFFF or is\n\t        // greater than 0x10FFFF, then this is a parse error. Return a U+FFFD\n\t        // REPLACEMENT CHARACTER.”\n\t        if (strict) {\n\t          parseError('character reference outside the permissible Unicode range');\n\t        }\n\n\t        return \"\\uFFFD\";\n\t      }\n\n\t      if (has(decodeMapNumeric, codePoint)) {\n\t        if (strict) {\n\t          parseError('disallowed character reference');\n\t        }\n\n\t        return decodeMapNumeric[codePoint];\n\t      }\n\n\t      if (strict && contains(invalidReferenceCodePoints, codePoint)) {\n\t        parseError('disallowed character reference');\n\t      }\n\n\t      if (codePoint > 0xFFFF) {\n\t        codePoint -= 0x10000;\n\t        output += stringFromCharCode(codePoint >>> 10 & 0x3FF | 0xD800);\n\t        codePoint = 0xDC00 | codePoint & 0x3FF;\n\t      }\n\n\t      output += stringFromCharCode(codePoint);\n\t      return output;\n\t    };\n\n\t    var hexEscape = function hexEscape(codePoint) {\n\t      return '&#x' + codePoint.toString(16).toUpperCase() + ';';\n\t    };\n\n\t    var decEscape = function decEscape(codePoint) {\n\t      return '&#' + codePoint + ';';\n\t    };\n\n\t    var parseError = function parseError(message) {\n\t      throw Error('Parse error: ' + message);\n\t    };\n\t    /*--------------------------------------------------------------------------*/\n\n\n\t    var encode = function encode(string, options) {\n\t      options = merge(options, encode.options);\n\t      var strict = options.strict;\n\n\t      if (strict && regexInvalidRawCodePoint.test(string)) {\n\t        parseError('forbidden code point');\n\t      }\n\n\t      var encodeEverything = options.encodeEverything;\n\t      var useNamedReferences = options.useNamedReferences;\n\t      var allowUnsafeSymbols = options.allowUnsafeSymbols;\n\t      var escapeCodePoint = options.decimal ? decEscape : hexEscape;\n\n\t      var escapeBmpSymbol = function escapeBmpSymbol(symbol) {\n\t        return escapeCodePoint(symbol.charCodeAt(0));\n\t      };\n\n\t      if (encodeEverything) {\n\t        // Encode ASCII symbols.\n\t        string = string.replace(regexAsciiWhitelist, function (symbol) {\n\t          // Use named references if requested & possible.\n\t          if (useNamedReferences && has(encodeMap, symbol)) {\n\t            return '&' + encodeMap[symbol] + ';';\n\t          }\n\n\t          return escapeBmpSymbol(symbol);\n\t        }); // Shorten a few escapes that represent two symbols, of which at least one\n\t        // is within the ASCII range.\n\n\t        if (useNamedReferences) {\n\t          string = string.replace(/&gt;\\u20D2/g, '&nvgt;').replace(/&lt;\\u20D2/g, '&nvlt;').replace(/&#x66;&#x6A;/g, '&fjlig;');\n\t        } // Encode non-ASCII symbols.\n\n\n\t        if (useNamedReferences) {\n\t          // Encode non-ASCII symbols that can be replaced with a named reference.\n\t          string = string.replace(regexEncodeNonAscii, function (string) {\n\t            // Note: there is no need to check `has(encodeMap, string)` here.\n\t            return '&' + encodeMap[string] + ';';\n\t          });\n\t        } // Note: any remaining non-ASCII symbols are handled outside of the `if`.\n\n\t      } else if (useNamedReferences) {\n\t        // Apply named character references.\n\t        // Encode `<>\"'&` using named character references.\n\t        if (!allowUnsafeSymbols) {\n\t          string = string.replace(regexEscape, function (string) {\n\t            return '&' + encodeMap[string] + ';'; // no need to check `has()` here\n\t          });\n\t        } // Shorten escapes that represent two symbols, of which at least one is\n\t        // `<>\"'&`.\n\n\n\t        string = string.replace(/&gt;\\u20D2/g, '&nvgt;').replace(/&lt;\\u20D2/g, '&nvlt;'); // Encode non-ASCII symbols that can be replaced with a named reference.\n\n\t        string = string.replace(regexEncodeNonAscii, function (string) {\n\t          // Note: there is no need to check `has(encodeMap, string)` here.\n\t          return '&' + encodeMap[string] + ';';\n\t        });\n\t      } else if (!allowUnsafeSymbols) {\n\t        // Encode `<>\"'&` using hexadecimal escapes, now that they’re not handled\n\t        // using named character references.\n\t        string = string.replace(regexEscape, escapeBmpSymbol);\n\t      }\n\n\t      return string // Encode astral symbols.\n\t      .replace(regexAstralSymbols, function ($0) {\n\t        // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae\n\t        var high = $0.charCodeAt(0);\n\t        var low = $0.charCodeAt(1);\n\t        var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000;\n\t        return escapeCodePoint(codePoint);\n\t      }) // Encode any remaining BMP symbols that are not printable ASCII symbols\n\t      // using a hexadecimal escape.\n\t      .replace(regexBmpWhitelist, escapeBmpSymbol);\n\t    }; // Expose default options (so they can be overridden globally).\n\n\n\t    encode.options = {\n\t      'allowUnsafeSymbols': false,\n\t      'encodeEverything': false,\n\t      'strict': false,\n\t      'useNamedReferences': false,\n\t      'decimal': false\n\t    };\n\n\t    var decode = function decode(html, options) {\n\t      options = merge(options, decode.options);\n\t      var strict = options.strict;\n\n\t      if (strict && regexInvalidEntity.test(html)) {\n\t        parseError('malformed character reference');\n\t      }\n\n\t      return html.replace(regexDecode, function ($0, $1, $2, $3, $4, $5, $6, $7, $8) {\n\t        var codePoint;\n\t        var semicolon;\n\t        var decDigits;\n\t        var hexDigits;\n\t        var reference;\n\t        var next;\n\n\t        if ($1) {\n\t          reference = $1; // Note: there is no need to check `has(decodeMap, reference)`.\n\n\t          return decodeMap[reference];\n\t        }\n\n\t        if ($2) {\n\t          // Decode named character references without trailing `;`, e.g. `&amp`.\n\t          // This is only a parse error if it gets converted to `&`, or if it is\n\t          // followed by `=` in an attribute context.\n\t          reference = $2;\n\t          next = $3;\n\n\t          if (next && options.isAttributeValue) {\n\t            if (strict && next == '=') {\n\t              parseError('`&` did not start a character reference');\n\t            }\n\n\t            return $0;\n\t          } else {\n\t            if (strict) {\n\t              parseError('named character reference was not terminated by a semicolon');\n\t            } // Note: there is no need to check `has(decodeMapLegacy, reference)`.\n\n\n\t            return decodeMapLegacy[reference] + (next || '');\n\t          }\n\t        }\n\n\t        if ($4) {\n\t          // Decode decimal escapes, e.g. `&#119558;`.\n\t          decDigits = $4;\n\t          semicolon = $5;\n\n\t          if (strict && !semicolon) {\n\t            parseError('character reference was not terminated by a semicolon');\n\t          }\n\n\t          codePoint = parseInt(decDigits, 10);\n\t          return codePointToSymbol(codePoint, strict);\n\t        }\n\n\t        if ($6) {\n\t          // Decode hexadecimal escapes, e.g. `&#x1D306;`.\n\t          hexDigits = $6;\n\t          semicolon = $7;\n\n\t          if (strict && !semicolon) {\n\t            parseError('character reference was not terminated by a semicolon');\n\t          }\n\n\t          codePoint = parseInt(hexDigits, 16);\n\t          return codePointToSymbol(codePoint, strict);\n\t        } // If we’re still here, `if ($7)` is implied; it’s an ambiguous\n\t        // ampersand for sure. https://mths.be/notes/ambiguous-ampersands\n\n\n\t        if (strict) {\n\t          parseError('named character reference was not terminated by a semicolon');\n\t        }\n\n\t        return $0;\n\t      });\n\t    }; // Expose default options (so they can be overridden globally).\n\n\n\t    decode.options = {\n\t      'isAttributeValue': false,\n\t      'strict': false\n\t    };\n\n\t    var escape = function escape(string) {\n\t      return string.replace(regexEscape, function ($0) {\n\t        // Note: there is no need to check `has(escapeMap, $0)` here.\n\t        return escapeMap[$0];\n\t      });\n\t    };\n\t    /*--------------------------------------------------------------------------*/\n\n\n\t    var he = {\n\t      'version': '1.2.0',\n\t      'encode': encode,\n\t      'decode': decode,\n\t      'escape': escape,\n\t      'unescape': decode\n\t    }; // Some AMD build optimizers, like r.js, check for specific condition patterns\n\t    // like the following:\n\n\t    if (freeExports && !freeExports.nodeType) {\n\t      if (freeModule) {\n\t        // in Node.js, io.js, or RingoJS v0.8.0+\n\t        freeModule.exports = he;\n\t      } else {\n\t        // in Narwhal or RingoJS v0.7.0-\n\t        for (var key in he) {\n\t          has(he, key) && (freeExports[key] = he[key]);\n\t        }\n\t      }\n\t    } else {\n\t      // in Rhino or a web browser\n\t      root.he = he;\n\t    }\n\t  })(commonjsGlobal);\n\t});\n\n\tvar utils = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * Various utility functions used throughout Mocha's codebase.\n\t   * @module utils\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var nanoid = nonSecure.nanoid;\n\t  var MOCHA_ID_PROP_NAME = '__mocha_id__';\n\t  /**\n\t   * Inherit the prototype methods from one constructor into another.\n\t   *\n\t   * @param {function} ctor - Constructor function which needs to inherit the\n\t   *     prototype.\n\t   * @param {function} superCtor - Constructor function to inherit prototype from.\n\t   * @throws {TypeError} if either constructor is null, or if super constructor\n\t   *     lacks a prototype.\n\t   */\n\n\t  exports.inherits = util.inherits;\n\t  /**\n\t   * Escape special characters in the given string of html.\n\t   *\n\t   * @private\n\t   * @param  {string} html\n\t   * @return {string}\n\t   */\n\n\t  exports.escape = function (html) {\n\t    return he.encode(String(html), {\n\t      useNamedReferences: false\n\t    });\n\t  };\n\t  /**\n\t   * Test if the given obj is type of string.\n\t   *\n\t   * @private\n\t   * @param {Object} obj\n\t   * @return {boolean}\n\t   */\n\n\n\t  exports.isString = function (obj) {\n\t    return typeof obj === 'string';\n\t  };\n\t  /**\n\t   * Compute a slug from the given `str`.\n\t   *\n\t   * @private\n\t   * @param {string} str\n\t   * @return {string}\n\t   */\n\n\n\t  exports.slug = function (str) {\n\t    return str.toLowerCase().replace(/\\s+/g, '-').replace(/[^-\\w]/g, '').replace(/-{2,}/g, '-');\n\t  };\n\t  /**\n\t   * Strip the function definition from `str`, and re-indent for pre whitespace.\n\t   *\n\t   * @param {string} str\n\t   * @return {string}\n\t   */\n\n\n\t  exports.clean = function (str) {\n\t    str = str.replace(/\\r\\n?|[\\n\\u2028\\u2029]/g, '\\n').replace(/^\\uFEFF/, '') // (traditional)->  space/name     parameters    body     (lambda)-> parameters       body   multi-statement/single          keep body content\n\t    .replace(/^function(?:\\s*|\\s+[^(]*)\\([^)]*\\)\\s*\\{((?:.|\\n)*?)\\s*\\}$|^\\([^)]*\\)\\s*=>\\s*(?:\\{((?:.|\\n)*?)\\s*\\}|((?:.|\\n)*))$/, '$1$2$3');\n\t    var spaces = str.match(/^\\n?( *)/)[1].length;\n\t    var tabs = str.match(/^\\n?(\\t*)/)[1].length;\n\t    var re = new RegExp('^\\n?' + (tabs ? '\\t' : ' ') + '{' + (tabs || spaces) + '}', 'gm');\n\t    str = str.replace(re, '');\n\t    return str.trim();\n\t  };\n\t  /**\n\t   * If a value could have properties, and has none, this function is called,\n\t   * which returns a string representation of the empty value.\n\t   *\n\t   * Functions w/ no properties return `'[Function]'`\n\t   * Arrays w/ length === 0 return `'[]'`\n\t   * Objects w/ no properties return `'{}'`\n\t   * All else: return result of `value.toString()`\n\t   *\n\t   * @private\n\t   * @param {*} value The value to inspect.\n\t   * @param {string} typeHint The type of the value\n\t   * @returns {string}\n\t   */\n\n\n\t  function emptyRepresentation(value, typeHint) {\n\t    switch (typeHint) {\n\t      case 'function':\n\t        return '[Function]';\n\n\t      case 'object':\n\t        return '{}';\n\n\t      case 'array':\n\t        return '[]';\n\n\t      default:\n\t        return value.toString();\n\t    }\n\t  }\n\t  /**\n\t   * Takes some variable and asks `Object.prototype.toString()` what it thinks it\n\t   * is.\n\t   *\n\t   * @private\n\t   * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString\n\t   * @param {*} value The value to test.\n\t   * @returns {string} Computed type\n\t   * @example\n\t   * canonicalType({}) // 'object'\n\t   * canonicalType([]) // 'array'\n\t   * canonicalType(1) // 'number'\n\t   * canonicalType(false) // 'boolean'\n\t   * canonicalType(Infinity) // 'number'\n\t   * canonicalType(null) // 'null'\n\t   * canonicalType(new Date()) // 'date'\n\t   * canonicalType(/foo/) // 'regexp'\n\t   * canonicalType('type') // 'string'\n\t   * canonicalType(global) // 'global'\n\t   * canonicalType(new String('foo') // 'object'\n\t   * canonicalType(async function() {}) // 'asyncfunction'\n\t   * canonicalType(await import(name)) // 'module'\n\t   */\n\n\n\t  var canonicalType = exports.canonicalType = function canonicalType(value) {\n\t    if (value === undefined) {\n\t      return 'undefined';\n\t    } else if (value === null) {\n\t      return 'null';\n\t    } else if (isBuffer$2(value)) {\n\t      return 'buffer';\n\t    }\n\n\t    return Object.prototype.toString.call(value).replace(/^\\[.+\\s(.+?)]$/, '$1').toLowerCase();\n\t  };\n\t  /**\n\t   *\n\t   * Returns a general type or data structure of a variable\n\t   * @private\n\t   * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures\n\t   * @param {*} value The value to test.\n\t   * @returns {string} One of undefined, boolean, number, string, bigint, symbol, object\n\t   * @example\n\t   * type({}) // 'object'\n\t   * type([]) // 'array'\n\t   * type(1) // 'number'\n\t   * type(false) // 'boolean'\n\t   * type(Infinity) // 'number'\n\t   * type(null) // 'null'\n\t   * type(new Date()) // 'object'\n\t   * type(/foo/) // 'object'\n\t   * type('type') // 'string'\n\t   * type(global) // 'object'\n\t   * type(new String('foo') // 'string'\n\t   */\n\n\n\t  exports.type = function type(value) {\n\t    // Null is special\n\t    if (value === null) return 'null';\n\t    var primitives = new Set(['undefined', 'boolean', 'number', 'string', 'bigint', 'symbol']);\n\n\t    var _type = _typeof(value);\n\n\t    if (_type === 'function') return _type;\n\t    if (primitives.has(_type)) return _type;\n\t    if (value instanceof String) return 'string';\n\t    if (value instanceof Error) return 'error';\n\t    if (Array.isArray(value)) return 'array';\n\t    return _type;\n\t  };\n\t  /**\n\t   * Stringify `value`. Different behavior depending on type of value:\n\t   *\n\t   * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.\n\t   * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.\n\t   * - If `value` is an *empty* object, function, or array, return result of function\n\t   *   {@link emptyRepresentation}.\n\t   * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of\n\t   *   JSON.stringify().\n\t   *\n\t   * @private\n\t   * @see exports.type\n\t   * @param {*} value\n\t   * @return {string}\n\t   */\n\n\n\t  exports.stringify = function (value) {\n\t    var typeHint = canonicalType(value);\n\n\t    if (!~['object', 'array', 'function'].indexOf(typeHint)) {\n\t      if (typeHint === 'buffer') {\n\t        var json = Buffer$1.prototype.toJSON.call(value); // Based on the toJSON result\n\n\t        return jsonStringify(json.data && json.type ? json.data : json, 2).replace(/,(\\n|$)/g, '$1');\n\t      } // IE7/IE8 has a bizarre String constructor; needs to be coerced\n\t      // into an array and back to obj.\n\n\n\t      if (typeHint === 'string' && _typeof(value) === 'object') {\n\t        value = value.split('').reduce(function (acc, _char, idx) {\n\t          acc[idx] = _char;\n\t          return acc;\n\t        }, {});\n\t        typeHint = 'object';\n\t      } else {\n\t        return jsonStringify(value);\n\t      }\n\t    }\n\n\t    for (var prop in value) {\n\t      if (Object.prototype.hasOwnProperty.call(value, prop)) {\n\t        return jsonStringify(exports.canonicalize(value, null, typeHint), 2).replace(/,(\\n|$)/g, '$1');\n\t      }\n\t    }\n\n\t    return emptyRepresentation(value, typeHint);\n\t  };\n\t  /**\n\t   * like JSON.stringify but more sense.\n\t   *\n\t   * @private\n\t   * @param {Object}  object\n\t   * @param {number=} spaces\n\t   * @param {number=} depth\n\t   * @returns {*}\n\t   */\n\n\n\t  function jsonStringify(object, spaces, depth) {\n\t    if (typeof spaces === 'undefined') {\n\t      // primitive types\n\t      return _stringify(object);\n\t    }\n\n\t    depth = depth || 1;\n\t    var space = spaces * depth;\n\t    var str = Array.isArray(object) ? '[' : '{';\n\t    var end = Array.isArray(object) ? ']' : '}';\n\t    var length = typeof object.length === 'number' ? object.length : Object.keys(object).length; // `.repeat()` polyfill\n\n\t    function repeat(s, n) {\n\t      return new Array(n).join(s);\n\t    }\n\n\t    function _stringify(val) {\n\t      switch (canonicalType(val)) {\n\t        case 'null':\n\t        case 'undefined':\n\t          val = '[' + val + ']';\n\t          break;\n\n\t        case 'array':\n\t        case 'object':\n\t          val = jsonStringify(val, spaces, depth + 1);\n\t          break;\n\n\t        case 'boolean':\n\t        case 'regexp':\n\t        case 'symbol':\n\t        case 'number':\n\t          val = val === 0 && 1 / val === -Infinity // `-0`\n\t          ? '-0' : val.toString();\n\t          break;\n\n\t        case 'bigint':\n\t          val = val.toString() + 'n';\n\t          break;\n\n\t        case 'date':\n\t          var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();\n\t          val = '[Date: ' + sDate + ']';\n\t          break;\n\n\t        case 'buffer':\n\t          var json = val.toJSON(); // Based on the toJSON result\n\n\t          json = json.data && json.type ? json.data : json;\n\t          val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';\n\t          break;\n\n\t        default:\n\t          val = val === '[Function]' || val === '[Circular]' ? val : JSON.stringify(val);\n\t        // string\n\t      }\n\n\t      return val;\n\t    }\n\n\t    for (var i in object) {\n\t      if (!Object.prototype.hasOwnProperty.call(object, i)) {\n\t        continue; // not my business\n\t      }\n\n\t      --length;\n\t      str += '\\n ' + repeat(' ', space) + (Array.isArray(object) ? '' : '\"' + i + '\": ') + // key\n\t      _stringify(object[i]) + ( // value\n\t      length ? ',' : ''); // comma\n\t    }\n\n\t    return str + ( // [], {}\n\t    str.length !== 1 ? '\\n' + repeat(' ', --space) + end : end);\n\t  }\n\t  /**\n\t   * Return a new Thing that has the keys in sorted order. Recursive.\n\t   *\n\t   * If the Thing...\n\t   * - has already been seen, return string `'[Circular]'`\n\t   * - is `undefined`, return string `'[undefined]'`\n\t   * - is `null`, return value `null`\n\t   * - is some other primitive, return the value\n\t   * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method\n\t   * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.\n\t   * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`\n\t   *\n\t   * @private\n\t   * @see {@link exports.stringify}\n\t   * @param {*} value Thing to inspect.  May or may not have properties.\n\t   * @param {Array} [stack=[]] Stack of seen values\n\t   * @param {string} [typeHint] Type hint\n\t   * @return {(Object|Array|Function|string|undefined)}\n\t   */\n\n\n\t  exports.canonicalize = function canonicalize(value, stack, typeHint) {\n\t    var canonicalizedObj;\n\t    /* eslint-disable no-unused-vars */\n\n\t    var prop;\n\t    /* eslint-enable no-unused-vars */\n\n\t    typeHint = typeHint || canonicalType(value);\n\n\t    function withStack(value, fn) {\n\t      stack.push(value);\n\t      fn();\n\t      stack.pop();\n\t    }\n\n\t    stack = stack || [];\n\n\t    if (stack.indexOf(value) !== -1) {\n\t      return '[Circular]';\n\t    }\n\n\t    switch (typeHint) {\n\t      case 'undefined':\n\t      case 'buffer':\n\t      case 'null':\n\t        canonicalizedObj = value;\n\t        break;\n\n\t      case 'array':\n\t        withStack(value, function () {\n\t          canonicalizedObj = value.map(function (item) {\n\t            return exports.canonicalize(item, stack);\n\t          });\n\t        });\n\t        break;\n\n\t      case 'function':\n\t        /* eslint-disable-next-line no-unused-vars, no-unreachable-loop */\n\t        for (prop in value) {\n\t          canonicalizedObj = {};\n\t          break;\n\t        }\n\t        /* eslint-enable guard-for-in */\n\n\n\t        if (!canonicalizedObj) {\n\t          canonicalizedObj = emptyRepresentation(value, typeHint);\n\t          break;\n\t        }\n\n\t      /* falls through */\n\n\t      case 'object':\n\t        canonicalizedObj = canonicalizedObj || {};\n\t        withStack(value, function () {\n\t          Object.keys(value).sort().forEach(function (key) {\n\t            canonicalizedObj[key] = exports.canonicalize(value[key], stack);\n\t          });\n\t        });\n\t        break;\n\n\t      case 'date':\n\t      case 'number':\n\t      case 'regexp':\n\t      case 'boolean':\n\t      case 'symbol':\n\t        canonicalizedObj = value;\n\t        break;\n\n\t      default:\n\t        canonicalizedObj = value + '';\n\t    }\n\n\t    return canonicalizedObj;\n\t  };\n\t  /**\n\t   * @summary\n\t   * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)\n\t   * @description\n\t   * When invoking this function you get a filter function that get the Error.stack as an input,\n\t   * and return a prettify output.\n\t   * (i.e: strip Mocha and internal node functions from stack trace).\n\t   * @returns {Function}\n\t   */\n\n\n\t  exports.stackTraceFilter = function () {\n\t    // TODO: Replace with `process.browser`\n\t    var is = typeof document === 'undefined' ? {\n\t      node: true\n\t    } : {\n\t      browser: true\n\t    };\n\t    var slash = path.sep;\n\t    var cwd;\n\n\t    if (is.node) {\n\t      cwd = exports.cwd() + slash;\n\t    } else {\n\t      cwd = (typeof location === 'undefined' ? window.location : location).href.replace(/\\/[^/]*$/, '/');\n\t      slash = '/';\n\t    }\n\n\t    function isMochaInternal(line) {\n\t      return ~line.indexOf('node_modules' + slash + 'mocha' + slash) || ~line.indexOf(slash + 'mocha.js') || ~line.indexOf(slash + 'mocha.min.js');\n\t    }\n\n\t    function isNodeInternal(line) {\n\t      return ~line.indexOf('(timers.js:') || ~line.indexOf('(events.js:') || ~line.indexOf('(node.js:') || ~line.indexOf('(module.js:') || ~line.indexOf('GeneratorFunctionPrototype.next (native)') || false;\n\t    }\n\n\t    return function (stack) {\n\t      stack = stack.split('\\n');\n\t      stack = stack.reduce(function (list, line) {\n\t        if (isMochaInternal(line)) {\n\t          return list;\n\t        }\n\n\t        if (is.node && isNodeInternal(line)) {\n\t          return list;\n\t        } // Clean up cwd(absolute)\n\n\n\t        if (/:\\d+:\\d+\\)?$/.test(line)) {\n\t          line = line.replace('(' + cwd, '(');\n\t        }\n\n\t        list.push(line);\n\t        return list;\n\t      }, []);\n\t      return stack.join('\\n');\n\t    };\n\t  };\n\t  /**\n\t   * Crude, but effective.\n\t   * @public\n\t   * @param {*} value\n\t   * @returns {boolean} Whether or not `value` is a Promise\n\t   */\n\n\n\t  exports.isPromise = function isPromise(value) {\n\t    return _typeof(value) === 'object' && value !== null && typeof value.then === 'function';\n\t  };\n\t  /**\n\t   * Clamps a numeric value to an inclusive range.\n\t   *\n\t   * @param {number} value - Value to be clamped.\n\t   * @param {number[]} range - Two element array specifying [min, max] range.\n\t   * @returns {number} clamped value\n\t   */\n\n\n\t  exports.clamp = function clamp(value, range) {\n\t    return Math.min(Math.max(value, range[0]), range[1]);\n\t  };\n\t  /**\n\t   * It's a noop.\n\t   * @public\n\t   */\n\n\n\t  exports.noop = function () {};\n\t  /**\n\t   * Creates a map-like object.\n\t   *\n\t   * @description\n\t   * A \"map\" is an object with no prototype, for our purposes. In some cases\n\t   * this would be more appropriate than a `Map`, especially if your environment\n\t   * doesn't support it. Recommended for use in Mocha's public APIs.\n\t   *\n\t   * @public\n\t   * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Custom_and_Null_objects|MDN:Map}\n\t   * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects}\n\t   * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Custom_and_Null_objects|MDN:Object.assign}\n\t   * @param {...*} [obj] - Arguments to `Object.assign()`.\n\t   * @returns {Object} An object with no prototype, having `...obj` properties\n\t   */\n\n\n\t  exports.createMap = function (obj) {\n\t    return Object.assign.apply(null, [Object.create(null)].concat(Array.prototype.slice.call(arguments)));\n\t  };\n\t  /**\n\t   * Creates a read-only map-like object.\n\t   *\n\t   * @description\n\t   * This differs from {@link module:utils.createMap createMap} only in that\n\t   * the argument must be non-empty, because the result is frozen.\n\t   *\n\t   * @see {@link module:utils.createMap createMap}\n\t   * @param {...*} [obj] - Arguments to `Object.assign()`.\n\t   * @returns {Object} A frozen object with no prototype, having `...obj` properties\n\t   * @throws {TypeError} if argument is not a non-empty object.\n\t   */\n\n\n\t  exports.defineConstants = function (obj) {\n\t    if (canonicalType(obj) !== 'object' || !Object.keys(obj).length) {\n\t      throw new TypeError('Invalid argument; expected a non-empty object');\n\t    }\n\n\t    return Object.freeze(exports.createMap(obj));\n\t  };\n\t  /**\n\t   * Returns current working directory\n\t   *\n\t   * Wrapper around `process.cwd()` for isolation\n\t   * @private\n\t   */\n\n\n\t  exports.cwd = function cwd() {\n\t    return process$4.cwd();\n\t  };\n\t  /**\n\t   * Returns `true` if Mocha is running in a browser.\n\t   * Checks for `process.browser`.\n\t   * @returns {boolean}\n\t   * @private\n\t   */\n\n\n\t  exports.isBrowser = function isBrowser() {\n\t    return Boolean(browser$2);\n\t  };\n\t  /*\n\t   * Casts `value` to an array; useful for optionally accepting array parameters\n\t   *\n\t   * It follows these rules, depending on `value`.  If `value` is...\n\t   * 1. `undefined`: return an empty Array\n\t   * 2. `null`: return an array with a single `null` element\n\t   * 3. Any other object: return the value of `Array.from()` _if_ the object is iterable\n\t   * 4. otherwise: return an array with a single element, `value`\n\t   * @param {*} value - Something to cast to an Array\n\t   * @returns {Array<*>}\n\t   */\n\n\n\t  exports.castArray = function castArray(value) {\n\t    if (value === undefined) {\n\t      return [];\n\t    }\n\n\t    if (value === null) {\n\t      return [null];\n\t    }\n\n\t    if (_typeof(value) === 'object' && (typeof value[Symbol.iterator] === 'function' || value.length !== undefined)) {\n\t      return Array.from(value);\n\t    }\n\n\t    return [value];\n\t  };\n\n\t  exports.constants = exports.defineConstants({\n\t    MOCHA_ID_PROP_NAME: MOCHA_ID_PROP_NAME\n\t  });\n\t  /**\n\t   * Creates a new unique identifier\n\t   * @returns {string} Unique identifier\n\t   */\n\n\t  exports.uniqueID = function () {\n\t    return nanoid();\n\t  };\n\n\t  exports.assignNewMochaID = function (obj) {\n\t    var id = exports.uniqueID();\n\t    Object.defineProperty(obj, MOCHA_ID_PROP_NAME, {\n\t      get: function get() {\n\t        return id;\n\t      }\n\t    });\n\t    return obj;\n\t  };\n\t  /**\n\t   * Retrieves a Mocha ID from an object, if present.\n\t   * @param {*} [obj] - Object\n\t   * @returns {string|void}\n\t   */\n\n\n\t  exports.getMochaID = function (obj) {\n\t    return obj && _typeof(obj) === 'object' ? obj[MOCHA_ID_PROP_NAME] : undefined;\n\t  };\n\t});\n\n\tvar _nodeResolve_empty = {};\n\n\tvar _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({\n\t\t__proto__: null,\n\t\t'default': _nodeResolve_empty\n\t});\n\n\tvar browser$1 = {\n\t  info: 'ℹ️',\n\t  success: '✅',\n\t  warning: '⚠️',\n\t  error: '❌️'\n\t};\n\n\t// `Map` constructor\n\t// https://tc39.es/ecma262/#sec-map-objects\n\tcollection('Map', function (init) {\n\t  return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };\n\t}, collectionStrong);\n\n\t/**\n\t @module Pending\n\t*/\n\n\tvar pending = Pending;\n\t/**\n\t * Initialize a new `Pending` error with the given message.\n\t *\n\t * @param {string} message\n\t */\n\n\tfunction Pending(message) {\n\t  this.message = message;\n\t}\n\n\t/**\n\t * Helpers.\n\t */\n\tvar s = 1000;\n\tvar m = s * 60;\n\tvar h = m * 60;\n\tvar d = h * 24;\n\tvar w = d * 7;\n\tvar y = d * 365.25;\n\t/**\n\t * Parse or format the given `val`.\n\t *\n\t * Options:\n\t *\n\t *  - `long` verbose formatting [false]\n\t *\n\t * @param {String|Number} val\n\t * @param {Object} [options]\n\t * @throws {Error} throw an error if val is not a non-empty string or a number\n\t * @return {String|Number}\n\t * @api public\n\t */\n\n\tvar ms = function ms(val, options) {\n\t  options = options || {};\n\n\t  var type = _typeof(val);\n\n\t  if (type === 'string' && val.length > 0) {\n\t    return parse(val);\n\t  } else if (type === 'number' && isFinite(val)) {\n\t    return options[\"long\"] ? fmtLong(val) : fmtShort(val);\n\t  }\n\n\t  throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val));\n\t};\n\t/**\n\t * Parse the given `str` and return milliseconds.\n\t *\n\t * @param {String} str\n\t * @return {Number}\n\t * @api private\n\t */\n\n\n\tfunction parse(str) {\n\t  str = String(str);\n\n\t  if (str.length > 100) {\n\t    return;\n\t  }\n\n\t  var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);\n\n\t  if (!match) {\n\t    return;\n\t  }\n\n\t  var n = parseFloat(match[1]);\n\t  var type = (match[2] || 'ms').toLowerCase();\n\n\t  switch (type) {\n\t    case 'years':\n\t    case 'year':\n\t    case 'yrs':\n\t    case 'yr':\n\t    case 'y':\n\t      return n * y;\n\n\t    case 'weeks':\n\t    case 'week':\n\t    case 'w':\n\t      return n * w;\n\n\t    case 'days':\n\t    case 'day':\n\t    case 'd':\n\t      return n * d;\n\n\t    case 'hours':\n\t    case 'hour':\n\t    case 'hrs':\n\t    case 'hr':\n\t    case 'h':\n\t      return n * h;\n\n\t    case 'minutes':\n\t    case 'minute':\n\t    case 'mins':\n\t    case 'min':\n\t    case 'm':\n\t      return n * m;\n\n\t    case 'seconds':\n\t    case 'second':\n\t    case 'secs':\n\t    case 'sec':\n\t    case 's':\n\t      return n * s;\n\n\t    case 'milliseconds':\n\t    case 'millisecond':\n\t    case 'msecs':\n\t    case 'msec':\n\t    case 'ms':\n\t      return n;\n\n\t    default:\n\t      return undefined;\n\t  }\n\t}\n\t/**\n\t * Short format for `ms`.\n\t *\n\t * @param {Number} ms\n\t * @return {String}\n\t * @api private\n\t */\n\n\n\tfunction fmtShort(ms) {\n\t  var msAbs = Math.abs(ms);\n\n\t  if (msAbs >= d) {\n\t    return Math.round(ms / d) + 'd';\n\t  }\n\n\t  if (msAbs >= h) {\n\t    return Math.round(ms / h) + 'h';\n\t  }\n\n\t  if (msAbs >= m) {\n\t    return Math.round(ms / m) + 'm';\n\t  }\n\n\t  if (msAbs >= s) {\n\t    return Math.round(ms / s) + 's';\n\t  }\n\n\t  return ms + 'ms';\n\t}\n\t/**\n\t * Long format for `ms`.\n\t *\n\t * @param {Number} ms\n\t * @return {String}\n\t * @api private\n\t */\n\n\n\tfunction fmtLong(ms) {\n\t  var msAbs = Math.abs(ms);\n\n\t  if (msAbs >= d) {\n\t    return plural(ms, msAbs, d, 'day');\n\t  }\n\n\t  if (msAbs >= h) {\n\t    return plural(ms, msAbs, h, 'hour');\n\t  }\n\n\t  if (msAbs >= m) {\n\t    return plural(ms, msAbs, m, 'minute');\n\t  }\n\n\t  if (msAbs >= s) {\n\t    return plural(ms, msAbs, s, 'second');\n\t  }\n\n\t  return ms + ' ms';\n\t}\n\t/**\n\t * Pluralization helper.\n\t */\n\n\n\tfunction plural(ms, msAbs, n, name) {\n\t  var isPlural = msAbs >= n * 1.5;\n\t  return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n\t}\n\n\t/**\n\t * This is the common logic for both the Node.js and web browser\n\t * implementations of `debug()`.\n\t */\n\n\tfunction setup(env) {\n\t  createDebug.debug = createDebug;\n\t  createDebug[\"default\"] = createDebug;\n\t  createDebug.coerce = coerce;\n\t  createDebug.disable = disable;\n\t  createDebug.enable = enable;\n\t  createDebug.enabled = enabled;\n\t  createDebug.humanize = ms;\n\t  createDebug.destroy = destroy;\n\t  Object.keys(env).forEach(function (key) {\n\t    createDebug[key] = env[key];\n\t  });\n\t  /**\n\t  * The currently active debug mode names, and names to skip.\n\t  */\n\n\t  createDebug.names = [];\n\t  createDebug.skips = [];\n\t  /**\n\t  * Map of special \"%n\" handling functions, for the debug \"format\" argument.\n\t  *\n\t  * Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n\t  */\n\n\t  createDebug.formatters = {};\n\t  /**\n\t  * Selects a color for a debug namespace\n\t  * @param {String} namespace The namespace string for the debug instance to be colored\n\t  * @return {Number|String} An ANSI color code for the given namespace\n\t  * @api private\n\t  */\n\n\t  function selectColor(namespace) {\n\t    var hash = 0;\n\n\t    for (var i = 0; i < namespace.length; i++) {\n\t      hash = (hash << 5) - hash + namespace.charCodeAt(i);\n\t      hash |= 0; // Convert to 32bit integer\n\t    }\n\n\t    return createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n\t  }\n\n\t  createDebug.selectColor = selectColor;\n\t  /**\n\t  * Create a debugger with the given `namespace`.\n\t  *\n\t  * @param {String} namespace\n\t  * @return {Function}\n\t  * @api public\n\t  */\n\n\t  function createDebug(namespace) {\n\t    var prevTime;\n\t    var enableOverride = null;\n\t    var namespacesCache;\n\t    var enabledCache;\n\n\t    function debug() {\n\t      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n\t        args[_key] = arguments[_key];\n\t      }\n\n\t      // Disabled?\n\t      if (!debug.enabled) {\n\t        return;\n\t      }\n\n\t      var self = debug; // Set `diff` timestamp\n\n\t      var curr = Number(new Date());\n\t      var ms = curr - (prevTime || curr);\n\t      self.diff = ms;\n\t      self.prev = prevTime;\n\t      self.curr = curr;\n\t      prevTime = curr;\n\t      args[0] = createDebug.coerce(args[0]);\n\n\t      if (typeof args[0] !== 'string') {\n\t        // Anything else let's inspect with %O\n\t        args.unshift('%O');\n\t      } // Apply any `formatters` transformations\n\n\n\t      var index = 0;\n\t      args[0] = args[0].replace(/%([a-zA-Z%])/g, function (match, format) {\n\t        // If we encounter an escaped % then don't increase the array index\n\t        if (match === '%%') {\n\t          return '%';\n\t        }\n\n\t        index++;\n\t        var formatter = createDebug.formatters[format];\n\n\t        if (typeof formatter === 'function') {\n\t          var val = args[index];\n\t          match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format`\n\n\t          args.splice(index, 1);\n\t          index--;\n\t        }\n\n\t        return match;\n\t      }); // Apply env-specific formatting (colors, etc.)\n\n\t      createDebug.formatArgs.call(self, args);\n\t      var logFn = self.log || createDebug.log;\n\t      logFn.apply(self, args);\n\t    }\n\n\t    debug.namespace = namespace;\n\t    debug.useColors = createDebug.useColors();\n\t    debug.color = createDebug.selectColor(namespace);\n\t    debug.extend = extend;\n\t    debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n\t    Object.defineProperty(debug, 'enabled', {\n\t      enumerable: true,\n\t      configurable: false,\n\t      get: function get() {\n\t        if (enableOverride !== null) {\n\t          return enableOverride;\n\t        }\n\n\t        if (namespacesCache !== createDebug.namespaces) {\n\t          namespacesCache = createDebug.namespaces;\n\t          enabledCache = createDebug.enabled(namespace);\n\t        }\n\n\t        return enabledCache;\n\t      },\n\t      set: function set(v) {\n\t        enableOverride = v;\n\t      }\n\t    }); // Env-specific initialization logic for debug instances\n\n\t    if (typeof createDebug.init === 'function') {\n\t      createDebug.init(debug);\n\t    }\n\n\t    return debug;\n\t  }\n\n\t  function extend(namespace, delimiter) {\n\t    var newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n\t    newDebug.log = this.log;\n\t    return newDebug;\n\t  }\n\t  /**\n\t  * Enables a debug mode by namespaces. This can include modes\n\t  * separated by a colon and wildcards.\n\t  *\n\t  * @param {String} namespaces\n\t  * @api public\n\t  */\n\n\n\t  function enable(namespaces) {\n\t    createDebug.save(namespaces);\n\t    createDebug.namespaces = namespaces;\n\t    createDebug.names = [];\n\t    createDebug.skips = [];\n\t    var i;\n\t    var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\\s,]+/);\n\t    var len = split.length;\n\n\t    for (i = 0; i < len; i++) {\n\t      if (!split[i]) {\n\t        // ignore empty strings\n\t        continue;\n\t      }\n\n\t      namespaces = split[i].replace(/\\*/g, '.*?');\n\n\t      if (namespaces[0] === '-') {\n\t        createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));\n\t      } else {\n\t        createDebug.names.push(new RegExp('^' + namespaces + '$'));\n\t      }\n\t    }\n\t  }\n\t  /**\n\t  * Disable debug output.\n\t  *\n\t  * @return {String} namespaces\n\t  * @api public\n\t  */\n\n\n\t  function disable() {\n\t    var namespaces = [].concat(_toConsumableArray(createDebug.names.map(toNamespace)), _toConsumableArray(createDebug.skips.map(toNamespace).map(function (namespace) {\n\t      return '-' + namespace;\n\t    }))).join(',');\n\t    createDebug.enable('');\n\t    return namespaces;\n\t  }\n\t  /**\n\t  * Returns true if the given mode name is enabled, false otherwise.\n\t  *\n\t  * @param {String} name\n\t  * @return {Boolean}\n\t  * @api public\n\t  */\n\n\n\t  function enabled(name) {\n\t    if (name[name.length - 1] === '*') {\n\t      return true;\n\t    }\n\n\t    var i;\n\t    var len;\n\n\t    for (i = 0, len = createDebug.skips.length; i < len; i++) {\n\t      if (createDebug.skips[i].test(name)) {\n\t        return false;\n\t      }\n\t    }\n\n\t    for (i = 0, len = createDebug.names.length; i < len; i++) {\n\t      if (createDebug.names[i].test(name)) {\n\t        return true;\n\t      }\n\t    }\n\n\t    return false;\n\t  }\n\t  /**\n\t  * Convert regexp to namespace\n\t  *\n\t  * @param {RegExp} regxep\n\t  * @return {String} namespace\n\t  * @api private\n\t  */\n\n\n\t  function toNamespace(regexp) {\n\t    return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\\.\\*\\?$/, '*');\n\t  }\n\t  /**\n\t  * Coerce `val`.\n\t  *\n\t  * @param {Mixed} val\n\t  * @return {Mixed}\n\t  * @api private\n\t  */\n\n\n\t  function coerce(val) {\n\t    if (val instanceof Error) {\n\t      return val.stack || val.message;\n\t    }\n\n\t    return val;\n\t  }\n\t  /**\n\t  * XXX DO NOT USE. This is a temporary stub function.\n\t  * XXX It WILL be removed in the next major release.\n\t  */\n\n\n\t  function destroy() {\n\t    console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t  }\n\n\t  createDebug.enable(createDebug.load());\n\t  return createDebug;\n\t}\n\n\tvar common$1 = setup;\n\n\tvar browser = createCommonjsModule(function (module, exports) {\n\t  /* eslint-env browser */\n\n\t  /**\n\t   * This is the web browser implementation of `debug()`.\n\t   */\n\t  exports.formatArgs = formatArgs;\n\t  exports.save = save;\n\t  exports.load = load;\n\t  exports.useColors = useColors;\n\t  exports.storage = localstorage();\n\n\t  exports.destroy = function () {\n\t    var warned = false;\n\t    return function () {\n\t      if (!warned) {\n\t        warned = true;\n\t        console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n\t      }\n\t    };\n\t  }();\n\t  /**\n\t   * Colors.\n\t   */\n\n\n\t  exports.colors = ['#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33'];\n\t  /**\n\t   * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n\t   * and the Firebug extension (any Firefox version) are known\n\t   * to support \"%c\" CSS customizations.\n\t   *\n\t   * TODO: add a `localStorage` variable to explicitly enable/disable colors\n\t   */\n\t  // eslint-disable-next-line complexity\n\n\t  function useColors() {\n\t    // NB: In an Electron preload script, document will be defined but not fully\n\t    // initialized. Since we know we're in Chrome, we'll just detect this case\n\t    // explicitly\n\t    if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n\t      return true;\n\t    } // Internet Explorer and Edge do not support colors.\n\n\n\t    if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n\t      return false;\n\t    } // Is webkit? http://stackoverflow.com/a/16459606/376773\n\t    // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n\n\n\t    return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773\n\t    typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?\n\t    // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n\t    typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker\n\t    typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/);\n\t  }\n\t  /**\n\t   * Colorize log arguments if enabled.\n\t   *\n\t   * @api public\n\t   */\n\n\n\t  function formatArgs(args) {\n\t    args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff);\n\n\t    if (!this.useColors) {\n\t      return;\n\t    }\n\n\t    var c = 'color: ' + this.color;\n\t    args.splice(1, 0, c, 'color: inherit'); // The final \"%c\" is somewhat tricky, because there could be other\n\t    // arguments passed either before or after the %c, so we need to\n\t    // figure out the correct index to insert the CSS into\n\n\t    var index = 0;\n\t    var lastC = 0;\n\t    args[0].replace(/%[a-zA-Z%]/g, function (match) {\n\t      if (match === '%%') {\n\t        return;\n\t      }\n\n\t      index++;\n\n\t      if (match === '%c') {\n\t        // We only are interested in the *last* %c\n\t        // (the user may have provided their own)\n\t        lastC = index;\n\t      }\n\t    });\n\t    args.splice(lastC, 0, c);\n\t  }\n\t  /**\n\t   * Invokes `console.debug()` when available.\n\t   * No-op when `console.debug` is not a \"function\".\n\t   * If `console.debug` is not available, falls back\n\t   * to `console.log`.\n\t   *\n\t   * @api public\n\t   */\n\n\n\t  exports.log = console.debug || console.log || function () {};\n\t  /**\n\t   * Save `namespaces`.\n\t   *\n\t   * @param {String} namespaces\n\t   * @api private\n\t   */\n\n\n\t  function save(namespaces) {\n\t    try {\n\t      if (namespaces) {\n\t        exports.storage.setItem('debug', namespaces);\n\t      } else {\n\t        exports.storage.removeItem('debug');\n\t      }\n\t    } catch (error) {// Swallow\n\t      // XXX (@Qix-) should we be logging these?\n\t    }\n\t  }\n\t  /**\n\t   * Load `namespaces`.\n\t   *\n\t   * @return {String} returns the previously persisted debug modes\n\t   * @api private\n\t   */\n\n\n\t  function load() {\n\t    var r;\n\n\t    try {\n\t      r = exports.storage.getItem('debug');\n\t    } catch (error) {// Swallow\n\t      // XXX (@Qix-) should we be logging these?\n\t    } // If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n\n\n\t    if (!r && typeof process$4 !== 'undefined' && 'env' in process$4) {\n\t      r = process$4.env.DEBUG;\n\t    }\n\n\t    return r;\n\t  }\n\t  /**\n\t   * Localstorage attempts to return the localstorage.\n\t   *\n\t   * This is necessary because safari throws\n\t   * when a user disables cookies/localstorage\n\t   * and you attempt to access it.\n\t   *\n\t   * @return {LocalStorage}\n\t   * @api private\n\t   */\n\n\n\t  function localstorage() {\n\t    try {\n\t      // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n\t      // The Browser also has localStorage in the global context.\n\t      return localStorage;\n\t    } catch (error) {// Swallow\n\t      // XXX (@Qix-) should we be logging these?\n\t    }\n\t  }\n\n\t  module.exports = common$1(exports);\n\t  var formatters = module.exports.formatters;\n\t  /**\n\t   * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n\t   */\n\n\t  formatters.j = function (v) {\n\t    try {\n\t      return JSON.stringify(v);\n\t    } catch (error) {\n\t      return '[UnexpectedJSONParseError]: ' + error.message;\n\t    }\n\t  };\n\t});\n\n\tvar $propertyIsEnumerable = objectPropertyIsEnumerable.f;\n\n\tvar propertyIsEnumerable = functionUncurryThis($propertyIsEnumerable);\n\tvar push = functionUncurryThis([].push);\n\n\t// `Object.{ entries, values }` methods implementation\n\tvar createMethod = function (TO_ENTRIES) {\n\t  return function (it) {\n\t    var O = toIndexedObject(it);\n\t    var keys = objectKeys(O);\n\t    var length = keys.length;\n\t    var i = 0;\n\t    var result = [];\n\t    var key;\n\t    while (length > i) {\n\t      key = keys[i++];\n\t      if (!descriptors || propertyIsEnumerable(O, key)) {\n\t        push(result, TO_ENTRIES ? [key, O[key]] : O[key]);\n\t      }\n\t    }\n\t    return result;\n\t  };\n\t};\n\n\tvar objectToArray = {\n\t  // `Object.entries` method\n\t  // https://tc39.es/ecma262/#sec-object.entries\n\t  entries: createMethod(true),\n\t  // `Object.values` method\n\t  // https://tc39.es/ecma262/#sec-object.values\n\t  values: createMethod(false)\n\t};\n\n\tvar $values = objectToArray.values;\n\n\t// `Object.values` method\n\t// https://tc39.es/ecma262/#sec-object.values\n\t_export({ target: 'Object', stat: true }, {\n\t  values: function values(O) {\n\t    return $values(O);\n\t  }\n\t});\n\n\tvar format = util.format;\n\t/**\n\t * Contains error codes, factory functions to create throwable error objects,\n\t * and warning/deprecation functions.\n\t * @module\n\t */\n\n\t/**\n\t * process.emitWarning or a polyfill\n\t * @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options\n\t * @ignore\n\t */\n\n\tvar emitWarning = function emitWarning(msg, type) {\n\t  if (process$4.emitWarning) {\n\t    process$4.emitWarning(msg, type);\n\t  } else {\n\t    /* istanbul ignore next */\n\t    nextTick$1(function () {\n\t      console.warn(type + ': ' + msg);\n\t    });\n\t  }\n\t};\n\t/**\n\t * Show a deprecation warning. Each distinct message is only displayed once.\n\t * Ignores empty messages.\n\t *\n\t * @param {string} [msg] - Warning to print\n\t * @private\n\t */\n\n\n\tvar deprecate = function deprecate(msg) {\n\t  msg = String(msg);\n\n\t  if (msg && !deprecate.cache[msg]) {\n\t    deprecate.cache[msg] = true;\n\t    emitWarning(msg, 'DeprecationWarning');\n\t  }\n\t};\n\n\tdeprecate.cache = {};\n\t/**\n\t * Show a generic warning.\n\t * Ignores empty messages.\n\t *\n\t * @param {string} [msg] - Warning to print\n\t * @private\n\t */\n\n\tvar warn = function warn(msg) {\n\t  if (msg) {\n\t    emitWarning(msg);\n\t  }\n\t};\n\t/**\n\t * When Mocha throws exceptions (or rejects `Promise`s), it attempts to assign a `code` property to the `Error` object, for easier handling. These are the potential values of `code`.\n\t * @public\n\t * @namespace\n\t * @memberof module:lib/errors\n\t */\n\n\n\tvar constants$4 = {\n\t  /**\n\t   * An unrecoverable error.\n\t   * @constant\n\t   * @default\n\t   */\n\t  FATAL: 'ERR_MOCHA_FATAL',\n\n\t  /**\n\t   * The type of an argument to a function call is invalid\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_ARG_TYPE: 'ERR_MOCHA_INVALID_ARG_TYPE',\n\n\t  /**\n\t   * The value of an argument to a function call is invalid\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_ARG_VALUE: 'ERR_MOCHA_INVALID_ARG_VALUE',\n\n\t  /**\n\t   * Something was thrown, but it wasn't an `Error`\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_EXCEPTION: 'ERR_MOCHA_INVALID_EXCEPTION',\n\n\t  /**\n\t   * An interface (e.g., `Mocha.interfaces`) is unknown or invalid\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_INTERFACE: 'ERR_MOCHA_INVALID_INTERFACE',\n\n\t  /**\n\t   * A reporter (.e.g, `Mocha.reporters`) is unknown or invalid\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_REPORTER: 'ERR_MOCHA_INVALID_REPORTER',\n\n\t  /**\n\t   * `done()` was called twice in a `Test` or `Hook` callback\n\t   * @constant\n\t   * @default\n\t   */\n\t  MULTIPLE_DONE: 'ERR_MOCHA_MULTIPLE_DONE',\n\n\t  /**\n\t   * No files matched the pattern provided by the user\n\t   * @constant\n\t   * @default\n\t   */\n\t  NO_FILES_MATCH_PATTERN: 'ERR_MOCHA_NO_FILES_MATCH_PATTERN',\n\n\t  /**\n\t   * Known, but unsupported behavior of some kind\n\t   * @constant\n\t   * @default\n\t   */\n\t  UNSUPPORTED: 'ERR_MOCHA_UNSUPPORTED',\n\n\t  /**\n\t   * Invalid state transition occurring in `Mocha` instance\n\t   * @constant\n\t   * @default\n\t   */\n\t  INSTANCE_ALREADY_RUNNING: 'ERR_MOCHA_INSTANCE_ALREADY_RUNNING',\n\n\t  /**\n\t   * Invalid state transition occurring in `Mocha` instance\n\t   * @constant\n\t   * @default\n\t   */\n\t  INSTANCE_ALREADY_DISPOSED: 'ERR_MOCHA_INSTANCE_ALREADY_DISPOSED',\n\n\t  /**\n\t   * Use of `only()` w/ `--forbid-only` results in this error.\n\t   * @constant\n\t   * @default\n\t   */\n\t  FORBIDDEN_EXCLUSIVITY: 'ERR_MOCHA_FORBIDDEN_EXCLUSIVITY',\n\n\t  /**\n\t   * To be thrown when a user-defined plugin implementation (e.g., `mochaHooks`) is invalid\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_PLUGIN_IMPLEMENTATION: 'ERR_MOCHA_INVALID_PLUGIN_IMPLEMENTATION',\n\n\t  /**\n\t   * To be thrown when a builtin or third-party plugin definition (the _definition_ of `mochaHooks`) is invalid\n\t   * @constant\n\t   * @default\n\t   */\n\t  INVALID_PLUGIN_DEFINITION: 'ERR_MOCHA_INVALID_PLUGIN_DEFINITION',\n\n\t  /**\n\t   * When a runnable exceeds its allowed run time.\n\t   * @constant\n\t   * @default\n\t   */\n\t  TIMEOUT: 'ERR_MOCHA_TIMEOUT',\n\n\t  /**\n\t   * Input file is not able to be parsed\n\t   * @constant\n\t   * @default\n\t   */\n\t  UNPARSABLE_FILE: 'ERR_MOCHA_UNPARSABLE_FILE'\n\t};\n\t/**\n\t * A set containing all string values of all Mocha error constants, for use by {@link isMochaError}.\n\t * @private\n\t */\n\n\tvar MOCHA_ERRORS = new Set(Object.values(constants$4));\n\t/**\n\t * Creates an error object to be thrown when no files to be tested could be found using specified pattern.\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} pattern - User-specified argument value.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\tfunction createNoFilesMatchPatternError(message, pattern) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.NO_FILES_MATCH_PATTERN;\n\t  err.pattern = pattern;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when the reporter specified in the options was not found.\n\t *\n\t * @public\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} reporter - User-specified reporter value.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createInvalidReporterError(message, reporter) {\n\t  var err = new TypeError(message);\n\t  err.code = constants$4.INVALID_REPORTER;\n\t  err.reporter = reporter;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when the interface specified in the options was not found.\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} ui - User-specified interface value.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createInvalidInterfaceError(message, ui) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.INVALID_INTERFACE;\n\t  err[\"interface\"] = ui;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when a behavior, option, or parameter is unsupported.\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createUnsupportedError$2(message) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.UNSUPPORTED;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when an argument is missing.\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} argument - Argument name.\n\t * @param {string} expected - Expected argument datatype.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createMissingArgumentError$1(message, argument, expected) {\n\t  return createInvalidArgumentTypeError$1(message, argument, expected);\n\t}\n\t/**\n\t * Creates an error object to be thrown when an argument did not use the supported type\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} argument - Argument name.\n\t * @param {string} expected - Expected argument datatype.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createInvalidArgumentTypeError$1(message, argument, expected) {\n\t  var err = new TypeError(message);\n\t  err.code = constants$4.INVALID_ARG_TYPE;\n\t  err.argument = argument;\n\t  err.expected = expected;\n\t  err.actual = _typeof(argument);\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when an argument did not use the supported value\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} argument - Argument name.\n\t * @param {string} value - Argument value.\n\t * @param {string} [reason] - Why value is invalid.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createInvalidArgumentValueError(message, argument, value, reason) {\n\t  var err = new TypeError(message);\n\t  err.code = constants$4.INVALID_ARG_VALUE;\n\t  err.argument = argument;\n\t  err.value = value;\n\t  err.reason = typeof reason !== 'undefined' ? reason : 'is invalid';\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when an exception was caught, but the `Error` is falsy or undefined.\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createInvalidExceptionError$2(message, value) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.INVALID_EXCEPTION;\n\t  err.valueType = _typeof(value);\n\t  err.value = value;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when an unrecoverable error occurs.\n\t *\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @returns {Error} instance detailing the error condition\n\t */\n\n\n\tfunction createFatalError$1(message, value) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.FATAL;\n\t  err.valueType = _typeof(value);\n\t  err.value = value;\n\t  return err;\n\t}\n\t/**\n\t * Dynamically creates a plugin-type-specific error based on plugin type\n\t * @param {string} message - Error message\n\t * @param {\"reporter\"|\"ui\"} pluginType - Plugin type. Future: expand as needed\n\t * @param {string} [pluginId] - Name/path of plugin, if any\n\t * @throws When `pluginType` is not known\n\t * @public\n\t * @static\n\t * @returns {Error}\n\t */\n\n\n\tfunction createInvalidLegacyPluginError(message, pluginType, pluginId) {\n\t  switch (pluginType) {\n\t    case 'reporter':\n\t      return createInvalidReporterError(message, pluginId);\n\n\t    case 'ui':\n\t      return createInvalidInterfaceError(message, pluginId);\n\n\t    default:\n\t      throw new Error('unknown pluginType \"' + pluginType + '\"');\n\t  }\n\t}\n\t/**\n\t * **DEPRECATED**.  Use {@link createInvalidLegacyPluginError} instead  Dynamically creates a plugin-type-specific error based on plugin type\n\t * @deprecated\n\t * @param {string} message - Error message\n\t * @param {\"reporter\"|\"interface\"} pluginType - Plugin type. Future: expand as needed\n\t * @param {string} [pluginId] - Name/path of plugin, if any\n\t * @throws When `pluginType` is not known\n\t * @public\n\t * @static\n\t * @returns {Error}\n\t */\n\n\n\tfunction createInvalidPluginError() {\n\t  deprecate('Use createInvalidLegacyPluginError() instead');\n\t  return createInvalidLegacyPluginError.apply(void 0, arguments);\n\t}\n\t/**\n\t * Creates an error object to be thrown when a mocha object's `run` method is executed while it is already disposed.\n\t * @param {string} message The error message to be displayed.\n\t * @param {boolean} cleanReferencesAfterRun the value of `cleanReferencesAfterRun`\n\t * @param {Mocha} instance the mocha instance that throw this error\n\t * @static\n\t */\n\n\n\tfunction createMochaInstanceAlreadyDisposedError(message, cleanReferencesAfterRun, instance) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.INSTANCE_ALREADY_DISPOSED;\n\t  err.cleanReferencesAfterRun = cleanReferencesAfterRun;\n\t  err.instance = instance;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when a mocha object's `run` method is called while a test run is in progress.\n\t * @param {string} message The error message to be displayed.\n\t * @static\n\t * @public\n\t */\n\n\n\tfunction createMochaInstanceAlreadyRunningError(message, instance) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.INSTANCE_ALREADY_RUNNING;\n\t  err.instance = instance;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when done() is called multiple times in a test\n\t *\n\t * @public\n\t * @param {Runnable} runnable - Original runnable\n\t * @param {Error} [originalErr] - Original error, if any\n\t * @returns {Error} instance detailing the error condition\n\t * @static\n\t */\n\n\n\tfunction createMultipleDoneError$1(runnable, originalErr) {\n\t  var title;\n\n\t  try {\n\t    title = format('<%s>', runnable.fullTitle());\n\n\t    if (runnable.parent.root) {\n\t      title += ' (of root suite)';\n\t    }\n\t  } catch (ignored) {\n\t    title = format('<%s> (of unknown suite)', runnable.title);\n\t  }\n\n\t  var message = format('done() called multiple times in %s %s', runnable.type ? runnable.type : 'unknown runnable', title);\n\n\t  if (runnable.file) {\n\t    message += format(' of file %s', runnable.file);\n\t  }\n\n\t  if (originalErr) {\n\t    message += format('; in addition, done() received error: %s', originalErr);\n\t  }\n\n\t  var err = new Error(message);\n\t  err.code = constants$4.MULTIPLE_DONE;\n\t  err.valueType = _typeof(originalErr);\n\t  err.value = originalErr;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when `.only()` is used with\n\t * `--forbid-only`.\n\t * @static\n\t * @public\n\t * @param {Mocha} mocha - Mocha instance\n\t * @returns {Error} Error with code {@link constants.FORBIDDEN_EXCLUSIVITY}\n\t */\n\n\n\tfunction createForbiddenExclusivityError$1(mocha) {\n\t  var err = new Error(mocha.isWorker ? '`.only` is not supported in parallel mode' : '`.only` forbidden by --forbid-only');\n\t  err.code = constants$4.FORBIDDEN_EXCLUSIVITY;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when a plugin definition is invalid\n\t * @static\n\t * @param {string} msg - Error message\n\t * @param {PluginDefinition} [pluginDef] - Problematic plugin definition\n\t * @public\n\t * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}\n\t */\n\n\n\tfunction createInvalidPluginDefinitionError(msg, pluginDef) {\n\t  var err = new Error(msg);\n\t  err.code = constants$4.INVALID_PLUGIN_DEFINITION;\n\t  err.pluginDef = pluginDef;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when a plugin implementation (user code) is invalid\n\t * @static\n\t * @param {string} msg - Error message\n\t * @param {Object} [opts] - Plugin definition and user-supplied implementation\n\t * @param {PluginDefinition} [opts.pluginDef] - Plugin Definition\n\t * @param {*} [opts.pluginImpl] - Plugin Implementation (user-supplied)\n\t * @public\n\t * @returns {Error} Error with code {@link constants.INVALID_PLUGIN_DEFINITION}\n\t */\n\n\n\tfunction createInvalidPluginImplementationError(msg) {\n\t  var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n\t      pluginDef = _ref.pluginDef,\n\t      pluginImpl = _ref.pluginImpl;\n\n\t  var err = new Error(msg);\n\t  err.code = constants$4.INVALID_PLUGIN_IMPLEMENTATION;\n\t  err.pluginDef = pluginDef;\n\t  err.pluginImpl = pluginImpl;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when a runnable exceeds its allowed run time.\n\t * @static\n\t * @param {string} msg - Error message\n\t * @param {number} [timeout] - Timeout in ms\n\t * @param {string} [file] - File, if given\n\t * @returns {MochaTimeoutError}\n\t */\n\n\n\tfunction createTimeoutError$1(msg, timeout, file) {\n\t  var err = new Error(msg);\n\t  err.code = constants$4.TIMEOUT;\n\t  err.timeout = timeout;\n\t  err.file = file;\n\t  return err;\n\t}\n\t/**\n\t * Creates an error object to be thrown when file is unparsable\n\t * @public\n\t * @static\n\t * @param {string} message - Error message to be displayed.\n\t * @param {string} filename - File name\n\t * @returns {Error} Error with code {@link constants.UNPARSABLE_FILE}\n\t */\n\n\n\tfunction createUnparsableFileError(message, filename) {\n\t  var err = new Error(message);\n\t  err.code = constants$4.UNPARSABLE_FILE;\n\t  return err;\n\t}\n\t/**\n\t * Returns `true` if an error came out of Mocha.\n\t * _Can suffer from false negatives, but not false positives._\n\t * @static\n\t * @public\n\t * @param {*} err - Error, or anything\n\t * @returns {boolean}\n\t */\n\n\n\tvar isMochaError$1 = function isMochaError(err) {\n\t  return Boolean(err && _typeof(err) === 'object' && MOCHA_ERRORS.has(err.code));\n\t};\n\n\tvar errors = {\n\t  constants: constants$4,\n\t  createFatalError: createFatalError$1,\n\t  createForbiddenExclusivityError: createForbiddenExclusivityError$1,\n\t  createInvalidArgumentTypeError: createInvalidArgumentTypeError$1,\n\t  createInvalidArgumentValueError: createInvalidArgumentValueError,\n\t  createInvalidExceptionError: createInvalidExceptionError$2,\n\t  createInvalidInterfaceError: createInvalidInterfaceError,\n\t  createInvalidLegacyPluginError: createInvalidLegacyPluginError,\n\t  createInvalidPluginDefinitionError: createInvalidPluginDefinitionError,\n\t  createInvalidPluginError: createInvalidPluginError,\n\t  createInvalidPluginImplementationError: createInvalidPluginImplementationError,\n\t  createInvalidReporterError: createInvalidReporterError,\n\t  createMissingArgumentError: createMissingArgumentError$1,\n\t  createMochaInstanceAlreadyDisposedError: createMochaInstanceAlreadyDisposedError,\n\t  createMochaInstanceAlreadyRunningError: createMochaInstanceAlreadyRunningError,\n\t  createMultipleDoneError: createMultipleDoneError$1,\n\t  createNoFilesMatchPatternError: createNoFilesMatchPatternError,\n\t  createTimeoutError: createTimeoutError$1,\n\t  createUnparsableFileError: createUnparsableFileError,\n\t  createUnsupportedError: createUnsupportedError$2,\n\t  deprecate: deprecate,\n\t  isMochaError: isMochaError$1,\n\t  warn: warn\n\t};\n\n\tvar EventEmitter$1 = EventEmitter$2.EventEmitter;\n\tvar debug$1 = browser('mocha:runnable');\n\tvar createInvalidExceptionError$1 = errors.createInvalidExceptionError,\n\t    createMultipleDoneError = errors.createMultipleDoneError,\n\t    createTimeoutError = errors.createTimeoutError;\n\t/**\n\t * Save timer references to avoid Sinon interfering (see GH-237).\n\t * @private\n\t */\n\n\tvar Date$4 = commonjsGlobal.Date;\n\tvar setTimeout$3 = commonjsGlobal.setTimeout;\n\tvar clearTimeout$1 = commonjsGlobal.clearTimeout;\n\tvar toString = Object.prototype.toString;\n\tvar runnable = Runnable;\n\t/**\n\t * Initialize a new `Runnable` with the given `title` and callback `fn`.\n\t *\n\t * @class\n\t * @extends external:EventEmitter\n\t * @public\n\t * @param {String} title\n\t * @param {Function} fn\n\t */\n\n\tfunction Runnable(title, fn) {\n\t  this.title = title;\n\t  this.fn = fn;\n\t  this.body = (fn || '').toString();\n\t  this.async = fn && fn.length;\n\t  this.sync = !this.async;\n\t  this._timeout = 2000;\n\t  this._slow = 75;\n\t  this._retries = -1;\n\t  utils.assignNewMochaID(this);\n\t  Object.defineProperty(this, 'id', {\n\t    get: function get() {\n\t      return utils.getMochaID(this);\n\t    }\n\t  });\n\t  this.reset();\n\t}\n\t/**\n\t * Inherit from `EventEmitter.prototype`.\n\t */\n\n\n\tutils.inherits(Runnable, EventEmitter$1);\n\t/**\n\t * Resets the state initially or for a next run.\n\t */\n\n\tRunnable.prototype.reset = function () {\n\t  this.timedOut = false;\n\t  this._currentRetry = 0;\n\t  this.pending = false;\n\t  delete this.state;\n\t  delete this.err;\n\t};\n\t/**\n\t * Get current timeout value in msecs.\n\t *\n\t * @private\n\t * @returns {number} current timeout threshold value\n\t */\n\n\t/**\n\t * @summary\n\t * Set timeout threshold value (msecs).\n\t *\n\t * @description\n\t * A string argument can use shorthand (e.g., \"2s\") and will be converted.\n\t * The value will be clamped to range [<code>0</code>, <code>2^<sup>31</sup>-1</code>].\n\t * If clamped value matches either range endpoint, timeouts will be disabled.\n\t *\n\t * @private\n\t * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value}\n\t * @param {number|string} ms - Timeout threshold value.\n\t * @returns {Runnable} this\n\t * @chainable\n\t */\n\n\n\tRunnable.prototype.timeout = function (ms) {\n\t  if (!arguments.length) {\n\t    return this._timeout;\n\t  }\n\n\t  if (typeof ms === 'string') {\n\t    ms = ms$1(ms);\n\t  } // Clamp to range\n\n\n\t  var INT_MAX = Math.pow(2, 31) - 1;\n\t  var range = [0, INT_MAX];\n\t  ms = utils.clamp(ms, range); // see #1652 for reasoning\n\n\t  if (ms === range[0] || ms === range[1]) {\n\t    this._timeout = 0;\n\t  } else {\n\t    this._timeout = ms;\n\t  }\n\n\t  debug$1('timeout %d', this._timeout);\n\n\t  if (this.timer) {\n\t    this.resetTimeout();\n\t  }\n\n\t  return this;\n\t};\n\t/**\n\t * Set or get slow `ms`.\n\t *\n\t * @private\n\t * @param {number|string} ms\n\t * @return {Runnable|number} ms or Runnable instance.\n\t */\n\n\n\tRunnable.prototype.slow = function (ms) {\n\t  if (!arguments.length || typeof ms === 'undefined') {\n\t    return this._slow;\n\t  }\n\n\t  if (typeof ms === 'string') {\n\t    ms = ms$1(ms);\n\t  }\n\n\t  debug$1('slow %d', ms);\n\t  this._slow = ms;\n\t  return this;\n\t};\n\t/**\n\t * Halt and mark as pending.\n\t *\n\t * @memberof Mocha.Runnable\n\t * @public\n\t */\n\n\n\tRunnable.prototype.skip = function () {\n\t  this.pending = true;\n\t  throw new pending('sync skip; aborting execution');\n\t};\n\t/**\n\t * Check if this runnable or its parent suite is marked as pending.\n\t *\n\t * @private\n\t */\n\n\n\tRunnable.prototype.isPending = function () {\n\t  return this.pending || this.parent && this.parent.isPending();\n\t};\n\t/**\n\t * Return `true` if this Runnable has failed.\n\t * @return {boolean}\n\t * @private\n\t */\n\n\n\tRunnable.prototype.isFailed = function () {\n\t  return !this.isPending() && this.state === constants$3.STATE_FAILED;\n\t};\n\t/**\n\t * Return `true` if this Runnable has passed.\n\t * @return {boolean}\n\t * @private\n\t */\n\n\n\tRunnable.prototype.isPassed = function () {\n\t  return !this.isPending() && this.state === constants$3.STATE_PASSED;\n\t};\n\t/**\n\t * Set or get number of retries.\n\t *\n\t * @private\n\t */\n\n\n\tRunnable.prototype.retries = function (n) {\n\t  if (!arguments.length) {\n\t    return this._retries;\n\t  }\n\n\t  this._retries = n;\n\t};\n\t/**\n\t * Set or get current retry\n\t *\n\t * @private\n\t */\n\n\n\tRunnable.prototype.currentRetry = function (n) {\n\t  if (!arguments.length) {\n\t    return this._currentRetry;\n\t  }\n\n\t  this._currentRetry = n;\n\t};\n\t/**\n\t * Return the full title generated by recursively concatenating the parent's\n\t * full title.\n\t *\n\t * @memberof Mocha.Runnable\n\t * @public\n\t * @return {string}\n\t */\n\n\n\tRunnable.prototype.fullTitle = function () {\n\t  return this.titlePath().join(' ');\n\t};\n\t/**\n\t * Return the title path generated by concatenating the parent's title path with the title.\n\t *\n\t * @memberof Mocha.Runnable\n\t * @public\n\t * @return {string}\n\t */\n\n\n\tRunnable.prototype.titlePath = function () {\n\t  return this.parent.titlePath().concat([this.title]);\n\t};\n\t/**\n\t * Clear the timeout.\n\t *\n\t * @private\n\t */\n\n\n\tRunnable.prototype.clearTimeout = function () {\n\t  clearTimeout$1(this.timer);\n\t};\n\t/**\n\t * Reset the timeout.\n\t *\n\t * @private\n\t */\n\n\n\tRunnable.prototype.resetTimeout = function () {\n\t  var self = this;\n\t  var ms = this.timeout();\n\n\t  if (ms === 0) {\n\t    return;\n\t  }\n\n\t  this.clearTimeout();\n\t  this.timer = setTimeout$3(function () {\n\t    if (self.timeout() === 0) {\n\t      return;\n\t    }\n\n\t    self.callback(self._timeoutError(ms));\n\t    self.timedOut = true;\n\t  }, ms);\n\t};\n\t/**\n\t * Set or get a list of whitelisted globals for this test run.\n\t *\n\t * @private\n\t * @param {string[]} globals\n\t */\n\n\n\tRunnable.prototype.globals = function (globals) {\n\t  if (!arguments.length) {\n\t    return this._allowedGlobals;\n\t  }\n\n\t  this._allowedGlobals = globals;\n\t};\n\t/**\n\t * Run the test and invoke `fn(err)`.\n\t *\n\t * @param {Function} fn\n\t * @private\n\t */\n\n\n\tRunnable.prototype.run = function (fn) {\n\t  var self = this;\n\t  var start = new Date$4();\n\t  var ctx = this.ctx;\n\t  var finished;\n\t  var errorWasHandled = false;\n\t  if (this.isPending()) return fn(); // Sometimes the ctx exists, but it is not runnable\n\n\t  if (ctx && ctx.runnable) {\n\t    ctx.runnable(this);\n\t  } // called multiple times\n\n\n\t  function multiple(err) {\n\t    if (errorWasHandled) {\n\t      return;\n\t    }\n\n\t    errorWasHandled = true;\n\t    self.emit('error', createMultipleDoneError(self, err));\n\t  } // finished\n\n\n\t  function done(err) {\n\t    var ms = self.timeout();\n\n\t    if (self.timedOut) {\n\t      return;\n\t    }\n\n\t    if (finished) {\n\t      return multiple(err);\n\t    }\n\n\t    self.clearTimeout();\n\t    self.duration = new Date$4() - start;\n\t    finished = true;\n\n\t    if (!err && self.duration > ms && ms > 0) {\n\t      err = self._timeoutError(ms);\n\t    }\n\n\t    fn(err);\n\t  } // for .resetTimeout() and Runner#uncaught()\n\n\n\t  this.callback = done;\n\n\t  if (this.fn && typeof this.fn.call !== 'function') {\n\t    done(new TypeError('A runnable must be passed a function as its second argument.'));\n\t    return;\n\t  } // explicit async with `done` argument\n\n\n\t  if (this.async) {\n\t    this.resetTimeout(); // allows skip() to be used in an explicit async context\n\n\t    this.skip = function asyncSkip() {\n\t      this.pending = true;\n\t      done(); // halt execution, the uncaught handler will ignore the failure.\n\n\t      throw new pending('async skip; aborting execution');\n\t    };\n\n\t    try {\n\t      callFnAsync(this.fn);\n\t    } catch (err) {\n\t      // handles async runnables which actually run synchronously\n\t      errorWasHandled = true;\n\n\t      if (err instanceof pending) {\n\t        return; // done() is already called in this.skip()\n\t      } else if (this.allowUncaught) {\n\t        throw err;\n\t      }\n\n\t      done(Runnable.toValueOrError(err));\n\t    }\n\n\t    return;\n\t  } // sync or promise-returning\n\n\n\t  try {\n\t    callFn(this.fn);\n\t  } catch (err) {\n\t    errorWasHandled = true;\n\n\t    if (err instanceof pending) {\n\t      return done();\n\t    } else if (this.allowUncaught) {\n\t      throw err;\n\t    }\n\n\t    done(Runnable.toValueOrError(err));\n\t  }\n\n\t  function callFn(fn) {\n\t    var result = fn.call(ctx);\n\n\t    if (result && typeof result.then === 'function') {\n\t      self.resetTimeout();\n\t      result.then(function () {\n\t        done(); // Return null so libraries like bluebird do not warn about\n\t        // subsequently constructed Promises.\n\n\t        return null;\n\t      }, function (reason) {\n\t        done(reason || new Error('Promise rejected with no or falsy reason'));\n\t      });\n\t    } else {\n\t      if (self.asyncOnly) {\n\t        return done(new Error('--async-only option in use without declaring `done()` or returning a promise'));\n\t      }\n\n\t      done();\n\t    }\n\t  }\n\n\t  function callFnAsync(fn) {\n\t    var result = fn.call(ctx, function (err) {\n\t      if (err instanceof Error || toString.call(err) === '[object Error]') {\n\t        return done(err);\n\t      }\n\n\t      if (err) {\n\t        if (Object.prototype.toString.call(err) === '[object Object]') {\n\t          return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err)));\n\t        }\n\n\t        return done(new Error('done() invoked with non-Error: ' + err));\n\t      }\n\n\t      if (result && utils.isPromise(result)) {\n\t        return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'));\n\t      }\n\n\t      done();\n\t    });\n\t  }\n\t};\n\t/**\n\t * Instantiates a \"timeout\" error\n\t *\n\t * @param {number} ms - Timeout (in milliseconds)\n\t * @returns {Error} a \"timeout\" error\n\t * @private\n\t */\n\n\n\tRunnable.prototype._timeoutError = function (ms) {\n\t  var msg = \"Timeout of \".concat(ms, \"ms exceeded. For async tests and hooks, ensure \\\"done()\\\" is called; if returning a Promise, ensure it resolves.\");\n\n\t  if (this.file) {\n\t    msg += ' (' + this.file + ')';\n\t  }\n\n\t  return createTimeoutError(msg, ms, this.file);\n\t};\n\n\tvar constants$3 = utils.defineConstants(\n\t/**\n\t * {@link Runnable}-related constants.\n\t * @public\n\t * @memberof Runnable\n\t * @readonly\n\t * @static\n\t * @alias constants\n\t * @enum {string}\n\t */\n\t{\n\t  /**\n\t   * Value of `state` prop when a `Runnable` has failed\n\t   */\n\t  STATE_FAILED: 'failed',\n\n\t  /**\n\t   * Value of `state` prop when a `Runnable` has passed\n\t   */\n\t  STATE_PASSED: 'passed',\n\n\t  /**\n\t   * Value of `state` prop when a `Runnable` has been skipped by user\n\t   */\n\t  STATE_PENDING: 'pending'\n\t});\n\t/**\n\t * Given `value`, return identity if truthy, otherwise create an \"invalid exception\" error and return that.\n\t * @param {*} [value] - Value to return, if present\n\t * @returns {*|Error} `value`, otherwise an `Error`\n\t * @private\n\t */\n\n\tRunnable.toValueOrError = function (value) {\n\t  return value || createInvalidExceptionError$1('Runnable failed with falsy or undefined exception. Please throw an Error instead.', value);\n\t};\n\n\tRunnable.constants = constants$3;\n\n\tvar inherits = utils.inherits,\n\t    constants$2 = utils.constants;\n\tvar MOCHA_ID_PROP_NAME$1 = constants$2.MOCHA_ID_PROP_NAME;\n\t/**\n\t * Expose `Hook`.\n\t */\n\n\tvar hook = Hook;\n\t/**\n\t * Initialize a new `Hook` with the given `title` and callback `fn`\n\t *\n\t * @class\n\t * @extends Runnable\n\t * @param {String} title\n\t * @param {Function} fn\n\t */\n\n\tfunction Hook(title, fn) {\n\t  runnable.call(this, title, fn);\n\t  this.type = 'hook';\n\t}\n\t/**\n\t * Inherit from `Runnable.prototype`.\n\t */\n\n\n\tinherits(Hook, runnable);\n\t/**\n\t * Resets the state for a next run.\n\t */\n\n\tHook.prototype.reset = function () {\n\t  runnable.prototype.reset.call(this);\n\t  delete this._error;\n\t};\n\t/**\n\t * Get or set the test `err`.\n\t *\n\t * @memberof Hook\n\t * @public\n\t * @param {Error} err\n\t * @return {Error}\n\t */\n\n\n\tHook.prototype.error = function (err) {\n\t  if (!arguments.length) {\n\t    err = this._error;\n\t    this._error = null;\n\t    return err;\n\t  }\n\n\t  this._error = err;\n\t};\n\t/**\n\t * Returns an object suitable for IPC.\n\t * Functions are represented by keys beginning with `$$`.\n\t * @private\n\t * @returns {Object}\n\t */\n\n\n\tHook.prototype.serialize = function serialize() {\n\t  return _defineProperty({\n\t    $$currentRetry: this.currentRetry(),\n\t    $$fullTitle: this.fullTitle(),\n\t    $$isPending: Boolean(this.isPending()),\n\t    $$titlePath: this.titlePath(),\n\t    ctx: this.ctx && this.ctx.currentTest ? {\n\t      currentTest: _defineProperty({\n\t        title: this.ctx.currentTest.title\n\t      }, MOCHA_ID_PROP_NAME$1, this.ctx.currentTest.id)\n\t    } : {},\n\t    duration: this.duration,\n\t    file: this.file,\n\t    parent: _defineProperty({\n\t      $$fullTitle: this.parent.fullTitle()\n\t    }, MOCHA_ID_PROP_NAME$1, this.parent.id),\n\t    state: this.state,\n\t    title: this.title,\n\t    type: this.type\n\t  }, MOCHA_ID_PROP_NAME$1, this.id);\n\t};\n\n\tvar suite = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * Module dependencies.\n\t   * @private\n\t   */\n\n\t  var EventEmitter = EventEmitter$2.EventEmitter;\n\t  var assignNewMochaID = utils.assignNewMochaID,\n\t      clamp = utils.clamp,\n\t      utilsConstants = utils.constants,\n\t      defineConstants = utils.defineConstants,\n\t      getMochaID = utils.getMochaID,\n\t      inherits = utils.inherits,\n\t      isString = utils.isString;\n\t  var debug = browser('mocha:suite');\n\t  var MOCHA_ID_PROP_NAME = utilsConstants.MOCHA_ID_PROP_NAME;\n\t  /**\n\t   * Expose `Suite`.\n\t   */\n\n\t  module.exports = Suite;\n\t  /**\n\t   * Create a new `Suite` with the given `title` and parent `Suite`.\n\t   *\n\t   * @public\n\t   * @param {Suite} parent - Parent suite (required!)\n\t   * @param {string} title - Title\n\t   * @return {Suite}\n\t   */\n\n\t  Suite.create = function (parent, title) {\n\t    var suite = new Suite(title, parent.ctx);\n\t    suite.parent = parent;\n\t    title = suite.fullTitle();\n\t    parent.addSuite(suite);\n\t    return suite;\n\t  };\n\t  /**\n\t   * Constructs a new `Suite` instance with the given `title`, `ctx`, and `isRoot`.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @extends EventEmitter\n\t   * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter|EventEmitter}\n\t   * @param {string} title - Suite title.\n\t   * @param {Context} parentContext - Parent context instance.\n\t   * @param {boolean} [isRoot=false] - Whether this is the root suite.\n\t   */\n\n\n\t  function Suite(title, parentContext, isRoot) {\n\t    if (!isString(title)) {\n\t      throw errors.createInvalidArgumentTypeError('Suite argument \"title\" must be a string. Received type \"' + _typeof(title) + '\"', 'title', 'string');\n\t    }\n\n\t    this.title = title;\n\n\t    function Context() {}\n\n\t    Context.prototype = parentContext;\n\t    this.ctx = new Context();\n\t    this.suites = [];\n\t    this.tests = [];\n\t    this.root = isRoot === true;\n\t    this.pending = false;\n\t    this._retries = -1;\n\t    this._beforeEach = [];\n\t    this._beforeAll = [];\n\t    this._afterEach = [];\n\t    this._afterAll = [];\n\t    this._timeout = 2000;\n\t    this._slow = 75;\n\t    this._bail = false;\n\t    this._onlyTests = [];\n\t    this._onlySuites = [];\n\t    assignNewMochaID(this);\n\t    Object.defineProperty(this, 'id', {\n\t      get: function get() {\n\t        return getMochaID(this);\n\t      }\n\t    });\n\t    this.reset();\n\t  }\n\t  /**\n\t   * Inherit from `EventEmitter.prototype`.\n\t   */\n\n\n\t  inherits(Suite, EventEmitter);\n\t  /**\n\t   * Resets the state initially or for a next run.\n\t   */\n\n\t  Suite.prototype.reset = function () {\n\t    this.delayed = false;\n\n\t    function doReset(thingToReset) {\n\t      thingToReset.reset();\n\t    }\n\n\t    this.suites.forEach(doReset);\n\t    this.tests.forEach(doReset);\n\n\t    this._beforeEach.forEach(doReset);\n\n\t    this._afterEach.forEach(doReset);\n\n\t    this._beforeAll.forEach(doReset);\n\n\t    this._afterAll.forEach(doReset);\n\t  };\n\t  /**\n\t   * Return a clone of this `Suite`.\n\t   *\n\t   * @private\n\t   * @return {Suite}\n\t   */\n\n\n\t  Suite.prototype.clone = function () {\n\t    var suite = new Suite(this.title);\n\t    debug('clone');\n\t    suite.ctx = this.ctx;\n\t    suite.root = this.root;\n\t    suite.timeout(this.timeout());\n\t    suite.retries(this.retries());\n\t    suite.slow(this.slow());\n\t    suite.bail(this.bail());\n\t    return suite;\n\t  };\n\t  /**\n\t   * Set or get timeout `ms` or short-hand such as \"2s\".\n\t   *\n\t   * @private\n\t   * @todo Do not attempt to set value if `ms` is undefined\n\t   * @param {number|string} ms\n\t   * @return {Suite|number} for chaining\n\t   */\n\n\n\t  Suite.prototype.timeout = function (ms) {\n\t    if (!arguments.length) {\n\t      return this._timeout;\n\t    }\n\n\t    if (typeof ms === 'string') {\n\t      ms = ms$1(ms);\n\t    } // Clamp to range\n\n\n\t    var INT_MAX = Math.pow(2, 31) - 1;\n\t    var range = [0, INT_MAX];\n\t    ms = clamp(ms, range);\n\t    debug('timeout %d', ms);\n\t    this._timeout = parseInt(ms, 10);\n\t    return this;\n\t  };\n\t  /**\n\t   * Set or get number of times to retry a failed test.\n\t   *\n\t   * @private\n\t   * @param {number|string} n\n\t   * @return {Suite|number} for chaining\n\t   */\n\n\n\t  Suite.prototype.retries = function (n) {\n\t    if (!arguments.length) {\n\t      return this._retries;\n\t    }\n\n\t    debug('retries %d', n);\n\t    this._retries = parseInt(n, 10) || 0;\n\t    return this;\n\t  };\n\t  /**\n\t   * Set or get slow `ms` or short-hand such as \"2s\".\n\t   *\n\t   * @private\n\t   * @param {number|string} ms\n\t   * @return {Suite|number} for chaining\n\t   */\n\n\n\t  Suite.prototype.slow = function (ms) {\n\t    if (!arguments.length) {\n\t      return this._slow;\n\t    }\n\n\t    if (typeof ms === 'string') {\n\t      ms = ms$1(ms);\n\t    }\n\n\t    debug('slow %d', ms);\n\t    this._slow = ms;\n\t    return this;\n\t  };\n\t  /**\n\t   * Set or get whether to bail after first error.\n\t   *\n\t   * @private\n\t   * @param {boolean} bail\n\t   * @return {Suite|number} for chaining\n\t   */\n\n\n\t  Suite.prototype.bail = function (bail) {\n\t    if (!arguments.length) {\n\t      return this._bail;\n\t    }\n\n\t    debug('bail %s', bail);\n\t    this._bail = bail;\n\t    return this;\n\t  };\n\t  /**\n\t   * Check if this suite or its parent suite is marked as pending.\n\t   *\n\t   * @private\n\t   */\n\n\n\t  Suite.prototype.isPending = function () {\n\t    return this.pending || this.parent && this.parent.isPending();\n\t  };\n\t  /**\n\t   * Generic hook-creator.\n\t   * @private\n\t   * @param {string} title - Title of hook\n\t   * @param {Function} fn - Hook callback\n\t   * @returns {Hook} A new hook\n\t   */\n\n\n\t  Suite.prototype._createHook = function (title, fn) {\n\t    var hook$1 = new hook(title, fn);\n\t    hook$1.parent = this;\n\t    hook$1.timeout(this.timeout());\n\t    hook$1.retries(this.retries());\n\t    hook$1.slow(this.slow());\n\t    hook$1.ctx = this.ctx;\n\t    hook$1.file = this.file;\n\t    return hook$1;\n\t  };\n\t  /**\n\t   * Run `fn(test[, done])` before running tests.\n\t   *\n\t   * @private\n\t   * @param {string} title\n\t   * @param {Function} fn\n\t   * @return {Suite} for chaining\n\t   */\n\n\n\t  Suite.prototype.beforeAll = function (title, fn) {\n\t    if (this.isPending()) {\n\t      return this;\n\t    }\n\n\t    if (typeof title === 'function') {\n\t      fn = title;\n\t      title = fn.name;\n\t    }\n\n\t    title = '\"before all\" hook' + (title ? ': ' + title : '');\n\n\t    var hook = this._createHook(title, fn);\n\n\t    this._beforeAll.push(hook);\n\n\t    this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_ALL, hook);\n\t    return this;\n\t  };\n\t  /**\n\t   * Run `fn(test[, done])` after running tests.\n\t   *\n\t   * @private\n\t   * @param {string} title\n\t   * @param {Function} fn\n\t   * @return {Suite} for chaining\n\t   */\n\n\n\t  Suite.prototype.afterAll = function (title, fn) {\n\t    if (this.isPending()) {\n\t      return this;\n\t    }\n\n\t    if (typeof title === 'function') {\n\t      fn = title;\n\t      title = fn.name;\n\t    }\n\n\t    title = '\"after all\" hook' + (title ? ': ' + title : '');\n\n\t    var hook = this._createHook(title, fn);\n\n\t    this._afterAll.push(hook);\n\n\t    this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_ALL, hook);\n\t    return this;\n\t  };\n\t  /**\n\t   * Run `fn(test[, done])` before each test case.\n\t   *\n\t   * @private\n\t   * @param {string} title\n\t   * @param {Function} fn\n\t   * @return {Suite} for chaining\n\t   */\n\n\n\t  Suite.prototype.beforeEach = function (title, fn) {\n\t    if (this.isPending()) {\n\t      return this;\n\t    }\n\n\t    if (typeof title === 'function') {\n\t      fn = title;\n\t      title = fn.name;\n\t    }\n\n\t    title = '\"before each\" hook' + (title ? ': ' + title : '');\n\n\t    var hook = this._createHook(title, fn);\n\n\t    this._beforeEach.push(hook);\n\n\t    this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_EACH, hook);\n\t    return this;\n\t  };\n\t  /**\n\t   * Run `fn(test[, done])` after each test case.\n\t   *\n\t   * @private\n\t   * @param {string} title\n\t   * @param {Function} fn\n\t   * @return {Suite} for chaining\n\t   */\n\n\n\t  Suite.prototype.afterEach = function (title, fn) {\n\t    if (this.isPending()) {\n\t      return this;\n\t    }\n\n\t    if (typeof title === 'function') {\n\t      fn = title;\n\t      title = fn.name;\n\t    }\n\n\t    title = '\"after each\" hook' + (title ? ': ' + title : '');\n\n\t    var hook = this._createHook(title, fn);\n\n\t    this._afterEach.push(hook);\n\n\t    this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_EACH, hook);\n\t    return this;\n\t  };\n\t  /**\n\t   * Add a test `suite`.\n\t   *\n\t   * @private\n\t   * @param {Suite} suite\n\t   * @return {Suite} for chaining\n\t   */\n\n\n\t  Suite.prototype.addSuite = function (suite) {\n\t    suite.parent = this;\n\t    suite.root = false;\n\t    suite.timeout(this.timeout());\n\t    suite.retries(this.retries());\n\t    suite.slow(this.slow());\n\t    suite.bail(this.bail());\n\t    this.suites.push(suite);\n\t    this.emit(constants.EVENT_SUITE_ADD_SUITE, suite);\n\t    return this;\n\t  };\n\t  /**\n\t   * Add a `test` to this suite.\n\t   *\n\t   * @private\n\t   * @param {Test} test\n\t   * @return {Suite} for chaining\n\t   */\n\n\n\t  Suite.prototype.addTest = function (test) {\n\t    test.parent = this;\n\t    test.timeout(this.timeout());\n\t    test.retries(this.retries());\n\t    test.slow(this.slow());\n\t    test.ctx = this.ctx;\n\t    this.tests.push(test);\n\t    this.emit(constants.EVENT_SUITE_ADD_TEST, test);\n\t    return this;\n\t  };\n\t  /**\n\t   * Return the full title generated by recursively concatenating the parent's\n\t   * full title.\n\t   *\n\t   * @memberof Suite\n\t   * @public\n\t   * @return {string}\n\t   */\n\n\n\t  Suite.prototype.fullTitle = function () {\n\t    return this.titlePath().join(' ');\n\t  };\n\t  /**\n\t   * Return the title path generated by recursively concatenating the parent's\n\t   * title path.\n\t   *\n\t   * @memberof Suite\n\t   * @public\n\t   * @return {string}\n\t   */\n\n\n\t  Suite.prototype.titlePath = function () {\n\t    var result = [];\n\n\t    if (this.parent) {\n\t      result = result.concat(this.parent.titlePath());\n\t    }\n\n\t    if (!this.root) {\n\t      result.push(this.title);\n\t    }\n\n\t    return result;\n\t  };\n\t  /**\n\t   * Return the total number of tests.\n\t   *\n\t   * @memberof Suite\n\t   * @public\n\t   * @return {number}\n\t   */\n\n\n\t  Suite.prototype.total = function () {\n\t    return this.suites.reduce(function (sum, suite) {\n\t      return sum + suite.total();\n\t    }, 0) + this.tests.length;\n\t  };\n\t  /**\n\t   * Iterates through each suite recursively to find all tests. Applies a\n\t   * function in the format `fn(test)`.\n\t   *\n\t   * @private\n\t   * @param {Function} fn\n\t   * @return {Suite}\n\t   */\n\n\n\t  Suite.prototype.eachTest = function (fn) {\n\t    this.tests.forEach(fn);\n\t    this.suites.forEach(function (suite) {\n\t      suite.eachTest(fn);\n\t    });\n\t    return this;\n\t  };\n\t  /**\n\t   * This will run the root suite if we happen to be running in delayed mode.\n\t   * @private\n\t   */\n\n\n\t  Suite.prototype.run = function run() {\n\t    if (this.root) {\n\t      this.emit(constants.EVENT_ROOT_SUITE_RUN);\n\t    }\n\t  };\n\t  /**\n\t   * Determines whether a suite has an `only` test or suite as a descendant.\n\t   *\n\t   * @private\n\t   * @returns {Boolean}\n\t   */\n\n\n\t  Suite.prototype.hasOnly = function hasOnly() {\n\t    return this._onlyTests.length > 0 || this._onlySuites.length > 0 || this.suites.some(function (suite) {\n\t      return suite.hasOnly();\n\t    });\n\t  };\n\t  /**\n\t   * Filter suites based on `isOnly` logic.\n\t   *\n\t   * @private\n\t   * @returns {Boolean}\n\t   */\n\n\n\t  Suite.prototype.filterOnly = function filterOnly() {\n\t    if (this._onlyTests.length) {\n\t      // If the suite contains `only` tests, run those and ignore any nested suites.\n\t      this.tests = this._onlyTests;\n\t      this.suites = [];\n\t    } else {\n\t      // Otherwise, do not run any of the tests in this suite.\n\t      this.tests = [];\n\n\t      this._onlySuites.forEach(function (onlySuite) {\n\t        // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite.\n\t        // Otherwise, all of the tests on this `only` suite should be run, so don't filter it.\n\t        if (onlySuite.hasOnly()) {\n\t          onlySuite.filterOnly();\n\t        }\n\t      }); // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants.\n\n\n\t      var onlySuites = this._onlySuites;\n\t      this.suites = this.suites.filter(function (childSuite) {\n\t        return onlySuites.indexOf(childSuite) !== -1 || childSuite.filterOnly();\n\t      });\n\t    } // Keep the suite only if there is something to run\n\n\n\t    return this.tests.length > 0 || this.suites.length > 0;\n\t  };\n\t  /**\n\t   * Adds a suite to the list of subsuites marked `only`.\n\t   *\n\t   * @private\n\t   * @param {Suite} suite\n\t   */\n\n\n\t  Suite.prototype.appendOnlySuite = function (suite) {\n\t    this._onlySuites.push(suite);\n\t  };\n\t  /**\n\t   * Marks a suite to be `only`.\n\t   *\n\t   * @private\n\t   */\n\n\n\t  Suite.prototype.markOnly = function () {\n\t    this.parent && this.parent.appendOnlySuite(this);\n\t  };\n\t  /**\n\t   * Adds a test to the list of tests marked `only`.\n\t   *\n\t   * @private\n\t   * @param {Test} test\n\t   */\n\n\n\t  Suite.prototype.appendOnlyTest = function (test) {\n\t    this._onlyTests.push(test);\n\t  };\n\t  /**\n\t   * Returns the array of hooks by hook name; see `HOOK_TYPE_*` constants.\n\t   * @private\n\t   */\n\n\n\t  Suite.prototype.getHooks = function getHooks(name) {\n\t    return this['_' + name];\n\t  };\n\t  /**\n\t   * cleans all references from this suite and all child suites.\n\t   */\n\n\n\t  Suite.prototype.dispose = function () {\n\t    this.suites.forEach(function (suite) {\n\t      suite.dispose();\n\t    });\n\t    this.cleanReferences();\n\t  };\n\t  /**\n\t   * Cleans up the references to all the deferred functions\n\t   * (before/after/beforeEach/afterEach) and tests of a Suite.\n\t   * These must be deleted otherwise a memory leak can happen,\n\t   * as those functions may reference variables from closures,\n\t   * thus those variables can never be garbage collected as long\n\t   * as the deferred functions exist.\n\t   *\n\t   * @private\n\t   */\n\n\n\t  Suite.prototype.cleanReferences = function cleanReferences() {\n\t    function cleanArrReferences(arr) {\n\t      for (var i = 0; i < arr.length; i++) {\n\t        delete arr[i].fn;\n\t      }\n\t    }\n\n\t    if (Array.isArray(this._beforeAll)) {\n\t      cleanArrReferences(this._beforeAll);\n\t    }\n\n\t    if (Array.isArray(this._beforeEach)) {\n\t      cleanArrReferences(this._beforeEach);\n\t    }\n\n\t    if (Array.isArray(this._afterAll)) {\n\t      cleanArrReferences(this._afterAll);\n\t    }\n\n\t    if (Array.isArray(this._afterEach)) {\n\t      cleanArrReferences(this._afterEach);\n\t    }\n\n\t    for (var i = 0; i < this.tests.length; i++) {\n\t      delete this.tests[i].fn;\n\t    }\n\t  };\n\t  /**\n\t   * Returns an object suitable for IPC.\n\t   * Functions are represented by keys beginning with `$$`.\n\t   * @private\n\t   * @returns {Object}\n\t   */\n\n\n\t  Suite.prototype.serialize = function serialize() {\n\t    var _ref2;\n\n\t    return _ref2 = {\n\t      _bail: this._bail,\n\t      $$fullTitle: this.fullTitle(),\n\t      $$isPending: Boolean(this.isPending()),\n\t      root: this.root,\n\t      title: this.title\n\t    }, _defineProperty(_ref2, MOCHA_ID_PROP_NAME, this.id), _defineProperty(_ref2, \"parent\", this.parent ? _defineProperty({}, MOCHA_ID_PROP_NAME, this.parent.id) : null), _ref2;\n\t  };\n\n\t  var constants = defineConstants(\n\t  /**\n\t   * {@link Suite}-related constants.\n\t   * @public\n\t   * @memberof Suite\n\t   * @alias constants\n\t   * @readonly\n\t   * @static\n\t   * @enum {string}\n\t   */\n\t  {\n\t    /**\n\t     * Event emitted after a test file has been loaded. Not emitted in browser.\n\t     */\n\t    EVENT_FILE_POST_REQUIRE: 'post-require',\n\n\t    /**\n\t     * Event emitted before a test file has been loaded. In browser, this is emitted once an interface has been selected.\n\t     */\n\t    EVENT_FILE_PRE_REQUIRE: 'pre-require',\n\n\t    /**\n\t     * Event emitted immediately after a test file has been loaded. Not emitted in browser.\n\t     */\n\t    EVENT_FILE_REQUIRE: 'require',\n\n\t    /**\n\t     * Event emitted when `global.run()` is called (use with `delay` option).\n\t     */\n\t    EVENT_ROOT_SUITE_RUN: 'run',\n\n\t    /**\n\t     * Namespace for collection of a `Suite`'s \"after all\" hooks.\n\t     */\n\t    HOOK_TYPE_AFTER_ALL: 'afterAll',\n\n\t    /**\n\t     * Namespace for collection of a `Suite`'s \"after each\" hooks.\n\t     */\n\t    HOOK_TYPE_AFTER_EACH: 'afterEach',\n\n\t    /**\n\t     * Namespace for collection of a `Suite`'s \"before all\" hooks.\n\t     */\n\t    HOOK_TYPE_BEFORE_ALL: 'beforeAll',\n\n\t    /**\n\t     * Namespace for collection of a `Suite`'s \"before each\" hooks.\n\t     */\n\t    HOOK_TYPE_BEFORE_EACH: 'beforeEach',\n\n\t    /**\n\t     * Emitted after a child `Suite` has been added to a `Suite`.\n\t     */\n\t    EVENT_SUITE_ADD_SUITE: 'suite',\n\n\t    /**\n\t     * Emitted after an \"after all\" `Hook` has been added to a `Suite`.\n\t     */\n\t    EVENT_SUITE_ADD_HOOK_AFTER_ALL: 'afterAll',\n\n\t    /**\n\t     * Emitted after an \"after each\" `Hook` has been added to a `Suite`.\n\t     */\n\t    EVENT_SUITE_ADD_HOOK_AFTER_EACH: 'afterEach',\n\n\t    /**\n\t     * Emitted after an \"before all\" `Hook` has been added to a `Suite`.\n\t     */\n\t    EVENT_SUITE_ADD_HOOK_BEFORE_ALL: 'beforeAll',\n\n\t    /**\n\t     * Emitted after an \"before each\" `Hook` has been added to a `Suite`.\n\t     */\n\t    EVENT_SUITE_ADD_HOOK_BEFORE_EACH: 'beforeEach',\n\n\t    /**\n\t     * Emitted after a `Test` has been added to a `Suite`.\n\t     */\n\t    EVENT_SUITE_ADD_TEST: 'test'\n\t  });\n\t  Suite.constants = constants;\n\t});\n\n\t/**\n\t * Module dependencies.\n\t * @private\n\t */\n\n\n\tvar EventEmitter = EventEmitter$2.EventEmitter;\n\tvar debug = browser('mocha:runner');\n\tvar HOOK_TYPE_BEFORE_EACH = suite.constants.HOOK_TYPE_BEFORE_EACH;\n\tvar HOOK_TYPE_AFTER_EACH = suite.constants.HOOK_TYPE_AFTER_EACH;\n\tvar HOOK_TYPE_AFTER_ALL = suite.constants.HOOK_TYPE_AFTER_ALL;\n\tvar HOOK_TYPE_BEFORE_ALL = suite.constants.HOOK_TYPE_BEFORE_ALL;\n\tvar EVENT_ROOT_SUITE_RUN = suite.constants.EVENT_ROOT_SUITE_RUN;\n\tvar STATE_FAILED = runnable.constants.STATE_FAILED;\n\tvar STATE_PASSED = runnable.constants.STATE_PASSED;\n\tvar STATE_PENDING = runnable.constants.STATE_PENDING;\n\tvar stackFilter = utils.stackTraceFilter();\n\tvar stringify = utils.stringify;\n\tvar createInvalidExceptionError = errors.createInvalidExceptionError,\n\t    createUnsupportedError$1 = errors.createUnsupportedError,\n\t    createFatalError = errors.createFatalError,\n\t    isMochaError = errors.isMochaError,\n\t    errorConstants = errors.constants;\n\t/**\n\t * Non-enumerable globals.\n\t * @private\n\t * @readonly\n\t */\n\n\tvar globals = ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'XMLHttpRequest', 'Date', 'setImmediate', 'clearImmediate'];\n\tvar constants$1 = utils.defineConstants(\n\t/**\n\t * {@link Runner}-related constants.\n\t * @public\n\t * @memberof Runner\n\t * @readonly\n\t * @alias constants\n\t * @static\n\t * @enum {string}\n\t */\n\t{\n\t  /**\n\t   * Emitted when {@link Hook} execution begins\n\t   */\n\t  EVENT_HOOK_BEGIN: 'hook',\n\n\t  /**\n\t   * Emitted when {@link Hook} execution ends\n\t   */\n\t  EVENT_HOOK_END: 'hook end',\n\n\t  /**\n\t   * Emitted when Root {@link Suite} execution begins (all files have been parsed and hooks/tests are ready for execution)\n\t   */\n\t  EVENT_RUN_BEGIN: 'start',\n\n\t  /**\n\t   * Emitted when Root {@link Suite} execution has been delayed via `delay` option\n\t   */\n\t  EVENT_DELAY_BEGIN: 'waiting',\n\n\t  /**\n\t   * Emitted when delayed Root {@link Suite} execution is triggered by user via `global.run()`\n\t   */\n\t  EVENT_DELAY_END: 'ready',\n\n\t  /**\n\t   * Emitted when Root {@link Suite} execution ends\n\t   */\n\t  EVENT_RUN_END: 'end',\n\n\t  /**\n\t   * Emitted when {@link Suite} execution begins\n\t   */\n\t  EVENT_SUITE_BEGIN: 'suite',\n\n\t  /**\n\t   * Emitted when {@link Suite} execution ends\n\t   */\n\t  EVENT_SUITE_END: 'suite end',\n\n\t  /**\n\t   * Emitted when {@link Test} execution begins\n\t   */\n\t  EVENT_TEST_BEGIN: 'test',\n\n\t  /**\n\t   * Emitted when {@link Test} execution ends\n\t   */\n\t  EVENT_TEST_END: 'test end',\n\n\t  /**\n\t   * Emitted when {@link Test} execution fails\n\t   */\n\t  EVENT_TEST_FAIL: 'fail',\n\n\t  /**\n\t   * Emitted when {@link Test} execution succeeds\n\t   */\n\t  EVENT_TEST_PASS: 'pass',\n\n\t  /**\n\t   * Emitted when {@link Test} becomes pending\n\t   */\n\t  EVENT_TEST_PENDING: 'pending',\n\n\t  /**\n\t   * Emitted when {@link Test} execution has failed, but will retry\n\t   */\n\t  EVENT_TEST_RETRY: 'retry',\n\n\t  /**\n\t   * Initial state of Runner\n\t   */\n\t  STATE_IDLE: 'idle',\n\n\t  /**\n\t   * State set to this value when the Runner has started running\n\t   */\n\t  STATE_RUNNING: 'running',\n\n\t  /**\n\t   * State set to this value when the Runner has stopped\n\t   */\n\t  STATE_STOPPED: 'stopped'\n\t});\n\n\tvar Runner = /*#__PURE__*/function (_EventEmitter) {\n\t  _inherits(Runner, _EventEmitter);\n\n\t  var _super = _createSuper(Runner);\n\n\t  /**\n\t   * Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}.\n\t   *\n\t   * @extends external:EventEmitter\n\t   * @public\n\t   * @class\n\t   * @param {Suite} suite - Root suite\n\t   * @param {Object|boolean} [opts] - Options. If `boolean` (deprecated), whether to delay execution of root suite until ready.\n\t   * @param {boolean} [opts.cleanReferencesAfterRun] - Whether to clean references to test fns and hooks when a suite is done.\n\t   * @param {boolean} [opts.delay] - Whether to delay execution of root suite until ready.\n\t   * @param {boolean} [opts.dryRun] - Whether to report tests without running them.\n\t   * @param {boolean} [opts.failZero] - Whether to fail test run if zero tests encountered.\n\t   */\n\t  function Runner(suite, opts) {\n\t    var _this;\n\n\t    _classCallCheck(this, Runner);\n\n\t    _this = _super.call(this);\n\n\t    if (opts === undefined) {\n\t      opts = {};\n\t    }\n\n\t    if (typeof opts === 'boolean') {\n\t      // TODO: remove this\n\t      errors.deprecate('\"Runner(suite: Suite, delay: boolean)\" is deprecated. Use \"Runner(suite: Suite, {delay: boolean})\" instead.');\n\t      _this._delay = opts;\n\t      opts = {};\n\t    } else {\n\t      _this._delay = opts.delay;\n\t    }\n\n\t    var self = _assertThisInitialized(_this);\n\n\t    _this._globals = [];\n\t    _this._abort = false;\n\t    _this.suite = suite;\n\t    _this._opts = opts;\n\t    _this.state = constants$1.STATE_IDLE;\n\t    _this.total = suite.total();\n\t    _this.failures = 0;\n\t    /**\n\t     * @type {Map<EventEmitter,Map<string,Set<EventListener>>>}\n\t     */\n\n\t    _this._eventListeners = new Map();\n\n\t    _this.on(constants$1.EVENT_TEST_END, function (test) {\n\t      if (test.type === 'test' && test.retriedTest() && test.parent) {\n\t        var idx = test.parent.tests && test.parent.tests.indexOf(test.retriedTest());\n\t        if (idx > -1) test.parent.tests[idx] = test;\n\t      }\n\n\t      self.checkGlobals(test);\n\t    });\n\n\t    _this.on(constants$1.EVENT_HOOK_END, function (hook) {\n\t      self.checkGlobals(hook);\n\t    });\n\n\t    _this._defaultGrep = /.*/;\n\n\t    _this.grep(_this._defaultGrep);\n\n\t    _this.globals(_this.globalProps());\n\n\t    _this.uncaught = _this._uncaught.bind(_assertThisInitialized(_this));\n\n\t    _this.unhandled = function (reason, promise) {\n\t      if (isMochaError(reason)) {\n\t        debug('trapped unhandled rejection coming out of Mocha; forwarding to uncaught handler:', reason);\n\n\t        _this.uncaught(reason);\n\t      } else {\n\t        debug('trapped unhandled rejection from (probably) user code; re-emitting on process');\n\n\t        _this._removeEventListener(process$4, 'unhandledRejection', _this.unhandled);\n\n\t        try {\n\t          process$4.emit('unhandledRejection', reason, promise);\n\t        } finally {\n\t          _this._addEventListener(process$4, 'unhandledRejection', _this.unhandled);\n\t        }\n\t      }\n\t    };\n\n\t    return _this;\n\t  }\n\n\t  return _createClass(Runner);\n\t}(EventEmitter);\n\t/**\n\t * Wrapper for setImmediate, process.nextTick, or browser polyfill.\n\t *\n\t * @param {Function} fn\n\t * @private\n\t */\n\n\n\tRunner.immediately = commonjsGlobal.setImmediate || nextTick$1;\n\t/**\n\t * Replacement for `target.on(eventName, listener)` that does bookkeeping to remove them when this runner instance is disposed.\n\t * @param {EventEmitter} target - The `EventEmitter`\n\t * @param {string} eventName - The event name\n\t * @param {string} fn - Listener function\n\t * @private\n\t */\n\n\tRunner.prototype._addEventListener = function (target, eventName, listener) {\n\t  debug('_addEventListener(): adding for event %s; %d current listeners', eventName, target.listenerCount(eventName));\n\t  /* istanbul ignore next */\n\n\t  if (this._eventListeners.has(target) && this._eventListeners.get(target).has(eventName) && this._eventListeners.get(target).get(eventName).has(listener)) {\n\t    debug('warning: tried to attach duplicate event listener for %s', eventName);\n\t    return;\n\t  }\n\n\t  target.on(eventName, listener);\n\t  var targetListeners = this._eventListeners.has(target) ? this._eventListeners.get(target) : new Map();\n\t  var targetEventListeners = targetListeners.has(eventName) ? targetListeners.get(eventName) : new Set();\n\t  targetEventListeners.add(listener);\n\t  targetListeners.set(eventName, targetEventListeners);\n\n\t  this._eventListeners.set(target, targetListeners);\n\t};\n\t/**\n\t * Replacement for `target.removeListener(eventName, listener)` that also updates the bookkeeping.\n\t * @param {EventEmitter} target - The `EventEmitter`\n\t * @param {string} eventName - The event name\n\t * @param {function} listener - Listener function\n\t * @private\n\t */\n\n\n\tRunner.prototype._removeEventListener = function (target, eventName, listener) {\n\t  target.removeListener(eventName, listener);\n\n\t  if (this._eventListeners.has(target)) {\n\t    var targetListeners = this._eventListeners.get(target);\n\n\t    if (targetListeners.has(eventName)) {\n\t      var targetEventListeners = targetListeners.get(eventName);\n\t      targetEventListeners[\"delete\"](listener);\n\n\t      if (!targetEventListeners.size) {\n\t        targetListeners[\"delete\"](eventName);\n\t      }\n\t    }\n\n\t    if (!targetListeners.size) {\n\t      this._eventListeners[\"delete\"](target);\n\t    }\n\t  } else {\n\t    debug('trying to remove listener for untracked object %s', target);\n\t  }\n\t};\n\t/**\n\t * Removes all event handlers set during a run on this instance.\n\t * Remark: this does _not_ clean/dispose the tests or suites themselves.\n\t */\n\n\n\tRunner.prototype.dispose = function () {\n\t  this.removeAllListeners();\n\n\t  this._eventListeners.forEach(function (targetListeners, target) {\n\t    targetListeners.forEach(function (targetEventListeners, eventName) {\n\t      targetEventListeners.forEach(function (listener) {\n\t        target.removeListener(eventName, listener);\n\t      });\n\t    });\n\t  });\n\n\t  this._eventListeners.clear();\n\t};\n\t/**\n\t * Run tests with full titles matching `re`. Updates runner.total\n\t * with number of tests matched.\n\t *\n\t * @public\n\t * @memberof Runner\n\t * @param {RegExp} re\n\t * @param {boolean} invert\n\t * @return {Runner} Runner instance.\n\t */\n\n\n\tRunner.prototype.grep = function (re, invert) {\n\t  debug('grep(): setting to %s', re);\n\t  this._grep = re;\n\t  this._invert = invert;\n\t  this.total = this.grepTotal(this.suite);\n\t  return this;\n\t};\n\t/**\n\t * Returns the number of tests matching the grep search for the\n\t * given suite.\n\t *\n\t * @memberof Runner\n\t * @public\n\t * @param {Suite} suite\n\t * @return {number}\n\t */\n\n\n\tRunner.prototype.grepTotal = function (suite) {\n\t  var self = this;\n\t  var total = 0;\n\t  suite.eachTest(function (test) {\n\t    var match = self._grep.test(test.fullTitle());\n\n\t    if (self._invert) {\n\t      match = !match;\n\t    }\n\n\t    if (match) {\n\t      total++;\n\t    }\n\t  });\n\t  return total;\n\t};\n\t/**\n\t * Return a list of global properties.\n\t *\n\t * @return {Array}\n\t * @private\n\t */\n\n\n\tRunner.prototype.globalProps = function () {\n\t  var props = Object.keys(commonjsGlobal); // non-enumerables\n\n\t  for (var i = 0; i < globals.length; ++i) {\n\t    if (~props.indexOf(globals[i])) {\n\t      continue;\n\t    }\n\n\t    props.push(globals[i]);\n\t  }\n\n\t  return props;\n\t};\n\t/**\n\t * Allow the given `arr` of globals.\n\t *\n\t * @public\n\t * @memberof Runner\n\t * @param {Array} arr\n\t * @return {Runner} Runner instance.\n\t */\n\n\n\tRunner.prototype.globals = function (arr) {\n\t  if (!arguments.length) {\n\t    return this._globals;\n\t  }\n\n\t  debug('globals(): setting to %O', arr);\n\t  this._globals = this._globals.concat(arr);\n\t  return this;\n\t};\n\t/**\n\t * Check for global variable leaks.\n\t *\n\t * @private\n\t */\n\n\n\tRunner.prototype.checkGlobals = function (test) {\n\t  if (!this.checkLeaks) {\n\t    return;\n\t  }\n\n\t  var ok = this._globals;\n\t  var globals = this.globalProps();\n\t  var leaks;\n\n\t  if (test) {\n\t    ok = ok.concat(test._allowedGlobals || []);\n\t  }\n\n\t  if (this.prevGlobalsLength === globals.length) {\n\t    return;\n\t  }\n\n\t  this.prevGlobalsLength = globals.length;\n\t  leaks = filterLeaks(ok, globals);\n\t  this._globals = this._globals.concat(leaks);\n\n\t  if (leaks.length) {\n\t    var msg = \"global leak(s) detected: \".concat(leaks.map(function (e) {\n\t      return \"'\".concat(e, \"'\");\n\t    }).join(', '));\n\t    this.fail(test, new Error(msg));\n\t  }\n\t};\n\t/**\n\t * Fail the given `test`.\n\t *\n\t * If `test` is a hook, failures work in the following pattern:\n\t * - If bail, run corresponding `after each` and `after` hooks,\n\t *   then exit\n\t * - Failed `before` hook skips all tests in a suite and subsuites,\n\t *   but jumps to corresponding `after` hook\n\t * - Failed `before each` hook skips remaining tests in a\n\t *   suite and jumps to corresponding `after each` hook,\n\t *   which is run only once\n\t * - Failed `after` hook does not alter execution order\n\t * - Failed `after each` hook skips remaining tests in a\n\t *   suite and subsuites, but executes other `after each`\n\t *   hooks\n\t *\n\t * @private\n\t * @param {Runnable} test\n\t * @param {Error} err\n\t * @param {boolean} [force=false] - Whether to fail a pending test.\n\t */\n\n\n\tRunner.prototype.fail = function (test, err, force) {\n\t  force = force === true;\n\n\t  if (test.isPending() && !force) {\n\t    return;\n\t  }\n\n\t  if (this.state === constants$1.STATE_STOPPED) {\n\t    if (err.code === errorConstants.MULTIPLE_DONE) {\n\t      throw err;\n\t    }\n\n\t    throw createFatalError('Test failed after root suite execution completed!', err);\n\t  }\n\n\t  ++this.failures;\n\t  debug('total number of failures: %d', this.failures);\n\t  test.state = STATE_FAILED;\n\n\t  if (!isError(err)) {\n\t    err = thrown2Error(err);\n\t  }\n\n\t  try {\n\t    err.stack = this.fullStackTrace || !err.stack ? err.stack : stackFilter(err.stack);\n\t  } catch (ignore) {// some environments do not take kindly to monkeying with the stack\n\t  }\n\n\t  this.emit(constants$1.EVENT_TEST_FAIL, test, err);\n\t};\n\t/**\n\t * Run hook `name` callbacks and then invoke `fn()`.\n\t *\n\t * @private\n\t * @param {string} name\n\t * @param {Function} fn\n\t */\n\n\n\tRunner.prototype.hook = function (name, fn) {\n\t  if (this._opts.dryRun) return fn();\n\t  var suite = this.suite;\n\t  var hooks = suite.getHooks(name);\n\t  var self = this;\n\n\t  function next(i) {\n\t    var hook = hooks[i];\n\n\t    if (!hook) {\n\t      return fn();\n\t    }\n\n\t    self.currentRunnable = hook;\n\n\t    if (name === HOOK_TYPE_BEFORE_ALL) {\n\t      hook.ctx.currentTest = hook.parent.tests[0];\n\t    } else if (name === HOOK_TYPE_AFTER_ALL) {\n\t      hook.ctx.currentTest = hook.parent.tests[hook.parent.tests.length - 1];\n\t    } else {\n\t      hook.ctx.currentTest = self.test;\n\t    }\n\n\t    setHookTitle(hook);\n\t    hook.allowUncaught = self.allowUncaught;\n\t    self.emit(constants$1.EVENT_HOOK_BEGIN, hook);\n\n\t    if (!hook.listeners('error').length) {\n\t      self._addEventListener(hook, 'error', function (err) {\n\t        self.fail(hook, err);\n\t      });\n\t    }\n\n\t    hook.run(function cbHookRun(err) {\n\t      var testError = hook.error();\n\n\t      if (testError) {\n\t        self.fail(self.test, testError);\n\t      } // conditional skip\n\n\n\t      if (hook.pending) {\n\t        if (name === HOOK_TYPE_AFTER_EACH) {\n\t          // TODO define and implement use case\n\t          if (self.test) {\n\t            self.test.pending = true;\n\t          }\n\t        } else if (name === HOOK_TYPE_BEFORE_EACH) {\n\t          if (self.test) {\n\t            self.test.pending = true;\n\t          }\n\n\t          self.emit(constants$1.EVENT_HOOK_END, hook);\n\t          hook.pending = false; // activates hook for next test\n\n\t          return fn(new Error('abort hookDown'));\n\t        } else if (name === HOOK_TYPE_BEFORE_ALL) {\n\t          suite.tests.forEach(function (test) {\n\t            test.pending = true;\n\t          });\n\t          suite.suites.forEach(function (suite) {\n\t            suite.pending = true;\n\t          });\n\t          hooks = [];\n\t        } else {\n\t          hook.pending = false;\n\t          var errForbid = createUnsupportedError$1('`this.skip` forbidden');\n\t          self.fail(hook, errForbid);\n\t          return fn(errForbid);\n\t        }\n\t      } else if (err) {\n\t        self.fail(hook, err); // stop executing hooks, notify callee of hook err\n\n\t        return fn(err);\n\t      }\n\n\t      self.emit(constants$1.EVENT_HOOK_END, hook);\n\t      delete hook.ctx.currentTest;\n\t      setHookTitle(hook);\n\t      next(++i);\n\t    });\n\n\t    function setHookTitle(hook) {\n\t      hook.originalTitle = hook.originalTitle || hook.title;\n\n\t      if (hook.ctx && hook.ctx.currentTest) {\n\t        hook.title = \"\".concat(hook.originalTitle, \" for \\\"\").concat(hook.ctx.currentTest.title, \"\\\"\");\n\t      } else {\n\t        var parentTitle;\n\n\t        if (hook.parent.title) {\n\t          parentTitle = hook.parent.title;\n\t        } else {\n\t          parentTitle = hook.parent.root ? '{root}' : '';\n\t        }\n\n\t        hook.title = \"\".concat(hook.originalTitle, \" in \\\"\").concat(parentTitle, \"\\\"\");\n\t      }\n\t    }\n\t  }\n\n\t  Runner.immediately(function () {\n\t    next(0);\n\t  });\n\t};\n\t/**\n\t * Run hook `name` for the given array of `suites`\n\t * in order, and callback `fn(err, errSuite)`.\n\t *\n\t * @private\n\t * @param {string} name\n\t * @param {Array} suites\n\t * @param {Function} fn\n\t */\n\n\n\tRunner.prototype.hooks = function (name, suites, fn) {\n\t  var self = this;\n\t  var orig = this.suite;\n\n\t  function next(suite) {\n\t    self.suite = suite;\n\n\t    if (!suite) {\n\t      self.suite = orig;\n\t      return fn();\n\t    }\n\n\t    self.hook(name, function (err) {\n\t      if (err) {\n\t        var errSuite = self.suite;\n\t        self.suite = orig;\n\t        return fn(err, errSuite);\n\t      }\n\n\t      next(suites.pop());\n\t    });\n\t  }\n\n\t  next(suites.pop());\n\t};\n\t/**\n\t * Run 'afterEach' hooks from bottom up.\n\t *\n\t * @param {String} name\n\t * @param {Function} fn\n\t * @private\n\t */\n\n\n\tRunner.prototype.hookUp = function (name, fn) {\n\t  var suites = [this.suite].concat(this.parents()).reverse();\n\t  this.hooks(name, suites, fn);\n\t};\n\t/**\n\t * Run 'beforeEach' hooks from top level down.\n\t *\n\t * @param {String} name\n\t * @param {Function} fn\n\t * @private\n\t */\n\n\n\tRunner.prototype.hookDown = function (name, fn) {\n\t  var suites = [this.suite].concat(this.parents());\n\t  this.hooks(name, suites, fn);\n\t};\n\t/**\n\t * Return an array of parent Suites from\n\t * closest to furthest.\n\t *\n\t * @return {Array}\n\t * @private\n\t */\n\n\n\tRunner.prototype.parents = function () {\n\t  var suite = this.suite;\n\t  var suites = [];\n\n\t  while (suite.parent) {\n\t    suite = suite.parent;\n\t    suites.push(suite);\n\t  }\n\n\t  return suites;\n\t};\n\t/**\n\t * Run the current test and callback `fn(err)`.\n\t *\n\t * @param {Function} fn\n\t * @private\n\t */\n\n\n\tRunner.prototype.runTest = function (fn) {\n\t  if (this._opts.dryRun) return Runner.immediately(fn);\n\t  var self = this;\n\t  var test = this.test;\n\n\t  if (!test) {\n\t    return;\n\t  }\n\n\t  if (this.asyncOnly) {\n\t    test.asyncOnly = true;\n\t  }\n\n\t  this._addEventListener(test, 'error', function (err) {\n\t    self.fail(test, err);\n\t  });\n\n\t  if (this.allowUncaught) {\n\t    test.allowUncaught = true;\n\t    return test.run(fn);\n\t  }\n\n\t  try {\n\t    test.run(fn);\n\t  } catch (err) {\n\t    fn(err);\n\t  }\n\t};\n\t/**\n\t * Run tests in the given `suite` and invoke the callback `fn()` when complete.\n\t *\n\t * @private\n\t * @param {Suite} suite\n\t * @param {Function} fn\n\t */\n\n\n\tRunner.prototype.runTests = function (suite, fn) {\n\t  var self = this;\n\t  var tests = suite.tests.slice();\n\t  var test;\n\n\t  function hookErr(_, errSuite, after) {\n\t    // before/after Each hook for errSuite failed:\n\t    var orig = self.suite; // for failed 'after each' hook start from errSuite parent,\n\t    // otherwise start from errSuite itself\n\n\t    self.suite = after ? errSuite.parent : errSuite;\n\n\t    if (self.suite) {\n\t      self.hookUp(HOOK_TYPE_AFTER_EACH, function (err2, errSuite2) {\n\t        self.suite = orig; // some hooks may fail even now\n\n\t        if (err2) {\n\t          return hookErr(err2, errSuite2, true);\n\t        } // report error suite\n\n\n\t        fn(errSuite);\n\t      });\n\t    } else {\n\t      // there is no need calling other 'after each' hooks\n\t      self.suite = orig;\n\t      fn(errSuite);\n\t    }\n\t  }\n\n\t  function next(err, errSuite) {\n\t    // if we bail after first err\n\t    if (self.failures && suite._bail) {\n\t      tests = [];\n\t    }\n\n\t    if (self._abort) {\n\t      return fn();\n\t    }\n\n\t    if (err) {\n\t      return hookErr(err, errSuite, true);\n\t    } // next test\n\n\n\t    test = tests.shift(); // all done\n\n\t    if (!test) {\n\t      return fn();\n\t    } // grep\n\n\n\t    var match = self._grep.test(test.fullTitle());\n\n\t    if (self._invert) {\n\t      match = !match;\n\t    }\n\n\t    if (!match) {\n\t      // Run immediately only if we have defined a grep. When we\n\t      // define a grep — It can cause maximum callstack error if\n\t      // the grep is doing a large recursive loop by neglecting\n\t      // all tests. The run immediately function also comes with\n\t      // a performance cost. So we don't want to run immediately\n\t      // if we run the whole test suite, because running the whole\n\t      // test suite don't do any immediate recursive loops. Thus,\n\t      // allowing a JS runtime to breathe.\n\t      if (self._grep !== self._defaultGrep) {\n\t        Runner.immediately(next);\n\t      } else {\n\t        next();\n\t      }\n\n\t      return;\n\t    } // static skip, no hooks are executed\n\n\n\t    if (test.isPending()) {\n\t      if (self.forbidPending) {\n\t        self.fail(test, new Error('Pending test forbidden'), true);\n\t      } else {\n\t        test.state = STATE_PENDING;\n\t        self.emit(constants$1.EVENT_TEST_PENDING, test);\n\t      }\n\n\t      self.emit(constants$1.EVENT_TEST_END, test);\n\t      return next();\n\t    } // execute test and hook(s)\n\n\n\t    self.emit(constants$1.EVENT_TEST_BEGIN, self.test = test);\n\t    self.hookDown(HOOK_TYPE_BEFORE_EACH, function (err, errSuite) {\n\t      // conditional skip within beforeEach\n\t      if (test.isPending()) {\n\t        if (self.forbidPending) {\n\t          self.fail(test, new Error('Pending test forbidden'), true);\n\t        } else {\n\t          test.state = STATE_PENDING;\n\t          self.emit(constants$1.EVENT_TEST_PENDING, test);\n\t        }\n\n\t        self.emit(constants$1.EVENT_TEST_END, test); // skip inner afterEach hooks below errSuite level\n\n\t        var origSuite = self.suite;\n\t        self.suite = errSuite || self.suite;\n\t        return self.hookUp(HOOK_TYPE_AFTER_EACH, function (e, eSuite) {\n\t          self.suite = origSuite;\n\t          next(e, eSuite);\n\t        });\n\t      }\n\n\t      if (err) {\n\t        return hookErr(err, errSuite, false);\n\t      }\n\n\t      self.currentRunnable = self.test;\n\t      self.runTest(function (err) {\n\t        test = self.test; // conditional skip within it\n\n\t        if (test.pending) {\n\t          if (self.forbidPending) {\n\t            self.fail(test, new Error('Pending test forbidden'), true);\n\t          } else {\n\t            test.state = STATE_PENDING;\n\t            self.emit(constants$1.EVENT_TEST_PENDING, test);\n\t          }\n\n\t          self.emit(constants$1.EVENT_TEST_END, test);\n\t          return self.hookUp(HOOK_TYPE_AFTER_EACH, next);\n\t        } else if (err) {\n\t          var retry = test.currentRetry();\n\n\t          if (retry < test.retries()) {\n\t            var clonedTest = test.clone();\n\t            clonedTest.currentRetry(retry + 1);\n\t            tests.unshift(clonedTest);\n\t            self.emit(constants$1.EVENT_TEST_RETRY, test, err); // Early return + hook trigger so that it doesn't\n\t            // increment the count wrong\n\n\t            return self.hookUp(HOOK_TYPE_AFTER_EACH, next);\n\t          } else {\n\t            self.fail(test, err);\n\t          }\n\n\t          self.emit(constants$1.EVENT_TEST_END, test);\n\t          return self.hookUp(HOOK_TYPE_AFTER_EACH, next);\n\t        }\n\n\t        test.state = STATE_PASSED;\n\t        self.emit(constants$1.EVENT_TEST_PASS, test);\n\t        self.emit(constants$1.EVENT_TEST_END, test);\n\t        self.hookUp(HOOK_TYPE_AFTER_EACH, next);\n\t      });\n\t    });\n\t  }\n\n\t  this.next = next;\n\t  this.hookErr = hookErr;\n\t  next();\n\t};\n\t/**\n\t * Run the given `suite` and invoke the callback `fn()` when complete.\n\t *\n\t * @private\n\t * @param {Suite} suite\n\t * @param {Function} fn\n\t */\n\n\n\tRunner.prototype.runSuite = function (suite, fn) {\n\t  var i = 0;\n\t  var self = this;\n\t  var total = this.grepTotal(suite);\n\t  debug('runSuite(): running %s', suite.fullTitle());\n\n\t  if (!total || self.failures && suite._bail) {\n\t    debug('runSuite(): bailing');\n\t    return fn();\n\t  }\n\n\t  this.emit(constants$1.EVENT_SUITE_BEGIN, this.suite = suite);\n\n\t  function next(errSuite) {\n\t    if (errSuite) {\n\t      // current suite failed on a hook from errSuite\n\t      if (errSuite === suite) {\n\t        // if errSuite is current suite\n\t        // continue to the next sibling suite\n\t        return done();\n\t      } // errSuite is among the parents of current suite\n\t      // stop execution of errSuite and all sub-suites\n\n\n\t      return done(errSuite);\n\t    }\n\n\t    if (self._abort) {\n\t      return done();\n\t    }\n\n\t    var curr = suite.suites[i++];\n\n\t    if (!curr) {\n\t      return done();\n\t    } // Avoid grep neglecting large number of tests causing a\n\t    // huge recursive loop and thus a maximum call stack error.\n\t    // See comment in `this.runTests()` for more information.\n\n\n\t    if (self._grep !== self._defaultGrep) {\n\t      Runner.immediately(function () {\n\t        self.runSuite(curr, next);\n\t      });\n\t    } else {\n\t      self.runSuite(curr, next);\n\t    }\n\t  }\n\n\t  function done(errSuite) {\n\t    self.suite = suite;\n\t    self.nextSuite = next; // remove reference to test\n\n\t    delete self.test;\n\t    self.hook(HOOK_TYPE_AFTER_ALL, function () {\n\t      self.emit(constants$1.EVENT_SUITE_END, suite);\n\t      fn(errSuite);\n\t    });\n\t  }\n\n\t  this.nextSuite = next;\n\t  this.hook(HOOK_TYPE_BEFORE_ALL, function (err) {\n\t    if (err) {\n\t      return done();\n\t    }\n\n\t    self.runTests(suite, next);\n\t  });\n\t};\n\t/**\n\t * Handle uncaught exceptions within runner.\n\t *\n\t * This function is bound to the instance as `Runner#uncaught` at instantiation\n\t * time. It's intended to be listening on the `Process.uncaughtException` event.\n\t * In order to not leak EE listeners, we need to ensure no more than a single\n\t * `uncaughtException` listener exists per `Runner`.  The only way to do\n\t * this--because this function needs the context (and we don't have lambdas)--is\n\t * to use `Function.prototype.bind`. We need strict equality to unregister and\n\t * _only_ unregister the _one_ listener we set from the\n\t * `Process.uncaughtException` event; would be poor form to just remove\n\t * everything. See {@link Runner#run} for where the event listener is registered\n\t * and unregistered.\n\t * @param {Error} err - Some uncaught error\n\t * @private\n\t */\n\n\n\tRunner.prototype._uncaught = function (err) {\n\t  // this is defensive to prevent future developers from mis-calling this function.\n\t  // it's more likely that it'd be called with the incorrect context--say, the global\n\t  // `process` object--than it would to be called with a context that is not a \"subclass\"\n\t  // of `Runner`.\n\t  if (!(this instanceof Runner)) {\n\t    throw createFatalError('Runner#uncaught() called with invalid context', this);\n\t  }\n\n\t  if (err instanceof pending) {\n\t    debug('uncaught(): caught a Pending');\n\t    return;\n\t  } // browser does not exit script when throwing in global.onerror()\n\n\n\t  if (this.allowUncaught && !utils.isBrowser()) {\n\t    debug('uncaught(): bubbling exception due to --allow-uncaught');\n\t    throw err;\n\t  }\n\n\t  if (this.state === constants$1.STATE_STOPPED) {\n\t    debug('uncaught(): throwing after run has completed!');\n\t    throw err;\n\t  }\n\n\t  if (err) {\n\t    debug('uncaught(): got truthy exception %O', err);\n\t  } else {\n\t    debug('uncaught(): undefined/falsy exception');\n\t    err = createInvalidExceptionError('Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger', err);\n\t  }\n\n\t  if (!isError(err)) {\n\t    err = thrown2Error(err);\n\t    debug('uncaught(): converted \"error\" %o to Error', err);\n\t  }\n\n\t  err.uncaught = true;\n\t  var runnable$1 = this.currentRunnable;\n\n\t  if (!runnable$1) {\n\t    runnable$1 = new runnable('Uncaught error outside test suite');\n\t    debug('uncaught(): no current Runnable; created a phony one');\n\t    runnable$1.parent = this.suite;\n\n\t    if (this.state === constants$1.STATE_RUNNING) {\n\t      debug('uncaught(): failing gracefully');\n\t      this.fail(runnable$1, err);\n\t    } else {\n\t      // Can't recover from this failure\n\t      debug('uncaught(): test run has not yet started; unrecoverable');\n\t      this.emit(constants$1.EVENT_RUN_BEGIN);\n\t      this.fail(runnable$1, err);\n\t      this.emit(constants$1.EVENT_RUN_END);\n\t    }\n\n\t    return;\n\t  }\n\n\t  runnable$1.clearTimeout();\n\n\t  if (runnable$1.isFailed()) {\n\t    debug('uncaught(): Runnable has already failed'); // Ignore error if already failed\n\n\t    return;\n\t  } else if (runnable$1.isPending()) {\n\t    debug('uncaught(): pending Runnable wound up failing!'); // report 'pending test' retrospectively as failed\n\n\t    this.fail(runnable$1, err, true);\n\t    return;\n\t  } // we cannot recover gracefully if a Runnable has already passed\n\t  // then fails asynchronously\n\n\n\t  if (runnable$1.isPassed()) {\n\t    debug('uncaught(): Runnable has already passed; bailing gracefully');\n\t    this.fail(runnable$1, err);\n\t    this.abort();\n\t  } else {\n\t    debug('uncaught(): forcing Runnable to complete with Error');\n\t    return runnable$1.callback(err);\n\t  }\n\t};\n\t/**\n\t * Run the root suite and invoke `fn(failures)`\n\t * on completion.\n\t *\n\t * @public\n\t * @memberof Runner\n\t * @param {Function} fn - Callback when finished\n\t * @param {{files: string[], options: Options}} [opts] - For subclasses\n\t * @returns {Runner} Runner instance.\n\t */\n\n\n\tRunner.prototype.run = function (fn) {\n\t  var _this2 = this;\n\n\t  var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\t  var rootSuite = this.suite;\n\t  var options = opts.options || {};\n\t  debug('run(): got options: %O', options);\n\n\t  fn = fn || function () {};\n\n\t  var end = function end() {\n\t    if (!_this2.total && _this2._opts.failZero) _this2.failures = 1;\n\t    debug('run(): root suite completed; emitting %s', constants$1.EVENT_RUN_END);\n\n\t    _this2.emit(constants$1.EVENT_RUN_END);\n\t  };\n\n\t  var begin = function begin() {\n\t    debug('run(): emitting %s', constants$1.EVENT_RUN_BEGIN);\n\n\t    _this2.emit(constants$1.EVENT_RUN_BEGIN);\n\n\t    debug('run(): emitted %s', constants$1.EVENT_RUN_BEGIN);\n\n\t    _this2.runSuite(rootSuite, end);\n\t  };\n\n\t  var prepare = function prepare() {\n\t    debug('run(): starting'); // If there is an `only` filter\n\n\t    if (rootSuite.hasOnly()) {\n\t      rootSuite.filterOnly();\n\t      debug('run(): filtered exclusive Runnables');\n\t    }\n\n\t    _this2.state = constants$1.STATE_RUNNING;\n\n\t    if (_this2._delay) {\n\t      _this2.emit(constants$1.EVENT_DELAY_END);\n\n\t      debug('run(): \"delay\" ended');\n\t    }\n\n\t    return begin();\n\t  }; // references cleanup to avoid memory leaks\n\n\n\t  if (this._opts.cleanReferencesAfterRun) {\n\t    this.on(constants$1.EVENT_SUITE_END, function (suite) {\n\t      suite.cleanReferences();\n\t    });\n\t  } // callback\n\n\n\t  this.on(constants$1.EVENT_RUN_END, function () {\n\t    this.state = constants$1.STATE_STOPPED;\n\t    debug('run(): emitted %s', constants$1.EVENT_RUN_END);\n\t    fn(this.failures);\n\t  });\n\n\t  this._removeEventListener(process$4, 'uncaughtException', this.uncaught);\n\n\t  this._removeEventListener(process$4, 'unhandledRejection', this.unhandled);\n\n\t  this._addEventListener(process$4, 'uncaughtException', this.uncaught);\n\n\t  this._addEventListener(process$4, 'unhandledRejection', this.unhandled);\n\n\t  if (this._delay) {\n\t    // for reporters, I guess.\n\t    // might be nice to debounce some dots while we wait.\n\t    this.emit(constants$1.EVENT_DELAY_BEGIN, rootSuite);\n\t    rootSuite.once(EVENT_ROOT_SUITE_RUN, prepare);\n\t    debug('run(): waiting for green light due to --delay');\n\t  } else {\n\t    Runner.immediately(prepare);\n\t  }\n\n\t  return this;\n\t};\n\t/**\n\t * Toggle partial object linking behavior; used for building object references from\n\t * unique ID's. Does nothing in serial mode, because the object references already exist.\n\t * Subclasses can implement this (e.g., `ParallelBufferedRunner`)\n\t * @abstract\n\t * @param {boolean} [value] - If `true`, enable partial object linking, otherwise disable\n\t * @returns {Runner}\n\t * @chainable\n\t * @public\n\t * @example\n\t * // this reporter needs proper object references when run in parallel mode\n\t * class MyReporter() {\n\t *   constructor(runner) {\n\t *     this.runner.linkPartialObjects(true)\n\t *       .on(EVENT_SUITE_BEGIN, suite => {\n\t           // this Suite may be the same object...\n\t *       })\n\t *       .on(EVENT_TEST_BEGIN, test => {\n\t *         // ...as the `test.parent` property\n\t *       });\n\t *   }\n\t * }\n\t */\n\n\n\tRunner.prototype.linkPartialObjects = function (value) {\n\t  return this;\n\t};\n\t/*\n\t * Like {@link Runner#run}, but does not accept a callback and returns a `Promise` instead of a `Runner`.\n\t * This function cannot reject; an `unhandledRejection` event will bubble up to the `process` object instead.\n\t * @public\n\t * @memberof Runner\n\t * @param {Object} [opts] - Options for {@link Runner#run}\n\t * @returns {Promise<number>} Failure count\n\t */\n\n\n\tRunner.prototype.runAsync = /*#__PURE__*/function () {\n\t  var _runAsync = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n\t    var _this3 = this;\n\n\t    var opts,\n\t        _args = arguments;\n\t    return regeneratorRuntime.wrap(function _callee$(_context) {\n\t      while (1) {\n\t        switch (_context.prev = _context.next) {\n\t          case 0:\n\t            opts = _args.length > 0 && _args[0] !== undefined ? _args[0] : {};\n\t            return _context.abrupt(\"return\", new Promise(function (resolve) {\n\t              _this3.run(resolve, opts);\n\t            }));\n\n\t          case 2:\n\t          case \"end\":\n\t            return _context.stop();\n\t        }\n\t      }\n\t    }, _callee);\n\t  }));\n\n\t  function runAsync() {\n\t    return _runAsync.apply(this, arguments);\n\t  }\n\n\t  return runAsync;\n\t}();\n\t/**\n\t * Cleanly abort execution.\n\t *\n\t * @memberof Runner\n\t * @public\n\t * @return {Runner} Runner instance.\n\t */\n\n\n\tRunner.prototype.abort = function () {\n\t  debug('abort(): aborting');\n\t  this._abort = true;\n\t  return this;\n\t};\n\t/**\n\t * Returns `true` if Mocha is running in parallel mode.  For reporters.\n\t *\n\t * Subclasses should return an appropriate value.\n\t * @public\n\t * @returns {false}\n\t */\n\n\n\tRunner.prototype.isParallelMode = function isParallelMode() {\n\t  return false;\n\t};\n\t/**\n\t * Configures an alternate reporter for worker processes to use. Subclasses\n\t * using worker processes should implement this.\n\t * @public\n\t * @param {string} path - Absolute path to alternate reporter for worker processes to use\n\t * @returns {Runner}\n\t * @throws When in serial mode\n\t * @chainable\n\t * @abstract\n\t */\n\n\n\tRunner.prototype.workerReporter = function () {\n\t  throw createUnsupportedError$1('workerReporter() not supported in serial mode');\n\t};\n\t/**\n\t * Filter leaks with the given globals flagged as `ok`.\n\t *\n\t * @private\n\t * @param {Array} ok\n\t * @param {Array} globals\n\t * @return {Array}\n\t */\n\n\n\tfunction filterLeaks(ok, globals) {\n\t  return globals.filter(function (key) {\n\t    // Firefox and Chrome exposes iframes as index inside the window object\n\t    if (/^\\d+/.test(key)) {\n\t      return false;\n\t    } // in firefox\n\t    // if runner runs in an iframe, this iframe's window.getInterface method\n\t    // not init at first it is assigned in some seconds\n\n\n\t    if (commonjsGlobal.navigator && /^getInterface/.test(key)) {\n\t      return false;\n\t    } // an iframe could be approached by window[iframeIndex]\n\t    // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak\n\n\n\t    if (commonjsGlobal.navigator && /^\\d+/.test(key)) {\n\t      return false;\n\t    } // Opera and IE expose global variables for HTML element IDs (issue #243)\n\n\n\t    if (/^mocha-/.test(key)) {\n\t      return false;\n\t    }\n\n\t    var matched = ok.filter(function (ok) {\n\t      if (~ok.indexOf('*')) {\n\t        return key.indexOf(ok.split('*')[0]) === 0;\n\t      }\n\n\t      return key === ok;\n\t    });\n\t    return !matched.length && (!commonjsGlobal.navigator || key !== 'onerror');\n\t  });\n\t}\n\t/**\n\t * Check if argument is an instance of Error object or a duck-typed equivalent.\n\t *\n\t * @private\n\t * @param {Object} err - object to check\n\t * @param {string} err.message - error message\n\t * @returns {boolean}\n\t */\n\n\n\tfunction isError(err) {\n\t  return err instanceof Error || err && typeof err.message === 'string';\n\t}\n\t/**\n\t *\n\t * Converts thrown non-extensible type into proper Error.\n\t *\n\t * @private\n\t * @param {*} thrown - Non-extensible type thrown by code\n\t * @return {Error}\n\t */\n\n\n\tfunction thrown2Error(err) {\n\t  return new Error(\"the \".concat(utils.canonicalType(err), \" \").concat(stringify(err), \" was thrown, throw an Error :)\"));\n\t}\n\n\tRunner.constants = constants$1;\n\t/**\n\t * Node.js' `EventEmitter`\n\t * @external EventEmitter\n\t * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter}\n\t */\n\n\tvar runner = Runner;\n\n\tvar require$$10 = getCjsExportFromNamespace(_nodeResolve_empty$1);\n\n\tvar base = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Base\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var isBrowser = utils.isBrowser();\n\n\t  function getBrowserWindowSize() {\n\t    if ('innerHeight' in commonjsGlobal) {\n\t      return [commonjsGlobal.innerHeight, commonjsGlobal.innerWidth];\n\t    } // In a Web Worker, the DOM Window is not available.\n\n\n\t    return [640, 480];\n\t  }\n\t  /**\n\t   * Expose `Base`.\n\t   */\n\n\n\t  exports = module.exports = Base;\n\t  /**\n\t   * Check if both stdio streams are associated with a tty.\n\t   */\n\n\t  var isatty = isBrowser || process$4.stdout.isTTY && process$4.stderr.isTTY;\n\t  /**\n\t   * Save log references to avoid tests interfering (see GH-3604).\n\t   */\n\n\t  var consoleLog = console.log;\n\t  /**\n\t   * Enable coloring by default, except in the browser interface.\n\t   */\n\n\t  exports.useColors = !isBrowser && (require$$10.stdout || process$4.env.MOCHA_COLORS !== undefined);\n\t  /**\n\t   * Inline diffs instead of +/-\n\t   */\n\n\t  exports.inlineDiffs = false;\n\t  /**\n\t   * Truncate diffs longer than this value to avoid slow performance\n\t   */\n\n\t  exports.maxDiffSize = 8192;\n\t  /**\n\t   * Default color map.\n\t   */\n\n\t  exports.colors = {\n\t    pass: 90,\n\t    fail: 31,\n\t    'bright pass': 92,\n\t    'bright fail': 91,\n\t    'bright yellow': 93,\n\t    pending: 36,\n\t    suite: 0,\n\t    'error title': 0,\n\t    'error message': 31,\n\t    'error stack': 90,\n\t    checkmark: 32,\n\t    fast: 90,\n\t    medium: 33,\n\t    slow: 31,\n\t    green: 32,\n\t    light: 90,\n\t    'diff gutter': 90,\n\t    'diff added': 32,\n\t    'diff removed': 31,\n\t    'diff added inline': '30;42',\n\t    'diff removed inline': '30;41'\n\t  };\n\t  /**\n\t   * Default symbol map.\n\t   */\n\n\t  exports.symbols = {\n\t    ok: browser$1.success,\n\t    err: browser$1.error,\n\t    dot: '.',\n\t    comma: ',',\n\t    bang: '!'\n\t  };\n\t  /**\n\t   * Color `str` with the given `type`,\n\t   * allowing colors to be disabled,\n\t   * as well as user-defined color\n\t   * schemes.\n\t   *\n\t   * @private\n\t   * @param {string} type\n\t   * @param {string} str\n\t   * @return {string}\n\t   */\n\n\t  var color = exports.color = function (type, str) {\n\t    if (!exports.useColors) {\n\t      return String(str);\n\t    }\n\n\t    return \"\\x1B[\" + exports.colors[type] + 'm' + str + \"\\x1B[0m\";\n\t  };\n\t  /**\n\t   * Expose term window size, with some defaults for when stderr is not a tty.\n\t   */\n\n\n\t  exports.window = {\n\t    width: 75\n\t  };\n\n\t  if (isatty) {\n\t    if (isBrowser) {\n\t      exports.window.width = getBrowserWindowSize()[1];\n\t    } else {\n\t      exports.window.width = process$4.stdout.getWindowSize(1)[0];\n\t    }\n\t  }\n\t  /**\n\t   * Expose some basic cursor interactions that are common among reporters.\n\t   */\n\n\n\t  exports.cursor = {\n\t    hide: function hide() {\n\t      isatty && process$4.stdout.write(\"\\x1B[?25l\");\n\t    },\n\t    show: function show() {\n\t      isatty && process$4.stdout.write(\"\\x1B[?25h\");\n\t    },\n\t    deleteLine: function deleteLine() {\n\t      isatty && process$4.stdout.write(\"\\x1B[2K\");\n\t    },\n\t    beginningOfLine: function beginningOfLine() {\n\t      isatty && process$4.stdout.write(\"\\x1B[0G\");\n\t    },\n\t    CR: function CR() {\n\t      if (isatty) {\n\t        exports.cursor.deleteLine();\n\t        exports.cursor.beginningOfLine();\n\t      } else {\n\t        process$4.stdout.write('\\r');\n\t      }\n\t    }\n\t  };\n\n\t  var showDiff = exports.showDiff = function (err) {\n\t    return err && err.showDiff !== false && sameType(err.actual, err.expected) && err.expected !== undefined;\n\t  };\n\n\t  function stringifyDiffObjs(err) {\n\t    if (!utils.isString(err.actual) || !utils.isString(err.expected)) {\n\t      err.actual = utils.stringify(err.actual);\n\t      err.expected = utils.stringify(err.expected);\n\t    }\n\t  }\n\t  /**\n\t   * Returns a diff between 2 strings with coloured ANSI output.\n\t   *\n\t   * @description\n\t   * The diff will be either inline or unified dependent on the value\n\t   * of `Base.inlineDiff`.\n\t   *\n\t   * @param {string} actual\n\t   * @param {string} expected\n\t   * @return {string} Diff\n\t   */\n\n\n\t  var generateDiff = exports.generateDiff = function (actual, expected) {\n\t    try {\n\t      var maxLen = exports.maxDiffSize;\n\t      var skipped = 0;\n\n\t      if (maxLen > 0) {\n\t        skipped = Math.max(actual.length - maxLen, expected.length - maxLen);\n\t        actual = actual.slice(0, maxLen);\n\t        expected = expected.slice(0, maxLen);\n\t      }\n\n\t      var result = exports.inlineDiffs ? inlineDiff(actual, expected) : unifiedDiff(actual, expected);\n\n\t      if (skipped > 0) {\n\t        result = \"\".concat(result, \"\\n      [mocha] output truncated to \").concat(maxLen, \" characters, see \\\"maxDiffSize\\\" reporter-option\\n\");\n\t      }\n\n\t      return result;\n\t    } catch (err) {\n\t      var msg = '\\n      ' + color('diff added', '+ expected') + ' ' + color('diff removed', '- actual:  failed to generate Mocha diff') + '\\n';\n\t      return msg;\n\t    }\n\t  };\n\t  /**\n\t   * Outputs the given `failures` as a list.\n\t   *\n\t   * @public\n\t   * @memberof Mocha.reporters.Base\n\t   * @variation 1\n\t   * @param {Object[]} failures - Each is Test instance with corresponding\n\t   *     Error property\n\t   */\n\n\n\t  exports.list = function (failures) {\n\t    var multipleErr, multipleTest;\n\t    Base.consoleLog();\n\t    failures.forEach(function (test, i) {\n\t      // format\n\t      var fmt = color('error title', '  %s) %s:\\n') + color('error message', '     %s') + color('error stack', '\\n%s\\n'); // msg\n\n\t      var msg;\n\t      var err;\n\n\t      if (test.err && test.err.multiple) {\n\t        if (multipleTest !== test) {\n\t          multipleTest = test;\n\t          multipleErr = [test.err].concat(test.err.multiple);\n\t        }\n\n\t        err = multipleErr.shift();\n\t      } else {\n\t        err = test.err;\n\t      }\n\n\t      var message;\n\n\t      if (typeof err.inspect === 'function') {\n\t        message = err.inspect() + '';\n\t      } else if (err.message && typeof err.message.toString === 'function') {\n\t        message = err.message + '';\n\t      } else {\n\t        message = '';\n\t      }\n\n\t      var stack = err.stack || message;\n\t      var index = message ? stack.indexOf(message) : -1;\n\n\t      if (index === -1) {\n\t        msg = message;\n\t      } else {\n\t        index += message.length;\n\t        msg = stack.slice(0, index); // remove msg from stack\n\n\t        stack = stack.slice(index + 1);\n\t      } // uncaught\n\n\n\t      if (err.uncaught) {\n\t        msg = 'Uncaught ' + msg;\n\t      } // explicitly show diff\n\n\n\t      if (!exports.hideDiff && showDiff(err)) {\n\t        stringifyDiffObjs(err);\n\t        fmt = color('error title', '  %s) %s:\\n%s') + color('error stack', '\\n%s\\n');\n\t        var match = message.match(/^([^:]+): expected/);\n\t        msg = '\\n      ' + color('error message', match ? match[1] : msg);\n\t        msg += generateDiff(err.actual, err.expected);\n\t      } // indent stack trace\n\n\n\t      stack = stack.replace(/^/gm, '  '); // indented test title\n\n\t      var testTitle = '';\n\t      test.titlePath().forEach(function (str, index) {\n\t        if (index !== 0) {\n\t          testTitle += '\\n     ';\n\t        }\n\n\t        for (var i = 0; i < index; i++) {\n\t          testTitle += '  ';\n\t        }\n\n\t        testTitle += str;\n\t      });\n\t      Base.consoleLog(fmt, i + 1, testTitle, msg, stack);\n\t    });\n\t  };\n\t  /**\n\t   * Constructs a new `Base` reporter instance.\n\t   *\n\t   * @description\n\t   * All other reporters generally inherit from this reporter.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\n\t  function Base(runner, options) {\n\t    var failures = this.failures = [];\n\n\t    if (!runner) {\n\t      throw new TypeError('Missing runner argument');\n\t    }\n\n\t    this.options = options || {};\n\t    this.runner = runner;\n\t    this.stats = runner.stats; // assigned so Reporters keep a closer reference\n\n\t    var maxDiffSizeOpt = this.options.reporterOption && this.options.reporterOption.maxDiffSize;\n\n\t    if (maxDiffSizeOpt !== undefined && !isNaN(Number(maxDiffSizeOpt))) {\n\t      exports.maxDiffSize = Number(maxDiffSizeOpt);\n\t    }\n\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      if (test.duration > test.slow()) {\n\t        test.speed = 'slow';\n\t      } else if (test.duration > test.slow() / 2) {\n\t        test.speed = 'medium';\n\t      } else {\n\t        test.speed = 'fast';\n\t      }\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test, err) {\n\t      if (showDiff(err)) {\n\t        stringifyDiffObjs(err);\n\t      } // more than one error per test\n\n\n\t      if (test.err && err instanceof Error) {\n\t        test.err.multiple = (test.err.multiple || []).concat(err);\n\t      } else {\n\t        test.err = err;\n\t      }\n\n\t      failures.push(test);\n\t    });\n\t  }\n\t  /**\n\t   * Outputs common epilogue used by many of the bundled reporters.\n\t   *\n\t   * @public\n\t   * @memberof Mocha.reporters\n\t   */\n\n\n\t  Base.prototype.epilogue = function () {\n\t    var stats = this.stats;\n\t    var fmt;\n\t    Base.consoleLog(); // passes\n\n\t    fmt = color('bright pass', ' ') + color('green', ' %d passing') + color('light', ' (%s)');\n\t    Base.consoleLog(fmt, stats.passes || 0, ms$1(stats.duration)); // pending\n\n\t    if (stats.pending) {\n\t      fmt = color('pending', ' ') + color('pending', ' %d pending');\n\t      Base.consoleLog(fmt, stats.pending);\n\t    } // failures\n\n\n\t    if (stats.failures) {\n\t      fmt = color('fail', '  %d failing');\n\t      Base.consoleLog(fmt, stats.failures);\n\t      Base.list(this.failures);\n\t      Base.consoleLog();\n\t    }\n\n\t    Base.consoleLog();\n\t  };\n\t  /**\n\t   * Pads the given `str` to `len`.\n\t   *\n\t   * @private\n\t   * @param {string} str\n\t   * @param {string} len\n\t   * @return {string}\n\t   */\n\n\n\t  function pad(str, len) {\n\t    str = String(str);\n\t    return Array(len - str.length + 1).join(' ') + str;\n\t  }\n\t  /**\n\t   * Returns inline diff between 2 strings with coloured ANSI output.\n\t   *\n\t   * @private\n\t   * @param {String} actual\n\t   * @param {String} expected\n\t   * @return {string} Diff\n\t   */\n\n\n\t  function inlineDiff(actual, expected) {\n\t    var msg = errorDiff(actual, expected); // linenos\n\n\t    var lines = msg.split('\\n');\n\n\t    if (lines.length > 4) {\n\t      var width = String(lines.length).length;\n\t      msg = lines.map(function (str, i) {\n\t        return pad(++i, width) + ' |' + ' ' + str;\n\t      }).join('\\n');\n\t    } // legend\n\n\n\t    msg = '\\n' + color('diff removed inline', 'actual') + ' ' + color('diff added inline', 'expected') + '\\n\\n' + msg + '\\n'; // indent\n\n\t    msg = msg.replace(/^/gm, '      ');\n\t    return msg;\n\t  }\n\t  /**\n\t   * Returns unified diff between two strings with coloured ANSI output.\n\t   *\n\t   * @private\n\t   * @param {String} actual\n\t   * @param {String} expected\n\t   * @return {string} The diff.\n\t   */\n\n\n\t  function unifiedDiff(actual, expected) {\n\t    var indent = '      ';\n\n\t    function cleanUp(line) {\n\t      if (line[0] === '+') {\n\t        return indent + colorLines('diff added', line);\n\t      }\n\n\t      if (line[0] === '-') {\n\t        return indent + colorLines('diff removed', line);\n\t      }\n\n\t      if (line.match(/@@/)) {\n\t        return '--';\n\t      }\n\n\t      if (line.match(/\\\\ No newline/)) {\n\t        return null;\n\t      }\n\n\t      return indent + line;\n\t    }\n\n\t    function notBlank(line) {\n\t      return typeof line !== 'undefined' && line !== null;\n\t    }\n\n\t    var msg = diff$1.createPatch('string', actual, expected);\n\t    var lines = msg.split('\\n').splice(5);\n\t    return '\\n      ' + colorLines('diff added', '+ expected') + ' ' + colorLines('diff removed', '- actual') + '\\n\\n' + lines.map(cleanUp).filter(notBlank).join('\\n');\n\t  }\n\t  /**\n\t   * Returns character diff for `err`.\n\t   *\n\t   * @private\n\t   * @param {String} actual\n\t   * @param {String} expected\n\t   * @return {string} the diff\n\t   */\n\n\n\t  function errorDiff(actual, expected) {\n\t    return diff$1.diffWordsWithSpace(actual, expected).map(function (str) {\n\t      if (str.added) {\n\t        return colorLines('diff added inline', str.value);\n\t      }\n\n\t      if (str.removed) {\n\t        return colorLines('diff removed inline', str.value);\n\t      }\n\n\t      return str.value;\n\t    }).join('');\n\t  }\n\t  /**\n\t   * Colors lines for `str`, using the color `name`.\n\t   *\n\t   * @private\n\t   * @param {string} name\n\t   * @param {string} str\n\t   * @return {string}\n\t   */\n\n\n\t  function colorLines(name, str) {\n\t    return str.split('\\n').map(function (str) {\n\t      return color(name, str);\n\t    }).join('\\n');\n\t  }\n\t  /**\n\t   * Object#toString reference.\n\t   */\n\n\n\t  var objToString = Object.prototype.toString;\n\t  /**\n\t   * Checks that a / b have the same type.\n\t   *\n\t   * @private\n\t   * @param {Object} a\n\t   * @param {Object} b\n\t   * @return {boolean}\n\t   */\n\n\t  function sameType(a, b) {\n\t    return objToString.call(a) === objToString.call(b);\n\t  }\n\n\t  Base.consoleLog = consoleLog;\n\t  Base[\"abstract\"] = true;\n\t});\n\n\tvar dot = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Dot\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var inherits = utils.inherits;\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  /**\n\t   * Expose `Dot`.\n\t   */\n\n\t  module.exports = Dot;\n\t  /**\n\t   * Constructs a new `Dot` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Dot(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var width = base.window.width * 0.75 | 0;\n\t    var n = -1;\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      process$4.stdout.write('\\n');\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function () {\n\t      if (++n % width === 0) {\n\t        process$4.stdout.write('\\n  ');\n\t      }\n\n\t      process$4.stdout.write(base.color('pending', base.symbols.comma));\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      if (++n % width === 0) {\n\t        process$4.stdout.write('\\n  ');\n\t      }\n\n\t      if (test.speed === 'slow') {\n\t        process$4.stdout.write(base.color('bright yellow', base.symbols.dot));\n\t      } else {\n\t        process$4.stdout.write(base.color(test.speed, base.symbols.dot));\n\t      }\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function () {\n\t      if (++n % width === 0) {\n\t        process$4.stdout.write('\\n  ');\n\t      }\n\n\t      process$4.stdout.write(base.color('fail', base.symbols.bang));\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      process$4.stdout.write('\\n');\n\t      self.epilogue();\n\t    });\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(Dot, base);\n\t  Dot.description = 'dot matrix representation';\n\t});\n\n\tvar doc = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Doc\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;\n\t  var EVENT_SUITE_END = constants.EVENT_SUITE_END;\n\t  /**\n\t   * Expose `Doc`.\n\t   */\n\n\t  module.exports = Doc;\n\t  /**\n\t   * Constructs a new `Doc` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Doc(runner, options) {\n\t    base.call(this, runner, options);\n\t    var indents = 2;\n\n\t    function indent() {\n\t      return Array(indents).join('  ');\n\t    }\n\n\t    runner.on(EVENT_SUITE_BEGIN, function (suite) {\n\t      if (suite.root) {\n\t        return;\n\t      }\n\n\t      ++indents;\n\t      base.consoleLog('%s<section class=\"suite\">', indent());\n\t      ++indents;\n\t      base.consoleLog('%s<h1>%s</h1>', indent(), utils.escape(suite.title));\n\t      base.consoleLog('%s<dl>', indent());\n\t    });\n\t    runner.on(EVENT_SUITE_END, function (suite) {\n\t      if (suite.root) {\n\t        return;\n\t      }\n\n\t      base.consoleLog('%s</dl>', indent());\n\t      --indents;\n\t      base.consoleLog('%s</section>', indent());\n\t      --indents;\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      base.consoleLog('%s  <dt>%s</dt>', indent(), utils.escape(test.title));\n\t      base.consoleLog('%s  <dt>%s</dt>', indent(), utils.escape(test.file));\n\t      var code = utils.escape(utils.clean(test.body));\n\t      base.consoleLog('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test, err) {\n\t      base.consoleLog('%s  <dt class=\"error\">%s</dt>', indent(), utils.escape(test.title));\n\t      base.consoleLog('%s  <dt class=\"error\">%s</dt>', indent(), utils.escape(test.file));\n\t      var code = utils.escape(utils.clean(test.body));\n\t      base.consoleLog('%s  <dd class=\"error\"><pre><code>%s</code></pre></dd>', indent(), code);\n\t      base.consoleLog('%s  <dd class=\"error\">%s</dd>', indent(), utils.escape(err));\n\t    });\n\t  }\n\n\t  Doc.description = 'HTML documentation';\n\t});\n\n\tvar tap = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module TAP\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var EVENT_TEST_END = constants.EVENT_TEST_END;\n\t  var inherits = utils.inherits;\n\t  var sprintf = util.format;\n\t  /**\n\t   * Expose `TAP`.\n\t   */\n\n\t  module.exports = TAP;\n\t  /**\n\t   * Constructs a new `TAP` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function TAP(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var n = 1;\n\t    var tapVersion = '12';\n\n\t    if (options && options.reporterOptions) {\n\t      if (options.reporterOptions.tapVersion) {\n\t        tapVersion = options.reporterOptions.tapVersion.toString();\n\t      }\n\t    }\n\n\t    this._producer = createProducer(tapVersion);\n\t    runner.once(EVENT_RUN_BEGIN, function () {\n\t      self._producer.writeVersion();\n\t    });\n\t    runner.on(EVENT_TEST_END, function () {\n\t      ++n;\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function (test) {\n\t      self._producer.writePending(n, test);\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      self._producer.writePass(n, test);\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test, err) {\n\t      self._producer.writeFail(n, test, err);\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      self._producer.writeEpilogue(runner.stats);\n\t    });\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(TAP, base);\n\t  /**\n\t   * Returns a TAP-safe title of `test`.\n\t   *\n\t   * @private\n\t   * @param {Test} test - Test instance.\n\t   * @return {String} title with any hash character removed\n\t   */\n\n\t  function title(test) {\n\t    return test.fullTitle().replace(/#/g, '');\n\t  }\n\t  /**\n\t   * Writes newline-terminated formatted string to reporter output stream.\n\t   *\n\t   * @private\n\t   * @param {string} format - `printf`-like format string\n\t   * @param {...*} [varArgs] - Format string arguments\n\t   */\n\n\n\t  function println(format, varArgs) {\n\t    var vargs = Array.from(arguments);\n\t    vargs[0] += '\\n';\n\t    process$4.stdout.write(sprintf.apply(null, vargs));\n\t  }\n\t  /**\n\t   * Returns a `tapVersion`-appropriate TAP producer instance, if possible.\n\t   *\n\t   * @private\n\t   * @param {string} tapVersion - Version of TAP specification to produce.\n\t   * @returns {TAPProducer} specification-appropriate instance\n\t   * @throws {Error} if specification version has no associated producer.\n\t   */\n\n\n\t  function createProducer(tapVersion) {\n\t    var producers = {\n\t      12: new TAP12Producer(),\n\t      13: new TAP13Producer()\n\t    };\n\t    var producer = producers[tapVersion];\n\n\t    if (!producer) {\n\t      throw new Error('invalid or unsupported TAP version: ' + JSON.stringify(tapVersion));\n\t    }\n\n\t    return producer;\n\t  }\n\t  /**\n\t   * @summary\n\t   * Constructs a new TAPProducer.\n\t   *\n\t   * @description\n\t   * <em>Only</em> to be used as an abstract base class.\n\t   *\n\t   * @private\n\t   * @constructor\n\t   */\n\n\n\t  function TAPProducer() {}\n\t  /**\n\t   * Writes the TAP version to reporter output stream.\n\t   *\n\t   * @abstract\n\t   */\n\n\n\t  TAPProducer.prototype.writeVersion = function () {};\n\t  /**\n\t   * Writes the plan to reporter output stream.\n\t   *\n\t   * @abstract\n\t   * @param {number} ntests - Number of tests that are planned to run.\n\t   */\n\n\n\t  TAPProducer.prototype.writePlan = function (ntests) {\n\t    println('%d..%d', 1, ntests);\n\t  };\n\t  /**\n\t   * Writes that test passed to reporter output stream.\n\t   *\n\t   * @abstract\n\t   * @param {number} n - Index of test that passed.\n\t   * @param {Test} test - Instance containing test information.\n\t   */\n\n\n\t  TAPProducer.prototype.writePass = function (n, test) {\n\t    println('ok %d %s', n, title(test));\n\t  };\n\t  /**\n\t   * Writes that test was skipped to reporter output stream.\n\t   *\n\t   * @abstract\n\t   * @param {number} n - Index of test that was skipped.\n\t   * @param {Test} test - Instance containing test information.\n\t   */\n\n\n\t  TAPProducer.prototype.writePending = function (n, test) {\n\t    println('ok %d %s # SKIP -', n, title(test));\n\t  };\n\t  /**\n\t   * Writes that test failed to reporter output stream.\n\t   *\n\t   * @abstract\n\t   * @param {number} n - Index of test that failed.\n\t   * @param {Test} test - Instance containing test information.\n\t   * @param {Error} err - Reason the test failed.\n\t   */\n\n\n\t  TAPProducer.prototype.writeFail = function (n, test, err) {\n\t    println('not ok %d %s', n, title(test));\n\t  };\n\t  /**\n\t   * Writes the summary epilogue to reporter output stream.\n\t   *\n\t   * @abstract\n\t   * @param {Object} stats - Object containing run statistics.\n\t   */\n\n\n\t  TAPProducer.prototype.writeEpilogue = function (stats) {\n\t    // :TBD: Why is this not counting pending tests?\n\t    println('# tests ' + (stats.passes + stats.failures));\n\t    println('# pass ' + stats.passes); // :TBD: Why are we not showing pending results?\n\n\t    println('# fail ' + stats.failures);\n\t    this.writePlan(stats.passes + stats.failures + stats.pending);\n\t  };\n\t  /**\n\t   * @summary\n\t   * Constructs a new TAP12Producer.\n\t   *\n\t   * @description\n\t   * Produces output conforming to the TAP12 specification.\n\t   *\n\t   * @private\n\t   * @constructor\n\t   * @extends TAPProducer\n\t   * @see {@link https://testanything.org/tap-specification.html|Specification}\n\t   */\n\n\n\t  function TAP12Producer() {\n\t    /**\n\t     * Writes that test failed to reporter output stream, with error formatting.\n\t     * @override\n\t     */\n\t    this.writeFail = function (n, test, err) {\n\t      TAPProducer.prototype.writeFail.call(this, n, test, err);\n\n\t      if (err.message) {\n\t        println(err.message.replace(/^/gm, '  '));\n\t      }\n\n\t      if (err.stack) {\n\t        println(err.stack.replace(/^/gm, '  '));\n\t      }\n\t    };\n\t  }\n\t  /**\n\t   * Inherit from `TAPProducer.prototype`.\n\t   */\n\n\n\t  inherits(TAP12Producer, TAPProducer);\n\t  /**\n\t   * @summary\n\t   * Constructs a new TAP13Producer.\n\t   *\n\t   * @description\n\t   * Produces output conforming to the TAP13 specification.\n\t   *\n\t   * @private\n\t   * @constructor\n\t   * @extends TAPProducer\n\t   * @see {@link https://testanything.org/tap-version-13-specification.html|Specification}\n\t   */\n\n\t  function TAP13Producer() {\n\t    /**\n\t     * Writes the TAP version to reporter output stream.\n\t     * @override\n\t     */\n\t    this.writeVersion = function () {\n\t      println('TAP version 13');\n\t    };\n\t    /**\n\t     * Writes that test failed to reporter output stream, with error formatting.\n\t     * @override\n\t     */\n\n\n\t    this.writeFail = function (n, test, err) {\n\t      TAPProducer.prototype.writeFail.call(this, n, test, err);\n\t      var emitYamlBlock = err.message != null || err.stack != null;\n\n\t      if (emitYamlBlock) {\n\t        println(indent(1) + '---');\n\n\t        if (err.message) {\n\t          println(indent(2) + 'message: |-');\n\t          println(err.message.replace(/^/gm, indent(3)));\n\t        }\n\n\t        if (err.stack) {\n\t          println(indent(2) + 'stack: |-');\n\t          println(err.stack.replace(/^/gm, indent(3)));\n\t        }\n\n\t        println(indent(1) + '...');\n\t      }\n\t    };\n\n\t    function indent(level) {\n\t      return Array(level + 1).join('  ');\n\t    }\n\t  }\n\t  /**\n\t   * Inherit from `TAPProducer.prototype`.\n\t   */\n\n\n\t  inherits(TAP13Producer, TAPProducer);\n\t  TAP.description = 'TAP-compatible output';\n\t});\n\n\tvar fs = {};\n\n\tvar json = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module JSON\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var createUnsupportedError = errors.createUnsupportedError;\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_TEST_END = constants.EVENT_TEST_END;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  /**\n\t   * Expose `JSON`.\n\t   */\n\n\t  module.exports = JSONReporter;\n\t  /**\n\t   * Constructs a new `JSON` reporter instance.\n\t   *\n\t   * @public\n\t   * @class JSON\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function JSONReporter(runner) {\n\t    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var tests = [];\n\t    var pending = [];\n\t    var failures = [];\n\t    var passes = [];\n\t    var output;\n\n\t    if (options.reporterOption && options.reporterOption.output) {\n\t      if (utils.isBrowser()) {\n\t        throw createUnsupportedError('file output not supported in browser');\n\t      }\n\n\t      output = options.reporterOption.output;\n\t    }\n\n\t    runner.on(EVENT_TEST_END, function (test) {\n\t      tests.push(test);\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      passes.push(test);\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test) {\n\t      failures.push(test);\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function (test) {\n\t      pending.push(test);\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      var obj = {\n\t        stats: self.stats,\n\t        tests: tests.map(clean),\n\t        pending: pending.map(clean),\n\t        failures: failures.map(clean),\n\t        passes: passes.map(clean)\n\t      };\n\t      runner.testResults = obj;\n\t      var json = JSON.stringify(obj, null, 2);\n\n\t      if (output) {\n\t        try {\n\t          fs.mkdirSync(path.dirname(output), {\n\t            recursive: true\n\t          });\n\t          fs.writeFileSync(output, json);\n\t        } catch (err) {\n\t          console.error(\"\".concat(base.symbols.err, \" [mocha] writing output to \\\"\").concat(output, \"\\\" failed: \").concat(err.message, \"\\n\"));\n\t          process$4.stdout.write(json);\n\t        }\n\t      } else {\n\t        process$4.stdout.write(json);\n\t      }\n\t    });\n\t  }\n\t  /**\n\t   * Return a plain-object representation of `test`\n\t   * free of cyclic properties etc.\n\t   *\n\t   * @private\n\t   * @param {Object} test\n\t   * @return {Object}\n\t   */\n\n\n\t  function clean(test) {\n\t    var err = test.err || {};\n\n\t    if (err instanceof Error) {\n\t      err = errorJSON(err);\n\t    }\n\n\t    return {\n\t      title: test.title,\n\t      fullTitle: test.fullTitle(),\n\t      file: test.file,\n\t      duration: test.duration,\n\t      currentRetry: test.currentRetry(),\n\t      speed: test.speed,\n\t      err: cleanCycles(err)\n\t    };\n\t  }\n\t  /**\n\t   * Replaces any circular references inside `obj` with '[object Object]'\n\t   *\n\t   * @private\n\t   * @param {Object} obj\n\t   * @return {Object}\n\t   */\n\n\n\t  function cleanCycles(obj) {\n\t    var cache = [];\n\t    return JSON.parse(JSON.stringify(obj, function (key, value) {\n\t      if (_typeof(value) === 'object' && value !== null) {\n\t        if (cache.indexOf(value) !== -1) {\n\t          // Instead of going in a circle, we'll print [object Object]\n\t          return '' + value;\n\t        }\n\n\t        cache.push(value);\n\t      }\n\n\t      return value;\n\t    }));\n\t  }\n\t  /**\n\t   * Transform an Error object into a JSON object.\n\t   *\n\t   * @private\n\t   * @param {Error} err\n\t   * @return {Object}\n\t   */\n\n\n\t  function errorJSON(err) {\n\t    var res = {};\n\t    Object.getOwnPropertyNames(err).forEach(function (key) {\n\t      res[key] = err[key];\n\t    }, err);\n\t    return res;\n\t  }\n\n\t  JSONReporter.description = 'single JSON object';\n\t});\n\n\tvar RangeError$2 = global_1.RangeError;\n\n\t// `String.prototype.repeat` method implementation\n\t// https://tc39.es/ecma262/#sec-string.prototype.repeat\n\tvar stringRepeat = function repeat(count) {\n\t  var str = toString_1(requireObjectCoercible(this));\n\t  var result = '';\n\t  var n = toIntegerOrInfinity(count);\n\t  if (n < 0 || n == Infinity) throw RangeError$2('Wrong number of repetitions');\n\t  for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;\n\t  return result;\n\t};\n\n\tvar RangeError$1 = global_1.RangeError;\n\tvar String$1 = global_1.String;\n\tvar floor = Math.floor;\n\tvar repeat = functionUncurryThis(stringRepeat);\n\tvar stringSlice = functionUncurryThis(''.slice);\n\tvar un$ToFixed = functionUncurryThis(1.0.toFixed);\n\n\tvar pow = function (x, n, acc) {\n\t  return n === 0 ? acc : n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc);\n\t};\n\n\tvar log = function (x) {\n\t  var n = 0;\n\t  var x2 = x;\n\t  while (x2 >= 4096) {\n\t    n += 12;\n\t    x2 /= 4096;\n\t  }\n\t  while (x2 >= 2) {\n\t    n += 1;\n\t    x2 /= 2;\n\t  } return n;\n\t};\n\n\tvar multiply = function (data, n, c) {\n\t  var index = -1;\n\t  var c2 = c;\n\t  while (++index < 6) {\n\t    c2 += n * data[index];\n\t    data[index] = c2 % 1e7;\n\t    c2 = floor(c2 / 1e7);\n\t  }\n\t};\n\n\tvar divide = function (data, n) {\n\t  var index = 6;\n\t  var c = 0;\n\t  while (--index >= 0) {\n\t    c += data[index];\n\t    data[index] = floor(c / n);\n\t    c = (c % n) * 1e7;\n\t  }\n\t};\n\n\tvar dataToString = function (data) {\n\t  var index = 6;\n\t  var s = '';\n\t  while (--index >= 0) {\n\t    if (s !== '' || index === 0 || data[index] !== 0) {\n\t      var t = String$1(data[index]);\n\t      s = s === '' ? t : s + repeat('0', 7 - t.length) + t;\n\t    }\n\t  } return s;\n\t};\n\n\tvar FORCED = fails(function () {\n\t  return un$ToFixed(0.00008, 3) !== '0.000' ||\n\t    un$ToFixed(0.9, 0) !== '1' ||\n\t    un$ToFixed(1.255, 2) !== '1.25' ||\n\t    un$ToFixed(1000000000000000128.0, 0) !== '1000000000000000128';\n\t}) || !fails(function () {\n\t  // V8 ~ Android 4.3-\n\t  un$ToFixed({});\n\t});\n\n\t// `Number.prototype.toFixed` method\n\t// https://tc39.es/ecma262/#sec-number.prototype.tofixed\n\t_export({ target: 'Number', proto: true, forced: FORCED }, {\n\t  toFixed: function toFixed(fractionDigits) {\n\t    var number = thisNumberValue(this);\n\t    var fractDigits = toIntegerOrInfinity(fractionDigits);\n\t    var data = [0, 0, 0, 0, 0, 0];\n\t    var sign = '';\n\t    var result = '0';\n\t    var e, z, j, k;\n\n\t    // TODO: ES2018 increased the maximum number of fraction digits to 100, need to improve the implementation\n\t    if (fractDigits < 0 || fractDigits > 20) throw RangeError$1('Incorrect fraction digits');\n\t    // eslint-disable-next-line no-self-compare -- NaN check\n\t    if (number != number) return 'NaN';\n\t    if (number <= -1e21 || number >= 1e21) return String$1(number);\n\t    if (number < 0) {\n\t      sign = '-';\n\t      number = -number;\n\t    }\n\t    if (number > 1e-21) {\n\t      e = log(number * pow(2, 69, 1)) - 69;\n\t      z = e < 0 ? number * pow(2, -e, 1) : number / pow(2, e, 1);\n\t      z *= 0x10000000000000;\n\t      e = 52 - e;\n\t      if (e > 0) {\n\t        multiply(data, 0, z);\n\t        j = fractDigits;\n\t        while (j >= 7) {\n\t          multiply(data, 1e7, 0);\n\t          j -= 7;\n\t        }\n\t        multiply(data, pow(10, j, 1), 0);\n\t        j = e - 1;\n\t        while (j >= 23) {\n\t          divide(data, 1 << 23);\n\t          j -= 23;\n\t        }\n\t        divide(data, 1 << j);\n\t        multiply(data, 1, 1);\n\t        divide(data, 2);\n\t        result = dataToString(data);\n\t      } else {\n\t        multiply(data, 0, z);\n\t        multiply(data, 1 << -e, 0);\n\t        result = dataToString(data) + repeat('0', fractDigits);\n\t      }\n\t    }\n\t    if (fractDigits > 0) {\n\t      k = result.length;\n\t      result = sign + (k <= fractDigits\n\t        ? '0.' + repeat('0', fractDigits - k) + result\n\t        : stringSlice(result, 0, k - fractDigits) + '.' + stringSlice(result, k - fractDigits));\n\t    } else {\n\t      result = sign + result;\n\t    } return result;\n\t  }\n\t});\n\n\t/**\n\t @module browser/Progress\n\t*/\n\n\t/**\n\t * Expose `Progress`.\n\t */\n\n\tvar progress$1 = Progress;\n\t/**\n\t * Initialize a new `Progress` indicator.\n\t */\n\n\tfunction Progress() {\n\t  this.percent = 0;\n\t  this.size(0);\n\t  this.fontSize(11);\n\t  this.font('helvetica, arial, sans-serif');\n\t}\n\t/**\n\t * Set progress size to `size`.\n\t *\n\t * @public\n\t * @param {number} size\n\t * @return {Progress} Progress instance.\n\t */\n\n\n\tProgress.prototype.size = function (size) {\n\t  this._size = size;\n\t  return this;\n\t};\n\t/**\n\t * Set text to `text`.\n\t *\n\t * @public\n\t * @param {string} text\n\t * @return {Progress} Progress instance.\n\t */\n\n\n\tProgress.prototype.text = function (text) {\n\t  this._text = text;\n\t  return this;\n\t};\n\t/**\n\t * Set font size to `size`.\n\t *\n\t * @public\n\t * @param {number} size\n\t * @return {Progress} Progress instance.\n\t */\n\n\n\tProgress.prototype.fontSize = function (size) {\n\t  this._fontSize = size;\n\t  return this;\n\t};\n\t/**\n\t * Set font to `family`.\n\t *\n\t * @param {string} family\n\t * @return {Progress} Progress instance.\n\t */\n\n\n\tProgress.prototype.font = function (family) {\n\t  this._font = family;\n\t  return this;\n\t};\n\t/**\n\t * Update percentage to `n`.\n\t *\n\t * @param {number} n\n\t * @return {Progress} Progress instance.\n\t */\n\n\n\tProgress.prototype.update = function (n) {\n\t  this.percent = n;\n\t  return this;\n\t};\n\t/**\n\t * Draw on `ctx`.\n\t *\n\t * @param {CanvasRenderingContext2d} ctx\n\t * @return {Progress} Progress instance.\n\t */\n\n\n\tProgress.prototype.draw = function (ctx) {\n\t  try {\n\t    var percent = Math.min(this.percent, 100);\n\t    var size = this._size;\n\t    var half = size / 2;\n\t    var x = half;\n\t    var y = half;\n\t    var rad = half - 1;\n\t    var fontSize = this._fontSize;\n\t    ctx.font = fontSize + 'px ' + this._font;\n\t    var angle = Math.PI * 2 * (percent / 100);\n\t    ctx.clearRect(0, 0, size, size); // outer circle\n\n\t    ctx.strokeStyle = '#9f9f9f';\n\t    ctx.beginPath();\n\t    ctx.arc(x, y, rad, 0, angle, false);\n\t    ctx.stroke(); // inner circle\n\n\t    ctx.strokeStyle = '#eee';\n\t    ctx.beginPath();\n\t    ctx.arc(x, y, rad - 1, 0, angle, true);\n\t    ctx.stroke(); // text\n\n\t    var text = this._text || (percent | 0) + '%';\n\t    var w = ctx.measureText(text).width;\n\t    ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1);\n\t  } catch (ignore) {// don't fail if we can't render progress\n\t  }\n\n\t  return this;\n\t};\n\n\tvar html = createCommonjsModule(function (module, exports) {\n\t  /* eslint-env browser */\n\n\t  /**\n\t   * @module HTML\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;\n\t  var EVENT_SUITE_END = constants.EVENT_SUITE_END;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var escape = utils.escape;\n\t  /**\n\t   * Save timer references to avoid Sinon interfering (see GH-237).\n\t   */\n\n\t  var Date = commonjsGlobal.Date;\n\t  /**\n\t   * Expose `HTML`.\n\t   */\n\n\t  module.exports = HTML;\n\t  /**\n\t   * Stats template.\n\t   */\n\n\t  var statsTemplate = '<ul id=\"mocha-stats\">' + '<li class=\"progress\"><canvas width=\"40\" height=\"40\"></canvas></li>' + '<li class=\"passes\"><a href=\"javascript:void(0);\">passes:</a> <em>0</em></li>' + '<li class=\"failures\"><a href=\"javascript:void(0);\">failures:</a> <em>0</em></li>' + '<li class=\"duration\">duration: <em>0</em>s</li>' + '</ul>';\n\t  var playIcon = '&#x2023;';\n\t  /**\n\t   * Constructs a new `HTML` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function HTML(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var stats = this.stats;\n\t    var stat = fragment(statsTemplate);\n\t    var items = stat.getElementsByTagName('li');\n\t    var passes = items[1].getElementsByTagName('em')[0];\n\t    var passesLink = items[1].getElementsByTagName('a')[0];\n\t    var failures = items[2].getElementsByTagName('em')[0];\n\t    var failuresLink = items[2].getElementsByTagName('a')[0];\n\t    var duration = items[3].getElementsByTagName('em')[0];\n\t    var canvas = stat.getElementsByTagName('canvas')[0];\n\t    var report = fragment('<ul id=\"mocha-report\"></ul>');\n\t    var stack = [report];\n\t    var progress;\n\t    var ctx;\n\t    var root = document.getElementById('mocha');\n\n\t    if (canvas.getContext) {\n\t      var ratio = window.devicePixelRatio || 1;\n\t      canvas.style.width = canvas.width;\n\t      canvas.style.height = canvas.height;\n\t      canvas.width *= ratio;\n\t      canvas.height *= ratio;\n\t      ctx = canvas.getContext('2d');\n\t      ctx.scale(ratio, ratio);\n\t      progress = new progress$1();\n\t    }\n\n\t    if (!root) {\n\t      return error('#mocha div missing, add it to your document');\n\t    } // pass toggle\n\n\n\t    on(passesLink, 'click', function (evt) {\n\t      evt.preventDefault();\n\t      unhide();\n\t      var name = /pass/.test(report.className) ? '' : ' pass';\n\t      report.className = report.className.replace(/fail|pass/g, '') + name;\n\n\t      if (report.className.trim()) {\n\t        hideSuitesWithout('test pass');\n\t      }\n\t    }); // failure toggle\n\n\t    on(failuresLink, 'click', function (evt) {\n\t      evt.preventDefault();\n\t      unhide();\n\t      var name = /fail/.test(report.className) ? '' : ' fail';\n\t      report.className = report.className.replace(/fail|pass/g, '') + name;\n\n\t      if (report.className.trim()) {\n\t        hideSuitesWithout('test fail');\n\t      }\n\t    });\n\t    root.appendChild(stat);\n\t    root.appendChild(report);\n\n\t    if (progress) {\n\t      progress.size(40);\n\t    }\n\n\t    runner.on(EVENT_SUITE_BEGIN, function (suite) {\n\t      if (suite.root) {\n\t        return;\n\t      } // suite\n\n\n\t      var url = self.suiteURL(suite);\n\t      var el = fragment('<li class=\"suite\"><h1><a href=\"%s\">%s</a></h1></li>', url, escape(suite.title)); // container\n\n\t      stack[0].appendChild(el);\n\t      stack.unshift(document.createElement('ul'));\n\t      el.appendChild(stack[0]);\n\t    });\n\t    runner.on(EVENT_SUITE_END, function (suite) {\n\t      if (suite.root) {\n\t        updateStats();\n\t        return;\n\t      }\n\n\t      stack.shift();\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      var url = self.testURL(test);\n\t      var markup = '<li class=\"test pass %e\"><h2>%e<span class=\"duration\">%ems</span> ' + '<a href=\"%s\" class=\"replay\">' + playIcon + '</a></h2></li>';\n\t      var el = fragment(markup, test.speed, test.title, test.duration, url);\n\t      self.addCodeToggle(el, test.body);\n\t      appendToStack(el);\n\t      updateStats();\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test) {\n\t      var el = fragment('<li class=\"test fail\"><h2>%e <a href=\"%e\" class=\"replay\">' + playIcon + '</a></h2></li>', test.title, self.testURL(test));\n\t      var stackString; // Note: Includes leading newline\n\n\t      var message = test.err.toString(); // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we\n\t      // check for the result of the stringifying.\n\n\t      if (message === '[object Error]') {\n\t        message = test.err.message;\n\t      }\n\n\t      if (test.err.stack) {\n\t        var indexOfMessage = test.err.stack.indexOf(test.err.message);\n\n\t        if (indexOfMessage === -1) {\n\t          stackString = test.err.stack;\n\t        } else {\n\t          stackString = test.err.stack.substr(test.err.message.length + indexOfMessage);\n\t        }\n\t      } else if (test.err.sourceURL && test.err.line !== undefined) {\n\t        // Safari doesn't give you a stack. Let's at least provide a source line.\n\t        stackString = '\\n(' + test.err.sourceURL + ':' + test.err.line + ')';\n\t      }\n\n\t      stackString = stackString || '';\n\n\t      if (test.err.htmlMessage && stackString) {\n\t        el.appendChild(fragment('<div class=\"html-error\">%s\\n<pre class=\"error\">%e</pre></div>', test.err.htmlMessage, stackString));\n\t      } else if (test.err.htmlMessage) {\n\t        el.appendChild(fragment('<div class=\"html-error\">%s</div>', test.err.htmlMessage));\n\t      } else {\n\t        el.appendChild(fragment('<pre class=\"error\">%e%e</pre>', message, stackString));\n\t      }\n\n\t      self.addCodeToggle(el, test.body);\n\t      appendToStack(el);\n\t      updateStats();\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function (test) {\n\t      var el = fragment('<li class=\"test pass pending\"><h2>%e</h2></li>', test.title);\n\t      appendToStack(el);\n\t      updateStats();\n\t    });\n\n\t    function appendToStack(el) {\n\t      // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.\n\t      if (stack[0]) {\n\t        stack[0].appendChild(el);\n\t      }\n\t    }\n\n\t    function updateStats() {\n\t      // TODO: add to stats\n\t      var percent = stats.tests / runner.total * 100 | 0;\n\n\t      if (progress) {\n\t        progress.update(percent).draw(ctx);\n\t      } // update stats\n\n\n\t      var ms = new Date() - stats.start;\n\t      text(passes, stats.passes);\n\t      text(failures, stats.failures);\n\t      text(duration, (ms / 1000).toFixed(2));\n\t    }\n\t  }\n\t  /**\n\t   * Makes a URL, preserving querystring (\"search\") parameters.\n\t   *\n\t   * @param {string} s\n\t   * @return {string} A new URL.\n\t   */\n\n\n\t  function makeUrl(s) {\n\t    var search = window.location.search; // Remove previous grep query parameter if present\n\n\t    if (search) {\n\t      search = search.replace(/[?&]grep=[^&\\s]*/g, '').replace(/^&/, '?');\n\t    }\n\n\t    return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeStringRegexp(s));\n\t  }\n\t  /**\n\t   * Provide suite URL.\n\t   *\n\t   * @param {Object} [suite]\n\t   */\n\n\n\t  HTML.prototype.suiteURL = function (suite) {\n\t    return makeUrl(suite.fullTitle());\n\t  };\n\t  /**\n\t   * Provide test URL.\n\t   *\n\t   * @param {Object} [test]\n\t   */\n\n\n\t  HTML.prototype.testURL = function (test) {\n\t    return makeUrl(test.fullTitle());\n\t  };\n\t  /**\n\t   * Adds code toggle functionality for the provided test's list element.\n\t   *\n\t   * @param {HTMLLIElement} el\n\t   * @param {string} contents\n\t   */\n\n\n\t  HTML.prototype.addCodeToggle = function (el, contents) {\n\t    var h2 = el.getElementsByTagName('h2')[0];\n\t    on(h2, 'click', function () {\n\t      pre.style.display = pre.style.display === 'none' ? 'block' : 'none';\n\t    });\n\t    var pre = fragment('<pre><code>%e</code></pre>', utils.clean(contents));\n\t    el.appendChild(pre);\n\t    pre.style.display = 'none';\n\t  };\n\t  /**\n\t   * Display error `msg`.\n\t   *\n\t   * @param {string} msg\n\t   */\n\n\n\t  function error(msg) {\n\t    document.body.appendChild(fragment('<div id=\"mocha-error\">%s</div>', msg));\n\t  }\n\t  /**\n\t   * Return a DOM fragment from `html`.\n\t   *\n\t   * @param {string} html\n\t   */\n\n\n\t  function fragment(html) {\n\t    var args = arguments;\n\t    var div = document.createElement('div');\n\t    var i = 1;\n\t    div.innerHTML = html.replace(/%([se])/g, function (_, type) {\n\t      switch (type) {\n\t        case 's':\n\t          return String(args[i++]);\n\n\t        case 'e':\n\t          return escape(args[i++]);\n\t        // no default\n\t      }\n\t    });\n\t    return div.firstChild;\n\t  }\n\t  /**\n\t   * Check for suites that do not have elements\n\t   * with `classname`, and hide them.\n\t   *\n\t   * @param {text} classname\n\t   */\n\n\n\t  function hideSuitesWithout(classname) {\n\t    var suites = document.getElementsByClassName('suite');\n\n\t    for (var i = 0; i < suites.length; i++) {\n\t      var els = suites[i].getElementsByClassName(classname);\n\n\t      if (!els.length) {\n\t        suites[i].className += ' hidden';\n\t      }\n\t    }\n\t  }\n\t  /**\n\t   * Unhide .hidden suites.\n\t   */\n\n\n\t  function unhide() {\n\t    var els = document.getElementsByClassName('suite hidden');\n\n\t    while (els.length > 0) {\n\t      els[0].className = els[0].className.replace('suite hidden', 'suite');\n\t    }\n\t  }\n\t  /**\n\t   * Set an element's text contents.\n\t   *\n\t   * @param {HTMLElement} el\n\t   * @param {string} contents\n\t   */\n\n\n\t  function text(el, contents) {\n\t    if (el.textContent) {\n\t      el.textContent = contents;\n\t    } else {\n\t      el.innerText = contents;\n\t    }\n\t  }\n\t  /**\n\t   * Listen on `event` with callback `fn`.\n\t   */\n\n\n\t  function on(el, event, fn) {\n\t    if (el.addEventListener) {\n\t      el.addEventListener(event, fn, false);\n\t    } else {\n\t      el.attachEvent('on' + event, fn);\n\t    }\n\t  }\n\n\t  HTML.browserOnly = true;\n\t});\n\n\tvar list = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module List\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var inherits = utils.inherits;\n\t  var constants = runner.constants;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_TEST_BEGIN = constants.EVENT_TEST_BEGIN;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var color = base.color;\n\t  var cursor = base.cursor;\n\t  /**\n\t   * Expose `List`.\n\t   */\n\n\t  module.exports = List;\n\t  /**\n\t   * Constructs a new `List` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function List(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var n = 0;\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      base.consoleLog();\n\t    });\n\t    runner.on(EVENT_TEST_BEGIN, function (test) {\n\t      process$4.stdout.write(color('pass', '    ' + test.fullTitle() + ': '));\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function (test) {\n\t      var fmt = color('checkmark', '  -') + color('pending', ' %s');\n\t      base.consoleLog(fmt, test.fullTitle());\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      var fmt = color('checkmark', '  ' + base.symbols.ok) + color('pass', ' %s: ') + color(test.speed, '%dms');\n\t      cursor.CR();\n\t      base.consoleLog(fmt, test.fullTitle(), test.duration);\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test) {\n\t      cursor.CR();\n\t      base.consoleLog(color('fail', '  %d) %s'), ++n, test.fullTitle());\n\t    });\n\t    runner.once(EVENT_RUN_END, self.epilogue.bind(self));\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(List, base);\n\t  List.description = 'like \"spec\" reporter but flat';\n\t});\n\n\tvar min = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Min\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var inherits = utils.inherits;\n\t  var constants = runner.constants;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  /**\n\t   * Expose `Min`.\n\t   */\n\n\t  module.exports = Min;\n\t  /**\n\t   * Constructs a new `Min` reporter instance.\n\t   *\n\t   * @description\n\t   * This minimal test reporter is best used with '--watch'.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Min(runner, options) {\n\t    base.call(this, runner, options);\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      // clear screen\n\t      process$4.stdout.write(\"\\x1B[2J\"); // set cursor position\n\n\t      process$4.stdout.write(\"\\x1B[1;3H\");\n\t    });\n\t    runner.once(EVENT_RUN_END, this.epilogue.bind(this));\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(Min, base);\n\t  Min.description = 'essentially just a summary';\n\t});\n\n\tvar spec = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Spec\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;\n\t  var EVENT_SUITE_END = constants.EVENT_SUITE_END;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var inherits = utils.inherits;\n\t  var color = base.color;\n\t  /**\n\t   * Expose `Spec`.\n\t   */\n\n\t  module.exports = Spec;\n\t  /**\n\t   * Constructs a new `Spec` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Spec(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var indents = 0;\n\t    var n = 0;\n\n\t    function indent() {\n\t      return Array(indents).join('  ');\n\t    }\n\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      base.consoleLog();\n\t    });\n\t    runner.on(EVENT_SUITE_BEGIN, function (suite) {\n\t      ++indents;\n\t      base.consoleLog(color('suite', '%s%s'), indent(), suite.title);\n\t    });\n\t    runner.on(EVENT_SUITE_END, function () {\n\t      --indents;\n\n\t      if (indents === 1) {\n\t        base.consoleLog();\n\t      }\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function (test) {\n\t      var fmt = indent() + color('pending', '  - %s');\n\t      base.consoleLog(fmt, test.title);\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      var fmt;\n\n\t      if (test.speed === 'fast') {\n\t        fmt = indent() + color('checkmark', '  ' + base.symbols.ok) + color('pass', ' %s');\n\t        base.consoleLog(fmt, test.title);\n\t      } else {\n\t        fmt = indent() + color('checkmark', '  ' + base.symbols.ok) + color('pass', ' %s') + color(test.speed, ' (%dms)');\n\t        base.consoleLog(fmt, test.title, test.duration);\n\t      }\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test) {\n\t      base.consoleLog(indent() + color('fail', '  %d) %s'), ++n, test.title);\n\t    });\n\t    runner.once(EVENT_RUN_END, self.epilogue.bind(self));\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(Spec, base);\n\t  Spec.description = 'hierarchical & verbose [default]';\n\t});\n\n\tvar nyan = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Nyan\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var inherits = utils.inherits;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  /**\n\t   * Expose `Dot`.\n\t   */\n\n\t  module.exports = NyanCat;\n\t  /**\n\t   * Constructs a new `Nyan` reporter instance.\n\t   *\n\t   * @public\n\t   * @class Nyan\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function NyanCat(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var width = base.window.width * 0.75 | 0;\n\t    var nyanCatWidth = this.nyanCatWidth = 11;\n\t    this.colorIndex = 0;\n\t    this.numberOfLines = 4;\n\t    this.rainbowColors = self.generateColors();\n\t    this.scoreboardWidth = 5;\n\t    this.tick = 0;\n\t    this.trajectories = [[], [], [], []];\n\t    this.trajectoryWidthMax = width - nyanCatWidth;\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      base.cursor.hide();\n\t      self.draw();\n\t    });\n\t    runner.on(EVENT_TEST_PENDING, function () {\n\t      self.draw();\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function () {\n\t      self.draw();\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function () {\n\t      self.draw();\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      base.cursor.show();\n\n\t      for (var i = 0; i < self.numberOfLines; i++) {\n\t        write('\\n');\n\t      }\n\n\t      self.epilogue();\n\t    });\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(NyanCat, base);\n\t  /**\n\t   * Draw the nyan cat\n\t   *\n\t   * @private\n\t   */\n\n\t  NyanCat.prototype.draw = function () {\n\t    this.appendRainbow();\n\t    this.drawScoreboard();\n\t    this.drawRainbow();\n\t    this.drawNyanCat();\n\t    this.tick = !this.tick;\n\t  };\n\t  /**\n\t   * Draw the \"scoreboard\" showing the number\n\t   * of passes, failures and pending tests.\n\t   *\n\t   * @private\n\t   */\n\n\n\t  NyanCat.prototype.drawScoreboard = function () {\n\t    var stats = this.stats;\n\n\t    function draw(type, n) {\n\t      write(' ');\n\t      write(base.color(type, n));\n\t      write('\\n');\n\t    }\n\n\t    draw('green', stats.passes);\n\t    draw('fail', stats.failures);\n\t    draw('pending', stats.pending);\n\t    write('\\n');\n\t    this.cursorUp(this.numberOfLines);\n\t  };\n\t  /**\n\t   * Append the rainbow.\n\t   *\n\t   * @private\n\t   */\n\n\n\t  NyanCat.prototype.appendRainbow = function () {\n\t    var segment = this.tick ? '_' : '-';\n\t    var rainbowified = this.rainbowify(segment);\n\n\t    for (var index = 0; index < this.numberOfLines; index++) {\n\t      var trajectory = this.trajectories[index];\n\n\t      if (trajectory.length >= this.trajectoryWidthMax) {\n\t        trajectory.shift();\n\t      }\n\n\t      trajectory.push(rainbowified);\n\t    }\n\t  };\n\t  /**\n\t   * Draw the rainbow.\n\t   *\n\t   * @private\n\t   */\n\n\n\t  NyanCat.prototype.drawRainbow = function () {\n\t    var self = this;\n\t    this.trajectories.forEach(function (line) {\n\t      write(\"\\x1B[\" + self.scoreboardWidth + 'C');\n\t      write(line.join(''));\n\t      write('\\n');\n\t    });\n\t    this.cursorUp(this.numberOfLines);\n\t  };\n\t  /**\n\t   * Draw the nyan cat\n\t   *\n\t   * @private\n\t   */\n\n\n\t  NyanCat.prototype.drawNyanCat = function () {\n\t    var self = this;\n\t    var startWidth = this.scoreboardWidth + this.trajectories[0].length;\n\t    var dist = \"\\x1B[\" + startWidth + 'C';\n\t    var padding = '';\n\t    write(dist);\n\t    write('_,------,');\n\t    write('\\n');\n\t    write(dist);\n\t    padding = self.tick ? '  ' : '   ';\n\t    write('_|' + padding + '/\\\\_/\\\\ ');\n\t    write('\\n');\n\t    write(dist);\n\t    padding = self.tick ? '_' : '__';\n\t    var tail = self.tick ? '~' : '^';\n\t    write(tail + '|' + padding + this.face() + ' ');\n\t    write('\\n');\n\t    write(dist);\n\t    padding = self.tick ? ' ' : '  ';\n\t    write(padding + '\"\"  \"\" ');\n\t    write('\\n');\n\t    this.cursorUp(this.numberOfLines);\n\t  };\n\t  /**\n\t   * Draw nyan cat face.\n\t   *\n\t   * @private\n\t   * @return {string}\n\t   */\n\n\n\t  NyanCat.prototype.face = function () {\n\t    var stats = this.stats;\n\n\t    if (stats.failures) {\n\t      return '( x .x)';\n\t    } else if (stats.pending) {\n\t      return '( o .o)';\n\t    } else if (stats.passes) {\n\t      return '( ^ .^)';\n\t    }\n\n\t    return '( - .-)';\n\t  };\n\t  /**\n\t   * Move cursor up `n`.\n\t   *\n\t   * @private\n\t   * @param {number} n\n\t   */\n\n\n\t  NyanCat.prototype.cursorUp = function (n) {\n\t    write(\"\\x1B[\" + n + 'A');\n\t  };\n\t  /**\n\t   * Move cursor down `n`.\n\t   *\n\t   * @private\n\t   * @param {number} n\n\t   */\n\n\n\t  NyanCat.prototype.cursorDown = function (n) {\n\t    write(\"\\x1B[\" + n + 'B');\n\t  };\n\t  /**\n\t   * Generate rainbow colors.\n\t   *\n\t   * @private\n\t   * @return {Array}\n\t   */\n\n\n\t  NyanCat.prototype.generateColors = function () {\n\t    var colors = [];\n\n\t    for (var i = 0; i < 6 * 7; i++) {\n\t      var pi3 = Math.floor(Math.PI / 3);\n\t      var n = i * (1.0 / 6);\n\t      var r = Math.floor(3 * Math.sin(n) + 3);\n\t      var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);\n\t      var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);\n\t      colors.push(36 * r + 6 * g + b + 16);\n\t    }\n\n\t    return colors;\n\t  };\n\t  /**\n\t   * Apply rainbow to the given `str`.\n\t   *\n\t   * @private\n\t   * @param {string} str\n\t   * @return {string}\n\t   */\n\n\n\t  NyanCat.prototype.rainbowify = function (str) {\n\t    if (!base.useColors) {\n\t      return str;\n\t    }\n\n\t    var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];\n\t    this.colorIndex += 1;\n\t    return \"\\x1B[38;5;\" + color + 'm' + str + \"\\x1B[0m\";\n\t  };\n\t  /**\n\t   * Stdout helper.\n\t   *\n\t   * @param {string} string A message to write to stdout.\n\t   */\n\n\n\t  function write(string) {\n\t    process$4.stdout.write(string);\n\t  }\n\n\t  NyanCat.description = '\"nyan cat\"';\n\t});\n\n\tvar xunit = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module XUnit\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var createUnsupportedError = errors.createUnsupportedError;\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\t  var STATE_FAILED = runnable.constants.STATE_FAILED;\n\t  var inherits = utils.inherits;\n\t  var escape = utils.escape;\n\t  /**\n\t   * Save timer references to avoid Sinon interfering (see GH-237).\n\t   */\n\n\t  var Date = commonjsGlobal.Date;\n\t  /**\n\t   * Expose `XUnit`.\n\t   */\n\n\t  module.exports = XUnit;\n\t  /**\n\t   * Constructs a new `XUnit` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function XUnit(runner, options) {\n\t    base.call(this, runner, options);\n\t    var stats = this.stats;\n\t    var tests = [];\n\t    var self = this; // the name of the test suite, as it will appear in the resulting XML file\n\n\t    var suiteName; // the default name of the test suite if none is provided\n\n\t    var DEFAULT_SUITE_NAME = 'Mocha Tests';\n\n\t    if (options && options.reporterOptions) {\n\t      if (options.reporterOptions.output) {\n\t        if (!fs.createWriteStream) {\n\t          throw createUnsupportedError('file output not supported in browser');\n\t        }\n\n\t        fs.mkdirSync(path.dirname(options.reporterOptions.output), {\n\t          recursive: true\n\t        });\n\t        self.fileStream = fs.createWriteStream(options.reporterOptions.output);\n\t      } // get the suite name from the reporter options (if provided)\n\n\n\t      suiteName = options.reporterOptions.suiteName;\n\t    } // fall back to the default suite name\n\n\n\t    suiteName = suiteName || DEFAULT_SUITE_NAME;\n\t    runner.on(EVENT_TEST_PENDING, function (test) {\n\t      tests.push(test);\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      tests.push(test);\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test) {\n\t      tests.push(test);\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      self.write(tag('testsuite', {\n\t        name: suiteName,\n\t        tests: stats.tests,\n\t        failures: 0,\n\t        errors: stats.failures,\n\t        skipped: stats.tests - stats.failures - stats.passes,\n\t        timestamp: new Date().toUTCString(),\n\t        time: stats.duration / 1000 || 0\n\t      }, false));\n\t      tests.forEach(function (t) {\n\t        self.test(t);\n\t      });\n\t      self.write('</testsuite>');\n\t    });\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(XUnit, base);\n\t  /**\n\t   * Override done to close the stream (if it's a file).\n\t   *\n\t   * @param failures\n\t   * @param {Function} fn\n\t   */\n\n\t  XUnit.prototype.done = function (failures, fn) {\n\t    if (this.fileStream) {\n\t      this.fileStream.end(function () {\n\t        fn(failures);\n\t      });\n\t    } else {\n\t      fn(failures);\n\t    }\n\t  };\n\t  /**\n\t   * Write out the given line.\n\t   *\n\t   * @param {string} line\n\t   */\n\n\n\t  XUnit.prototype.write = function (line) {\n\t    if (this.fileStream) {\n\t      this.fileStream.write(line + '\\n');\n\t    } else if (_typeof(process$4) === 'object' && process$4.stdout) {\n\t      process$4.stdout.write(line + '\\n');\n\t    } else {\n\t      base.consoleLog(line);\n\t    }\n\t  };\n\t  /**\n\t   * Output tag for the given `test.`\n\t   *\n\t   * @param {Test} test\n\t   */\n\n\n\t  XUnit.prototype.test = function (test) {\n\t    base.useColors = false;\n\t    var attrs = {\n\t      classname: test.parent.fullTitle(),\n\t      name: test.title,\n\t      time: test.duration / 1000 || 0\n\t    };\n\n\t    if (test.state === STATE_FAILED) {\n\t      var err = test.err;\n\t      var diff = !base.hideDiff && base.showDiff(err) ? '\\n' + base.generateDiff(err.actual, err.expected) : '';\n\t      this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + escape(diff) + '\\n' + escape(err.stack))));\n\t    } else if (test.isPending()) {\n\t      this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));\n\t    } else {\n\t      this.write(tag('testcase', attrs, true));\n\t    }\n\t  };\n\t  /**\n\t   * HTML tag helper.\n\t   *\n\t   * @param name\n\t   * @param attrs\n\t   * @param close\n\t   * @param content\n\t   * @return {string}\n\t   */\n\n\n\t  function tag(name, attrs, close, content) {\n\t    var end = close ? '/>' : '>';\n\t    var pairs = [];\n\t    var tag;\n\n\t    for (var key in attrs) {\n\t      if (Object.prototype.hasOwnProperty.call(attrs, key)) {\n\t        pairs.push(key + '=\"' + escape(attrs[key]) + '\"');\n\t      }\n\t    }\n\n\t    tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;\n\n\t    if (content) {\n\t      tag += content + '</' + name + end;\n\t    }\n\n\t    return tag;\n\t  }\n\n\t  XUnit.description = 'XUnit-compatible XML output';\n\t});\n\n\tvar markdown = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Markdown\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;\n\t  var EVENT_SUITE_END = constants.EVENT_SUITE_END;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  /**\n\t   * Constants\n\t   */\n\n\t  var SUITE_PREFIX = '$';\n\t  /**\n\t   * Expose `Markdown`.\n\t   */\n\n\t  module.exports = Markdown;\n\t  /**\n\t   * Constructs a new `Markdown` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Markdown(runner, options) {\n\t    base.call(this, runner, options);\n\t    var level = 0;\n\t    var buf = '';\n\n\t    function title(str) {\n\t      return Array(level).join('#') + ' ' + str;\n\t    }\n\n\t    function mapTOC(suite, obj) {\n\t      var ret = obj;\n\t      var key = SUITE_PREFIX + suite.title;\n\t      obj = obj[key] = obj[key] || {\n\t        suite: suite\n\t      };\n\t      suite.suites.forEach(function (suite) {\n\t        mapTOC(suite, obj);\n\t      });\n\t      return ret;\n\t    }\n\n\t    function stringifyTOC(obj, level) {\n\t      ++level;\n\t      var buf = '';\n\t      var link;\n\n\t      for (var key in obj) {\n\t        if (key === 'suite') {\n\t          continue;\n\t        }\n\n\t        if (key !== SUITE_PREFIX) {\n\t          link = ' - [' + key.substring(1) + ']';\n\t          link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\\n';\n\t          buf += Array(level).join('  ') + link;\n\t        }\n\n\t        buf += stringifyTOC(obj[key], level);\n\t      }\n\n\t      return buf;\n\t    }\n\n\t    function generateTOC(suite) {\n\t      var obj = mapTOC(suite, {});\n\t      return stringifyTOC(obj, 0);\n\t    }\n\n\t    generateTOC(runner.suite);\n\t    runner.on(EVENT_SUITE_BEGIN, function (suite) {\n\t      ++level;\n\t      var slug = utils.slug(suite.fullTitle());\n\t      buf += '<a name=\"' + slug + '\"></a>' + '\\n';\n\t      buf += title(suite.title) + '\\n';\n\t    });\n\t    runner.on(EVENT_SUITE_END, function () {\n\t      --level;\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      var code = utils.clean(test.body);\n\t      buf += test.title + '.\\n';\n\t      buf += '\\n```js\\n';\n\t      buf += code + '\\n';\n\t      buf += '```\\n\\n';\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      process$4.stdout.write('# TOC\\n');\n\t      process$4.stdout.write(generateTOC(runner.suite));\n\t      process$4.stdout.write(buf);\n\t    });\n\t  }\n\n\t  Markdown.description = 'GitHub Flavored Markdown';\n\t});\n\n\tvar progress = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Progress\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_TEST_END = constants.EVENT_TEST_END;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var inherits = utils.inherits;\n\t  var color = base.color;\n\t  var cursor = base.cursor;\n\t  /**\n\t   * Expose `Progress`.\n\t   */\n\n\t  module.exports = Progress;\n\t  /**\n\t   * General progress bar color.\n\t   */\n\n\t  base.colors.progress = 90;\n\t  /**\n\t   * Constructs a new `Progress` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Progress(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var width = base.window.width * 0.5 | 0;\n\t    var total = runner.total;\n\t    var complete = 0;\n\t    var lastN = -1; // default chars\n\n\t    options = options || {};\n\t    var reporterOptions = options.reporterOptions || {};\n\t    options.open = reporterOptions.open || '[';\n\t    options.complete = reporterOptions.complete || '▬';\n\t    options.incomplete = reporterOptions.incomplete || base.symbols.dot;\n\t    options.close = reporterOptions.close || ']';\n\t    options.verbose = reporterOptions.verbose || false; // tests started\n\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      process$4.stdout.write('\\n');\n\t      cursor.hide();\n\t    }); // tests complete\n\n\t    runner.on(EVENT_TEST_END, function () {\n\t      complete++;\n\t      var percent = complete / total;\n\t      var n = width * percent | 0;\n\t      var i = width - n;\n\n\t      if (n === lastN && !options.verbose) {\n\t        // Don't re-render the line if it hasn't changed\n\t        return;\n\t      }\n\n\t      lastN = n;\n\t      cursor.CR();\n\t      process$4.stdout.write(\"\\x1B[J\");\n\t      process$4.stdout.write(color('progress', '  ' + options.open));\n\t      process$4.stdout.write(Array(n).join(options.complete));\n\t      process$4.stdout.write(Array(i).join(options.incomplete));\n\t      process$4.stdout.write(color('progress', options.close));\n\n\t      if (options.verbose) {\n\t        process$4.stdout.write(color('progress', ' ' + complete + ' of ' + total));\n\t      }\n\t    }); // tests are complete, output some stats\n\t    // and the failures if any\n\n\t    runner.once(EVENT_RUN_END, function () {\n\t      cursor.show();\n\t      process$4.stdout.write('\\n');\n\t      self.epilogue();\n\t    });\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(Progress, base);\n\t  Progress.description = 'a progress bar';\n\t});\n\n\tvar landing = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module Landing\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var inherits = utils.inherits;\n\t  var constants = runner.constants;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  var EVENT_TEST_END = constants.EVENT_TEST_END;\n\t  var STATE_FAILED = runnable.constants.STATE_FAILED;\n\t  var cursor = base.cursor;\n\t  var color = base.color;\n\t  /**\n\t   * Expose `Landing`.\n\t   */\n\n\t  module.exports = Landing;\n\t  /**\n\t   * Airplane color.\n\t   */\n\n\t  base.colors.plane = 0;\n\t  /**\n\t   * Airplane crash color.\n\t   */\n\n\t  base.colors['plane crash'] = 31;\n\t  /**\n\t   * Runway color.\n\t   */\n\n\t  base.colors.runway = 90;\n\t  /**\n\t   * Constructs a new `Landing` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function Landing(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var width = base.window.width * 0.75 | 0;\n\t    var stream = process$4.stdout;\n\t    var plane = color('plane', '✈');\n\t    var crashed = -1;\n\t    var n = 0;\n\t    var total = 0;\n\n\t    function runway() {\n\t      var buf = Array(width).join('-');\n\t      return '  ' + color('runway', buf);\n\t    }\n\n\t    runner.on(EVENT_RUN_BEGIN, function () {\n\t      stream.write('\\n\\n\\n  ');\n\t      cursor.hide();\n\t    });\n\t    runner.on(EVENT_TEST_END, function (test) {\n\t      // check if the plane crashed\n\t      var col = crashed === -1 ? width * ++n / ++total | 0 : crashed; // show the crash\n\n\t      if (test.state === STATE_FAILED) {\n\t        plane = color('plane crash', '✈');\n\t        crashed = col;\n\t      } // render landing strip\n\n\n\t      stream.write(\"\\x1B[\" + (width + 1) + \"D\\x1B[2A\");\n\t      stream.write(runway());\n\t      stream.write('\\n  ');\n\t      stream.write(color('runway', Array(col).join('⋅')));\n\t      stream.write(plane);\n\t      stream.write(color('runway', Array(width - col).join('⋅') + '\\n'));\n\t      stream.write(runway());\n\t      stream.write(\"\\x1B[0m\");\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      cursor.show();\n\t      process$4.stdout.write('\\n');\n\t      self.epilogue();\n\t    }); // if cursor is hidden when we ctrl-C, then it will remain hidden unless...\n\n\t    process$4.once('SIGINT', function () {\n\t      cursor.show();\n\t      nextTick$1(function () {\n\t        process$4.kill(process$4.pid, 'SIGINT');\n\t      });\n\t    });\n\t  }\n\t  /**\n\t   * Inherit from `Base.prototype`.\n\t   */\n\n\n\t  inherits(Landing, base);\n\t  Landing.description = 'Unicode landing strip';\n\t});\n\n\tvar jsonStream = createCommonjsModule(function (module, exports) {\n\t  /**\n\t   * @module JSONStream\n\t   */\n\n\t  /**\n\t   * Module dependencies.\n\t   */\n\n\t  var constants = runner.constants;\n\t  var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\t  var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\t  var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\t  var EVENT_RUN_END = constants.EVENT_RUN_END;\n\t  /**\n\t   * Expose `JSONStream`.\n\t   */\n\n\t  module.exports = JSONStream;\n\t  /**\n\t   * Constructs a new `JSONStream` reporter instance.\n\t   *\n\t   * @public\n\t   * @class\n\t   * @memberof Mocha.reporters\n\t   * @extends Mocha.reporters.Base\n\t   * @param {Runner} runner - Instance triggers reporter actions.\n\t   * @param {Object} [options] - runner options\n\t   */\n\n\t  function JSONStream(runner, options) {\n\t    base.call(this, runner, options);\n\t    var self = this;\n\t    var total = runner.total;\n\t    runner.once(EVENT_RUN_BEGIN, function () {\n\t      writeEvent(['start', {\n\t        total: total\n\t      }]);\n\t    });\n\t    runner.on(EVENT_TEST_PASS, function (test) {\n\t      writeEvent(['pass', clean(test)]);\n\t    });\n\t    runner.on(EVENT_TEST_FAIL, function (test, err) {\n\t      test = clean(test);\n\t      test.err = err.message;\n\t      test.stack = err.stack || null;\n\t      writeEvent(['fail', test]);\n\t    });\n\t    runner.once(EVENT_RUN_END, function () {\n\t      writeEvent(['end', self.stats]);\n\t    });\n\t  }\n\t  /**\n\t   * Mocha event to be written to the output stream.\n\t   * @typedef {Array} JSONStream~MochaEvent\n\t   */\n\n\t  /**\n\t   * Writes Mocha event to reporter output stream.\n\t   *\n\t   * @private\n\t   * @param {JSONStream~MochaEvent} event - Mocha event to be output.\n\t   */\n\n\n\t  function writeEvent(event) {\n\t    process$4.stdout.write(JSON.stringify(event) + '\\n');\n\t  }\n\t  /**\n\t   * Returns an object literal representation of `test`\n\t   * free of cyclic properties, etc.\n\t   *\n\t   * @private\n\t   * @param {Test} test - Instance used as data source.\n\t   * @return {Object} object containing pared-down test instance data\n\t   */\n\n\n\t  function clean(test) {\n\t    return {\n\t      title: test.title,\n\t      fullTitle: test.fullTitle(),\n\t      file: test.file,\n\t      duration: test.duration,\n\t      currentRetry: test.currentRetry(),\n\t      speed: test.speed\n\t    };\n\t  }\n\n\t  JSONStream.description = 'newline delimited JSON events';\n\t});\n\n\tvar reporters = createCommonjsModule(function (module, exports) {\n\t  // for dynamic (try/catch) requires, which Browserify doesn't handle.\n\n\t  exports.Base = exports.base = base;\n\t  exports.Dot = exports.dot = dot;\n\t  exports.Doc = exports.doc = doc;\n\t  exports.TAP = exports.tap = tap;\n\t  exports.JSON = exports.json = json;\n\t  exports.HTML = exports.html = html;\n\t  exports.List = exports.list = list;\n\t  exports.Min = exports.min = min;\n\t  exports.Spec = exports.spec = spec;\n\t  exports.Nyan = exports.nyan = nyan;\n\t  exports.XUnit = exports.xunit = xunit;\n\t  exports.Markdown = exports.markdown = markdown;\n\t  exports.Progress = exports.progress = progress;\n\t  exports.Landing = exports.landing = landing;\n\t  exports.JSONStream = exports['json-stream'] = jsonStream;\n\t});\n\n\tvar name = \"mocha\";\n\tvar version = \"9.2.2\";\n\tvar homepage = \"https://mochajs.org/\";\n\tvar notifyLogo = \"https://ibin.co/4QuRuGjXvl36.png\";\n\tvar _package = {\n\t\tname: name,\n\t\tversion: version,\n\t\thomepage: homepage,\n\t\tnotifyLogo: notifyLogo\n\t};\n\n\tvar _package$1 = /*#__PURE__*/Object.freeze({\n\t\t__proto__: null,\n\t\tname: name,\n\t\tversion: version,\n\t\thomepage: homepage,\n\t\tnotifyLogo: notifyLogo,\n\t\t'default': _package\n\t});\n\n\tvar require$$9 = getCjsExportFromNamespace(_package$1);\n\n\t/**\n\t * Web Notifications module.\n\t * @module Growl\n\t */\n\n\t/**\n\t * Save timer references to avoid Sinon interfering (see GH-237).\n\t */\n\n\n\tvar Date$3 = commonjsGlobal.Date;\n\tvar setTimeout$2 = commonjsGlobal.setTimeout;\n\tvar EVENT_RUN_END$1 = runner.constants.EVENT_RUN_END;\n\tvar isBrowser = utils.isBrowser;\n\t/**\n\t * Checks if browser notification support exists.\n\t *\n\t * @public\n\t * @see {@link https://caniuse.com/#feat=notifications|Browser support (notifications)}\n\t * @see {@link https://caniuse.com/#feat=promises|Browser support (promises)}\n\t * @see {@link Mocha#growl}\n\t * @see {@link Mocha#isGrowlCapable}\n\t * @return {boolean} whether browser notification support exists\n\t */\n\n\tvar isCapable = function isCapable() {\n\t  var hasNotificationSupport = ('Notification' in window);\n\t  var hasPromiseSupport = typeof Promise === 'function';\n\t  return isBrowser() && hasNotificationSupport && hasPromiseSupport;\n\t};\n\t/**\n\t * Implements browser notifications as a pseudo-reporter.\n\t *\n\t * @public\n\t * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/notification|Notification API}\n\t * @see {@link https://developers.google.com/web/fundamentals/push-notifications/display-a-notification|Displaying a Notification}\n\t * @see {@link Growl#isPermitted}\n\t * @see {@link Mocha#_growl}\n\t * @param {Runner} runner - Runner instance.\n\t */\n\n\n\tvar notify = function notify(runner) {\n\t  var promise = isPermitted();\n\t  /**\n\t   * Attempt notification.\n\t   */\n\n\t  var sendNotification = function sendNotification() {\n\t    // If user hasn't responded yet... \"No notification for you!\" (Seinfeld)\n\t    Promise.race([promise, Promise.resolve(undefined)]).then(canNotify).then(function () {\n\t      display(runner);\n\t    })[\"catch\"](notPermitted);\n\t  };\n\n\t  runner.once(EVENT_RUN_END$1, sendNotification);\n\t};\n\t/**\n\t * Checks if browser notification is permitted by user.\n\t *\n\t * @private\n\t * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission|Notification.permission}\n\t * @see {@link Mocha#growl}\n\t * @see {@link Mocha#isGrowlPermitted}\n\t * @returns {Promise<boolean>} promise determining if browser notification\n\t *     permissible when fulfilled.\n\t */\n\n\n\tfunction isPermitted() {\n\t  var permitted = {\n\t    granted: function allow() {\n\t      return Promise.resolve(true);\n\t    },\n\t    denied: function deny() {\n\t      return Promise.resolve(false);\n\t    },\n\t    \"default\": function ask() {\n\t      return Notification.requestPermission().then(function (permission) {\n\t        return permission === 'granted';\n\t      });\n\t    }\n\t  };\n\t  return permitted[Notification.permission]();\n\t}\n\t/**\n\t * @summary\n\t * Determines if notification should proceed.\n\t *\n\t * @description\n\t * Notification shall <strong>not</strong> proceed unless `value` is true.\n\t *\n\t * `value` will equal one of:\n\t * <ul>\n\t *   <li><code>true</code> (from `isPermitted`)</li>\n\t *   <li><code>false</code> (from `isPermitted`)</li>\n\t *   <li><code>undefined</code> (from `Promise.race`)</li>\n\t * </ul>\n\t *\n\t * @private\n\t * @param {boolean|undefined} value - Determines if notification permissible.\n\t * @returns {Promise<undefined>} Notification can proceed\n\t */\n\n\n\tfunction canNotify(value) {\n\t  if (!value) {\n\t    var why = value === false ? 'blocked' : 'unacknowledged';\n\t    var reason = 'not permitted by user (' + why + ')';\n\t    return Promise.reject(new Error(reason));\n\t  }\n\n\t  return Promise.resolve();\n\t}\n\t/**\n\t * Displays the notification.\n\t *\n\t * @private\n\t * @param {Runner} runner - Runner instance.\n\t */\n\n\n\tfunction display(runner) {\n\t  var stats = runner.stats;\n\t  var symbol = {\n\t    cross: \"\\u274C\",\n\t    tick: \"\\u2705\"\n\t  };\n\t  var logo = require$$9.notifyLogo;\n\n\t  var _message;\n\n\t  var message;\n\t  var title;\n\n\t  if (stats.failures) {\n\t    _message = stats.failures + ' of ' + stats.tests + ' tests failed';\n\t    message = symbol.cross + ' ' + _message;\n\t    title = 'Failed';\n\t  } else {\n\t    _message = stats.passes + ' tests passed in ' + stats.duration + 'ms';\n\t    message = symbol.tick + ' ' + _message;\n\t    title = 'Passed';\n\t  } // Send notification\n\n\n\t  var options = {\n\t    badge: logo,\n\t    body: message,\n\t    dir: 'ltr',\n\t    icon: logo,\n\t    lang: 'en-US',\n\t    name: 'mocha',\n\t    requireInteraction: false,\n\t    timestamp: Date$3.now()\n\t  };\n\t  var notification = new Notification(title, options); // Autoclose after brief delay (makes various browsers act same)\n\n\t  var FORCE_DURATION = 4000;\n\t  setTimeout$2(notification.close.bind(notification), FORCE_DURATION);\n\t}\n\t/**\n\t * As notifications are tangential to our purpose, just log the error.\n\t *\n\t * @private\n\t * @param {Error} err - Why notification didn't happen.\n\t */\n\n\n\tfunction notPermitted(err) {\n\t  console.error('notification error:', err.message);\n\t}\n\n\tvar growl = {\n\t  isCapable: isCapable,\n\t  notify: notify\n\t};\n\n\tvar diff = true;\n\tvar extension = [\n\t\t\"js\",\n\t\t\"cjs\",\n\t\t\"mjs\"\n\t];\n\tvar reporter = \"spec\";\n\tvar slow = 75;\n\tvar timeout = 2000;\n\tvar ui = \"bdd\";\n\tvar mocharc$1 = {\n\t\tdiff: diff,\n\t\textension: extension,\n\t\t\"package\": \"./package.json\",\n\t\treporter: reporter,\n\t\tslow: slow,\n\t\ttimeout: timeout,\n\t\tui: ui,\n\t\t\"watch-ignore\": [\n\t\t\"node_modules\",\n\t\t\".git\"\n\t]\n\t};\n\n\tvar mocharc$2 = /*#__PURE__*/Object.freeze({\n\t\t__proto__: null,\n\t\tdiff: diff,\n\t\textension: extension,\n\t\treporter: reporter,\n\t\tslow: slow,\n\t\ttimeout: timeout,\n\t\tui: ui,\n\t\t'default': mocharc$1\n\t});\n\n\t/**\n\t * Provides a factory function for a {@link StatsCollector} object.\n\t * @module\n\t */\n\n\n\tvar constants = runner.constants;\n\tvar EVENT_TEST_PASS = constants.EVENT_TEST_PASS;\n\tvar EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;\n\tvar EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;\n\tvar EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN;\n\tvar EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;\n\tvar EVENT_RUN_END = constants.EVENT_RUN_END;\n\tvar EVENT_TEST_END = constants.EVENT_TEST_END;\n\t/**\n\t * Test statistics collector.\n\t *\n\t * @public\n\t * @typedef {Object} StatsCollector\n\t * @property {number} suites - integer count of suites run.\n\t * @property {number} tests - integer count of tests run.\n\t * @property {number} passes - integer count of passing tests.\n\t * @property {number} pending - integer count of pending tests.\n\t * @property {number} failures - integer count of failed tests.\n\t * @property {Date} start - time when testing began.\n\t * @property {Date} end - time when testing concluded.\n\t * @property {number} duration - number of msecs that testing took.\n\t */\n\n\tvar Date$2 = commonjsGlobal.Date;\n\t/**\n\t * Provides stats such as test duration, number of tests passed / failed etc., by listening for events emitted by `runner`.\n\t *\n\t * @private\n\t * @param {Runner} runner - Runner instance\n\t * @throws {TypeError} If falsy `runner`\n\t */\n\n\tfunction createStatsCollector(runner) {\n\t  /**\n\t   * @type StatsCollector\n\t   */\n\t  var stats = {\n\t    suites: 0,\n\t    tests: 0,\n\t    passes: 0,\n\t    pending: 0,\n\t    failures: 0\n\t  };\n\n\t  if (!runner) {\n\t    throw new TypeError('Missing runner argument');\n\t  }\n\n\t  runner.stats = stats;\n\t  runner.once(EVENT_RUN_BEGIN, function () {\n\t    stats.start = new Date$2();\n\t  });\n\t  runner.on(EVENT_SUITE_BEGIN, function (suite) {\n\t    suite.root || stats.suites++;\n\t  });\n\t  runner.on(EVENT_TEST_PASS, function () {\n\t    stats.passes++;\n\t  });\n\t  runner.on(EVENT_TEST_FAIL, function () {\n\t    stats.failures++;\n\t  });\n\t  runner.on(EVENT_TEST_PENDING, function () {\n\t    stats.pending++;\n\t  });\n\t  runner.on(EVENT_TEST_END, function () {\n\t    stats.tests++;\n\t  });\n\t  runner.once(EVENT_RUN_END, function () {\n\t    stats.end = new Date$2();\n\t    stats.duration = stats.end - stats.start;\n\t  });\n\t}\n\n\tvar statsCollector = createStatsCollector;\n\n\tvar createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError;\n\tvar isString = utils.isString;\n\tvar MOCHA_ID_PROP_NAME = utils.constants.MOCHA_ID_PROP_NAME;\n\tvar test = Test;\n\t/**\n\t * Initialize a new `Test` with the given `title` and callback `fn`.\n\t *\n\t * @public\n\t * @class\n\t * @extends Runnable\n\t * @param {String} title - Test title (required)\n\t * @param {Function} [fn] - Test callback.  If omitted, the Test is considered \"pending\"\n\t */\n\n\tfunction Test(title, fn) {\n\t  if (!isString(title)) {\n\t    throw createInvalidArgumentTypeError('Test argument \"title\" should be a string. Received type \"' + _typeof(title) + '\"', 'title', 'string');\n\t  }\n\n\t  this.type = 'test';\n\t  runnable.call(this, title, fn);\n\t  this.reset();\n\t}\n\t/**\n\t * Inherit from `Runnable.prototype`.\n\t */\n\n\n\tutils.inherits(Test, runnable);\n\t/**\n\t * Resets the state initially or for a next run.\n\t */\n\n\tTest.prototype.reset = function () {\n\t  runnable.prototype.reset.call(this);\n\t  this.pending = !this.fn;\n\t  delete this.state;\n\t};\n\t/**\n\t * Set or get retried test\n\t *\n\t * @private\n\t */\n\n\n\tTest.prototype.retriedTest = function (n) {\n\t  if (!arguments.length) {\n\t    return this._retriedTest;\n\t  }\n\n\t  this._retriedTest = n;\n\t};\n\t/**\n\t * Add test to the list of tests marked `only`.\n\t *\n\t * @private\n\t */\n\n\n\tTest.prototype.markOnly = function () {\n\t  this.parent.appendOnlyTest(this);\n\t};\n\n\tTest.prototype.clone = function () {\n\t  var test = new Test(this.title, this.fn);\n\t  test.timeout(this.timeout());\n\t  test.slow(this.slow());\n\t  test.retries(this.retries());\n\t  test.currentRetry(this.currentRetry());\n\t  test.retriedTest(this.retriedTest() || this);\n\t  test.globals(this.globals());\n\t  test.parent = this.parent;\n\t  test.file = this.file;\n\t  test.ctx = this.ctx;\n\t  return test;\n\t};\n\t/**\n\t * Returns an minimal object suitable for transmission over IPC.\n\t * Functions are represented by keys beginning with `$$`.\n\t * @private\n\t * @returns {Object}\n\t */\n\n\n\tTest.prototype.serialize = function serialize() {\n\t  return _defineProperty({\n\t    $$currentRetry: this._currentRetry,\n\t    $$fullTitle: this.fullTitle(),\n\t    $$isPending: Boolean(this.pending),\n\t    $$retriedTest: this._retriedTest || null,\n\t    $$slow: this._slow,\n\t    $$titlePath: this.titlePath(),\n\t    body: this.body,\n\t    duration: this.duration,\n\t    err: this.err,\n\t    parent: _defineProperty({\n\t      $$fullTitle: this.parent.fullTitle()\n\t    }, MOCHA_ID_PROP_NAME, this.parent.id),\n\t    speed: this.speed,\n\t    state: this.state,\n\t    title: this.title,\n\t    type: this.type,\n\t    file: this.file\n\t  }, MOCHA_ID_PROP_NAME, this.id);\n\t};\n\n\t/**\n\t @module interfaces/common\n\t*/\n\n\n\tvar createMissingArgumentError = errors.createMissingArgumentError;\n\tvar createUnsupportedError = errors.createUnsupportedError;\n\tvar createForbiddenExclusivityError = errors.createForbiddenExclusivityError;\n\t/**\n\t * Functions common to more than one interface.\n\t *\n\t * @private\n\t * @param {Suite[]} suites\n\t * @param {Context} context\n\t * @param {Mocha} mocha\n\t * @return {Object} An object containing common functions.\n\t */\n\n\tvar common = function common(suites, context, mocha) {\n\t  /**\n\t   * Check if the suite should be tested.\n\t   *\n\t   * @private\n\t   * @param {Suite} suite - suite to check\n\t   * @returns {boolean}\n\t   */\n\t  function shouldBeTested(suite) {\n\t    return !mocha.options.grep || mocha.options.grep && mocha.options.grep.test(suite.fullTitle()) && !mocha.options.invert;\n\t  }\n\n\t  return {\n\t    /**\n\t     * This is only present if flag --delay is passed into Mocha. It triggers\n\t     * root suite execution.\n\t     *\n\t     * @param {Suite} suite The root suite.\n\t     * @return {Function} A function which runs the root suite\n\t     */\n\t    runWithSuite: function runWithSuite(suite) {\n\t      return function run() {\n\t        suite.run();\n\t      };\n\t    },\n\n\t    /**\n\t     * Execute before running tests.\n\t     *\n\t     * @param {string} name\n\t     * @param {Function} fn\n\t     */\n\t    before: function before(name, fn) {\n\t      suites[0].beforeAll(name, fn);\n\t    },\n\n\t    /**\n\t     * Execute after running tests.\n\t     *\n\t     * @param {string} name\n\t     * @param {Function} fn\n\t     */\n\t    after: function after(name, fn) {\n\t      suites[0].afterAll(name, fn);\n\t    },\n\n\t    /**\n\t     * Execute before each test case.\n\t     *\n\t     * @param {string} name\n\t     * @param {Function} fn\n\t     */\n\t    beforeEach: function beforeEach(name, fn) {\n\t      suites[0].beforeEach(name, fn);\n\t    },\n\n\t    /**\n\t     * Execute after each test case.\n\t     *\n\t     * @param {string} name\n\t     * @param {Function} fn\n\t     */\n\t    afterEach: function afterEach(name, fn) {\n\t      suites[0].afterEach(name, fn);\n\t    },\n\t    suite: {\n\t      /**\n\t       * Create an exclusive Suite; convenience function\n\t       * See docstring for create() below.\n\t       *\n\t       * @param {Object} opts\n\t       * @returns {Suite}\n\t       */\n\t      only: function only(opts) {\n\t        if (mocha.options.forbidOnly) {\n\t          throw createForbiddenExclusivityError(mocha);\n\t        }\n\n\t        opts.isOnly = true;\n\t        return this.create(opts);\n\t      },\n\n\t      /**\n\t       * Create a Suite, but skip it; convenience function\n\t       * See docstring for create() below.\n\t       *\n\t       * @param {Object} opts\n\t       * @returns {Suite}\n\t       */\n\t      skip: function skip(opts) {\n\t        opts.pending = true;\n\t        return this.create(opts);\n\t      },\n\n\t      /**\n\t       * Creates a suite.\n\t       *\n\t       * @param {Object} opts Options\n\t       * @param {string} opts.title Title of Suite\n\t       * @param {Function} [opts.fn] Suite Function (not always applicable)\n\t       * @param {boolean} [opts.pending] Is Suite pending?\n\t       * @param {string} [opts.file] Filepath where this Suite resides\n\t       * @param {boolean} [opts.isOnly] Is Suite exclusive?\n\t       * @returns {Suite}\n\t       */\n\t      create: function create(opts) {\n\t        var suite$1 = suite.create(suites[0], opts.title);\n\t        suite$1.pending = Boolean(opts.pending);\n\t        suite$1.file = opts.file;\n\t        suites.unshift(suite$1);\n\n\t        if (opts.isOnly) {\n\t          suite$1.markOnly();\n\t        }\n\n\t        if (suite$1.pending && mocha.options.forbidPending && shouldBeTested(suite$1)) {\n\t          throw createUnsupportedError('Pending test forbidden');\n\t        }\n\n\t        if (typeof opts.fn === 'function') {\n\t          opts.fn.call(suite$1);\n\t          suites.shift();\n\t        } else if (typeof opts.fn === 'undefined' && !suite$1.pending) {\n\t          throw createMissingArgumentError('Suite \"' + suite$1.fullTitle() + '\" was defined but no callback was supplied. ' + 'Supply a callback or explicitly skip the suite.', 'callback', 'function');\n\t        } else if (!opts.fn && suite$1.pending) {\n\t          suites.shift();\n\t        }\n\n\t        return suite$1;\n\t      }\n\t    },\n\t    test: {\n\t      /**\n\t       * Exclusive test-case.\n\t       *\n\t       * @param {Object} mocha\n\t       * @param {Function} test\n\t       * @returns {*}\n\t       */\n\t      only: function only(mocha, test) {\n\t        if (mocha.options.forbidOnly) {\n\t          throw createForbiddenExclusivityError(mocha);\n\t        }\n\n\t        test.markOnly();\n\t        return test;\n\t      },\n\n\t      /**\n\t       * Pending test case.\n\t       *\n\t       * @param {string} title\n\t       */\n\t      skip: function skip(title) {\n\t        context.test(title);\n\t      }\n\t    }\n\t  };\n\t};\n\n\tvar EVENT_FILE_PRE_REQUIRE$2 = suite.constants.EVENT_FILE_PRE_REQUIRE;\n\t/**\n\t * BDD-style interface:\n\t *\n\t *      describe('Array', function() {\n\t *        describe('#indexOf()', function() {\n\t *          it('should return -1 when not present', function() {\n\t *            // ...\n\t *          });\n\t *\n\t *          it('should return the index when present', function() {\n\t *            // ...\n\t *          });\n\t *        });\n\t *      });\n\t *\n\t * @param {Suite} suite Root suite.\n\t */\n\n\tvar bdd$1 = function bddInterface(suite) {\n\t  var suites = [suite];\n\t  suite.on(EVENT_FILE_PRE_REQUIRE$2, function (context, file, mocha) {\n\t    var common$1 = common(suites, context, mocha);\n\t    context.before = common$1.before;\n\t    context.after = common$1.after;\n\t    context.beforeEach = common$1.beforeEach;\n\t    context.afterEach = common$1.afterEach;\n\t    context.run = mocha.options.delay && common$1.runWithSuite(suite);\n\t    /**\n\t     * Describe a \"suite\" with the given `title`\n\t     * and callback `fn` containing nested suites\n\t     * and/or tests.\n\t     */\n\n\t    context.describe = context.context = function (title, fn) {\n\t      return common$1.suite.create({\n\t        title: title,\n\t        file: file,\n\t        fn: fn\n\t      });\n\t    };\n\t    /**\n\t     * Pending describe.\n\t     */\n\n\n\t    context.xdescribe = context.xcontext = context.describe.skip = function (title, fn) {\n\t      return common$1.suite.skip({\n\t        title: title,\n\t        file: file,\n\t        fn: fn\n\t      });\n\t    };\n\t    /**\n\t     * Exclusive suite.\n\t     */\n\n\n\t    context.describe.only = function (title, fn) {\n\t      return common$1.suite.only({\n\t        title: title,\n\t        file: file,\n\t        fn: fn\n\t      });\n\t    };\n\t    /**\n\t     * Describe a specification or test-case\n\t     * with the given `title` and callback `fn`\n\t     * acting as a thunk.\n\t     */\n\n\n\t    context.it = context.specify = function (title, fn) {\n\t      var suite = suites[0];\n\n\t      if (suite.isPending()) {\n\t        fn = null;\n\t      }\n\n\t      var test$1 = new test(title, fn);\n\t      test$1.file = file;\n\t      suite.addTest(test$1);\n\t      return test$1;\n\t    };\n\t    /**\n\t     * Exclusive test-case.\n\t     */\n\n\n\t    context.it.only = function (title, fn) {\n\t      return common$1.test.only(mocha, context.it(title, fn));\n\t    };\n\t    /**\n\t     * Pending test case.\n\t     */\n\n\n\t    context.xit = context.xspecify = context.it.skip = function (title) {\n\t      return context.it(title);\n\t    };\n\t  });\n\t};\n\n\tvar description$3 = 'BDD or RSpec style [default]';\n\tbdd$1.description = description$3;\n\n\tvar EVENT_FILE_PRE_REQUIRE$1 = suite.constants.EVENT_FILE_PRE_REQUIRE;\n\t/**\n\t * TDD-style interface:\n\t *\n\t *      suite('Array', function() {\n\t *        suite('#indexOf()', function() {\n\t *          suiteSetup(function() {\n\t *\n\t *          });\n\t *\n\t *          test('should return -1 when not present', function() {\n\t *\n\t *          });\n\t *\n\t *          test('should return the index when present', function() {\n\t *\n\t *          });\n\t *\n\t *          suiteTeardown(function() {\n\t *\n\t *          });\n\t *        });\n\t *      });\n\t *\n\t * @param {Suite} suite Root suite.\n\t */\n\n\tvar tdd$1 = function tdd(suite) {\n\t  var suites = [suite];\n\t  suite.on(EVENT_FILE_PRE_REQUIRE$1, function (context, file, mocha) {\n\t    var common$1 = common(suites, context, mocha);\n\t    context.setup = common$1.beforeEach;\n\t    context.teardown = common$1.afterEach;\n\t    context.suiteSetup = common$1.before;\n\t    context.suiteTeardown = common$1.after;\n\t    context.run = mocha.options.delay && common$1.runWithSuite(suite);\n\t    /**\n\t     * Describe a \"suite\" with the given `title` and callback `fn` containing\n\t     * nested suites and/or tests.\n\t     */\n\n\t    context.suite = function (title, fn) {\n\t      return common$1.suite.create({\n\t        title: title,\n\t        file: file,\n\t        fn: fn\n\t      });\n\t    };\n\t    /**\n\t     * Pending suite.\n\t     */\n\n\n\t    context.suite.skip = function (title, fn) {\n\t      return common$1.suite.skip({\n\t        title: title,\n\t        file: file,\n\t        fn: fn\n\t      });\n\t    };\n\t    /**\n\t     * Exclusive test-case.\n\t     */\n\n\n\t    context.suite.only = function (title, fn) {\n\t      return common$1.suite.only({\n\t        title: title,\n\t        file: file,\n\t        fn: fn\n\t      });\n\t    };\n\t    /**\n\t     * Describe a specification or test-case with the given `title` and\n\t     * callback `fn` acting as a thunk.\n\t     */\n\n\n\t    context.test = function (title, fn) {\n\t      var suite = suites[0];\n\n\t      if (suite.isPending()) {\n\t        fn = null;\n\t      }\n\n\t      var test$1 = new test(title, fn);\n\t      test$1.file = file;\n\t      suite.addTest(test$1);\n\t      return test$1;\n\t    };\n\t    /**\n\t     * Exclusive test-case.\n\t     */\n\n\n\t    context.test.only = function (title, fn) {\n\t      return common$1.test.only(mocha, context.test(title, fn));\n\t    };\n\n\t    context.test.skip = common$1.test.skip;\n\t  });\n\t};\n\n\tvar description$2 = 'traditional \"suite\"/\"test\" instead of BDD\\'s \"describe\"/\"it\"';\n\ttdd$1.description = description$2;\n\n\tvar EVENT_FILE_PRE_REQUIRE = suite.constants.EVENT_FILE_PRE_REQUIRE;\n\t/**\n\t * QUnit-style interface:\n\t *\n\t *     suite('Array');\n\t *\n\t *     test('#length', function() {\n\t *       var arr = [1,2,3];\n\t *       ok(arr.length == 3);\n\t *     });\n\t *\n\t *     test('#indexOf()', function() {\n\t *       var arr = [1,2,3];\n\t *       ok(arr.indexOf(1) == 0);\n\t *       ok(arr.indexOf(2) == 1);\n\t *       ok(arr.indexOf(3) == 2);\n\t *     });\n\t *\n\t *     suite('String');\n\t *\n\t *     test('#length', function() {\n\t *       ok('foo'.length == 3);\n\t *     });\n\t *\n\t * @param {Suite} suite Root suite.\n\t */\n\n\tvar qunit$1 = function qUnitInterface(suite) {\n\t  var suites = [suite];\n\t  suite.on(EVENT_FILE_PRE_REQUIRE, function (context, file, mocha) {\n\t    var common$1 = common(suites, context, mocha);\n\t    context.before = common$1.before;\n\t    context.after = common$1.after;\n\t    context.beforeEach = common$1.beforeEach;\n\t    context.afterEach = common$1.afterEach;\n\t    context.run = mocha.options.delay && common$1.runWithSuite(suite);\n\t    /**\n\t     * Describe a \"suite\" with the given `title`.\n\t     */\n\n\t    context.suite = function (title) {\n\t      if (suites.length > 1) {\n\t        suites.shift();\n\t      }\n\n\t      return common$1.suite.create({\n\t        title: title,\n\t        file: file,\n\t        fn: false\n\t      });\n\t    };\n\t    /**\n\t     * Exclusive Suite.\n\t     */\n\n\n\t    context.suite.only = function (title) {\n\t      if (suites.length > 1) {\n\t        suites.shift();\n\t      }\n\n\t      return common$1.suite.only({\n\t        title: title,\n\t        file: file,\n\t        fn: false\n\t      });\n\t    };\n\t    /**\n\t     * Describe a specification or test-case\n\t     * with the given `title` and callback `fn`\n\t     * acting as a thunk.\n\t     */\n\n\n\t    context.test = function (title, fn) {\n\t      var test$1 = new test(title, fn);\n\t      test$1.file = file;\n\t      suites[0].addTest(test$1);\n\t      return test$1;\n\t    };\n\t    /**\n\t     * Exclusive test-case.\n\t     */\n\n\n\t    context.test.only = function (title, fn) {\n\t      return common$1.test.only(mocha, context.test(title, fn));\n\t    };\n\n\t    context.test.skip = common$1.test.skip;\n\t  });\n\t};\n\n\tvar description$1 = 'QUnit style';\n\tqunit$1.description = description$1;\n\n\t/**\n\t * Exports-style (as Node.js module) interface:\n\t *\n\t *     exports.Array = {\n\t *       '#indexOf()': {\n\t *         'should return -1 when the value is not present': function() {\n\t *\n\t *         },\n\t *\n\t *         'should return the correct index when the value is present': function() {\n\t *\n\t *         }\n\t *       }\n\t *     };\n\t *\n\t * @param {Suite} suite Root suite.\n\t */\n\n\n\tvar exports$2 = function exports(suite$1) {\n\t  var suites = [suite$1];\n\t  suite$1.on(suite.constants.EVENT_FILE_REQUIRE, visit);\n\n\t  function visit(obj, file) {\n\t    var suite$1;\n\n\t    for (var key in obj) {\n\t      if (typeof obj[key] === 'function') {\n\t        var fn = obj[key];\n\n\t        switch (key) {\n\t          case 'before':\n\t            suites[0].beforeAll(fn);\n\t            break;\n\n\t          case 'after':\n\t            suites[0].afterAll(fn);\n\t            break;\n\n\t          case 'beforeEach':\n\t            suites[0].beforeEach(fn);\n\t            break;\n\n\t          case 'afterEach':\n\t            suites[0].afterEach(fn);\n\t            break;\n\n\t          default:\n\t            var test$1 = new test(key, fn);\n\t            test$1.file = file;\n\t            suites[0].addTest(test$1);\n\t        }\n\t      } else {\n\t        suite$1 = suite.create(suites[0], key);\n\t        suites.unshift(suite$1);\n\t        visit(obj[key], file);\n\t        suites.shift();\n\t      }\n\t    }\n\t  }\n\t};\n\n\tvar description = 'Node.js module (\"exports\") style';\n\texports$2.description = description;\n\n\tvar bdd = bdd$1;\n\tvar tdd = tdd$1;\n\tvar qunit = qunit$1;\n\tvar exports$1 = exports$2;\n\tvar interfaces = {\n\t  bdd: bdd,\n\t  tdd: tdd,\n\t  qunit: qunit,\n\t  exports: exports$1\n\t};\n\n\tvar context = Context;\n\t/**\n\t * Initialize a new `Context`.\n\t *\n\t * @private\n\t */\n\n\tfunction Context() {}\n\t/**\n\t * Set or get the context `Runnable` to `runnable`.\n\t *\n\t * @private\n\t * @param {Runnable} runnable\n\t * @return {Context} context\n\t */\n\n\n\tContext.prototype.runnable = function (runnable) {\n\t  if (!arguments.length) {\n\t    return this._runnable;\n\t  }\n\n\t  this.test = this._runnable = runnable;\n\t  return this;\n\t};\n\t/**\n\t * Set or get test timeout `ms`.\n\t *\n\t * @private\n\t * @param {number} ms\n\t * @return {Context} self\n\t */\n\n\n\tContext.prototype.timeout = function (ms) {\n\t  if (!arguments.length) {\n\t    return this.runnable().timeout();\n\t  }\n\n\t  this.runnable().timeout(ms);\n\t  return this;\n\t};\n\t/**\n\t * Set or get test slowness threshold `ms`.\n\t *\n\t * @private\n\t * @param {number} ms\n\t * @return {Context} self\n\t */\n\n\n\tContext.prototype.slow = function (ms) {\n\t  if (!arguments.length) {\n\t    return this.runnable().slow();\n\t  }\n\n\t  this.runnable().slow(ms);\n\t  return this;\n\t};\n\t/**\n\t * Mark a test as skipped.\n\t *\n\t * @private\n\t * @throws Pending\n\t */\n\n\n\tContext.prototype.skip = function () {\n\t  this.runnable().skip();\n\t};\n\t/**\n\t * Set or get a number of allowed retries on failed tests\n\t *\n\t * @private\n\t * @param {number} n\n\t * @return {Context} self\n\t */\n\n\n\tContext.prototype.retries = function (n) {\n\t  if (!arguments.length) {\n\t    return this.runnable().retries();\n\t  }\n\n\t  this.runnable().retries(n);\n\t  return this;\n\t};\n\n\tvar mocharc = getCjsExportFromNamespace(mocharc$2);\n\n\tvar mocha$1 = createCommonjsModule(function (module, exports) {\n\t  /*!\n\t   * mocha\n\t   * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\t   * MIT Licensed\n\t   */\n\n\t  var createInvalidReporterError = errors.createInvalidReporterError,\n\t      createInvalidInterfaceError = errors.createInvalidInterfaceError,\n\t      createMochaInstanceAlreadyDisposedError = errors.createMochaInstanceAlreadyDisposedError,\n\t      createMochaInstanceAlreadyRunningError = errors.createMochaInstanceAlreadyRunningError,\n\t      createUnsupportedError = errors.createUnsupportedError;\n\t  var _Suite$constants = suite.constants,\n\t      EVENT_FILE_PRE_REQUIRE = _Suite$constants.EVENT_FILE_PRE_REQUIRE,\n\t      EVENT_FILE_POST_REQUIRE = _Suite$constants.EVENT_FILE_POST_REQUIRE,\n\t      EVENT_FILE_REQUIRE = _Suite$constants.EVENT_FILE_REQUIRE;\n\t  var debug = browser('mocha:mocha');\n\t  exports = module.exports = Mocha;\n\t  /**\n\t   * A Mocha instance is a finite state machine.\n\t   * These are the states it can be in.\n\t   * @private\n\t   */\n\n\t  var mochaStates = utils.defineConstants({\n\t    /**\n\t     * Initial state of the mocha instance\n\t     * @private\n\t     */\n\t    INIT: 'init',\n\n\t    /**\n\t     * Mocha instance is running tests\n\t     * @private\n\t     */\n\t    RUNNING: 'running',\n\n\t    /**\n\t     * Mocha instance is done running tests and references to test functions and hooks are cleaned.\n\t     * You can reset this state by unloading the test files.\n\t     * @private\n\t     */\n\t    REFERENCES_CLEANED: 'referencesCleaned',\n\n\t    /**\n\t     * Mocha instance is disposed and can no longer be used.\n\t     * @private\n\t     */\n\t    DISPOSED: 'disposed'\n\t  });\n\t  /**\n\t   * To require local UIs and reporters when running in node.\n\t   */\n\n\t  if (!utils.isBrowser() && typeof module.paths !== 'undefined') {\n\t    var cwd = utils.cwd();\n\t    module.paths.push(cwd, path.join(cwd, 'node_modules'));\n\t  }\n\t  /**\n\t   * Expose internals.\n\t   * @private\n\t   */\n\n\n\t  exports.utils = utils;\n\t  exports.interfaces = interfaces;\n\t  /**\n\t   * @public\n\t   * @memberof Mocha\n\t   */\n\n\t  exports.reporters = reporters;\n\t  exports.Runnable = runnable;\n\t  exports.Context = context;\n\t  /**\n\t   *\n\t   * @memberof Mocha\n\t   */\n\n\t  exports.Runner = runner;\n\t  exports.Suite = suite;\n\t  exports.Hook = hook;\n\t  exports.Test = test;\n\t  var currentContext;\n\n\t  exports.afterEach = function () {\n\t    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n\t      args[_key] = arguments[_key];\n\t    }\n\n\t    return (currentContext.afterEach || currentContext.teardown).apply(this, args);\n\t  };\n\n\t  exports.after = function () {\n\t    for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n\t      args[_key2] = arguments[_key2];\n\t    }\n\n\t    return (currentContext.after || currentContext.suiteTeardown).apply(this, args);\n\t  };\n\n\t  exports.beforeEach = function () {\n\t    for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n\t      args[_key3] = arguments[_key3];\n\t    }\n\n\t    return (currentContext.beforeEach || currentContext.setup).apply(this, args);\n\t  };\n\n\t  exports.before = function () {\n\t    for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {\n\t      args[_key4] = arguments[_key4];\n\t    }\n\n\t    return (currentContext.before || currentContext.suiteSetup).apply(this, args);\n\t  };\n\n\t  exports.describe = function () {\n\t    for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {\n\t      args[_key5] = arguments[_key5];\n\t    }\n\n\t    return (currentContext.describe || currentContext.suite).apply(this, args);\n\t  };\n\n\t  exports.describe.only = function () {\n\t    for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {\n\t      args[_key6] = arguments[_key6];\n\t    }\n\n\t    return (currentContext.describe || currentContext.suite).only.apply(this, args);\n\t  };\n\n\t  exports.describe.skip = function () {\n\t    for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) {\n\t      args[_key7] = arguments[_key7];\n\t    }\n\n\t    return (currentContext.describe || currentContext.suite).skip.apply(this, args);\n\t  };\n\n\t  exports.it = function () {\n\t    for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) {\n\t      args[_key8] = arguments[_key8];\n\t    }\n\n\t    return (currentContext.it || currentContext.test).apply(this, args);\n\t  };\n\n\t  exports.it.only = function () {\n\t    for (var _len9 = arguments.length, args = new Array(_len9), _key9 = 0; _key9 < _len9; _key9++) {\n\t      args[_key9] = arguments[_key9];\n\t    }\n\n\t    return (currentContext.it || currentContext.test).only.apply(this, args);\n\t  };\n\n\t  exports.it.skip = function () {\n\t    for (var _len10 = arguments.length, args = new Array(_len10), _key10 = 0; _key10 < _len10; _key10++) {\n\t      args[_key10] = arguments[_key10];\n\t    }\n\n\t    return (currentContext.it || currentContext.test).skip.apply(this, args);\n\t  };\n\n\t  exports.xdescribe = exports.describe.skip;\n\t  exports.xit = exports.it.skip;\n\t  exports.setup = exports.beforeEach;\n\t  exports.suiteSetup = exports.before;\n\t  exports.suiteTeardown = exports.after;\n\t  exports.suite = exports.describe;\n\t  exports.teardown = exports.afterEach;\n\t  exports.test = exports.it;\n\n\t  exports.run = function () {\n\t    for (var _len11 = arguments.length, args = new Array(_len11), _key11 = 0; _key11 < _len11; _key11++) {\n\t      args[_key11] = arguments[_key11];\n\t    }\n\n\t    return currentContext.run.apply(this, args);\n\t  };\n\t  /**\n\t   * Constructs a new Mocha instance with `options`.\n\t   *\n\t   * @public\n\t   * @class Mocha\n\t   * @param {Object} [options] - Settings object.\n\t   * @param {boolean} [options.allowUncaught] - Propagate uncaught errors?\n\t   * @param {boolean} [options.asyncOnly] - Force `done` callback or promise?\n\t   * @param {boolean} [options.bail] - Bail after first test failure?\n\t   * @param {boolean} [options.checkLeaks] - Check for global variable leaks?\n\t   * @param {boolean} [options.color] - Color TTY output from reporter?\n\t   * @param {boolean} [options.delay] - Delay root suite execution?\n\t   * @param {boolean} [options.diff] - Show diff on failure?\n\t   * @param {boolean} [options.dryRun] - Report tests without running them?\n\t   * @param {boolean} [options.failZero] - Fail test run if zero tests?\n\t   * @param {string} [options.fgrep] - Test filter given string.\n\t   * @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite?\n\t   * @param {boolean} [options.forbidPending] - Pending tests fail the suite?\n\t   * @param {boolean} [options.fullTrace] - Full stacktrace upon failure?\n\t   * @param {string[]} [options.global] - Variables expected in global scope.\n\t   * @param {RegExp|string} [options.grep] - Test filter given regular expression.\n\t   * @param {boolean} [options.growl] - Enable desktop notifications?\n\t   * @param {boolean} [options.inlineDiffs] - Display inline diffs?\n\t   * @param {boolean} [options.invert] - Invert test filter matches?\n\t   * @param {boolean} [options.noHighlighting] - Disable syntax highlighting?\n\t   * @param {string|constructor} [options.reporter] - Reporter name or constructor.\n\t   * @param {Object} [options.reporterOption] - Reporter settings object.\n\t   * @param {number} [options.retries] - Number of times to retry failed tests.\n\t   * @param {number} [options.slow] - Slow threshold value.\n\t   * @param {number|string} [options.timeout] - Timeout threshold value.\n\t   * @param {string} [options.ui] - Interface name.\n\t   * @param {boolean} [options.parallel] - Run jobs in parallel.\n\t   * @param {number} [options.jobs] - Max number of worker processes for parallel runs.\n\t   * @param {MochaRootHookObject} [options.rootHooks] - Hooks to bootstrap the root suite with.\n\t   * @param {string[]} [options.require] - Pathname of `rootHooks` plugin for parallel runs.\n\t   * @param {boolean} [options.isWorker] - Should be `true` if `Mocha` process is running in a worker process.\n\t   */\n\n\n\t  function Mocha() {\n\t    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\t    options = _objectSpread2(_objectSpread2({}, mocharc), options);\n\t    this.files = [];\n\t    this.options = options; // root suite\n\n\t    this.suite = new exports.Suite('', new exports.Context(), true);\n\t    this._cleanReferencesAfterRun = true;\n\t    this._state = mochaStates.INIT;\n\t    this.grep(options.grep).fgrep(options.fgrep).ui(options.ui).reporter(options.reporter, options.reporterOption || options.reporterOptions // for backwards compability\n\t    ).slow(options.slow).global(options.global); // this guard exists because Suite#timeout does not consider `undefined` to be valid input\n\n\t    if (typeof options.timeout !== 'undefined') {\n\t      this.timeout(options.timeout === false ? 0 : options.timeout);\n\t    }\n\n\t    if ('retries' in options) {\n\t      this.retries(options.retries);\n\t    }\n\n\t    ['allowUncaught', 'asyncOnly', 'bail', 'checkLeaks', 'color', 'delay', 'diff', 'dryRun', 'failZero', 'forbidOnly', 'forbidPending', 'fullTrace', 'growl', 'inlineDiffs', 'invert'].forEach(function (opt) {\n\t      if (options[opt]) {\n\t        this[opt]();\n\t      }\n\t    }, this);\n\n\t    if (options.rootHooks) {\n\t      this.rootHooks(options.rootHooks);\n\t    }\n\t    /**\n\t     * The class which we'll instantiate in {@link Mocha#run}.  Defaults to\n\t     * {@link Runner} in serial mode; changes in parallel mode.\n\t     * @memberof Mocha\n\t     * @private\n\t     */\n\n\n\t    this._runnerClass = exports.Runner;\n\t    /**\n\t     * Whether or not to call {@link Mocha#loadFiles} implicitly when calling\n\t     * {@link Mocha#run}.  If this is `true`, then it's up to the consumer to call\n\t     * {@link Mocha#loadFiles} _or_ {@link Mocha#loadFilesAsync}.\n\t     * @private\n\t     * @memberof Mocha\n\t     */\n\n\t    this._lazyLoadFiles = false;\n\t    /**\n\t     * It's useful for a Mocha instance to know if it's running in a worker process.\n\t     * We could derive this via other means, but it's helpful to have a flag to refer to.\n\t     * @memberof Mocha\n\t     * @private\n\t     */\n\n\t    this.isWorker = Boolean(options.isWorker);\n\t    this.globalSetup(options.globalSetup).globalTeardown(options.globalTeardown).enableGlobalSetup(options.enableGlobalSetup).enableGlobalTeardown(options.enableGlobalTeardown);\n\n\t    if (options.parallel && (typeof options.jobs === 'undefined' || options.jobs > 1)) {\n\t      debug('attempting to enable parallel mode');\n\t      this.parallelMode(true);\n\t    }\n\t  }\n\t  /**\n\t   * Enables or disables bailing on the first failure.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-bail-b)\n\t   * @param {boolean} [bail=true] - Whether to bail on first error.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.bail = function (bail) {\n\t    this.suite.bail(bail !== false);\n\t    return this;\n\t  };\n\t  /**\n\t   * @summary\n\t   * Adds `file` to be loaded for execution.\n\t   *\n\t   * @description\n\t   * Useful for generic setup code that must be included within test suite.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-file-filedirectoryglob)\n\t   * @param {string} file - Pathname of file to be loaded.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.addFile = function (file) {\n\t    this.files.push(file);\n\t    return this;\n\t  };\n\t  /**\n\t   * Sets reporter to `reporter`, defaults to \"spec\".\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-reporter-name-r-name)\n\t   * @see [Reporters](../#reporters)\n\t   * @param {String|Function} reporterName - Reporter name or constructor.\n\t   * @param {Object} [reporterOptions] - Options used to configure the reporter.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   * @throws {Error} if requested reporter cannot be loaded\n\t   * @example\n\t   *\n\t   * // Use XUnit reporter and direct its output to file\n\t   * mocha.reporter('xunit', { output: '/path/to/testspec.xunit.xml' });\n\t   */\n\n\n\t  Mocha.prototype.reporter = function (reporterName, reporterOptions) {\n\t    if (typeof reporterName === 'function') {\n\t      this._reporter = reporterName;\n\t    } else {\n\t      reporterName = reporterName || 'spec';\n\t      var reporter; // Try to load a built-in reporter.\n\n\t      if (reporters[reporterName]) {\n\t        reporter = reporters[reporterName];\n\t      } // Try to load reporters from process.cwd() and node_modules\n\n\n\t      if (!reporter) {\n\t        var foundReporter;\n\n\t        try {\n\t          foundReporter = require.resolve(reporterName);\n\t          reporter = commonjsRequire(foundReporter);\n\t        } catch (err) {\n\t          if (foundReporter) {\n\t            throw createInvalidReporterError(err.message, foundReporter);\n\t          } // Try to load reporters from a cwd-relative path\n\n\n\t          try {\n\t            reporter = commonjsRequire(path.resolve(reporterName));\n\t          } catch (e) {\n\t            throw createInvalidReporterError(e.message, reporterName);\n\t          }\n\t        }\n\t      }\n\n\t      this._reporter = reporter;\n\t    }\n\n\t    this.options.reporterOption = reporterOptions; // alias option name is used in built-in reporters xunit/tap/progress\n\n\t    this.options.reporterOptions = reporterOptions;\n\t    return this;\n\t  };\n\t  /**\n\t   * Sets test UI `name`, defaults to \"bdd\".\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-ui-name-u-name)\n\t   * @see [Interface DSLs](../#interfaces)\n\t   * @param {string|Function} [ui=bdd] - Interface name or class.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   * @throws {Error} if requested interface cannot be loaded\n\t   */\n\n\n\t  Mocha.prototype.ui = function (ui) {\n\t    var bindInterface;\n\n\t    if (typeof ui === 'function') {\n\t      bindInterface = ui;\n\t    } else {\n\t      ui = ui || 'bdd';\n\t      bindInterface = exports.interfaces[ui];\n\n\t      if (!bindInterface) {\n\t        try {\n\t          bindInterface = commonjsRequire(ui);\n\t        } catch (err) {\n\t          throw createInvalidInterfaceError(\"invalid interface '\".concat(ui, \"'\"), ui);\n\t        }\n\t      }\n\t    }\n\n\t    bindInterface(this.suite);\n\t    this.suite.on(EVENT_FILE_PRE_REQUIRE, function (context) {\n\t      currentContext = context;\n\t    });\n\t    return this;\n\t  };\n\t  /**\n\t   * Loads `files` prior to execution. Does not support ES Modules.\n\t   *\n\t   * @description\n\t   * The implementation relies on Node's `require` to execute\n\t   * the test interface functions and will be subject to its cache.\n\t   * Supports only CommonJS modules. To load ES modules, use Mocha#loadFilesAsync.\n\t   *\n\t   * @private\n\t   * @see {@link Mocha#addFile}\n\t   * @see {@link Mocha#run}\n\t   * @see {@link Mocha#unloadFiles}\n\t   * @see {@link Mocha#loadFilesAsync}\n\t   * @param {Function} [fn] - Callback invoked upon completion.\n\t   */\n\n\n\t  Mocha.prototype.loadFiles = function (fn) {\n\t    var self = this;\n\t    var suite = this.suite;\n\t    this.files.forEach(function (file) {\n\t      file = path.resolve(file);\n\t      suite.emit(EVENT_FILE_PRE_REQUIRE, commonjsGlobal, file, self);\n\t      suite.emit(EVENT_FILE_REQUIRE, commonjsRequire(), file, self);\n\t      suite.emit(EVENT_FILE_POST_REQUIRE, commonjsGlobal, file, self);\n\t    });\n\t    fn && fn();\n\t  };\n\t  /**\n\t   * Loads `files` prior to execution. Supports Node ES Modules.\n\t   *\n\t   * @description\n\t   * The implementation relies on Node's `require` and `import` to execute\n\t   * the test interface functions and will be subject to its cache.\n\t   * Supports both CJS and ESM modules.\n\t   *\n\t   * @public\n\t   * @see {@link Mocha#addFile}\n\t   * @see {@link Mocha#run}\n\t   * @see {@link Mocha#unloadFiles}\n\t   * @returns {Promise}\n\t   * @example\n\t   *\n\t   * // loads ESM (and CJS) test files asynchronously, then runs root suite\n\t   * mocha.loadFilesAsync()\n\t   *   .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0))\n\t   *   .catch(() => process.exitCode = 1);\n\t   */\n\n\n\t  Mocha.prototype.loadFilesAsync = function () {\n\t    var self = this;\n\t    var suite = this.suite;\n\t    this.lazyLoadFiles(true);\n\t    return require$$10.loadFilesAsync(this.files, function (file) {\n\t      suite.emit(EVENT_FILE_PRE_REQUIRE, commonjsGlobal, file, self);\n\t    }, function (file, resultModule) {\n\t      suite.emit(EVENT_FILE_REQUIRE, resultModule, file, self);\n\t      suite.emit(EVENT_FILE_POST_REQUIRE, commonjsGlobal, file, self);\n\t    });\n\t  };\n\t  /**\n\t   * Removes a previously loaded file from Node's `require` cache.\n\t   *\n\t   * @private\n\t   * @static\n\t   * @see {@link Mocha#unloadFiles}\n\t   * @param {string} file - Pathname of file to be unloaded.\n\t   */\n\n\n\t  Mocha.unloadFile = function (file) {\n\t    if (utils.isBrowser()) {\n\t      throw createUnsupportedError('unloadFile() is only suported in a Node.js environment');\n\t    }\n\n\t    return require$$10.unloadFile(file);\n\t  };\n\t  /**\n\t   * Unloads `files` from Node's `require` cache.\n\t   *\n\t   * @description\n\t   * This allows required files to be \"freshly\" reloaded, providing the ability\n\t   * to reuse a Mocha instance programmatically.\n\t   * Note: does not clear ESM module files from the cache\n\t   *\n\t   * <strong>Intended for consumers &mdash; not used internally</strong>\n\t   *\n\t   * @public\n\t   * @see {@link Mocha#run}\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.unloadFiles = function () {\n\t    if (this._state === mochaStates.DISPOSED) {\n\t      throw createMochaInstanceAlreadyDisposedError('Mocha instance is already disposed, it cannot be used again.', this._cleanReferencesAfterRun, this);\n\t    }\n\n\t    this.files.forEach(function (file) {\n\t      Mocha.unloadFile(file);\n\t    });\n\t    this._state = mochaStates.INIT;\n\t    return this;\n\t  };\n\t  /**\n\t   * Sets `grep` filter after escaping RegExp special characters.\n\t   *\n\t   * @public\n\t   * @see {@link Mocha#grep}\n\t   * @param {string} str - Value to be converted to a regexp.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Select tests whose full title begins with `\"foo\"` followed by a period\n\t   * mocha.fgrep('foo.');\n\t   */\n\n\n\t  Mocha.prototype.fgrep = function (str) {\n\t    if (!str) {\n\t      return this;\n\t    }\n\n\t    return this.grep(new RegExp(escapeStringRegexp(str)));\n\t  };\n\t  /**\n\t   * @summary\n\t   * Sets `grep` filter used to select specific tests for execution.\n\t   *\n\t   * @description\n\t   * If `re` is a regexp-like string, it will be converted to regexp.\n\t   * The regexp is tested against the full title of each test (i.e., the\n\t   * name of the test preceded by titles of each its ancestral suites).\n\t   * As such, using an <em>exact-match</em> fixed pattern against the\n\t   * test name itself will not yield any matches.\n\t   * <br>\n\t   * <strong>Previous filter value will be overwritten on each call!</strong>\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-grep-regexp-g-regexp)\n\t   * @see {@link Mocha#fgrep}\n\t   * @see {@link Mocha#invert}\n\t   * @param {RegExp|String} re - Regular expression used to select tests.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Select tests whose full title contains `\"match\"`, ignoring case\n\t   * mocha.grep(/match/i);\n\t   * @example\n\t   *\n\t   * // Same as above but with regexp-like string argument\n\t   * mocha.grep('/match/i');\n\t   * @example\n\t   *\n\t   * // ## Anti-example\n\t   * // Given embedded test `it('only-this-test')`...\n\t   * mocha.grep('/^only-this-test$/');    // NO! Use `.only()` to do this!\n\t   */\n\n\n\t  Mocha.prototype.grep = function (re) {\n\t    if (utils.isString(re)) {\n\t      // extract args if it's regex-like, i.e: [string, pattern, flag]\n\t      var arg = re.match(/^\\/(.*)\\/([gimy]{0,4})$|.*/);\n\t      this.options.grep = new RegExp(arg[1] || arg[0], arg[2]);\n\t    } else {\n\t      this.options.grep = re;\n\t    }\n\n\t    return this;\n\t  };\n\t  /**\n\t   * Inverts `grep` matches.\n\t   *\n\t   * @public\n\t   * @see {@link Mocha#grep}\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Select tests whose full title does *not* contain `\"match\"`, ignoring case\n\t   * mocha.grep(/match/i).invert();\n\t   */\n\n\n\t  Mocha.prototype.invert = function () {\n\t    this.options.invert = true;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables or disables checking for global variables leaked while running tests.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-check-leaks)\n\t   * @param {boolean} [checkLeaks=true] - Whether to check for global variable leaks.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.checkLeaks = function (checkLeaks) {\n\t    this.options.checkLeaks = checkLeaks !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables or disables whether or not to dispose after each test run.\n\t   * Disable this to ensure you can run the test suite multiple times.\n\t   * If disabled, be sure to dispose mocha when you're done to prevent memory leaks.\n\t   * @public\n\t   * @see {@link Mocha#dispose}\n\t   * @param {boolean} cleanReferencesAfterRun\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.cleanReferencesAfterRun = function (cleanReferencesAfterRun) {\n\t    this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.\n\t   * It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.\n\t   * @public\n\t   */\n\n\n\t  Mocha.prototype.dispose = function () {\n\t    if (this._state === mochaStates.RUNNING) {\n\t      throw createMochaInstanceAlreadyRunningError('Cannot dispose while the mocha instance is still running tests.');\n\t    }\n\n\t    this.unloadFiles();\n\t    this._previousRunner && this._previousRunner.dispose();\n\t    this.suite.dispose();\n\t    this._state = mochaStates.DISPOSED;\n\t  };\n\t  /**\n\t   * Displays full stack trace upon test failure.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-full-trace)\n\t   * @param {boolean} [fullTrace=true] - Whether to print full stacktrace upon failure.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.fullTrace = function (fullTrace) {\n\t    this.options.fullTrace = fullTrace !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables desktop notification support if prerequisite software installed.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-growl-g)\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.growl = function () {\n\t    this.options.growl = this.isGrowlCapable();\n\n\t    if (!this.options.growl) {\n\t      var detail = utils.isBrowser() ? 'notification support not available in this browser...' : 'notification support prerequisites not installed...';\n\t      console.error(detail + ' cannot enable!');\n\t    }\n\n\t    return this;\n\t  };\n\t  /**\n\t   * @summary\n\t   * Determines if Growl support seems likely.\n\t   *\n\t   * @description\n\t   * <strong>Not available when run in browser.</strong>\n\t   *\n\t   * @private\n\t   * @see {@link Growl#isCapable}\n\t   * @see {@link Mocha#growl}\n\t   * @return {boolean} whether Growl support can be expected\n\t   */\n\n\n\t  Mocha.prototype.isGrowlCapable = growl.isCapable;\n\t  /**\n\t   * Implements desktop notifications using a pseudo-reporter.\n\t   *\n\t   * @private\n\t   * @see {@link Mocha#growl}\n\t   * @see {@link Growl#notify}\n\t   * @param {Runner} runner - Runner instance.\n\t   */\n\n\t  Mocha.prototype._growl = growl.notify;\n\t  /**\n\t   * Specifies whitelist of variable names to be expected in global scope.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-global-variable-name)\n\t   * @see {@link Mocha#checkLeaks}\n\t   * @param {String[]|String} global - Accepted global variable name(s).\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Specify variables to be expected in global scope\n\t   * mocha.global(['jQuery', 'MyLib']);\n\t   */\n\n\t  Mocha.prototype.global = function (global) {\n\t    this.options.global = (this.options.global || []).concat(global).filter(Boolean).filter(function (elt, idx, arr) {\n\t      return arr.indexOf(elt) === idx;\n\t    });\n\t    return this;\n\t  }; // for backwards compability, 'globals' is an alias of 'global'\n\n\n\t  Mocha.prototype.globals = Mocha.prototype.global;\n\t  /**\n\t   * Enables or disables TTY color output by screen-oriented reporters.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-color-c-colors)\n\t   * @param {boolean} [color=true] - Whether to enable color output.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\t  Mocha.prototype.color = function (color) {\n\t    this.options.color = color !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables or disables reporter to use inline diffs (rather than +/-)\n\t   * in test failure output.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-inline-diffs)\n\t   * @param {boolean} [inlineDiffs=true] - Whether to use inline diffs.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.inlineDiffs = function (inlineDiffs) {\n\t    this.options.inlineDiffs = inlineDiffs !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables or disables reporter to include diff in test failure output.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-diff)\n\t   * @param {boolean} [diff=true] - Whether to show diff on failure.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.diff = function (diff) {\n\t    this.options.diff = diff !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * @summary\n\t   * Sets timeout threshold value.\n\t   *\n\t   * @description\n\t   * A string argument can use shorthand (such as \"2s\") and will be converted.\n\t   * If the value is `0`, timeouts will be disabled.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-timeout-ms-t-ms)\n\t   * @see [Timeouts](../#timeouts)\n\t   * @param {number|string} msecs - Timeout threshold value.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Sets timeout to one second\n\t   * mocha.timeout(1000);\n\t   * @example\n\t   *\n\t   * // Same as above but using string argument\n\t   * mocha.timeout('1s');\n\t   */\n\n\n\t  Mocha.prototype.timeout = function (msecs) {\n\t    this.suite.timeout(msecs);\n\t    return this;\n\t  };\n\t  /**\n\t   * Sets the number of times to retry failed tests.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-retries-n)\n\t   * @see [Retry Tests](../#retry-tests)\n\t   * @param {number} retry - Number of times to retry failed tests.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Allow any failed test to retry one more time\n\t   * mocha.retries(1);\n\t   */\n\n\n\t  Mocha.prototype.retries = function (retry) {\n\t    this.suite.retries(retry);\n\t    return this;\n\t  };\n\t  /**\n\t   * Sets slowness threshold value.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-slow-ms-s-ms)\n\t   * @param {number} msecs - Slowness threshold value.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   * @example\n\t   *\n\t   * // Sets \"slow\" threshold to half a second\n\t   * mocha.slow(500);\n\t   * @example\n\t   *\n\t   * // Same as above but using string argument\n\t   * mocha.slow('0.5s');\n\t   */\n\n\n\t  Mocha.prototype.slow = function (msecs) {\n\t    this.suite.slow(msecs);\n\t    return this;\n\t  };\n\t  /**\n\t   * Forces all tests to either accept a `done` callback or return a promise.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-async-only-a)\n\t   * @param {boolean} [asyncOnly=true] - Whether to force `done` callback or promise.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.asyncOnly = function (asyncOnly) {\n\t    this.options.asyncOnly = asyncOnly !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Disables syntax highlighting (in browser).\n\t   *\n\t   * @public\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.noHighlighting = function () {\n\t    this.options.noHighlighting = true;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables or disables uncaught errors to propagate.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-allow-uncaught)\n\t   * @param {boolean} [allowUncaught=true] - Whether to propagate uncaught errors.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.allowUncaught = function (allowUncaught) {\n\t    this.options.allowUncaught = allowUncaught !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * @summary\n\t   * Delays root suite execution.\n\t   *\n\t   * @description\n\t   * Used to perform async operations before any suites are run.\n\t   *\n\t   * @public\n\t   * @see [delayed root suite](../#delayed-root-suite)\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.delay = function delay() {\n\t    this.options.delay = true;\n\t    return this;\n\t  };\n\t  /**\n\t   * Enables or disables running tests in dry-run mode.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-dry-run)\n\t   * @param {boolean} [dryRun=true] - Whether to activate dry-run mode.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.dryRun = function (dryRun) {\n\t    this.options.dryRun = dryRun !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Fails test run if no tests encountered with exit-code 1.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-fail-zero)\n\t   * @param {boolean} [failZero=true] - Whether to fail test run.\n\t   * @return {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.failZero = function (failZero) {\n\t    this.options.failZero = failZero !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Causes tests marked `only` to fail the suite.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-forbid-only)\n\t   * @param {boolean} [forbidOnly=true] - Whether tests marked `only` fail the suite.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.forbidOnly = function (forbidOnly) {\n\t    this.options.forbidOnly = forbidOnly !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Causes pending tests and tests marked `skip` to fail the suite.\n\t   *\n\t   * @public\n\t   * @see [CLI option](../#-forbid-pending)\n\t   * @param {boolean} [forbidPending=true] - Whether pending tests fail the suite.\n\t   * @returns {Mocha} this\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.forbidPending = function (forbidPending) {\n\t    this.options.forbidPending = forbidPending !== false;\n\t    return this;\n\t  };\n\t  /**\n\t   * Throws an error if mocha is in the wrong state to be able to transition to a \"running\" state.\n\t   * @private\n\t   */\n\n\n\t  Mocha.prototype._guardRunningStateTransition = function () {\n\t    if (this._state === mochaStates.RUNNING) {\n\t      throw createMochaInstanceAlreadyRunningError('Mocha instance is currently running tests, cannot start a next test run until this one is done', this);\n\t    }\n\n\t    if (this._state === mochaStates.DISPOSED || this._state === mochaStates.REFERENCES_CLEANED) {\n\t      throw createMochaInstanceAlreadyDisposedError('Mocha instance is already disposed, cannot start a new test run. Please create a new mocha instance. Be sure to set disable `cleanReferencesAfterRun` when you want to reuse the same mocha instance for multiple test runs.', this._cleanReferencesAfterRun, this);\n\t    }\n\t  };\n\t  /**\n\t   * Mocha version as specified by \"package.json\".\n\t   *\n\t   * @name Mocha#version\n\t   * @type string\n\t   * @readonly\n\t   */\n\n\n\t  Object.defineProperty(Mocha.prototype, 'version', {\n\t    value: require$$9.version,\n\t    configurable: false,\n\t    enumerable: true,\n\t    writable: false\n\t  });\n\t  /**\n\t   * Callback to be invoked when test execution is complete.\n\t   *\n\t   * @private\n\t   * @callback DoneCB\n\t   * @param {number} failures - Number of failures that occurred.\n\t   */\n\n\t  /**\n\t   * Runs root suite and invokes `fn()` when complete.\n\t   *\n\t   * @description\n\t   * To run tests multiple times (or to run tests in files that are\n\t   * already in the `require` cache), make sure to clear them from\n\t   * the cache first!\n\t   *\n\t   * @public\n\t   * @see {@link Mocha#unloadFiles}\n\t   * @see {@link Runner#run}\n\t   * @param {DoneCB} [fn] - Callback invoked when test execution completed.\n\t   * @returns {Runner} runner instance\n\t   * @example\n\t   *\n\t   * // exit with non-zero status if there were test failures\n\t   * mocha.run(failures => process.exitCode = failures ? 1 : 0);\n\t   */\n\n\t  Mocha.prototype.run = function (fn) {\n\t    var _this = this;\n\n\t    this._guardRunningStateTransition();\n\n\t    this._state = mochaStates.RUNNING;\n\n\t    if (this._previousRunner) {\n\t      this._previousRunner.dispose();\n\n\t      this.suite.reset();\n\t    }\n\n\t    if (this.files.length && !this._lazyLoadFiles) {\n\t      this.loadFiles();\n\t    }\n\n\t    var suite = this.suite;\n\t    var options = this.options;\n\t    options.files = this.files;\n\t    var runner = new this._runnerClass(suite, {\n\t      cleanReferencesAfterRun: this._cleanReferencesAfterRun,\n\t      delay: options.delay,\n\t      dryRun: options.dryRun,\n\t      failZero: options.failZero\n\t    });\n\t    statsCollector(runner);\n\t    var reporter = new this._reporter(runner, options);\n\t    runner.checkLeaks = options.checkLeaks === true;\n\t    runner.fullStackTrace = options.fullTrace;\n\t    runner.asyncOnly = options.asyncOnly;\n\t    runner.allowUncaught = options.allowUncaught;\n\t    runner.forbidOnly = options.forbidOnly;\n\t    runner.forbidPending = options.forbidPending;\n\n\t    if (options.grep) {\n\t      runner.grep(options.grep, options.invert);\n\t    }\n\n\t    if (options.global) {\n\t      runner.globals(options.global);\n\t    }\n\n\t    if (options.growl) {\n\t      this._growl(runner);\n\t    }\n\n\t    if (options.color !== undefined) {\n\t      exports.reporters.Base.useColors = options.color;\n\t    }\n\n\t    exports.reporters.Base.inlineDiffs = options.inlineDiffs;\n\t    exports.reporters.Base.hideDiff = !options.diff;\n\n\t    var done = function done(failures) {\n\t      _this._previousRunner = runner;\n\t      _this._state = _this._cleanReferencesAfterRun ? mochaStates.REFERENCES_CLEANED : mochaStates.INIT;\n\t      fn = fn || utils.noop;\n\n\t      if (typeof reporter.done === 'function') {\n\t        reporter.done(failures, fn);\n\t      } else {\n\t        fn(failures);\n\t      }\n\t    };\n\n\t    var runAsync = /*#__PURE__*/function () {\n\t      var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(runner) {\n\t        var context, failureCount;\n\t        return regeneratorRuntime.wrap(function _callee$(_context) {\n\t          while (1) {\n\t            switch (_context.prev = _context.next) {\n\t              case 0:\n\t                if (!(_this.options.enableGlobalSetup && _this.hasGlobalSetupFixtures())) {\n\t                  _context.next = 6;\n\t                  break;\n\t                }\n\n\t                _context.next = 3;\n\t                return _this.runGlobalSetup(runner);\n\n\t              case 3:\n\t                _context.t0 = _context.sent;\n\t                _context.next = 7;\n\t                break;\n\n\t              case 6:\n\t                _context.t0 = {};\n\n\t              case 7:\n\t                context = _context.t0;\n\t                _context.next = 10;\n\t                return runner.runAsync({\n\t                  files: _this.files,\n\t                  options: options\n\t                });\n\n\t              case 10:\n\t                failureCount = _context.sent;\n\n\t                if (!(_this.options.enableGlobalTeardown && _this.hasGlobalTeardownFixtures())) {\n\t                  _context.next = 14;\n\t                  break;\n\t                }\n\n\t                _context.next = 14;\n\t                return _this.runGlobalTeardown(runner, {\n\t                  context: context\n\t                });\n\n\t              case 14:\n\t                return _context.abrupt(\"return\", failureCount);\n\n\t              case 15:\n\t              case \"end\":\n\t                return _context.stop();\n\t            }\n\t          }\n\t        }, _callee);\n\t      }));\n\n\t      return function runAsync(_x) {\n\t        return _ref.apply(this, arguments);\n\t      };\n\t    }(); // no \"catch\" here is intentional. errors coming out of\n\t    // Runner#run are considered uncaught/unhandled and caught\n\t    // by the `process` event listeners.\n\t    // also: returning anything other than `runner` would be a breaking\n\t    // change\n\n\n\t    runAsync(runner).then(done);\n\t    return runner;\n\t  };\n\t  /**\n\t   * Assigns hooks to the root suite\n\t   * @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite\n\t   * @chainable\n\t   */\n\n\n\t  Mocha.prototype.rootHooks = function rootHooks() {\n\t    var _this2 = this;\n\n\t    var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n\t        _ref2$beforeAll = _ref2.beforeAll,\n\t        beforeAll = _ref2$beforeAll === void 0 ? [] : _ref2$beforeAll,\n\t        _ref2$beforeEach = _ref2.beforeEach,\n\t        beforeEach = _ref2$beforeEach === void 0 ? [] : _ref2$beforeEach,\n\t        _ref2$afterAll = _ref2.afterAll,\n\t        afterAll = _ref2$afterAll === void 0 ? [] : _ref2$afterAll,\n\t        _ref2$afterEach = _ref2.afterEach,\n\t        afterEach = _ref2$afterEach === void 0 ? [] : _ref2$afterEach;\n\n\t    beforeAll = utils.castArray(beforeAll);\n\t    beforeEach = utils.castArray(beforeEach);\n\t    afterAll = utils.castArray(afterAll);\n\t    afterEach = utils.castArray(afterEach);\n\t    beforeAll.forEach(function (hook) {\n\t      _this2.suite.beforeAll(hook);\n\t    });\n\t    beforeEach.forEach(function (hook) {\n\t      _this2.suite.beforeEach(hook);\n\t    });\n\t    afterAll.forEach(function (hook) {\n\t      _this2.suite.afterAll(hook);\n\t    });\n\t    afterEach.forEach(function (hook) {\n\t      _this2.suite.afterEach(hook);\n\t    });\n\t    return this;\n\t  };\n\t  /**\n\t   * Toggles parallel mode.\n\t   *\n\t   * Must be run before calling {@link Mocha#run}. Changes the `Runner` class to\n\t   * use; also enables lazy file loading if not already done so.\n\t   *\n\t   * Warning: when passed `false` and lazy loading has been enabled _via any means_ (including calling `parallelMode(true)`), this method will _not_ disable lazy loading. Lazy loading is a prerequisite for parallel\n\t   * mode, but parallel mode is _not_ a prerequisite for lazy loading!\n\t   * @param {boolean} [enable] - If `true`, enable; otherwise disable.\n\t   * @throws If run in browser\n\t   * @throws If Mocha not in `INIT` state\n\t   * @returns {Mocha}\n\t   * @chainable\n\t   * @public\n\t   */\n\n\n\t  Mocha.prototype.parallelMode = function parallelMode() {\n\t    var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n\n\t    if (utils.isBrowser()) {\n\t      throw createUnsupportedError('parallel mode is only supported in Node.js');\n\t    }\n\n\t    var parallel = Boolean(enable);\n\n\t    if (parallel === this.options.parallel && this._lazyLoadFiles && this._runnerClass !== exports.Runner) {\n\t      return this;\n\t    }\n\n\t    if (this._state !== mochaStates.INIT) {\n\t      throw createUnsupportedError('cannot change parallel mode after having called run()');\n\t    }\n\n\t    this.options.parallel = parallel; // swap Runner class\n\n\t    this._runnerClass = parallel ? require$$10 : exports.Runner; // lazyLoadFiles may have been set `true` otherwise (for ESM loading),\n\t    // so keep `true` if so.\n\n\t    return this.lazyLoadFiles(this._lazyLoadFiles || parallel);\n\t  };\n\t  /**\n\t   * Disables implicit call to {@link Mocha#loadFiles} in {@link Mocha#run}. This\n\t   * setting is used by watch mode, parallel mode, and for loading ESM files.\n\t   * @todo This should throw if we've already loaded files; such behavior\n\t   * necessitates adding a new state.\n\t   * @param {boolean} [enable] - If `true`, disable eager loading of files in\n\t   * {@link Mocha#run}\n\t   * @chainable\n\t   * @public\n\t   */\n\n\n\t  Mocha.prototype.lazyLoadFiles = function lazyLoadFiles(enable) {\n\t    this._lazyLoadFiles = enable === true;\n\t    debug('set lazy load to %s', enable);\n\t    return this;\n\t  };\n\t  /**\n\t   * Configures one or more global setup fixtures.\n\t   *\n\t   * If given no parameters, _unsets_ any previously-set fixtures.\n\t   * @chainable\n\t   * @public\n\t   * @param {MochaGlobalFixture|MochaGlobalFixture[]} [setupFns] - Global setup fixture(s)\n\t   * @returns {Mocha}\n\t   */\n\n\n\t  Mocha.prototype.globalSetup = function globalSetup() {\n\t    var setupFns = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n\t    setupFns = utils.castArray(setupFns);\n\t    this.options.globalSetup = setupFns;\n\t    debug('configured %d global setup functions', setupFns.length);\n\t    return this;\n\t  };\n\t  /**\n\t   * Configures one or more global teardown fixtures.\n\t   *\n\t   * If given no parameters, _unsets_ any previously-set fixtures.\n\t   * @chainable\n\t   * @public\n\t   * @param {MochaGlobalFixture|MochaGlobalFixture[]} [teardownFns] - Global teardown fixture(s)\n\t   * @returns {Mocha}\n\t   */\n\n\n\t  Mocha.prototype.globalTeardown = function globalTeardown() {\n\t    var teardownFns = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n\t    teardownFns = utils.castArray(teardownFns);\n\t    this.options.globalTeardown = teardownFns;\n\t    debug('configured %d global teardown functions', teardownFns.length);\n\t    return this;\n\t  };\n\t  /**\n\t   * Run any global setup fixtures sequentially, if any.\n\t   *\n\t   * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalSetup` option is `false`; see {@link Mocha#enableGlobalSetup}.\n\t   *\n\t   * The context object this function resolves with should be consumed by {@link Mocha#runGlobalTeardown}.\n\t   * @param {object} [context] - Context object if already have one\n\t   * @public\n\t   * @returns {Promise<object>} Context object\n\t   */\n\n\n\t  Mocha.prototype.runGlobalSetup = /*#__PURE__*/function () {\n\t    var _runGlobalSetup = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n\t      var context,\n\t          globalSetup,\n\t          _args2 = arguments;\n\t      return regeneratorRuntime.wrap(function _callee2$(_context2) {\n\t        while (1) {\n\t          switch (_context2.prev = _context2.next) {\n\t            case 0:\n\t              context = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {};\n\t              globalSetup = this.options.globalSetup;\n\n\t              if (!(globalSetup && globalSetup.length)) {\n\t                _context2.next = 7;\n\t                break;\n\t              }\n\n\t              debug('run(): global setup starting');\n\t              _context2.next = 6;\n\t              return this._runGlobalFixtures(globalSetup, context);\n\n\t            case 6:\n\t              debug('run(): global setup complete');\n\n\t            case 7:\n\t              return _context2.abrupt(\"return\", context);\n\n\t            case 8:\n\t            case \"end\":\n\t              return _context2.stop();\n\t          }\n\t        }\n\t      }, _callee2, this);\n\t    }));\n\n\t    function runGlobalSetup() {\n\t      return _runGlobalSetup.apply(this, arguments);\n\t    }\n\n\t    return runGlobalSetup;\n\t  }();\n\t  /**\n\t   * Run any global teardown fixtures sequentially, if any.\n\t   *\n\t   * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalTeardown` option is `false`; see {@link Mocha#enableGlobalTeardown}.\n\t   *\n\t   * Should be called with context object returned by {@link Mocha#runGlobalSetup}, if applicable.\n\t   * @param {object} [context] - Context object if already have one\n\t   * @public\n\t   * @returns {Promise<object>} Context object\n\t   */\n\n\n\t  Mocha.prototype.runGlobalTeardown = /*#__PURE__*/function () {\n\t    var _runGlobalTeardown = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {\n\t      var context,\n\t          globalTeardown,\n\t          _args3 = arguments;\n\t      return regeneratorRuntime.wrap(function _callee3$(_context3) {\n\t        while (1) {\n\t          switch (_context3.prev = _context3.next) {\n\t            case 0:\n\t              context = _args3.length > 0 && _args3[0] !== undefined ? _args3[0] : {};\n\t              globalTeardown = this.options.globalTeardown;\n\n\t              if (!(globalTeardown && globalTeardown.length)) {\n\t                _context3.next = 6;\n\t                break;\n\t              }\n\n\t              debug('run(): global teardown starting');\n\t              _context3.next = 6;\n\t              return this._runGlobalFixtures(globalTeardown, context);\n\n\t            case 6:\n\t              debug('run(): global teardown complete');\n\t              return _context3.abrupt(\"return\", context);\n\n\t            case 8:\n\t            case \"end\":\n\t              return _context3.stop();\n\t          }\n\t        }\n\t      }, _callee3, this);\n\t    }));\n\n\t    function runGlobalTeardown() {\n\t      return _runGlobalTeardown.apply(this, arguments);\n\t    }\n\n\t    return runGlobalTeardown;\n\t  }();\n\t  /**\n\t   * Run global fixtures sequentially with context `context`\n\t   * @private\n\t   * @param {MochaGlobalFixture[]} [fixtureFns] - Fixtures to run\n\t   * @param {object} [context] - context object\n\t   * @returns {Promise<object>} context object\n\t   */\n\n\n\t  Mocha.prototype._runGlobalFixtures = /*#__PURE__*/function () {\n\t    var _runGlobalFixtures2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {\n\t      var fixtureFns,\n\t          context,\n\t          _iteratorAbruptCompletion,\n\t          _didIteratorError,\n\t          _iteratorError,\n\t          _iterator,\n\t          _step,\n\t          fixtureFn,\n\t          _args4 = arguments;\n\n\t      return regeneratorRuntime.wrap(function _callee4$(_context4) {\n\t        while (1) {\n\t          switch (_context4.prev = _context4.next) {\n\t            case 0:\n\t              fixtureFns = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : [];\n\t              context = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {};\n\t              _iteratorAbruptCompletion = false;\n\t              _didIteratorError = false;\n\t              _context4.prev = 4;\n\t              _iterator = _asyncIterator(fixtureFns);\n\n\t            case 6:\n\t              _context4.next = 8;\n\t              return _iterator.next();\n\n\t            case 8:\n\t              if (!(_iteratorAbruptCompletion = !(_step = _context4.sent).done)) {\n\t                _context4.next = 15;\n\t                break;\n\t              }\n\n\t              fixtureFn = _step.value;\n\t              _context4.next = 12;\n\t              return fixtureFn.call(context);\n\n\t            case 12:\n\t              _iteratorAbruptCompletion = false;\n\t              _context4.next = 6;\n\t              break;\n\n\t            case 15:\n\t              _context4.next = 21;\n\t              break;\n\n\t            case 17:\n\t              _context4.prev = 17;\n\t              _context4.t0 = _context4[\"catch\"](4);\n\t              _didIteratorError = true;\n\t              _iteratorError = _context4.t0;\n\n\t            case 21:\n\t              _context4.prev = 21;\n\t              _context4.prev = 22;\n\n\t              if (!(_iteratorAbruptCompletion && _iterator[\"return\"] != null)) {\n\t                _context4.next = 26;\n\t                break;\n\t              }\n\n\t              _context4.next = 26;\n\t              return _iterator[\"return\"]();\n\n\t            case 26:\n\t              _context4.prev = 26;\n\n\t              if (!_didIteratorError) {\n\t                _context4.next = 29;\n\t                break;\n\t              }\n\n\t              throw _iteratorError;\n\n\t            case 29:\n\t              return _context4.finish(26);\n\n\t            case 30:\n\t              return _context4.finish(21);\n\n\t            case 31:\n\t              return _context4.abrupt(\"return\", context);\n\n\t            case 32:\n\t            case \"end\":\n\t              return _context4.stop();\n\t          }\n\t        }\n\t      }, _callee4, null, [[4, 17, 21, 31], [22,, 26, 30]]);\n\t    }));\n\n\t    function _runGlobalFixtures() {\n\t      return _runGlobalFixtures2.apply(this, arguments);\n\t    }\n\n\t    return _runGlobalFixtures;\n\t  }();\n\t  /**\n\t   * Toggle execution of any global setup fixture(s)\n\t   *\n\t   * @chainable\n\t   * @public\n\t   * @param {boolean } [enabled=true] - If `false`, do not run global setup fixture\n\t   * @returns {Mocha}\n\t   */\n\n\n\t  Mocha.prototype.enableGlobalSetup = function enableGlobalSetup() {\n\t    var enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n\t    this.options.enableGlobalSetup = Boolean(enabled);\n\t    return this;\n\t  };\n\t  /**\n\t   * Toggle execution of any global teardown fixture(s)\n\t   *\n\t   * @chainable\n\t   * @public\n\t   * @param {boolean } [enabled=true] - If `false`, do not run global teardown fixture\n\t   * @returns {Mocha}\n\t   */\n\n\n\t  Mocha.prototype.enableGlobalTeardown = function enableGlobalTeardown() {\n\t    var enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n\t    this.options.enableGlobalTeardown = Boolean(enabled);\n\t    return this;\n\t  };\n\t  /**\n\t   * Returns `true` if one or more global setup fixtures have been supplied.\n\t   * @public\n\t   * @returns {boolean}\n\t   */\n\n\n\t  Mocha.prototype.hasGlobalSetupFixtures = function hasGlobalSetupFixtures() {\n\t    return Boolean(this.options.globalSetup.length);\n\t  };\n\t  /**\n\t   * Returns `true` if one or more global teardown fixtures have been supplied.\n\t   * @public\n\t   * @returns {boolean}\n\t   */\n\n\n\t  Mocha.prototype.hasGlobalTeardownFixtures = function hasGlobalTeardownFixtures() {\n\t    return Boolean(this.options.globalTeardown.length);\n\t  };\n\t  /**\n\t   * An alternative way to define root hooks that works with parallel runs.\n\t   * @typedef {Object} MochaRootHookObject\n\t   * @property {Function|Function[]} [beforeAll] - \"Before all\" hook(s)\n\t   * @property {Function|Function[]} [beforeEach] - \"Before each\" hook(s)\n\t   * @property {Function|Function[]} [afterAll] - \"After all\" hook(s)\n\t   * @property {Function|Function[]} [afterEach] - \"After each\" hook(s)\n\t   */\n\n\t  /**\n\t   * An function that returns a {@link MochaRootHookObject}, either sync or async.\n\t     @callback MochaRootHookFunction\n\t   * @returns {MochaRootHookObject|Promise<MochaRootHookObject>}\n\t   */\n\n\t  /**\n\t   * A function that's invoked _once_ which is either sync or async.\n\t   * Can be a \"teardown\" or \"setup\".  These will all share the same context.\n\t   * @callback MochaGlobalFixture\n\t   * @returns {void|Promise<void>}\n\t   */\n\n\t  /**\n\t   * An object making up all necessary parts of a plugin loader and aggregator\n\t   * @typedef {Object} PluginDefinition\n\t   * @property {string} exportName - Named export to use\n\t   * @property {string} [optionName] - Option name for Mocha constructor (use `exportName` if omitted)\n\t   * @property {PluginValidator} [validate] - Validator function\n\t   * @property {PluginFinalizer} [finalize] - Finalizer/aggregator function\n\t   */\n\n\t  /**\n\t   * A (sync) function to assert a user-supplied plugin implementation is valid.\n\t   *\n\t   * Defined in a {@link PluginDefinition}.\n\t  \n\t   * @callback PluginValidator\n\t   * @param {*} value - Value to check\n\t   * @this {PluginDefinition}\n\t   * @returns {void}\n\t   */\n\n\t  /**\n\t   * A function to finalize plugins impls of a particular ilk\n\t   * @callback PluginFinalizer\n\t   * @param {Array<*>} impls - User-supplied implementations\n\t   * @returns {Promise<*>|*}\n\t   */\n\n\t});\n\n\t/* eslint no-unused-vars: off */\n\n\t/* eslint-env commonjs */\n\n\t/**\n\t * Shim process.stdout.\n\t */\n\n\n\tprocess$4.stdout = browserStdout({\n\t  label: false\n\t});\n\t/**\n\t * Create a Mocha instance.\n\t *\n\t * @return {undefined}\n\t */\n\n\tvar mocha = new mocha$1({\n\t  reporter: 'html'\n\t});\n\t/**\n\t * Save timer references to avoid Sinon interfering (see GH-237).\n\t */\n\n\tvar Date$1 = commonjsGlobal.Date;\n\tvar setTimeout$1 = commonjsGlobal.setTimeout;\n\tcommonjsGlobal.setInterval;\n\tcommonjsGlobal.clearTimeout;\n\tcommonjsGlobal.clearInterval;\n\tvar uncaughtExceptionHandlers = [];\n\tvar originalOnerrorHandler = commonjsGlobal.onerror;\n\t/**\n\t * Remove uncaughtException listener.\n\t * Revert to original onerror handler if previously defined.\n\t */\n\n\tprocess$4.removeListener = function (e, fn) {\n\t  if (e === 'uncaughtException') {\n\t    if (originalOnerrorHandler) {\n\t      commonjsGlobal.onerror = originalOnerrorHandler;\n\t    } else {\n\t      commonjsGlobal.onerror = function () {};\n\t    }\n\n\t    var i = uncaughtExceptionHandlers.indexOf(fn);\n\n\t    if (i !== -1) {\n\t      uncaughtExceptionHandlers.splice(i, 1);\n\t    }\n\t  }\n\t};\n\t/**\n\t * Implements listenerCount for 'uncaughtException'.\n\t */\n\n\n\tprocess$4.listenerCount = function (name) {\n\t  if (name === 'uncaughtException') {\n\t    return uncaughtExceptionHandlers.length;\n\t  }\n\n\t  return 0;\n\t};\n\t/**\n\t * Implements uncaughtException listener.\n\t */\n\n\n\tprocess$4.on = function (e, fn) {\n\t  if (e === 'uncaughtException') {\n\t    commonjsGlobal.onerror = function (err, url, line) {\n\t      fn(new Error(err + ' (' + url + ':' + line + ')'));\n\t      return !mocha.options.allowUncaught;\n\t    };\n\n\t    uncaughtExceptionHandlers.push(fn);\n\t  }\n\t};\n\n\tprocess$4.listeners = function (e) {\n\t  if (e === 'uncaughtException') {\n\t    return uncaughtExceptionHandlers;\n\t  }\n\n\t  return [];\n\t}; // The BDD UI is registered by default, but no UI will be functional in the\n\t// browser without an explicit call to the overridden `mocha.ui` (see below).\n\t// Ensure that this default UI does not expose its methods to the global scope.\n\n\n\tmocha.suite.removeAllListeners('pre-require');\n\tvar immediateQueue = [];\n\tvar immediateTimeout;\n\n\tfunction timeslice() {\n\t  var immediateStart = new Date$1().getTime();\n\n\t  while (immediateQueue.length && new Date$1().getTime() - immediateStart < 100) {\n\t    immediateQueue.shift()();\n\t  }\n\n\t  if (immediateQueue.length) {\n\t    immediateTimeout = setTimeout$1(timeslice, 0);\n\t  } else {\n\t    immediateTimeout = null;\n\t  }\n\t}\n\t/**\n\t * High-performance override of Runner.immediately.\n\t */\n\n\n\tmocha$1.Runner.immediately = function (callback) {\n\t  immediateQueue.push(callback);\n\n\t  if (!immediateTimeout) {\n\t    immediateTimeout = setTimeout$1(timeslice, 0);\n\t  }\n\t};\n\t/**\n\t * Function to allow assertion libraries to throw errors directly into mocha.\n\t * This is useful when running tests in a browser because window.onerror will\n\t * only receive the 'message' attribute of the Error.\n\t */\n\n\n\tmocha.throwError = function (err) {\n\t  uncaughtExceptionHandlers.forEach(function (fn) {\n\t    fn(err);\n\t  });\n\t  throw err;\n\t};\n\t/**\n\t * Override ui to ensure that the ui functions are initialized.\n\t * Normally this would happen in Mocha.prototype.loadFiles.\n\t */\n\n\n\tmocha.ui = function (ui) {\n\t  mocha$1.prototype.ui.call(this, ui);\n\t  this.suite.emit('pre-require', commonjsGlobal, null, this);\n\t  return this;\n\t};\n\t/**\n\t * Setup mocha with the given setting options.\n\t */\n\n\n\tmocha.setup = function (opts) {\n\t  if (typeof opts === 'string') {\n\t    opts = {\n\t      ui: opts\n\t    };\n\t  }\n\n\t  if (opts.delay === true) {\n\t    this.delay();\n\t  }\n\n\t  var self = this;\n\t  Object.keys(opts).filter(function (opt) {\n\t    return opt !== 'delay';\n\t  }).forEach(function (opt) {\n\t    if (Object.prototype.hasOwnProperty.call(opts, opt)) {\n\t      self[opt](opts[opt]);\n\t    }\n\t  });\n\t  return this;\n\t};\n\t/**\n\t * Run mocha, returning the Runner.\n\t */\n\n\n\tmocha.run = function (fn) {\n\t  var options = mocha.options;\n\t  mocha.globals('location');\n\t  var query = parseQuery(commonjsGlobal.location.search || '');\n\n\t  if (query.grep) {\n\t    mocha.grep(query.grep);\n\t  }\n\n\t  if (query.fgrep) {\n\t    mocha.fgrep(query.fgrep);\n\t  }\n\n\t  if (query.invert) {\n\t    mocha.invert();\n\t  }\n\n\t  return mocha$1.prototype.run.call(mocha, function (err) {\n\t    // The DOM Document is not available in Web Workers.\n\t    var document = commonjsGlobal.document;\n\n\t    if (document && document.getElementById('mocha') && options.noHighlighting !== true) {\n\t      highlightTags('code');\n\t    }\n\n\t    if (fn) {\n\t      fn(err);\n\t    }\n\t  });\n\t};\n\t/**\n\t * Expose the process shim.\n\t * https://github.com/mochajs/mocha/pull/916\n\t */\n\n\n\tmocha$1.process = process$4;\n\t/**\n\t * Expose mocha.\n\t */\n\n\tcommonjsGlobal.Mocha = mocha$1;\n\tcommonjsGlobal.mocha = mocha; // for bundlers: enable `import {describe, it} from 'mocha'`\n\t// `bdd` interface only\n\t// prettier-ignore\n\n\t['describe', 'context', 'it', 'specify', 'xdescribe', 'xcontext', 'xit', 'xspecify', 'before', 'beforeEach', 'afterEach', 'after'].forEach(function (key) {\n\t  mocha[key] = commonjsGlobal[key];\n\t});\n\tvar browserEntry = mocha;\n\n\treturn browserEntry;\n\n}));\n//# sourceMappingURL=mocha.js.map\n"
  },
  {
    "path": "public/tests/tabpanel.test.js",
    "content": "import { render, screen, waitFor, expect, fireEvent } from './imports-test.js';\n\nconst renderTabPanel = () => {\n    const div = document.createElement('div');\n    div.innerHTML = `\n        <x-tab-panel>\n            <x-tab title=\"Tab 1\" active>\n                <p>Tab 1 content</p> \n            </x-tab>\n            <x-tab title=\"Tab 2\">\n                <p>Tab 2 content</p>\n            </x-tab>\n        </x-tab-panel>\n    `;\n    render(div);\n}\n\ndescribe('tabpanel', () => {\n    it(\"renders a tabpanel with active tab\", async () => {\n        // ARRANGE\n        renderTabPanel();\n    \n        // ASSERT\n        // active tab is selected\n        const activeTab = await screen.findByRole('tab', { name: 'Tab 1', selected: true });\n        expect(activeTab).to.not.be.undefined;\n        // active tabpanel is visible\n        const activePanel = screen.getByText(/Tab 1 content/);\n        expect(activePanel).to.not.be.undefined;\n        // not active tabpanel content is hidden\n        const tab2 = screen.getByTitle('Tab 2');\n        await waitFor(() => expect(tab2.offsetParent).to.be.null);\n    });\n    \n    it(\"activates a different tab on click\", async () => {\n        // ARRANGE\n        renderTabPanel();\n        const tab2 = screen.getByTitle('Tab 2');\n    \n        // ASSERT\n        // inactive tabpanel content is hidden\n        await waitFor(() => expect(tab2.offsetParent).to.be.null);\n        // find inactive tab button and click it\n        const tab2Button = await screen.findByRole('tab', { name: 'Tab 2' });\n        expect(tab2Button).not.to.be.undefined;\n        fireEvent.click(tab2Button);\n        // inactive tabpanel content is made visible\n        await waitFor(() => expect(tab2.offsetParent).not.to.be.null);\n    });\n});\n"
  }
]