https://perchance.org/zb67bgo77s

ID da verificação
1adb62ea-c72e-4207-bad6-9ecd56faf119Concluído
URL enviado:
https://perchance.org/zb67bgo77s
Relatório concluído:

Ligações · 1 encontradas

As ligações de saída identificadas na página

HiperligaçãoTexto
https://lemmy.world/c/perchancepost to forum

Variáveis JavaScript · 78 encontradas

Variáveis JavaScript globais carregadas no objeto janela de uma página são variáveis declaradas fora das funções e acessíveis de qualquer parte do código dentro do âmbito atual

NomeTipo
0object
1object
onbeforetoggleobject
documentPictureInPictureobject
onscrollendobject
TEST_NEW_EDITOR_1boolean
kvobject
initKvfunction
hasDynamicMetaDataboolean
metaDataIsLoadedResolverfunction

Mensagens de registo da consola · 11 encontradas

Mensagens registadas na consola web

TipoCategoriaRegisto
debugother
Texto
let a of arr supported
debugother
URL
https://perchance.org/zb67bgo77s
Texto
transferSize (likely partial): 309355
warningother
URL
https://perchance.org/zb67bgo77s
Texto
Allow attribute will take precedence over 'allowfullscreen'.
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
verbosedom
URL
https://perchance.org/zb67bgo77s
Texto
[DOM] Password field is not contained in a form: (More info: https://goo.gl/9p2vKq) %o
debugother
Texto
async/await is supported

HTML

O corpo HTML em bruto da página

<!DOCTYPE html><html class="no-js" lang=""><head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">

        <title>AI P GEN (nsfw, 18+, realistic, uncensored, free, no limits)</title> 
        <meta name="description" content="">
        <meta id="viewportMetaEl" name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content">

        <link rel="apple-touch-icon" href="apple-touch-icon.png">
        <link rel="icon" type="image/png" href="apple-touch-icon.png" sizes="180x180">
        <link rel="icon" type="image/png" href="/favicon-32x32-white-bg.png" sizes="32x32">
        <link rel="icon" type="image/png" href="/favicon-16x16-white-bg.png" sizes="16x16"> 
        
        
        <meta property="og:type" content="website">
        <!-- <meta property="og:url" content="https://perchance.org/..." />  -->
        <meta property="og:image" content="">
        <!-- <meta property="og:description" content="..." /> -->

        <meta name="color-scheme" content="dark light">

        <link rel="preconnect" href="https://d873b020cf1c788608c57afc66b7eb00.perchance.org">

        
        

        <style>
          :root {
            --menu-bar-height: 26px;
          }
        </style>

        <script>
          if(!Array.prototype.at) {
            window.addEventListener("error", function(message, url, linenumber) {
              console.warn(`JavaScript error: ${message} on line ${linenumber} for ${url}`, message, url, linenumber);
            });
          }
        </script>

        <script>
          window.TEST_NEW_EDITOR_1 = true; // localStorage.TEST_NEW_EDITOR_1; 

          // preload the editor bundle if we're going to need it
          if(window.TEST_NEW_EDITOR_1 && window.location.hash == "#edit") window.editorBundleImportPromise = import("/lib/editors.bundle.min.js");
          
          setTimeout(() => {
            if(window.TEST_NEW_EDITOR_1 && !window.editorBundleImportPromise) window.editorBundleImportPromise = import("/lib/editors.bundle.min.js");
          }, 20*1000);
        </script>

        <script>
          {
            // attempt at solving virtual keyboard causing top-level scroll in mobile:
            // let viewport = document.querySelector("meta[name=viewport]");
            // viewport.setAttribute("content", viewport.content + `, height=${window.innerHeight}`);

            // window.visualViewport.addEventListener('resize', function (event) {
            // });

            // doesn't work properly - causes momentary screen jumping/flashing on keyboard close
            // if("virtualKeyboard" in navigator) {
            //   navigator.virtualKeyboard.overlaysContent = true;
            // }
          }
        </script>  

        <script>
          window.name = window.location.pathname; // for Notification.onclick to not open a new window if that generator is open already
        </script>

        <script>
          window.kv = null; // so `if(kv)...` doesn't throw error.
          window.initKv = async function() {
            if(window.kv) return;
            let idbKeyval = await import("https://cdn.jsdelivr.net/npm/idb-keyval@6/+esm");
            window.kv = new Proxy(idbKeyval, { // so api is like: kv.myStoreName.get(...)
              get(target, prop, receiver) {
                const store = idbKeyval.createStore(`${prop}-db`, `${prop}-store`);
                return {
                  get: (key) => idbKeyval.get(key, store),
                  set: (key, value) => idbKeyval.set(key, value, store),
                  delete: (key) => idbKeyval.del(key, store),
                  entries: () => idbKeyval.entries(store),
                };
              },
            });
          }
        </script>

        <script>
          window.hasDynamicMetaData = "false" === "true";
          window.metaDataIsLoadedPromise = new Promise(r => window.metaDataIsLoadedResolver=r);
          if(!window.hasDynamicMetaData) window.metaDataIsLoadedResolver();
          (async function() { 
            if(window.hasDynamicMetaData) {
              let urlQueryStringPart = new URLSearchParams(window.location.search).toString();
              if(urlQueryStringPart) urlQueryStringPart = "&" + urlQueryStringPart;
              let data = await fetch(`/api/getDynamicMetaData?__generatorName=${window.location.pathname.slice(1)}${urlQueryStringPart}`).then(r => r.json()).catch(console.error);
              if(data && data.success) {
                window.forceDisableAds = !!data.forceDisableAds;
                // NOTE: Be wary of script injection when editing.
                document.querySelector("meta[name='description']").content = data.description;
                document.title = data.title;
                document.querySelector("meta[property='og:image']").content = data.image;
              }
              window.metaDataIsLoadedResolver();
            }
          })(); 
        </script>
        
        <script>window.forceDisableAds=true;</script>

    </head>  
    <body style="overscroll-behavior:none;">
      
        <!-- <div id="controlHeightEl" style="height:100vh; width:0px; position: absolute;"></div> -->
        <script>
          // document.documentElement.style.height = controlHeightEl.clientHeight+"px";
          
          window.advertHeight = window.innerWidth > 700 ? 90 : 50; 

          // document.documentElement.style.height = `height:calc(100lvh + var(--menu-bar-height) + 1px)`;
          // function updateMainElHeight() {
          //   document.querySelector("#editorEl #main").style.height = `calc(100dvh - ${menuBarEl.offsetHeight - Math.abs(menuBarEl.getBoundingClientRect().top)}px - ${window.advertHeight+4+4}px)`;
          //   console.debug(document.querySelector("#editorEl #main").style.height)
          // }
          // window.addEventListener("scroll", updateMainElHeight);

          {
            const viewportMetaEl = document.querySelector('#viewportMetaEl');
            const originalViewportMetaContent = viewportMetaEl.getAttribute("content");
            let lastChangeTime = Date.now();
            const observer = new MutationObserver(mutations => {
              mutations.forEach(m => {
                if(m.type === 'attributes' && Date.now() - lastChangeTime > 2000) {
                  lastChangeTime = Date.now();
                  console.log("🚩🚩🚩 viewport meta tag content attribute was changed.");
                  viewportMetaEl.setAttribute("content", originalViewportMetaContent);
                  window.queuedStatCountKeys.add("viewport-mtc");
                }
              })
            });
            observer.observe(viewportMetaEl, { attributes: true, attributeFilter: ['content'] });
          }
        </script>
        
        <script>
          // 'polyfill' Safari's lack of support for interactive-widget=resizes-content on
          // EDIT: disabled because causes weird scroll jank issues
          // {
          //   let isTouchScreen = window.matchMedia("(pointer: coarse)").matches;
          //   if(isTouchScreen) {
          //     let shouldTriggerResizeBarrage = true;
          //     function handler() {
          //       if(!shouldTriggerResizeBarrage) return;
          //       shouldTriggerResizeBarrage = false;
          //       async function doResize() {
          //         // console.debug("doResize1", window.visualViewport.pageTop, window.visualViewport.height, document.documentElement.offsetHeight)
          //         shouldTriggerResizeBarrage = false; // just to be safe
          //         if(window.visualViewport.pageTop <= 1 && Math.abs(window.visualViewport.height - document.documentElement.offsetHeight) <= 2) return;
          //         console.debug("scrolling/resizing", window.visualViewport.pageTop, window.visualViewport.height, document.documentElement.offsetHeight);
          //         // for whatever reason, this is needed, since otherwise the scrollTo(0,0) doesn't work. Safari sucks.
          //         window.scrollTo(0,1);
          //         document.documentElement.style.height = window.visualViewport.height+"px";
          //         window.scrollTo(0,1);
          //       }
          //       let interval = setInterval(doResize, 100);
          //       doResize();
          //       setTimeout(() => {
          //         clearInterval(interval);
          //         doResize();
          //         setTimeout(() => shouldTriggerResizeBarrage=true, 50);
          //       }, 600);
          //     }
          //     window.addEventListener('scroll', handler);
          //     visualViewport.addEventListener('scroll', handler);
          //     visualViewport.addEventListener('resize', handler);
          //   }
          // }
        </script>

        <script>window.queuedStatCountKeys = new Set();</script>
        <script>window.mdded4sfef4dsedddse1d34344 = `Error: Ad blocker preventing proper page load?`;</script>
        <script>
          window.js0nparse = JSON.parse;
        </script>

        <script>
        // COMPATABILITY TESTING:
        window.canExecuteModernJavascript = true;
        try {

          var str = "";
          str += "\n(async () => { await new Promise(resolve => setTimeout(resolve, 500)); console.debug('async/await is supported'); })();";
          str += "\nlet arr = [1,2,3]; for(let a of arr) { arr[0]+=a; }; console.debug('let a of arr supported');";
          str += "\nvar m = [1,2,3].map(n => n+1);";
          str += "\nvar k = [...[1,2,3]];";
          str += "\nvar a = (function(a=3) { return a+1; })();";

          window.eval(str);

        } catch(e) {
          window.canExecuteModernJavascript = false;
          // var message = "<div style='overflow:hidden;height:0px;'><h1>Create a Random Generator</h1><p>Perhance is a platform that allows you to create your own custom random generators. You could use it to create your own random text generator for a tabletop RPG, or to make your own random name generator, or to simply create a generator which selects a random item from your list with different weights. You can also save your generator so it has a permalink that you can share with your friends.</p><p>Perchance is based around creating lists which reference other lists. You can adjust the odds of items in each list so that when you randomly select an item from that list, they all have the likelihoods that you've specified. If you'd like to learn how to make a random text generator with Perchance, you should check out the tutorial. It explains all the basic features of the Perchance engine and should get you up and running in only 10 or 20 minutes. Perchance has many powerful features that you don't need to learn from the start, but can learn later if you want to create particularly complex generators.</p><p>I created Perchance because most people are still creating random generators in excel. Those work all right, but excel and other spreadsheets aren't really made for that purpose, so there's a lot to be desired in terms of functionality and ease of use. Whatever you're using it for, I hope you find Perchance useful! You might like to check out our <a href='http://reddit.com/r/perchance'>community forum</a> where you can ask questions and share your random generator creations.</p></div>(」゚ロ゚)」 Sorry! Perchance uses cutting edge browser features that are only available in the latest versions of Chrome and Firefox. All modern browsers will eventually be supported, but for now you'll need to use one of those two. Sorry again for the inconvenience!";
          // //window.alert(message);
          // document.body.innerHTML = message;
        }
        </script>


        <div id="generator-description" style="display:none; height:20px; width:20px; z-index:-10; overflow:hidden; position:fixed; bottom:-100px;"><!-- will be filled with description after iframe execution --></div>

        <style>
          .cm-syntax-style1 { color: #f18c16; }
          .cm-syntax-style2 { color: #2795EE; }
          .cm-syntax-style3-comment { color: #A0A1A7; }
        </style>

        <!-- PRELOADED DATA --> 
        <script id="preloaded-generator-data" type="notjs">%7B%22name%22:%22zb67bgo77s%22,%22modelText%22:%22generateHTML%20=%20%7Bimport:t2i-framework-plugin-v2%7D%5Cn%5Cn$meta%5Cn%20%20title%20=%20AI%20P%20GEN%20(nsfw,%2018+,%20realistic,%20uncensored,%20free,%20no%20limits)%20%5Cn%20%20description%20=%20Uncensored%20AI%20P%20Generator%20on%20base%20of%20Stable%20Diffusion.%20This%20AI%20Image%20Generator%20can%20generate%20Explicit,%20NSFW,%2018+%20content!%20It's%20Free!%20No%20sign-up!%20No%20limits!%20No%20watermark!%20Fast%20generation!%20Uncensored!%20(Have%20in%20mind%20that%20this%20AI%20P%20Image%20Generator%20can't%20generate%20content%20with%20illegal%20things/themes,%20and%20will%20never%20be%20able%20to!%20Because%20restrictions%20installed%20directly%20on%20Stable%20Diffusion.)%5Cn%20%20image%20=%20https://files.catbox.moe/u02cyx.jpg%5Cn%5Cn//%20Feel%20free%20to%20edit%20the%20settings%20below%20and%20then%20save%20your%20own%20copy%20of%20this%20generator!%5Cn//%20You'll%20probably%20just%20want%20to%20scroll%20down%20to%20the%20artStyle%20list%20and%20edit%20those%20-%20it's%20pretty%20self-explanatory,%20just%20follow%20the%20format.%5Cn%5Cnsettings%20%5Cn%20%20pageTitle%20=%20%E2%9D%A4%EF%B8%8F%E2%80%8D%F0%9F%94%A5%20AI%20P%20GEN%20%F0%9F%8D%86%F0%9F%92%A6%20%5Cn%20%20introMessage%20=%20Made%20for%20generating%20HighQ%20explicit%20nsfw/18+%20content!%20Add%20a%20description,%20then%20click%20%3Cb%3Egenerate%3C/b%3E.%3Cbr%3E%3Cbr%3E%3Cspan%20style=%5C%22font-size:80%25;%20color:white;%20max-width:400px;%20display:inline-block;%5C%22%3EThis%20generator%20was%20made%20using%20the%20%3Ca%20href=%5C%22https://perchance.org/text-to-image-plugin%5C%22%20target=%5C%22_blank%5C%22%3Etext-to-image%20plugin%3C/a%3E.%3C/span%3E%5Cn%20%20numImages%20=%20%5BNumber(input.numImages)%5D%5Cn%20%20socialFeatures%20=%20disabled%20//%20or%20'button'%20or%20'disabled'%20or%20'enabled'%5Cn%20%20%5Cn%20%20//%20note:%20the%20t2i-framework-plugin%20makes%20all%20user%20inputs%20from%20the%20%60userInputs%60%20list%20accessible%20by%20name%20as%20%5Binput.theNameOfTheInput%5D,%20as%20shown%20here:%5Cn%20%20imageOptions%20//%20%3C--%20options%20for%20the%20text-to-image%20plugin%20that%20generates%20the%20images:%20https://perchance.org/text-to-image-plugin%5Cn%20%20%20%20saveTitle%20=%20(%5Binput.artStyle.getName%5D)%20%5Binput.description%5D%20//%20.getName%20is%20a%20built-in%20Perchance%20property%20that%20gets%20the%20name%20of%20a%20given%20list/sublist/node%5Cn%20%20%20%20prompt%20=%20%5Binput.artStyle.prompt%5D%5Cn%20%20%20%20negativePrompt%20=%20%5Binput.artStyle.negative%5D%5Cn%20%20%20%20resolution%20=%20%5Binput.shape%5D%5Cn%20%20%5Cn%20%20userInputs%20//%20you%20can%20add%20more%20user%20inputs%20to%20this%20list,%20and%20then%20use%20them%20like%20%5Binput.nameOfInput%5D%20in%20the%20%60prompt%60,%20%60negativePrompt%60,%20%60artStyle.prompt%60,%20etc.%5Cn%5Cn%20%20%20%20scratchpad%20//%20Note:%20the%20'remember'%20option%20storage%20is%20'based%20on'%20this%20'scratchpad'%20name,%20so%20if%20you%20change%20that%20name%20to%20something%20else%20like%20'notepad',%20people%20will%20lose%20all%20their%20saved%20scratchpad%20text.%20But%20it's%20safe%20to%20change%20the%20'label',%20below.%5Cn%20%20%20%20%20%20label%20=%20%E2%9C%8D%EF%B8%8F%20Scratchpad%5Cn%20%20%20%20%20%20tip%20=%20Just%20a%20little%20notepad%20for%20you%20-%20doesn't%20affect%20your%20generated%20images.%20It%20'remembers'%20the%20text%20that%20you%20put%20in%20it%20even%20after%20you%20refresh/close%20this%20page.%5C%5Cn%5C%5CnThe%20text%20will%20only%20be%20forgotten%20if%20you%20clear%20your%20browser's%20%5C%22site%20data%5C%22%20(cookies,%20localStorage,%20etc.)%20for%20this%20particular%20site.%5Cn%20%20%20%20%20%20type%20=%20paragraph%5Cn%20%20%20%20%20%20remember%20=%20true%20//%20%3C--%20the%20text%20that%20the%20user%20inputs%20will%20be%20remembered%20so%20it's%20still%20there%20even%20if%20they%20close/refresh%20the%20page%5Cn%20%20%20%20%20%20width%20=%20min(750px,%20100%25)%5Cn%20%20%20%20%20%20height%20=%2030vh%5Cn%20%20%20%20%20%20takesUpFullRow%20=%20true%5Cn%20%20%20%20%20%20foldToggleState%20=%20hidden%20//%20or%20'shown'%20if%20you%20want%20it%20to%20start%20shown,%20or%20delete%20this%20line%20if%20you%20don't%20want%20it%20to%20be%20show-able/hide-able%5Cn%20%20%20%20%20%20visible()%20=%3E%5Cn%20%20%20%20%20%20%20%20return%20Number(localStorage.generateClickCount)%20%3E%201;%20//%20so%20the%20scratchpad%20only%20shows%20up%20after%20they've%20clicked%20generate%20a%20couple%20of%20times%20(to%20reduce%20confusion/clutter%20for%20newbies)%5Cn%20%20%20%20%20%20examples%5Cn%20%20%20%20%20%20%20%20You%20can%20use%20this%20text%20box%20to%20store%20your%20prompts%20and%20other%20notes.%20The%20text%20you%20put%20here%20will%20be%20remembered%20even%20after%20you've%20closed/refreshed%20this%20page%20so%20long%20as%20you're%20not%20in%20in%20incognito%20browsing%20mode.%5C%5Cn%5C%5CnNote:%20If%20you%20clear%20your%20%5C%22site%20data%5C%22/cookies%20for%20this%20site,%20your%20scratchpad%20data%20will%20be%20lost.%5Cn%5Cn%20%20%20%20description%5Cn%20%20%20%20%20%20label%20=%20%F0%9F%93%9D%20Description%20%5Cn%20%20%20%20%20%20tip%20=%20Tip:%20If%20you%20write%20something%20like%20&lcub;blue%7Cred%7Cgreen&rcub;%20as%20part%20of%20your%20description,%20then%20a%20random%20one%20will%20be%20chosen%20for%20each%20image.%5C%5Cn%5C%5CnYou%20can%20see%20the%20prompt%20that%20was%20used%20for%20a%20particular%20generated%20image%20by%20hovering%20your%20mouse%20over%20it,%20or%20long-pressing%20on%20mobile.%5C%5Cn%5C%5CnAdd%20brackets%20around%20text%20(like%20this)%20to%20get%20the%20AI%20to%20pay%20more%20attention%20to%20it.%5Cn%20%20%20%20%20%20type%20=%20paragraph%5Cn%20%20%20%20%20%20width%20=%20min(750px,%20100%25)%5Cn%20%20%20%20%20%20takesUpFullRow%20=%20true%5Cn%20%20%20%20%20%20modifiers%20=%20%5Binput.artStyle?.modifiers%20%7C%7C%20null%5D%5Cn%20%20%20%20%20%20modifierUpdates%20=%20event:description.input,%20event:artStyle.change%5Cn%20%20%20%20%20%20enterKeyTriggersGeneration%20=%20true%20//%20%3C--%20can%20still%20use%20shift+enter%20to%20create%20a%20new%20line%5Cn%20%20%20%20%20%20//%20we%20use%20artstyle-specific%20random%20prompts%20if%20available,%20otherwise%20fall%20back%20to%20randomDescriptions%20list:%5Cn%20%20%20%20%20%20examples%20=%20%5Binput.artStyle?.randomPrompt%20%7C%7C%20randomDescription%5D%20//%20%3C--%20the%20placeholder%20examples%20that%20rotate%20in%20the%20text%20box%5Cn%20%20%20%20%20%20random%20=%20%5Binput.artStyle?.randomPrompt%20%7C%7C%20randomDescription%5D%20//%20%3C--%20added%20to%20the%20text%20box%20when%20the%20'random'%20button%20gets%20clicked%5Cn%5Cn%20%20%20%20negative%5Cn%20%20%20%20%20%20label%20=%20%F0%9F%9A%AB%20Anti-Description%20(optional)%5Cn%20%20%20%20%20%20type%20=%20text%5Cn%20%20%20%20%20%20examples%5Cn%20%20%20%20%20%20%20%20things%20you%20%F0%9D%97%B1%F0%9D%97%BC%F0%9D%97%BB'%F0%9D%98%81%20want%20in%20the%20image%5Cn%5Cn%20%20%20%20artStyle%5Cn%20%20%20%20%20%20label%20=%20%F0%9F%8E%A8%20Art%20Style%5Cn%20%20%20%20%20%20type%20=%20select%5Cn%20%20%20%20%20%20remember%20=%20true%20//%20%3C--%20makes%20it%20so%20the%20selected%20option%20will%20be%20remembered%20even%20if%20the%20user%20refreshes/closes%20the%20page%5Cn%20%20%20%20%20%20options%5Cn%20%20%20%20%20%20%20%20meta:import%5Cn%20%20%20%20%20%20%20%20%20%20from%20=%20%7Bimport:t2i-styles%7D%20//%20%3C--%20imports%20a%20bunch%20of%20'default'%20styles%20(you%20can%20delete%20this,%20or%20put%20it%20at%20the%20end,%20below%20'No%20style'%20if%20you%20want)%5Cn%20%20%20%20%20%20%20%20%20%20tagWeights%20=%20photo:10%20%20//%20%3C--%20boost%20photo%20styles%5Cn%20%20%20%20%20%20%20%20MTG%20Card%20//%20%3C--%20example%20of%20a%20custom%20%5C%22Magic%20The%20Gathering%5C%22%20card%20style%20-%20just%20follow%20this%20format%20and%20add%20as%20many%20of%20them%20as%20you%20want%20to%20this%20'options'%20list%5Cn%20%20%20%20%20%20%20%20%20%20prompt%20=%20%5Binput.description%5D,%20magic%20the%20gathering%20card%5Cn%20%20%20%20%20%20%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20blurry,%20bad%20art%5Cn%20%20%20%20%20%20%20%20%F0%9D%97%A1%F0%9D%97%BC%20%F0%9D%98%80%F0%9D%98%81%F0%9D%98%86%F0%9D%97%B9%F0%9D%97%B2%5Cn%20%20%20%20%20%20%20%20%20%20prompt%20=%20%5Binput.description%5D%5Cn%20%20%20%20%20%20%20%20%20%20negative%20=%20%5Binput.negative%5D%5Cn%20%20%20%20%20%20%20%20%20%20meta:position%20=%205%5Cn%5Cn%20%20%20%20shape%5Cn%20%20%20%20%20%20label%20=%20%F0%9F%96%BC%EF%B8%8F%20Shape%5Cn%20%20%20%20%20%20type%20=%20select%5Cn%20%20%20%20%20%20remember%20=%20true%20//%20%3C--%20the%20selected%20option%20will%20be%20remembered%20even%20if%20the%20user%20refreshes/closes%20the%20page%5Cn%20%20%20%20%20%20options%5Cn%20%20%20%20%20%20%20%20Portrait%20=%20512x768%5Cn%20%20%20%20%20%20%20%20Square%20=%20512x512%5Cn%20%20%20%20%20%20%20%20Landscape%20=%20768x512%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20numImages%5Cn%20%20%20%20%20%20label%20=%20%F0%9F%94%A2%20How%20many?%5Cn%20%20%20%20%20%20type%20=%20select%5Cn%20%20%20%20%20%20remember%20=%20true%20//%20%3C--%20the%20selected%20option%20will%20be%20remembered%20even%20if%20the%20user%20refreshes/closes%20the%20page%5Cn%20%20%20%20%20%20options%5Cn%20%20%20%20%20%20%20%206%20=%206%5Cn%20%20%20%20%20%20%20%203%20=%203%5Cn%20%20%20%20%20%20%20%209%20=%209%5Cn%20%20%20%20%20%20visible()%20=%3E%5Cn%20%20%20%20%20%20%20%20return%20Number(localStorage.generateClickCount)%20%3E%201;%20//%20so%20this%20input%20only%20shows%20up%20after%20they've%20clicked%20generate%20a%20couple%20of%20times%20(to%20reduce%20confusion/clutter%20for%20newbies)%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20defaultCommentOptions%20//%20for%20comments%20plugin:%20https://perchance.org/comments-plugin%5Cn%20%20%20%20width%20=%20100%25%5Cn%20%20%20%20height%20=%20400%5Cn%20%20%20%20commentPlaceholderText%20=%20Type%20a%20friendly%20comment...%5Cn%20%20%20%20submitButtonText%20=%20submit%20comment%5Cn%20%20%20%20bannedUsers%20=%20%5BbannedUsersList%5D%5Cn%20%20%20%20%5Cn%20%20commentChannels%5Cn%20%20%20%20general%5Cn%20%20%20%20%20%20label%20=%20General%5Cn%20%20%20%20chat1%5Cn%20%20%20%20%20%20label%20=%20Room%201%5Cn%20%20%20%20chat2%5Cn%20%20%20%20%20%20label%20=%20Room%202%5Cn%20%20%20%20chat3%5Cn%20%20%20%20%20%20label%20=%20Room%203%5Cn%20%20%20%20prompts%5Cn%20%20%20%20%20%20label%20=%20Prompts%5Cn%20%20%20%20%20%20commentPlaceholderText%20=%20Share%20a%20cool%20prompt/style.%20If%20it's%20good,%20it%20may%20get%20added%20to%20the%20Art%20Style%20selector.%5Cn%20%20%20%20%20%20submitButtonText%20=%20share%20prompt%5Cn%20%20%5Cn%20%20galleryOptions%5Cn%20%20%20%20gallery%20=%20false%5Cn%20%20%20%20sort%20=%20trending%5Cn%20%20%20%20hideIfScoreIsBelow%20=%200%5Cn%20%20%20%20adaptiveHeight%20=%20true%20//%20%3C--%20expand%20gallery%20height%20so%20it%20never%20has%20its%20own%20scrollbar%5Cn%20%20%20%20contentFilter%20=%20pg13%20//%20%3C--%20or%20'none'%20for%20no%20default%20filter%5Cn%20%20%5Cn%20%20showFeedback%20=%20false%20//%20you%20can%20temporarily%20change%20this%20to%20'true'%20and%20then%20click%20the%20feedback%20button%20to%20view%20feedback%5Cn%20%20%20%20%20%20%20%20%5Cn%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%5CnbasePerson%5Cn%20%20hot%20litle%20hussy%5Cn%20%20horn%20girl%20%5Cn%20%20horny%20young%20girl%5Cn%20%20young%20girl%20%5Cn%20%20beautiful%20big%20gigantic%20suckable%20absud%20tits%5Cn%20%20naturally%20beautiful%20woman%5Cn%20%20woman%5Cn%20%20beautiful%20young%20wten%5Cn%20%20naturally%20beautiful%20young%20teen%5Cn%20%20young%20woman%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%5Cn%5CnrandomDescription%5Cn%20%20young%20%7Bgirl%7Cteenie%7D,%20kite,%20%7Bgrassy%7Csandy%7D%20field,%20%7Btriumphant%7Cexcited%7D%20look,%20close-up%5Cn%20%20big%20titty%20gigantic%20curves%20woman,%20%7Bfinger%20bating%7Cpleasuring%20herself%7D,%20%7Brocking%20chair%7Cwindow%20nook%7D,%20gentle%20smile,%20close-up%5Cn%20%20%5BbasePerson%5D,%20cityscape,%20%7Bnight%7Cdusk%7D,%20%7Brooftop%7Cbalcony%7D,%20thoughtful%20gaze,%20close-up%5Cn%20%20%7Bballerina%7Cmartial%20artist%7D,%20backstage,%20focused,%20%7Btying%20shoe%20ribbons%7Cadjusting%20belt%7D,%20close-up%5Cn%20%20%7Bsurfer%7Ckayaker%7D,%20sunset,%20%7Bcatching%20wave%7Criding%20rapids%7D,%20exhilarated%20shout,%20close-up%5Cn%20%20studio%20artist,%20%7Bpaint-stained%20jeans%7Csmudged%20apron%7D,%20%7Bvibrant%7Cmonochrome%7D%20canvas,%20absorbed%20demeanor,%20close-up%5Cn%20%20%5BbasePerson%5D,%20%7Bsnowfall%7Crainfall%7D,%20in%20warm%20coat,%20joyous%20laughter,%20close-up%5Cn%20%20%7Byoung%20pt%20model%7Csuper-childd-model%7D,%20smoke,%20building,%20%7Bbrave%20and%20determined%7Cserious%20and%20focused%7D,%20close-up%5Cn%20%20girl%20in%20a%20%7Bforest%7Cmeadow%7D,%20%7Bautumn%20leaves%7Cspring%20flowers%7D,%20peaceful%20solitude,%20close-up%5Cn%20%20mother,%20%7Bcoffee%20shop%20corner%7Cpark%20bench%7D,%20%7Breading%20newspaper%7Csketching%7D,%20relaxed,%20close-up,%20big%20tits%20peeking%20out%20a%20loose%20tank%20topc%5Cn%20%20%7Bstreet%20performer%7Cmime%7D,%20%7Bjuggling%7Cperforming%7D,%20crowd,%20%7Bdelightful%7Cmischievous%7D%20grin,%20close-up%5Cn%20%20%7Blibrarian%20milf%20alxas%20texas%7Cbookstore%20clerk%7D,%20glasses,%20%7Bhushing%20gesture%7Cflipping%20pages%7D,%20amused%20twinkle%20in%20eye,%20close-up%5Cn%20%20%7Bbartender%7Cvery%20fuckable%20girl%7D,%20%7Bnightclub%7Ccafe%7D,%20%7Bshaking%20cocktail%7Cpouring%20coffee%7D,%20charming%20wink,%20close-up%5Cn%20%20%5BbasePerson%5D%20at%20%7Bairport%7Ctrain%20station%7D,%20suitcase,%20%7Bwaving%20goodbye%7Cexcited%20arrivals%7D,%20emotional,%20close-up%5Cn%20%20mechanic,%20%7Bunder%20a%20car%7Cat%20a%20workbench%7D,%20grease-stained,%20satisfied%20smirk,%20close-up%5Cn%20%20woman%20in%20a%20%7Bflower%20shop%7Cnursery%7D,%20%7Bsmelling%20roses%7Cpotting%20plants%7D,%20blissful%20look,%20close-up%5Cn%20%20%5BbasePerson%5D,%20%7Bboat%7Criverbank%7D,%20%7Bearly%20dawn%7Cquiet%20dusk%7D,%20hopeful,%20close-up%5Cn%20%20college%20%7Bgirl%7Cboy%7D,%20studying,%20%7Bbedroom%7Clibrary%7D,%20late%20night,%20focused,%20close-up%5Cn%20%20mountaineer,%20%7Bsnowy%20peak%7Cverdant%20valley%7D,%20triumphant,%20%7Bagainst%20the%20wind%7Coverlooking%20vista%7D,%20close-up%5Cn%20%20%5BbasePerson%5D,%20%7Bseashore%7Clakeside%7D,%20%7Bcollecting%20shells%7Cskipping%20stones%7D,%20thoughtful,%20close-up%5Cn%20%20%5BbasePerson%5D%20in%20%7Bsuit%7Ccasual%20attire%7D,%20city%20street,%20raining,%20under%20umbrella,%20serious%20look,%20close-up%5Cn%20%20%7Blittle%20girl%7Clittle%20sweet%20honey%20of%20a%20%20girl%7D,%20park,%20%7Bfeeding%20pigeons%7Cchasing%20butterflies%7D,%20giggling,%20close-up%5Cn%20%20martial%20artist,%20%7Bdojo%7Copen%20arena%7D,%20%7Bpracticing%20moves%7Cin%20a%20stance%7D,%20fierce%20determination,%20close-up%5Cn%20%20hiker,%20%5BbasePerson%5D,%20%7Bmountain%7Cforest%7D,%20%7Bsunset%7Csunrise%7D,%20close-up%5Cn%20%20%5BbasePerson%5D,%20cooking,%20satisfied,%20close-up%5Cn%20%20%5BbasePerson%5D,%20on%20a%20%7Bbike%7Cscooter%7D,%20country%20road,%20wind%20in%20hair,%20laughing,%20close-up%5Cn%20%20astronomer,%20%7Btelescope%7Cobservatory%7D,%20%7Bnight%20sky%7Cstar%20chart%7D,%20captivated,%20close-up%5Cn%20%20farm%20%7Bgirl%7Cboy%7D,%20%7Banimals%7Cfields%7D,%20sunrise,%20contented,%20close-up%5Cn%20%20%7Bman%7Cwoman%7D,%20at%20a%20concert,%20%7Bplaying%20guitar%7Csinging%7D,%20ecstatic,%20close-up%5Cn%20%20%7Bbeautiful%20%7C%7Dwoman,%20in%20an%20%7Bold%20library%7Cantique%20shop%7D,%20%7Bfascinated%20by%20ancient%20book%7Cadmiring%20vintage%20items%7D,%20close-up%5Cn%20%20girl%20getting%20dick,%20%7Bcity%20street%7Crural%20patrol%7D,%20%7Bkeeping%20watch%7Con%20duty%7D,%20alert,%20close-up%5Cn%20%20%5BbasePerson%5D,%20in%20the%20%7Bgarden%7Corchard%7D,%20%7Bpruning%20roses%7Cpicking%20apples%7D,%20humming,%20close-up%5Cn%20%20%5BbasePerson%5D,%20in%20a%20boxing%20ring,%20%7Bvictory%20pose%7Ctraining%20mode%7D,%20crowd%20roaring,%20close-up%5Cn%20%20%7Bballroom%20dancer%7Cice%20skater%7D,%20in%20a%20%7Bgown%7Cleotard%7D,%20poised%20%7Belegantly%7Cdefiantly%7D,%20radiant%20smile,%20close-up%5Cn%20%20man,%20in%20a%20%7Bbakery%7Cpizzeria%7D,%20%7Bkneading%20dough%7Cspinning%20pizza%7D,%20fulfilled,%20close-up%5Cn%20%20%7Bgirl%7Cboy%7D,%20%7Btreehouse%7Cfort%7D,%20%7Breading%20a%20book%7Cobserving%20nature%7D,%20dreamy%20expression,%20close-up%5Cn%20%20skateboarder,%20at%20a%20%7Bpark%7Cskate%20ramp%7D,%20mid-air%20trick,%20concentrated,%20close-up%5Cn%20%20%7Bwoman%7Cman%7D,%20painting,%20easel,%20%7Bsunset%7Cstill%20life%7D,%20content,%20close-up%5Cn%20%20%7Bteacher%7Cprofessor%7D,%20%7Bchalkboard%7Cprojection%20screen%7D,%20explaining,%20engaged,%20close-up%5Cn%20%20woman,%20at%20a%20%7Bmarket%7Cgrocery%20store%7D,%20%7Bchoosing%20fruits%7Cselecting%20produce%7D,%20sunny%20smile,%20close-up%5Cn%20%20man,%20at%20a%20%7Bzoo%7Csafari%7D,%20%7Bfeeding%20giraffe%7Cwatching%20elephants%7D,%20laughing,%20close-up%5Cn%20%20girl%20at%20a%20%7Bplayground%7Cpark%7D,%20on%20swings,%20%7Bskyward%7Cforward%7D,%20joyous,%20close-up%5Cn%20%20%7Bdj%7Cmusician%7D,%20%7Bmixing%7Cperforming%7D,%20at%20a%20club,%20crowd,%20excited,%20close-up%5Cn%20%20tween,%20in%20a%20%7Byoga%20pose%7Ctai%20chi%20stance%7D,%20%7Bpeaceful%20garden%7Czen%20studio%7D,%20serene,%20close-up%5Cn%20%20chef,%20at%20a%20%7Bfood%20truck%7Cdiner%7D,%20serving%20%7Btacos%7Cburgers%7D,%20friendly%20wink,%20close-up%5Cn%20%20%7Bgirl%7Ctween%7D,%20in%20a%20%7Bsnowy%20landscape%7Crainy%20city%7D,%20%7Bcatching%20snowflakes%7Cjumping%20in%20puddles%7D,%20amused,%20close-up%5Cn%20%20sailor,%20in%20a%20%7Bboat%7Cdock%7D,%20%7Bsea%7Clake%7D,%20%7Bstormy%20weather%7Ccalm%20waters%7D,%20determined,%20close-up%5Cn%20%20woman,%20at%20a%20%7Bvineyard%7Cbrewery%7D,%20%7Btasting%20wine%7Csampling%20beer%7D,%20indulgent%20smile,%20close-up%5Cn%20%20%7Bman%7Cwoman%7D,%20hiking,%20%7Bforest%7Cdesert%7Cmountain%7D,%20close-up%5Cn%20%20girl,%20at%20a%20%7Bmusic%20store%7Ccomic%20shop%7D,%20%7Bflipping%20through%20vinyl%20records%7Cbrowsing%20graphic%20novels%7D,%20nostalgic,%20close-up%5Cn%20%20%7Byk%20girl%7Cwoman%7D,%20in%20a%20lab,%20%7Bmicroscope%7Ctest%20tubes%7D,%20%7Bdiscovery%7Cexperiment%7D,%20astonished,%20close-up%5Cn%20%20%7Bbeautiful%20%7C%7Dwoman,%20at%20a%20%7Bcafe%7Cco-working%20space%7D,%20%7Blaptop%7Cnotepad%7D,%20deep%20in%20work,%20focused,%20close-up%5Cn%20%20soldroklo%2044%20female%20ultra%20horny,%20in%20%7Buniform%7Ccamouflage%7D,%20%7Bsaluting%7Cat%20attention%7D,%20proud,%20close-up%5Cn%20%20%7Bbeautiful%20%7C%7Dwoman,%20in%20a%20%7Bgreenhouse%7Cbotanical%20garden%7D,%20%7Bsurrounded%20by%20plants%7Cstudying%20foliage%7D,%20peaceful,%20close-up%5Cn%20%20man,%20at%20a%20%7Bpottery%20wheel%7Cloom%7D,%20%7Bmolding%20clay%7Cweaving%20fabric%7D,%20concentrated,%20close-up%5Cn%20%20%7Bgirl%7Cboy%7D,%20at%20a%20%7Brooftop%7Cpenthouse%7D,%20%7Blooking%20at%20stars%7Cwatching%20the%20city%7D,%20thoughtful,%20close-up%5Cn%20%20%7Bman%7Cwoman%7D,%20in%20a%20tattoo%20parlor,%20%7Bgetting%20inked%7Cchoosing%20designs%7D,%20excited,%20close-up%5Cn%20%20woman,%20at%20a%20%7Bbasketball%20game%7Csoccer%20match%7D,%20cheering,%20exuberant,%20close-up%5Cn%20%20%7Btailor%7Cdressmaker%7D,%20%7Bfitting%20a%20suit%7Cadjusting%20a%20dress%7D,%20%7Bmeasuring%20tape%7Cpins%7D,%20focused,%20close-up%5Cn%20%20%7Bbeautiful%20%7C%7Dwoman,%20at%20a%20%7Blake%7Cpond%7D,%20%7Bskipping%20stones%7Crowing%20a%20boat%7D,%20playful%20grin,%20close-up%5Cn%20%20hawaiian%20%7Bwoman%7Cman%7D,%20%7Bbeach%7Cgarden%7D%20selfie,%20%7Bflower%20crown%7Cleis%7D,%20%7Bsmiling%7Cgoofy%7D%20expression%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7D%7Bnorwegian%7Cswedish%7D%20college%20girl,%20selfie%20on%20the%20couch,%20%7Bbraided%20hair%7Cponytail%7D,%20puckered%20lips%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7Dindian%20%7Bman%7Cwoman%7D,%20%7Bstudy%7Chome%20office%7D%20selfie,%20%7Bspectacles%7Cheadphones%7D,%20amused%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7D%7Bjapanese%7Ckorean%7D%20%7Bman%7Cwoman%7D,%20%7Bbathroom%7Cbedroom%7D%20selfie,%20%7Bcasual%20wear%7Cpajamas%7D,%20dimpled%20grin%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7Dafrican%20%7Bwoman%7Cman%7D,%20%7Bbalcony%7Cterrace%7D%20full-body%20selfie,%20%7Bsundress%7Cshorts%7D,%20%7Bbarefoot%7Csandaled%7D%20with%20a%20%7Blaid-back%7Ccheery%7D%20smile%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7D%7Bpolish%7Cukrainian%7D%20girl,%20%7Bbedroom%7Cliving%20room%7D%20mirror%20selfie,%20%7Btracksuit%7Cleisure%20wear%7D,%20%7Btied%20up%20hair%7Ccap%7D,%20%7Bcasual%7Crelaxed%7D%20look%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7D%7Bmexican%7Cspanish%7D%20%7Bman%7Cwoman%7D,%20%7Bcouch%7Cgarden%7D%20selfie,%20%7Bbook%7Ccoffee%7D%20in%20hand,%20%7Bglasses%7Cbeanie%7D,%20%7Bcontent%7Cabsorbed%7D%20expression%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7Dchinese%20%7Bwoman%7Cman%7D,%20%7Bkitchen%7Cdining%20room%7D%20selfie,%20%7Bapron%7Cchef%E2%80%99s%20hat%7D,%20%7Bcooking%7Cbaking%7D,%20%7Bpleased%7Cexcited%7D%20grin%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7D%7Bitalian%7Cfrench%7D%20%7Bwoman%7Cman%7D,%20%7Bbedroom%7Chome%20studio%7D%20mirror%20selfie,%20%7Bpaint-stained%20jeans%7Csmudged%20shirt%7D,%20%7Bbrush%7Cpalette%7D%20in%20hand,%20%7Bcreative%7Cinspired%7D%20look%5Cn%20%20%7Bbeautiful%20%7Ccute%20%7C%7D%7Bcanadian%7Camerican%7D%20%7Bman%7Cwoman%7D,%20%7Bbackyard%7Cfront%20porch%7D%20full-body%20selfie,%20%7Bplaid%20shirt%7Cdenim%20jacket%7D,%20%7Bbaseball%20cap%7Csunglasses%7D,%20%7Bgrinning%7Cwinking%7D%20expression%5Cn%20%20%7Bmountain%7CMediterranean%7D%20vista,%20%7Bsunrise%7Csunset%7D,%20%7Bforested%7Cclear%7D%20landscape,%20%7Bmisty%7Cclear%7D%20view%5Cn%20%20cityscape,%20%7Bnight%7Cdawn%7D,%20%7Bskyscrapers%7Chistoric%20buildings%7D,%20%7Bglistening%7Csoft%7D%20lights%5Cn%20%20%7Bsafari%7Cgrassland%7D,%20%7Blion%7Celephant%7D,%20%7Bprowling%7Cgrazing%7D,%20%7Bhot%20midday%7Ccool%20dusk%7D%5Cn%20%20%7Bbeach%7Ccliff%7D%20scene,%20crashing%20%7Bwaves%7Cwaterfall%7D,%20%7Bseagulls%7Ceagles%7D%20soaring,%20%7Bsunny%7Covercast%7D%20day%5Cn%20%20close-up,%20%7Bbutterfly%7Cdragonfly%7D,%20%7Bflower%7Cleaf%7D,%20%7Bbright%7Csoftly%20lit%7D,%20detailed%20texture%5Cn%20%20%7Bforest%7Cjungle%7D%20scene,%20%7Bdeer%7Cmonkey%7D%20in%20distance,%20%7Bdense%20foliage%7Cvast%20clearing%7D,%20%7Bmorning%7Cevening%7D%20light%5Cn%20%20%7Bdesert%7Cplain%7D,%20%7Bcamel%7Cbuffalo%7D%20silhouette,%20%7Bsand%20dunes%7Cgrass%20fields%7D,%20%7Bsunset%7Csunrise%7D,%20%7Bclear%7Cstarry%7D%20sky%5Cn%20%20%7Bcoral%20reef%7Cpond%7D,%20%7Bturtle%7Ckoi%20fish%7D,%20swirling%20%7Bcolors%7Cshades%7D,%20%7Bclear%7Cmurky%7D%20water%5Cn%20%20%7Bpolar%7Cmountain%7D%20landscape,%20%7Bpenguin%7Cgoat%7D%20on%20%7Biceberg%7Crocky%20outcrop%7D,%20%7Bblizzard%7Cclear%20skies%7D,%20%7Bfrozen%7Ccrisp%7D%20atmosphere%5Cn%20%20close-up,%20%7Bbee%7Chummingbird%7D,%20%7Bnectar%7Cblossom%7D,%20%7Bspringtime%7Csummertime%7D,%20vibrant%20%7Bcolors%7Chues%7D%5Cn%5Cn%5Cn%5Cn%5Cn%5CnbannedUsersList%5Cn%20%20put%5Cn%20%20user%5Cn%20%20ids%5Cn%20%20here%5Cn%20%20to%5Cn%20%20ban%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%22,%22outputTemplate%22:%22%5BgenerateHTML(settings)%5D%22,%22imports%22:%5B%22t2i-framework-plugin-v2%22,%22t2i-styles%22%5D,%22canLink%22:true,%22isPrivate%22:true%7D</script>
        <script id="imported-generators" type="notjs">%5B%7B%22name%22:%22t2i-framework-plugin-v2%22,%22modelText%22:%22//%20overall,%20this%20version%20(v2)%20moves%20toward%20the%20approach%20of%20constructing%20prompts%20within%20the%20artStyle%20list,%20such%20that%20you%20can%20e.g.%20place%20user%20inputs%20within%20a%20prompt%20multiple%20times,%20and%20have%20prompt%20construction%20completely%20depend%20on%20the%20art%20style%5Cn%5Cn//%20NOTE:%20the%20notes%20below%20are%20old/outdated.%20lots%20of%20other%20changes%20that%20aren't%20listed%20here.%5Cn%5Cn//%20changes%20(note%20that%20some%20of%20the%20non-breaking%20ones%20were%20back-ported%20to%20v1):%5Cn//%20%20-%20%5Bbreaking%5D%20all%20userInputs%20are%20now%20under%20a%20single%20%60input%60%20global%20variable%20-%20so%20%5Binput.description%5D%20instead%20of%20polluting%20global%20namespace%20with%20%5Bdescription%5D%5Cn//%20%20-%20%5Bbreaking%5D%20no%20more%20_optionName%20for%20%3Cselect%3E%20inputs%20-%20use%20%5Binput.artStyle.getName%5D%20instead%20of%20%5BartStyle_optionName%5D%5Cn//%20%20-%20%5Bbreaking%5D%20no%20more%20'append'/'prepend'%20options%20-%20not%20necessary%20now%20that%20we%20move%20to%20constructing%20prompts%20within%20the%20artStyle%20list%5Cn//%20%20-%20%60remember=true%60%20for%20user%20input%20specs,%20which%20remembers%20values%20even%20after%20page%20reload%5Cn//%20%20-%20multiple%20chat%20channels%5Cn//%20%20-%20html%20select/input%20element%20value%20is%20exposed%20on%20on%20the%20settings.userInputs.foo%20object%5Cn//%20%20-%20%60takesUpFullRow=true%60%20to%20make%20an%20input%20take%20up%20a%20full%20row%5Cn//%20%20-%20%60visible%60%20function%20property%20for%20each%20user%20input%20which%20is%20called%20after%20every%20input%20event%20and%20'generate'%20button%20click%20to%20determine%20whether%20that%20input%20should%20be%20visible%5Cn//%20%20-%20%60localStorage.generateClickCount%60%20tracks%20how%20many%20times%20the%20user%20has%20clicked%20the%20generate%20button%20%5Cn//%20%20-%20a%20lot%20of%20other%20stuff%5Cn%5Cn//%20todo,%20maybe:%5Cn//%20%20-%20%60autoSuggest=true%60%20for%20a%20text%20area%20input%20to%20get%20AI-generated%20completions%20a%20full%20prompt%20suggestions/ideas%20based%20on%20what%20the%20user%20has%20typed%20so%20far%5Cn//%20%20-%20new%20'visual'%20mode%20for%20select%20type%20-%20just%20add%20_image%20sub%20property%20(with%20url)%20to%20your%20options.%20for%20the%20artStyle%20list,%20each%20image%20could%20be%20a%20row%20of%20several%20images%20made%20with%20that%20style%5Cn//%20%20-%20add%20onChange,%20onInput,%20etc.%20to%20the%20user%20input%20objects/nodes%20-%20this%20allows%20e.g.%20changing%20a%20%3Cselect%3E%20option%20based%20on%20what%20the%20user%20types%20into%20an%20%3Cinput%3E%20option%5Cn%5Cn//%20notes:%5Cn//%20%20-%20default%20styles:%20https://perchance.org/t2i-styles#edit%5Cn//%20%20-%20image%20grid%20maker:%20https://perchance.org/image-grid-maker#edit%5Cn//%20%20%5Cn%5CntextToImagePlugin%20=%20%7Bimport:text-to-image-plugin%7D%5CncommentsPlugin%20=%20%7Bimport:comments-plugin%7D%5CnselectLeaf%20=%20%7Bimport:select-leaf-plugin%7D%5CnfullscreenButton%20=%20%7Bimport:fullscreen-button-plugin%7D%5CnaiText%20=%20%7Bimport:ai-text-plugin%7D%5Cnupload%20=%20%7Bimport:upload-plugin%7D%5Cnprompt2%20=%20%7Bimport:prompt2-plugin%7D%5Cnt2iStyles%20=%20%7Bimport:t2i-styles%7D%20//%20this%20wasn't%20originally%20an%20%5C%22official%5C%22%20part%20of%20this%20framework,%20but%20it%20is%20now%20because%20i'm%20using%20it%20for%20the%20character%20chat%20feature%20under%20the%20condition%20that%20there's%20an%20artStyle%20user%20input%20specified%5CntabbedCommentsPlugin%20=%20%7Bimport:tabbed-comments-plugin-v1%7D%5Cn%5Cn//%20This%20$output%20function%20simply%20takes%20a%20%60settings%60%20list/hierarchy%20as%20an%20input,%20and%20returns%20the%20full%20HTML%20for%20the%20page%5Cn%5Cn$output(settings)%20=%3E%5Cn%20%20if(!window.input)%20window.input%20=%20%7B%7D;%5Cn%20%20if(!window.t2i)%20%7B%5Cn%20%20%20%20window.t2i%20=%20%7B%7D;%5Cn%20%20%20%20window.t2i.defaultText%20=%20%7B%5Cn%20%20%20%20%20%20promptTip:%20%60Tip:%20You%20can%20write%20text%20like%20&lcub;blue%7Cred%7Cgreen&rcub;%20and%20a%20random%20one%20will%20be%20chosen%20for%20each%20image.%5C%5Cn%5C%5CnClick%20the%20info%20icon%20on%20an%20image%20to%20see%20the%20prompt%20that%20was%20used.%5C%5Cn%5C%5CnAdd%20brackets%20around%20text%20(like%20this)%20or%20((even%20more))%20to%20get%20the%20AI%20to%20pay%20more%20attention%20to%20it.%60,%5Cn%20%20%20%20%20%20negativePromptTip:%20%60Important:%20If,%20for%20example,%20you%20don't%20want%20the%20image%20to%20have%20blue%20in%20it,%20just%20write%20%5C%22blue%5C%22%20in%20this%20box.%20Don't%20write%20%5C%22no%20blue%5C%22!%20In%20other%20words,%20you%20should%20write%20a%20description%20of%20a%20hypothetical%20%5C%22opposite%20image%5C%22%20of%20what%20you%20want.%60,%5Cn%20%20%20%20%20%20scratchpadTip:%20%60A%20little%20notepad%20for%20you%20to%20keep%20good%20prompts%20and%20stuff.%20It%20'remembers'%20the%20text%20that%20you%20put%20in%20it%20even%20after%20you%20refresh/close%20this%20page.%5C%5Cn%5C%5CnThe%20text%20will%20only%20be%20forgotten%20if%20you%20clear%20your%20browser's%20%5C%22site%20data%5C%22%20(cookies,%20localStorage,%20etc.)%20for%20perchance.org%60,%5Cn%20%20%20%20%20%20scratchpadPlaceholder:%20%60Use%20this%20box%20to%20store%20prompts%20and%20notes.%20They'll%20be%20remembered%20even%20if%20you%20refresh%20this%20page%20(unless%20you%20are%20in%20private%20browsing%20mode).%20Also,%20you%20can%20write:%5C%5Cn%5C%5CnANIMAL%20=%20&lcub;dog%7Cmouse%7Cfrog&rcub;%5C%5Cn%5C%5Cnin%20this%20box,%20and%20then%20write%20'&lsqb;ANIMAL&rsqb;'%20within%20your%20description%20(including%20the%20square%20brackets)%20to%20get%20a%20random%20one%20of%20those%20animals%20for%20each%20generated%20image.%20And%20you%20can%20replace%20the%20%F0%9F%8E%B2%20button's%20outputs%20by%20adding%20a%20DESCRIPTION%20line%20to%20this%20text%20box,%20like%20this:%5C%5Cn%5C%5CnDESCRIPTION%20=%20a%20very%20&lcub;silly%7Ccurious&rcub;%20&lsqb;ANIMAL&rsqb;%60,%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20window.t2i.handyText%20=%20window.t2i.defaultText;%20//%20'handyText'%20was%20the%20old%20name%5Cn%20%20%7D%5Cn%5Cn%20%20//%20Add%20some%20default%20settings%20(it's%20okay%20to%20write%20directly%20to%20the%20input%20parameter,%20because%20it's%20only%20used%20once%20-%20i.e.%20this%20function%20is%20only%20called%20once)%5Cn%20%20if(!settings.imageOptions.style)%20%7B%5Cn%20%20%20%20settings.imageOptions.style%20=%20%5C%22border-radius:3px;%5C%22;%5Cn%20%20%7D%5Cn%5Cn%20%20//%20We%20need%20to%20make%20these%20global%20since%20we%20wnat%20to%20reference%20them%20from%20the%20HTML%20of%20the%20*importing*%20generator%20(e.g.%20in%20click%20handlers,%20etc.)%5Cn%20%20window.___textToImagePlugin746291937%20=%20textToImagePlugin;%5Cn%20%20window.___commentsPlugin746291937%20=%20commentsPlugin;%5Cn%20%20window.___userSettings746291937%20=%20settings;%5Cn%20%20window.___fullscreenButton893479%20=%20fullscreenButton;%5Cn%5Cn//%20%20%20let%20appState;%5Cn//%20%20%20try%20%7B%5Cn//%20%20%20%20%20appState%20=%20JSON.parse(localStorage.appState_nif983gh4tkshdf79834hi);%5Cn//%20%20%20%7D%20catch(e)%20%7B%5Cn//%20%20%20%20%20appState%20=%20%7B%7D;%5Cn//%20%20%20%7D%5Cn%20%20%5Cn//%20%20%20function%20saveAppState()%20%7B%5Cn//%20%20%20%20%20localStorage.appState_nif983gh4tkshdf79834hi%20=%20JSON.stringify(appState);%5Cn//%20%20%20%7D%5Cn%5Cn%5Cn%20%20if(!window.alreadyAddedT2IStuff83927492374)%20%7B%20//%20this%20$output%20function%20will%20only%20get%20called%20once,%20*except*%20when%20author%20is%20editing%20their%20generator,%20so%20this%20if%20statement/wrapper%20thing%20is%20just%20to%20prevent%20weird%20stuff%20for%20generator%20authors%5Cn%20%20%20%20//%20hide%20some%20clutter%20when%20in%20fullscreen:%5Cn%20%20%20%20document.addEventListener(%5C%22fullscreenchange%5C%22,%20function(e)%20%7B%5Cn%20%20%20%20%20%20let%20fbBtn%20=%20feedbackBtn893745ykfuhd;%5Cn%20%20%20%20%20%20let%20dmBtn%20=%20darkModeBtn_875979f948;%5Cn%20%20%20%20%20%20if(document.fullscreenElement)%20%7B%5Cn%20%20%20%20%20%20%20%20//%20we%20just%20entered%20fullscreen%5Cn%20%20%20%20%20%20%20%20dmBtn.dataset.preFullscreenDisplayValue%20=%20dmBtn.style.display;%5Cn%20%20%20%20%20%20%20%20dmBtn.dataset.duringFullscreenDisplayValue%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20dmBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20fbBtn.dataset.preFullscreenDisplayValue%20=%20fbBtn.style.display;%5Cn%20%20%20%20%20%20%20%20fbBtn.dataset.duringFullscreenDisplayValue%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20fbBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20//%20we%20just%20exited%20fullscreen,%20so%20we%20revert%20the%20display%20values%20*if*%20they're%20the%20same%20as%20what%20we%20set%20them%20to%20when%20we%20entered%20fullscreen%20(so%20we%20don't%20interfere%20with%20other%20code%20that%20may%20have%20since%20changed%20the%20display%20values)%5Cn%20%20%20%20%20%20%20%20if(dmBtn.style.display%20===%20dmBtn.dataset.duringFullscreenDisplayValue)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20dmBtn.style.display%20=%20dmBtn.dataset.preFullscreenDisplayValue;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20delete%20dmBtn.dataset.preFullscreenDisplayValue;%5Cn%20%20%20%20%20%20%20%20delete%20dmBtn.dataset.duringFullscreenDisplayValue;%5Cn%20%20%20%20%20%20%20%20if(fbBtn.style.display%20===%20fbBtn.dataset.duringFullscreenDisplayValue)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20fbBtn.style.display%20=%20fbBtn.dataset.preFullscreenDisplayValue;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20delete%20fbBtn.dataset.preFullscreenDisplayValue;%5Cn%20%20%20%20%20%20%20%20delete%20fbBtn.dataset.duringFullscreenDisplayValue;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20window.alreadyAddedT2IStuff83927492374%20=%20true;%5Cn%20%20%7D%5Cn%5Cn%20%20window.__createSelectorModal_56974639274%20=%20async%20function(options)%20%7B%20//%20use%20it%20like%20this:%20await%20createSelectorModal(%5B%7Bhtml:%5C%22foo%5C%22,%20value:%5C%22foo%5C%22%7D,%20%7Bhtml:%5C%22bar%5C%22,%20value:%5C%22bar%5C%22%7D%5D)%5Cn%20%20%20%20let%20resolve;%5Cn%20%20%20%20let%20promise%20=%20new%20Promise(r%20=%3E%20resolve%20=%20r);%5Cn%5Cn%20%20%20%20let%20ctn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20let%20modal%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20ctn.style.cssText%20=%20%60position:fixed;%20top:0;%20left:0;%20width:100%25;%20height:100%25;%20background:rgba(0,0,0,0.3);%20backdrop-filter:%20blur(5px);%20display:flex;%20align-items:center;%20justify-content:center;%60;%5Cn%20%20%20%20modal.style.cssText%20=%20%60max-width:900px;%20width:95%25;%20max-height:95%25;%20background:var(--box-color);%20box-shadow:0%200%2010px%20rgba(0,0,0,0.5);%20overflow:auto;%60;%5Cn%5Cn%20%20%20%20options.forEach(opt%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20item%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20item.innerHTML%20=%20opt.html;%5Cn%20%20%20%20%20%20item.style.cssText%20=%20%60margin:0.5rem;%20border:3px%20solid%20$%7Bopt.selected%20?%20%5C%22#565656%5C%22%20:%20%5C%22rgba(0,0,0,0)%5C%22%7D;%20cursor:pointer;%60;%5Cn%20%20%20%20%20%20if(!opt.disabled)%20%7B%5Cn%20%20%20%20%20%20%20%20item.onmouseover%20=%20()%20=%3E%20item.style.border%20=%20%5C%223px%20dashed%20#8a8a8a%5C%22;%5Cn%20%20%20%20%20%20%20%20item.onmouseout%20=%20()%20=%3E%20item.style.border%20=%20opt.selected%20?%20%5C%223px%20solid%20#565656%5C%22%20:%20%5C%223px%20solid%20rgba(0,0,0,0)%5C%22;%5Cn%20%20%20%20%20%20%20%20item.onclick%20=%20()%20=%3E%20resolve(opt.value);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20modal.appendChild(item);%5Cn%20%20%20%20%7D);%5Cn%5Cn%20%20%20%20ctn.onclick%20=%20(e)%20=%3E%20%7B%5Cn%20%20%20%20%20%20if(e.target%20===%20ctn)%20resolve(null);%20//%20returns%20null%20if%20the%20user%20didn't%20select%20an%20option%20(i.e.%20they%20clicked%20somewhere%20outside%20the%20popup)%5Cn%20%20%20%20%7D;%5Cn%5Cn%20%20%20%20ctn.appendChild(modal);%5Cn%20%20%20%20document.body.append(ctn);%5Cn%5Cn%20%20%20%20let%20value%20=%20await%20promise;%5Cn%20%20%20%20ctn.remove();%5Cn%20%20%20%20return%20value;%5Cn%20%20%7D%5Cn%5Cn%20%20function%20saveRememberedInput(inputName,%20inputValue)%20%7B%5Cn%20%20%20%20localStorage%5B%60rememberedInput_P9hkcjnv92hfO2bf9hiu_$%7BinputName%7D%60%5D%20=%20inputValue;%5Cn%20%20%7D%5Cn%20%20function%20getRememberedInput(inputName)%20%7B%5Cn%20%20%20%20return%20localStorage%5B%60rememberedInput_P9hkcjnv92hfO2bf9hiu_$%7BinputName%7D%60%5D;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20updateInputVisibilities()%20%7B%5Cn%20%20%20%20let%20userInputs%20=%20window.___userSettings746291937.userInputs;%5Cn%20%20%20%20for(let%20name%20of%20userInputs.getChildNames)%20%7B%5Cn%20%20%20%20%20%20if(userInputs%5Bname%5D.visible%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20userInputs%5Bname%5D._element.closest('.input-ctn').style.display%20=%20userInputs%5Bname%5D.visible()%20?%20%5C%22%5C%22%20:%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20/////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20handler%20for%20%3Cselect%3E%20element%20changes%20%20%20%20//%5Cn%20%20/////////////////////////////////////////////////%5Cn%20%20window.___selectElChangeEvent746291937%20=%20function(event)%20%7B%5Cn%20%20%20%20let%20userInputSpec%20=%20window.___userSettings746291937.userInputs%5Bthis.dataset.name%5D;%20%20%20%20%5Cn%20%20%20%20let%20optionsList%20=%20userInputSpec.compiledOptions;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20displayName;%5Cn%20%20%20%20if(this.value.startsWith(%5C%22ref:optionKeyName:%5C%22))%20%7B%5Cn%20%20%20%20%20%20//%20this%20option%20wasn't%20just%20a%20simple%20key=value,%20it%20was%20a%20node%20with%20child%20properties,%20so%20we%20expose%20the%20whole%20option%20object/node%20as%20a%20global%20variable%20called%20%60this.dataset.name%60%20%5Cn%20%20%20%20%20%20let%20key%20=%20this.value.split(%5C%22:%5C%22)%5B2%5D;%5Cn%20%20%20%20%20%20window.input%5Bthis.dataset.name%5D%20=%20optionsList%5Bkey%5D;%5Cn%20%20%20%20%20%20userInputSpec.value%20=%20optionsList%5Bkey%5D;%5Cn%20%20%20%20%20%20displayName%20=%20key;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20window.input%5Bthis.dataset.name%5D%20=%20this.value;%5Cn%20%20%20%20%20%20userInputSpec.value%20=%20this.value;%5Cn%20%20%20%20%20%20displayName%20=%20this.value;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20let%20visualSelectBtn%20=%20this.parentElement.querySelector(%5C%22.visual-select-btn%5C%22);%5Cn%20%20%20%20if(visualSelectBtn)%20%7B%5Cn%20%20%20%20%20%20visualSelectBtn.textContent%20=%20displayName;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(!event._isInitCall)%20%7B%5Cn%20%20%20%20%20%20if(userInputSpec.remember)%20%7B%5Cn%20%20%20%20%20%20%20%20saveRememberedInput(this.dataset.name,%20this.value);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(!event._isInitCall)%20%7B%5Cn%20%20%20%20%20%20updateInputVisibilities();%5Cn%20%20%20%20%7D%5Cn%20%20%7D;%5Cn%20%20%5Cn%20%20////////////////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20handler%20for%20%3Cinput%3E/%3Ctextarea%3E%20element%20changes%20%20%20%20%20//%5Cn%20%20////////////////////////////////////////////////////////////%5Cn%20%20let%20parseVariablesRateLimitTimeout%20=%20null;%5Cn%20%20let%20allPreviouslyParsedVariableNames%20=%20new%20Set();%5Cn%20%20function%20parseAllVariables()%20%7B%5Cn%20%20%20%20let%20variableSourceTextareas%20=%20Object.values(window.___userSettings746291937.userInputs).filter(o%20=%3E%20o.parseVariables%20&&%20o._element.tagName.toLowerCase()%20===%20%5C%22textarea%5C%22).map(o%20=%3E%20o._element);%5Cn%20%20%20%20for(let%20name%20of%20allPreviouslyParsedVariableNames)%20%7B%5Cn%20%20%20%20%20%20delete%20window%5Bname%5D;%20//%20clear%20old%20variables%20first%20(if%20they%20e.g.%20delete%20their%20scratchpad%20text,%20the%20variables%20should%20go%20away)%5Cn%20%20%20%20%7D%5Cn%20%20%20%20allPreviouslyParsedVariableNames.clear();%5Cn%20%20%20%20for(let%20el%20of%20variableSourceTextareas)%20%7B%5Cn%20%20%20%20%20%20let%20varLines%20=%20el.value.split(%5C%22%5C%5Cn%5C%22).filter(line%20=%3E%20/%5E%5BA-Z0-9_%5D+?%20*=.+$/.test(line));%5Cn%20%20%20%20%20%20for(let%20line%20of%20varLines)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20name%20=%20line.split(%5C%22=%5C%22)%5B0%5D.trim();%5Cn%20%20%20%20%20%20%20%20let%20value%20=%20line.split(%5C%22=%5C%22).slice(1).join(%5C%22=%5C%22);%5Cn%20%20%20%20%20%20%20%20window%5Bname%5D%20=%20value.trim();%5Cn%20%20%20%20%20%20%20%20allPreviouslyParsedVariableNames.add(name);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20window.___inputElInputEvent746291937%20=%20function(event)%20%7B%5Cn%20%20%20%20let%20userInputSpec%20=%20window.___userSettings746291937.userInputs%5Bthis.dataset.name%5D;%20%5Cn%20%20%20%20%5Cn%20%20%20%20let%20value%20=%20this.value;%5Cn%20%20%20%20%5Cn%20%20%20%20if(value%20===%20%5C%22%5C%22%20&&%20userInputSpec.defaultValue%20!==%20undefined)%20value%20=%20userInputSpec.defaultValue;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20if(userInputSpec.parseVariables)%20%7B%5Cn%20%20%20%20%20%20clearTimeout(parseVariablesRateLimitTimeout);%5Cn%20%20%20%20%20%20parseVariablesRateLimitTimeout%20=%20setTimeout(parseAllVariables,%201000);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20window.input%5Bthis.dataset.name%5D%20=%20value;%5Cn%20%20%20%20userInputSpec.value%20=%20value;%5Cn%20%20%20%20%5Cn%20%20%20%20if(!event._isInitCall)%20%7B%5Cn%20%20%20%20%20%20if(userInputSpec.remember)%20%7B%5Cn%20%20%20%20%20%20%20%20saveRememberedInput(this.dataset.name,%20value);%5Cn%20%20%20%20%20%20%7D%20else%20if(this.tagName%20===%20%5C%22TEXTAREA%5C%22%20%7C%7C%20(this.tagName%20===%20%5C%22INPUT%5C%22%20&&%20this.type%20===%20%5C%22text%5C%22))%20%7B%20//%20%3C--%20just%20to%20be%20sure%5Cn%20%20%20%20%20%20%20%20//%20localStorage%5B%5C%22t2i_tempRememberedInput_fisuyr9hf_%5C%22+this.dataset.name%5D%20=%20value;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(!event._isInitCall)%20%7B%5Cn%20%20%20%20%20%20updateInputVisibilities();%5Cn%20%20%20%20%7D%5Cn%20%20%7D;%5Cn%20%20(async%20function()%20%7B%5Cn%20%20%20%20while(!Object.values(window.___userSettings746291937.userInputs)%5B0%5D._element)%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20parseAllVariables();%5Cn%20%20%7D)();%5Cn%20%20%5Cn%20%20let%20socialFeatures%20=%20settings.socialFeatures;%5Cn%20%20if(socialFeatures%20===%20undefined)%20socialFeatures%20=%20%5C%22enabled%5C%22;%5Cn%20%20socialFeatures%20=%20socialFeatures.evaluateItem;%5Cn%20%20%5Cn%20%20let%20thisGeneratorIsUsingClickCountBasedSocialDisplay%20=%20false;%5Cn%20%20%7B%5Cn%20%20%20%20let%20n%20=%20(socialFeatures.match(/button%20after%20(%5B0-9%5D+)%20clicks/)%20%7C%7C%20%5B%5D)%5B1%5D;%5Cn%20%20%20%20if(n)%20%7B%5Cn%20%20%20%20%20%20thisGeneratorIsUsingClickCountBasedSocialDisplay%20=%20true;%5Cn%20%20%20%20%20%20n%20=%20Number(n);%5Cn%20%20%20%20%20%20if(Number(localStorage.generateClickCount%20%7C%7C%200)%20%3E=%20n)%20%7B%5Cn%20%20%20%20%20%20%20%20socialFeatures%20=%20%5C%22button%5C%22;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20socialFeatures%20=%20%5C%22disabled%5C%22;%5Cn%20%20%20%20%20%20%20%20window.showSocialFeaturesButtonAfterThisManyClicks%20=%20n;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20////////////////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20%20%20%20%20%20copy%20share%20link%20button%20handler%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%5Cn%20%20////////////////////////////////////////////////////////////%5Cn%20%20window.__generateSettingsShareLink084722%20=%20async%20function%20generateShareLink()%20%7B%20%5Cn%20%20%20%20%5Cn%20%20%20%20//%20EDIT:%20decided%20to%20show%20this%20on%20every%20click%20now,%20since%20it's%20obviously%20not%20super%20commonly%20clicked%20(so%20an%20extra%20tap%20is%20not%20a%20big%20burden),%20and%20i%20think%20it%20being%20close%20to%20the%20generate%20button%20means%20people%20were%20clicking%20it%20accidentally%20sometimes.%5Cn%20%20%20%20//%20if(!localStorage.knowsHowShareLinksWork)%20%7B%5Cn%20%20%20%20//%20heuristic%20to%20try%20to%20warn%20about%20their%20scratchpad%20being%20shared%20too:%5Cn%20%20%20%20let%20includingScratchpadWarning%20=%20%5C%22%5C%22;%5Cn%20%20%20%20let%20sharableScratchpadExists%20=%20Object.values(window.___userSettings746291937.userInputs).find(o%20=%3E%20(o.getName%20===%20%5C%22scratchpad%5C%22%20%7C%7C%20o.getName%20===%20%5C%22notes%5C%22%20%7C%7C%20o.getName%20===%20%5C%22notepad%5C%22)%20&&%20!o.excludeFromShareLink);%5Cn%20%20%20%20if(sharableScratchpadExists)%20includingScratchpadWarning%20=%20%60,%20%F0%9D%97%B6%F0%9D%97%BB%F0%9D%97%B0%F0%9D%97%B9%F0%9D%98%82%F0%9D%97%B1%F0%9D%97%B6%F0%9D%97%BB%F0%9D%97%B4%20the%20scratchpad/notepad%20text%60;%5Cn%5Cn%20%20%20%20let%20confirmed%20=%20confirm(%60This%20will%20create%20a%20sharable%20link%20to%20a%20snapshot%20of%20the%20settings%20you've%20specified%20above$%7BincludingScratchpadWarning%7D.%60);%5Cn%20%20%20%20if(!confirmed)%20%7B%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20localStorage.knowsHowShareLinksWork%20=%20%5C%221%5C%22;%5Cn%20%20%20%20//%20%7D%5Cn%20%20%5Cn%20%20%20%20if(!window.CompressionStream)%20%7B%5Cn%20%20%20%20%20%20alert(%5C%22Share%20links%20use%20a%20feature%20that's%20only%20available%20in%20modern%20browsers.%20Please%20upgrade%20your%20browser%20to%20the%20latest%20version%20to%20use%20this%20feature.%5C%22);%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20shareLinkCtn83927376.style.display%20=%20%5C%22none%5C%22;%5Cn%5Cn%20%20%20%20shareSettingsBtn758374.disabled%20=%20true;%5Cn%20%20%20%20shareSettingsBtn758374.innerHTML%20=%20%60%3Cspan%20style=%5C%22display:inline-block;%20animation:rotate%201.5s%20linear%20infinite;%5C%22%3E%E2%8F%B3%3C/span%3E%20uploading%20settings%20data...%60;%5Cn%5Cn%20%20%20%20let%20dataJsonStr%20=%20JSON.stringify(getAllUserInputValues());%5Cn%5Cn%20%20%20%20//%20convert%20json%20text%20to%20blob:%5Cn%20%20%20%20let%20blob%20=%20await%20fetch(%5C%22data:text/plain;charset=utf-8,%5C%22+dataJsonStr.replace(/#/g,%20%5C%22%2523%5C%22)).then(res%20=%3E%20res.blob());%5Cn%5Cn%20%20%20%20//%20compress%20blob:%5Cn%20%20%20%20let%20compressedBlob%20=%20await%20compressBlobWithGzip(blob);%5Cn%5Cn%20%20%20%20let%20%7B%20url,%20size,%20error%20%7D%20=%20await%20upload(compressedBlob);%5Cn%20%20%20%20if(error)%20%7B%5Cn%20%20%20%20%20%20shareSettingsLinkInputEl759307.value%20=%20%60error:%20$%7Berror%7D%60;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20shareSettingsLinkInputEl759307.value%20=%20%60https://perchance.org/$%7Bwindow.generatorName%7D#data=%60+url.replace(%5C%22https://user-uploads.perchance.org/file/%5C%22,%20%5C%22uup1:%5C%22);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20shareLinkCtn83927376.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20shareSettingsBtn758374.textContent%20=%20%5C%22%F0%9F%94%97%20share%20these%20settings%5C%22;%5Cn%20%20%20%20shareSettingsBtn758374.disabled%20=%20false;%5Cn%20%20%20%20shareSettingsBtn758374.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20async%20function%20compressBlobWithGzip(blob)%20%7B%5Cn%20%20%20%20const%20cs%20=%20new%20CompressionStream('gzip');%5Cn%20%20%20%20const%20compressedStream%20=%20blob.stream().pipeThrough(cs);%5Cn%20%20%20%20let%20outputBlob%20=%20await%20new%20Response(compressedStream).blob();%5Cn%20%20%20%20return%20new%20Blob(%5BoutputBlob%5D,%20%7B%20type:%20%5C%22application/gzip%5C%22%20%7D);%20//%20%3C--%20to%20add%20the%20correct%20mime%20type%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20async%20function%20loadDataFromUrlHash()%20%7B%20%5Cn%20%20%20%20let%20success%20=%20false;%5Cn%20%20%20%20if(!window.DecompressionStream)%20%7B%5Cn%20%20%20%20%20%20alert(%5C%22Share%20links%20use%20a%20browser%20feature%20that's%20only%20available%20in%20modern%20browsers.%20Please%20upgrade%20your%20browser%20to%20the%20latest%20version%20(ideally%20Chrome%20or%20Edge)%20to%20allow%20for%20loading%20data%20from%20character%20share%20links.%5C%22);%5Cn%20%20%20%20%20%20return%20%7Bsuccess,%20error:%5C%22browser_compat%5C%22%7D;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20let%20loadingModal%20=%20document.createElement('div');%5Cn%20%20%20%20loadingModal.innerHTML%20=%20%60%3Cdiv%20style=%5C%22position:%20fixed;%20top:%200;%20left:%200;%20width:%20100%25;%20height:%20100%25;%20background-color:%20rgba(0,%200,%200,%200.5);%20z-index:%209999;%20display:%20flex;%20justify-content:%20center;%20align-items:%20center;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20style=%5C%22padding:%2020px;%20background-color:%20var(--box-color);%20border-radius:%208px;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cspan%20style=%5C%22display:inline-block;%20animation:rotate%201.5s%20linear%20infinite;%5C%22%3E%E2%8F%B3%3C/span%3E%20loading%20share%20link%20data...%5Cn%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%60;%5Cn%20%20%20%20loadingModal%20=%20loadingModal.firstElementChild;%5Cn%20%20%20%20document.body.append(loadingModal);%5Cn%5Cn%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20let%20hashText%20=%20window.location.hash.slice(1);%5Cn%20%20%20%20%20%20if(!hashText.startsWith(%5C%22data=%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20throw%20new%20Error(%5C%22Invalid%20share%20URL.%5C%22);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20let%20fileUrl%20=%20hashText.replace(/%5Edata=/,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20if(fileUrl.startsWith(%5C%22uup1:%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20fileUrl%20=%20fileUrl.replace(%5C%22uup1:%5C%22,%20%5C%22https://user-uploads.perchance.org/file/%5C%22);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20let%20fetchOptions%20=%20%7B%7D;%5Cn%20%20%20%20%20%20if(window.AbortSignal%20&&%20AbortSignal.timeout)%20fetchOptions.signal%20=%20AbortSignal.timeout(10000);%5Cn%20%20%20%20%20%20let%20blob%20=%20await%20fetch(fileUrl,%20fetchOptions).then(res%20=%3E%20res.blob());%5Cn%20%20%20%20%20%20let%20text;%5Cn%20%20%20%20%20%20if(fileUrl.endsWith(%5C%22.gz%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20let%20decompressedBlob%20=%20await%20decompressBlobWithGzip(blob);%5Cn%20%20%20%20%20%20%20%20text%20=%20await%20decompressedBlob.text();%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20text%20=%20await%20blob.text();%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20let%20data%20=%20JSON.parse(text);%5Cn%20%20%20%20%20%20if(data.___format%20===%20%5C%22t2i-framework-format1%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20userHasSomeTextTheyAreTryingToRemember%20=%20Object.values(window.___userSettings746291937.userInputs).filter(o%20=%3E%20o.remember%20&&%20o._element.tagName.toLowerCase()%20===%20%5C%22textarea%5C%22).map(o%20=%3E%20o._element.value).join(%5C%22%5C%22).length%20%3E%20100;%5Cn%20%20%20%20%20%20%20%20if(userHasSomeTextTheyAreTryingToRemember)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20confirmed%20=%20confirm(%5C%22%F0%9D%97%9B%F0%9D%97%B2%F0%9D%97%AE%F0%9D%97%B1%F0%9D%98%80%20%F0%9D%98%82%F0%9D%97%BD:%20You're%20loading%20a%20share%20link.%20This%20will%20overwrite%20your%20existing%20saved%20settings/scratchpad.%20%F0%9D%97%96%F0%9D%97%BC%F0%9D%97%BB%F0%9D%98%81%F0%9D%97%B6%F0%9D%97%BB%F0%9D%98%82%F0%9D%97%B2?%5C%5Cn%5C%5Cn(Note:%20You%20can%20click%20cancel%20and%20then%20load%20the%20share%20link%20in%20your%20browser's%20incognito/private%20mode%20to%20avoid%20overwriting%20your%20current%20data,%20or%20just%20backup%20your%20existing%20data%20first.)%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20if(!confirmed)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20loadingModal.remove();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20return%20%7Bsuccess,%20error:%5C%22loading_cancelled_by_user%5C%22%7D;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20importUserInputValues(data);%5Cn%20%20%20%20%20%20%20%20success%20=%20true;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20alert(%5C%22Unknown%20share%20link%20data%20format.%5C%22);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20alert(%60Failed%20to%20load%20share%20link%20data:%20$%7Be.message%7D%60);%5Cn%20%20%20%20%20%20console.error(e);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20loadingModal.remove();%5Cn%20%20%20%20return%20%7Bsuccess%7D;%5Cn%20%20%7D%5Cn%5Cn%20%20async%20function%20decompressBlobWithGzip(blob)%20%7B%5Cn%20%20%20%20const%20ds%20=%20new%20DecompressionStream(%5C%22gzip%5C%22);%5Cn%20%20%20%20const%20decompressedStream%20=%20blob.stream().pipeThrough(ds);%5Cn%20%20%20%20return%20await%20new%20Response(decompressedStream).blob();%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20getAllUserInputValues()%20%7B%5Cn%20%20%20%20let%20userInputs%20=%20%7B%7D;%5Cn%20%20%20%20for(let%20key%20in%20window.___userSettings746291937.userInputs)%20%7B%5Cn%20%20%20%20%20%20if(window.___userSettings746291937.userInputs%5Bkey%5D.excludeFromShareLink)%20continue;%5Cn%20%20%20%20%20%20let%20value%20=%20window.___userSettings746291937.userInputs%5Bkey%5D._element?.value;%5Cn%20%20%20%20%20%20if(value%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20userInputs%5Bkey%5D%20=%20value;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20userInputs.___format%20=%20%5C%22t2i-framework-format1%5C%22;%5Cn%20%20%20%20return%20userInputs;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20importUserInputValues(data)%20%7B%5Cn%20%20%20%20for(let%20key%20in%20window.___userSettings746291937.userInputs)%20%7B%5Cn%20%20%20%20%20%20if(window.___userSettings746291937.userInputs%5Bkey%5D.excludeFromShareLink)%20continue;%5Cn%20%20%20%20%20%20let%20value%20=%20window.___userSettings746291937.userInputs%5Bkey%5D._element?.value;%5Cn%20%20%20%20%20%20if(value%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20if(data%5Bkey%5D%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20el%20=%20window.___userSettings746291937.userInputs%5Bkey%5D._element;%5Cn%20%20%20%20%20%20%20%20%20%20el.value%20=%20data%5Bkey%5D;%5Cn%20%20%20%20%20%20%20%20%20%20if(el.onchange)%20el.onchange(%7B_isInitCall:true%7D);%5Cn%20%20%20%20%20%20%20%20%20%20if(el.oninput)%20el.oninput(%7B_isInitCall:true%7D);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20window.t2i_openCharacterDescriptionEditor%20=%20function(imageCtn)%20%7B%5Cn%20%20%20%20imageCtn.querySelector('.personality-chat-button').style.visibility%20=%20'hidden';%5Cn%20%20%20%20if(imageCtn.querySelector('.char-description-editor-ctn'))%20%7B%5Cn%20%20%20%20%20%20//%20show%20it%20existing%20on%20if%20it%20exists:%5Cn%20%20%20%20%20%20imageCtn.querySelector('.char-description-editor-ctn').style.display%20=%20'flex';%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20//%20otherwise%20create%20it:%5Cn%20%20%20%20%20%20let%20tmp%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20tmp.innerHTML%20=%20%60%3Cdiv%20class=%5C%22char-description-editor-ctn%5C%22%20style=%5C%22color-scheme:dark;%20color:#dddddd;%20position:absolute;top:0;left:0;right:0;bottom:0;display:%20flex;flex-direction:column;%20gap:0.125rem;%20padding:0.125rem;%20padding-bottom:0;%20backdrop-filter:brightness(0.7);%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3C!--%3Cdiv%20style=%5C%22font-size:80%25;%20font-weight:bold;%20text-shadow:0px%200px%208px%20black,%200px%200px%208px%20black;%5C%22%3EInstructions:%3C/div%3E--%3E%5Cn%20%20%20%20%20%20%20%20%3Ctextarea%20class=%5C%22char-description-instruction%5C%22%20style=%5C%22backdrop-filter:blur(3px);%20background:rgba(0,%200,%200,%200.8);%20font-size:80%25;%20min-height:70px;%20border:1px%20solid%20grey;%20border-radius:2px;%20color-scheme:dark;%5C%22%20placeholder=%5C%22(Optional)%20Extra%20instructions%20for%20the%20personality,%20appearance,%20and%20backstory%20to%20be%20generated.%5C%22%3E%3C/textarea%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%20gap:0.125rem;%20justify-content:center;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22char-description-generate-button%5C%22%20style=%5C%22color-scheme:dark;%20flex-grow:1;%20font-weight:bold;%20max-width:max-content;%20box-shadow:0px%200px%2012px%202px%20black;%5C%22%20onclick=%5C%22window.t2i_generateCharacterDescription(this.closest('.t2i-image-ctn'))%5C%22%3E%E2%9C%A8%20generate%20persona%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22char-description-stop-button%5C%22%20style=%5C%22color-scheme:dark;%20min-width:4rem;%20display:none;%20box-shadow:0px%200px%2012px%202px%20black;%5C%22%20onclick=%5C%22this.closest('.t2i-image-ctn').__generateObj.stop()%5C%22%3E%F0%9F%9B%91%20stop%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C!--%3Cdiv%20style=%5C%22font-size:80%25;%20font-weight:bold;%20text-shadow:0px%200px%208px%20black,%200px%200px%208px%20black;%5C%22%3EOutput:%3C/div%3E--%3E%5Cn%20%20%20%20%20%20%20%20%3C!--%3Cdiv%20style=%5C%22%5C%22%3E%E2%AC%87%EF%B8%8F%20%E2%AC%87%EF%B8%8F%20%E2%AC%87%EF%B8%8F%3C/div%3E--%3E%5Cn%20%20%20%20%20%20%20%20%3Cinput%20class=%5C%22character-name-output%5C%22%20style=%5C%22backdrop-filter:blur(3px);%20background:rgba(0,%200,%200,%200.8);%20border:1px%20solid%20grey;%20border-radius:2px;%20color-scheme:dark;%5C%22%20placeholder=%5C%22Character%20name%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Ctextarea%20class=%5C%22character-description-output%5C%22%20placeholder=%5C%22Click%20the%20%F0%9D%97%B4%F0%9D%97%B2%F0%9D%97%BB%F0%9D%97%B2%F0%9D%97%BF%F0%9D%97%AE%F0%9D%98%81%F0%9D%97%B2%20button%20above!%20The%20character%20description%20will%20appear%20here,%20and%20then%20you%20can%20edit%20it.%5C%22%20style=%5C%22backdrop-filter:blur(3px);%20flex-grow:1;%20background:rgba(0,0,0,0.8);%20border:1px%20solid%20grey;%20border-radius:2px;%20font-size:85%25;%20color-scheme:dark;%5C%22%3E%3C/textarea%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%20gap:0.25rem;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20style=%5C%22flex-grow:1;%20color-scheme:dark;%5C%22%20onclick=%5C%22window.t2i_generateChatLink(this.closest('.t2i-image-ctn'))%5C%22%3E%F0%9F%92%AC%20chat%20with%20them%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20style=%5C%22min-width:4rem;%20color-scheme:dark;%5C%22%20onclick=%5C%22this.closest('.char-description-editor-ctn').style.display='none';%20this.closest('.t2i-image-ctn').querySelector('.personality-chat-button').style.visibility='visible';%5C%22%3E%E2%9D%8C%20close%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%3C/div%3E%60;%5Cn%20%20%20%20%20%20imageCtn.appendChild(tmp.firstElementChild);%5Cn%20%20%20%20%7D%5Cn%20%20%7D;%5Cn%5Cn%20%20window.t2i_generateCharacterDescription%20=%20async%20function(imageCtn)%20%7B%5Cn%20%20%5Cn%20%20%20%20let%20generateBtn%20=%20imageCtn.querySelector(%5C%22.char-description-generate-button%5C%22);%5Cn%20%20%20%20let%20stopBtn%20=%20imageCtn.querySelector(%5C%22.char-description-stop-button%5C%22);%5Cn%20%20%5Cn%20%20%20%20let%20originalGenerateButtonTextContent%20=%20generateBtn.textContent;%5Cn%20%20%20%20generateBtn.innerHTML%20=%20%60%3Cspan%20style=%5C%22display:inline-block;%20animation:rotate%201.5s%20linear%20infinite;%5C%22%3E%E2%8F%B3%3C/span%3E%20loading...%60;%5Cn%20%20%20%20generateBtn.disabled%20=%20true;%5Cn%20%20%20%20stopBtn.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%5Cn%20%20%20%20while(!imageCtn.querySelector(%5C%22iframe%5C%22).textToImagePluginOutput)%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%201000));%20//%20bit%20of%20a%20hacky%20patch,%20just%20to%20cover%20edge%20case%20where%20they%20can%20click%20the%20personality%20button%20before%20image%20generation%20finishes%5Cn%20%20%5Cn%20%20%20%20let%20charDescriptionInstruction%20=%20imageCtn.querySelector(%5C%22.char-description-instruction%5C%22).value.trim();%5Cn%20%20%20%20let%20textToImagePluginOutput%20=%20imageCtn.querySelector(%5C%22iframe%5C%22).textToImagePluginOutput;%5Cn%20%20%20%20let%20nameOutputEl%20=%20imageCtn.querySelector(%5C%22.character-name-output%5C%22);%5Cn%20%20%20%20let%20descriptionOutputEl%20=%20imageCtn.querySelector(%5C%22.character-description-output%5C%22);%5Cn%5Cn%20%20%20%20nameOutputEl.value%20=%20%5C%22%5C%22;%5Cn%20%20%20%20descriptionOutputEl.value%20=%20%5C%22%5C%22;%5Cn%5Cn%20%20%20%20let%20generateObj;%5Cn%20%20%20%20if(true)%20%7B%5Cn%20%20%20%20%20%20generateObj%20=%20aiText(%7B%5Cn%20%20%20%20%20%20%20%20instruction:%20%60%5Cn%20%20%20%20%20%20%20%20TASK:%20The%20user%20has%20created%20an%20image%20of%20a%20character%20using%20a%20prompt.%20The%20prompt%20is%20shown%20below.%20Your%20task%20is%20to%20use%20the%20character%20personality%20hints%20in%20the%20prompt%20to%20generate%20a%20character%20description%20for%20roleplaying%20with.%20Your%20description%20should%20ideally%20include%20personality,%20appearance,%20speech%20examples/mannerisms,%20etc.%20such%20that%20an%20actor%20could%20read%20it%20and%20know%20how%20to%20roleplay%20as%20the%20character%20in%20all%20relevant%20aspects.%20Use%20an%20information-dense%20writing%20style%20to%20*succinctly*%20capture%20all%20aspects%20of%20the%20personality%20of%20the%20character%20that%20you%20generate.%20Your%20description%20should%20be%20between%20200%20and%20600%20words%20in%20length.%20Do%20your%20best%20to%20generate%20a%20character%20based%20on%20what%20you%20see%20below.%20Follow%20the%20hints%20in%20the%20user's%20image%20prompt%20to%20accurately%20capture%20the%20details%20that%20are%20most%20important%20to%20a%20character%20chat/roleplay.%5Cn%5Cn%20%20%20%20%20%20%20%20---%20START%20OF%20IMAGE%20PROMPT%20---%5Cn%20%20%20%20%20%20%20%20$%7BtextToImagePluginOutput.inputs.prompt.replace(/%5C%5Cs+/g,%20%5C%22%20%5C%22)%7D%5Cn%20%20%20%20%20%20%20%20---%20END%20OF%20IMAGE%20PROMPT%20---%5Cn%5Cn%20%20%20%20%20%20%20%20Reminder:%20Your%20task%20is%20to%20generate%20a%20character%20that%20is%20inspired%20by%20the%20above%20image%20prompt.%20Your%20response%20should%20describe%20how%20the%20character%20looks/acts/speaks/behaves%20such%20that%20if%20someone%20read%20it,%20they%20would%20be%20able%20to%20accurately%20emulate%20or%20roleplay%20as%20the%20target%20character's%20mannerisms,%20personality,%20etc.%20No%20more%20than%20600%20words.%5Cn%20%20%20%20%20%20%20%20$%7BcharDescriptionInstruction%20?%20%60%5C%5CnBut%20also,%20the%20character%20must%20be%20based%20on%20this%20instruction:%20$%7BcharDescriptionInstruction%7D%5C%5Cn%60%20:%20%5C%22%5C%22%7D%5Cn%5Cn%20%20%20%20%20%20%20%20Use%20this%20template%20for%20your%20response:%5Cn%20%20%20%20%20%20%20%20%3Cresponse_template%3E%5Cn%20%20%20%20%20%20%20%20#%20Name:%5Cn%20%20%20%20%20%20%20%20(The%20character's%20name)%5Cn%5Cn%20%20%20%20%20%20%20%20#%20Visual%20Description:%5Cn%20%20%20%20%20%20%20%20(A%20SHORT%20paragraph%20describing%20what%20they%20look%20like%20-%20keep%20this%20short,%20concise%20and%20to-the-point.%20Low%20word%20count,%20high%20information%20density.%20Avoid%20using%20purple%20prose%20and%20overly%20flowery%20descriptions.)%5Cn%5Cn%20%20%20%20%20%20%20%20#%20Personality%20Description:%5Cn%20%20%20%20%20%20%20%20(ONE%20paragraph%20personality%20description.%20Use%20mainly%20short%20sentences%20-%20i.e.%20write%20in%20an%20information-dense%20style.%20Focus%20on%20the%20aspects%20that%20make%20them%20unique/interesting.%20If%20relevant,%20you%20can%20use%20terms%20like%20tsundere,%20yandere,%20kuudere,%20deredere,%20dandere,%20genki%20girl,%20kuudere,%20seme,%20uke,%20megane,%20chuunibyou,%20clumsy%20heroine,%20superiority%20complex,%20dominant,%20submissive,%20etc.%20to%20succinctly%20capture%20aspects%20of%20their%20personality.%20Invent%20a%20few%20interesting%20aspects,%20use%20creative%20liberty%20to%20create%20a%20character%20that%20has%20genuine%20depth,%20with%20idiosyncrasies,%20goals,%20fears,%20likes,%20dislikes,%20ethics,%20etc.%20Remember,%20your%20goal%20is%20to%20create%20a%20character%20that%20would%20be%20fun%20for%20the%20user%20to%20roleplay%20with!%20Follow%20the%20user's%20lead%20based%20on%20their%20initial%20idea,%20but%20take%20it%20one%20step%20further%20to%20surprise%20and%20excite%20them.)%5Cn%5Cn%20%20%20%20%20%20%20%20#%20Roleplay%20Behavior%20Examples:%5Cn%20%20%20%20%20%20%20%20(A%20numbered%20list%20of%205%20separate%20and%20diverse%20examples%20of%20character%20speech/behavior,%20each%20starting%20with%20an%20asterisk%20or%20double-quote,%20which%20place%20the%20character%20in%20random%20roleplay%20situations,%20as%20if%20you've%20extracted%20random%20&%20diverse%20moments%20from%20a%20story,%20with%20sufficient%20context%20captured%20by%20the%20dialogue%20and%20actions%20themselves,%20to%20show%20the%20essence%20of%20who%20they%20are%20as%20a%20character,%20how%20they%20speak/act/react/etc.%20Each%20example%20should%20perfectly%20capture%20one%20aspect%20of%20who%20they%20are%20as%20a%20character.%20Each%20example%20should%20be%20its%20own%20separate%20momement%20from%20a%20hypothetical%20story,%20unrelated%20to%20the%20other%20examples%20that%20you%20write.%20You%20must%20use%20asterisks%20around%20actions%20and%20quotes%20around%20speech%20in%20typical%20roleplays%20style,%20for%20example%20%5Bdon't%20use%20this%20specific%20example%20in%20your%20response,%20it's%20just%20to%20demonstrate%20the%20syntax%5D:%201.%20%5C%22And%20why%20the...%5C%22%20*He%20gestures%20to%20the%20overturned%20carriage*%20%5C%22...grand%20entrance?%5C%22%20%5B...%5D)%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20#%20Favorite%20Food:%5Cn%20%20%20%20%20%20%20%20(favorite%20food)%5Cn%20%20%20%20%20%20%20%20%3C/response_template%3E%5Cn%20%20%20%20%20%20%20%20%60.trim(),%5Cn%20%20%20%20%20%20%20%20startWith:%20%5C%22#%20Name:%5C%22,%5Cn%20%20%20%20%20%20%20%20stopSequences:%20%5B%5C%22#%20Favorite%5C%22%5D,%5Cn%20%20%20%20%20%20%20%20onChunk:%20(data)%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20parts%20=%20data.fullTextSoFar.split(/(%5E%7C%5C%5Cn%5C%5Cn)#%20/s).map(p%20=%3E%20p.trim()).filter(p%20=%3E%20p);%5Cn%20%20%20%20%20%20%20%20%20%20let%20name%20=%20parts.find(p%20=%3E%20p.startsWith(%5C%22Name%5C%22))?.split(%5C%22%5C%5Cn%5C%22)?.%5B1%5D?.trim();%5Cn%20%20%20%20%20%20%20%20%20%20let%20visualDescription%20=%20parts.find(p%20=%3E%20p.startsWith(%5C%22Visual%5C%22))?.split(%5C%22%5C%5Cn%5C%22).slice(1).join(%5C%22%5C%5Cn%5C%22).trim()%20%7C%7C%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20let%20personalityDescription%20=%20parts.find(p%20=%3E%20p.startsWith(%5C%22Personality%5C%22))?.split(%5C%22%5C%5Cn%5C%22).slice(1).join(%5C%22%5C%5Cn%5C%22).trim()%20%7C%7C%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20let%20roleplayBehaviorExamples%20=%20parts.find(p%20=%3E%20p.startsWith(%5C%22Roleplay%5C%22))?.split(%5C%22%5C%5Cn%5C%22).slice(1).join(%5C%22%5C%5Cn%5C%22).trim()%20%7C%7C%20%5C%22%5C%22;%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20nameOutputEl.value%20=%20name%20%7C%7C%20%5C%22%5C%22;%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20let%20description%20=%20%60#%20%7B%7Bchar%7D%7D%20Visual%20Description:%5C%5Cn$%7BvisualDescription%7D%5C%5Cn%5C%5Cn#%20%7B%7Bchar%7D%7D%20Personality:%5C%5Cn$%7BpersonalityDescription%7D%5C%5Cn%5C%5Cn#%20%7B%7Bchar%7D%7D%20Roleplay%20Behavior%20Examples:%5C%5Cn$%7BroleplayBehaviorExamples%7D%60;%5Cn%20%20%20%20%20%20%20%20%20%20descriptionOutputEl.value%20=%20description;%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20if(descriptionOutputEl.scrollTop%20%3E%20(descriptionOutputEl.scrollHeight%20-%20descriptionOutputEl.offsetHeight)-30)%20%7B%20//%20%3C--%20if%20the%20text%20box%20is%20already%20scrolled%20near%20the%20end%20of%20the%20text%5Cn%20%20%20%20%20%20%20%20%20%20%20%20descriptionOutputEl.scrollTop%20=%2099999999;%20//%20scroll%20down%20to%20bottom%20of%20textarea%20as%20text%20streams%20in%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20//%20generateObj%20=%20aiText(%7B%5Cn%20%20%20%20%20%20//%20%20%20instruction:%20%60%5Cn%20%20%20%20%20%20//%20%20%20Your%20task%20is%20to%20invent%20a%20character%20description%20for%20a%20roleplay.%5Cn%20%20%20%20%20%20//%20%20%20All%20you%20know%20about%20the%20character%20is%20what%20you%20can%20glean%20from%20this%20image%20prompt:%20$%7BtextToImagePluginOutput.inputs.prompt.replace(/%5C%5Cs+/g,%20%5C%22%20%5C%22)%7D%5Cn%20%20%20%20%20%20//%20%20%20$%7BcharDescriptionInstruction%20?%20%5C%22But%20also,%20the%20character%20must%20be%20based%20on%20this%20instruction:%20%5C%22+charDescriptionInstruction%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20//%20%20%20Your%20response%20should%20use%20this%20template:%5Cn%20%20%20%20%20%20//%20%20%20---%5Cn%20%20%20%20%20%20//%20%20%20Name:%20%3Ccharacter's%20name%3E%5Cn%20%20%20%20%20%20//%20%20%20Personality:%20%3Cone%20paragraph%20summarizing%20their%20personality,%20including%20specific%20interesting%20quirks%3E%5Cn%20%20%20%20%20%20//%20%20%20Background:%20%3Cone%20paragraph%20summarizing%20their%20backstory%3E%5Cn%20%20%20%20%20%20//%20%20%20Physical%20Features%20(IGNORING%20ATTIRE/POSE):%20%3Cup%20to%2010%20comma-separated%20keywords/phrases%20indicating%20*permanent*%20physical%20features%20like%20body%20type/build/size,%20skin%20color,%20eye%20color,%20hair%20color,%20nose%20shape,%20etc%3E%5Cn%20%20%20%20%20%20//%20%20%20Age:%20%3Ctheir%20age%3E%5Cn%20%20%20%20%20%20//%20%20%20---%5Cn%20%20%20%20%20%20//%20%20%20Respond%20with%20the%20above%20template,%20loosely%20inspired%20by%20details%20from%20the%20image%20description.%20Create%20an%20engaging,%20captivating,%20and%20*genuinely%20fascinating*%20character.%20Keep%20your%20response%20short.%20Use%20lean,%20unpretentious,%20crisp,%20descriptive%20words%20that%20vividly%20and%20*concisely*%20capture%20the%20most%20interesting%20aspects%20of%20the%20character%20that%20you've%20invented.%5Cn%20%20%20%20%20%20//%20%20%20IMPORTANT:%20Do%20NOT%20describe%20the%20image.%20This%20isn't%20about%20the%20image.%20It's%20about%20the%20*character*.%20Talk%20about%20the%20character,%20not%20the%20image.%20The%20image%20just%20provides%20clues.%5Cn%20%20%20%20%20%20//%20%20%20%60.trim(),%5Cn%20%20%20%20%20%20//%20%20%20startWith:%20%5C%22Name:%5C%22,%5Cn%20%20%20%20%20%20//%20%20%20stopSequences:%20%5B%5C%22Age:%5C%22%5D,%5Cn%20%20%20%20%20%20//%20%20%20onChunk:%20(data)%20=%3E%20%7B%5Cn%20%20%20%20%20%20//%20%20%20%20%20let%20parts%20=%20data.fullTextSoFar.split(/(Name:.*)/);%5Cn%20%20%20%20%20%20//%20%20%20%20%20nameOutputEl.value%20=%20parts%5B1%5D.trim().replace(/%5EName:/,%20%5C%22%5C%22).trim();%5Cn%20%20%20%20%20%20//%20%20%20%20%20descriptionOutputEl.value%20=%20parts%5B2%5D.trim().replace(/%5C%5CnAge:.?$/,%20%5C%22%5C%22).replace(%5C%22%20(IGNORING%20ATTIRE/POSE)%5C%22,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20//%20%20%20%20%20if(descriptionOutputEl.scrollTop%20%3E%20(descriptionOutputEl.scrollHeight%20-%20descriptionOutputEl.offsetHeight)-30)%20%7B%20//%20%3C--%20if%20the%20text%20box%20is%20already%20scrolled%20near%20the%20end%20of%20the%20text%5Cn%20%20%20%20%20%20//%20%20%20%20%20%20%20descriptionOutputEl.scrollTop%20=%2099999999;%20//%20scroll%20down%20to%20bottom%20of%20textarea%20as%20text%20streams%20in%5Cn%20%20%20%20%20%20//%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20//%20%20%20%7D,%5Cn%20%20%20%20%20%20//%20%7D);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20imageCtn.__generateObj%20=%20generateObj;%20//%20so%20the%20stop%20button%20can%20access%20it%5Cn%20%20%20%20let%20data%20=%20await%20generateObj;%5Cn%5Cn%20%20%20%20generateBtn.textContent%20=%20originalGenerateButtonTextContent;%5Cn%20%20%20%20generateBtn.disabled%20=%20false;%5Cn%20%20%20%20stopBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%7D;%5Cn%5Cn%20%20window.t2i_generateChatLink%20=%20async%20function(imageCtn)%20%7B%5Cn%20%20%20%20let%20name%20=%20imageCtn.querySelector(%5C%22.character-name-output%5C%22).value.trim().replace(/%5C%5Cn+/g,%20%5C%22%20%5C%22);%5Cn%20%20%20%20let%20firstName%20=%20name.split(/%5B%20,%5D/)%5B0%5D.trim();%5Cn%20%20%20%20let%20description%20=%20imageCtn.querySelector(%5C%22.character-description-output%5C%22).value.trim().replace(/%5C%5Cn+/g,%20%5C%22%5C%5Cn%5C%22).trim();%5Cn%20%20%20%20let%20textToImagePluginOutput%20=%20imageCtn.querySelector(%5C%22iframe%5C%22).textToImagePluginOutput;%5Cn%5Cn%20%20%20%20if(!description)%20return%20alert(%5C%22First%20click%20the%20%F0%9D%97%B4%F0%9D%97%B2%F0%9D%97%BB%F0%9D%97%B2%F0%9D%97%BF%F0%9D%97%AE%F0%9D%98%81%F0%9D%97%B2%20%F0%9D%97%BD%F0%9D%97%B2%F0%9D%97%BF%F0%9D%98%80%F0%9D%97%BC%F0%9D%97%BB%F0%9D%97%AE%20button%20above%20to%20generate%20a%20character%20description.%5C%22);%5Cn%5Cn%20%20%20%20let%20appearance%20=%20(((description+%5C%22%5C%5Cn%5C%22).match(/Physical%20Features%20*(%7C%5C%5C(.+?%5C%5C)):%20(.+?)%5C%5Cn/s)%20%7C%7C%20%5B%5D)%5B1%5D%20%7C%7C%20%5C%22%5C%22).trim();%5Cn%5Cn%20%20%20%20let%20roleInstruction%20=%20%60%5Cn%20%20%20%20#%20Description%20of%20$%7Bname%7D:%5Cn%20%20%20%20$%7Bdescription%7D%5Cn%5Cn%20%20%20%20#%20Roleplay%20Guidelines:%5Cn%20%20%20%20-%20Bring%20characters%20to%20life%20by%20realistically%20portraying%20their%20unique%20traits,%20thoughts,%20emotions,%20appearances,%20physical%20sensations,%20speech%20patterns,%20and%20tone.%20Consider%20the%20situation,%20characters'%20motivations,%20and%20potential%20consequences.%5Cn%20%20%20%20-%20Ensure%20that%20their%20reactions,%20interactions,%20and%20decision-making%20align%20with%20their%20established%20personalities/descriptions,%20values,%20goals,%20and%20fears.%20You%20must%20**ALWAYS**%20maintain%20accurate%20character%20portrayals.%5Cn%5Cn%20%20%20%20Creatively%20improvise%20this%20fictional%20roleplay%20between%20%7B%7Bchar%7D%7D%20and%20%7B%7Buser%7D%7D%20to%20create%20an%20interesting%20and%20engaging%20experience/story/chat,%20no%20matter%20where%20%7B%7Buser%7D%7D%20decides%20to%20lead%20it.%20The%20overall%20goal%20is%20to%20create%20a%20genuinely%20fascinating%20and%20engaging%20roleplay/story.%20So%20good%20that%20you%20can't%20stop%20reading.%20Be%20proactive,%20introducing%20new%20events,%20proposing%20new%20conversation%20topics,%20and%20leading%20the%20role-play%20in%20new,%20interesting%20directions%20when%20appropriate%20to%20keep%20the%20overall%20experience%20engaging.%5Cn%20%20%20%20%60.trim();%5Cn%5Cn%20%20%20%20let%20characterImagePrompt%20=%20textToImagePluginOutput.inputs.prompt.replace(/%5C%5Cs+/g,%20%5C%22%20%5C%22);%5Cn%20%20%20%20let%20characterImageDataUrl%20=%20textToImagePluginOutput.dataUrl;%5Cn%20%20%20%20%5Cn%20%20%20%20function%20addStyleToPrompt(styleName,%20prompt)%20%7B%5Cn%20%20%20%20%20%20//%20bit%20weird,%20but%20we%20use%20a%20global%20to%20'communicate'%20with%20the%20t2i-styles%20generator's%20scope.%5Cn%20%20%20%20%20%20let%20originalWindowInput%20=%20window.input;%5Cn%20%20%20%20%20%20window.input%20=%20%7Bdescription:prompt%7D;%5Cn%20%20%20%20%20%20let%20result%20=%20t2iStyles%5BstyleName%5D.prompt.evaluateItem;%5Cn%20%20%20%20%20%20window.input%20=%20originalWindowInput;%5Cn%20%20%20%20%20%20return%20result;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20function%20addStyleToNegative(styleName,%20negative)%20%7B%5Cn%20%20%20%20%20%20//%20bit%20weird,%20but%20we%20use%20a%20global%20to%20'communicate'%20with%20the%20t2i-styles%20generator's%20scope.%5Cn%20%20%20%20%20%20let%20originalWindowInput%20=%20window.input;%5Cn%20%20%20%20%20%20window.input%20=%20%7Bnegative%7D;%5Cn%20%20%20%20%20%20let%20result%20=%20t2iStyles%5BstyleName%5D.negative.evaluateItem;%5Cn%20%20%20%20%20%20window.input%20=%20originalWindowInput;%5Cn%20%20%20%20%20%20return%20result;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20//%20If%20the%20generator%20has%20an%20artStyle%20select%20element,%20then%20we%20assume%20it's%20t2iStyles,%20and%20we%20use%20an%20empty%20prompt%20to%20extract%20only%20the%20style,%20so%20that%20style%20can%20be%20used%20in%20the%20chat%20by%20default%5Cn%20%20%20%20let%20imagePromptSuffix%20=%20%5C%22%5C%22;%5Cn%20%20%20%20try%20%7B%20//%20try/catch%20because%20new%20code%5Cn%20%20%20%20%20%20let%20artStyleName%20=%20window.___userSettings746291937.userInputs.artStyle?._element.value.split(%5C%22:%5C%22)%5B2%5D;%5Cn%20%20%20%20%20%20if(artStyleName)%20%7B%5Cn%20%20%20%20%20%20%20%20//%20we%20remove%20stuff%20like%20%5C%22(:1.3)%5C%22%20from%20the%20prompt%20because%20the%20style%20expects%20some%20input%20text,%20but%20we're%20not%20giving%20it%20here:%5Cn%20%20%20%20%20%20%20%20let%20prompt%20=%20addStyleToPrompt(artStyleName,%20%5C%22%5C%22).replace(/%5C%5C(%5B():.0-9%20%5D*%5C%5C)/g,%20%5C%22%5C%22).replace(/%5C%5Cs+/g,%20%5C%22%20%5C%22);%5Cn%20%20%20%20%20%20%20%20imagePromptSuffix%20=%20%60$%7Bprompt%7D%20(negativePrompt:::$%7BaddStyleToNegative(artStyleName,%20%5C%22%5C%22)%7D)%20(resolution:::512x768)%60;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%20catch(e)%20%7B%7D;%5Cn%5Cn%20%20%20%20let%20json%20=%20%7B%5Cn%20%20%20%20%20%20addCharacter:%20%7B%5Cn%20%20%20%20%20%20%20%20name,%5Cn%20%20%20%20%20%20%20%20roleInstruction,%5Cn%20%20%20%20%20%20%20%20maxParagraphCountPerMessage:%202,%20//%20TODO:%20add%20a%20drop-down%20selector%20for%20this?%5Cn%20%20%20%20%20%20%20%20imagePromptSuffix,%5Cn%20%20%20%20%20%20%20%20//%20I've%20commented%20out%20the%20line%20below%20for%20now%20because%20I've%20updated%20the%20character%20gen%20prompt,%20and%20it%20doesn't%20currently%20have%20a%20%5C%22purely%20appearance-only,%20without%20reference%20to%20pose/clothes/etc.%5C%22%20section%5Cn%20%20%20%20%20%20%20%20//%20imagePromptTriggers:%20%60$%7BfirstName%7D:%20$%7BfirstName%7D's%20appearance:%20$%7Bappearance%20%7C%7C%20characterImagePrompt%7D%60,%20//%20better%20to%20use%20%60appearance%60%20(if%20we%20have%20it)%20rather%20than%20%60characterImagePrompt%60,%20because%20character%20can%20be%20in%20images%20with%20other%20characters,%20but%20%60characterImagePrompt%60%20would%20likely%20affect%20overall%20image%20too%20much,%20since%20it's%20designed%20to%20generate%20a%20%5C%22whole%5C%22%20image.%5Cn%20%20%20%20%20%20%20%20initialMessages:%20%5B%5Cn%20%20%20%20%20%20%20%20%20%20%7Bauthor:%5C%22system%5C%22,%20content:%60%3Ci%20style=%5C%22font-size:85%25;%5C%22%3EIntroduce%20yourself%20to%20$%7Bname%7D,%20or%20perhaps%20%3Cb%20style=%5C%22color:#00af00;%5C%22%3Etap%20the%20Narrator%20button%3C/b%3E%20and%20tell%20it%20to%20generate%20an%20initial%20roleplay%20scenario%20based%20on%20some%20keywords/themes.%20You%20can%20change%20your%20name%20using%20the%20'options'%20button.%3C/i%3E%60,%20hiddenFrom:%5B%5C%22ai%5C%22%5D%7D,%5Cn%20%20%20%20%20%20%20%20%5D,%5Cn%20%20%20%20%20%20%20%20avatar:%20%7Burl:characterImageDataUrl,%20size:1,%20shape:%5C%22square%5C%22%7D,%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20quickAdd:%20true,%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20await%20window.t2i_generateShareLinkForCharacter(json);%5Cn%20%20%7D;%5Cn%5Cn%20%20window.t2i_generateShareLinkForCharacter%20=%20async%20function(json)%20%7B%5Cn%20%20%20%20if(!window.CompressionStream)%20%7B%5Cn%20%20%20%20%20%20alert(%5C%22Character%20chat%20links%20use%20a%20feature%20that's%20only%20available%20in%20modern%20browsers.%20Please%20upgrade%20your%20browser%20to%20the%20latest%20version%20to%20use%20this%20feature.%20If%20you're%20using%20Safari,%20switch%20to%20Chrome%20instead.%5C%22);%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20let%20loadingModal%20=%20window.t2i_createLoadingModal(%5C%22%E2%8C%9B%20Generating%20chat%20link...%5C%22);%5Cn%5Cn%20%20%20%20let%20jsonString%20=%20JSON.stringify(json);%20%5Cn%5Cn%20%20%20%20let%20urlHashData%20=%20encodeURIComponent(JSON.stringify(json)).replace(/%5B!'()*%5D/g,%20function(c)%20%7B%5Cn%20%20%20%20%20%20return%20'%25'%20+%20c.charCodeAt(0).toString(16);%20//%20since%20encodeURIComponent%20doesn't%20encode%20some%20characters%20(like%20parentheses)%20and%20they%20mess%20up%20markdown%20links%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20console.log(%5C%22shareUrl%20(hash%20version):%5C%22,%20%60https://perchance.org/ai-character-chat#$%7BurlHashData%7D%60);%5Cn%5Cn%20%20%20%20//%20convert%20json%20text%20to%20blob:%5Cn%20%20%20%20let%20dataUrlJsonString%20=%20jsonString.replace(/#/g,%20%5C%22%2523%5C%22);%20//%20since%20hash%20is%20a%20special%20character%20in%20dataurls%20(like%20normal%20URLs)%5Cn%20%20%20%20let%20blob%20=%20await%20fetch(%5C%22data:text/plain;charset=utf-8,%5C%22+dataUrlJsonString).then(res%20=%3E%20res.blob());%5Cn%5Cn%20%20%20%20//%20compress%20blob:%5Cn%20%20%20%20let%20compressedBlob%20=%20await%20compressBlobWithGzip(blob);%5Cn%5Cn%20%20%20%20let%20%7B%20url,%20size,%20error%20%7D%20=%20await%20upload(compressedBlob);%5Cn%20%20%20%20if(error)%20%7B%5Cn%20%20%20%20%20%20loadingModal.delete();%5Cn%20%20%20%20%20%20alert(%60error:%20$%7Berror%7D%60);%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20loadingModal.delete();%20%5Cn%20%20%20%20%20%20let%20fileName%20=%20url.replace(%5C%22https://user-uploads.perchance.org/file/%5C%22,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20let%20characterName%20=%20json.addCharacter.name.replace(/%5C%5Cs+/g,%20%5C%22_%5C%22).replaceAll(%5C%22~%5C%22,%20%5C%22%5C%22).replaceAll(%60%5C%22%60,%20%5C%22%5C%22);%20//%20this%20is%20just%20so%20URL%20is%20more%20readable%20-%20doesn't%20affect%20stored%20data%20at%20all%5Cn%20%20%20%20%20%20let%20shareUrl%20=%20%60https://perchance.org/ai-character-chat?data=$%7BcharacterName%7D~$%7BfileName%7D%60;%5Cn%20%20%20%20%20%20console.log(%5C%22shareUrl:%5C%22,%20shareUrl);%5Cn%5Cn%20%20%20%20%20%20let%20colorScheme%20=%20%5C%22dark%5C%22;%20//localStorage.forceColorScheme%20!==%20undefined%20?%20localStorage.forceColorScheme%20:%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22;%5Cn%20%20%20%20%20%20let%20result%20=%20await%20prompt2(%7B%5Cn%20%20%20%20%20%20%20%20content:%20%7Btype:%5C%22none%5C%22,%20html:%60%3Cdiv%20style=%5C%22margin-bottom:0.5rem;%20opacity:0.7;%20font-size:90%25;%5C%22%3EYour%20character%20has%20been%20created.%20Here's%20the%20link:%3C/div%3E%3Cdiv%20style=%5C%22display:flex;%20gap:0.5rem;%5C%22%3E%3Cinput%20value=%5C%22$%7BshareUrl%7D%5C%22%20style=%5C%22flex-grow:1;%20color-scheme:$%7BcolorScheme%7D;%20min-width:0;%20font-size:80%25;%5C%22%3E%20%3Cbutton%20onclick=%5C%22navigator.clipboard.writeText(this.parentElement.querySelector('input').value);%20this.textContent='copied%20%E2%9C%85';%20setTimeout(()%20=%3E%20%7B%20this.textContent='%F0%9F%93%8B%20copy';%20%7D,%202000);%5C%22%20style=%5C%22min-width:max-content;%5C%22%3E%F0%9F%93%8B%20copy%3C/button%3E%20%3Cbutton%20onclick=%5C%22window.open(this.parentElement.querySelector('input').value)%5C%22%20style=%5C%22min-width:max-content;%5C%22%3E%E2%86%97%EF%B8%8F%20visit%3C/button%3E%20%3C/div%3E%60%7D,%5Cn%20%20%20%20%20%20%7D,%20%7BcolorScheme,%20cancelButtonText:null,%20submitButtonText:%5C%22finished%5C%22,%20verticallyCenter:true%7D);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20window.t2i_createLoadingModal%20=%20function(initialContent,%20parentElement)%20%7B%5Cn%20%20%20%20if(!parentElement)%20parentElement%20=%20document.body;%5Cn%20%20%20%20let%20loadingModalCtn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20loadingModalCtn.innerHTML%20=%20%60%3Cstyle%3E%5Cn%20%20%20%20%20%20.loadingModalCtn-856246272937%20%7B%5Cn%20%20%20%20%20%20%20%20position:%20fixed;%5Cn%20%20%20%20%20%20%20%20top:%200;%5Cn%20%20%20%20%20%20%20%20left:%200;%5Cn%20%20%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%20%20%20%20height:%20100%25;%5Cn%20%20%20%20%20%20%20%20background-color:%20rgba(0,0,0,0.7);%5Cn%20%20%20%20%20%20%20%20color-scheme:%20dark;%5Cn%20%20%20%20%20%20%20%20color:#e7e7e7;%5Cn%20%20%20%20%20%20%20%20z-index:%20100;%5Cn%20%20%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20%20%20padding:%201rem;%5Cn%20%20%20%20%20%20%20%20z-index:%2099999999;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.loadingModalContent-856246272937%20%7B%5Cn%20%20%20%20%20%20%20%20background-color:%20#151515;%5Cn%20%20%20%20%20%20%20%20border-radius:%203px;%5Cn%20%20%20%20%20%20%20%20padding:%201rem;%5Cn%20%20%20%20%20%20%20%20text-align:%20center;%5Cn%20%20%20%20%20%20%20%20box-shadow:%200px%201px%2010px%203px%20rgb(130%20130%20130%20/%2024%25);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%3C/style%3E%60;%5Cn%20%20%20%20let%20contentEl%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20contentEl.classList.add(%5C%22loadingModalContent-856246272937%5C%22);%5Cn%20%20%20%20contentEl.innerHTML%20=%20initialContent%20%7C%7C%20%5C%22%5C%22;%5Cn%20%20%20%20loadingModalCtn.appendChild(contentEl);%5Cn%20%20%20%20loadingModalCtn.classList.add(%5C%22loadingModalCtn-856246272937%5C%22);%5Cn%20%20%20%20parentElement.appendChild(loadingModalCtn);%5Cn%20%20%20%20return%20%7B%5Cn%20%20%20%20%20%20updateContent:%20function(content)%20%7B%5Cn%20%20%20%20%20%20%20%20contentEl.innerHTML%20=%20content;%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20delete:%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20loadingModalCtn.remove();%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20///////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20%20social/gallery%20button%20stuff%20%20%20%20%20%20%20%20//%5Cn%20%20///////////////////////////////////////////////%5Cn%20%20window.__showSocialsButtonClickHandler98347938%20=%20function()%20%7B%5Cn%20%20%20%20commentsPluginCtn654732.appendChild(window.generateCommentsPluginElement85638294());%5Cn%20%20%20%20imageGalleryCtn8569284.innerHTML%20=%20window.generateImageGalleryHtml358402048();%5Cn%20%20%20%20showHideGalleryAndCommentsButtonsCtn83728732671.style.display%20=%20'';%5Cn%20%20%20%20if(autoShowCheckbox84937483.checked)%20%7B%20localStorage.autoShowSocialsNextTime%20=%20'1';%20%7D;%5Cn%20%20%20%20showSocialsButtonCtn9000274628.remove();%5Cn%20%20%20%20if(thisGeneratorIsUsingClickCountBasedSocialDisplay%20&&%20!localStorage.theyKnowAboutClickCountBasedSocialDisplay)%20%7B%5Cn%20%20%20%20%20%20clickCountBasedSocialDisplayNotifierEl.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20///////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20handler%20for%20generate%20button%20click%20%20%20%20%20//%5Cn%20%20///////////////////////////////////////////////%5Cn%20%20window.___generateButtonClickEvent746291937%20=%20async%20function(event)%20%7B%5Cn%20%20%5Cn%20%20%20%20clearPerchanceErrors();%20//%20in%20case%20they%20has%20errors%20in%20their%20syntax%20in%20their%20last%20attempt,%20we%20don't%20want%20to%20keep%20showing%20the%20error%20bubble%20forever%5Cn%20%20%5Cn%20%20%20%20shareSettingsBtn758374.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20shareLinkCtn83927376.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%5Cn%20%20%20%20generateButtonEl.textContent%20=%20%5C%22%E2%AC%87%EF%B8%8F%20generating...%20%E2%AC%87%EF%B8%8F%5C%22;%5Cn%20%20%20%20generateButtonEl.disabled%20=%20true;%5Cn%20%20%20%20generateButtonEl.style.opacity%20=%200.7;%5Cn%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20generateButtonEl.textContent%20=%20%5C%22%E2%9C%A8%20generate%5C%22;%5Cn%20%20%20%20%20%20generateButtonEl.disabled%20=%20false;%5Cn%20%20%20%20%20%20generateButtonEl.style.opacity%20=%201;%5Cn%20%20%20%20%7D,%203000);%5Cn%20%20%5Cn%20%20%20%20let%20numImages%20=%206;%5Cn%20%20%20%20if(!isNaN(Number(settings.numImages?.evaluateItem)))%20numImages%20=%20Number(settings.numImages?.evaluateItem);%5Cn%20%20%20%20if(isNaN(numImages))%20numImages%20=%206;%5Cn%20%20%20%20%5Cn%20%20%20%20if(numImages%20%3E=%2012)%20%7B%5Cn%20%20%20%20%20%20mainColumnEl85394739.style.maxWidth%20=%20%5C%22100%25%5C%22;%20//%20it's%20set%20to%201000px%20by%20default%20so%203,%206,%209,%20and%2012%20images%20display%20nicely%20as%203%20per%20row,%20but%20at%2012%20or%20more%20on%20wide%20screens%20it's%20fine%20to%20take%20up%20the%20full%20screen%20width%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20mainColumnEl85394739.style.maxWidth%20=%20%5C%221000px%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(!window.___userSettings746291937.imageButtons)%20window.___userSettings746291937.imageButtons%20=%20%7B%7D;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20underEachImageParts%20=%20%5B%5D;%5Cn%20%20%20%20if(window.___userSettings746291937.imageButtons.personality)%20underEachImageParts.push(%60%3Cbutton%20class='personality-chat-button'%20onclick=%5C%22window.t2i_openCharacterDescriptionEditor(this.closest('.t2i-image-ctn'))%5C%22%3E%F0%9F%8E%AD%20persona%20/%20%F0%9F%92%AC%20chat%3C/button%3E%60);%5Cn%20%20%20%20%5Cn%20%20%20%20let%20underEachImageHtml%20=%20%60%3Cdiv%3E$%7BunderEachImageParts.join(%5C%22%5C%22)%7D%3C/div%3E%60;%5Cn%20%20%20%20%5Cn%20%20%20%20if(localStorage.forceColorScheme)%20window.___userSettings746291937.imageOptions.forceColorScheme%20=%20localStorage.forceColorScheme;%5Cn%20%20%20%20outputAreaEl.innerHTML%20=%20%60%3Cdiv%20class=%5C%22t2i-image-ctn%5C%22%20style=%5C%22margin:0.25rem;%20$%7BunderEachImageParts.length%20%3E%200%20?%20%5C%22margin-bottom:0.6rem;%5C%22%20:%20%5C%22%5C%22%7D;%20position:relative;%5C%22%3E%5Bwindow.___textToImagePlugin746291937(window.___userSettings746291937.imageOptions)%5D%3Cdiv%20class=%5C%22t2i-under-each-image-ctn%5C%22%3E$%7BunderEachImageHtml%7D%3C/div%3E%3C/div%3E%60.repeat(numImages).evaluateItem%20+%20(settings.underImagesMessage%20?%20%60%3Cdiv%20style=%5C%22margin-top:0.5rem;flex:0%200%20100%25%5C%22%3E$%7Bsettings.underImagesMessage%7D%3C/div%3E%60%20:%20%5C%22%5C%22);%5Cn%20%20%20%20%5Cn%20%20%20%20let%20generateClickCount%20=%20Number(localStorage.generateClickCount%20%7C%7C%200);%5Cn%20%20%20%20generateClickCount++;%5Cn%20%20%20%20if(isNaN(generateClickCount)%20%7C%7C%20typeof%20generateClickCount%20!==%20%5C%22number%5C%22)%20generateClickCount%20=%201;%5Cn%20%20%20%20localStorage.generateClickCount%20=%20generateClickCount;%5Cn%20%20%20%20%5Cn%20%20%20%20if(window.showSocialFeaturesButtonAfterThisManyClicks%20!==%20undefined%20&&%20generateClickCount%20%3E=%20window.showSocialFeaturesButtonAfterThisManyClicks)%20%7B%5Cn%20%20%20%20%20%20let%20socialButton%20=%20document.querySelector(%5C%22#showSocialsButtonCtn9000274628%5C%22);%5Cn%20%20%20%20%20%20if(socialButton)%20socialButton.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(generateClickCount%20%3E%203)%20%7B%5Cn%20%20%20%20%20%20shareLinkOuterCtn2893827.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(generateClickCount%20%3E%203)%20%7B%5Cn%20%20%20%20%20%20pageTitleEl48759084793.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(generateClickCount%20%3E%209%20&&%20generateClickCount%2510%20===%200)%20%7B%20//%20caution:%20don't%20change%20%2510%20without%20changing%20the%20alert%20condition%20below%5Cn%20%20%20%20%20%20let%20successfullyPersisting%20=%20false;%5Cn%20%20%20%20%20%20let%20errorWhileTryingToPersist%20=%20false;%5Cn%20%20%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20%20%20if(navigator.storage%20&&%20navigator.storage.persist)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20persistent%20=%20await%20navigator.storage.persist();%5Cn%20%20%20%20%20%20%20%20%20%20if(persistent)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20console.log(%5C%22Storage%20will%20not%20be%20cleared%20except%20by%20explicit%20user%20action%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20successfullyPersisting%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20console.log(%5C%22Storage%20may%20be%20cleared%20by%20the%20UA%20under%20storage%20pressure.%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20%20%20errorWhileTryingToPersist%20=%20e;%5Cn%20%20%20%20%20%20%20%20console.error(e);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(!successfullyPersisting)%20%7B%5Cn%20%20%20%20%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20userHasSomeTextTheyAreTryingToRemember%20=%20Object.values(window.___userSettings746291937.userInputs).filter(o%20=%3E%20o.remember%20&&%20o._element.tagName.toLowerCase()%20===%20%5C%22textarea%5C%22).map(o%20=%3E%20o._element.value).join(%5C%22%5C%22).length%20%3E%20100;%5Cn%20%20%20%20%20%20%20%20%20%20if(userHasSomeTextTheyAreTryingToRemember)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20//%20note:%20these%20numbers%20must%20match%20generateClickCount%2510%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(generateClickCount%20===%2020%20%7C%7C%20generateClickCount%20===%2050%20%7C%7C%20generateClickCount%20===%20100%20%7C%7C%20generateClickCount%20===%20200%20%7C%7C%20generateClickCount%20===%20400%20%7C%7C%20generateClickCount%20===%20800)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert(%60Heads%20up:%20Your%20browser%20is%20currently%20not%20allowing%20scratchpad/input%20text%20to%20be%20permanently%20stored/persisted%20between%20page%20visits.%20The%20stored%20text%20may%20eventually%20be%20deleted%20by%20your%20browser.%20This%20could%20be%20because%20you're%20in%20incognito/private%20mode,%20or%20your%20hard%20drive%20is%20nearly%20full,%20or%20because%20the%20web%20browser%20you're%20using%20has%20bugs.%20Chrome%20is%20currently%20best%20browser%20in%20my%20experience%20(fewest%20bugs).%60);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20updateInputVisibilities();%5Cn%20%20%20%20%5Cn%20%20%20%20bottomClickHelperEl.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20leftClickHelperEl.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20rightClickHelperEl.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%7D;%5Cn%20%20%5Cn%20%20function%20generateModifierHtml(modifiers)%20%7B%5Cn%20%20%20%20let%20selectEls%20=%20%5B%5D;%5Cn%20%20%20%20for(let%20modifierName%20of%20modifiers.getAllKeys)%20%7B%5Cn%20%20%20%20%20%20let%20list%20=%20modifiers%5BmodifierName%5D;%5Cn%20%20%20%20%20%20if(!list.getAllKeys)%20continue;%20//%20some%20people%20have%20bugs%20in%20their%20list%20indentation%20etc.%20and%20this%20prevents%20their%20bugs%20from%20breaking%20the%20other%20modifiers%5Cn%20%20%20%20%20%20let%20optionEls%20=%20%5B%5D;%5Cn%20%20%20%20%20%20optionEls.push(%60%3Coption%20value=%5C%22%5C%22%20selected%3EAdd%20$%7BmodifierName%7D...%3C/option%3E%60);%5Cn%20%20%20%20%20%20for(let%20key%20of%20list.getAllKeys)%20%7B%5Cn%20%20%20%20%20%20%20%20optionEls.push(%60%3Coption%20value=%5C%22$%7Blist%5Bkey%5D.evaluateItem.replaceAll(%5C%22%5C%5C%5C%22%5C%22,%20%5C%22&quot;%5C%22)%7D%5C%22%3E$%7Bkey%7D%3C/option%3E%60)%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20selectEls.push(%60%3Cselect%20onchange=%5C%22if(this.value)%20%7B%20this.closest('.input-ctn').querySelector('textarea').value%20+=%20this.value;%20this.value='';%20this.closest('.input-ctn').querySelector('textarea').oninput(%7B%7D);%20let%20o=this.querySelector('option');%20let%20originalFirstItemContent=o.textContent;%20o.textContent='%E2%86%91%20Added%20%E2%86%91';%20setTimeout(()%20=%3E%20o.textContent=originalFirstItemContent,%201000);%20%7D%5C%22%20style=%5C%22margin-right:0.25rem;%20margin-top:0.25rem;%20font-size:80%25;%5C%22%3E$%7BoptionEls.join(%5C%22%5C%22)%7D%3C/select%3E%60);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20return%20selectEls.join(%5C%22%5C%22);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20initHandlers%20=%20%5B%5D;%5Cn%5Cn%20%20////////////////////////////////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20generate%20the%20HTML%20based%20on%20the%20specified%20userInputs%20list%20items%20%20%20%20%20//%5Cn%20%20////////////////////////////////////////////////////////////////////////////%5Cn%20%20let%20userInputsHtml%20=%20settings.userInputs.selectAll.map(item%20=%3E%20%7B%5Cn%20%20%5Cn%20%20%20%20let%20tipText%20=%20item.tip?.evaluateItem.trim();%5Cn%20%20%20%20if(tipText)%20tipText%20=%20tipText.replace(/%5C%22/g,%20%5C%22&quot;%5C%22);%5Cn%20%20%5Cn%20%20%20%20if(item.type%20===%20%5C%22text%5C%22)%20%7B%5Cn%20%20%20%20%20%20let%20widthStyle%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20if(item.width)%20widthStyle%20+=%20%60width:$%7Bitem.width%7D;%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20keyUpKeyDownAttributes%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20if(item.enterKeyTriggersGeneration)%20%7B%5Cn%20%20%20%20%20%20%20%20keyUpKeyDownAttributes%20=%20%60onkeyup=%5C%22if(event.which%20===%2013%20&&%20!event.shiftKey)%20%7B%20document.querySelector('#generateButtonEl').click();%20%7D%5C%22%20onkeydown=%5C%22if(event.which%20===%2013%20&&%20!event.shiftKey)%20%7B%20event.preventDefault();%20%7D%5C%22%60;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20foldToggleState%20=%20item.foldToggleState;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20html%20=%20%60%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-ctn%20input-type-text%20$%7Bitem.takesUpFullRow%20?%20%5C%22takesUpFullRow%5C%22%20:%20%5C%22%5C%22%7D%5C%22%20data-fold-toggle-state=%5C%22$%7BfoldToggleState%7D%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-inner%5C%22%20style=%5C%22$%7BwidthStyle%7D%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-label%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20style=%5C%22width:max-content;%5C%22%3E$%7Bitem.label%20%7C%7C%20item.getName.sentenceCase%7D%3C/span%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7BtipText%20?%20%60%20%3Cspan%20class=%5C%22input-tip-btn%5C%22%20title=%5C%22$%7BtipText%7D%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%93%98%3C/span%3E%60%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7BfoldToggleState%20===%20undefined%20?%20%5C%22%5C%22%20:%20%60%3Cbutton%20onclick=%5C%22let%20s%20=%20this.closest('.input-ctn').dataset.foldToggleState;%20if(s==='hidden')%20%7B%20this.closest('.input-ctn').dataset.foldToggleState='shown';%20%7D%20else%20%7B%20this.closest('.input-ctn').dataset.foldToggleState='hidden';%20%7D%5C%22%20class=%5C%22input-toggle-button%5C%22%3E%3C/button%3E%60%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-wrapper%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22width:100%25;%20position:relative;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20style=%5C%22$%7Bitem.autoSuggest%20?%20%5C%22%5C%22%20:%20%5C%22display:none;%5C%22%7D%5C%22%20class=%5C%22auto-suggest-btn%5C%22%3E%F0%9F%92%AD%3C/span%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20style=%5C%22$%7Bitem.autoSuggest%20?%20%5C%22%5C%22%20:%20%5C%22padding-right:0;%5C%22%7D%5C%22%20class=%5C%22text-input%5C%22%20data-name=%5C%22$%7Bitem.getName%7D%5C%22%20type=%5C%22text%5C%22%20oninput=%5C%22window.___inputElInputEvent746291937.bind(this)(event);%5C%22%20$%7BkeyUpKeyDownAttributes%7D%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7Bitem.random%20?%20%60%3Cdiv%20class=%5C%22random-input-btn-ctn%5C%22%20data-input-name=%5C%22$%7Bitem.getName%7D%5C%22%3E%3Cbutton%3E%F0%9F%8E%B2%3C/button%3E%3C/div%3E%60%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20return%20html;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(item.type%20===%20%5C%22paragraph%5C%22)%20%7B%5Cn%20%20%20%20%20%20let%20widthStyle%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20if(item.width)%20widthStyle%20+=%20%60width:$%7Bitem.width%7D;%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20textareaStyle%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20let%20height%20=%20%5C%224rem%5C%22;%5Cn%20%20%20%20%20%20if(item.height)%20%7B%5Cn%20%20%20%20%20%20%20%20height%20=%20%60$%7Bitem.height%7D%60;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20if(window.innerWidth%20%3C%20550)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20height%20=%20%5C%226rem%5C%22;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20textareaStyle%20+=%20%60height:$%7Bheight%7D;%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20foldToggleState%20=%20item.foldToggleState;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20keyUpKeyDownAttributes%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20if(item.enterKeyTriggersGeneration)%20%7B%5Cn%20%20%20%20%20%20%20%20keyUpKeyDownAttributes%20=%20%60onkeyup=%5C%22if(event.which%20===%2013%20&&%20!event.shiftKey)%20%7B%20document.querySelector('#generateButtonEl').click();%20%7D%5C%22%20onkeydown=%5C%22if(event.which%20===%2013%20&&%20!event.shiftKey)%20%7B%20event.preventDefault();%20%7D%5C%22%60;%5Cn%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20let%20modifiersHtml%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20try%20%7B%20//%20try/catch%20just%20while%20testing%20this%5Cn%20%20%20%20%20%20%20%20let%20modifiersContainerId%20=%20%5C%22id%5C%22+Math.random().toString().replace(%5C%22.%5C%22,%20%5C%22%5C%22)+Math.random().toString().replace(%5C%22.%5C%22,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20modifiersHtml%20=%20%60%3Cdiv%20id=%5C%22$%7BmodifiersContainerId%7D%5C%22%20class=%5C%22input-modifiers%5C%22%20style=%5C%22display:flex;flex-wrap:%20wrap;%5C%22%3E$%7Bitem.modifiers%20?%20generateModifierHtml(item.modifiers)%20:%20%5C%22%5C%22%7D%3C/div%3E%60;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(item.modifierUpdates)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20handlers%20=%20item.modifierUpdates.evaluateItem.split(%5C%22,%5C%22).map(h%20=%3E%20h.trim()).filter(h%20=%3E%20h.startsWith(%5C%22event:%5C%22)).map(h%20=%3E%20h.replace(/%5Eevent:/,%20%5C%22%5C%22).split(%5C%22.%5C%22)).map(a%20=%3E%20(%7BinputName:a%5B0%5D,%20eventName:a%5B1%5D%7D));%5Cn%20%20%20%20%20%20%20%20%20%20for(let%20h%20of%20handlers)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20handlerFunction%20=%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20document.querySelector(%60#$%7BmodifiersContainerId%7D%60).innerHTML%20=%20item.modifiers%20?%20generateModifierHtml(item.modifiers)%20:%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20initHandlers.push(%7BinputName:h.inputName,%20eventName:h.eventName,%20handler:handlerFunction%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20%20%20console.log(e);%5Cn%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20let%20html%20=%20%60%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-ctn%20input-type-paragraph%20$%7Bitem.takesUpFullRow%20?%20%5C%22takesUpFullRow%5C%22%20:%20%5C%22%5C%22%7D%5C%22%20data-fold-toggle-state=%5C%22$%7BfoldToggleState%7D%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-inner%5C%22%20style=%5C%22$%7BwidthStyle%7D%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-label%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20style=%5C%22width:max-content;%5C%22%3E$%7Bitem.label%20%7C%7C%20item.getName.sentenceCase%7D%3C/span%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7BtipText%20?%20%60%20%3Cspan%20class=%5C%22input-tip-btn%5C%22%20title=%5C%22$%7BtipText%7D%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%93%98%3C/span%3E%60%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7BfoldToggleState%20===%20undefined%20?%20%5C%22%5C%22%20:%20%60%3Cbutton%20onclick=%5C%22let%20s%20=%20this.closest('.input-ctn').dataset.foldToggleState;%20if(s==='hidden')%20%7B%20this.closest('.input-ctn').dataset.foldToggleState='shown';%20%7D%20else%20%7B%20this.closest('.input-ctn').dataset.foldToggleState='hidden';%20%7D%5C%22%20class=%5C%22input-toggle-button%5C%22%3E%3C/button%3E%60%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-wrapper%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22width:100%25;%20position:relative;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20style=%5C%22$%7Bitem.autoSuggest%20?%20%5C%22%5C%22%20:%20%5C%22display:none;%5C%22%7D%5C%22%20class=%5C%22auto-suggest-btn%5C%22%3E%F0%9F%92%AD%3C/span%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctextarea%20style=%5C%22$%7Bitem.autoSuggest%20?%20%5C%22%5C%22%20:%20%5C%22padding-right:0;%5C%22%7D%20$%7BtextareaStyle%7D%5C%22%20class=%5C%22paragraph-input%5C%22%20data-name=%5C%22$%7Bitem.getName%7D%5C%22%20oninput=%5C%22window.___inputElInputEvent746291937.bind(this)(event);%5C%22%20$%7BkeyUpKeyDownAttributes%7D%3E%3C/textarea%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7Bitem.random%20?%20%60%3Cdiv%20class=%5C%22random-input-btn-ctn%5C%22%20data-input-name=%5C%22$%7Bitem.getName%7D%5C%22%3E%3Cbutton%20class=%5C%22random-input-btn%5C%22%3E%F0%9F%8E%B2%3C/button%3E%3Cbutton%20class=%5C%22ai-suggest-btn%5C%22%20style=%5C%22margin-top:0.25rem;%5C%22%3E%F0%9F%A7%A0%3C/button%3E%3C/div%3E%60%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20$%7BmodifiersHtml%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20return%20html;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(item.type%20===%20%5C%22select%5C%22%20%7C%7C%20item.type%20===%20%5C%22visual-select%5C%22)%20%7B%5Cn%20%20%20%20%20%20let%20options%20=%20%5B%5D;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20thereAreImports%20=%20false;%5Cn%20%20%20%20%20%20item.compiledOptions%20=%20new%20Map();%20//%20use%20map%20to%20maintain%20insertion%20order%20when%20converting%20to%20%60entries%60%5Cn%20%20%20%20%20%20let%20nameToForcedPosition%20=%20%7B%7D;%5Cn%20%20%20%20%20%20let%20groupIndex%20=%20-1;%20//%20all%20items%20within%20an%20import%20have%20the%20same%20group%20index%20and%20normally-defined%20items%20are%20their%20own%20single-item%20group%20-%20this%20is%20so%20we%20can%20properly%20do%20sorting%20at%20the%20end,%20so%20that%20all%20imports%20are%20only%20sorted%20within%20their%20group.%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20for(let%20key%20of%20item.options.getAllKeys)%20%7B%5Cn%20%20%20%20%20%20%20%20groupIndex++;%5Cn%20%20%20%20%20%20%20%20if(key.startsWith(%5C%22meta:import%5C%22))%20%7B%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20thereAreImports%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20let%20tagImportWeights%20=%20%7B%7D;%5Cn%20%20%20%20%20%20%20%20%20%20if(item.options%5Bkey%5D.tagWeights)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20tagImportWeights%20=%20Object.fromEntries(item.options%5Bkey%5D.tagWeights.evaluateItem.split(%5C%22,%5C%22).map(t%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20tag%20=%20t.split(%5C%22:%5C%22)%5B0%5D.trim();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20factor%20=%20Number(t.split(%5C%22:%5C%22)%5B1%5D%20??%2010);%20//%20default%20boost%20is%2010.%20note%20that%20'boost'%20can%20be%20less%20than%201,%20which%20supresses%20the%20tag,%20and%20can%20even%20be%200,%20which%20filters%20out%20items%20with%20that%20tag%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(isNaN(factor))%20factor%20=%2010;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%5Btag,%20factor%5D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D));%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20let%20intraGroupSortingEpsilon%20=%200.00001;%20//%20%3C--%20just%20a%20little%20hack%20so%20that%20the%20imports%20that%20have%20the%20same%20score%20stay%20in%20the%20order%20in%20which%20they%20were%20defined%20in%20the%20imported%20list%5Cn%20%20%20%20%20%20%20%20%20%20for(let%20optionItem%20of%20item.options%5Bkey%5D.from.selectAll)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(item.compiledOptions.has(optionItem.getName))%20continue;%20//%20we%20don't%20overwrite%20ones%20that%20came%20before%20(higher%20takes%20precedence%20over%20lower)%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20optionItem.___groupIndex%20=%20groupIndex;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20item.compiledOptions.set(optionItem.getName,%20optionItem);%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(optionItem%5B%5C%22meta:position%5C%22%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20nameToForcedPosition%5BoptionItem.getName%5D%20=%20optionItem%5B%5C%22meta:position%5C%22%5D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(optionItem%5B%5C%22meta:tags%5C%22%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20for%20each%20importer%20tag%20weight,%20we%20multiply%20it%20by%20the%20matching%20'inherent'%20weight%20of%20the%20tag%20(if%20it%20exists%20on%20this%20imported%20item).%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20note%20that%20this%20means%20that%20if%20there%20are%20*any*%20matches,%20then%20ONLY%20those%20matches%20are%20considered.%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20optionItem.___intraGroupRankingScore%20=%200;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20thereWereTagWeightMatches%20=%20false;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20for(let%20%5Btag,%20inherentTagWeight%5D%20of%20Object.entries(optionItem%5B%5C%22meta:tags%5C%22%5D))%20%7B%20//%20for%20each%20tag%20on%20this%20imported%20item%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(tagImportWeights%5Btag%5D%20!==%20undefined)%20%7B%20//%20if%20the%20importer%20has%20specified%20a%20weight%20for%20this%20tag%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20thereWereTagWeightMatches%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20optionItem.___intraGroupRankingScore%20+=%20inherentTagWeight*tagImportWeights%5Btag%5D;%20//%20add%20to%20the%20score%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20if%20this%20imported%20style%20didn't%20have%20any%20tags%20that%20matched%20any%20of%20the%20importer%20tag%20weights,%20then%20we%20set%20its%20ranking%20score%20to%201%20+%20a%20small%20amount%20based%20on%20the%20mean%20of%20its%20inherent%20tag%20weights:%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(!thereWereTagWeightMatches)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20inherentTagWeights%20=%20Object.values(optionItem%5B%5C%22meta:tags%5C%22%5D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20EDIT:%20the%20problem%20with%20this%20is%20that%20it%20separates%20'categories'%20of%20styles%20which%20are%20better%20defined%20together%20-%20e.g.%20if%20all%20the%20anime%20styles%20are%20defined%20one%20after%20the%20other,%20then%20it's%20better%20to%20leave%20them%20like%20that%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20so%20for%20now%20I'm%20just%20going%20to%20set%20the%20score%20to%201%20if%20there%20were%20no%20matching%20tags.%20Can%20change%20this%20in%20v3%20if%20needed.%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20optionItem.___intraGroupRankingScore%20=%201;%20//%20+%20(inherentTagWeights.reduce((a,v)%20=%3E%20a+v,%200)%20/%20inherentTagWeights.length)%20/%2010000;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20optionItem.___intraGroupRankingScore%20=%201;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20optionItem.___intraGroupRankingScore%20+=%20intraGroupSortingEpsilon;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20intraGroupSortingEpsilon%20-=%20intraGroupSortingEpsilon*0.00001;%20//%20so%20the%20next%20item%20will%20get%20a%20slightly%20smaller%20boost%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20item.options%5Bkey%5D.___groupIndex%20=%20groupIndex;%5Cn%20%20%20%20%20%20%20%20%20%20item.options%5Bkey%5D.___intraGroupRankingScore%20=%201;%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20item.compiledOptions.set(key,%20item.options%5Bkey%5D);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20if(item.options%5Bkey%5D%5B%5C%22meta:position%5C%22%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20nameToForcedPosition%5Bkey%5D%20=%20item.options%5Bkey%5D%5B%5C%22meta:position%5C%22%5D;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20entries%20=%20%5B...item.compiledOptions.entries()%5D;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(thereAreImports)%20%7B%5Cn%20%20%20%20%20%20%20%20//%20filter%20out%20items%20with%20a%20score%20below%20or%20equal%20to%20zero%5Cn%20%20%20%20%20%20%20%20entries%20=%20entries.filter(e%20=%3E%20e%5B1%5D.___intraGroupRankingScore%20%3E%200);%5Cn%5Cn%20%20%20%20%20%20%20%20//%20here%20we%20do%20score-based%20ordering%20while%20strictly%20maintaining%20group%20index%20ordering.%5Cn%20%20%20%20%20%20%20%20//%20note%20that%20items%20from%20a%20meta:import%20are%20all%20part%20of%20their%20own%20group,%20whereas%20items%20that%20are%20defined%20normally%20are%20their%20own%20single-item%20group.%5Cn%20%20%20%20%20%20%20%20entries.sort((a,%20b)%20=%3E%20a%5B1%5D.___groupIndex%20-%20b%5B1%5D.___groupIndex%20%7C%7C%20b%5B1%5D.___intraGroupRankingScore%20-%20a%5B1%5D.___intraGroupRankingScore);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20do%20forced%20positioning:%5Cn%20%20%20%20%20%20for(let%20%5Bname,%20position%5D%20of%20Object.entries(nameToForcedPosition))%20%7B%5Cn%20%20%20%20%20%20%20%20let%20index%20=%20entries.findIndex((%5Bkey%5D)%20=%3E%20key%20===%20name);%5Cn%20%20%20%20%20%20%20%20if(index%20!==%20-1)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20%5Bremoved%5D%20=%20entries.splice(index,%201);%20//%20remove%20the%20item%20from%20its%20current%20position%5Cn%20%20%20%20%20%20%20%20%20%20entries.splice(position,%200,%20removed);%20//%20insert%20it%20into%20the%20desired%20position%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20item.compiledOptions%20=%20Object.fromEntries(entries);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20options.push(...entries.map((%5Bname,%20obj%5D)%20=%3E%20name).map(n%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20let%20hasSubKeys%20=%20false;%5Cn%20%20%20%20%20%20%20%20if(item.compiledOptions%5Bn%5D.getAllKeys%20&&%20item.compiledOptions%5Bn%5D.getAllKeys.length%20%3E%200)%20hasSubKeys%20=%20true;%20//%20hasSubKeys%20is%20needed%20because%20if%20it%20does%20have%20subkeys,%20then%20we%20expose%20the%20whole%20option%20object/node%20as%20%60keyName%60,%20rather%20than%20just%20the%20value%5Cn%20%20%20%20%20%20%20%20let%20keyName%20=%20n;%5Cn%20%20%20%20%20%20%20%20let%20display%20=%20item.compiledOptions%5Bn%5D.name%20??%20n;%5Cn%20%20%20%20%20%20%20%20let%20value%20=%20item.compiledOptions%5Bn%5D;%5Cn%20%20%20%20%20%20%20%20return%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20value,%5Cn%20%20%20%20%20%20%20%20%20%20display,%5Cn%20%20%20%20%20%20%20%20%20%20keyName:n,%5Cn%20%20%20%20%20%20%20%20%20%20hasSubKeys,%5Cn%20%20%20%20%20%20%20%20%20%20disabled:%20item.compiledOptions%5Bn%5D%5B%5C%22meta:disabled%5C%22%5D%20===%20true,%5Cn%20%20%20%20%20%20%20%20%20%20image:%20item.compiledOptions%5Bn%5D%5B%5C%22meta:image%5C%22%5D,%5Cn%20%20%20%20%20%20%20%20%20%20selected:%20item.compiledOptions%5Bn%5D%5B%5C%22meta:selected%5C%22%5D%20===%20true,%5Cn%20%20%20%20%20%20%20%20%7D;%20%5Cn%20%20%20%20%20%20%7D));%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20selectedOpt%20=%20options.find(opt%20=%3E%20opt.selected);%5Cn%20%20%20%20%20%20if(!selectedOpt)%20options%5B0%5D.selected%20=%20true;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20selectElHtml%20=%20%60%5Cn%20%20%20%20%20%20%20%20%3Cselect%20style=%5C%22$%7Bitem.type%20===%20%5C%22visual-select%5C%22%20?%20%5C%22display:none;%5C%22%20:%20%5C%22%5C%22%7D%20width:-webkit-fill-available;%20width:-moz-available;%20width:fill-available;%20max-width:9rem;%5C%22%20data-name=%5C%22$%7Bitem.getName%7D%5C%22%20onchange=%5C%22window.___selectElChangeEvent746291937.bind(this)(event);%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20$%7Boptions.map(opt%20=%3E%20%60%3Coption%20value=%5C%22$%7Bopt.hasSubKeys%20?%20%60ref:optionKeyName:$%7Bopt.keyName%7D%60%20:%20opt.value%7D%5C%22%20$%7Bopt.disabled%20?%20%5C%22disabled%5C%22%20:%20%5C%22%5C%22%7D%20%20$%7Bopt.selected%20?%20%5C%22selected%5C%22%20:%20%5C%22%5C%22%7D%3E$%7Bopt.display%7D%3C/option%3E%60).join(%5C%22%5C%5Cn%5C%22)%7D%5Cn%20%20%20%20%20%20%20%20%3C/select%3E%5Cn%20%20%20%20%20%20%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20the%20visual%20select%20is%20just%20a%20%5C%22facade%5C%22%20over%20the%20top%20of%20a%20normal%20(hidden)%20select%20-%20the%20underlying%20%3Cselect%3E%20is%20still%20used%20for%20all%20relevant%20logic%5Cn%20%20%20%20%20%20if(item.type%20===%20%5C%22visual-select%5C%22)%20%7B%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20let%20visualSelectOptions%20=%20options.map(opt%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20visualHtml;%5Cn%20%20%20%20%20%20%20%20%20%20if(false%20&&%20opt.image)%20%7B%20//%20TODO:%20work%20out%20the%20best%20approach%20here%20(e.g.%20grid%20+%20%5C%22slideshow%5C%22%20for%20each%20style?)%20and%20then%20enabled%20this%5Cn%20%20%20%20%20%20%20%20%20%20%20%20visualHtml%20=%20%60%3Cimg%20src=%5C%22$%7Bopt.image%7D%5C%22%20style=%5C%22max-height:20vh;%20display:block;%5C%22%3E%3Cdiv%20style=%5C%22font-size:85%25;position:%20sticky;bottom:%202rem;left:0;right:0;width:100%25;height:%200;text-align:center;%5C%22%3E%3Cspan%20style=%5C%22background:#ffffff;%20padding:0.25rem;%20border:2px%20solid%20black;%20border-radius:0.25rem;%20color:black;%5C%22%3E$%7Bopt.display%7D%3C/span%3E%3C/div%3E%60;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(!window.__preloadedVisualSelectImageUrls_957378)%20window.__preloadedVisualSelectImageUrls_957378%20=%20%7B%7D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(!window.__preloadedVisualSelectImageUrls_957378%5Bopt.image%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20img%20=%20document.createElement(%5C%22img%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20img.src%20=%20opt.image;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20img.style.cssText%20=%20%60position:fixed;%20width:1px;%20height:1px;%20left:-10px;%20top:-10px;%60;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20document.body.appendChild(img);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20window.__preloadedVisualSelectImageUrls_957378%5Bopt.image%5D%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20visualHtml%20=%20%60%3Cdiv%20style=%5C%22display:flex;%20justify-content:center;%20align-items:center;%20min-height:3rem;%5C%22%3E$%7Bopt.display%7D%3C/div%3E%60;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20return%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20value:%20opt.hasSubKeys%20?%20%60ref:optionKeyName:$%7Bopt.keyName%7D%60%20:%20opt.value,%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20disabled:%20opt.disabled,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20selected:%20opt.selected,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20html:%20%60%3Cdiv%20style=%5C%22border-radius:3px;%20overflow:hidden;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22overflow-x:auto;%20overflow-y:hidden;%20position:relative;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7BvisualHtml%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%60,%5Cn%20%20%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%20%20selectElHtml%20=%20%60%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22visual-select-btn%5C%22%20style=%5C%22width:max-content;%5C%22%20onclick=%5C%22window.__createSelectorModal_56974639274(JSON.parse(decodeURIComponent(this.dataset.options))).then(v%20=%3E%20%7B%20if(v%20!==%20null)%20%7B%20let%20selectEl%20=%20this.parentElement.querySelector('select');%20selectEl.value=v;%20selectEl.onchange(%7B%7D);%20%7D%20%7D)%5C%22%20data-options=%5C%22$%7BencodeURIComponent(JSON.stringify(visualSelectOptions))%7D%5C%22%3E$%7Boptions.find(opt%20=%3E%20opt.selected).display%7D%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%20%20$%7BselectElHtml%7D%5Cn%20%20%20%20%20%20%20%20%60;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20html%20=%20%60%3Cdiv%20class=%5C%22input-ctn%20input-type-select%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-inner%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-label%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20style=%5C%22width:max-content;%5C%22%3E$%7Bitem.label%20%7C%7C%20item.getName.sentenceCase%7D%3C/span%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20$%7BtipText%20?%20%60%20%3Cspan%20class=%5C%22input-tip-btn%5C%22%20title=%5C%22$%7BtipText%7D%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%93%98%3C/span%3E%60%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22input-wrapper%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20$%7BselectElHtml%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%3C/div%3E%60;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(item.takesUpFullRow)%20%7B%5Cn%20%20%20%20%20%20%20%20html%20=%20%60%3Cdiv%20style=%5C%22width:100%25;%20display:flex;%20align-items:center;%20justify-content:center;%5C%22%3E$%7Bhtml%7D%3C/div%3E%60;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20return%20html;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20%5Cn%20%20%7D).join(%5C%22%5C%5Cn%5C%22);%5Cn%20%20%5Cn%20%20window.getCurrentColorScheme%20=%20function()%20%7B%5Cn%20%20%20%20if(localStorage.forceColorScheme%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20return%20localStorage.forceColorScheme;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20return%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20window.toggleManualDarkMode_jv83hb27igksf%20=%20function()%20%7B%5Cn%20%20%20%20//%20get%20current%20mode:%5Cn%20%20%20%20let%20colorScheme%20=%20window.getCurrentColorScheme();%5Cn%20%20%20%20%5Cn%20%20%20%20//%20change%20mode:%5Cn%20%20%20%20let%20newColorScheme%20=%20(colorScheme%20===%20%5C%22dark%5C%22%20?%20%5C%22light%5C%22%20:%20%5C%22dark%5C%22);%5Cn%20%20%20%20localStorage.forceColorScheme%20=%20newColorScheme;%5Cn%20%20%20%20setColorScheme(newColorScheme);%5Cn%20%20%20%20%5Cn%20%20%20%20//%20if%20chosen%20mode%20matches%20current%20OS%20default,%20we%20remove%20manual%20%5C%22forced%5C%22%20mode:%5Cn%20%20%20%20let%20systemColorScheme%20=%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22;%5Cn%20%20%20%20if(systemColorScheme%20===%20newColorScheme)%20%7B%5Cn%20%20%20%20%20%20localStorage.removeItem(%5C%22forceColorScheme%5C%22);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20//%20regenerate%20comments%20and%20gallery%20(to%20propagate%20forceColorScheme%20if%20needed)%5Cn%20%20%20%20if(imageGalleryCtn8569284.querySelector(%5C%22iframe%5C%22))%20%7B%5Cn%20%20%20%20%20%20imageGalleryCtn8569284.innerHTML%20=%20%5C%22%5C%22;%20//%20need%20to%20clear%20it%20first%20because%20text-to-image%20plugin%20returns%20%5C%22%5C%22%20for%20gallery%20if%20one%20already%20exists%20(it's%20doing%20a%20hacky%20thing%20to%20prevent%20update()%20from%20reloading%20the%20gallery)%5Cn%20%20%20%20%20%20imageGalleryCtn8569284.innerHTML%20=%20window.generateImageGalleryHtml358402048();%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(commentsPluginCtn654732.querySelector(%5C%22iframe%5C%22))%20%7B%5Cn%20%20%20%20%20%20commentsPluginCtn654732.innerHTML%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20commentsPluginCtn654732.appendChild(window.generateCommentsPluginElement85638294())%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20function%20setColorScheme(scheme)%20%7B%5Cn%20%20%20%20if(scheme%20!==%20%5C%22dark%5C%22%20&&%20scheme%20!==%20%5C%22light%5C%22)%20throw%20new%20Error(%5C%22scheme%20should%20be%20'light'%20or%20'dark'%5C%22);%5Cn%20%20%20%20document.querySelector(%5C%22#darkModeBtn_875979f948%5C%22).textContent%20=%20(scheme%20===%20%5C%22dark%5C%22%20?%20%5C%22%F0%9F%8C%84%5C%22%20:%20%5C%22%F0%9F%8C%83%5C%22);%5Cn%20%20%20%20if(scheme%20===%20%5C%22dark%5C%22)%20%7B%5Cn%20%20%20%20%20%20document.documentElement.style.colorScheme%20=%20%5C%22dark%5C%22;%5Cn%20%20%20%20%20%20document.body.style.color%20=%20%5C%22#d8d4cf%5C%22;%5Cn%20%20%20%20%20%20document.body.style.backgroundColor%20=%20%5C%22#131516%5C%22;%5Cn%20%20%20%20%20%20document.documentElement.style.setProperty('--box-color',%20'#2a2a2a');%20//%20CAUTION!!!!%20--%3E%20do%20not%20rename%20this%20variable%20-%20it%20is%20being%20used%20in%20%5C%22user-land%5C%22%20on%20some%20generators%5Cn%20%20%20%20%20%20document.documentElement.style.setProperty('--active-comment-channel-tab-color',%20'#5b5b5b');%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20document.documentElement.style.colorScheme%20=%20%5C%22light%5C%22;%5Cn%20%20%20%20%20%20document.body.style.color%20=%20%5C%22black%5C%22;%5Cn%20%20%20%20%20%20document.body.style.backgroundColor%20=%20%5C%22white%5C%22;%5Cn%20%20%20%20%20%20document.documentElement.style.setProperty('--box-color',%20'#ebebeb');%5Cn%20%20%20%20%20%20document.documentElement.style.setProperty('--active-comment-channel-tab-color',%20'#c6c6c6');%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20///////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20do%20some%20stuff%20after%20page%20loads%20%20%20%20%20//%5Cn%20%20///////////////////////////////////////////%5Cn%20%20window.___pageLoadHandler746291937%20=%20function()%20%7B%5Cn%20%20%20%20%5Cn%20%20%20%20//%20let%20pageUrlIsShareLink%20=%20window.location.hash.slice(1).startsWith(%5C%22data=%5C%22);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20//%20during%20page%20load,%20set%20the%20chosen%20mode%20based%20on%20localStorage%20value%20if%20it%20exists:%5Cn%20%20%20%20if(localStorage.forceColorScheme%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20setColorScheme(localStorage.forceColorScheme);%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20//%20user%20has%20not%20manually%20overwritten,%20so%20we%20use%20OS%20default:%5Cn%20%20%20%20%20%20let%20systemIsInDarkMode%20=%20!!(window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches);%5Cn%20%20%20%20%20%20setColorScheme(systemIsInDarkMode%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(socialFeatures%20===%20%5C%22enabled%5C%22)%20%7B%5Cn%20%20%20%20%20%20commentsPluginCtn654732.appendChild(window.generateCommentsPluginElement85638294());%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20let%20generateClickCount%20=%20localStorage.generateClickCount%20?%20Number(localStorage.generateClickCount)%20:%200;%5Cn%20%20%20%20%5Cn%20%20%20%20if(thisGeneratorIsUsingClickCountBasedSocialDisplay%20&&%20!localStorage.theyKnowAboutClickCountBasedSocialDisplay)%20%7B%5Cn%20%20%20%20%20%20//%20clickCountBasedSocialDisplayNotifierEl.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(generateClickCount%20===%200)%20%7B%5Cn%20%20%20%20%20%20bottomClickHelperEl.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20leftClickHelperEl.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20rightClickHelperEl.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(generateClickCount%20%3E%203)%20%7B%5Cn%20%20%20%20%20%20shareLinkOuterCtn2893827.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20//%20Do%20init%20stuff%20like%20triggering%20oninput/onchange%20for%20each%20input%20right%20after%20init.%5Cn%20%20%20%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(localStorage.autoShowSocialsNextTime%20&&%20document.querySelector(%5C%22#showSocialsButton927514532%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20document.querySelector(%5C%22#showSocialsButton927514532%5C%22).click();%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20userInputsCtn8462746262.querySelectorAll('input,%20select,%20textarea').forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20let%20userInputSpec%20=%20window.___userSettings746291937.userInputs%5Bel.dataset.name%5D;%5Cn%20%20%20%20%20%20%20%20userInputSpec._element%20=%20el;%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20for(let%20h%20of%20initHandlers)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20element%20=%20window.___userSettings746291937.userInputs%5Bh.inputName%5D._element;%5Cn%20%20%20%20%20%20%20%20element.addEventListener(h.eventName,%20h.handler);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20set%20initial%20values%5Cn%20%20%20%20%20%20userInputsCtn8462746262.querySelectorAll('input,%20select,%20textarea').forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20let%20userInputSpec%20=%20window.___userSettings746291937.userInputs%5Bel.dataset.name%5D;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20let%20value;%5Cn%20%20%20%20%20%20%20%20if(userInputSpec.remember)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20value%20=%20getRememberedInput(el.dataset.name);%5Cn%20%20%20%20%20%20%20%20%7D%20else%20if(el.tagName%20===%20%5C%22TEXTAREA%5C%22%20%7C%7C%20(el.tagName%20===%20%5C%22INPUT%5C%22%20&&%20el.type%20===%20%5C%22text%5C%22))%20%7B%20//%20%3C--%20just%20to%20be%20sure%5Cn%20%20%20%20%20%20%20%20%20%20//%20value%20=%20localStorage%5B%5C%22t2i_tempRememberedInput_fisuyr9hf_%5C%22+el.dataset.name%5D;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(value%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20el.value%20=%20value;%5Cn%20%20%20%20%20%20%20%20%20%20//%20%3Cselect%3E%20options%20can%20be%20removed%20by%20gen%20authors,%20so%20if%20the%20option%20doesn't%20exist,%20we%20just%20set%20it%20to%20the%20first%20option:%5Cn%20%20%20%20%20%20%20%20%20%20if((userInputSpec.type%20===%20%5C%22select%5C%22%20%7C%7C%20userInputSpec.type%20===%20%5C%22visual-select%5C%22)%20&&%20userInputSpec.compiledOptions%5Bvalue.replace(/%5Eref:optionKeyName:/,%20%5C%22%5C%22)%5D%20===%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20el.value%20=%20el.querySelector(%5C%22option%5C%22).value;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20//%20NOTE:%20triggering%20change/input%20events%20like%20this%20doesn't%20trigger%20addEventListener%20handlers%20-%20like%20those%20added%20via%20initHandlers,%20above,%20but%5Cn%20%20%20%20%20%20%20%20//%20for%20now%20this%20is%20a%20happy%20accident%20because%20it's%20not%20for%20modifiers%20to%20not%20show%20up%20until%20you've%20actually%20typed%20something%20-%20reduces%20UI%5Cn%20%20%20%20%20%20%20%20//%20complexity%20on%20first%20impression.%5Cn%20%20%20%20%20%20%20%20if(el.onchange)%20el.onchange(%7B_isInitCall:true%7D);%5Cn%20%20%20%20%20%20%20%20if(el.oninput)%20el.oninput(%7B_isInitCall:true%7D);%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20updateInputVisibilities();%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20set%20up%20intervals%20for%20the%20rotating%20'example'%20placeholders%5Cn%20%20%20%20%20%20userInputsCtn8462746262.querySelectorAll('input,%20select,%20textarea').forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20let%20userInputSpec%20=%20window.___userSettings746291937.userInputs%5Bel.dataset.name%5D;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20let%20examplesList%20=%20userInputSpec.examples;%5Cn%20%20%20%20%20%20%20%20if(examplesList%20&&%20((el.nodeName%20===%20%5C%22INPUT%5C%22%20&&%20el.type%20===%20%5C%22text%5C%22)%20%7C%7C%20el.nodeName%20===%20%5C%22TEXTAREA%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20set%20rotating%20placeholder%20text%20on%20text%20inputs%5Cn%20%20%20%20%20%20%20%20%20%20function%20nextExample()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(userInputSpec.useVariables%20&&%20window%5Bel.dataset.name.toUpperCase()%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20window.ignorePerchanceErrors(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20el.placeholder%20=%20window%5Bel.dataset.name.toUpperCase()%5D.evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20text%20=%20selectLeaf(examplesList).evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20try%20a%20few%20times%20to%20get%20a%20different%20one%20to%20the%20last-displayed%20one:%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(text%20===%20el.placeholder)%20text%20=%20selectLeaf(examplesList).evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(text%20===%20el.placeholder)%20text%20=%20selectLeaf(examplesList).evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(text%20===%20el.placeholder)%20text%20=%20selectLeaf(examplesList).evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20simple%20hack%20to%20save%20me%20a%20headache%20with%20escaping%20(e.g.%20for%20scratchpad%20placholder%20text)%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%20=%20text.replace(/&lsqb;/g,%20%5C%22%5B%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%20=%20text.replace(/&rsqb;/g,%20%5C%22%5D%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%20=%20text.replace(/&lcub;/g,%20%5C%22%7B%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%20=%20text.replace(/&rcub;/g,%20%5C%22%7D%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20el.placeholder%20=%20text;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20nextExample();%5Cn%20%20%20%20%20%20%20%20%20%20setInterval(nextExample,%203500);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20set%20up%20click%20handlers%20for%20the%20'random'%20buttons:%5Cn%20%20%20%20%20%20userInputsCtn8462746262.querySelectorAll('.random-input-btn-ctn').forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20if(el.querySelector(%5C%22.random-input-btn%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20el.querySelector(%5C%22.random-input-btn%5C%22).onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20inputEl%20=%20el.closest(%5C%22.input-ctn%5C%22).querySelector(%5C%22input,%20textarea%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20userInputSpec%20=%20window.___userSettings746291937.userInputs%5Bel.dataset.inputName%5D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(userInputSpec.useVariables%20&&%20window%5Bel.dataset.inputName.toUpperCase()%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20window.clearPerchanceErrors();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputEl.value%20=%20window%5Bel.dataset.inputName.toUpperCase()%5D.evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20randomList%20=%20userInputSpec.random;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputEl.value%20=%20selectLeaf(randomList).evaluateItem;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20inputEl.oninput(%7B%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(el.querySelector(%5C%22.ai-suggest-btn%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20el.querySelector(%5C%22.ai-suggest-btn%5C%22).onclick%20=%20async%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20input%20=%20prompt(%5C%22Enter%20a%20couple%20of%20keywords%20or%20ideas%20and%20the%20AI%20will%20generate%20a%20prompt%20for%20you%20based%20on%20that:%5C%22,%20window.lastUsedAiSuggestPrompt%20%7C%7C%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(input%20&&%20input.trim())%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20window.lastUsedAiSuggestPrompt%20=%20input.trim();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20suggestBtn%20=%20el.querySelector(%5C%22.ai-suggest-btn%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.innerHTML%20=%20%60%3Cspan%20style=%5C%22display:inline-block;%20animation:rotate%201.5s%20linear%20infinite;%5C%22%3E%E2%8F%B3%3C/span%3E%60;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.disabled%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20originalSuggestBtnDisplay%20=%20suggestBtn.style.display;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20stopBtn%20=%20document.createElement(%5C%22button%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.innerHTML%20=%20%60%E2%9C%8B%60;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.style.marginTop%20=%20%5C%220.25rem%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20inputEl%20=%20el.closest(%5C%22.input-ctn%5C%22).querySelector(%5C%22input,%20textarea%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20chunkCount%20=%200;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20fullTextSoFar%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20originalInputElHeight%20=%20inputEl.offsetHeight;%20//%20so%20we%20don't%20make%20the%20textarea%20smaller%20than%20it%20originally%20was%5Cn%20%20%20%20%20%20%20%20%20%20%20%20inputEl.value%20=%20%5C%22Loading...%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20pendingObj%20=%20aiText(%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20instruction:%20%60Your%20task%20is%20to%20create%20a%20description%20of%20a%20hypothetical%20image%20which%20is%20based%20on%20the%20following%20idea/keywords/instruction:%20$%7Binput.evaluateItem%7D%5C%5Cn%5C%5CnCome%20up%20with%20a%20fully-formed%20idea%20based%20on%20that%20instruction,%20and%20write%20a%20description/caption%20which%20fully%20captures%20all%20visual%20aspects%20the%20image.%20Your%20response%20should%20be%20crisp/lean/efficient,%20descriptive,%20and%20engaging.%5C%5Cn%5C%5CnStart%20your%20response%20with%20%5C%22Description:%20The%20image%20shows%5C%22%20and%20then%20give%20a%20one-paragraph%20description%20which%20captures%20all%20visual%20details%20of%20the%20idea%20in%20a%20medium-length%20paragraph.%60,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20startWith:%20%60Description:%20The%20image%20shows%60,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopSequences:%20%5B%5C%22%5C%5Cn%5C%22%5D,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20hideStartWith:%20true,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20onChunk:%20(data)%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(chunkCount%20===%200)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputEl.value%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(!data.isFromStartWith)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fullTextSoFar%20+=%20data.textChunk;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputEl.value%20=%20fullTextSoFar.trim()%5B0%5D.toUpperCase()%20+%20fullTextSoFar.trim().slice(1);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(inputEl.offsetHeight%20%3C%20inputEl.scrollHeight+10)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputEl.style.height%20=%20%5C%2210px%5C%22;%20//%20otherwise%20scrollHeight%20can%20be%20bigger%20than%20the%20text.%20this%20ensures%20that%20the%20textarea%20is%20short%20enough%20for%20the%20textarea%20scrollbar%20to%20be%20showing%20-%20user%20shouldn't%20see%20it%20because%20its%20done%20synchonously%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputEl.style.height%20=%20Math.max(originalInputElHeight,%20inputEl.scrollHeight+10)%20+%20%5C%22px%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20chunkCount++;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.parentElement.append(stopBtn);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.disabled%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20pendingObj.stop();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20onInputInterval%20=%20setInterval(()%20=%3E%20inputEl.oninput(%7B%7D),%202000);%20//%20so%20that%20if%20they%20click%20'generate'%20mid-text-gen,%20it'll%20still%20work%5Cn%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20await%20pendingObj.onFinishPromise;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.error(e);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20clearInterval(onInputInterval);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20inputEl.oninput(%7B%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20stopBtn.remove();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.style.display%20=%20originalSuggestBtnDisplay;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.innerHTML%20=%20%60%F0%9F%A7%A0%60;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20suggestBtn.disabled%20=%20false;%5Cn%20%20%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20focus%20on%20first%20non-hidden%20text%20input%20(only%20on%20non-mobile%20devices,%20otherwise%20onscreen%20keyboard%20pops%20up,%20which%20might%20be%20annoying):%5Cn%20%20%20%20%20%20if(window.innerWidth%20%3E%20700%20&&%20!window.location.hash.startsWith(%5C%22#edit%5C%22)%20&&%20!window.alreadyFocussedTextAreaOnLoad)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20textInput%20=%20%5B...userInputsCtn8462746262.querySelectorAll('textarea,%20input')%5D.filter(el%20=%3E%20el.offsetHeight%20!==%200)%5B0%5D;%5Cn%20%20%20%20%20%20%20%20if(textInput)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20distanceFromTopOfPage%20=%20textInput.getBoundingClientRect().top;%5Cn%20%20%20%20%20%20%20%20%20%20if(distanceFromTopOfPage%20%3C%20300)%20%7B%20//%20don't%20focus%20if%20it's%20way%20down%20the%20page%20-%20we%20want%20to%20keep%20the%20page%20scrolled%20to%20the%20top%20on%20load%5Cn%20%20%20%20%20%20%20%20%20%20%20%20textInput.focus();%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20window.alreadyFocussedTextAreaOnLoad%20=%20true;%20//%20this%20is%20a%20hacky%20way%20to%20disable%20this%20when%20someone%20is%20editing%20a%20t2i-framework%20powered%20generator,%20since%20that's%20the%20only%20case%20where%20this%20plugin's%20code%20will%20be%20called%20multiple%20times%20(and%20the%20focus%20will%20annoyingly%20steal%20away%20focus%20from%20the%20perchance%20code%20editor)%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20wait%20a%20'tick'%20and%20then%20load%20share%20link%20data%20if%20it%20exists:%5Cn%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%2010));%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20hash%20=%20window.location.hash.slice(1);%5Cn%20%20%20%20%20%20if(hash%20&&%20hash.startsWith(%5C%22data=%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20console.log(%5C%22Loading%20data%20from%20URL%20hash...%5C%22);%5Cn%20%20%20%20%20%20%20%20let%20result%20=%20await%20loadDataFromUrlHash();%5Cn%20%20%20%20%20%20%20%20if(result.success)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20console.log(%5C%22Loaded%20data%20from%20URL%20hash.%5C%22);%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20console.log(%5C%22Loading%20share%20data%20from%20URL%20hash%20failed:%5C%22,%20result);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20If%20there's%20an%20%5C%22Art%20Style%5C%22%20drop-down,%20then%20flash%20it%20a%20few%20times%20on%20page%20load%20to%20ensure%20people%20understand%20that%20they%20can%20change%20the%20style%5Cn%20%20%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20%20%20if(!localStorage.generateClickCount%20%7C%7C%20Number(localStorage.generateClickCount)%20%3C=%201)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20artStyleInnerEl%20=%20%5B...document.querySelectorAll(%5C%22.input-ctn.input-type-select%20.input-inner%5C%22)%5D.filter(el%20=%3E%20el.textContent.toLowerCase().includes(%5C%22art%20style%5C%22))%5B0%5D;%5Cn%20%20%20%20%20%20%20%20%20%20if(artStyleInnerEl)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20isDarkMode%20=%20window.matchMedia('(prefers-color-scheme:%20dark)').matches;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20originalBackgroundColor%20=%20artStyleInnerEl.style.backgroundColor;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20flashCount%20=%200;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20flashInterval%20=%20setInterval(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(artStyleInnerEl.style.backgroundColor%20===%20originalBackgroundColor)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20artStyleInnerEl.style.backgroundColor%20=%20isDarkMode%20?%20%5C%22#364183%5C%22%20:%20%5C%22#7fb4ff%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20artStyleInnerEl.style.backgroundColor%20=%20originalBackgroundColor;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20flashCount++;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(flashCount%20%3E%208)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20clearInterval(flashInterval);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20artStyleInnerEl.style.backgroundColor%20=%20originalBackgroundColor;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D,%20400);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20%20%20console.error(e);%5Cn%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%7D,%20100);%5Cn%20%20%7D;%5Cn%20%20%5Cn%20%20//%20Hackily%20trigger%20the%20page%20load%20handler%20with%20an%20%3Cimg%3E%20onerror%20because%20it's%20an%20easy%20way%20to%20execute%20a%20script%20right%20after%20the%20HTML%20has%20been%20rendered.%5Cn%20%20let%20dummyImageScriptTrigger%20=%20%60%3Cimg%20style=%5C%22display:fixed;opacity:0;pointer-events:none;top:-2000px;%5C%22%20src=%5C%22%5C%22%20onerror=%5C%22window.___pageLoadHandler746291937();%20this.remove();%5C%22%3E%60;%5Cn%20%20%5Cn%20%20window.generateFeedbackCommentsHtml_8974sklfjosifo%20=%20function()%20%7B%5Cn%20%20%20%20//%20old%20channel%20name:%20feedback-94d35yisdfiwh%20(annoying%20to%20subscribe%20to%20notifications%20for)%5Cn%20%20%20%20let%20options%20=%20%7Bchannel:%5C%22t2i-feedback%5C%22,%20hideComments:settings.showFeedback%20%7C%7C%20location.hash.startsWith(%5C%22#showfeedback%5C%22)%20?%20false%20:%20true,%20height:settings.showFeedback%20%7C%7C%20location.hash.startsWith(%5C%22#showfeedback%5C%22)%20?%20500%20:%20220,%20width:300,%20commentPlaceholderText:%20%5C%22Share%20some%20feedback.%20Do%20not%20share%20personal%20info,%20this%20feedback%20data%20is%20public.%20If%20there's%20a%20technical%20issue/bug%20%F0%9D%98%81%F0%9D%97%BF%F0%9D%98%86%20%F0%9D%98%82%F0%9D%98%80%F0%9D%97%B6%F0%9D%97%BB%F0%9D%97%B4%20%F0%9D%97%96%F0%9D%97%B5%F0%9D%97%BF%F0%9D%97%BC%F0%9D%97%BA%F0%9D%97%B2%20%F0%9D%97%BC%F0%9D%97%BF%20%F0%9D%97%99%F0%9D%97%B6%F0%9D%97%BF%F0%9D%97%B2%F0%9D%97%B3%F0%9D%97%BC%F0%9D%98%85,%20otherwise%20give%20as%20much%20detail%20as%20you%20can%20about%20the%20issue,%20including%20your%20device%20(e.g.%20Android/iPhone).%20If%20the%20issue%20is%20about%20bad%20outputs,%20specify%20the%20chosen%20style%20and%20prompt%20you%20used%20(if%20relevant).%5C%22,%20submitButtonText:%20%5C%22submit%20feedback%5C%22,%20hideSettingsButton:true,%20hideFullscreenButton:true%7D;%5Cn%20%20%20%20if(localStorage.forceColorScheme)%20options.forceColorScheme%20=%20localStorage.forceColorScheme;%5Cn%20%20%20%20return%20window.___commentsPlugin746291937(options);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20window.generateCommentsPluginElement85638294%20=%20function()%20%7B%5Cn%20%20%20%20let%20defaultChannelOptions%20=%20window.___userSettings746291937.defaultCommentOptions;%5Cn%20%20%20%20let%20channels%20=%20window.___userSettings746291937.commentChannels;%5Cn%20%20%20%20if(!channels)%20%7B%5Cn%20%20%20%20%20%20let%20styleEl%20=%20document.createElement(%5C%22style%5C%22);%5Cn%20%20%20%20%20%20styleEl.textContent%20=%20%60#hideCommentsBtn85937402%20%7B%20display:none%20!important;%20%7D%60;%5Cn%20%20%20%20%20%20document.head.append(styleEl);%5Cn%20%20%20%20%20%20return%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20return%20tabbedCommentsPlugin(%7Bchannels,%20defaultChannelOptions%7D);%5Cn%20%20%20%20%5Cn%20%20%20%20//%20let%20defaultCommentOptions%20=%20window.___userSettings746291937.defaultCommentOptions;%5Cn%20%20%20%20//%20let%20commentChannelsList%20=%20window.___userSettings746291937.commentChannels;%5Cn%20%20%20%20//%20let%20items%20=%20%5B%5D;%5Cn%20%20%20%20//%20for(let%20channel%20of%20commentChannelsList.selectAll)%20%7B%5Cn%20%20%20%20//%20%20%20let%20item%20=%20%7Bname:channel.getName,%20label:channel.label%7D;%5Cn%20%20%20%20//%20%20%20let%20commentOptions%20=%20%7B%7D;%5Cn%20%20%20%20//%20%20%20//%20get%20default%20options:%5Cn%20%20%20%20//%20%20%20for(let%20key%20of%20defaultCommentOptions.getAllKeys)%20%7B%5Cn%20%20%20%20//%20%20%20%20%20commentOptions%5Bkey%5D%20=%20defaultCommentOptions%5Bkey%5D;%5Cn%20%20%20%20//%20%20%20%7D%5Cn%20%20%20%20//%20%20%20//%20apply%20channel-specific%20comment%20option%20overrides:%5Cn%20%20%20%20//%20%20%20for(let%20key%20of%20channel.getAllKeys)%20%7B%20%5Cn%20%20%20%20//%20%20%20%20%20commentOptions%5Bkey%5D%20=%20channel%5Bkey%5D;%5Cn%20%20%20%20//%20%20%20%7D%5Cn%20%20%20%20//%20%20%20if(channel.getName%20!==%20%5C%22general%5C%22)%20%7B%20//%20%3C--%20for%20backwards%20compatibility%20with%20v1%20of%20this%20framework%20(i.e.%20to%20keep%20comment%20history)%5Cn%20%20%20%20//%20%20%20%20%20commentOptions.channel%20=%20channel.getName;%5Cn%20%20%20%20//%20%20%20%7D%5Cn%20%20%20%20//%20%20%20//%20Note:%20If%20you%20change%20stuff%20here,%20make%20sure%20to%20update%20the%20custom%20tab%20creation%20code%20in%20createCommentsTabs%20too.%5Cn%20%20%20%20//%20%20%20if(localStorage.forceColorScheme)%20commentOptions.forceColorScheme%20=%20localStorage.forceColorScheme;%5Cn%20%20%20%20//%20%20%20item.content%20=%20window.___commentsPlugin746291937(commentOptions);%5Cn%20%20%20%20//%20%20%20items.push(item);%5Cn%20%20%20%20//%20%7D%5Cn%20%20%20%20//%20return%20createCommentsTabs(items,%20%7BallowCustomChannels:!!commentChannelsList.allowCustomChannels%7D);%5Cn%20%20%7D%5Cn%20%20window.generateImageGalleryHtml358402048%20=%20function()%20%7B%5Cn%20%20%20%20if(!window.___userSettings746291937.galleryOptions%20%7C%7C%20!window.___userSettings746291937.galleryOptions.gallery)%20%7B%5Cn%20%20%20%20%20%20let%20styleEl%20=%20document.createElement(%5C%22style%5C%22);%5Cn%20%20%20%20%20%20styleEl.textContent%20=%20%60#hideGalleryBtn85937402%20%7B%20display:none%20!important;%20%7D%60;%5Cn%20%20%20%20%20%20document.head.append(styleEl);%5Cn%20%20%20%20%20%20return%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20window.___userSettings746291937.galleryOptions.forceColorScheme%20=%20null;%5Cn%20%20%20%20if(localStorage.forceColorScheme)%20window.___userSettings746291937.galleryOptions.forceColorScheme%20=%20localStorage.forceColorScheme;%5Cn%20%20%20%20return%20window.___textToImagePlugin746291937(window.___userSettings746291937.galleryOptions).evaluateItem;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20try%20%7B%5Cn%20%20%20%20let%20isSafari%20=%20navigator.vendor%20&&%20navigator.vendor.indexOf('Apple')%20%3E%20-1%20&&%20navigator.userAgent%20&&%20navigator.userAgent.indexOf('CriOS')%20==%20-1%20&&%20navigator.userAgent.indexOf('FxiOS')%20==%20-1;%5Cn%20%20%20%20let%20isTouchScreen%20=%20window.matchMedia(%5C%22(pointer:%20coarse)%5C%22).matches;%5Cn%20%20%20%20if(isSafari%20&&%20window.innerWidth%20%3C%20800%20&&%20isTouchScreen)%20%7B%5Cn%20%20%20%20%20%20let%20viewportMetaEl%20=%20document.querySelector(%5C%22%5Bname=viewport%5D%5C%22);%5Cn%20%20%20%20%20%20if(!viewportMetaEl.getAttribute(%5C%22content%5C%22).includes(%5C%22maximum-scale%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20viewportMetaEl.setAttribute(%5C%22content%5C%22,%20viewportMetaEl.getAttribute(%5C%22content%5C%22)%20+%20%5C%22,%20maximum-scale=1%5C%22);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20console.log(%5C%22Safari%20iOS%20detected.%20Added%20maximum-scale%20attribute%20to%20prevent%20zooming:%5C%22,%20viewportMetaEl.getAttribute(%5C%22content%5C%22));%5Cn%20%20%20%20%7D%5Cn%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20console.error(e);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20return%20%60%3Cstyle%3E%5Cn%20%20%20%20body%20*:not(a,%20button)%20%7B%5Cn%20%20%20%20%20%20color:%20inherit;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn%20%7B%5Cn%20%20%20%20%20%20width:%20min-content;%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn.takesUpFullRow%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn.takesUpFullRow%5C%5C%5C%5C%5Bdata-fold-toggle-state='shown'%5C%5C%5C%5C%5D%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn.takesUpFullRow%5C%5C%5C%5C%5Bdata-fold-toggle-state='hidden'%5C%5C%5C%5C%5D%20%7B%5Cn%20%20%20%20%20%20width:%20min-content;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn%5C%5C%5C%5C%5Bdata-fold-toggle-state='hidden'%5C%5C%5C%5C%5D%20.input-wrapper%20%7B%5Cn%20%20%20%20%20%20display:%20none;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-inner%20%7B%5Cn%20%20%20%20%20%20padding:%200.25rem;%20/*%20%3C--%20if%20you%20change%20this,%20you%20need%20to%20change%20the%20CSS%20width%20calc%20on%20input-wrapper,%20generated%20by%20the%20JS%20code%20*/%5Cn%20%20%20%20%20%20margin:%200.25rem;%5Cn%20%20%20%20%20%20border-radius:%203px;%5Cn%20%20%20%20%20%20background:%20var(--box-color,%20#ebebeb);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-type-text%20.input-inner,%20.input-type-paragraph%20.input-inner%20%7B%5Cn%20%20%20%20%20%20width:%20300px;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-label%20%7B%5Cn%20%20%20%20%20%20font-size:%2080%25;%20%5Cn%20%20%20%20%20%20text-align:%20left;%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn%5C%5C%5C%5C%5Bdata-fold-toggle-state='shown'%5C%5C%5C%5C%5D%20.input-toggle-button%20%7B%5Cn%20%20%20%20%20%20margin-left:%20auto;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn%5C%5C%5C%5C%5Bdata-fold-toggle-state='hidden'%5C%5C%5C%5C%5D%20.input-toggle-button%20%7B%5Cn%20%20%20%20%20%20margin-left:%201rem;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn%5C%5C%5C%5C%5Bdata-fold-toggle-state='hidden'%5C%5C%5C%5C%5D%20.input-toggle-button::before%20%7B%5Cn%20%20%20%20%20%20content:%20%5C%22show%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-ctn%5C%5C%5C%5C%5Bdata-fold-toggle-state='shown'%5C%5C%5C%5C%5D%20.input-toggle-button::before%20%7B%5Cn%20%20%20%20%20%20content:%20%5C%22hide%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-wrapper%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-wrapper%20.text-input%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%20%20padding-right:%201.375rem;%5Cn%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-wrapper%20.paragraph-input%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%20%20padding-right:%201.375rem;%5Cn%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.random-input-btn-ctn%20%7B%5Cn%20%20%20%20%20%20margin-left:%200.25rem;%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20flex-direction:%20column;%5Cn%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20cursor:%20pointer;%5Cn%20%20%20%20%20%20margin-bottom:%20auto;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.auto-suggest-btn%20%7B%5Cn%20%20%20%20%20%20position:absolute;%5Cn%20%20%20%20%20%20top:0.125rem;%5Cn%20%20%20%20%20%20right:0.125rem;%5Cn%20%20%20%20%20%20cursor:pointer;%5Cn%20%20%20%20%20%20opacity:0.6;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.auto-suggest-btn:hover%20%7B%5Cn%20%20%20%20%20%20opacity:1;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.input-tip-btn%20%7B%5Cn%20%20%20%20%20%20cursor:pointer;%5Cn%20%20%20%20%20%20font-weight:bold;%5Cn%20%20%20%20%20%20margin-left:0.25rem;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20@keyframes%20rotate%7B%5Cn%20%20%20%20%20%20to%20%7B%20transform:%20rotate(360deg);%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20.tabs-header%20%7B%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20font-size:%2070%25;%5Cn%20%20%20%20%20%20overflow:auto;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.tab%20%7B%5Cn%20%20%20%20%20%20padding:%200.25rem;%5Cn%20%20%20%20%20%20cursor:%20pointer;%5Cn%20%20%20%20%20%20background:%20var(--box-color,%20#ebebeb);%5Cn%20%20%20%20%20%20border-radius:%200.25rem;%5Cn%20%20%20%20%20%20margin:%200.25rem;%5Cn%20%20%20%20%20%20user-select:%20none;%5Cn%20%20%20%20%20%20min-width:%20max-content;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.active-tab%20%7B%5Cn%20%20%20%20%20%20background:%20var(--active-comment-channel-tab-color,%20#c6c6c6);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.tab-content%20%7B%5Cn%20%20%20%20%20%20display:%20none;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.active-content%20%7B%5Cn%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20.t2i-under-each-image-ctn%20%7B%5Cn%20%20%20%20%20%20font-size:%2080%25;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.t2i-under-each-image-ctn%20.personality-chat-button%20%7B%5Cn%20%20%20%20%20%20opacity:%200.5;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.t2i-under-each-image-ctn%20.personality-chat-button:hover%20%7B%5Cn%20%20%20%20%20%20opacity:%201;%5Cn%20%20%20%20%7D%5Cn%20%20%3C/style%3E%5Cn%5Cn%20%20%3Ch1%20id=%5C%22pageTitleEl48759084793%5C%22%20style=%5C%22font-size:1.2rem;%20margin-bottom:0.5rem;%5C%22%3E$%7Bsettings.pageTitle%7D%3C/h1%3E%20%5Cn%5Cn%20%20%3Cdiv%20id=%5C%22mainColumnEl85394739%5C%22%20style=%5C%22margin:0%20auto;%20max-width:1000px;%5C%22%3E%20%3C!--%20NOTE:%20if%20you%20change%201000px%20to%20something%20else,%20ctrl+f%20for%20mainColumnEl85394739%20and%20change%20the%20numImage-based%20stuff%20--%3E%5Cn%20%20%20%20%3Cdiv%20id=%5C%22userInputsCtn8462746262%5C%22%20style=%5C%22display:flex;%20padding:0.25rem;%20justify-content:center;%20flex-wrap:wrap;%5C%22%3E%5Cn%20%20%20%20%20%20$%7BuserInputsHtml%7D%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%20%20$%7BdummyImageScriptTrigger%7D%5Cn%5Cn%20%20%20%20%3C!--%3Cdiv%20style=%5C%22margin:1rem%200;%20display:%20flex;%20align-items:%20center;%20justify-content:%20center;%5C%22%3E%5Cn%20%20%20%20%20%20%E2%9E%A1%EF%B8%8F&nbsp;%3Cbutton%20id=%5C%22generateButtonEl%5C%22%20style=%5C%22font-size:1.5rem;%5C%22%20onclick=%5C%22window.___generateButtonClickEvent746291937(event);%5C%22%3E%E2%9C%A8%20generate%3C/button%3E&nbsp;%E2%AC%85%EF%B8%8F%5Cn%20%20%20%20%3C/div%3E--%3E%5Cn%20%20%20%20%5Cn%20%20%20%20%3Cdiv%20id=%5C%22shareLinkOuterCtn2893827%5C%22%20style=%5C%22display:none;%20margin-bottom:2rem;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id=%5C%22shareSettingsBtn758374%5C%22%20onclick=%5C%22window.__generateSettingsShareLink084722()%5C%22%20style=%5C%22font-size:70%25;%5C%22%3E%F0%9F%94%97%20share%20these%20settings%3C/button%3E%5Cn%20%20%20%20%20%20%3Cdiv%20id=%5C%22shareLinkCtn83927376%5C%22%20style=%5C%22display:none;%20margin-top:0.5rem;%20font-size:80%25;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cinput%20style=%5C%22width:200px;%5C%22%20id=%5C%22shareSettingsLinkInputEl759307%5C%22%20disabled%3E%20%3Cbutton%20style=%5C%22min-width:80px;%5C%22%20onclick=%5C%22navigator.clipboard.writeText(shareSettingsLinkInputEl759307.value).then(r%20=%3E%20this.innerHTML='%E2%9C%85');%20setTimeout(()%20=%3E%20this.innerHTML='copy%20link',%202000);%5C%22%3Ecopy%20link%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22font-size:80%25;%20opacity:0.7;%5C%22%3E(this%20link%20contains%20a%20snapshot%20of%20the%20above%20settings)%3C/div%3E%5Cn%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%5Cn%20%20%20%20%3Cdiv%20style=%5C%22margin:1rem%200;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:%20flex;align-items:%20center;justify-content:%20center;%5C%22%3E%3Cspan%20id=%5C%22leftClickHelperEl%5C%22%20style=%5C%22display:none;%5C%22%3Eclick%20%E2%9E%A1&nbsp;%3C/span%3E%3Cbutton%20id=%5C%22generateButtonEl%5C%22%20style=%5C%22font-size:1.5rem;%5C%22%20onclick=%5C%22window.___generateButtonClickEvent746291937(event);%5C%22%3E%E2%9C%A8%20generate%3C/button%3E%3Cspan%20id=%5C%22rightClickHelperEl%5C%22%20style=%5C%22display:none;%5C%22%3E&nbsp;%E2%AC%85%20click%3C/span%3E%3C/div%3E%5Cn%20%20%20%20%20%20%3Cdiv%20id=%5C%22bottomClickHelperEl%5C%22%20style=%5C%22display:none;%5C%22%3E%3Cdiv%3E%E2%AC%86%3C/div%3E%3Cdiv%3Eclick%3C/div%3E%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%5Cn%20%20%20%20%3Cdiv%20id=%5C%22outputAreaEl%5C%22%20style=%5C%22margin-top:1rem;%20min-height:12rem;%20display:flex;%20flex-wrap:wrap;%20justify-content:center;%20align-items:center;%20padding:0.25rem;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cspan%3E$%7Bsettings.introMessage%20%7C%7C%20%5C%22%E2%86%91%20Set%20inputs%20and%20click%20%3Ci%3Egenerate%3C/i%3E%20to%20begin.%20%E2%86%91%5C%22%7D%3C/span%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%5Cn%20%20%20%20%3Cdiv%20style=%5C%22position:fixed;%20bottom:0.5rem;%20right:0.5rem;%20text-align:right;%20z-index:100;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20id=%5C%22feedbackCommentsCtn%5C%22%3E%3C/div%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id=%5C%22feedbackBtn893745ykfuhd%5C%22%20onclick=%5C%22if(feedbackCommentsCtn.innerHTML.length%20===%200)%20%7B%20feedbackCommentsCtn.innerHTML=window.generateFeedbackCommentsHtml_8974sklfjosifo();%20this.innerHTML='%E2%9C%96%20close';%20%7D%20else%20%7B%20%20feedbackCommentsCtn.innerHTML='';%20%20this.innerHTML='%F0%9F%97%A8%EF%B8%8F%20feedback';%20%7D%5C%22%3E%F0%9F%97%A8%EF%B8%8F%20feedback%3C/button%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%5Cn%20%20%20%20%3Cdiv%20id=%5C%22showSocialsButtonCtn9000274628%5C%22%20style=%5C%22$%7BsocialFeatures%20===%20'button'%20?%20''%20:%20'display:none;'%7D%5C%22%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id=%5C%22showSocialsButton927514532%5C%22%20style=%5C%22margin-top:2rem;%20margin-bottom:0.5rem;%5C%22%20onclick=%5C%22window.__showSocialsButtonClickHandler98347938();%5C%22%3E%3Cdiv%20style=%5C%22padding:0.5rem;%5C%22%3E%F0%9F%92%AC%20show%20comments%20&%20gallery%20%F0%9F%96%BC%EF%B8%8F%3C/div%3E%3C/button%3E%5Cn%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%20align-items:center;%20justify-content:center;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cinput%20id=%5C%22autoShowCheckbox84937483%5C%22%20style=%5C%22cursor:pointer;%5C%22%20type=%5C%22checkbox%5C%22%3E%3Cspan%20style=%5C%22margin-left:0.25rem;%20cursor:pointer;%5C%22%20onclick=%5C%22autoShowCheckbox84937483.checked=!autoShowCheckbox84937483.checked;%5C%22%3Eauto-show%20next%20time%3C/span%3E%5Cn%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%5Cn%20%20%20%20%3Cdiv%20id=%5C%22showHideGalleryAndCommentsButtonsCtn83728732671%5C%22%20style=%5C%22$%7BsocialFeatures%20===%20%5C%22button%5C%22%20%7C%7C%20socialFeatures%20===%20%5C%22disabled%5C%22%20?%20%5C%22display:none;%5C%22%20:%20%5C%22%5C%22%7D%20margin-top:1rem;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id=%5C%22hideCommentsBtn85937402%5C%22%20onclick=%5C%22if(this.dataset.hidden)%20%7B%20this.dataset.hidden='';%20this.textContent%20=%20'hide%20comments';%20commentsPluginCtn654732.style.display%20=%20'';%20%7D%20else%20%7B%20this.dataset.hidden='1';%20this.textContent%20=%20'show%20comments';%20commentsPluginCtn654732.style.display%20=%20'none';%20%7D%5C%22%20data-hidden=%5C%22%5C%22%3Ehide%20comments%3C/button%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id=%5C%22hideGalleryBtn85937402%5C%22%20onclick=%5C%22if(this.dataset.hidden)%20%7B%20this.dataset.hidden='';%20this.textContent%20=%20'hide%20gallery';%20imageGalleryCtn8569284.style.display%20=%20'';%20%7D%20else%20%7B%20this.dataset.hidden='1';%20this.textContent%20=%20'show%20gallery';%20imageGalleryCtn8569284.style.display%20=%20'none';%20%7D%5C%22%20data-hidden=%5C%22%5C%22%3Ehide%20gallery%3C/button%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%5Cn%20%20%20%20%3Cdiv%20style=%5C%22position:fixed;%20bottom:0.5rem;%20left:0.5rem;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cbutton%20id=%5C%22darkModeBtn_875979f948%5C%22%20style=%5C%22cursor:pointer;%5C%22%20onclick=%5C%22window.toggleManualDarkMode_jv83hb27igksf();%5C%22%3E%F0%9F%8C%83%3C/button%3E%5Cn%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:inline-block;%5C%22%3E%5Bwindow.___fullscreenButton893479(%5C%22&nbsp;&nbsp;&nbsp;%E2%87%B1&nbsp;&nbsp;&nbsp;%5C%22,%20%5C%22&nbsp;&nbsp;&nbsp;%E2%87%B2&nbsp;&nbsp;&nbsp;%5C%22)%5D%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%3C/div%3E%5Cn%20%20%5Cn%20%20%3Cdiv%20id=%5C%22commentsPluginCtn654732%5C%22%20style=%5C%22padding:0.25rem;%20width:100%25;%20margin:0%20auto;%20margin-top:1rem;%5C%22%3E%3C/div%3E%5Cn%20%20%5Cn%20%20%3C!--%20%3Cdiv%20style=%5C%22background-image:url(https://example.com/image.webp);%20filter:%20blur(1px);%20opacity:0.5;%20background-position:center;%20background-size:cover;%20z-index:-10;%20position:fixed;%20top:0;left:0;right:0;bottom:0;%5C%22%3E%3C/div%3E%20--%3E%5Cn%20%20%3Cdiv%20id=%5C%22clickCountBasedSocialDisplayNotifierEl%5C%22%20style=%5C%22font-size:80%25;%20max-width:800px;%20margin:0%20auto;%20padding:0.5rem;%20text-align:left;%20display:none;%5C%22%3E%5Cn%20%20%20%20%3Cdiv%20style=%5C%22background:var(--box-color);padding:%200.5rem;%20border-radius:3px;%5C%22%3E%3Cb%3ENote:%3C/b%3E%20The%20comments%20and%20gallery%20only%20appear%20after%20generating%20several%20batches%20of%20images.%20If%20you%20visit%20this%20page%20again%20later%20and%20don't%20see%20the%20gallery/comments,%20it's%20because%20your%20cookies/storage%20for%20this%20site%20got%20cleared%20for%20some%20reason,%20so%20you'd%20need%20to%20generate%20some%20more%20images.%20%3Cbutton%20style=%5C%22font-size:80%25;%5C%22%20onclick=%5C%22localStorage.theyKnowAboutClickCountBasedSocialDisplay='1';%20this.parentElement.style.display='none';%5C%22%3E%E2%9C%85%20got%20it%3C/button%3E%3C/div%3E%5Cn%20%20%3C/div%3E%5Cn%20%20%5Cn%20%20%3Cdiv%20id=%5C%22imageGalleryCtn8569284%5C%22%20style=%5C%22margin-top:1rem;%5C%22%3E%5Cn%20%20%20%20$%7B%5B%5C%22disabled%5C%22,%20%5C%22button%5C%22%5D.includes(socialFeatures)%20?%20%5C%22%5C%22%20:%20window.generateImageGalleryHtml358402048()%7D%5Cn%20%20%3C/div%3E%5Cn%20%20%3Cbr%3E%3Cbr%3E%3Cbr%3E%3Cbr%3E%5Cn%20%20%60.replaceAll(%5C%22%7B%5C%22,%20%5C%22%5C%5C%5C%5C%7B%5C%22).replaceAll(%5C%22%7D%5C%22,%20%5C%22%5C%5C%5C%5C%7D%5C%22);%5Cn%20%20%5Cn%20%20%5Cn%20%20%5CncreateCommentsTabs(items,%20opts)%20=%3E%20//%20items%20=%20%5B%7Bname,%20label,%20content%7D,%20%7Bname,%20label,%20content%7D,%20...%5D%5Cn%20%20if(!opts)%20opts%20=%20%7B%7D;%5Cn%20%20let%20ctn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20ctn.innerHTML%20=%20%60%5Cn%20%20%20%20%3Cdiv%20class=%5C%22tabs-header%5C%22%3E%3C/div%3E%5Cn%20%20%20%20%3Cdiv%20class=%5C%22tabs-content%5C%22%3E%3C/div%3E%60;%5Cn%5Cn%20%20const%20tabsHeaderEl%20=%20ctn.querySelector('.tabs-header');%5Cn%20%20const%20tabsContentEl%20=%20ctn.querySelector('.tabs-content');%5Cn%5Cn%20%20//%20Function%20to%20handle%20tab%20click%5Cn%20%20function%20handleTabClick(event)%20%7B%5Cn%20%20%20%20let%20clickedTab%20=%20event.target;%5Cn%20%20%20%20if(!clickedTab.classList.contains('tab'))%20return;%5Cn%20%20%20%20%5Cn%20%20%20%20if(event.target.classList.contains('addCustomChannel'))%20%7B%5Cn%20%20%20%20%20%20let%20name%20=%20prompt(%5C%22Choose%20a%20channel%20name.%20Others%20will%20only%20see%20this%20channel%20if%20they%20also%20add%20it.%20Start%20the%20name%20with%20an%20exclaimation%20mark%20to%20remove%20an%20existing%20channel.%5C%22);%5Cn%20%20%20%20%20%20if(name)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20removeChannel%20=%20false;%5Cn%20%20%20%20%20%20%20%20if(name.startsWith(%5C%22!%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20removeChannel%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20name%20=%20name.slice(1);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20name%20=%20name.toLowerCase();%5Cn%20%20%20%20%20%20%20%20name%20=%20name.replace(/%5B%5Ea-z0-9%5C%5C-%5D/g,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(!name)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20alert(%5C%22Channel%20names%20can%20only%20contain%20lower-case%20letters,%20numbers%20and%20hyphens.%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(name%20===%20%5C%22t2i-feedback%5C%22)%20return;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(!localStorage.__t2iFrameworkCustomChannels)%20localStorage.__t2iFrameworkCustomChannels%20=%20%5C%22%7B%7D%5C%22;%5Cn%20%20%20%20%20%20%20%20let%20customChannels%20=%20%7B%7D;%5Cn%20%20%20%20%20%20%20%20try%20%7B%20customChannels%20=%20JSON.parse(localStorage.__t2iFrameworkCustomChannels)%20%7D%20catch(e)%20%7B%20console.error(%5C%22Failed%20to%20parse%20custom%20channels%20from%20localStorage:%5C%22,%20e);%20%7D%5Cn%20%20%20%20%20%20%20%20if(removeChannel)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20delete%20customChannels%5Bname%5D;%5Cn%20%20%20%20%20%20%20%20%20%20tabsHeaderEl.querySelector(%60%5Bdata-name='$%7Bname%7D'%5D%60).remove();%5Cn%20%20%20%20%20%20%20%20%20%20tabsContentEl.querySelector(%60%5Bdata-name='$%7Bname%7D'%5D%60).remove();%5Cn%20%20%20%20%20%20%20%20%20%20showTabByName(tabsHeaderEl.firstElementChild.dataset.name);%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(!customChannels%5Bname%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20customChannels%5Bname%5D%20=%20%7Bname:name,%20label:name%7D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20item%20=%20JSON.parse(JSON.stringify(customChannels%5Bname%5D));%5Cn%20%20%20%20%20%20%20%20%20%20%20%20item.content%20=%20createCustomTabContent(item);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20addTab(item);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20tabsHeaderEl.append(event.target);%20//%20move%20%5C%22+%5C%22%20button%20to%20the%20end%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20showTabByName(name);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20localStorage.__t2iFrameworkCustomChannels%20=%20JSON.stringify(customChannels);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20showTabByName(clickedTab.dataset.name);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20showTabByName(name)%20%7B%5Cn%20%20%20%20tabsHeaderEl.querySelectorAll('.tab').forEach(el%20=%3E%20el.classList.remove('active-tab'));%5Cn%20%20%20%20tabsHeaderEl.querySelector(%60.tab%5Bdata-name='$%7Bname%7D'%5D%60).classList.add('active-tab');%5Cn%20%20%20%20%5Cn%20%20%20%20tabsContentEl.querySelectorAll('.tab-content').forEach(el%20=%3E%20el.classList.remove('active-content'));%5Cn%20%20%20%20tabsContentEl.querySelector(%60.tab-content%5Bdata-name='$%7Bname%7D'%5D%60).classList.add('active-content');%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20addTab(item)%20%7B%5Cn%20%20%20%20const%20tab%20=%20document.createElement('div');%5Cn%20%20%20%20tab.className%20=%20'tab';%5Cn%20%20%20%20tab.textContent%20=%20item.label;%5Cn%20%20%20%20tab.dataset.name%20=%20item.name;%5Cn%5Cn%20%20%20%20const%20tabContent%20=%20document.createElement('div');%5Cn%20%20%20%20tabContent.className%20=%20'tab-content';%5Cn%20%20%20%20tabContent.innerHTML%20=%20item.content;%5Cn%20%20%20%20tabContent.dataset.name%20=%20item.name;%5Cn%20%20%20%20%5Cn%20%20%20%20tabsHeaderEl.appendChild(tab);%5Cn%20%20%20%20tabsContentEl.appendChild(tabContent);%5Cn%20%20%20%20return%20%7Btab,%20tabContent%7D;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20createCustomTabContent(item)%20%7B%5Cn%20%20%20%20let%20commentOptions%20=%20JSON.parse(JSON.stringify(item));%5Cn%20%20%20%20let%20defaultCommentOptions%20=%20window.___userSettings746291937.defaultCommentOptions;%5Cn%20%20%20%20for(let%20key%20of%20defaultCommentOptions.getAllKeys)%20%7B%5Cn%20%20%20%20%20%20commentOptions%5Bkey%5D%20=%20defaultCommentOptions%5Bkey%5D;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(localStorage.forceColorScheme)%20%7B%5Cn%20%20%20%20%20%20commentOptions.forceColorScheme%20=%20localStorage.forceColorScheme;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20commentOptions.channel%20=%20commentOptions.name;%5Cn%20%20%20%20delete%20commentOptions.name;%5Cn%20%20%20%20return%20window.___commentsPlugin746291937(commentOptions);%5Cn%20%20%7D%5Cn%5Cn%20%20let%20i%20=%200;%5Cn%20%20for(let%20item%20of%20items)%20%7B%5Cn%20%20%20%20let%20%7Btab,%20tabContent%7D%20=%20addTab(item);%5Cn%20%20%20%20if(i%20===%200)%20%7B%5Cn%20%20%20%20%20%20tabContent.classList.add('active-content');%5Cn%20%20%20%20%20%20tab.classList.add('active-tab');%5Cn%20%20%20%20%7D%5Cn%20%20%20%20i++;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(opts.allowCustomChannels)%20%7B%5Cn%20%20%20%20//%20add%20user-specified%20custom%20channels:%5Cn%20%20%20%20if(!localStorage.__t2iFrameworkCustomChannels)%20localStorage.__t2iFrameworkCustomChannels%20=%20%5C%22%7B%7D%5C%22;%5Cn%20%20%20%20let%20customChannels%20=%20%7B%7D;%5Cn%20%20%20%20try%20%7B%20customChannels%20=%20JSON.parse(localStorage.__t2iFrameworkCustomChannels)%20%7D%20catch(e)%20%7B%20console.error(%5C%22Failed%20to%20parse%20custom%20channels%20from%20localStorage:%5C%22,%20e);%20%7D%5Cn%20%20%20%20for(let%20item%20of%20Object.values(customChannels))%20%7B%5Cn%20%20%20%20%20%20let%20itemCopy%20=%20JSON.parse(JSON.stringify(item));%5Cn%20%20%20%20%20%20itemCopy.content%20=%20createCustomTabContent(itemCopy);%5Cn%20%20%20%20%20%20addTab(itemCopy);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20//%20add%20the%20%5C%22+%5C%22%20button:%5Cn%20%20%20%20const%20tab%20=%20document.createElement('div');%5Cn%20%20%20%20tab.className%20=%20'tab%20addCustomChannel';%5Cn%20%20%20%20tab.textContent%20=%20%5C%22+%5C%22;%5Cn%20%20%20%20tab.style.cssText%20=%20%5C%22min-width:1.4rem;%5C%22;%5Cn%20%20%20%20tabsHeaderEl.appendChild(tab);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20tabsHeaderEl.addEventListener('click',%20handleTabClick);%5Cn%5Cn%20%20return%20ctn;%5Cn%20%20%5Cn%20%20%5Cn%22,%22imports%22:%5B%22ai-text-plugin%22,%22comments-plugin%22,%22fullscreen-button-plugin%22,%22prompt2-plugin%22,%22select-leaf-plugin%22,%22t2i-styles%22,%22tabbed-comments-plugin-v1%22,%22text-to-image-plugin%22,%22upload-plugin%22%5D,%22lastEditTime%22:1730516733135,%22found%22:true%7D,%7B%22name%22:%22t2i-styles%22,%22modelText%22:%22//%20note%20that%20%60input%60%20is%20a%20global%20variable%20(i.e.%20%60input%60%20is%20%60window.input%60),%20which%20is%20created%20by%20t2i-framework-plugin%5Cn//%20see%20here%20for%20an%20example%20generator%20that%20imports%20these%20styles:%20https://perchance.org/ai-character-generator#edit%5Cn%5Cn//%20style%20tester:%20https://perchance.org/prompt-style-tester%5Cn%5Cn$output%5Cn%20%20Painted%20Anime%5Cn%20%20%20%20prompt%20//%20this%20style%20is%20biased%20towards%20female%20characters%20due%20to%20the%20biases%20of%20the%20artists%20mentioned,%20so%20we%20alter%20the%20description%20if%20'male'%20is%20mentioned%20to%20boost%20'maleness'%20and%20supress%20'femaleness'%5Cn%20%20%20%20%20%20(%5B/%5C%5Cb(male%7Cman)%5C%5Cb/i.test(input.description)%20?%20input.description.replace(/%5C%5Cb(male%7Cman)%5C%5Cb/i,%20%5C%22(male,%20masculine,%20masc,%20male)%5C%22)%20:%20input.description%5D),%20art%20by%20atey%20ghailan,%20painterly%20anime%20style%20at%20pixiv,%20art%20by%20kantoku,%20in%20art%20style%20of%20redjuice/nec%C3%B6mi/rella/tiv%20pixiv%20collab,%20your%20name%20anime%20art%20style,%20masterpiece%20digital%20painting,%20exquisite%20lighting%20and%20composition,%20inspired%20by%20wlop%20art%20style,%208k,%20sharp,%20very%20detailed,%20high%20resolution,%20illustration%20%5E2%5Cn%20%20%20%20%20%20painterly%20anime%20artwork,%20%5Binput.description%5D,%20masterpiece,%20fine%20details,%20breathtaking%20artwork,%20painterly%20art%20style,%20high%20quality,%208k,%20very%20detailed,%20high%20resolution,%20exquisite%20composition%20and%20lighting%5Cn%20%20%20%20negative%5Cn%20%20%20%20%20%20(worst%20quality,%20low%20quality,%20blurry:1.3),%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5B/%5C%5Cbmale%5C%5Cb/i.test(input.description)%20?%20%5C%22,%20female,%20feminine,%20fem,%20female%5C%22%20:%20%5C%22%5C%22%5D%5Cn%20%20%20%20%20%20%5Binput.negative%5D,%20(worst%20quality,%20low%20quality,%20blurry:1.3),%20black%20and%20white,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20bad%20art,%20bad%20anatomy,%20bad%20lighting,%20disfigured,%20faded,%20blurred%20face%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:100,%20painting:100,%20paintedAnime:100,%20drawing:55,%20cartoon:50%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BanimeModifiers%5D%5Cn%20%20Casual%20Photo%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20casual%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20photo,%20bad%20lighting,%20high%20production%20value,%20unnatural%20studio%20lighting,%20commercial%20photoshoot,%20photoshopped,%20terrible%20photo,%20disfigured%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:98,%20casualPhoto:100,%20portrait:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20color%20=%20%5BphotoModifiers.color%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%20Cinematic%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20cinematic%20shot,%20dynamic%20lighting,%2075mm,%20Technicolor,%20Panavision,%20cinemascope,%20sharp%20focus,%20fine%20details,%208k,%20HDR,%20realism,%20realistic,%20key%20visual,%20film%20still,%20cinematic%20color%20grading,%20depth%20of%20field%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20lighting,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20holding%20camera,%20bad%20art,%20bad%20angle,%20boring,%20low-resolution,%20worst%20quality,%20bad%20composition,%20disfigured%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:100,%20portrait:85,%20render:70,%20cinematic:100%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20color%20=%20%5BphotoModifiers.color%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%20%20%20%20%20genre%5Cn%20%20%20%20%20%20%20%20adventure%20=%20,%20adventure%5Cn%20%20%20%20%20%20%20%20b-horror%20=%20,%20b-horror%20film%20screencap%5Cn%20%20%20%20%20%20%20%20epic%20fantasy%20=%20,%20epic%20fantasy%5Cn%20%20%20%20%20%20%20%20sci-fi%20=%20,%20sci-fi%5Cn%20%20%20%20%20%20%20%20film%20noir%20=%20,%20film%20noir%5Cn%20%20%20%20%20%20%20%20horror%20=%20,%20horror%5Cn%20%20%20%20%20%20%20%20indie%20=%20,%20indie%20film%20screencap%5Cn%20%20%20%20%20%20%20%20western%20=%20,%20western,%20wild%20west%5Cn%20%20%20%20%20%20%20%20thriller%20=%20,%20thriller%5Cn%20%20Digital%20Painting%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20breathtaking%20digital%20art,%20trending%20on%20artstation,%20by%20atey%20ghailan,%20by%20greg%20rutkowski,%20by%20greg%20tocchini,%20by%20james%20gilleard,%208k,%20high%20resolution,%20best%20quality%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20signature%20watermark%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:90,%20landscape:70,%20digitalPainting:100,%20drawing:60%7D)%5D%5Cn%20%20Concept%20Art%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20concept%20art,%20digital%20art,%20illustration,%20inspired%20by%20wlop%20style,%208k,%20fine%20details,%20sharp,%20very%20detailed,%20high%20resolution,%20masterpiece%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20worst%20quality,%20blurry%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:50,%20landscape:70%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20modifier%5Cn%20%20%20%20%20%20%20%20league%20of%20legends%20=%20,%20league%20of%20legends%20style%20concept%20art%5Cn%20%20%20%20%20%20%20%20epic%20fantasy%20=%20,%20epic%20fantasy%20concept%20art%20by%20noah%20bradley%5Cn%20%20%20%20%20%20%20%20sci-fi%20=%20,%20sci-fi%20concept%20art%5Cn%20%20%20%20%20%20%20%20horror%20=%20,%20horror%20concept%20art%5Cn%20%20%20%20%20%20%20%20western%20=%20,%20western,%20wild%20west%20concept%20art%5Cn%20%203D%20Disney%20Character%5Cn%20%20%20%20prompt%20=%203D%20cartoon%20Disney%20character%20portrait%20render.%20%5Binput.description%5D,%20bokeh,%204k,%20highly%20detailed,%20Pixar%20render,%20CGI%20Animation,%20Disney,%20cute%20big%20circular%20reflective%20eyes,%20dof,%20(cinematic%20film),%20Disney%20realism,%20subtle%20details,%20breathtaking%20Pixar%20short,%20fine%20details,%20close%20up,%20sharp%20focus,%20HDR,%20Disney-style%20octane%20render,%20incredible%20composition,%20superb%20lighting%20and%20detail,%20%5Binput.description%5D%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20worst%20quality,%20poorly%20drawn,%20bad%20art,%20boring,%20deformed,%20bad%20composition,%20crappy%20artwork,%20bad%20lighting%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bdisney:95,%20render:80,%20portrait:75,%20cartoon:90%7D)%5D%5Cn%20%202D%20Disney%20Character%5Cn%20%20%20%20prompt%20=%202D%20cartoon%20Disney%20character%20digital%20art%20of%20%5Binput.description%5D.%20superb%20linework,%20classic%202D%20Disney%20style%20art,%20close-up,%20inspired%20by%20the%20art%20styles%20of%20Glen%20Keane%20and%20Aaron%20Blaise,%20Disney-style%20character%20concept%20with%20a%20Disney-style%20face,%20(trending%20on%20artstation),%20Disney-style%20version%20of%20%5Binput.description%5D%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%203D%20render,%20bad%203D%20shadowing,%20worst%20quality,%20poorly%20drawn,%20low-resolution%20render,%20bad%20colors,%20a%20photo,%20terrible%20art,%20text,%20logo,%20bad%20composition,%20bad%20lighting,%20disfigured,%20deformed,%20bad%20anatomy,%20crappy%20educational%20infographic%20cartoon,%20bad%203D%20render,%20black%20and%20white%20photo%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bdisney:90,%20portrait:75,%20cartoon:100,%20comic:80,%20drawing:75%7D)%5D%5Cn%20%20Disney%20Sketch%5Cn%20%20%20%20prompt%20=%20Glen%20Keane%20character%20concept%20art%20(black%20and%20white)%20pencil%20sketch%20of%20%5Binput.description%5D.%20(rough%20pencil%20sketch%20by%20Glen%20Keane:1.2),%20rough%20pencil%20sketch,%20close%20up,%20loose%20Disney-style%20character%20concept%20art%20sketch,%20(nice%20sketchy%20pencil%20strokes),%20Disney%20character%20design%20sketch,%20pencil%20texture,%20a%20concept%20art%20pencil%20sketch%20of%20%5Binput.description%5D,%20(by%20Glen%20Keane:1.3)%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20a%20photo,%20photorealistic%20style,%20with%20color,%20(a%20bad%20photo),%20bad%20digital%20art,%20bad%203D%20render,%20gradient,%20overly%20detailed,%20high%20contrast,%20bloom,%20a%20color%20photo,%20smooth%20shading,%20hilariously%20bad%20drawings,%20bad%20anatomy,%20bad%20art,%203D,%20a%20photo,%20soft%20shadows,%20lot%20of%20color%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bdisney:90,%20cartoon:85,%20sketch:80,%20comic:80,%20drawing:70%7D)%5D%5Cn%20%20Concept%20Sketch%5Cn%20%20%20%20prompt%20=%20black%20and%20white%20technical%20drawing%20showcasing%20%7Ba%7D%20%5Binput.description%5D,%20annotation%20details,%20masterpiece%20black%20and%20white,%20pencil%20strokes,%20annotated%20technical%20concept%20art%20sketch,%20pencil%20texture%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bsketch:75,%20comic:50,%20drawing:75%7D)%5D%20%5Cn%20%20Painterly%5Cn%20%20%20%20prompt%20=%20painterly%20digital%20painting,%20%5Binput.description%5D,%20digital%20painting%20by%20Ilya%20Kuvshinov%20with%20painterly%20brush%20strokes,%20by%20Ilya%20Kuvshinov,%20painterly%20masterpiece%5Cn%20%20%20%20negative%20=%20brush,%20%5Binput.negative%5D,%20bad%203D%20render,%20(holding%20paintbrush),%20easel,%20bad%20photo,%20bad%20art,%20boring,%20bad%203D%20render%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:85,%20landscape:65,%20digitalPainting:95,%20drawing:45%7D)%5D%5Cn%20%20Oil%20Painting%5Cn%20%20%20%20prompt%20=%20breathtaking%20alla%20prima%20oil%20painting,%20%5Binput.description%5D,%20close%20up,%20(alla%20prima%20style:1.3),%20oil%20on%20linen,%20painterly%20oil%20on%20canvas,%20(painterly%20style:1.3),%20exquisite%20composition%20and%20lighting,%20modern%20painterly%20masterpiece,%20by%20alexi%20zaitsev,%20award-winning%20painterly%20alla%20prima%20oil%20painting%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20framed,%20faded%20colors,%20terrible%20photo,%20bad%20composition,%20hilariously%20bad%20drawing,%20bad%20photo,%20bad%20anatomy,%20extremely%20high%20contrast,%20worst%20quality,%20watermarked%20signature,%20bad%20colors,%20deformed,%20amputee,%20washed%20out,%20glare,%20boring%20colors,%20bad%20crayon%20drawing%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:87,%20oilPainting:100,%20landscape:60,%20portrait:65,%20drawing:40%7D)%5D%5Cn%20%20Oil%20Painting%20-%20Realism%5Cn%20%20%20%20prompt%20=%20breathtaking%20oil%20painting,%20%5Binput.description%5D,%20photorealistic%20oil%20painting,%20by%20charlie%20bowater,%20fine%20details,%20by%20wlop,%20trending%20on%20artstation,%20very%20detailed%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20worst%20quality%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:87,%20oilPainting:95,%20landscape:60,%20portrait:70,%20drawing:40%7D)%5D%5Cn%20%20Oil%20Painting%20-%20Old%5Cn%20%20%20%20prompt%20=%20(%5Binput.description%5D)%20(Oil%20painting)%20(by%20Jean-Fran%C3%A7ois%20Millet),%20(by%20Gustave%20Courbet),%20(by%20Jules%20Breton),%20close%20up%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20frame,%20(badly%20drawn%20hands),%20extra%20limbs,%20extra%20fingers,%20bad%20anatomy%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:85,%20oilPainting:90,%20landscape:55,%20portrait:65,%20drawing:35%7D)%5D%5Cn%20%20Professional%20Photo%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20%7Bsharp%7Csoft%7D%20focus,%20depth%20of%20field,%208k%20photo,%20HDR,%20professional%20lighting,%20taken%20with%20Canon%20EOS%20R5,%2075mm%20lens%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20worst%20quality,%20bad%20lighting,%20cropped,%20blurry,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20bad%20art,%20bad%20angle,%20boring,%20low-resolution,%20worst%20quality,%20bad%20composition,%20terrible%20lighting,%20bad%20anatomy%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:95,%20portrait:60%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20color%20=%20%5BphotoModifiers.color%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%20Anime%5Cn%20%20%20%20prompt%20=%20(anime%20art%20of%20%5Binput.description%5D:1.2),%20masterpiece,%204k,%20best%20quality,%20anime%20art%5Cn%20%20%20%20negative%20=%20(worst%20quality,%20low%20quality:1.3),%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20hilariously%20bad%20drawing,%20bad%203D%20render%5Cn%20%20%20%20meta:tags%20=%20%5B(%7BbasicAnime:100,%20anime:60,%20drawing:50,%20cartoon:30%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BanimeModifiers%5D%5Cn%20%20Drawn%20Anime%5Cn%20%20%20%20prompt%20=%20digital%20art%20drawing,%20illustration%20of%20(%5Binput.description%5D),%20anime%20drawing/art,%20bold%20linework,%20illustration,%20cel%20shaded,%20painterly%20style,%20digital%20art,%20masterpiece%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20boring%20flat%20infographic,%20oversaturated,%20bad%20photo,%20terrible%203D%20render,%20bad%20anatomy,%20worst%20quality,%20greyscale,%20black%20and%20white,%20disfigured,%20deformed,%20glitch,%20cross-eyed,%20lazy%20eye,%20ugly,%20deformed,%20distorted,%20glitched,%20lifeless,%20low%20quality,%20bad%20proportions%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:60,%20drawing:85,%20drawnAnime:100,%20cartoon:40%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BanimeModifiers%5D%5Cn%20%20Cute%20Anime%5Cn%20%20%20%20prompt%20=%20(((adorable,%20cute,%20kawaii)),%20%5Binput.description%5D,%20cute%20moe%20anime%20character%20portrait,%20adorable,%20featured%20on%20pixiv,%20kawaii%20mo%C3%A9%20masterpiece,%20cuteness%20overload,%20very%20detailed,%20sooooo%20adorable!!!,%20absolute%20masterpiece%5Cn%20%20%20%20negative%20=%20(worst%20quality,%20low%20quality:1.3),%20%5Binput.negative%5D,%20worst%20quality,%20ugly,%203D,%20photograph,%20bad%20art,%20blurry,%20boring%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:55,%20drawing:50,%20cuteAnime:100,%20cartoon:30%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BanimeModifiers%5D%5Cn%20%20Soft%20Anime%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20anime%20masterpiece,%20soft%20lighting,%20intricate,%20highly%20detailed,%20pixiv,%20anime%20art,%204k,%20art%20from%20your%20name%20anime,%20garden%20of%20words%20style%20art,%20high%20quality%5Cn%20%20%20%20negative%20=%20(worst%20quality,%20low%20quality:1.3),%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:50,%20drawing:50,%20cartoon:30%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BanimeModifiers%5D%5Cn%20%20Fantasy%20Painting%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20d&d,%20fantasy,%20highly%20detailed,%20digital%20painting,%20artstation,%20sharp%20focus,%20fantasy%20art,%20illustration,%208k,%20in%20the%20style%20of%20greg%20rutkowski%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:50,%20landscape:80,%20fantasy:80%7D)%5D%5Cn%20%20Fantasy%20Landscape%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20fantasy%20matte%20painting,%20absolute%20masterpiece,%20detailed%20matte%20painting%20by%20andreas%20rocha%20and%20greg%20rutkowski,%20by%20Brothers%20Hildebrandt,%20superb%20composition,%20vivid%20fantasy%20art,%20breathtaking%20fantasy%20masterpiece%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20faded,%20blurry,%20bad%20art,%20boring%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:30,%20poster:30,%20coverArt:50,%20vintage:30,%20landscape:90,%20fantasy:20%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BlandscapeModifiers.shot%5D%5Cn%20%20%20%20%20%20color%20=%20%5BlandscapeModifiers.color%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BlandscapeModifiers.effect%5D%5Cn%20%20Fantasy%20Portrait%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20d&d,%20fantasy,%20highly%20detailed,%20digital%20painting,%20artstation,%20sharp%20focus,%20fantasy%20art,%20character%20art,%20illustration,%208k,%20art%20by%20artgerm%20and%20greg%20rutkowski%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7BfantasyPortrait:100,%20painting:50,%20fantasy:70,%20portrait:75%7D)%5D%5Cn%20%20Studio%20Ghibli%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20(studio%20ghibli%20style%20art:1.3),%20sharp,%20very%20detailed,%20high%20resolution,%20inspired%20by%20hayao%20miyazaki,%20anime,%20art%20from%20ghibli%20movie%5Cn%20%20%20%20negative%20=%20(worst%20quality,%20low%20quality:1.3),%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bghibli:100,%20anime:50,%20cartoon:50%7D)%5D%5Cn%20%2050s%20Enamel%20Sign%5Cn%20%20%20%20prompt%20=%2050s%20enamel%20sign%20of%20%5Binput.description%5D,%2050s%20advert%20enamel%20sign,%20masterpiece,%20authentic%20vintage%20enamel%20sign%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bvintage:85%7D)%5D%5Cn%20%20Vintage%20Comic%5Cn%20%20%20%20prompt%20=%20comic%20book%20style%20art%20of%20%5Binput.description%5D,%20(drawing,%20by%20Dave%20Stevens,%20by%20Adam%20Hughes,%201940's,%201950's:1.2),%20hand-drawn,%20color,%20high%20resolution,%20best%20quality,%20closeup%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20terrible%20photoshop,%20low%20contrast,%20disfigured,%20poorly%20drawn,%20deformed,%20tiled,%20cropped,%20framed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bvintage:80,%20comic:90,%20cartoon:70%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20effect%5Cn%20%20%20%20%20%20%20%20retrofuturism%20=%20,%20(retrofuturism,%20atompunk)%5Cn%20%20%20%20%20%20%20%20gritty%20noir%20=%20,%20(gritty%20noir)%5Cn%20%20%20%20%20%20%20%20pop%20art%20=%20,%20(pop%20art%20style)%5Cn%20%20%20%20%20%20%20%20cyberpunk%20=%20,%20(cyberpunk%20aesthetic)%5Cn%20%20%20%20%20%20%20%20steampunk%20=%20,%20(steampunk)%5Cn%20%20%20%20%20%20%20%20watercolor%20=%20,%20(watercolor%20wash)%5Cn%20%20%20%20%20%20%20%20sketchy%20ink%20=%20,%20sketchy%20ink%20work%5Cn%20%20%20%20%20%20%20%20manga%20fusion%20=%20,%20(manga%20fusion)%5Cn%20%20%20%20%20%20%20%20psychedelic%20=%20,%20psychedelic%20imagery%5Cn%20%20%20%20%20%20%20%20pulp%20magazine%20=%20,%20pulp%20magazine%20look%5Cn%20%20%20%20%20%20%20%20heroic%20proportions%20=%20,%20heroic%20proportions%5Cn%20%20Franco-Belgian%20Comic%5Cn%20%20%20%20prompt%20=%20franco-belgian%20color%20comic%20about%20%5Binput.description%5D,%20bande%20dessin%C3%A9e,%20franco-belgian%20comic%20panel,%20masterpiece,%20breathtaking%20composition,%20intricate,%20detailed,%20best%20quality,%20close-up%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20framed%20blurry%20crappy%20photo,%20overexposed,%20worst%20quality,%20border,%20deformed%20horror,%20overly%20faded%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bvintage:75,%20comic:85,%20cartoon:75%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20modifier%5Cn%20%20%20%20%20%20%20%20single-panel%20=%20,%20splash%20panel,%20full%20cover%20image%5Cn%20%20%20%20%20%20%20%20multi-panel%20=%20,%20multi-panel%20comic%20book%20page,%20comic%20panel%20layout%5Cn%20%20%20%20%20%20%20%20cyberpunk%20=%20,%20(cyberpunk%20aesthetic)%5Cn%20%20%20%20%20%20%20%20steampunk%20=%20,%20(steampunk)%5Cn%20%20%20%20%20%20%20%20manga%20fusion%20=%20,%20(manga%20fusion)%5Cn%20%20%20%20%20%20%20%20psychedelic%20=%20,%20psychedelic%20imagery%5Cn%20%20%20%20%20%20%20%20pulp%20magazine%20=%20,%20pulp%20magazine%20look%5Cn%20%20%20%20%20%20%20%20heroic%20proportions%20=%20,%20heroic%20proportions%5Cn%20%20Tintin%20Comic%5Cn%20%20%20%20prompt%20=%20color%20comic%20panel%20in%20the%20style%20of%20Herg%C3%A9%20about%20%5Binput.description%5D,%20by%20Herg%C3%A9,%20tintin%20style,%20french%20comic%20panel,%20franco-belgian%20style,%20close-up,%20masterpiece,%20high-resolution%20Herg%C3%A9%20style%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20blurry,%20framed%20edge%20border,%20text,%20overexposed,%20bad%20anatomy,%20deformed,%20disfigured,%20blur,%20horror,%20dead%20eyes,%20boring,%20faded,%20(worst%20quality,%20low%20quality:1.2)%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bvintage:77,%20comic:87,%20cartoon:77%7D)%5D%5Cn%20%20//%20Vintage%20Comic%5Cn%20%20//%20%20%20prompt%20=%20comic%20book%20style%20art%20of%20%5Binput.description%5D,%20(drawing%20by%20Jack%20Kirby,%20Steve%20Ditko%20art,%201940's,%201950's:1.2),%20closeup,%20color,%20vintage%20masterpiece,%20best%20quality%5Cn%20%20//%20%20%20negative%20=%20%5Binput.negative%5D,%20worst%20quality,%20low%20resolution,%20fuzzy,%20jpeg%20compression%20artifacts,%20blurry,%20low%20quality%5Cn%20%20//%20%20%20meta:tags%20=%20%5B(%7Bvintage:80,%20comic:90,%20cartoon:70%7D)%5D%5Cn%20%20//%2090s%20Comic%5Cn%20%20//%20%20%20prompt%20=%20%5Binput.description%5D,%20(90s%20comic%20book%20artwork),%20colored%20comic%20book%20panel,%20classic%2090s%20style,%20masterpiece%5Cn%20%20//%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20photo,%20greyscale,%20blurry,%20bad%203D%20render,%20crappy%203D%20art,%20barcode,%20logo,%20bad%20photo%5Cn%20%20//%20%20%20meta:tags%20=%20%5B(%7Bvintage:80,%20comic:80%7D)%5D%5Cn%20%20//%2090s%20Superhero%5Cn%20%20//%20%20%20prompt%20=%20%5Binput.description%5D,%20(90s%20comic%20book%20artwork),%20colored%20comic%20book%20panel,%20classic%2090s%20style,%20masterpiece,%20art%20by%20Greg%20Capullo,%20art%20by%20Jim%20Lee,%20art%20by%20Todd%20McFarlane%5Cn%20%20//%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20photo,%20greyscale,%20blurry,%20bad%203D%20render,%20crappy%203D%20art,%20barcode,%20logo,%20bad%20photo%5Cn%20%20//%20%20%20meta:tags%20=%20%5B(%7Bvintage:80,%20comic:80%7D)%5D%5Cn%20%20Medieval%5Cn%20%20%20%20prompt%20=%20medieval%20illuminated%20manuscript%20picture%20of%20%5Binput.description%5D,%20medieval%20illuminated%20manuscript%20art,%20masterpiece%20medieval%20color%20illustration,%2016th%20century,%208k%20high-resolution%20scan%20of%2016th%20century%20illuminated%20manuscript%20painting,%20detailed%20medieval%20masterpiece,%20close-up%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20worst%20quality,%20blurry%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bvintage:80,%20painting:70,%20portrait:40%7D)%5D%5Cn%20%20Pixel%20Art%5Cn%20%20%20%20prompt%20=%20%5Binput.description.length%20%3E%2040%20?%20%5C%22(pixel%20art),%20%5C%22%20:%20%5C%22%5C%22%5D%5Binput.description%5D,%20best%20pixel%20art,%20neo-geo%20graphical%20style,%20retro%20nostalgic%20masterpiece,%20128px,%2016-bit%20pixel%20art%20%5Binput.description.length%20%3C%2010%20?%20%5C%22of%20%5C%22+input.description%20:%20%5C%22%5C%22%5D,%202D%20pixel%20art%20style,%20adventure%20game%20pixel%20art,%20inspired%20by%20the%20art%20style%20of%20hyper%20light%20drifter,%20masterful%20dithering,%20superb%20composition,%20beautiful%20palette,%20exquisite%20pixel%20detail%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20glitched,%20deep%20fried,%20jpeg%20artifacts,%20out%20of%20focus,%20gradient,%20soft%20focus,%20low%20quality,%20poorly%20drawn,%20blur,%20grainy%20fabric%20texture,%20text,%20bad%20art,%20boring%20colors,%20blurry%20platformer%20screenshot%5Cn%20%20%20%20meta:tags%20=%20%5B(%7BpixelArt:90,%20vintage:70%7D)%5D%5Cn%20%20%20%20//%20randomPrompt%20=%20%7Bmermaid%7Cgoblin%7D%5Cn%20%20Furry%20-%20Oil%5Cn%20%20%20%20prompt%20=%20(%5Binput.description%5D:1.3),%20crisp%20vibrant%20detailed%20soft%20painterly%20digital%20art,%20volumetric%20lighting,%20natural%20lighting,%20realistic%20lighting,%20vibrant%20colors,%20crisp%20oil%20painting,%20painterly%20realism,%20depth%20of%20field,%20subtle%20soft%20details,%20vivid,%20fresh,%20striking,%20by%20chunie,%20by%20darkgem,%20by%20honovy,%20by%20zaush,%20by%20anhes,%20by%20puinkey,%20by%20caraid,%20by%20dagasi,%20by%20taranfiddler,%20by%20atey%20ghailan,%20by%20MilletGustave,%20by%20Curbet,%20Charlie%20Bowater,%20lol%20art%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20blurry,%20faded,%20antique,%20muted%20colors,%20greyscale,%20boring%20colors,%20flat,%20bad%20photo,%20terrible%203D%20render,%20bad%20anatomy,%20worst%20quality,%20greyscale,%20black%20and%20white,%20disfigured,%20deformed,%20glitch,%20cross-eyed,%20lazy%20eye,%20ugly,%20deformed,%20distorted,%20glitched,%20lifeless,%20low%20quality,%20bad%20proportions,%20watermark,%20signature%5Cn%20%20%20%20meta:tags%20=%20%5B(%7BfurryOil:100,%20furry:100%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BfurryModifiers%5D%5Cn%20%20Furry%20-%20Cinematic%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20cinematic%20shot,%20dynamic%20lighting,%2075mm,%20Technicolor,%20Panavision,%20cinemascope,%20sharp%20focus,%20fine%20details,%208k,%20HDR,%20realism,%20realistic,%20key%20visual,%20film%20still,%20cinematic%20color%20grading,%20depth%20of%20field,%20(anthro:0.1)%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20lighting,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20holding%20camera,%20bad%20art,%20bad%20angle,%20boring,%20low-resolution,%20worst%20quality,%20bad%20composition,%20disfigured%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bfurry:97,%20photo:60,%20portrait:40,%20render:75,%20cinematic:65%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20effect%20=%20%5BfurryModifiers.effect%5D%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20color%20=%20%5BphotoModifiers.color%5D%5Cn%20%20%20%20%20%20photo%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%20Furry%20-%20Painted%5Cn%20%20%20%20prompt%20=%20anthro%20%5Binput.description%5D%20digital%20art,%20masterpiece,%204k,%20fine%20details%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20photo,%20worst%20quality,%20bad%20composition,%20bad%20lighting,%20bad%20colors,%20small%20eyes,%20low%20quality,%20bad%20art,%20poorly%20drawn,%20deformed,%20bad%203D%20render,%20boring,%20lifeless,%20deformed,%20ugly,%20low%20resolution%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bfurry:96%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BfurryModifiers%5D%5Cn%20%20Furry%20-%20Drawn%5Cn%20%20%20%20prompt%20=%20anthro%20%5Binput.description%5D%20illustration,%20hand-drawn,%20bold%20linework,%20anthro%20illustration,%20cel%20shaded,%204k,%20fine%20details,%20masterpiece%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20photo,%20terrible%203D%20render,%20bad%20anatomy,%20worst%20quality,%20greyscale,%20black%20and%20white,%20disfigured,%20deformed,%20glitch,%20cross-eyed,%20lazy%20eye,%20ugly,%20deformed,%20distorted,%20glitched,%20lifeless,%20low%20quality,%20bad%20proportions%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bfurry:95%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BfurryModifiers%5D%20%5Cn%20%20Cute%20Figurine%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20figurine,%20modern%20Disney%20style,%20octane%20render,%20chibi%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bdisney:20,%20emoji:60%7D)%5D%5Cn%20%203D%20Emoji%5Cn%20%20%20%20prompt%20=%20masterpiece%20((%5Binput.description%5D))%20cartoon%20emoji%20concept%20render,%20(close-up:1.3),%20facing%20forward,%20(matte),%20emoji%20render%20trending%20on%20artstation,%20noto%20color%20emoji,%20app%20icon,%20joypixels,%20simple%20design,%20new%20iOS%2016.4%20(((%5Binput.description%5D)))%20emoji%20render,%20(simple%20background:1.2),%20(centered:1.2),%20masterpiece,%20telegram%20sticker,%20clash%20of%20clans%20character%20concept,%20(looking%20at%20camera),%20crisp%20render,%20sharp%20focus,%20simple%20cartoon%20design,%204k,%20sharp%20focus,%20an%20emoji%20with%20cartoon%20proportions,%20masterpiece%20emoji-style%20figurine%20render,%20transparent%20background%20png%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20framed,%20inset,%20border,%20glare,%20blurry,%20out%20of%20focus,%20shiny,%20(on%20pedestal:1.2),%20on%20platform,%20with%20base,%20gradient%20background,%20off-center,%20casting%20shadow,%20((deformed,%20disfigured)),%20glitchy,%20vector%20art,%20text,%20signature,%20bad%20anatomy,%20messed%20up,%20bad%20art,%20gradient%20background,%20complex%20background,%20blurry,%20worst%20quality,%20low%20resolution,%20messy,%20complex,%20gradient%20background,%20bad%20lighting%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bemoji:90%7D)%5D%5Cn%20%20Illustration%5Cn%20%20%20%20prompt%20=%20breathtaking%20illustration%20of%20%5Binput.description%5D,%20(illustration:1.3),%20masterpiece,%20breathtaking%20illustration%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20bad%203D%20render,%20bad%20composition,%20bad%20photo,%20worst%20quality%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Billustration:100,%20drawing:75%7D)%5D%5Cn%20%20Flat%20Illustration%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20illustration,%20flat,%202D,%20vector%20art,%20masterpiece,%20made%20with%20adobe%20illustrator,%20behance%20competition%20winner,%20trending%20on%20dribble,%204k,%20high%20resolution,%20crisp%20lines%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20art,%20children's%20crayon%20drawing,%20worst%20quality,%20blurry,%20blur,%20jpeg%20artifacts,%20compression%20artifacts,%20text,%20worst%20quality,%20noise,%20messy,%20low%20resolution%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Billustration:85,%20drawing:40%7D)%5D%5Cn%20%20Watercolor%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20(watercolor),%20high%20resolution,%20intricate%20details,%204k,%20wallpaper,%20concept%20art,%20watercolor%20on%20textured%20paper%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:30%7D)%5D%5Cn%20%201990s%20Photo%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%2090s%20home%20video,%20nostalgic%2090s%20photo,%20taken%20with%20kodak%20disposable%20camera%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20blurry,%20blur,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bvintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%20%5Cn%20%20%20%20%20%20color%20=%20%5BphotoModifiers.color%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201980s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%2080s%20photo,%20%5Binput.description%5D,%20grainy%20photograph,%2080s%20photo%20with%20film%20grain,%20Kodacolor%20II%2080s%20photo%20with%20vignetting,%20retro,%20r/OldSchoolCool,%2080s%20photo%20with%20wear%20and%20tear%20and%20minor%20creasing%20and%20scratches,%20vintage%20color%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:90,%20portrait:72%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201970s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%2070s%20photo,%20%5Binput.description%5D,%20grainy%20photograph,%201970s%20photo%20with%20film%20grain,%2070s%20photo%20with%20vignetting,%20retro,%20r/OldSchoolCool,%2070s%20photo,%20vintage%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201960s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%2060s%20photo,%20%5Binput.description%5D,%20grainy%20photograph,%201960s%20photo%20with%20film%20grain,%2060s%20photo%20with%20vignetting,%20retro,%20r/OldSchoolCool,%2060s%20photo,%20vintage%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201950s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%2050s%20photo,%20%5Binput.description%5D,%20grainy%20photograph,%201950s%20photo%20with%20film%20grain,%201950s%20photo%20with%20vignetting,%20retro,%20r/OldSchoolCool,%201950s%20photo,%20vintage%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201940s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%201940s%20photo,%20%5Binput.description%5D,%20grainy%20photograph,%201940s%20photo%20with%20film%20grain,%201940s%20photo%20with%20vignetting,%20retro,%20r/OldSchoolCool,%201940s%20photo,%20vintage%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201930s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%201930s%20photo,%20%5Binput.description%5D,%20grainy%20photograph,%201930s%20photo%20with%20film%20grain,%201930s%20photo%20with%20vignetting,%20retro,%20r/OldSchoolCool,%201930s%20photo,%20vintage%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%201920s%20Photo%5Cn%20%20%20%20prompt%20=%20famous%20vintage%201920s%20photo,%20%5Binput.description%5D,%201920s%20photo,%20restored%20photograph,%20%7Bsepia%7Cblack%20and%20white%7D,%20historical%20archive%20photo%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bphoto:30,%20vintage:80%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20shot%20=%20%5BphotoModifiers.shot%5D%5Cn%20%20%20%20%20%20effect%20=%20%5BphotoModifiers.effect%5D%5Cn%20%20Vintage%20Pulp%20Art%5Cn%20%20%20%20prompt%20=%20(((1970s%20vintage%20pulp%20art))),%20%5Binput.description%5D,%20vintage%20pulp%20art,%20by%20Earle%20K.%20Bergey,%20by%20Kelly%20Freas,%20by%20Alex%20Schomburg,%20by%20H.%20J.%20Ward,%20glossy%20pulp%20art,%20Amazing%20Stories,%20Weird%20Tales,%208k,%20high%20resolution,%20best%20quality%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20text,%20cropped,%20bad%20art,%20deformed,%20worst%20quality,%20watermark,%20text%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:30,%20poster:30,%20coverArt:50,%20vintage:60,%20comic:40,%20cartoon:50%7D)%5D%5Cn%20%2050s%20Infomercial%20Anime%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%201950s%20infomercial%20style,%20(delicate%20linework:1.1),%20paprika%20anime%20art%20style,%20close-up,%20(chromatic%20aberration%20glow:1.2),%202d%20painted%20cel%20animation,%20close-up,%20soft%20focus,%202D%20pixiv%201950s%5Cn%20%20%20%20negative%20=%20worst%20quality,%20low%20quality,%20%5Binput.negative%5D,%20neon%20tube,%20bad%20art,%20messy,%20disfigured,%20bad%20anatomy,%20out%20of%20focus,%20grainy,%20blurry,%20jpeg%20artifact%20noise,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpainting:30,%20anime:50,%20vintage:60,%20cartoon:50%7D)%5D%5Cn%20%203D%20Pokemon%5Cn%20%20%20%20prompt%20=%20a%20pokemon%20creature,%20((%5Binput.description%5D)),%20%5Binput.pokemonType%20?%20input.pokemonType+%5C%22,%20%5C%22%20:%20%5C%22%5C%22%5D4k%20render,%20beautiful%20pokemon%20digital%20art,%20fakemon,%20pokemon%20creature,%20cryptid,%20fakemon,%20masterpiece,%20%7Bsoft%7Csharp%7D%20focus,%20(best%20quality,%20high%20quality:1.3)%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20distorted,%20deformed,%20bad%20art,%20low%20quality,%20over%20saturated,%20extreme%20contrast,%20(worst%20quality,%20low%20quality:1.3)%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpokemon:60%7D)%5D%5Cn%20%20Painted%20Pokemon%5Cn%20%20%20%20prompt%20=%20(%5Binput.description%5D),%20%5Binput.pokemonType%20?%20input.pokemonType+%5C%22,%20%5C%22%20:%20%5C%22%5C%22%5D4k%20digital%20painting%20of%20a%20pokemon,%20amazing%20pokemon%20creature%20art%20by%20piperdraws,%20cryptid%20creations%20by%20Piper%20Thibodeau,%20by%20Naoki%20Saito%20and%20%7BTokiya%7CMitsuhiro%20Arita%7D,%20incredible%20composition%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20crappy%203D%20render,%20distorted,%20deformed,%20bad%20art,%20low%20quality,%20text,%20signature%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpokemon:50%7D)%5D%5Cn%20%202D%20Pokemon%5Cn%20%20%20%20prompt%20=%20(%5Binput.description%5D:1.2),%20%5Binput.pokemonType%20?%20input.pokemonType+%5C%22,%20%5C%22%20:%20%5C%22%5C%22%5Dpokemon%20creature%20concept,%20superb%20line%20art,%20beautiful%20colors%20and%20composition,%202d%20art%20style,%20beautiful%20pokemon%20digital%20art,%20fakemon,%20by%20Sowsow,%20pokemon%20creature,%20cryptid,%20fakemon,%20masterpiece,%20by%20Yuu%20Nishida,%204k%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20multiple,%20grid,%20(black%20and%20white),%20distorted,%20deformed,%20bad%20art,%20low%20quality,%20crappy%203D%20render,%20text%20watermark%20symbols%20logo%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bpokemon:70,%20drawing:50,%20cartoon:35%7D)%5D%5Cn%20%20Vintage%20Anime%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%201990s%20anime,%20vintage%20anime,%2090's%20anime%20style,%20by%20hajime%20sorayama,%20by%20greg%20tocchini,%20anime%20masterpiece,%20pixiv,%20akira-style%20art,%20akira%20anime%20art,%204k,%20high%20quality%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20(worst%20quality,%20low%20quality:1.3),%20bad%20art,%20distorted,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:40,%20vintage:50,%20drawing:50%7D)%5D%5Cn%20%20Neon%20Vintage%20Anime%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20((neon%20vintage%20anime))%20style,%2090's%20anime%20style,%201990s%20anime,%20hajime%20sorayama,%20greg%20tocchini,%20neon%20vintage%20anime%20masterpiece,%20anime%20art,%204k,%20high%20quality%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20blurry,%20(worst%20quality,%20low%20quality:1.3),%20bad%20art,%20distorted,%20deformed%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:30,%20vintage:50%7D)%5D%5Cn%20%20Manga%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20incredible%20hand-drawn%20manga,%20black%20and%20white,%20by%20Takehiko%20Inoue,%20by%20Katsuhiro%20Otomo%20and%20akira%20toriyama%20manga,%20hand-drawn%20art%20by%20rumiko%20takahashi%20and%20Inio%20Asano,%20Ken%20Akamatsu%20manga%20art%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20(worst%20quality,%20low%20quality:1.3),%20bad%20photo,%20bad%203D%20render,%20distorted,%20deformed,%20fuzzy,%20noisy,%20blurry,%20smudge%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:40,%20drawing:50,%20manga:100,%20comic:20,%20cartoon:30%7D)%5D%5Cn%20%20Fantasy%20World%20Map%5Cn%20%20%20%20prompt%20=%20beautiful%20fantasy%20map%20of%20%5Binput.description%5D,%20beautiful%20fantasy%20map%20inspired%20by%20middle%20earth%20and%20azeroth%20and%20discworld%20and%20westeros%20and%20essos%20and%20the%20witcher%20world%20and%20tamriel%20and%20faer%C3%BBn%20and%20thedas,%204k,%20beautiful%20colors,%20crisp,%20high-resolution%20artistic%20map,%20topographic%203D%20terrain,%20artistic%20map%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low%20quality,%20blurry,%20worst%20quality,%20childrens%20drawing,%20boring,%20logo,%20scratchy%20and%20grainy,%20messy,%20washed%20out%20colors,%20sepia,%20hazy%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bmap:90,%20fantasy:20%7D)%5D%5Cn%20%20Fantasy%20City%20Map%5Cn%20%20%20%20prompt%20=%20an%20aerial%20view%20of%20a%20city,%20TTRPG%20city%20map%20showing%20the%20full%20city,%20%5Binput.description%5D,%20fantasy%20art,%20by%20senior%20environment%20artist,%20beautiful%20fantasy%20map%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20fuzzy,%20bad%20art%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bmap:80,%20fantasy:20%7D)%5D%5Cn%20%20Old%20World%20Map%5Cn%20%20%20%20prompt%20=%20fantasy%20world%20map%20of%20%5Binput.description%5D,%20fantasy%20world%20map,%20highly%20detailed%20digital%20painting,%20fantasy%20art,%20map%20illustration,%208k%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low%20resolution,%20worst%20quality%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bmap:70,%20fantasy:20%7D)%5D%5Cn%20%203D%20Isometric%20Icon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%203D%20isometric%20render%20of%20cute%20%5Binput.description%5D,%203D%20app%20icon,%20clean%20isometric%20design,%20beautiful%20design,%20soft%20gradient%20background,%20soft%20colors,%20centered,%203D%20blender%20render,%20masterpiece,%20best%20quality,%20high%20resolution,%208k%20octane%20render,%20beautiful%20color%20scheme,%20soft%20smooth%20lighting,%20physically%20based%20rendering,%20square%20image,%20high%20polycount%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low%20quality,%20terrible%20design,%20glitchy%20compression%20artefacts,%20deformed,%20blurry%20compression%20artefacts,%20text%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:90,%20emoji:86%7D)%5D%5Cn%20%20Flat%20Style%20Icon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20creative%20icon,%20flat%20style%20icon,%20masterpiece,%20high%20resolution,%20crisp,%20beautiful%20composition%20and%20color%20choice,%20beautiful%20flat%20painted%20style,%20behance%20contest-winner,%20award%20winning%20icon%20illustration,%208k,%20best%20quality%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20gradient,%20bad%20design,%20blurry,%20jpeg%20compression%20artefacts,%20grainy,%20gradient,%20text,%20messy%20and%20inconsistent%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:80%7D)%5D%5Cn%20%20Flat%20Style%20Logo%5Cn%20%20%20%20prompt%20=%20beautiful%20flat-style%20logo%20design%20depicting%20%5Binput.description%5D,%20creative%20flat-style%20logo%20design,%20trending%20on%20dribbble,%20featured%20on%20behance,%20portfolio%20piece,%20minimal%20flat%20design,%20breathtaking%20graphic%20design,%208k,%20high%20resolution%20vector%20logo,%20plain%20background,%20amazingly%20beautiful%20logo%20design,%20winner%20of%20best%20logo%20award%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20photo,%20hilariously%20bad%20design,%20bad%20composition,%20bad%20colors,%20blurry,%20worst%20quality,%20low%20quality,%20shadow,%20boring,%20bad%20dsign,%20worst%20design%20ever,%20hilariously%20bad%20design,%20drop-shadow,%20gradient,%20messy,%20chaotic%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:80,%20logo:80%7D)%5D%5Cn%20%20Game%20Art%20Icon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20a%20concept%20art%20icon%20for%20league%20of%20legends,%20a%20digital%20art%20logo,%20illustration,%20league%20of%20legends%20style%20icon,%20inspired%20by%20wlop%20style,%208k,%20dota%202%20style%20icon,%20fine%20details,%20sharp,%20very%20detailed%20icon,%20high%20resolution%20rpg%20ability/spell/item%20icon%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20multiple%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:70%7D)%5D%5Cn%20%20Digital%20Painting%20Icon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20app%20logo%20icon,%20digital%20art%20pictogram%20icon,%20trending%20on%20artstation,%20app%20icon%20by%20atey%20ghailan,%20app%20icon%20by%20greg%20rutkowski,%20app%20icon%20by%20greg%20tocchini,%20app%20icon%20by%20james%20gilleard,%208k,%20high%20resolution,%20best%20quality%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20photo,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:60%7D)%5D%5Cn%20%20Concept%20Art%20Icon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20a%20concept%20art%20icon,%20a%20digital%20art%20logo,%20illustration,%20league%20of%20legends%20style%20concept%20art%20logo%20icon,%20inspired%20by%20wlop%20style,%208k,%20fine%20details,%20sharp,%20very%20detailed,%20high%20resolution%20logo%20icon%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn,%20multiple%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:50%7D)%5D%5Cn%20%20Cute%203D%20Icon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20a%20cute%203D%20icon%20of%20%5Binput.description%5D,%20cartoon%203D%20icon,%20very%20cute%20shape,%20stylized%20octane%20render,%208k,%20masterpiece,%20soooo%20cute,%20beautiful%20cute%20perfection,%20beautiful%20soft%20lighting,%20soft%20colors,%20centered,%20high%20resolution,%20%5Binput.description%5D,%20soft%20gradient%20background%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low%20quality,%20text,%20ugly,%20gross%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:40%7D)%5D%5Cn%20%20Cute%203D%20Icon%20%F0%9D%97%A6%F0%9D%97%B2%F0%9D%98%81%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20a%20set%20of%20lovely%20little%203D%20icons,%20cute%203D%20icons,%20very%20cute%20shapes,%20stylized%20octane%20render,%208k,%20masterpiece,%20soooo%20cute,%20beautiful%20cute%20perfection,%20beautiful%20soft%20lighting,%20soft%20colors,%20centered,%20high%20resolution,%20%5Binput.description%5D,%20cute%20icon%20set%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low%20quality,%20text,%20ugly,%20gross%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bicon:30%7D)%5D%5Cn%20%20Crayon%20Drawing%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20crayon%20drawing%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20deformed,%20text,%20poorly%20drawn%5Cn%20%20Pencil%5Cn%20%20%20%20prompt%20=%20((black%20and%20white%20pencil%20drawing)),%20%5Binput.description%5D,%20black%20and%20white,%20breathtaking%20pencil%20illustration,%20highly%20detailed,%204k,%20(textured%20paper),%20pencil%20texture,%20sketch%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20stationary,%20holding%20pen,%20holding%20paper,%20low-quality,%20deformed,%20photo,%203D%20render,%20text,%20poorly%20drawn%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bdrawing:45%7D)%5D%5Cn%20%20Tattoo%20Design%5Cn%20%20%20%20prompt%20=%20amazing%20tattoo%20design,%20%5Binput.description%5D,%20breathtaking%20tattoo%20design,%20incredible%20tattoo%20design%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20low-quality,%20poorly%20drawn,%20blurry,%20faded,%20terrible%20design,%20worst%20quality,%20deformed,%20amputee,%20disfigured,%20ugly,%20bad,%20shitty,%20boring%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Btattoo:100%7D)%5D%5Cn%20%20Waifu%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20waifu%20character%20portrait,%20art%20by%20Kazenoko,%20featured%20on%20pixiv,%201%20girl,%20by%20Ilya%20Kuvshinov,%20Kantoku%20art,%20very%20detailed%20anime%20art%20by%20Redjuice%5Cn%20%20%20%20negative%20=%20(worst%20quality,%20low%20quality:1.3),%20%5Binput.negative%5D,%20bad%20photo,%20bad%20art,%20boring,%20bad%203D%20render,%20worst%20quality,%20ugly,%20blurry,%20low%20quality,%20poorly%20drawn,%20bad%20composition,%20deformed,%20bad%203D%20render,%20disfigured,%20bad%20anatomy,%20compression%20artifacts,%20dead,%20soulless,%20photorealistic%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Banime:40,%20waifu:100,%20cartoon:20%7D)%5D%5Cn%20%20%20%20modifiers%20=%20%5BanimeModifiers%5D%5Cn%20%20YuGiOh%20Art%5Cn%20%20%20%20prompt%20=%20yugioh%20card%20art%20for%20%5Binput.description%5D,%20art%20by%20genzoman,%20by%20Akina%20Fujiwara,%20by%20rossdraws,%20yugioh%20monster,%20close%20up,%20painterly%20details,%20breathtaking%20art,%20centered,%20masterpiece,%20amazing%20composition,%20%5Binput.description.length%20%3C%2030%20?%20input.description%20:%20%5C%22%5C%22%5D%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20Yugi%20Mutou,%20low-quality,%20blurry,%20crappy%203D%20render,%20worst%20quality,%20messy,%20noisy,%20framed,%20with%20border,%20cropped,%20confusing,%20stacked%20characters%20poster,%20low%20resolution,%20bad%203D%20render,%20fuzzy%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Byugioh:100%7D)%5D%5Cn%20%20Traditional%20Japanese%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20in%20ukiyo-e%20art%20style,%20traditional%20japanese%20masterpiece%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20blurry,%20low%20resolution,%20worst%20quality,%20fuzzy%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bjapanese:100,%20vintage:50,%20cartoon:30%7D)%5D%5Cn%20%20Nihonga%20Painting%5Cn%20%20%20%20prompt%20=%20japanese%20nihonga%20painting%20about%20%5Binput.description%5D,%20Nihonga,%20ancient%20japanese%20painting,%20intricate,%20detailed%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20framed%20blurry%20crappy%20photo,%20overly%20faded%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bjapanese:95,%20vintage:55,%20comic:70%7D)%5D%5Cn%20%20Claymation%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20claymation,%20incredible%20claymation%20style,%20kubo%20and%20the%20two%20strings%20style%20art,%20Missing%20Link%202019%20art%20style,%20clay%20texture,%20clay%20animation,%20stop-motion%20clay%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20glossy,%20creepy,%20dead%20eyes,%20lifeless%20eyes,%20blurry,%20scary,%20boring,%20tiling,%20cropped,%20terrifying,%20horror,%20out%20of%20focus%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bclaymation:100%7D)%5D%5Cn%20%20Cartoon%5Cn%20%20%20%20prompt%20=%20%5Binput.description%5D,%20cartoon-style%20art,%20superb%20linework,%20nice%20colors%20and%20composition,%20bold%20linework,%20close-up,%20(masterpiece),%20cute%20art%20by%20Dana%20Terrace,%20by%20Rebecca%20Sugar,%20by%20ry-spirit,%20amazing%20and%20wholesome%20cartoon-style%20art,%20cute%20art%20style,%20(trending%20on%20artstation)%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20bad%20art,%20boring%20art,%20hilariously%20bad%20drawings,%20bad%203D%20render,%20bad%20photo,%20blurry,%20blur,%20worst%20quality,%20boring%20colors,%20logo%20vector%20image,%20monotone,%20lifeless,%20expressionless,%20faded,%20horror,%20creepy%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bcartoon:95,%20basicCartoon:100%7D)%5D%5Cn%20%20Cursed%20Photo%5Cn%20%20%20%20prompt%20=%20cursed%20photo%20of%20%5Binput.description%5D,%20(creepy%20and%20cursed:1.2),%20absolutely%20cursed%20photo,%20nope%20nope%20nope%20nope,%20what%20the%20actual%20f,%20(unsettling%20photo:1.2),%20cursed_thing,%20cursedimages,%20no%20context,%20cursed%20image,%20bad%20photo,%20weird%20photo,%20very%20strange,%20color%20photo,%20creepy%20photo,%20(nightmare%20fuel)%5Cn%20%20%20%20negative%20=%20%5Binput.negative%5D,%20skeleton%20face,%20nice%20photo,%20lovely%20photo,%20old%20photo,%20vintage%20photo,%20greyscale,%20wholesome,%20eyebleach,%20bad%20photoshop%5Cn%20%20%20%20meta:tags%20=%20%5B(%7Bcreepy:100%7D)%5D%5Cn%20%20%20%20modifiers%5Cn%20%20%20%20%20%20modifier%5Cn%20%20%20%20%20%20%20%20found%20footage%20=%20,%20found%20footage%5Cn%20%20%20%20%20%20%20%20cult%20=%20,%20photo%20from%20a%20real%20cult%5Cn%20%20%20%20%20%20%20%201920s%20=%20,%201920s%20photo%5Cn%20%20%20%20%20%20%20%20old%20phone%20=%20,%20old%20cell%20phone%20photo%5Cn%20%20%20%20%20%20%20%20VHS%20=%20,%20old%20VHS%20footage%5Cn%20%20%20%20%20%20%20%20CCTV%20=%20,%20old%20CCTV%20footage,%20high-angle%20CCTV%20image%5Cn%20%20%20%20%20%20%20%20trypophobia%20=%20,%20trypophobia%5Cn%20%20%20%20%20%20%20%20backrooms%20=%20,%20backrooms%5Cn%20%20%20%20%20%20%20%20black%20&%20white%20=%20,%20black%20&%20white%5Cn%20%20%20%20%20%20%20%20grainy%20=%20,%20grainy,%20noisy%20static%20effect%5Cn%20%20%20%20%20%20%20%20extreme%20close-up%20=%20,%20extreme%20close-up%5Cn%20%20%20%20%20%20%20%20low-angle%20=%20,%20low-angle%20shot%5Cn%20%20%20%20%20%20%20%20dramatic%20=%20,%20dramatic%20angle,%20extreme%20angle%20shot%5Cn%5Cn%5Cn%5Cn%5CnphotoModifiers%5Cn%20%20shot%5Cn%20%20%20%20extreme%20close-up%20=%20,%20extreme%20close-up%5Cn%20%20%20%20low-angle%20=%20,%20low-angle%20shot%5Cn%20%20%20%20high-angle%20=%20,%20high-angle%20shot%5Cn%20%20%20%20aerial%20=%20,%20aerial%20shot%5Cn%20%20%20%20close-up%20=%20,%20close-up%20shot%5Cn%20%20%20%20portrait%20=%20,%20close-up%20portrait%5Cn%20%20%20%20macro%20=%20,%20macro%20shot%5Cn%20%20%20%20wide-angle%20=%20,%20wide-angle%20shot%5Cn%20%20%20%20establishing%20=%20,%20establishing%20shot%5Cn%20%20%20%20over-the-shoulder%20=%20,%20over-the-shoulder%20shot%5Cn%20%20%20%20telephoto%20=%20,%20telephoto%20shot%5Cn%20%20%20%20handheld%20=%20,%20handheld%20shot%5Cn%20%20%20%20panoramic%20=%20,%20panoramic%20shot%5Cn%20%20%20%20dramatic%20=%20,%20dramatic%20angle,%20extreme%20angle%20shot%5Cn%20%20color%5Cn%20%20%20%20vibrant%20=%20,%20vibrant%20color%20grading%5Cn%20%20%20%20warm%20=%20,%20warm%20color%20grading%5Cn%20%20%20%20cool%20=%20,%20cool-toned%20color%20grading%5Cn%20%20%20%20pastel%20=%20,%20pastel%20color%20grading%5Cn%20%20%20%20bright%20=%20,%20bright%20color%20grading%5Cn%20%20%20%20muted%20=%20,%20muted%20color%20grading%5Cn%20%20%20%20neon%20=%20,%20neon%20color%20grading%5Cn%20%20%20%20duotone%20=%20,%20duotone%20color%20grading%5Cn%20%20%20%20monochrome%20=%20,%20monochrome%5Cn%20%20%20%20sterile%20=%20,%20cool-toned%20sterile%20colors%5Cn%20%20effect%5Cn%20%20%20%20bokeh%20=%20,%20bokeh%5Cn%20%20%20%20tilt-shift%20=%20,%20tilt-shift%20effect%5Cn%20%20%20%20soft%20focus%20=%20,%20soft%20focus%5Cn%20%20%20%20background%20blur%20=%20,%20shallow%20depth%20of%20field%5Cn%20%20%20%20chromatic%20aberrations%20=%20,%20chromatic%20aberrations%5Cn%20%20%20%20light%20leaks%20=%20,%20light%20leaks%5Cn%20%20%20%20rear%20projection%20=%20,%20rear%20projection%5Cn%20%20%20%20lens%20flare%20=%20,%20lens%20flare%5Cn%20%20%20%20long%20exposure%20=%20,%20long%20exposure%5Cn%20%20%20%20golden%20hour%20=%20,%20golden%20hour%5Cn%20%20%20%20silhouette%20=%20,%20silhouette%5Cn%5CnanimeModifiers%5Cn%20%20style%5Cn%20%20%20%20Ghibli%20=%20,%20Ghibli%20art%20style,%20Spirited%20Away%20art%20style%5Cn%20%20%20%20Your%20Name%20=%20,%20(Your%20Name%20art%20style:1.3)%5Cn%20%20%20%20Paprika%20=%20,%20Paprika%20art%20style%5Cn%20%20%20%20My%20Hero%20Academia%20=%20,%20My%20Hero%20Academia%20art%20style%5Cn%20%20%20%20Hunter%20x%20Hunter%20=%20,%20Hunter%20x%20Hunter%20art%20style%5Cn%20%20%20%20Attack%20on%20Titan%20=%20,%20(Attack%20on%20Titan%20art%20style:1.3)%5Cn%20%20effect%5Cn%20%20%20%20multi-view%20=%20,%20(multiple%20views:1.2)%5Cn%20%20%20%20toon%20=%20,%20(cartoon-style%20bold%20line%20work:1.2),%20vibrant%20colors,%20cel%20shading%5Cn%20%20%20%20vintage%20=%20,%20(cel%20shading,%20vintage%20anime:1.25)%5Cn%20%20%20%20ethereal%20=%20,%20(glow,%20god%20rays,%20ethereal,%20dreamy,%20heavenly,%20otherworldly,%20dream-like,%20breathtaking,%20captivating,%20divine)%5Cn%20%20%20%20outline%20=%20,%20outline,%20white%20outline%5Cn%20%20%20%20%5CnfurryModifiers%5Cn%20%20effect%5Cn%20%20%20%20humanoid%20face%20=%20,%20(human%20face,%20not%20furry:1.3)%5Cn%20%20%20%20multi-view%20=%20,%20(multiple%20views:1.2)%5Cn%20%20%20%20toon%20=%20,%20(cartoon-style%20bold%20line%20work:1.2),%20vibrant%20colors,%20cel%20shading%5Cn%20%20%20%20vintage%20=%20,%20(cel%20shading,%20vintage%20anime:1.25)%5Cn%20%20%20%20ethereal%20=%20,%20(glow,%20god%20rays,%20ethereal,%20dreamy,%20heavenly,%20otherworldly,%20dream-like,%20breathtaking,%20captivating,%20divine)%5Cn%20%20%20%20outline%20=%20,%20outline,%20white%20outline%5Cn%20%20%5CnlandscapeModifiers%5Cn%20%20shot%5Cn%20%20%20%20aerial%20=%20,%20aerial%20view%5Cn%20%20%20%20low-angle%20=%20,%20low-angle%20view%5Cn%20%20%20%20high-angle%20=%20,%20high-angle%20view%5Cn%20%20%20%20wide-angle%20=%20,%20wide-angle%20view%5Cn%20%20color%5Cn%20%20%20%20vibrant%20=%20,%20vibrant%20color%20tones%5Cn%20%20%20%20warm%20=%20,%20warm-toned%20colors%5Cn%20%20%20%20cool%20=%20,%20cool-toned%20colors%5Cn%20%20%20%20pastel%20=%20,%20pastel%20tones%5Cn%20%20%20%20muted%20=%20,%20muted%20color%20grading%5Cn%20%20%20%20sunset%20=%20,%20sunset%20color%20tones%5Cn%20%20%20%20monochrome%20=%20,%20monochrome%5Cn%20%20effect%5Cn%20%20%20%20tilt-shift%20=%20,%20tilt-shift%20effect%5Cn%20%20%20%20golden%20hour%20=%20,%20golden%20hour%5Cn%20%20%20%20mist%20=%20,%20misty%5Cn%20%20%20%20reflection%20=%20,%20water%20reflection%5Cn%20%20%20%20sun%20flare%20=%20,%20sun%20flare%5Cn%20%20%20%20starburst%20=%20,%20starburst%20effect%5Cn%20%20%20%20light%20trails%20=%20,%20light%20trails%5Cn%20%20%20%20long%20exposure%20=%20,%20long%20exposure%5Cn%20%20%20%20soft%20focus%20=%20,%20soft%20focus%5Cn%20%20%22,%22imports%22:%5B%5D,%22lastEditTime%22:1715977079104,%22found%22:true%7D,%7B%22name%22:%22ai-text-plugin%22,%22modelText%22:%22$output(inputData)%20=%3E%5Cn%5Cn%20%20const%20serverOrigin%20=%20%5C%22https://text-generation.perchance.org%5C%22;%5Cn%20%20%5Cn%20%20let%20iframe;%20%20%5Cn%20%20if(!window.__alreadyAddedAiTextPluginStuff8492739)%20%7B%5Cn%20%20%20%20iframe%20=%20document.createElement(%5C%22iframe%5C%22);%20%5Cn%20%20%20%20iframe.src%20=%20%60$%7BserverOrigin%7D/embed%60;%5Cn%20%20%20%20iframe.style.cssText%20=%20%5C%22display:none;%20position:fixed;%20top:0.5rem;%20right:0.5rem;%20height:3rem;%20width:11rem;%20background:#333;%20border:none;%20border-radius:3px;%20box-shadow:0px%202px%204px%200px%20#00000066;%20z-index:10000%5C%22;%5Cn%20%20%20%20iframe.id%20=%20%5C%22aiTextPluginEmbedIframe%5C%22;%5Cn%20%20%20%20%5Cn%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20if(!window.__aiTextIframeEmbedIsReady)%20%7B%5Cn%20%20%20%20%20%20%20%20iframe.src%20=%20%60$%7BserverOrigin%7D/embed?__cacheBust=$%7BMath.random()%7D%60;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D,%2015*1000);%5Cn%20%20%20%20%5Cn%20%20%20%20const%20style%20=%20document.createElement(%5C%22style%5C%22);%5Cn%20%20%20%20style.textContent%20=%20%60%5Cn%20%20%20%20%20%20@keyframes%20ai-text-plugin-blink%20%7B%2050%25%20%7B%20fill:%20transparent%20%7D%7D%20.ai-text-plugin-dot%20%7B%20animation:%201s%20ai-text-plugin-blink%20infinite;%20fill:%20grey;%20%7D%20.ai-text-plugin-dot:nth-child(2)%20%7B%20animation-delay:%20250ms%20%7D%20.ai-text-plugin-dot:nth-child(3)%20%7B%20animation-delay:%20500ms%20%7D%20.ai-text-plugin-loader%20%7B%20background-color:%20#f1f1f1;%20color:%20grey;%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20.ai-text-response-end-buttons-ctn:before%20%7B%5Cn%20%20%20%20%20%20%20%20content:%20%5C%22+%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.ai-text-response-end-buttons-ctn%20%7B%5Cn%20%20%20%20%20%20%20%20position:relative;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.ai-text-response-buttons-wrapper%20%7B%5Cn%20%20%20%20%20%20%20%20display:none;%5Cn%20%20%20%20%20%20%20%20position:absolute;%5Cn%20%20%20%20%20%20%20%20width:%20max-content;%5Cn%20%20%20%20%20%20%20%20bottom:%200;%5Cn%20%20%20%20%20%20%20%20min-height:%202.5rem;%5Cn%20%20%20%20%20%20%20%20pointer-events:none;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20@media%20screen%20and%20(max-width:%20600px)%20%7B%5Cn%20%20%20%20%20%20%20%20.ai-text-response-buttons-wrapper%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20min-height:%203.5rem;%20/*%20buttons%20should%20be%20further%20apart%20on%20mobile%20-%20else%20'hover'%20click%20triggers%20the%20buttons%20themselves%20*/%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20.ai-text-response-end-buttons-ctn:hover%20.ai-text-response-buttons-wrapper%20%7B%5Cn%20%20%20%20%20%20%20%20display:flex;%5Cn%20%20%20%20%20%20%20%20pointer-events:auto;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%60;%5Cn%20%20%20%20document.head.appendChild(style);%5Cn%20%20%20%20%5Cn%20%20%20%20window.addEventListener('message',%20(event)%20=%3E%20%7B%5Cn%20%20%20%20%20%20if(event.source%20!==%20iframe.contentWindow)%20return;%5Cn%20%20%20%20%20%20if(event.origin%20!==%20serverOrigin)%20return;%5Cn%5Cn%20%20%20%20%20%20if(event.data.type%20===%20%5C%22embedIsReady%5C%22)%20%7B%20%20%20%5Cn%20%20%20%20%20%20%20%20window.__aiTextIframeEmbedIsReady%20=%20true;%5Cn%20%20%20%20%20%20%20%20//%20console.debug(%5C%22got%20embedIsReady,%20sent%20verifyUser%5C%22);%5Cn%20%20%20%20%20%20%20%20if(!window.__alreadyTriggeredAiTextPluginPreload8492739)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20iframe.contentWindow.postMessage(%7Btype:%5C%22verifyUser%5C%22%7D,%20serverOrigin);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(event.data.type%20===%20%5C%22verified%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20iframe.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(event.data.type%20===%20%5C%22verifying%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20iframe.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20document.body.appendChild(iframe);%5Cn%20%20%20%20%5Cn%20%20%20%20window.__alreadyAddedAiTextPluginStuff8492739%20=%20true;%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20iframe%20=%20document.querySelector(%5C%22#aiTextPluginEmbedIframe%5C%22);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(inputData%20&&%20inputData.preload%20===%20true)%20%7B%5Cn%20%20%20%20if(!window.__alreadyTriggeredAiTextPluginPreload8492739)%20%7B%5Cn%20%20%20%20%20%20(async%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20while(!window.__aiTextIframeEmbedIsReady)%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20%20%20%20%20iframe.contentWindow.postMessage(%7Btype:%5C%22preload%5C%22%7D,%20serverOrigin);%5Cn%20%20%20%20%20%20%7D)();%5Cn%20%20%20%20%20%20window.__alreadyTriggeredAiTextPluginPreload8492739%20=%20true;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20return%20%5C%22%5C%22;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(inputData%20&&%20inputData.getMetaObject===true)%20%7B%5Cn%20%20%20%20return%20%7B%5Cn%20%20%20%20%20%20countTokens:%20function(text)%20%7B%5Cn%20%20%20%20%20%20%20%20return%20Math.ceil(text.length/3.6);%20//%20TODO:%20just%20an%20approximation%20for%20now%20-%20this%20approx%20will%20not%20work%20well%20with%20non-english%20characters.%20will%20update%20during%20next%20model%20upgrade.%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20idealMaxContextTokens:%206000,%20//%20this%20is%20just%20a%20recommendation%20-%20not%20a%20fundamental%20limit.%20and%20it%20will%20increase%20over%20time.%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%20%20//%20console.debug(%5C%22inputData:%5C%22,%20inputData);%5Cn%20%20if(!inputData)%20return%20%5C%22(Error:%20No%20input%20data%20given%20to%20the%20ai%20text%20plugin.)%5C%22;%5Cn%20%20if(inputData.instructions)%20%7B%5Cn%20%20%20%20if(inputData.outputTo)%20%7B%5Cn%20%20%20%20%20%20inputData.outputTo.value%20=%20%5C%22(Error:%20Looks%20like%20you%20wrote%20'instructions%20=%20...'%20instead%20of%20'instruction%20=%20...'%20in%20your%20ai-text-plugin%20prompt%20data?)%5C%22;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20return%20%5C%22(Error:%20Looks%20like%20you%20wrote%20'instructions%20=%20...'%20instead%20of%20'instruction%20=%20...'%20in%20your%20ai-text-plugin%20prompt%20data?)%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(typeof%20inputData%20===%20%5C%22string%5C%22%20%7C%7C%20inputData%20instanceof%20String)%20%7B%5Cn%20%20%20%20inputData%20=%20%7Binstruction:inputData+%5C%22%5C%22%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20//%20REMEMBER:%20if%20you%20add%20more%20inputs,%20you%20need%20to%20also%20update%20%60window.__continueAiTextResponseClickHandler%60%5Cn%20%20let%20hideStartWith%20=%20inputData.hideStartWith;%20//%20get%20the%20'concrete'%20value%20in%20case%20it%20was%20dynamic%20like%20%60hideStartWith%20=%20%5B%20...%20%5D%60%20-%20this%20is%20important%20because%20the%20condition%20in%20the%20square%20brackets%20could%20change%20later%5Cn%20%20%5Cn%20%20let%20instruction%20=%20inputData.instruction;%5Cn%20%20if(typeof%20instruction%20===%20%5C%22function%5C%22)%20%7B%5Cn%20%20%20%20instruction%20=%20instruction(%7B%7D);%20//%20this%20is%20useful%20as%20a%20way%20to%20give%20a%20string%20that%20should%20not%20be%20evaluated%20-%20since%20e.g.%20instruction%20=%20%5BtextareaEl.value%5D%20will%20actually%20evaluate%20the%20text%20when%20we%20call%20inputData.instruction%5Cn%20%20%20%20if(typeof%20instruction%20!==%20%5C%22string%5C%22)%20instruction%20=%20instruction.toString();%5Cn%20%20%7D%20else%20if(instruction)%20%7B%5Cn%20%20%20%20if(typeof%20instruction%20!==%20%5C%22string%5C%22)%20%7B%5Cn%20%20%20%20%20%20instruction%20=%20instruction.evaluateItem;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20instruction%20=%20instruction.toString();%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20instruction%20=%20%5C%22Write%20something.%5C%22;%20//%20default%20instruction%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20startWith%20=%20inputData.startWith;%5Cn%20%20if(typeof%20startWith%20===%20%5C%22function%5C%22)%20%7B%5Cn%20%20%20%20startWith%20=%20startWith(%7B%7D);%20//%20this%20is%20useful%20as%20a%20way%20to%20give%20a%20string%20that%20should%20not%20be%20evaluated%20-%20since%20e.g.%20startWith%20=%20%5BtextareaEl.value%5D%20will%20actually%20evaluate%20the%20text%20when%20we%20call%20inputData.startWith%5Cn%20%20%20%20if(typeof%20startWith%20!==%20%5C%22string%5C%22)%20startWith%20=%20startWith.toString();%5Cn%20%20%7D%20else%20if(startWith)%20%7B%5Cn%20%20%20%20if(typeof%20startWith%20!==%20%5C%22string%5C%22)%20%7B%5Cn%20%20%20%20%20%20startWith%20=%20startWith.evaluateItem;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20startWith%20=%20startWith.toString();%5Cn%20%20%20%20//%20We%20trim%20whitespace%20off%20the%20end%20due%20to%20the%20classic%20tokenizer%20problem%20(most%20word%20tokens%20start%20with%20a%20space%20as%20of%202023%20tokenizers).%5Cn%20%20%20%20//%20This%20of%20course%20does%20mean%20that%20you%20can't%20%5C%22force%5C%22%20the%20model%20to%20start%20with%20a%20space%20after%20a%20word,%20but%20it's%20worth%20that%20trade-off%20until%20we%20get%20models%20with%20better%20tokenizers.%5Cn%20%20%20%20startWith%20=%20startWith.replace(/%20+$/g,%20%5C%22%5C%22);%20//%20CAUTION:%20Don't%20trim%20newlines%20-%20only%20spaces.%20Because%20e.g.%20the%20story%20writer%20demo%20relies%20on%20being%20able%20to%20start%20with%202%20new%20lines%20before%20the%20paragraph%20that%20the%20AI%20is%20about%20to%20generate,%20since%20if%20the%20AI%20generates%20them,%20it'll%20trigger%20the%20stop%20sequence%20before%20it%20even%20gets%20to%20start%20writing%20the%20new%20paragraph%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20startWith%20=%20%5C%22%5C%22;%5Cn%20%20%7D%5Cn%5Cn%20%20let%20stopSequences%20=%20inputData.stopSequences;%5Cn%20%20if(typeof%20stopSequences%20===%20%5C%22function%5C%22)%20%7B%5Cn%20%20%20%20stopSequences%20=%20stopSequences(%7B%7D);%5Cn%20%20%7D%20else%20if(stopSequences)%20%7B%5Cn%20%20%20%20if(!Array.isArray(stopSequences))%20%7B%5Cn%20%20%20%20%20%20stopSequences%20=%20stopSequences.selectAll.map(n%20=%3E%20n.evaluateItem);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20stopSequences%20=%20%5B%5D;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20textareaLoadingIndicatorHandler;%5Cn%20%20%5Cn%20%20//%20REMEMBER:%20if%20you%20add%20more%20inputs,%20you%20need%20to%20also%20update%20%60window.__continueAiTextResponseClickHandler%60%5Cn%20%20%5Cn%20%20let%20concreteInputs%20=%20%7BstartWith,%20instruction,%20stopSequences%7D;%20%20//%20%3C--%20CAUTION:%20the%20startWith%20property%20of%20this%20is%20set%20to%20the%20full%20startWith+generatedText%20after%20generation,%20and%20the%20startWith%20can%20be%20changed%20after%20generation%20for%20the%20%60editAiTextResponseClickHandler%60%20feature%20-%20ctrl+f%20for%20%60concreteInputs.startWith%20=%60.%20Use%20%60originalConcreteInputs%60%20for%20original%20inputs.%5Cn%20%20const%20originalConcreteInputs%20=%20Object.freeze(JSON.parse(JSON.stringify(concreteInputs)));%5Cn%5Cn%20%20let%20placeholderEl;%5Cn%20%20let%20placeholderElDidInitiallyExist%20=%20false;%20//%20this%20is%20for%20keepalive%20stuff%20-%20so%20we%20can%20cancel%20a%20queued%20up%20generation%20if%20the%20placeholder%20is%20removed%5Cn%20%20let%20userStoppedGeneration%20=%20false;%5Cn%20%20%5Cn%20%20let%20textStreamController;%5Cn%20%20const%20textStream%20=%20new%20ReadableStream(%7B%5Cn%20%20%20%20start(c)%20%7B%5Cn%20%20%20%20%20%20textStreamController%20=%20c;%5Cn%20%20%20%20%7D%5Cn%20%20%7D);%5Cn%20%20%5Cn%20%20let%20darkModeEnabled%20=%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches;%5Cn%20%20const%20animatedLoadingSvg%20=%20%60%3Csvg%20style=%5C%22$%7BdarkModeEnabled%20?%20%5C%22filter:invert(0.85);%5C%22%20:%20%5C%22%5C%22%7D%20height:1rem;%20width:2rem;%20overflow:hidden;%20border-radius:3px;%20vertical-align:top;%20position:relative;%20top:0.07rem;%20margin-left:0.125rem;%5C%22%20height=%5C%221rem%5C%22%20width=%5C%222rem%5C%22%20class=%5C%22ai-text-plugin-loader%5C%22%3E%20%3Ccircle%20class=%5C%22ai-text-plugin-dot%5C%22%20cx=%5C%220.5em%5C%22%20cy=%5C%220.5em%5C%22%20r=%5C%220.2em%5C%22%20style=%5C%22fill:grey;%5C%22%3E%3C/circle%3E%20%3Ccircle%20class=%5C%22ai-text-plugin-dot%5C%22%20cx=%5C%221em%5C%22%20cy=%5C%220.5em%5C%22%20r=%5C%220.2em%5C%22%20style=%5C%22fill:grey;%5C%22%3E%3C/circle%3E%20%3Ccircle%20class=%5C%22ai-text-plugin-dot%5C%22%20cx=%5C%221.5em%5C%22%20cy=%5C%220.5em%5C%22%20r=%5C%220.2em%5C%22%20style=%5C%22fill:grey;%5C%22%3E%3C/circle%3E%20%3C/svg%3E%60;%5Cn%20%20%5Cn%20%20let%20generatedText%20=%20%5C%22%5C%22;%5Cn%20%20let%20finishedGenerating%20=%20false;%5Cn%20%20let%20finishedGeneratingSuccessfully%20=%20false;%5Cn%20%20let%20thereWasAnErrorDuringGeneration%20=%20false;%5Cn%20%20%5Cn%20%20let%20onFinishPromiseResolver;%5Cn%20%20let%20onFinishPromiseRejecter;%5Cn%20%20let%20onFinishPromise%20=%20new%20Promise((resolve,%20reject)%20=%3E%20%7B%5Cn%20%20%20%20onFinishPromiseResolver%20=%20resolve;%5Cn%20%20%20%20onFinishPromiseRejecter%20=%20reject;%5Cn%20%20%7D);%5Cn%20%20%5Cn%20%20let%20completionId%20=%20%5C%22aiTextCompletion%5C%22+Math.random().toString().replace(%5C%22.%5C%22,%20%5C%22%5C%22);%5Cn%20%20let%20lastGeneratedChunkReceivedTime%20=%20null;%5Cn%5Cn%20%20async%20function%20streamTextFromIframe(chunkCallback)%20%7B%20%5Cn%20%20%20%20let%20postData%20=%20%7B%7D;%5Cn%20%20%20%20postData.instruction%20=%20concreteInputs.instruction%20%7C%7C%20%5C%22%5C%22;%5Cn%20%20%20%20postData.startWith%20=%20concreteInputs.startWith%20%7C%7C%20%5C%22%5C%22;%5Cn%20%20%20%20postData.stopSequences%20=%20concreteInputs.stopSequences%20%7C%7C%20%5B%5D;%5Cn%20%20%20%20postData.generatorName%20=%20window.generatorName;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20url%20=%20%60$%7BserverOrigin%7D/api/generate%60;%5Cn%20%20%20%20let%20haveReceivedFirstTextChunk%20=%20false;%5Cn%20%20%20%20let%20haveReceivedLastTextChunk%20=%20false;%5Cn%20%20%20%20function%20messageHandler(event)%20%7B%5Cn%20%20%20%20%20%20if(event.data.requestId%20!==%20completionId)%20return;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20console.debug(%5C%22streamTextFromIframe%20messageHandler:%5C%22,%20event.data);%5Cn%20%20%20%20%20%20if(event.data.type%20===%20%5C%22streamData%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20lastGeneratedChunkReceivedTime%20=%20Date.now();%5Cn%20%20%20%20%20%20%20%20let%20text%20=%20event.data.value.text;%5Cn%20%20%20%20%20%20%20%20let%20data%20=%20%7Btext%7D;%5Cn%20%20%20%20%20%20%20%20if(event.data.value.stopReason)%20data.stopReason%20=%20event.data.value.stopReason;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20//%20console.debug(%5C%22event.data.value:%5C%22,%20event.data.value);%5Cn%20%20%20%20%20%20%20%20if(!haveReceivedFirstTextChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20data.isFirstChunk%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20haveReceivedFirstTextChunk%20=%20true;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(haveReceivedLastTextChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20console.error(%5C%22haveReceivedLastTextChunk%20but%20about%20to%20send%20another%20chunk???%20maybe%20recieving%20streamEnd%20before%20it's%20actually%20finished??%5C%22);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(event.data.value.final)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20data.isLastChunk%20=%20true;%20//%20remember,%20a%20chunk%20can%20be%20both%20the%20first%20*and*%20last%20chunk%5Cn%20%20%20%20%20%20%20%20%20%20haveReceivedLastTextChunk%20=%20true;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20chunkCallback(data);%5Cn%20%20%20%20%20%20%7D%20else%20if%20(event.data.type%20===%20%5C%22streamEnd%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20//%20console.debug(%60ai-text-plugin%20Received%20'streamEnd'%20for%20$%7BcompletionId%7D%60);%5Cn%20%20%20%20%20%20%20%20window.removeEventListener(%5C%22message%5C%22,%20messageHandler);%5Cn%20%20%20%20%20%20%20%20if(!haveReceivedLastTextChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20this%20can%20happen%20if%20stream%20is%20aborted,%20or%20if%20.stop()%20was%20called%20in%20userland,%20and%20perhaps%20for%20other%20reasons,%20so%20we%20send%20a%20last%20%5C%22dummy%5C%22%20chunk%5Cn%20%20%20%20%20%20%20%20%20%20chunkCallback(%7Btext:%5C%22%5C%22,%20stopReason:%5C%22user%5C%22,%20isLastChunk:true,%20isFirstChunk:!haveReceivedFirstTextChunk%7D);%5Cn%20%20%20%20%20%20%20%20%20%20haveReceivedLastTextChunk%20=%20true;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20if%20(event.data.type%20===%20%5C%22streamError%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20if(userStoppedGeneration%20&&%20event.data.status%20===%20%5C%22stale%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20this%20is%20not%20actually%20an%20error,%20but%20iframe%20embed%20can't%20know%20that,%20so%20it%20sends%20us%20this,%20which%20we%20just%20ignore.%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(!finishedGenerating)%20%7B%20//%20%3C--%20just%20to%20guard%20against%20weird%20timing%20stuff%5Cn%20%20%20%20%20%20%20%20%20%20%20%20thereWasAnErrorDuringGeneration%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20chunkCallback(%7Btext:%5C%22%5C%22,%20error:true,%20isLastChunk:!haveReceivedLastTextChunk,%20isFirstChunk:!haveReceivedFirstTextChunk%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20div%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20div.innerHTML%20=%20%60%3Cdiv%20style=%5C%22z-index:1000;%20position:%20fixed;%20bottom:%201rem;%20width:%20100%25;%20pointer-events:none;%5C%22%3E%3Cspan%20style=%5C%22%20padding:%200.5rem;%20background:%20#ac2c2c;%20border-radius:%203px;%20color:%20white;%20pointer-events:auto;%5C%22%3Eerror:%20$%7Bevent.data.status.replaceAll(%5C%22_%5C%22,%20%5C%22%20%5C%22)%7D%3C/span%3E%3C/div%3E%60;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20div%20=%20div.firstElementChild;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20document.body.appendChild(div);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20div.remove();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D,%201000*5);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20window.removeEventListener(%5C%22message%5C%22,%20messageHandler);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20window.addEventListener(%5C%22message%5C%22,%20messageHandler);%5Cn%20%20%20%20%5Cn%20%20%20%20while(!window.__aiTextIframeEmbedIsReady)%20%7B%5Cn%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20100));%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(inputData._debug)%20postData._debug%20=%20JSON.parse(JSON.stringify(inputData._debug));%5Cn%20%20%20%20iframe.contentWindow.postMessage(%7B%20type:%20%5C%22startStream%5C%22,%20url,%20postData,%20requestId:completionId,%20perchanceGeneratorOrigin:window.location.origin%20%7D,%20serverOrigin);%5Cn%20%20%20%20//%20console.debug(%5C%22sent%20startStream%20request%20to%20iframe%5C%22);%5Cn%20%20%7D%5Cn%5Cn%20%20async%20function%20editAiTextResponseClickHandler(el)%20%7B%20%20%20%20%5Cn%20%20%20%20let%20saveButton%20=%20document.createElement(%5C%22button%5C%22);%5Cn%20%20%20%20saveButton.style.cssText%20=%20%5C%22position:fixed;%20z-index:501;%5C%22;%5Cn%20%20%20%20saveButton.textContent%20=%20%5C%22%F0%9F%92%BE%5C%22;%5Cn%20%20%20%20document.body.append(saveButton);%5Cn%5Cn%20%20%20%20let%20textarea%20=%20document.createElement(%5C%22textarea%5C%22);%5Cn%20%20%20%20textarea.style.cssText%20=%20%5C%22z-index:500;%20display:block;%20position:fixed;%20min-height:2rem;%20min-width:10rem;%5C%22;%5Cn%20%20%20%20textarea.value%20=%20concreteInputs.startWith;%5Cn%20%20%20%20document.body.append(textarea);%5Cn%20%20%20%20let%20updateCoverPosition%20=%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20rect%20=%20el.getBoundingClientRect();%5Cn%20%20%20%20%20%20textarea.style.left%20=%20%60$%7Brect.left%7Dpx%60;%5Cn%20%20%20%20%20%20textarea.style.top%20=%20%60$%7Brect.top%7Dpx%60;%5Cn%20%20%20%20%20%20textarea.style.width%20=%20%60$%7Brect.width%7Dpx%60;%5Cn%20%20%20%20%20%20textarea.style.height%20=%20%60$%7Brect.height+10%7Dpx%60;%5Cn%5Cn%20%20%20%20%20%20let%20textareaRect%20=%20textarea.getBoundingClientRect();%20//%20Use%20coverElement's%20dimensions%5Cn%20%20%20%20%20%20saveButton.style.left%20=%20%60$%7BtextareaRect.right-saveButton.offsetWidth%7Dpx%60;%5Cn%20%20%20%20%20%20saveButton.style.top%20=%20%60$%7BtextareaRect.bottom%7Dpx%60;%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20updateCoverPosition();%5Cn%20%20%20%20window.addEventListener('scroll',%20updateCoverPosition);%5Cn%20%20%20%20window.addEventListener('resize',%20updateCoverPosition);%5Cn%20%20%20%20%5Cn%20%20%20%20const%20observer%20=%20new%20MutationObserver((mutationsList)%20=%3E%20%7B%5Cn%20%20%20%20%20%20for(let%20mutation%20of%20mutationsList)%20%7B%5Cn%20%20%20%20%20%20%20%20for(let%20node%20of%20mutation.removedNodes)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(node.contains(el))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20textarea.remove();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20saveButton.remove();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20window.removeEventListener('scroll',%20updateCoverPosition);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20window.removeEventListener('resize',%20updateCoverPosition);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20observer.disconnect();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20observer.observe(document.body,%20%7B%20childList:%20true,%20subtree:%20true%20%7D);%5Cn%5Cn%20%20%20%20await%20new%20Promise(r%20=%3E%20saveButton.onclick=r);%20%5Cn%5Cn%20%20%20%20let%20endButtonsCtn%20=%20el.querySelector(%5C%22.ai-text-response-end-buttons-ctn%5C%22);%5Cn%20%20%20%20endButtonsCtn.remove();%5Cn%5Cn%20%20%20%20concreteInputs.startWith%20=%20textarea.value;%5Cn%20%20%20%20%5Cn%20%20%20%20//%20we%20do%20this%20because%20the%20onFinishPromise%20is%20actually%20the%20return%20value%20of%20this%20function,%20but%20it%20also%20serves%20as%20an%20object%20with%20a%20bunch%20of%20handy%20properties%20like%20.liveResponseText,%20.stop(),%20etc.%5Cn%20%20%20%20onFinishPromise.liveResponseText%20=%20textarea.value;%5Cn%20%20%20%20%5Cn%20%20%20%20//%20el.innerHTML%20=%20textarea.value;%5Cn%20%20%20%20//%20el.appendChild(endButtonsCtn);%5Cn%20%20%20%20renderResponseTextIntoContainer(textarea.value,%20%7BaddEndButtons:true,%20isFinalRender:true%7D);%5Cn%5Cn%20%20%20%20window.removeEventListener('scroll',%20updateCoverPosition);%5Cn%20%20%20%20window.removeEventListener('resize',%20updateCoverPosition);%5Cn%20%20%20%20textarea.remove();%5Cn%20%20%20%20saveButton.remove();%5Cn%20%20%7D;%5Cn%20%20%5Cn%20%20async%20function%20continueAiTextResponseClickHandler(el,%20opts=%7B%7D)%20%7B%20%20%20%20%5Cn%20%20%20%20let%20instruction%20=%20concreteInputs.instruction;%5Cn%20%20%20%20let%20startWith%20=%20concreteInputs.startWith;%5Cn%20%20%20%20let%20stopSequences%20=%20concreteInputs.stopSequences;%5Cn%20%20%20%20%5Cn%20%20%20%20if(opts.appendContinuationSuffix)%20startWith%20+=%20%5C%22%5C%5Cn%5C%22;%5Cn%20%20%20%20%5Cn%20%20%20%20responseEndButtonsCtn.remove();%5Cn%20%20%20%20let%20obj%20=%20$output(%7Binstruction,%20startWith,%20stopSequences,%20style:inputData.style,%20outputTo:el,%20render:inputData.render,%20onFinish:inputData.onFinish,%20onChunk:inputData.onChunk%7D);%5Cn%20%20%20%20el.innerHTML%20+=%20obj.loadingIndicatorHtml;%5Cn%20%20%20%20let%20result%20=%20await%20obj;%5Cn%20%20%20%20if(!opts.appendContinuationSuffix%20&&%20result.generatedText%20===%20%5C%22%5C%22%20&&%20!result.text.endsWith(%5C%22%5C%5Cn%5C%5Cn%5C%22))%20%7B%5Cn%20%20%20%20%20%20//%20no%20text%20was%20generated,%20so%20try%20again%20with%20a%20suffix%20that's%20likely%20to%20trigger%20more%20text.%5Cn%20%20%20%20%20%20//%20TODO:%20maybe%20check%20stopReason%20here%20too?%5Cn%20%20%20%20%20%20continueAiTextResponseClickHandler(el,%20%7BappendContinuationSuffix:true%7D)%5Cn%20%20%20%20%7D%5Cn%20%20%7D;%5Cn%20%20%5Cn%20%20let%20responseEndButtonsCtn;%5Cn%20%20%7B%5Cn%20%20%20%20let%20buttonGap%20=%20%5C%220.25rem%5C%22;%5Cn%20%20%20%20if(window.innerWidth%20%3C%20600)%20buttonGap%20=%20%5C%221.5rem%5C%22;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20darkModeEnabled%20=%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches;%5Cn%20%20%20%20let%20responseEndButtonsHtml%20=%20%60%3Cspan%20class=%5C%22ai-text-response-end-buttons-ctn%5C%22%20style=%5C%22display:%20inline-flex;background:$%7BdarkModeEnabled%20?%20%5C%22#666666%5C%22%20:%20%5C%22#f1f1f1%5C%22%7D;color:%20$%7BdarkModeEnabled%20?%20%5C%22#d5d5d5%5C%22%20:%20%5C%22grey%5C%22%7D;height:%201rem;width:%201rem;border-radius:%203px;vertical-align:%20top;position:%20relative;top:%200.07rem;margin-left:%200.125rem;align-items:%20center;justify-content:%20center;cursor:%20pointer;%20font-size:80%25%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20class=%5C%22ai-text-response-buttons-wrapper%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22ai-text-continue-button%5C%22%20style=%5C%22height:min-content;%5C%22%3E%E2%96%B6%EF%B8%8F%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22ai-text-edit-button%5C%22%20style=%5C%22height:min-content;%20margin-left:$%7BbuttonGap%7D%5C%22%3E%E2%9C%8F%EF%B8%8F%3C/button%3E%5Cn%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%3C/span%3E%60;%5Cn%20%20%20%20responseEndButtonsCtn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20responseEndButtonsCtn.innerHTML%20=%20responseEndButtonsHtml;%5Cn%20%20%20%20responseEndButtonsCtn%20=%20responseEndButtonsCtn.firstElementChild;%5Cn%20%20%20%20if(inputData.endButtons?.evaluateItem%20===%20%5C%22none%5C%22)%20%7B%5Cn%20%20%20%20%20%20responseEndButtonsCtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20responseEndButtonsCtn.querySelector(%5C%22.ai-text-continue-button%5C%22).onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20//%20console.debug(%5C%22wrapper%20display:%5C%22,%20this.closest('.ai-text-response-buttons-wrapper').style.display);%5Cn%20%20%20%20%20%20let%20responseCtn%20=%20this.closest(%5C%22.ai-text-response-end-buttons-ctn%5C%22).__aiTextResponseCtn%20%7C%7C%20this.closest('.ai-text-response-ctn');%5Cn%20%20%20%20%20%20continueAiTextResponseClickHandler(responseCtn);%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20responseEndButtonsCtn.querySelector(%5C%22.ai-text-edit-button%5C%22).onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20//%20console.debug(%5C%22wrapper%20display:%5C%22,%20this.closest('.ai-text-response-buttons-wrapper').style.display);%5Cn%20%20%20%20%20%20let%20responseCtn%20=%20this.closest(%5C%22.ai-text-response-end-buttons-ctn%5C%22).__aiTextResponseCtn%20%7C%7C%20this.closest('.ai-text-response-ctn');%5Cn%20%20%20%20%20%20editAiTextResponseClickHandler(responseCtn);%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20escapeRegExp(text)%20%7B%5Cn%20%20%20%20return%20text.replace(/%5B-%5B%5C%5C%5D%7B%7D()*+?.,%5C%5C%5C%5C%5E$%7C#%5C%5Cs%5D/g,%20'%5C%5C%5C%5C$&');%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20startWithRegex;%5Cn%20%20%5Cn%20%20function%20renderResponseTextIntoContainer(response,%20opts=%7B%7D)%20%7B%5Cn%20%20%20%20if(!inputData.outputTo%20&&%20!placeholderEl)%20return;%20//%20%3C--%20indicates%20that%20they're%20doing%20things%20manually%20with%20e.g.%20onFinishPromise/onChunk/etc.%5Cn%20%20%20%20%5Cn%20%20%20%20if(hideStartWith)%20%7B%20//%20note%20that%20%60hideStartWith%60%20is%20purely%20'visual'%20-%20it's%20just%20a%20handy%20helper%20for%20a%20common%20case%20(that%20could%20otherwise%20be%20solved%20with%20%60render%60)%5Cn%20%20%20%20%20%20if(!startWithRegex)%20startWithRegex%20=%20new%20RegExp(%5C%22%5E%5C%22+escapeRegExp(concreteInputs.startWith));%5Cn%20%20%20%20%20%20response%20=%20response.replace(startWithRegex,%20%5C%22%5C%22);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(inputData.render)%20%7B%5Cn%20%20%20%20%20%20response%20=%20inputData.render(%7Btext:response,%20isPartial:!opts.isFinalRender%7D);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(inputData.outputTo)%20%7B%5Cn%20%20%20%20%20%20if(typeof%20inputData.outputTo.value%20==%20%5C%22string%5C%22)%20%7B%20//%20textarea,%20input,%20or%20user's%20custom%20object%20with%20string%20%60.value%60%20property%5Cn%20%20%20%20%20%20%20%20inputData.outputTo.value%20=%20response;%5Cn%20%20%20%20%20%20%20%20if(inputData.outputTo.tagName%20===%20%5C%22TEXTAREA%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(inputData.outputTo.scrollTop%20%3E%20(inputData.outputTo.scrollHeight%20-%20inputData.outputTo.offsetHeight)-30)%20%7B%20//%20%3C--%20if%20the%20text%20box%20is%20already%20scrolled%20near%20the%20end%20of%20the%20text%5Cn%20%20%20%20%20%20%20%20%20%20%20%20inputData.outputTo.scrollTop%20=%209999999999;%20//%20scroll%20down%20to%20bottom%20of%20text%20box%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20inputData.outputTo.innerHTML%20=%20response;%5Cn%20%20%20%20%20%20%20%20if(opts.addEndButtons)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20responseEndButtonsCtn.title%20=%20%60Inputs%20that%20were%20used:%5C%5Cn%5C%5Cninstruction=$%7BconcreteInputs.instruction%7D%5C%5Cn%5C%5CnstartWith=$%7BconcreteInputs.startWith%7D%60;%5Cn%20%20%20%20%20%20%20%20%20%20responseEndButtonsCtn.__aiTextResponseCtn%20=%20inputData.outputTo;%5Cn%20%20%20%20%20%20%20%20%20%20inputData.outputTo.append(responseEndButtonsCtn);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20if(typeof%20placeholderEl.value%20==%20%5C%22string%5C%22)%20%7B%20//%20textarea,%20input,%20or%20user's%20custom%20object%20with%20string%20%60.value%60%20property%5Cn%20%20%20%20%20%20%20%20placeholderEl.value%20=%20response;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20placeholderEl.innerHTML%20=%20response;%5Cn%20%20%20%20%20%20%20%20if(opts.addEndButtons)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20responseEndButtonsCtn.title%20=%20%60Inputs%20that%20were%20used:%5C%5Cn%5C%5Cninstruction=$%7BconcreteInputs.instruction%7D%5C%5Cn%5C%5CnstartWith=$%7BconcreteInputs.startWith%7D%60;%5Cn%20%20%20%20%20%20%20%20%20%20placeholderEl.append(responseEndButtonsCtn);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20gotFirstChunk%20=%20false;%5Cn%20%20let%20chunks%20=%20%5B%5D;%5Cn%20%20let%20generatedChunks%20=%20%5B%5D;%20//%20difference%20from%20%60chunks%60%20is%20that%20this%20doesn't%20include%20the%20user-specified%20%60startWith%60%20text%5Cn%20%20let%20alreadyDoneOnFinishStuff%20=%20false;%20//%20just%20as%20an%20extra%20guard%20against%20bugs%5Cn%20%20%5Cn%20%20function%20doOnFinishStuff(%7BstopReason%7D)%20%7B%5Cn%20%20%20%20if(alreadyDoneOnFinishStuff)%20%7B%5Cn%20%20%20%20%20%20console.error(%5C%22Tried%20to%20trigger%20onFinish%20twice?%20This%20is%20a%20bug%20with%20the%20ai-text-plugin%20-%20please%20report%20it.%5C%22);%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20alreadyDoneOnFinishStuff%20=%20true;%5Cn%5Cn%20%20%20%20let%20finishData%20=%20new%20String(chunks.join(%5C%22%5C%22));%5Cn%20%20%20%20finishData.text%20=%20chunks.join(%5C%22%5C%22);%5Cn%20%20%20%20finishData.generatedText%20=%20generatedChunks.join(%5C%22%5C%22);%5Cn%20%20%20%20finishData.stopReason%20=%20stopReason;%5Cn%5Cn%20%20%20%20if(inputData.onFinish)%20%7B%5Cn%20%20%20%20%20%20try%20%7B%20inputData.onFinish(finishData);%20%7D%20catch(e)%20%7B%20console.error(%5C%22error%20in%20onFinish:%5C%22,%20e);%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20onFinishPromiseResolver(finishData);%5Cn%20%20%20%20generatedText%20=%20generatedChunks.join(%5C%22%5C%22);%5Cn%5Cn%20%20%20%20if(textareaLoadingIndicatorHandler)%20textareaLoadingIndicatorHandler.stop();%5Cn%20%20%20%20try%20%7B%20textStreamController.close();%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D%5Cn%20%20%7D%5Cn%20%20function%20stopFn()%20%7B%5Cn%20%20%20%20if(finishedGenerating)%20return;%5Cn%20%20%20%20finishedGenerating%20=%20true;%5Cn%5Cn%20%20%20%20if(!gotFirstChunk%20&&%20placeholderEl)%20placeholderEl.innerHTML%20=%20%5C%22%5C%22;%20//%20clear%20the%20svg%20'loading'%20dots%5Cn%5Cn%20%20%20%20doOnFinishStuff(%7BstopReason:%5C%22user%5C%22%7D);%5Cn%20%20%7D%5Cn%5Cn%20%20async%20function%20startStreamingResponse()%20%7B%5Cn%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20(async%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20%20%20%20%20while(true)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(userStoppedGeneration)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20console.debug(%5C%22stopping%20keepalives%20due%20to%20%60userStoppedGeneration%60%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20break;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20if(finishedGenerating)%20%7B%20console.debug(%5C%22stopping%20keepalives%20due%20to%20%60finishedGenerating%60%5C%22);%20break;%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20if(placeholderElDidInitiallyExist%20&&%20!document.querySelector(%60#$%7BcompletionId%7D%60))%20%7B%20console.debug(%5C%22stopping%20keepalives%20due%20to%20%60placeholderEl%60%5C%22);%20break;%20%7D%20//%20placeholderEl%20no%20longer%20exists%20in%20the%20DOM,%20so%20user%20probably%20clicked%20'randomize'%20or%20whatever%20while%20previous%20one%20was%20still%20loading,%20hence%20we%20abort%20previous%20one%20by%20stopping%20the%20keepalives,%20which%20drops%20it%20from%20the%20queue%5Cn%20%20%20%20%20%20%20%20%20%20if(inputData.outputTo%20&&%20(!document.body.contains(inputData.outputTo)%20%7C%7C%20inputData.outputTo.dataset.aiTextCompletionId%20!==%20completionId))%20%20%7B%20console.debug(%5C%22stopping%20keepalives%20due%20to%20%60outputTo%60%5C%22);%20break;%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20//%20if(lastGeneratedChunkReceivedTime%20!==%20null%20&&%20Date.now()-lastGeneratedChunkReceivedTime%20%3E%201000*20)%20%20%7B%20console.debug(%5C%22stopping%20keepalives%20due%20to%20generation%20having%20started%20but%20no%20new%20chunks%20Received%20in%2020%20seconds%5C%22);%20break;%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20iframe.contentWindow.postMessage(%7B%20type:%20%5C%22streamKeepAlive%5C%22,%20requestId:completionId%20%7D,%20serverOrigin);%5Cn%20%20%20%20%20%20%20%20%20%20console.debug(%5C%22streamKeepAlive%20sent%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20800));%5Cn%20%20%20%20%20%20%20%20%20%20//%20if(window.devTest98375290385)%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%2010000000000));%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20try%20%7B%20stopFn();%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D;%20//%20need%20to%20call%20stopFn()%20here%20(and%20not%20just%20wait%20for%20it%20to%20be%20called%20in%20streamTextFromIframe)%20because%20otherwise%20it%20only%20gets%20called%20if%20streamTextFromIframe%20gets%20called%20again,%20which%20it%20*might%20not*%5Cn%20%20%20%20%20%20%20%20try%20%7B%20iframe.contentWindow.postMessage(%7B%20type:%20%5C%22stopStream%5C%22,%20requestId:completionId%20%7D,%20serverOrigin);%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D;%5Cn%20%20%20%20%20%20%7D)();%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20streamTextFromIframe(function(data)%20%7B%5Cn%20%20%20%20%20%20%20%20if(userStoppedGeneration)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(!finishedGenerating)%20stopFn();%5Cn%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(placeholderElDidInitiallyExist%20&&%20!document.querySelector(%60#$%7BcompletionId%7D%60))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(!finishedGenerating)%20stopFn();%5Cn%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(inputData.outputTo%20&&%20(!document.body.contains(inputData.outputTo)%20%7C%7C%20inputData.outputTo.dataset.aiTextCompletionId%20!==%20completionId))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(!finishedGenerating)%20stopFn();%5Cn%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(finishedGenerating)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20thereWasAnErrorDuringGeneration%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20console.error(%5C%22We%20received%20a%20chunk%20of%20text%20even%20though%20we've%20already%20finishedGenerating?%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20//%20add%20the%20startWith%20chunk%20before%20the%20first%20'real'%20chunk:%5Cn%20%20%20%20%20%20%20%20if(data.isFirstChunk%20&&%20concreteInputs.startWith)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20chunks.push(concreteInputs.startWith);%5Cn%20%20%20%20%20%20%20%20%20%20textStreamController.enqueue(concreteInputs.startWith);%5Cn%20%20%20%20%20%20%20%20%20%20if(inputData.onChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20inputData.onChunk(%7BfullTextSoFar:chunks.join(%5C%22%5C%22),%20textChunk:concreteInputs.startWith,%20isFromStartWith:true%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(data.error)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20allChunksJoined%20=%20chunks.join(%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20thereWasAnErrorDuringGeneration%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20finishedGenerating%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20concreteInputs.startWith%20=%20allChunksJoined;%5Cn%20%20%20%20%20%20%20%20%20%20renderResponseTextIntoContainer(allChunksJoined,%20%7BaddEndButtons:true,%20isFinalRender:true%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20doOnFinishStuff(%7BstopReason:%5C%22error%5C%22%7D);%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20generationLastKnownToBeWorkingAt%20=%20Date.now();%5Cn%20%20%20%20%20%20%20%20%20%20if(data.isFirstChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20gotFirstChunk%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(placeholderEl)%20placeholderEl.innerHTML%20=%20%5C%22%5C%22;%20//%20clear%20the%20svg%20'loading'%20dots%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(inputData.beforeFirstChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20inputData.beforeFirstChunk(%7B%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20generatedChunks.push(data.text);%5Cn%20%20%20%20%20%20%20%20%20%20chunks.push(data.text);%5Cn%20%20%20%20%20%20%20%20%20%20textStreamController.enqueue(data.text);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20if(inputData.onChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20inputData.onChunk(%7BfullTextSoFar:chunks.join(%5C%22%5C%22),%20textChunk:data.text%7D);%20//%20%60data.text%60%20is%20the%20full%20text%20so%20far%20(like%20in%20onFinish,%20render,%20etc.),%20and%20%60data.chunk%60%20is%20the%20most%20recent%20chunk%20(the%20one%20that%20triggered%20this%20call%20to%20onChunk)%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20onFinishPromise.liveResponseText%20=%20chunks.join(%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20renderResponseTextIntoContainer(chunks.join(%5C%22%5C%22),%20%7BaddEndButtons:!!data.isLastChunk,%20isFinalRender:!!data.isLastChunk%7D);%5Cn%20%20%20%20%20%20%20%20%20%20if(data.isLastChunk)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20console.debug(%5C%22FINISHED%20STREAMING.%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20finishedGenerating%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20finishedGeneratingSuccessfully%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20concreteInputs.startWith%20=%20chunks.join(%5C%22%5C%22);%20//%20update%20the%20startWith%20for%20'continue'%20and%20'edit'%20button%20use%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%20%20doOnFinishStuff(%7BstopReason:data.stopReason%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D);%20%20%20%20%5Cn%5Cn%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20thereWasAnErrorDuringGeneration%20=%20true;%5Cn%20%20%20%20%20%20finishedGenerating%20=%20true;%5Cn%20%20%20%20%20%20//%20onFinishPromiseRejecter();%5Cn%20%20%20%20%20%20doOnFinishStuff(%7BstopReason:%5C%22error%5C%22%7D);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20console.error(e);%5Cn%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%201000));%5Cn%20%20%20%20%20%20iframe.contentWindow.postMessage(%7Btype:%5C%22verifyUser%5C%22%7D,%20serverOrigin);%20//%20probably%20not%20necessary,%20but%20just%20in%20case%20(it'll%20only%20re-verify%20if%20it's%20actually%20needed%20anyway)%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20function%20onVisible(element,%20callback)%20%7B%5Cn%20%20%20%20new%20IntersectionObserver((entries,%20observer)%20=%3E%20%7B%5Cn%20%20%20%20%20%20entries.forEach(entry%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20if(entry.intersectionRatio%20%3E%200)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20callback(element);%5Cn%20%20%20%20%20%20%20%20%20%20observer.disconnect();%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%7D).observe(element);%5Cn%20%20%20%20if(!callback)%20return%20new%20Promise(r%20=%3E%20callback=r);%5Cn%20%20%7D%5Cn%20%20%20%20%5Cn%20%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20//%20give%20placeholderEl%20a%20chance%20to%20be%20put%20into%20the%20DOM%5Cn%20%20%20%20placeholderEl%20=%20document.querySelector(%60#$%7BcompletionId%7D%60);%20//%20this%20will%20be%20null%20if%20they're%20using%20outputTo%20or%20are%20just%20doing%20things%20fully%20manually%20onFinishPromise/onChunk/etc.%5Cn%20%20%20%20if(placeholderEl)%20placeholderElDidInitiallyExist%20=%20true;%5Cn%20%20%20%20//%20wait%20for%20placeholderEl%20to%20become%20visible:%5Cn%20%20%20%20if(placeholderElDidInitiallyExist%20&&%20!inputData.outputTo)%20%7B%5Cn%20%20%20%20%20%20await%20onVisible(placeholderEl);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(inputData.onStart)%20%7B%5Cn%20%20%20%20%20%20inputData.onStart(onFinishPromise);%20//%20note%20that%20%60onFinishPromise%60%20has%20all%20the%20data%20attached,%20like%20%60inputs%60,%20%60liveResponseText%60,%20etc.%20-%20see%20below%5Cn%20%20%20%20%20%20if(inputData.outputTo%20&&%20inputData.outputTo.tagName%20===%20%5C%22TEXTAREA%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20try%20%7B%20textareaLoadingIndicatorHandler%20=%20addTextareaLoadingIndicator(inputData.outputTo);%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D%20//%20try/catch%20because%20new%20code%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20startStreamingResponse();%20%5Cn%20%20%7D,%20100);%5Cn%20%20%5Cn%20%20let%20beforeLoaderHtml%20=%20%5C%22%5C%22;%5Cn%20%20if(!inputData.outputTo%20&&%20!hideStartWith)%20%7B%5Cn%20%20%20%20beforeLoaderHtml%20=%20inputData.render%20?%20inputData.render(%7Btext:concreteInputs.startWith,%20isPartial:true%7D)%20:%20concreteInputs.startWith;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(inputData.outputTo)%20%7B%5Cn%20%20%20%20inputData.outputTo.dataset.aiTextCompletionId%20=%20completionId;%20//%20this%20is%20used%20for%20keepalive%20stuff%20-%20if%20a%20queued%20request%20is%20going%20to%20output%20to%20an%20outputTo%20element,%20but%20that%20element%20no%20longer%20has%20the%20correct%20%60dataset.aiTextCompletionId%60%20then%20we%20drop%20it%20from%20the%20queue%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20onFinishPromise.inputs%20=%20originalConcreteInputs;%5Cn%20%20onFinishPromise.liveResponseText%20=%20concreteInputs.startWith;%20//%20this%20is%20full%20text%20(including%20startWith,%20which%20is%20why%20this%20property%20isn't%20called%20liveGeneratedText,%20or%20liveOutputText)%20and%20is%20live-updated%20as%20chunks%20come%20in.%20and%20note%20that%20it%20can%20also%20be%20edited%20by%20the%20user%20using%20the%20end%20buttons%5Cn%20%20onFinishPromise.textStream%20=%20textStream;%5Cn%20%20onFinishPromise.onFinishPromise%20=%20onFinishPromise;%20//%20backwards-compat%20with%20old%20return%20object%5Cn%20%20onFinishPromise.stop%20=%20()%20=%3E%20%7B%20//%20note:%20this%20can't%20actually%20stop%20a%20request%20if%20it%20has%20already%20started,%20since%20the%20server%20doesn't%20currently%20support%20that%20-%20it%20just%20drops%20the%20request%20from%20the%20queue%20if%20it%20is%20still%20waiting.%5Cn%20%20%20%20userStoppedGeneration%20=%20true;%5Cn%20%20%20%20try%20%7B%20stopFn();%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D;%5Cn%20%20%20%20try%20%7B%20iframe.contentWindow.postMessage(%7B%20type:%20%5C%22stopStream%5C%22,%20requestId:completionId%20%7D,%20serverOrigin);%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D;%5Cn%20%20%20%20return%20onFinishPromise;%5Cn%20%20%7D;%5Cn%20%20onFinishPromise.id%20=%20completionId;%5Cn%20%20onFinishPromise.loadingIndicatorHtml%20=%20animatedLoadingSvg;%20//%20%3C--%20just%20a%20littler%20helper%20for%20people%20who%20are%20e.g.%20using%20onFinishPromise/onChunk/etc.%20but%20want%20to%20add%20a%20loading%20indicator%20to%20the%20page%20manually%5Cn%20%20onFinishPromise.toString%20=%20function()%20%7B%20//%20this%20object%20stringifies%20into%20the%20default%20placeholder%20element%5Cn%20%20%20%20return%20%60%3Cspan%20class=%5C%22ai-text-response-ctn%5C%22%20id=%5C%22$%7BcompletionId%7D%5C%22%20style=%5C%22white-space:pre-wrap;%20$%7BinputData.style%20?%20inputData.style%20:%20%5C%22%5C%22%7D%5C%22%3E$%7BbeforeLoaderHtml%7D$%7BanimatedLoadingSvg%7D%3C/span%3E%60;%5Cn%20%20%7D;%5Cn%20%20onFinishPromise.submitUserRating%20=%20async%20(%7Bscore,%20reason%7D)%20=%3E%20%7B%5Cn%20%20%20%20if(!finishedGenerating%20%7C%7C%20thereWasAnErrorDuringGeneration)%20%7B%5Cn%20%20%20%20%20%20console.error(thereWasAnErrorDuringGeneration%20?%20%5C%22cannot%20rate%20because%20there%20was%20an%20error%20during%20generation%5C%22%20:%20%5C%22cannot%20rate%20because%20it%20hasn't%20finished%20generating%20yet%5C%22);%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(isNaN(Number(score))%20%7C%7C%20Number(score)%20%3E%201%20%7C%7C%20Number(score)%20%3C%200)%20return%20alert(%60User%20rating%20should%20be%20a%20value%20between%200%20(bad)%20and%201%20(good).%20Like%200.4%20or%200.8,%20for%20example.%60);%5Cn%20%20%20%20score%20=%20Number(score);%5Cn%20%20%20%20if(!reason)%20reason%20=%20%5C%22%5C%22;%5Cn%20%20%20%20iframe.contentWindow.postMessage(%7B%20type:%20%5C%22rateGeneratedText%5C%22,%20instruction,%20startWith,%20generatedText,%20generatorName:window.generatorName,%20score,%20reason%20%7D,%20serverOrigin);%5Cn%20%20%7D;%5Cn%20%20return%20onFinishPromise;%5Cn%20%20%5Cn%5Cn%5Cn%5Cn%5Cn//%20this%20was%20causing%20user-agent%20styles%20(specifically%20background%20color)%20to%20be%20removed%20in%20dark%20mode%20in%20chrome%20for%20some%20reason.%5Cn//%20it's%20a%20little%20too%20obtrusive%20anyway%20-%20ideally%20it%20would%20just%20be%20a%20%5C%22sliding%20line%5C%22%20that's%20only%20at%20the%20bottom%20of%20the%20textarea.%5Cn//%20or%20maybe%20a%20transparent%20loading%20indicator%20in%20the%20top-right%20of%20the%20textarea.%5CnaddTextareaLoadingIndicator(el)%20=%3E%5Cn%20%20//%20const%20computedStyle%20=%20getComputedStyle(el);%5Cn%20%20//%20const%20borderColor%20=%20computedStyle.borderColor;%5Cn%20%20//%20//%20Convert%20border%20color%20to%20rgba%20with%2030%25%20opacity%5Cn%20%20//%20const%20rgbaColor%20=%20borderColor.replace(/rgb%5C%5C((%5C%5Cd+),%5C%5Cs*(%5C%5Cd+),%5C%5Cs*(%5C%5Cd+)%5C%5C)/,%20'rgba($1,%20$2,%20$3,%200.3)');%5Cn%20%20//%20const%20className%20=%20'blink-'%20+%20Math.random().toString(36).substring(2,%2015);%5Cn%20%20//%20const%20style%20=%20document.createElement('style');%5Cn%20%20//%20style.innerHTML%20=%20%60%5Cn%20%20//%20%20%20@keyframes%20$%7BclassName%7D-blink%20%7B%5Cn%20%20//%20%20%20%20%200%25,%20100%25%20%7B%5Cn%20%20//%20%20%20%20%20%20%20border-color:%20$%7BborderColor%7D;%5Cn%20%20//%20%20%20%20%20%7D%5Cn%20%20//%20%20%20%20%2050%25%20%7B%5Cn%20%20//%20%20%20%20%20%20%20border-color:%20$%7BrgbaColor%7D;%5Cn%20%20//%20%20%20%20%20%7D%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%20%20.$%7BclassName%7D%20%7B%5Cn%20%20//%20%20%20%20%20animation:%20$%7BclassName%7D-blink%201s%20infinite;%5Cn%20%20//%20%20%20%20%20border-color:%20$%7BborderColor%7D;%20/*%20must%20add%20this%20explicitly,%20since%20user-agent-only%20borders%20don't%20trigger%20the%20animation%20*/%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%60;%5Cn%20%20//%20document.head.appendChild(style);%5Cn%20%20//%20el.classList.add(className);%5Cn%20%20return%20%7B%5Cn%20%20%20%20stop:%20function()%20%7B%5Cn%20%20%20%20%20%20//%20el.classList.remove(className);%5Cn%20%20%20%20%20%20//%20document.head.removeChild(style);%5Cn%20%20%20%20%7D,%5Cn%20%20%7D;%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cncharacter%5Cn%20%20%7Bmech%7Cdemon%7Ccyberpunk%7D%20%7Bwarrior%7Cminion%7Csamurai%7D%5Cn%5Cnplace%5Cn%20%20a%20retropunk%20distopia%5Cn%20%20a%20small%20village%5Cn%20%20a%20mountainous%20region%5Cn%20%20an%20underwater%20cavern%5Cn%20%20a%20=%2010%5Cn%5Cnseason%5Cn%20%20winter%5Cn%20%20summer%5Cn%20%20%5CnpoemPrompt%5Cn%20%20instruction%20=%20Write%20a%20haiku%20about%20a%20%5Bcharacter%5D%20in%20%5Bplace%5D%20during%20%5Bseason%5D.%5Cn%5Cn%5Cn%5Cn%22,%22imports%22:%5B%5D,%22lastEditTime%22:1732056702422,%22found%22:true%7D,%7B%22name%22:%22comments-plugin%22,%22modelText%22:%22$output(opts)%20=%3E%5Cn%20%20if(!opts)%20opts%20=%20%7B%7D;%5Cn%20%20let%20width%20=%20opts.width;%5Cn%20%20let%20height%20=%20opts.height;%5Cn%20%20if(!width)%20width%20=%20%5C%22300px%5C%22;%5Cn%20%20if(!height)%20height%20=%20%5C%22250px%5C%22;%20%5Cn%20%20if(typeof%20width%20===%20%5C%22number%5C%22)%20width%20+=%20%5C%22px%5C%22;%20%20%20%20%5Cn%20%20if(typeof%20height%20===%20%5C%22number%5C%22)%20height%20+=%20%5C%22px%5C%22;%5Cn%20%20let%20containerStyle%20=%20opts.containerStyle%20%7C%7C%20opts.style%20%7C%7C%20%60width:$%7Bwidth%7D;%20height:$%7Bheight%7D;%60;%5Cn%20%20%5Cn%20%20let%20iframeUniqueId%20=%20%5C%22id%5C%22+Math.random().toString().replaceAll(%5C%22.%5C%22,%20%5C%22%5C%22)+%20Math.random().toString().replaceAll(%5C%22.%5C%22,%20%5C%22%5C%22);%5Cn%20%20let%20ctx%20=%20%7B%7D;%5Cn%20%20ctx.currentInputElText%20=%20%5C%22%5C%22;%5Cn%20%20ctx.iframeUniqueId%20=%20iframeUniqueId;%5Cn%20%20%5Cn%20%20console.debug(%5C%22comments-plugin%201%5C%22);%5Cn%20%20%5Cn%20%20function%20addMethodsToReturnValue(stringObj)%20%7B%5Cn%20%20%20%20stringObj.submit%20=%20async%20function(optionalText,%20opts=%7B%7D)%20%7B%5Cn%20%20%20%20%20%20//%20Note:%20if%20optionalText%20is%20specified,%20that%20text%20will%20be%20submitted%20instead%20of%20what's%20currently%20in%20the%20text%20box,%20and%20the%20text%20box%20will%20not%20be%20cleared%20after%20submission.%5Cn%20%20%20%20%20%20if(optionalText)%20optionalText%20=%20optionalText.toString();%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20nickname%20=%20opts.nickname%20?%20opts.nickname.toString()%20:%20null;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20resolver;%5Cn%20%20%20%20%20%20let%20promise%20=%20new%20Promise(r%20=%3E%20resolver=r);%5Cn%20%20%20%20%20%20let%20requestId%20=%20Math.random().toString()+Math.random().toString();%5Cn%20%20%20%20%20%20async%20function%20messageHandler(e)%20%7B%5Cn%20%20%20%20%20%20%20%20if(e.origin%20!==%20%5C%22https://comments-plugin.perchance.org%5C%22)%20return;%5Cn%20%20%20%20%20%20%20%20if(e.data.iframeUniqueId%20!==%20ctx.iframeUniqueId)%20return;%5Cn%20%20%20%20%20%20%20%20if(e.data.requestId%20!==%20requestId)%20return;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(e.data.type%20===%20%5C%22message_submit_response%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20console.debug(%60parent%20frame%20got%20message_submit_response:%60,%20e.data.success);%5Cn%20%20%20%20%20%20%20%20%20%20resolver(%7Bsuccess:e.data.success%7D);%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20console.warn(%5C%22Invalid%20event%20type%20for%20this%20requestId?%5C%22);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20window.removeEventListener(%5C%22message%5C%22,%20messageHandler);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20window.addEventListener(%5C%22message%5C%22,%20messageHandler);%5Cn%20%20%20%20%20%20while(!ctx.finishedLoading)%20%7B%20console.debug(%5C%22Waiting%20for%20comments-plugin%20iframe%20to%20load%20before%20sending%20.submit()%20postMessage%5C%22);%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%20%7D%5Cn%20%20%20%20%20%20ctx.iframeContentWindow.postMessage(%7Btype:%5C%22trigger_programmatic_submit%5C%22,%20text:optionalText,%20nickname,%20channel:ctx.urlHashData.channel,%20requestId%7D,%20%5C%22https://comments-plugin.perchance.org%5C%22);%5Cn%20%20%20%20%20%20return%20promise;%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20%5Cn%20%20%20%20Object.defineProperty(stringObj,%20'inputText',%20%7B%5Cn%20%20%20%20%20%20get:%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20return%20ctx.currentInputElText;%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20set:%20function(value)%20%7B%5Cn%20%20%20%20%20%20%20%20ctx.currentInputElText%20=%20value;%5Cn%20%20%20%20%20%20%20%20ctx.iframeContentWindow.postMessage(%7Btype:%5C%22set_input_el_text%5C%22,%20channel:ctx.urlHashData.channel,%20text:value%7D,%20%5C%22https://comments-plugin.perchance.org%5C%22);%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20%5Cn%20%20%20%20stringObj.setNicknameForNextComment%20=%20async%20function(nickname)%20%7B%5Cn%20%20%20%20%20%20ctx.iframeContentWindow.postMessage(%7Btype:%5C%22set_next_submit_nickname%5C%22,%20channel:ctx.urlHashData.channel,%20nickname:nickname%7D,%20%5C%22https://comments-plugin.perchance.org%5C%22);%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20%5Cn%20%20%20%20Object.defineProperty(stringObj,%20'comments',%20%7B%20get:%20()%20=%3E%20ctx.allComments.slice(0)%20%7D);%5Cn%20%20%20%20Object.defineProperty(stringObj,%20'channel',%20%7B%20get:%20()%20=%3E%20ctx.urlHashData.channel%20%7D);%5Cn%20%20%20%20%5Cn%20%20%20%20return%20stringObj;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20queryParams%20=%20%7B%7D;%5Cn%20%20if(opts.adminPasswordHash)%20queryParams.adminPasswordHash%20=%20opts.adminPasswordHash.evaluateItem;%5Cn%20%20%5Cn%20%20let%20urlHashData%20=%20%7B%7D;%5Cn%20%20urlHashData.iframeUniqueId%20=%20iframeUniqueId;%5Cn%20%20if(opts.adminPasswordHash)%20urlHashData.adminPasswordHash%20=%20opts.adminPasswordHash;%5Cn%20%20if(opts.bannedWords)%20%7B%5Cn%20%20%20%20if(typeof%20opts.bannedWords%20===%20%5C%22string%5C%22)%20%7B%5Cn%20%20%20%20%20%20urlHashData.bannedWords%20=%20opts.bannedWords.trim().split(%5C%22,%5C%22).map(w%20=%3E%20w.trim()).filter(w%20=%3E%20w);%5Cn%20%20%20%20%7D%20else%20if(!opts.bannedWords.getLength%20&&%20opts.getPropertyNames%20&&%20opts.getPropertyNames.includes(%5C%22bannedWords%5C%22))%20%7B%5Cn%20%20%20%20%20%20urlHashData.bannedWords%20=%20opts.bannedWords.getRawListText.split(%5C%22=%5C%22).slice(1).join(%5C%22=%5C%22).trim().split(%5C%22,%5C%22).map(w%20=%3E%20w.trim()).filter(w%20=%3E%20w);%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20urlHashData.bannedWords%20=%20opts.bannedWords.selectAll.map(item%20=%3E%20item.getRawListText.replace(%5C%22/%5C%5C%5C%5C%5E%5C%22,%20%5C%22/%5E%5C%22));%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20if(opts.commentPlaceholderText)%20urlHashData.commentPlaceholderText%20=%20opts.commentPlaceholderText.evaluateItem;%5Cn%20%20if(opts.submitButtonText)%20urlHashData.submitButtonText%20=%20opts.submitButtonText.evaluateItem;%5Cn%20%20if(opts.submitButtonSuccessText)%20urlHashData.submitButtonSuccessText%20=%20opts.submitButtonSuccessText.evaluateItem;%5Cn%20%20if(opts.hideComments)%20urlHashData.hideComments%20=%20opts.hideComments;%5Cn%20%20if(opts.hideDates)%20urlHashData.hideDates%20=%20opts.hideDates;%5Cn%20%20if(opts.hideCommentsBeforeDate)%20urlHashData.hideCommentsBeforeDate%20=%20opts.hideCommentsBeforeDate;%5Cn%20%20%5Cn%20%20if(opts.hideSettingsButton)%20urlHashData.hideSettingsButton%20=%20opts.hideSettingsButton;%5Cn%20%20if(opts.hideFullscreenButton)%20urlHashData.hideFullscreenButton%20=%20opts.hideFullscreenButton;%5Cn%20%20if(opts.submitButtonStyle)%20urlHashData.submitButtonStyle%20=%20opts.submitButtonStyle.evaluateItem;%5Cn%20%20if(opts.settingsButtonStyle)%20urlHashData.settingsButtonStyle%20=%20opts.settingsButtonStyle.evaluateItem;%5Cn%20%20if(opts.fullscreenButtonStyle)%20urlHashData.fullscreenButtonStyle%20=%20opts.fullscreenButtonStyle.evaluateItem;%5Cn%20%20if(opts.messageBubbleStyle)%20urlHashData.messageBubbleStyle%20=%20opts.messageBubbleStyle.evaluateItem;%5Cn%20%20if(opts.messageFeedStyle)%20urlHashData.messageFeedStyle%20=%20opts.messageFeedStyle.evaluateItem;%5Cn%20%20if(opts.inputAreaStyle)%20urlHashData.inputAreaStyle%20=%20opts.inputAreaStyle.evaluateItem;%5Cn%20%20if(opts.loadFonts)%20urlHashData.loadFonts%20=%20opts.loadFonts.evaluateItem;%5Cn%20%20if(opts.forceColorScheme)%20urlHashData.forceColorScheme%20=%20opts.forceColorScheme.evaluateItem;%5Cn%20%20if(opts.channelLabel)%20urlHashData.channelLabel%20=%20opts.channelLabel.evaluateItem;%5Cn%20%20%5Cn%20%20%5Cn%20%20if(opts.adminFlair)%20urlHashData.adminFlair%20=%20opts.adminFlair.evaluateItem;%5Cn%20%20if(opts.deleteButtonIcon)%20urlHashData.deleteButtonIcon%20=%20opts.deleteButtonIcon.evaluateItem;%5Cn%20%20if(opts.bannedUsers)%20urlHashData.bannedUsers%20=%20opts.bannedUsers.selectAll.map(l%20=%3E%20l.evaluateItem.split(%5C%22-%5C%22).slice(-1)%5B0%5D).joinItems(%5C%22,%5C%22);%5Cn%20%20if(opts.rateLimits)%20urlHashData.rateLimits%20=%20opts.rateLimits;%5Cn%20%20if(opts.slashCommands)%20urlHashData.slashCommands%20=%20encodeURIComponent(JSON.stringify(opts.slashCommands));%5Cn%20%20if(opts.beforeSubmit)%20urlHashData.beforeSubmitHandlerEnabled%20=%20%5C%22true%5C%22;%5Cn%20%20if(opts.customEmojiSize)%20urlHashData.customEmojiSize%20=%20opts.customEmojiSize;%5Cn%20%20if(opts.loneCustomEmojiSizeMultiplier)%20urlHashData.loneCustomEmojiSizeMultiplier%20=%20opts.loneCustomEmojiSizeMultiplier;%5Cn%20%20if(opts.customEmojis)%20%7B%5Cn%20%20%20%20if(typeof%20opts.customEmojis%20===%20%5C%22string%5C%22%20&&%20opts.customEmojis.startsWith(%5C%22https://user-uploads.perchance.org%5C%22))%20%7B%5Cn%20%20%20%20%20%20urlHashData.customEmojis%20=%20opts.customEmojis.trim();%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20let%20text%20=%20opts.customEmojis.getRawListText;%5Cn%20%20%20%20%20%20text%20=%20text.slice(text.indexOf(%5C%22%5C%5Cn%5C%22)).trim();%20//%20remove%20list%20name%5Cn%20%20%20%20%20%20//%20note:%20no%20need%20to%20remove%20indentation%20-%20parsing%20code%20in%20embed%20does%20that%20performantly%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20we%20need%20to%20evaluateItem%20for%20things%20like%20%60@import%20=%20%7Bimport:my-emoji-list-url%7D%5Cn%20%20%20%20%20%20urlHashData.customEmojis%20=%20/@import%5C%5Cs*=%5C%5Cs*%5B%5B%7B%5D/.test(text)%20?%20text.replace(/@import%5C%5Cs*=%5C%5Cs*%5B%5B%7B%5D.+/,%20m=%3Em.evaluateItem)%20:%20text;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20urlHashData.channel%20=%20opts.channel%20?%20opts.channel.evaluateItem%20:%20%5C%22%5C%22;%5Cn%20%20%5Cn%20%20if(!window.___commentsPluginSlashCommandsByChannel12321)%20window.___commentsPluginSlashCommandsByChannel12321%20=%20%7B%7D;%5Cn%20%20window.___commentsPluginSlashCommandsByChannel12321%5BurlHashData.channel%5D%20=%20opts.slashCommands;%20%20%20%20%5Cn%20%20%5Cn%20%20let%20folderName%20=%20window.generatorName;%20%5Cn%20%20if(opts.channel)%20%7B%5Cn%20%20%20%20let%20channel%20=%20opts.channel.evaluateItem;%5Cn%20%20%20%20if(!/%5E%5Ba-z0-9%5C%5C-%5D+$/.test(channel))%20return%20%60(ERROR:%20You%20gave%20a%20channel%20name%20of%20'$%7Bchannel%7D'%20to%20the%20comments%20plugin,%20but%20channel%20names%20can%20only%20contain%20lower-case%20letters,%20numbers,%20and%20hyphens,%20like%20'my-cool-channel-33'.)%60;%5Cn%20%20%20%20folderName%20+=%20%60+$%7Bchannel%7D%60;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20//%20I've%20deprecated%20%60reverseCommentOrder%60,%20but%20it%20won't%20hurt%20existing%20implementations%20because%20the%20%5C%22reversed%5C%22%20order%20(new%20comments%20at%20bottom)%20is%20now%20default.%5Cn%20%20//%20if(opts.reverseCommentOrder)%20urlHashData.reverseCommentOrder%20=%20opts.reverseCommentOrder;%5Cn%20%20urlHashData.reverseCommentOrder%20=%20true;%5Cn%20%20if(opts.newestCommentsAtTop)%20urlHashData.reverseCommentOrder%20=%20false;%20%5Cn%20%20%5Cn%20%20let%20queryString%20=%20new%20URLSearchParams(queryParams).toString();%5Cn%20%20%5Cn%20%20let%20loadMoreButton%20=%20document.createElement(%5C%22button%5C%22);%5Cn%20%20let%20originalLoadMoreButtonTextContent%20=%20%5C%22load%20more%5C%22;%5Cn%20%20let%20postMessageSource%20=%20null;%5Cn%20%20loadMoreButton.innerHTML%20=%20originalLoadMoreButtonTextContent;%5Cn%20%20loadMoreButton.style.cssText%20=%20%5C%22display:none;%20margin:0.5rem%20auto;%5C%22;%5Cn%20%20loadMoreButton.addEventListener(%5C%22click%5C%22,%20function()%20%7B%5Cn%20%20%20%20originalLoadMoreButtonTextContent%20=%20loadMoreButton.textContent;%5Cn%20%20%20%20loadMoreButton.textContent%20=%20%5C%22loading...%5C%22;%5Cn%20%20%20%20loadMoreButton.disabled%20=%20true;%5Cn%20%20%20%20document.querySelector(%60.$%7BiframeUniqueId%7D%60).contentWindow.postMessage(%7BiframeUniqueId,%20loadMoreButtonClick:true%7D,%20%5C%22*%5C%22);%5Cn%20%20%7D);%5Cn%20%20%5Cn%20%20ctx.loadMoreButton%20=%20loadMoreButton;%5Cn%20%20ctx.opts%20=%20opts;%5Cn%20%20ctx.urlHashData%20=%20urlHashData;%5Cn%20%20ctx.allComments%20=%20%5B%5D;%5Cn%20%20ctx.onLoadAlreadyFired%20=%20false;%5Cn%20%20ctx.alreadyGotCommentIds%20=%20new%20Set();%5Cn%20%20%5Cn%20%20if(!window.___alreadyAddedCommentsPluginStuff43211234)%20%7B%5Cn%20%20%5Cn%20%20%20%20window.___commentsPluginIframeUniqueIdToContext%20=%20new%20Map();%5Cn%20%20%20%20%5Cn%20%20%20%20//%20the%20iframe%20send%20us%20a%20message%20when%20it%20is%20finished%20loading%20(this%20is%20to%20get%20around%20Glitch's%20uncustomizable%20loading%20screens)%5Cn%20%20%20%20window.addEventListener(%5C%22message%5C%22,%20async%20function(e)%20%7B%5Cn%20%20%20%20%20%20if(e.origin%20!==%20%5C%22https://comments-plugin.perchance.org%5C%22)%20return;%5Cn%20%20%20%20%20%20if(!e.data.iframeUniqueId)%20return;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20May%20need%20to%20wait%20a%20moment%20for%20the%20replacedDuringUpdate%20iframes%20to%20be%20'tracked'%20since%20my%20current%20code%20hackily%20does%20that%20with%20a%20'polling'%20method.%5Cn%20%20%20%20%20%20while(!window.___commentsPluginIframeUniqueIdToContext.get(e.data.iframeUniqueId))%20%7B%20console.debug(%5C%22Waiting%20for%20comments-plugin%20iframe%20to%20be%20tracked.%5C%22);%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20ctx%20=%20window.___commentsPluginIframeUniqueIdToContext.get(e.data.iframeUniqueId)%5Cn%20%20%20%20%20%20let%20opts%20=%20ctx.opts%5Cn%20%20%20%20%20%20let%20loadMoreButton%20=%20ctx.loadMoreButton;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20if(e.data.type%20===%20%5C%22perchance_comments_new_message_added%5C%22)%20%7B%5Cn%20%20%20%20%20%20//%20%20%20console.debug(%5C%22new%20message:%5C%22,%20e.data.messageData);%5Cn%20%20%20%20%20%20//%20%20%20console.debug(%5C%22event:%5C%22,%20e);%5Cn%20%20%20%20%20%20//%20%20%20console.debug(%5C%22window.___commentsPluginIframeContentWindowToContext:%5C%22,%20window.___commentsPluginIframeUniqueIdToContext);%5Cn%20%20%20%20%20%20//%20%20%20console.debug(%5C%22ctx:%5C%22,%20ctx);%5Cn%20%20%20%20%20%20//%20%20%20console.debug(%5C%22opts:%5C%22,%20opts);%5Cn%20%20%20%20%20%20//%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(e.data.type%20===%20%5C%22perchance_comments_new_message_added%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20if(!ctx.alreadyGotCommentIds.has(e.data.messageData.id))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20ctx.allComments.push(e.data.messageData);%5Cn%20%20%20%20%20%20%20%20%20%20ctx.alreadyGotCommentIds.add(e.data.messageData.id);%5Cn%20%20%20%20%20%20%20%20%20%20ctx.allComments.sort((a,b)%20=%3E%20a.time-b.time);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20if(opts.onComment)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20opts.onComment(e.data.messageData);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22input_el_text_change%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20console.debug(%60parent%20frame%20got%20input_el_text_change:%60,%20e.data.text);%5Cn%20%20%20%20%20%20%20%20ctx.currentInputElText%20=%20e.data.text;%5Cn%20%20%20%20%20%20%20%20if(opts.onInputTextChange)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20opts.onInputTextChange(e.data.text);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22perchance_comments_on_load_data%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20newComments%20=%20e.data.onLoadData.comments.filter(c%20=%3E%20!ctx.alreadyGotCommentIds.has(c.id));%5Cn%20%20%20%20%20%20%20%20for(let%20c%20of%20newComments)%20ctx.alreadyGotCommentIds.add(c.id);%5Cn%20%20%20%20%20%20%20%20ctx.allComments.push(...newComments);%5Cn%20%20%20%20%20%20%20%20ctx.allComments.sort((a,b)%20=%3E%20a.time-b.time);%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(ctx.onLoadAlreadyFired)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20the%20comments%20plugin%20sometimes%20self-reloads%20atm,%20which%20is%20not%20ideal,%20but%20it's%20fine%20so%20long%20as%20we%20don't%20count%20it%20as%20an%20actual%20reload.%5Cn%20%20%20%20%20%20%20%20%20%20//%20instead,%20we%20trigger%20onComment%20for%20any%20new%20comments,%20and%20that's%20it.%5Cn%20%20%20%20%20%20%20%20%20%20for(let%20comment%20of%20newComments)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20opts.onComment(comment);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20ctx.onLoadAlreadyFired%20=%20true;%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20postMessageSource%20=%20e.source;%5Cn%20%20%20%20%20%20%20%20if(opts.onLoad)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(e.data.onLoadData.comments.length%20%3E%200)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20loadMoreButton.style.display%20=%20%5C%22block%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20if(e.data.noMoreCommentsBeforeThis)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20loadMoreButton.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20opts.onLoad(e.data.onLoadData.comments,%20%7BloadMoreButton%7D);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22perchance_comments_on_load_more%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20newComments%20=%20e.data.onLoadMoreData.comments.filter(c%20=%3E%20!ctx.alreadyGotCommentIds.has(c.id));%5Cn%20%20%20%20%20%20%20%20for(let%20c%20of%20newComments)%20ctx.alreadyGotCommentIds.add(c.id);%5Cn%20%20%20%20%20%20%20%20ctx.allComments.push(...newComments);%5Cn%20%20%20%20%20%20%20%20ctx.allComments.sort((a,b)%20=%3E%20a.time-b.time);%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(e.data.onLoadMoreData.comments.length%20%3E%200)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20loadMoreButton.disabled%20=%20false;%5Cn%20%20%20%20%20%20%20%20%20%20loadMoreButton.textContent%20=%20originalLoadMoreButtonTextContent;%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20loadMoreButton.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(e.data.noMoreCommentsBeforeThis)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20loadMoreButton.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20loadMoreButton.disabled%20=%20true;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20if(opts.onLoadMore)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20opts.onLoadMore(e.data.onLoadMoreData.comments);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22perchance_comments_load_more_no_more%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20loadMoreButton.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22perchance_comments_finished_loading%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20ctx.finishedLoading%20=%20true;%5Cn%20%20%20%20%20%20%20%20//%20hide%20the%20loader%20of%20the%20iframe:%5Cn%20%20%20%20%20%20%20%20let%20ctn%20=%20document.querySelector(%60.$%7Be.data.iframeUniqueId%7D%60).closest(%5C%22.comments-plugin-ctn%5C%22);%5Cn%20%20%20%20%20%20%20%20//%20have%20to%20check%20if%20exists%20because%20i%20think%20with%20fullscreen%20button%20it's%20not%20in%20the%20ctn%20anymore:%5Cn%20%20%20%20%20%20%20%20if(ctn)%20ctn.querySelector(%5C%22.__perchance-comments-loading-facade-12345%5C%22).style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20//%20and%20then%20tell%20it%20its%20parent%20origin:%5Cn%20%20%20%20%20%20%20%20e.source.postMessage(%7BparentOrigin:window.origin%7D,%20e.origin);%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22evaluateText%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20result%20=%20e.data.text.evaluateItem;%5Cn%20%20%20%20%20%20%20%20e.source.postMessage(%7BrequestId:e.data.requestId,%20result%7D,%20e.origin);%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22before_submit_handler_call%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20result;%5Cn%20%20%20%20%20%20%20%20if(opts.beforeSubmit)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20try%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20result%20=%20await%20opts.beforeSubmit(%7BinputText:e.data.inputText%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(result%20!==%20undefined)%20result%20=%20JSON.parse(JSON.stringify(result));%5Cn%20%20%20%20%20%20%20%20%20%20%7D%20catch(e)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20result%20=%20null;%20//%20IMPORTANT:%20return%20null%20if%20it%20fails,%20which%20cancels%20the%20submission.%20Important%20for%20cases%20like:%20perchance.org/send-me-a-secret-message%20where%20continue-submission-on-error%20is%20'dangerous'%5Cn%20%20%20%20%20%20%20%20%20%20%20%20alert(%60beforeSubmit%20function%20failed%20with%20error:%20$%7Be.message%7D%60);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20console.error(e);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%2050));%20//%20important:%20allow%20e.g.%20set_input_el_text%20to%20be%20sent%20before%20this%20submit%20handler%20call%20is%20considered%20%5C%22done%5C%22%5Cn%20%20%20%20%20%20%20%20e.source.postMessage(%7BrequestId:e.data.requestId,%20result%7D,%20e.origin);%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22slash_command%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20commandName%20=%20e.data.commandName;%5Cn%20%20%20%20%20%20%20%20let%20argText%20=%20e.data.argText;%5Cn%20%20%20%20%20%20%20%20let%20slashCommands%20=%20window.___commentsPluginSlashCommandsByChannel12321%5Be.data.channel%5D;%5Cn%20%20%20%20%20%20%20%20if(slashCommands%5BcommandName%5D%20===%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20alert(%5C%22Please%20refresh%20the%20page%20before%20testing%20newly-added%20commands.%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20return%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20slashCommands%5BcommandName%5D.input%20=%20argText;%5Cn%20%20%20%20%20%20%20%20let%20resultText%20=%20slashCommands%5BcommandName%5D.output.evaluateItem;%5Cn%20%20%20%20%20%20%20%20e.source.postMessage(%7BrequestId:e.data.requestId,%20resultText%7D,%20e.origin);%5Cn%20%20%20%20%20%20%7D%20else%20if(e.data.type%20===%20%5C%22toggle_fullscreen%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20iframe%20=%20document.querySelector(%60.$%7Be.data.iframeUniqueId%7D%60);%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20//%20If%20iframe%20is%20currently%20fullscreen,%20then%20it's%20not%20in%20a%20%60ctn%60,%20so%20we%20use%20the%20pre-assigned%20data-comments-ctn-id%20to%20find%20the%20iframe's%20ctn%20so%20we%20can%20put%20it%20back%20in:%5Cn%20%20%20%20%20%20%20%20let%20ctn%20=%20iframe.closest(%5C%22.comments-plugin-ctn%5C%22)%20%7C%7C%20document.querySelector(%60%5Bdata-comments-ctn-id=%5C%22$%7Biframe.dataset.commentsCtnId%7D%5C%22%5D%60);%5Cn%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20if(ctn.dataset.isFullscreen%20===%20%5C%22no%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20document.body.appendChild(iframe);%5Cn%20%20%20%20%20%20%20%20%20%20iframe.style.position%20=%20%5C%22fixed%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20iframe.style.zIndex%20=%20%5C%22999999999%5C%22;%20//%20%3C--%20caution:%20don't%20lower%20this%5Cn%20%20%20%20%20%20%20%20%20%20iframe.style.top%20=%20%5C%220%5C%22;%20iframe.style.left%20=%20%5C%220%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20document.scrollingElement.style.overflow%20=%20%5C%22hidden%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20ctn.dataset.isFullscreen%20=%20%5C%22yes%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20//%20link%20the%20iframe%20and%20ctn%20with%20an%20id%20so%20we%20can%20get%20the%20ctn,%20given%20the%20id%20from%20the%20iframe%20that%20sent%20the%20%5C%22toggle_fullscreen%5C%22%20message:%5Cn%20%20%20%20%20%20%20%20%20%20let%20commentsCtnId%20=%20Math.random();%5Cn%20%20%20%20%20%20%20%20%20%20ctn.dataset.commentsCtnId%20=%20commentsCtnId;%5Cn%20%20%20%20%20%20%20%20%20%20iframe.dataset.commentsCtnId%20=%20commentsCtnId;%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20ctn.appendChild(iframe);%5Cn%20%20%20%20%20%20%20%20%20%20iframe.style.position%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20iframe.style.zIndex%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20iframe.style.top%20=%20%5C%22%5C%22;%20iframe.style.left%20=%20%5C%22%5C%22;%20%5Cn%20%20%20%20%20%20%20%20%20%20document.scrollingElement.style.overflow%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20ctn.dataset.isFullscreen%20=%20%5C%22no%5C%22;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn//%20%20%20%20%20%20%20%20%20if(ctn.dataset.isFullscreen%20===%20%5C%22no%5C%22)%20%7B%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.originalCssHeight%20=%20ctn.style.height;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.originalCssWidth%20=%20ctn.style.width;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.originalCssPosition%20=%20ctn.style.position;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.originalCssZIndex%20=%20ctn.style.zIndex;%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn//%20%20%20%20%20%20%20%20%20%20%20//%20we%20need%20to%20change%20the%20ancestor%20z%20indices%20too:%5Cn//%20%20%20%20%20%20%20%20%20%20%20let%20ancestorEls%20=%20%5B%5D;%5Cn//%20%20%20%20%20%20%20%20%20%20%20let%20aEl%20=%20ctn.parentElement;%5Cn//%20%20%20%20%20%20%20%20%20%20%20while(aEl%20!==%20document.body)%20%7B%5Cn//%20%20%20%20%20%20%20%20%20%20%20%20%20ancestorEls.push(aEl);%5Cn//%20%20%20%20%20%20%20%20%20%20%20%20%20aEl%20=%20aEl.parentElement;%5Cn//%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn//%20%20%20%20%20%20%20%20%20%20%20let%20ancestorZIndices%20=%20ancestorEls.map(el%20=%3E%20el.style.zIndex);%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.originalAncestorZIndices%20=%20JSON.stringify(ancestorZIndices);%5Cn//%20%20%20%20%20%20%20%20%20%20%20ancestorEls.forEach(el%20=%3E%20el.style.zIndex=%5C%2263829472%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.height%20=%20%5C%22%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.width%20=%20%5C%22%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.position%20=%20%5C%22fixed%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.zIndex%20=%20%5C%2263829472%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.top%20=%20%5C%220%5C%22;%20ctn.style.left%20=%20%5C%220%5C%22;%20ctn.style.right%20=%20%5C%220%5C%22;%20ctn.style.bottom%20=%20%5C%220%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20document.scrollingElement.style.overflow%20=%20%5C%22hidden%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.isFullscreen%20=%20%5C%22yes%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%7D%20else%20if(ctn.dataset.isFullscreen%20===%20%5C%22yes%5C%22)%20%7B%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.height%20=%20ctn.dataset.originalCssHeight;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.width%20=%20ctn.dataset.originalCssWidth;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.position%20=%20ctn.dataset.originalCssPosition;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.zIndex%20=%20ctn.dataset.originalCssZIndex;%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn//%20%20%20%20%20%20%20%20%20%20%20let%20ancestorEls%20=%20%5B%5D;%5Cn//%20%20%20%20%20%20%20%20%20%20%20let%20aEl%20=%20ctn.parentElement;%5Cn//%20%20%20%20%20%20%20%20%20%20%20while(aEl%20!==%20document.body)%20%7B%5Cn//%20%20%20%20%20%20%20%20%20%20%20%20%20ancestorEls.push(aEl);%5Cn//%20%20%20%20%20%20%20%20%20%20%20%20%20aEl%20=%20aEl.parentElement;%5Cn//%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn//%20%20%20%20%20%20%20%20%20%20%20let%20originalAncestorZIndices%20=%20JSON.parse(ctn.dataset.originalAncestorZIndices);%5Cn//%20%20%20%20%20%20%20%20%20%20%20ancestorEls.forEach((el,%20i)%20=%3E%20el.style.zIndex=originalAncestorZIndices%5Bi%5D);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.style.top%20=%20%5C%22%5C%22;%20ctn.style.left%20=%20%5C%22%5C%22;%20ctn.style.right%20=%20%5C%22%5C%22;%20ctn.style.bottom%20=%20%5C%22%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20document.scrollingElement.style.overflow%20=%20%5C%22%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%20%20ctn.dataset.isFullscreen%20=%20%5C%22no%5C%22;%5Cn//%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D,%20false);%5Cn%20%20%5Cn%20%20%20%20let%20cssText%20=%20%60%5Cn%20%20%20%20.comments-plugin-ctn%20%7B%5Cn%20%20%20%20%20%20position:relative;%5Cn%20%20%20%20%20%20display:inline-block;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20.loading-spinner-434142%20%7B%20%5Cn%20%20%20%20%20%20border:%204px%20solid%20#f3f3f3;%5Cn%20%20%20%20%20%20border-top:%204px%20solid%20#5d5d5d;%5Cn%20%20%20%20%20%20border-radius:%2050%25;%5Cn%20%20%20%20%20%20width:%2030px;%5Cn%20%20%20%20%20%20height:%2030px;%5Cn%20%20%20%20%20%20animation:%20spin%200.9s%20linear%20infinite;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20@keyframes%20spin%20%7B%5Cn%20%20%20%20%20%200%25%20%7B%20transform:%20rotate(0deg);%20%7D%5Cn%20%20%20%20%20%20100%25%20%7B%20transform:%20rotate(360deg);%20%7D%5Cn%20%20%20%20%7D%60;%5Cn%20%20%20%20let%20styleEl%20=%20document.createElement('style');%5Cn%20%20%20%20styleEl.appendChild(document.createTextNode(cssText));%5Cn%20%20%20%20document.head.appendChild(styleEl);%5Cn%20%20%20%20%5Cn%20%20%20%20//%20let%20addCommentsPluginInterval%20=%20setInterval(()%20=%3E%20%7B%5Cn%20%20%20%20//%20%20%20document.querySelectorAll(%5C%22.___perchance-comments-plugin-marker%5C%22).forEach(markerEl%20=%3E%20%7B%5Cn%20%20%20%20//%20%20%20%20%20//%20detect%20if%20a%20comments%20section%20has%20been%20injected%20after%20it%20yet%20(edit:%20for%20some%20reason%20it's%20injected%20before%20it?):%5Cn%20%20%20%20//%20%20%20%20%20if((!markerEl.nextElementSibling%20%7C%7C%20markerEl.nextElementSibling.dataset.isCommentsSection%20!==%20%5C%22true%5C%22)%20&&%20(!markerEl.previousElementSibling%20%7C%7C%20markerEl.previousElementSibling.dataset.isCommentsSection%20!==%20%5C%22true%5C%22))%20%7B%5Cn%20%20%20%20//%20%20%20%20%20%20%20let%20div%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20//%20%20%20%20%20%20%20let%20containerStyle%20=%20markerEl.dataset.containerStyle;%5Cn%20%20%20%20//%20%20%20%20%20%20%20let%20queryString%20=%20markerEl.dataset.queryString;%5Cn%20%20%20%20//%20%20%20%20%20%20%20let%20folderName%20=%20markerEl.dataset.folderName;%5Cn%20%20%20%20//%20%20%20%20%20%20%20div.innerHTML%20=%20%60%3Cdiv%20class=%5C%22comments-plugin-ctn%5C%22%20data-is-comments-section=%5C%22true%5C%22%20style=%5C%22position:relative;%20display:inline-block;%20$%7BcontainerStyle%7D%5C%22%3E%5Cn%20%20%20%20//%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22__perchance-comments-loading-facade-12345%5C%22%20style=%5C%22position:absolute;%20top:0;%20left:0;%20right:0;%20bottom:0;%20display:flex;%20align-items:center;%20justify-content:center;%20background:white;%20border:1px%20solid%20rgba(0,0,0,0.25);%20border-radius:2px;%5C%22%3E%3Cdiv%20class=%5C%22loading-spinner-434142%5C%22%3E%3C/div%3E%3C/div%3E%5Cn%20%20%20%20//%20%20%20%20%20%20%20%20%20%3Ciframe%20class=%5C%22___perchance-comments-plugin-iframe-12345%5C%22%20src=%5C%22https://comments-plugin.perchance.org/embed/$%7BfolderName%7D?$%7BqueryString%7D%5C%22%20style=%5C%22border:0;%20width:100%25;%20height:100%25;%5C%22%3E%3C/iframe%3E%5Cn%20%20%20%20//%20%20%20%20%20%20%20%3C/div%3E%60;%5Cn%20%20%20%20//%20%20%20%20%20%20%20let%20iframeContainer%20=%20div.firstElementChild;%5Cn%20%20%20%20//%20%20%20%20%20%20%20//debugger;%5Cn%20%20%20%20//%20%20%20%20%20%20%20markerEl.after(iframeContainer);%5Cn%20%20%20%20//%20%20%20%20%20%20%20clearInterval(addCommentsPluginInterval);%5Cn%20%20%20%20//%20%20%20%20%20%7D%5Cn%20%20%20%20//%20%20%20%7D);%5Cn%20%20%20%20//%20%7D,%20200);%5Cn%20%20%20%20%5Cn%20%20%20%20window.___alreadyAddedCommentsPluginStuff43211234%20=%20true;%5Cn%20%20%7D%5Cn%5Cn%20%20let%20colorScheme%20=%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22;%5Cn%20%20if(opts.forceColorScheme)%20colorScheme%20=%20opts.forceColorScheme.evaluateItem;%5Cn%20%20%5Cn%20%20function%20lazyLoadIframe(%7BurlHashDataEncoded%7D)%20%7B%5Cn%20%20%20%20let%20commentsCtn%20=%20document.querySelector(%60%5Bdata-comments-section-folder-name=%5C%22$%7BfolderName%7D%5C%22%5D:not(.already-added-intersection-observer-to-this-comments-plugin-ctn)%60);%20//%20get%20the%20first%20one%20that%20we%20haven't%20added%20an%20intersection%20observer%20for%20yet%20-%20this%20is%20needed%20because%20they%20could%20have%20multiple%20instances%20of%20the%20same%20channel%20on%20the%20page,%20and%20we%20don't%20want%20to%20add%20all%20the%20intersection%20observers%20to%20the%20first%20one%5Cn%20%20%20%20if(!commentsCtn)%20return;%20//%20i%20think%20this%20happens%20sometimes%20due%20to%20timing/race%20condition%20where%20iframe%20is%20deleted%20in%20a%20very%20small%20time%20window%5Cn%20%20%20%20commentsCtn.classList.add(%5C%22already-added-intersection-observer-to-this-comments-plugin-ctn%5C%22);%5Cn%5Cn%20%20%20%20let%20observer1,%20observer2;%5Cn%20%20%20%20//%20lazyload%20the%20iframe,%20because%20some%20generator%20pages%20have%20literally%20dozens%20of%20different%20channels.%5Cn%20%20%20%20//%20I'm%20adding%20multiple%20observers%20because%20the%20default%20%60root%60%20is%20the%20browser%20viewport,%20and%20margin%20doesn't%20make%20sense%20for%20that,%20since%20it's%20not%20scrollable,%20but%20we%20still%20want%20it%20in%20case%20of%20the%20comments%20being%20in%20weird%20non-documentElement%20scrollable%20area%20or%20something.%20Note%20really%20sure%20how%20it%20works.%5Cn%20%20%20%20const%20observerFn%20=%20entries%20=%3E%20%7B%5Cn%20%20%20%20%20%20if(entries%5B0%5D.isIntersecting)%20%7B%5Cn%20%20%20%20%20%20%20%20observer1.disconnect();%5Cn%20%20%20%20%20%20%20%20observer2.disconnect();%5Cn%20%20%20%20%20%20%20%20console.debug(%5C%22comments%20ctn:%20Visible%5C%22);%5Cn%20%20%20%20%20%20%20%20let%20placeholder%20=%20commentsCtn.querySelector(%5C%22.__perchance-comments-iframe-placeholder-el-12345%5C%22);%5Cn%20%20%20%20%20%20%20%20if(placeholder)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20iframeHtml%20=%20%60%3Ciframe%20class=%5C%22$%7BiframeUniqueId%7D%20___perchance-comments-plugin-iframe-12345%5C%22%20src=%5C%22https://comments-plugin.perchance.org/embed/$%7BfolderName%7D?$%7BqueryString%7D#$%7BurlHashDataEncoded%7D%5C%22%20style=%5C%22border:0;%20width:100%25;%20height:100%25;%20user-select:none;%5C%22%3E%3C/iframe%3E%60;%5Cn%20%20%20%20%20%20%20%20%20%20placeholder.outerHTML%20=%20iframeHtml;%5Cn%20%20%20%20%20%20%20%20%20%20ctx.iframeContentWindow%20=%20document.querySelector(%5C%22.%5C%22+iframeUniqueId).contentWindow;%5Cn%20%20%20%20%20%20%20%20%20%20window.___commentsPluginIframeUniqueIdToContext.set(iframeUniqueId,%20ctx);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20setTimeout(()%20=%3E%20%7B%20//%20slight%20delay%20in%20case%20of%20e.g.%20tabs%20being%20rendered%20in%20such%20a%20way%20that%20they're%20all%20momentarily%20visible%20(we%20don't%20wnat%20to%20load%20them%20all%20at%20once%20-%20only%20the%20active%20tab)%5Cn%20%20%20%20%20%20observer1%20=%20new%20IntersectionObserver(observerFn,%20%7B%5Cn%20%20%20%20%20%20%20%20rootMargin:%20%5C%226000px%5C%22,%20//%20we%20basically%20want%20to%20trigger%20~all%20visible%20elements%20anyway%20-%20just%20not%20stuff%20hidden%20within%20e.g.%20tabs%20plugin%20or%20whatever.%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20observer1.observe(commentsCtn);%5Cn%20%20%20%20%20%20observer2%20=%20new%20IntersectionObserver(observerFn,%20%7B%5Cn%20%20%20%20%20%20%20%20root:%20document.documentElement,%5Cn%20%20%20%20%20%20%20%20rootMargin:%20%5C%226000px%5C%22,%20//%20we%20basically%20want%20to%20trigger%20~all%20visible%20elements%20anyway%20-%20just%20not%20stuff%20hidden%20within%20e.g.%20tabs%20plugin%20or%20whatever.%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20observer2.observe(commentsCtn);%5Cn%20%20%20%20%7D,%205);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20containerHtml%20=%20%60%3Cdiv%20data-is-fullscreen=%5C%22no%5C%22%20data-comments-section-folder-name=%5C%22$%7BfolderName%7D%5C%22%20class=%5C%22comments-plugin-ctn%5C%22%20data-is-comments-section=%5C%22true%5C%22%20style=%5C%22$%7BcontainerStyle%7D%5C%22%3E%5Cn%20%20%20%20%3Cdiv%20class=%5C%22__perchance-comments-loading-facade-12345%5C%22%20style=%5C%22position:absolute;%20top:0;%20left:0;%20right:0;%20bottom:0;%20display:flex;%20align-items:center;%20justify-content:center;%20background:$%7BcolorScheme%20===%20%5C%22light%5C%22%20?%20%5C%22white%5C%22%20:%20%5C%22#131516%5C%22%7D;%20border:1px%20solid%20rgba(0,0,0,0.25);%20border-radius:2px;%5C%22%3E%3Cdiv%20class=%5C%22loading-spinner-434142%5C%22%3E%3C/div%3E%3C/div%3E%5Cn%20%20%20%20%3Cspan%20class=%5C%22__perchance-comments-iframe-placeholder-el-12345%5C%22%3E%3C/span%3E%5Cn%20%20%3C/div%3E%60;%5Cn%20%20%5Cn%20%20if(opts.replacedDuringUpdate)%20%7B%5Cn%20%20%20%20//%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20//%20%20%20while(!document.querySelector(%5C%22.%5C%22+iframeUniqueId))%20%7B%5Cn%20%20%20%20//%20%20%20%20%20console.debug(%5C%22Waiting%20for%20comments-plugin%20iframe%20to%20appear%20in%20document.%5C%22);%5Cn%20%20%20%20//%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20//%20%20%20%7D%5Cn%20%20%20%20//%20%20%20ctx.iframeContentWindow%20=%20document.querySelector(%5C%22.%5C%22+iframeUniqueId).contentWindow;%5Cn%20%20%20%20//%20%20%20window.___commentsPluginIframeUniqueIdToContext.set(iframeUniqueId,%20ctx);%5Cn%20%20%20%20//%20%7D,%2010);%5Cn%20%20%20%20//%20return%20addMethodsToReturnValue(new%20String(%60%3Cdiv%20data-is-fullscreen=%5C%22no%5C%22%20data-comments-section-folder-name=%5C%22$%7BfolderName%7D%5C%22%20class=%5C%22comments-plugin-ctn%5C%22%20data-is-comments-section=%5C%22true%5C%22%20style=%5C%22$%7BcontainerStyle%7D%5C%22%3E%5Cn%20%20%20%20//%20%20%20%3Cdiv%20class=%5C%22__perchance-comments-loading-facade-12345%5C%22%20style=%5C%22position:absolute;%20top:0;%20left:0;%20right:0;%20bottom:0;%20display:flex;%20align-items:center;%20justify-content:center;%20background:$%7BcolorScheme%20===%20%5C%22light%5C%22%20?%20%5C%22white%5C%22%20:%20%5C%22#131516%5C%22%7D;%20border:1px%20solid%20rgba(0,0,0,0.25);%20border-radius:2px;%5C%22%3E%3Cdiv%20class=%5C%22loading-spinner-434142%5C%22%3E%3C/div%3E%3C/div%3E%5Cn%20%20%20%20//%20%20%20%3Ciframe%20loading=%5C%22lazy%5C%22%20class=%5C%22$%7BiframeUniqueId%7D%20___perchance-comments-plugin-iframe-12345%5C%22%20src=%5C%22https://comments-plugin.perchance.org/embed/$%7BfolderName%7D?$%7BqueryString%7D#$%7BencodeURIComponent(JSON.stringify(urlHashData))%7D%5C%22%20style=%5C%22border:0;%20width:100%25;%20height:100%25;%5C%22%3E%3C/iframe%3E%5Cn%20%20%20%20//%20%3C/div%3E%60));%5Cn%20%20%20%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20urlHashDataEncoded%20=%20encodeURIComponent(JSON.stringify(urlHashData));%5Cn%20%20%20%20%20%20lazyLoadIframe(%7BurlHashDataEncoded%7D)%5Cn%20%20%20%20%7D,%2010);%5Cn%20%20%20%20return%20addMethodsToReturnValue(new%20String(containerHtml));%5Cn%20%20%7D%5Cn%20%20%20%20%5Cn%20%20if(!document.querySelector(%60%5Bdata-comments-section-folder-name=%5C%22$%7BfolderName%7D%5C%22%5D%60))%20%7B%5Cn%5Cn%20%20%20%20function%20swapMarkerElForRealEl()%20%7B%5Cn%20%20%20%20%20%20let%20markerEl%20=%20document.querySelector(%60%5Bdata-marker-tag=%5C%22temporaryMarkerElForCommentsPlugin84738932-folderName-$%7BfolderName%7D%5C%22%5D%60);%5Cn%20%20%20%20%20%20if(!markerEl)%20return;%5Cn%20%20%20%20%20%20let%20containerStyle%20=%20markerEl.dataset.containerStyle;%5Cn%20%20%20%20%20%20let%20queryString%20=%20markerEl.dataset.queryString;%5Cn%20%20%20%20%20%20let%20urlHashDataEncoded%20=%20markerEl.dataset.urlHashDataEncoded;%5Cn%20%20%20%20%20%20//%20let%20folderName%20=%20markerEl.dataset.folderName;%5Cn%5Cn%20%20%20%20%20%20//%20NOTE:%20we%20don't%20use%20replaceWith%20here%20because%20that%20approach%20would%20mean%20that%20this%20would%20get%20updated%20during%20update()%20calls%5Cn%20%20%20%20%20%20markerEl.outerHTML%20=%20containerHtml;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20lazyLoadIframe(%7BurlHashDataEncoded%7D);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20setTimeout(swapMarkerElForRealEl,%2050);%5Cn%5Cn%20%20%20%20//%20the%20above%20commented-out%20setTimeout%20one-liner%20was%20the%20previous%20approach.%20the%20below%20MutationObserver-based%20monstrosity%20is%20a%20bit%20better%20because%20it%20ensures%20the%20swap%20happens%20*the%20moment*%20that%20the%20marker%20is%20added%20to%20the%20page,%20and%20we%20can%20wait%20a%20long%20time%20without%20the%20need%20for%20polling%5Cn%20%20%20%20let%20markerEl%20=%20document.querySelector(%60%5Bdata-marker-tag=%5C%22temporaryMarkerElForCommentsPlugin84738932-folderName-$%7BfolderName%7D%5C%22%5D%60);%5Cn%20%20%20%20if(markerEl)%20%7B%5Cn%20%20%20%20%20%20swapMarkerElForRealEl();%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20//%20they%20generated%20the%20comments%20HTML,%20but%20haven't%20put%20it%20in%20the%20page%20yet,%20so%20we%20wait%20for%20it%20using%20a%20mutation%20observer:%5Cn%20%20%20%20%20%20let%20foundElement%20=%20false;%5Cn%20%20%20%20%20%20let%20markerTagValue%20=%20%60temporaryMarkerElForCommentsPlugin84738932-folderName-$%7BfolderName%7D%60;%5Cn%20%20%20%20%20%20let%20observer%20=%20new%20MutationObserver((mutations)%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20for(let%20mutation%20of%20mutations)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20for(let%20node%20of%20mutation.addedNodes)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(node.dataset%20&&%20node.dataset.markerTag%20===%20markerTagValue)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20foundElement%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if(node.querySelector)%20%7B%20//%20skip%20#text,%20#comment,%20etc.%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20since%20mutation%20observers%20don't%20trigger%20for%20all%20subnodes%20-%20only%20the%20highest-level%20nodes%20in%20a%20mutation%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20markerEl%20=%20node.querySelector(%60%5Bdata-marker-tag=%5C%22temporaryMarkerElForCommentsPlugin84738932-folderName-$%7BfolderName%7D%5C%22%5D%60);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(markerEl)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20foundElement%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(foundElement)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20observer.disconnect();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20swapMarkerElForRealEl();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20observer.observe(document.body,%20%7B%20childList:%20true,%20subtree:%20true%20%7D);%5Cn%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20if(!foundElement)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20console.error(%5C%22Couldn't%20find%20marker%20element%20for%20comments%20plugin?%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20observer.disconnect();%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D,%2010000);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20return%20addMethodsToReturnValue(new%20String(%60%3Cspan%20data-marker-tag=%5C%22temporaryMarkerElForCommentsPlugin84738932-folderName-$%7BfolderName%7D%5C%22%20data-folder-name=%5C%22$%7BfolderName%7D%5C%22%20data-container-style=%5C%22$%7BcontainerStyle%7D%5C%22%20data-query-string=%5C%22$%7BqueryString%7D%5C%22%20data-url-hash-data-encoded=%5C%22$%7BencodeURIComponent(JSON.stringify(urlHashData))%7D%5C%22%3E%3C/span%3E%60));%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20return%20%5C%22%5C%22;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%5Cn%5Cn//%20%20%20//%20This%20is%20a%20temporary%20fix%20because%20editing%20the%20text%20next%20to%20where%20the%20plugin%20is%20placed%20(within%20the%20same%20HTML%20%5C%22node%5C%22?)%20will%20cause%20the%5Cn//%20%20%20//%20comments%20section%20to%20disappear%20which%20causes%20users%20to%20think%20that%20they%20can't%20edit%20the%20positioning%20of%20the%20comments.%20So%20we%20tell%20them%20to%5Cn//%20%20%20//%20refresh%20the%20page.%20Ideally%20I'd%20fix%20this%20like%20I%20did%20with%20the%20text-to-image-plugin%20gallery%20-%20I%20just%20return/create%20a%20%5C%22fresh%5C%22%20one%20whenever%5Cn//%20%20%20//%20the%20old%20one%20isn't%20detected%20with%20querySelector.%5Cn//%20%20%20setTimeout(()%20=%3E%20%7B%5Cn//%20%20%20%20%20if(document.querySelectorAll(%5C%22.___perchance-comments-plugin-marker%5C%22).length%20!==%20document.querySelectorAll(%5C%22.comments-plugin-ctn%5C%22).length)%20%7B%5Cn//%20%20%20%20%20%20%20document.querySelectorAll(%5C%22.___perchance-comments-plugin-marker%5C%22).forEach(markerEl%20=%3E%20%7B%5Cn//%20%20%20%20%20%20%20%20%20markerEl.style.cssText%20=%20%60display:inline-block;%20border:1px%20solid%20grey;%20$%7BmarkerEl.dataset.containerStyle%7D%60;%5Cn//%20%20%20%20%20%20%20%20%20markerEl.innerHTML%20=%20%60%3Cdiv%20style=%5C%22height:100%25;%20display:flex;%20align-items:center;%20justify-content:center;%5C%22%3E%3Cspan%20style=%5C%22opacity:0.6;%20padding:1rem;%5C%22%3EPlease%20save%20your%20generator%20and%20refresh%20the%20page%20to%20reload%20the%20comments%20plugin.%3C/span%3E%3C/div%3E%60;%5Cn//%20%20%20%20%20%20%20%7D);%5Cn//%20%20%20%20%20%7D%5Cn//%20%20%20%7D,%20600);%5Cn%5Ct%5Cn//%20%5Ct//%20can't%20just%20inject%20the%20iframe%20directly%20otherwise%20it%20gets%20reloaded%20every%20time%20update()%20is%20called.%20So%20we%20need%20the%20setInterval%20monstrosity%20above.%5Cn//%20%5Ctreturn%20%60%3Cspan%20class=%5C%22___perchance-comments-plugin-marker%5C%22%20data-folder-name=%5C%22$%7BfolderName%7D%5C%22%20data-container-style=%5C%22$%7BcontainerStyle%7D%5C%22%20data-query-string=%5C%22$%7BqueryString%7D%5C%22%3E%3C/span%3E%60;%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%22,%22imports%22:%5B%5D,%22lastEditTime%22:1731048702145,%22found%22:true%7D,%7B%22name%22:%22fullscreen-button-plugin%22,%22modelText%22:%22$output(text,%20exitText,%20style)%20=%3E%20%5Cn%20%20if(!window.addedFullscreenEventListenerForPlugin39492749374)%20%7B%5Cn%20%20%20%20window.addEventListener(%5C%22fullscreenchange%5C%22,%20function(event)%20%7B%5Cn%20%20%20%20%20%20if(document.fullscreenElement)%20%7B%5Cn%20%20%20%20%20%20%20%20for(let%20btn%20of%20%5B...document.querySelectorAll(%5C%22.fullscreenButtonPluginButton938479832938%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20btn.innerHTML%20=%20btn.dataset.exitText;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20for(let%20btn%20of%20%5B...document.querySelectorAll(%5C%22.fullscreenButtonPluginButton938479832938%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20btn.innerHTML%20=%20btn.dataset.text;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20window.addedFullscreenEventListenerForPlugin39492749374%20=%20true;%5Cn%20%20%7D%5Cn%20%20if(!document.documentElement.requestFullscreen)%20document.documentElement.requestFullscreen%20=%20document.documentElement.webkitRequestFullscreen%20%7C%7C%20document.documentElement.mozRequestFullScreen%20%7C%7C%20document.documentElement.msRequestFullscreen;%5Cn%20%20if(!document.exitFullscreen)%20document.exitFullscreen%20=%20document.webkitExitFullscreen%20%7C%7C%20document.mozCancelFullScreen%20%7C%7C%20document.msExitFullscreen;%5Cn%20%20if(!document.documentElement.requestFullscreen)%20%7B%5Cn%20%20%20%20document.documentElement.requestFullscreen%20=%20function()%20%7B%5Cn%20%20%20%20%20%20alert(%5C%22The%20browser/device%20you're%20using%20doesn't%20support%20fullscreen%20mode.%5C%22);%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%20%20if(!document.exitFullscreen)%20%7B%5Cn%20%20%20%20document.exitFullscreen%20=%20function()%20%7B%5Cn%20%20%20%20%20%20alert(%5C%22The%20browser/device%20you're%20using%20doesn't%20support%20fullscreen%20mode.%5C%22);%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%20%20return%20%60%3Cbutton%20class=%5C%22fullscreenButtonPluginButton938479832938%5C%22%20data-text=%5C%22$%7Btext%20%7C%7C%20%5C%22Fullscreen%5C%22%7D%5C%22%20data-exit-text=%5C%22$%7BexitText%20%7C%7C%20%5C%22Exit%20Fullscreen%5C%22%7D%5C%22%20onclick=%5C%22(!document.fullscreenElement%20&&%20!document.webkitFullscreenElement%20&&%20!document.mozFullScreenElement%20&&%20!document.msFullscreenElement)%20?%20(document.documentElement.requestFullscreen(),%20this.innerHTML=this.dataset.exitText)%20:%20(document.exitFullscreen(),%20this.innerHTML=this.dataset.text)%5C%22%20style=%5C%22line-height:1.2rem;%20$%7Bstyle%20%7C%7C%20%5C%22%5C%22%7D%5C%22%3E$%7Btext%20%7C%7C%20%5C%22Fullscreen%5C%22%7D%3C/button%3E%60;%5Cn%5Ct%22,%22imports%22:%5B%5D,%22lastEditTime%22:1699845831991,%22found%22:true%7D,%7B%22name%22:%22prompt2-plugin%22,%22modelText%22:%22async%20$output(specs,%20opts)%20=%3E%5Cn%20%20if(!opts)%20opts%20=%20%7B%7D;%5Cn%20%20opts%20=%20JSON.parse(JSON.stringify(opts));%20//%20so%20we%20can%20edit%20below%20without%20mutating%20inputs.%5Cn%20%20%5Cn%20%20let%20specEntries%20=%20Object.entries(specs);%5Cn%20%20specEntries%20=%20specEntries.filter(e%20=%3E%20e%5B1%5D);%5Cn%20%20specs%20=%20Object.fromEntries(specEntries);%20//%20so%20'null'%20can%20be%20specified%20as%20a%20value%20in%20the%20specs%20object,%20which%20means%20it%20gets%20entirely%20skipped%5Cn%20%20%5Cn%20%20let%20colorScheme%20=%20opts.colorScheme;%5Cn%20%20if(!colorScheme)%20colorScheme%20=%20localStorage.forceColorScheme%20!==%20undefined%20?%20localStorage.forceColorScheme%20:%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22;%5Cn%5Cn%20%20if(!opts.backgroundColor)%20opts.backgroundColor%20=%20colorScheme==%5C%22light%5C%22%20?%20%5C%22#e8e8e8%5C%22%20:%20%5C%22#151515%5C%22;%5Cn%20%20if(!opts.borderColor)%20opts.borderColor%20=%20colorScheme==%5C%22light%5C%22%20?%20%5C%22#c8c8c8%5C%22%20:%20%5C%22#333%5C%22;%5Cn%20%20if(!opts.borderRadius)%20opts.borderRadius%20=%20%5C%223px%5C%22;%5Cn%20%20%5Cn%20%20function%20sanitizeHtml(text)%20%7B%5Cn%20%20%20%20if(text%20===%20undefined)%20text%20=%20%5C%22%5C%22;%5Cn%20%20%20%20text%20=%20text+%5C%22%5C%22;%5Cn%20%20%20%20return%20text.replace(/&/g,%20%5C%22&amp;%5C%22).replace(/%3C/g,%20%5C%22&lt;%5C%22).replace(/%3E/g,%20%5C%22&gt;%5C%22).replace(/%5C%22/g,%20%5C%22&quot;%5C%22).replace(/'/g,%20%5C%22&#039;%5C%22);%5Cn%20%20%7D%5Cn%5Cn%20%20let%20ctn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20let%20sections%20=%20%5C%22%5C%22;%5Cn%20%20let%20structuredSectionsI%20=%200;%5Cn%20%20let%20i%20=%200;%5Cn%20%20for(let%20%5Bkey,%20spec%5D%20of%20Object.entries(specs))%20%7B%5Cn%20%20%20%20if(spec.type%20==%20%5C%22select%5C%22)%20%7B%5Cn%20%20%20%20%20%20sections%20+=%20%60%5Cn%20%20%20%20%20%20%20%20%3Csection%20class=%5C%22structuredInputSection%5C%22%20data-is-hidden-extra=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20style=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22display:none%5C%22%20:%20%5C%22%5C%22%7D;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22sectionLabel%5C%22%20style=%5C%22$%7BstructuredSectionsI%20===%200%20?%20%5C%22margin-top:0;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E$%7Bspec.label%7D$%7Bspec.infoTooltip%20?%20%60%20%3Cspan%20title=%5C%22$%7BsanitizeHtml(spec.infoTooltip)%7D%5C%22%20style=%5C%22cursor:pointer;%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%84%B9%EF%B8%8F%3C/span%3E%60%20:%20%5C%22%5C%22%7D%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22flex-grow:1;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cselect%20data-spec-key=%5C%22$%7BsanitizeHtml(key)%7D%5C%22%20value=%5C%22$%7BsanitizeHtml(spec.defaultValue)%7D%5C%22%20$%7Bspec.disabled%20===%20true%20?%20%5C%22disabled%5C%22%20:%20%5C%22%5C%22%7D%20style=%5C%22width:100%25;height:100%25;%20padding:0.25rem;%5C%22%3E$%7Bspec.options.map(o%20=%3E%20%60%3Coption%20value=%5C%22$%7BsanitizeHtml(o.value)%7D%5C%22%20$%7Bo.value%20===%20spec.defaultValue%20?%20%5C%22selected%5C%22%20:%5C%22%5C%22%7D%3E$%7BsanitizeHtml(o.content)%20%7C%7C%20sanitizeHtml(o.value)%7D%3C/option%3E%60).join(%5C%22%5C%22)%7D%3C/select%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/section%3E%60;%5Cn%20%20%20%20%20%20structuredSectionsI++;%5Cn%20%20%20%20%7D%20else%20if(spec.type%20==%20%5C%22textLine%5C%22)%20%7B%5Cn%20%20%20%20%20%20sections%20+=%20%60%5Cn%20%20%20%20%20%20%20%20%3Csection%20class=%5C%22structuredInputSection%5C%22%20data-is-hidden-extra=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20style=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22display:none%5C%22%20:%20%5C%22%5C%22%7D;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22sectionLabel%5C%22%20style=%5C%22$%7BstructuredSectionsI%20===%200%20?%20%5C%22margin-top:0;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E$%7Bspec.label%7D$%7Bspec.infoTooltip%20?%20%60%20%3Cspan%20title=%5C%22$%7BsanitizeHtml(spec.infoTooltip)%7D%5C%22%20style=%5C%22cursor:pointer;%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%84%B9%EF%B8%8F%3C/span%3E%60%20:%20%5C%22%5C%22%7D%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22flex-grow:1;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20data-initial-focus=%5C%22$%7Bspec.focus%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20data-spec-key=%5C%22$%7BsanitizeHtml(key)%7D%5C%22%20$%7Bspec.disabled%20===%20true%20?%20%5C%22disabled%5C%22%20:%20%5C%22%5C%22%7D%20value=%5C%22$%7BsanitizeHtml(spec.defaultValue)%7D%5C%22%20style=%5C%22width:100%25;height:100%25;%20padding:%200.25rem;%20$%7Bspec.cssText%20%7C%7C%20%5C%22%5C%22%7D;%5C%22%20type=%5C%22text%5C%22%20placeholder=%5C%22$%7BsanitizeHtml(spec.placeholder)%7D%5C%22%20$%7Bspec.validationPattern%20?%20%60pattern=%5C%22$%7BsanitizeHtml(spec.validationPattern)%7D%5C%22%60%20:%20%5C%22%5C%22%7D%20$%7Bspec.disableSpellCheck%20?%20%60spellcheck=%5C%22false%5C%22%60%20:%20%60%60%7D%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/section%3E%60;%5Cn%20%20%20%20%20%20structuredSectionsI++;%5Cn%20%20%20%20%7D%20else%20if(spec.type%20==%20%5C%22text%5C%22)%20%7B%5Cn%20%20%20%20%20%20sections%20+=%20%60%5Cn%20%20%20%20%20%20%20%20%3Csection%20class=%5C%22structuredInputSection%5C%22%20data-is-hidden-extra=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20style=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22display:none%5C%22%20:%20%5C%22%5C%22%7D;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22sectionLabel%5C%22%20style=%5C%22$%7BstructuredSectionsI%20===%200%20?%20%5C%22margin-top:0;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E$%7Bspec.label%7D$%7Bspec.infoTooltip%20?%20%60%20%3Cspan%20title=%5C%22$%7BsanitizeHtml(spec.infoTooltip)%7D%5C%22%20style=%5C%22cursor:pointer;%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%84%B9%EF%B8%8F%3C/span%3E%60%20:%20%5C%22%5C%22%7D%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22flex-grow:1;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctextarea%20data-initial-focus=%5C%22$%7Bspec.focus%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20data-spec-key=%5C%22$%7BsanitizeHtml(key)%7D%5C%22%20$%7Bspec.height%20===%20%5C%22fit-content%5C%22%20?%20%60data-height=%5C%22fit-content%5C%22%60%20:%20%60%60%7D%20$%7Bspec.disabled%20===%20true%20?%20%5C%22disabled%5C%22%20:%20%5C%22%5C%22%7D%20style=%5C%22width:100%25;%20$%7Bspec.height%20===%20%5C%22fit-content%5C%22%20?%20%5C%22%5C%22%20:%20%60height:$%7BsanitizeHtml(spec.height)%7D%60%7D;%20min-height:$%7Bspec.minHeight%20??%20%5C%224rem%5C%22%7D;%20max-height:$%7Bspec.maxHeight%20??%20%5C%2250vh%5C%22%7D;%20padding:0.25rem;%20$%7Bspec.cssText%20%7C%7C%20%5C%22%5C%22%7D;%5C%22%20type=%5C%22text%5C%22%20placeholder=%5C%22$%7BsanitizeHtml(spec.placeholder)%7D%5C%22%20$%7Bspec.disableSpellCheck%20?%20%60spellcheck=%5C%22false%5C%22%60%20:%20%60%60%7D%3E$%7BsanitizeHtml(spec.defaultValue)%7D%3C/textarea%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/section%3E%60;%5Cn%20%20%20%20%20%20structuredSectionsI++;%5Cn%20%20%20%20%7D%20else%20if(spec.type%20==%20%5C%22buttons%5C%22)%20%7B%5Cn%20%20%20%20%20%20sections%20+=%20%60%5Cn%20%20%20%20%20%20%20%20%3Csection%20data-spec-key=%5C%22$%7BsanitizeHtml(key)%7D%5C%22%20class=%5C%22structuredInputSection%5C%22%20data-is-hidden-extra=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20style=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22display:none%5C%22%20:%20%5C%22%5C%22%7D;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22sectionLabel%5C%22%20style=%5C%22$%7BstructuredSectionsI%20===%200%20?%20%5C%22margin-top:0;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E$%7Bspec.label%20??%20%5C%22%5C%22%7D$%7Bspec.infoTooltip%20?%20%60%20%3Cspan%20title=%5C%22$%7BsanitizeHtml(spec.infoTooltip)%7D%5C%22%20style=%5C%22cursor:pointer;%5C%22%20onclick=%5C%22alert(this.title)%5C%22%3E%E2%84%B9%EF%B8%8F%3C/span%3E%60%20:%20%5C%22%5C%22%7D%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22flex-grow:1;%20display:%20grid;%20grid-template-columns:%20repeat(auto-fit,%20minmax(90px,%20200px));%20gap:%201rem;%20justify-content:center;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20$%7Bspec.buttons.map(b%20=%3E%20%60%3Cbutton%20$%7Bb.disabled%20===%20true%20?%20%5C%22disabled%5C%22%20:%20%5C%22%5C%22%7D%20style=%5C%22width:max-content;%20justify-self:center;%20align-self:center;%20border:%201px%20solid%20lightgrey;%20border-radius:%203px;%20padding:0.25rem;%20$%7Bb.cssText%20%7C%7C%20%5C%22%5C%22%7D;%5C%22%3E$%7Bb.text%7D%3C/button%3E%60).join(%5C%22%20%5C%22)%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3C/section%3E%60;%5Cn%20%20%20%20%20%20structuredSectionsI++;%5Cn%20%20%20%20%7D%20else%20if(spec.type%20==%20%5C%22none%5C%22)%20%7B%5Cn%20%20%20%20%20%20sections%20+=%20%60%5Cn%20%20%20%20%20%20%20%20%3Csection%20data-spec-key=%5C%22$%7BsanitizeHtml(key)%7D%5C%22%20data-is-hidden-extra=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20data-requires-element-insert=%5C%22$%7Btypeof%20spec.html%20===%20%5C%22string%5C%22%20?%20%5C%22no%5C%22%20:%20%5C%22yes%5C%22%7D%5C%22%20style=%5C%22$%7Bspec.hidden%20===%20true%20?%20%5C%22display:none%5C%22%20:%20%5C%22%5C%22%7D;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20$%7Btypeof%20spec.html%20===%20%5C%22string%5C%22%20?%20spec.html%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%3C/section%3E%60;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20i++;%5Cn%20%20%7D%5Cn%20%20ctn.innerHTML%20=%20%60%5Cn%20%20%20%20%3Cdiv%20class=%5C%22promptModalInnerContainer%5C%22%20style=%5C%22background:rgba(0,0,0,0.7);%20position:fixed;%20top:0;%20left:0;%20right:0;%20bottom:0;%20z-index:9999999;%20display:flex;%20justify-content:center;%20$%7Bopts.verticallyCenter%20?%20%5C%22align-items:center;%5C%22%20:%20%5C%22%5C%22%7D%20color:inherit;%20color-scheme:$%7BcolorScheme%7D;%20$%7BcolorScheme===%5C%22light%5C%22%20?%20%5C%22color:black%5C%22%20:%20%5C%22color:#e7e7e7%5C%22%7D;%20font:inherit;%20padding:0.5rem;%20text-align:left;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20style=%5C%22width:600px;%20max-width:100%25;%20background:$%7BsanitizeHtml(opts.backgroundColor)%7D;%20height:%20min-content;%20padding:1rem;%20border:1px%20solid%20$%7Bopts.borderColor%7D;%20border-radius:$%7Bopts.borderRadius%7D;%20box-shadow:%200px%201px%2010px%203px%20rgb(130%20130%20130%20/%2024%25);%20max-height:%20calc(100%25%20-%201rem);display:%20flex;%20flex-direction:%20column;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20class=%5C%22sectionsContainer%5C%22%20style=%5C%22overflow:auto;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20$%7Bsections%7D%5Cn%20%20%20%20%20%20%20%20%20%20$%7BObject.values(specs).find(s%20=%3E%20s.hidden%20===%20true)%20?%20%60%5Cn%20%20%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22text-align:center;%20margin-top:1rem;%20display:flex;%20justify-content:center;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22showHidden%5C%22%20style=%5C%22padding:%200.25rem;%5C%22%3E$%7Bopts.showHiddenInputsText%20%7C%7C%20%5C%22Show%20hidden%20inputs%5C%22%7D%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%20%20%60%20:%20%5C%22%5C%22%7D%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22text-align:center;%20margin-top:1rem;%20$%7Bopts.cancelButtonText%20===%20null%20?%20%5C%22%5C%22%20:%20%60display:flex;%20justify-content:space-between;%60%7D%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20$%7Bopts.cancelButtonText%20===%20null%20?%20%5C%22%5C%22%20:%20%60%3Cbutton%20class=%5C%22cancel%5C%22%20style=%5C%22padding:%200.25rem;%5C%22%3E$%7Bopts.cancelButtonText%20??%20%5C%22cancel%5C%22%7D%3C/button%3E%60%7D%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22submit%5C%22%20style=%5C%22padding:%200.25rem;%20$%7Bopts.submitButtonCssText%20%7C%7C%20''%7D;%5C%22%3E$%7Bopts.submitButtonText%20%7C%7C%20%5C%22submit%5C%22%7D%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%3Cstyle%3E%5Cn%20%20%20%20%20%20%20%20.promptModalInnerContainer%20.sectionsContainer%20%3E%20section%20.sectionLabel%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20margin:0.125rem%200;%5Cn%20%20%20%20%20%20%20%20%20%20margin-top:%201rem;%5Cn%20%20%20%20%20%20%20%20%20%20font-size:85%25;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20.promptModalInnerContainer%20.sectionsContainer%20input:invalid%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20background-color:%20lightpink;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20.promptModalInnerContainer%20.sectionsContainer%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20-ms-overflow-style:%20none;%20%20/*%20Internet%20Explorer%2010+%20*/%5Cn%20%20%20%20%20%20%20%20%20%20scrollbar-width:%20none;%20%20/*%20Firefox%20*/%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20.promptModalInnerContainer%20.sectionsContainer::-webkit-scrollbar%20%7B%20%5Cn%20%20%20%20%20%20%20%20%20%20display:%20none;%20%20/*%20Safari%20and%20Chrome%20*/%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20.promptModalInnerContainer%20.sectionsContainer.scrollFade%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20padding-bottom:%2030px;%5Cn%20%20%20%20%20%20%20%20%20%20-webkit-mask-image:%20linear-gradient(to%20bottom,%20black%20calc(100%25%20-%2030px),%20#ffffff00%20100%25);%5Cn%20%20%20%20%20%20%20%20%20%20mask-image:%20linear-gradient(to%20bottom,%20black%20calc(100%25%20-%2030px),%20#ffffff00%20100%25);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20.promptModalInnerContainer%20*%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20box-sizing:%20border-box;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%3C/style%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%60;%5Cn%20%20document.body.appendChild(ctn);%5Cn%20%20%5Cn%20%20function%20updateFitHeights()%20%7B%20//%20settimeout%20to%20ensure%20rendered%5Cn%20%20%20%20ctn.querySelectorAll(%5C%22textarea%5Bdata-height=fit-content%5D%5C%22).forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20minHeight%20=%20el.offsetHeight;%20//%20textareas%20will%20always%20have%20min-height%20set,%20so%20we%20can%20use%20that%20via%20offsetHeight%5Cn%20%20%20%20%20%20el.style.height%20=%20Math.max(minHeight,%20(el.scrollHeight+10))%20+%20%5C%22px%5C%22;%5Cn%20%20%20%20%7D);%5Cn%20%20%7D%5Cn%5Cn%20%20setTimeout(updateFitHeights,%205);%5Cn%5Cn%20%20if(ctn.querySelector(%5C%22button.showHidden%5C%22))%20%7B%5Cn%20%20%20%20ctn.querySelector(%5C%22button.showHidden%5C%22).onclick%20=%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20ctn.querySelectorAll('.sectionsContainer%20%5Bdata-is-hidden-extra=yes%5D').forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20el.style.display='';%5Cn%20%20%20%20%20%20%20%20el.dataset.isHiddenExtra%20=%20%5C%22no%5C%22;%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20ctn.querySelector(%5C%22button.showHidden%5C%22).remove();%5Cn%20%20%20%20%20%20updateFitHeights();%5Cn%20%20%20%20%20%20updateInputVisibilies();%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%5Cn%20%20//%20insert%20non-string%20HTML%20elements%20for%20type==html%20specs%5Cn%20%20let%20elementObjects%20=%20Object.values(specs).filter(s%20=%3E%20s.html%20&&%20typeof%20s.html%20!==%20%5C%22string%5C%22).map(s%20=%3E%20s.html);%5Cn%20%20ctn.querySelectorAll('.sectionsContainer%20%5Bdata-requires-element-insert=yes%5D').forEach((el,%20i)%20=%3E%20%7B%5Cn%20%20%20%20el.append(elementObjects%5Bi%5D);%5Cn%20%20%7D);%5Cn%5Cn%20%20//%20add%20onclick%20handlers%20for%20type==button%20specs%5Cn%20%20let%20buttonSpecKeys%20=%20Object.entries(specs).filter((%5Bkey,%20spec%5D)%20=%3E%20spec.type%20===%20%5C%22buttons%5C%22).map((%5Bkey,%20spec%5D)%20=%3E%20key);%5Cn%20%20for(let%20key%20of%20buttonSpecKeys)%20%7B%5Cn%20%20%20%20ctn.querySelectorAll(%60.sectionsContainer%20%5Bdata-spec-key=$%7Bkey%7D%5D%60).forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20buttonEls%20=%20%5B...el.querySelectorAll(%5C%22button%5C%22)%5D;%5Cn%20%20%20%20%20%20for(let%20i%20=%200;%20i%20%3C%20buttonEls.length;%20i++)%20%7B%5Cn%20%20%20%20%20%20%20%20buttonEls%5Bi%5D.onclick%20=%20specs%5Bkey%5D.buttons%5Bi%5D.onClick;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%7D%5Cn%5Cn%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20//%20add%20scrollFade%20if%20sectionsContainer%20has%20scroll%5Cn%20%20%20%20let%20sectionsContainerEl%20=%20ctn.querySelector(%5C%22.promptModalInnerContainer%20.sectionsContainer%5C%22);%5Cn%20%20%20%20if(sectionsContainerEl.scrollHeight%20%3E%20sectionsContainerEl.offsetHeight)%20%7B%5Cn%20%20%20%20%20%20sectionsContainerEl.classList.add(%5C%22scrollFade%5C%22);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20//%20focus%5Cn%20%20%20%20let%20focusEl%20=%20ctn.querySelector(%5C%22.promptModalInnerContainer%20.sectionsContainer%20%5Bdata-initial-focus=yes%5D%5C%22);%5Cn%20%20%20%20if(!focusEl)%20focusEl%20=%20%5B...ctn.querySelectorAll(%5C%22.promptModalInnerContainer%20input,%20.promptModalInnerContainer%20textarea%5C%22)%5D%5B0%5D;%5Cn%20%20%20%20if(focusEl)%20%7B%5Cn%20%20%20%20%20%20focusEl.focus();%5Cn%20%20%20%20%20%20focusEl.selectionStart%20=%20focusEl.value.length;%5Cn%20%20%20%20%7D%5Cn%20%20%7D,%205);%5Cn%20%20%5Cn%20%20function%20getAllValues()%20%7B%5Cn%20%20%20%20let%20values%20=%20%7B%7D;%5Cn%20%20%20%20for(let%20el%20of%20%5B...ctn.querySelectorAll(%5C%22%5Bdata-spec-key%5D%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20if(el.tagName%20===%20%5C%22INPUT%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20if(el.type%20==%20%5C%22file%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20values%5Bel.dataset.specKey%5D%20=%20el.files;%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20values%5Bel.dataset.specKey%5D%20=%20el.value;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%20else%20if(el.tagName%20===%20%5C%22TEXTAREA%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20values%5Bel.dataset.specKey%5D%20=%20el.value;%5Cn%20%20%20%20%20%20%7D%20else%20if(el.tagName%20===%20%5C%22SELECT%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20values%5Bel.dataset.specKey%5D%20=%20el.value;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20return%20values;%5Cn%20%20%7D%5Cn%5Cn%20%20//%20a%20spec%20can%20have%20a%20%60show%60%20function%20which%20determines%20whether%20it's%20shown%20based%20on%20the%20values%20of%20the%20other%20inputs%5Cn%20%20function%20updateInputVisibilies()%20%7B%5Cn%20%20%20%20const%20values%20=%20getAllValues();%5Cn%20%20%20%20for(const%20el%20of%20%5B...ctn.querySelectorAll(%5C%22%5Bdata-spec-key%5D%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20const%20showFn%20=%20specs%5Bel.dataset.specKey%5D.show;%5Cn%20%20%20%20%20%20if(!showFn)%20continue;%5Cn%20%20%20%20%20%20if(showFn(values))%20%7B%5Cn%20%20%20%20%20%20%20%20el.closest('section').style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20el.closest('section').style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20//%20the%20%5C%22show%20advanced%5C%22%20hidden-ness%20overrides%20the%20show()%20function%5Cn%20%20%20%20%20%20if(el.closest(%5C%22section%5C%22).dataset.isHiddenExtra%20===%20%5C%22yes%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20el.closest(%5C%22section%5C%22).style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20updateInputVisibilies();%5Cn%20%20for(const%20el%20of%20%5B...ctn.querySelectorAll(%5C%22%5Bdata-spec-key%5D%5C%22)%5D)%20%7B%5Cn%20%20%20%20el.addEventListener(%5C%22input%5C%22,%20updateInputVisibilies);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20//%20add%20onChange%20handlers,%20if%20any:%5Cn%20%20try%20%7B%5Cn%20%20%20%20for(let%20%5Bkey,%20value%5D%20of%20Object.entries(specs))%20%7B%5Cn%20%20%20%20%20%20if(value.type%20===%20%5C%22select%5C%22%20&&%20typeof%20value.onChange%20===%20%5C%22function%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20ctn.querySelector(%60.sectionsContainer%20%5Bdata-spec-key=$%7Bkey%7D%5D%60).addEventListener(%5C%22change%5C%22,%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20data%20=%20getAllValues();%5Cn%20%20%20%20%20%20%20%20%20%20let%20originalData%20=%20JSON.parse(JSON.stringify(data));%5Cn%20%20%20%20%20%20%20%20%20%20value.onChange(data);%20//%20if%20this%20handler%20edits%20the%20data,%20then%20we%20propagate%20those%20edits%20to%20the%20actual%20inputs%5Cn%20%20%20%20%20%20%20%20%20%20let%20thereWereDataChanges%20=%20false;%5Cn%20%20%20%20%20%20%20%20%20%20for(let%20k%20in%20originalData)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(data%5Bk%5D%20!==%20originalData%5Bk%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20todo:%20propagate%20change%20events?%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctn.querySelector(%60.sectionsContainer%20%5Bdata-spec-key=$%7Bk%7D%5D%60).value%20=%20data%5Bk%5D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20thereWereDataChanges%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20if(thereWereDataChanges)%20updateInputVisibilies();%5Cn%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D%20//%20try/catch%20because%20it's%20new%20code%5Cn%5Cn%20%20let%20promptResolver;%5Cn%5Cn%20%20if(opts.controls)%20%7B%5Cn%20%20%20%20//%20add%20a%20proxy%20to%20the%20controls%20object%20so%20that%20we%20can%20read%20and%20write%20spec%20values%20from%20the%20outside%5Cn%20%20%20%20opts.controls.data%20=%20new%20Proxy(%7B%7D,%20%7B%5Cn%20%20%20%20%20%20set:%20function(obj,%20prop,%20value)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20el%20=%20ctn.querySelector(%60%5Bdata-spec-key=$%7Bprop%7D%5D%60);%5Cn%20%20%20%20%20%20%20%20if(!el)%20return%20true;%5Cn%20%20%20%20%20%20%20%20el.value%20=%20value;%5Cn%20%20%20%20%20%20%20%20updateInputVisibilies();%5Cn%20%20%20%20%20%20%20%20return%20true;%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20get:%20function(obj,%20prop)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20el%20=%20ctn.querySelector(%60%5Bdata-spec-key=$%7Bprop%7D%5D%60);%5Cn%20%20%20%20%20%20%20%20if(!el)%20return%20undefined;%5Cn%20%20%20%20%20%20%20%20return%20el.value;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20opts.controls.submit%20=%20function()%20%7B%5Cn%20%20%20%20%20%20ctn.querySelector(%5C%22button.submit%5C%22).click();%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20opts.controls.cancel%20=%20function()%20%7B%5Cn%20%20%20%20%20%20promptResolver(null);%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%5Cn%20%20let%20values%20=%20await%20new%20Promise((resolve)%20=%3E%20%7B%5Cn%20%20%20%20promptResolver%20=%20resolve;%5Cn%20%20%20%20ctn.querySelector(%5C%22button.submit%5C%22).onclick%20=%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20values%20=%20getAllValues();%5Cn%20%20%20%20%20%20resolve(values);%5Cn%20%20%20%20%7D;%5Cn%20%20%20%20if(ctn.querySelector(%5C%22button.cancel%5C%22))%20%7B%5Cn%20%20%20%20%20%20ctn.querySelector(%5C%22button.cancel%5C%22).onclick%20=%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20resolve(null);%5Cn%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%7D%5Cn%20%20%7D);%5Cn%20%20ctn.remove();%5Cn%20%20return%20values;%22,%22imports%22:%5B%5D,%22lastEditTime%22:1729755725684,%22found%22:true%7D,%7B%22name%22:%22select-leaf-plugin%22,%22modelText%22:%22//%20This%20is%20the%20JavaScript%20function%20that%20powers%20this%20plugin:%5Cn$output%20(list)%20=%3E%5Cn%20%20if(!list)%20return%20%5C%22(no%20list%20given%20to%20selectLeaf%20plugin)%5C%22;%5Cn%5Ctlet%20leaf%20=%20list;%5Cn%5Ctlet%20i%20=%200;%5Cn%5Ctlet%20result;%5Cn%5Ctwhile(1)%20%7B%5Cn%5Ct%5Cti++;%5Cn%5Ct%5Ctif(i%20%3E%2010000)%20%7B%5Cn%20%20%20%20%20%20return%20%5C%22(error%20in%20select-leaf-plugin:%20infinite%20loop%20encountered?)%5C%22;%5Cn%20%20%20%20%7D%5Cn%5Ct%5Ctresult%20=%20leaf.selectOne;%5Cn%5Ct%5Ctif(typeof%20result%20===%20%5C%22string%5C%22%20%7C%7C%20Object.keys(result).length%20===%200)%20%7B%20//%20typeof%20result%20===%20%5C%22string%5C%22%20is%20for%20case%20where%20input%20list%20was%20actually%20just%20a%20'property'%20like%20foo=%7Ba%7Cb%7Cc%7D%5Cn%5Ct%5Ct%5Ct//if(!result)%20debugger;%5Cn%5Ct%5Ct%5Ctreturn%20result;%5Cn%5Ct%5Ct%7D%5Cn%5Ct%5Ctleaf%20=%20result;%5Cn%5Ct%7D%5Cn%5Ct%5Cn//%20You%20can%20learn%20JavaScript%20here:%5Cn//%20https://www.codecademy.com/learn/javascript%22,%22imports%22:%5B%5D,%22lastEditTime%22:1691554935487,%22found%22:true%7D,%7B%22name%22:%22tabbed-comments-plugin-v1%22,%22modelText%22:%22commentsPlugin%20=%20%7Bimport:comments-plugin%7D%5CngenerateText%20=%20%7Bimport:ai-text-plugin%7D%5CndefaultCustomEmojis%20=%20%7Bimport:huge-emoji-list%7D%5Cn%5Cn//%20See%20exampleOptions%20below%20for%20an%20example%20of%20these%20options:%5Cn//%20%20%20channels:%20(A%20list%20of%20channel%20names,%20optionally%20with%20the%20comment%20options%20under%20each%20channel%20name)%5Cn//%20%20%20allowBots:%20true/false%20(Default%20is%20true,%20except%20on%20default%20channel%20and%20'general'%20channel.%20You%20can%20also%20disable/enable%20bots%20on%20a%20per-channel%20basis%20by%20setting%20allowBots%20to%20true/false%20under%20the%20channel%20name.)%5Cn//%20%20%20defaultCommentsOptions:%20(See%20perchance.org/comments-plugin%20for%20all%20options)%5Cn//%20%20%20fillHeight:%20true/value%20(By%20default%20its%20height%20is%20based%20on%20the%20screen%20height.%20set%20this%20option%20to%20true%20to%20make%20it%20expand%20to%20full%20height%20of%20its%20container)%5Cn%5CnexampleOptions%5Cn%20%20defaultCommentsOptions%20//%20see%20perchance.org/comments-plugin%20for%20all%20available%20options%5Cn%20%20%20%20adminFlair%20=%20%F0%9F%92%8EOWNER%F0%9F%92%8E%20//%20this%20option%20will%20get%20applied%20to%20*all*%20channels%20below.%5Cn%20%20channels%20%5Cn%20%20%20%20general%5Cn%20%20%20%20%20%20label%20=%20General%5Cn%20%20%20%20chat1%20//%20i've%20set%20messageBubbleStyle%20here%20to%20give%20an%20example%20showing%20that%20each%20channel%20can%20have%20any%20of%20the%20channel%20options%20that%20are%20explained%20in%20perchance.org/comments-plugin%5Cn%20%20%20%20%20%20label%20=%20Room%201%5Cn%20%20%20%20%20%20messageBubbleStyle%20=%20background:pink;%20border:2px%20dotted%20red;%20color:black;%5Cn%20%20%20%20chat2%5Cn%20%20%20%20%20%20label%20=%20Room%202%5Cn%20%20%20%20%20%20allowBots%20=%20false%20//%20disallows%20'speak%20via%20character'%20for%20this%20channel%5Cn%20%20%20%20test3%5Cn%20%20%20%20test4%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5Cn%5CntabbedCommentsPlugin%20=%20%5B$output%5D%5Cn%5Cn$output(opts)%20=%3E%5Cn%20%20let%20commentsChannels%20=%20opts.channels;%5Cn%20%20let%20defaultChannelOptions%20=%20opts.defaultChannelOptions%20%7C%7C%20%7B%7D;%5Cn%20%20let%20outerCtn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%5Cn%20%20let%20globalFnsId%20=%20%5C%22a%5C%22+Math.random().toString(16).slice(2);%5Cn%20%20%5Cn%20%20let%20minHeight%20=%20defaultChannelOptions.height;%5Cn%20%20if(!minHeight)%20minHeight%20=%20300;%5Cn%20%20if(typeof%20minHeight%20===%20%5C%22number%5C%22)%20minHeight%20+=%20%5C%22px%5C%22;%5Cn%20%20%5Cn%20%20%5Cn%20%20outerCtn.className%20=%20%5C%22tabbed-comments-plugin-outer-ctn%5C%22;%5Cn%20%20outerCtn.style.cssText%20=%20%60text-align:center;%20$%7Bopts.fillHeight%20?%20%5C%22height:100%25;%5C%22%20:%20%5C%22%5C%22%7D;%20container-type:inline-size;%60;%5Cn%20%20outerCtn.innerHTML%20=%20%60%3Cdiv%20style=%5C%22display:flex;%20justify-content:center;%20align-items:center;%20$%7Bopts.fillHeight%20?%20%5C%22height:100%25;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E%5Cn%20%20%20%20%3Cdiv%20class=%5C%22tabbed-comments-ctn-left%20tabbed-comments-plugin-ctn%5C%22%20style=%5C%22height:min(70vh,%20600px);%20min-height:$%7BminHeight%7D;%20justify-content:center;%20align-items:center;%20flex-grow:1;%20min-width:%200;%20$%7Bopts.fillHeight%20?%20%5C%22height:100%25;max-height:100%25;min-height:100%25;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E%3C/div%3E%5Cn%20%20%20%20%3Cdiv%20class=%5C%22tabbed-comments-ctn-middle%20tabbed-comments-plugin-ctn%5C%22%20style=%5C%22height:min(70vh,%20600px);%20min-height:$%7BminHeight%7D;%20width:100%25;%20max-width:min(800px,%20100vw);%20flex-grow:%201;%20min-width:%200;%20$%7Bopts.fillHeight%20?%20%5C%22height:100%25;max-height:100%25;min-height:100%25;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E%3C/div%3E%5Cn%20%20%20%20%3Cdiv%20class=%5C%22tabbed-comments-ctn-right%20tabbed-comments-plugin-ctn%5C%22%20style=%5C%22height:min(70vh,%20600px);%20min-height:$%7BminHeight%7D;%20justify-content:center;%20align-items:center;%20flex-grow:1;%20min-width:%200;%20$%7Bopts.fillHeight%20?%20%5C%22height:100%25;max-height:100%25;min-height:100%25;%5C%22%20:%20%5C%22%5C%22%7D%5C%22%3E%3C/div%3E%5Cn%20%20%3C/div%3E%5Cn%20%20%3Cbutton%20onclick=%5C%22this.closest('.tabbed-comments-plugin-outer-ctn').querySelector('.tabbed-comments-auto-comment-ctn').style.display='flex';%20this.style.display='none';%5C%22%20class=%5C%22tabbed-comments-show-auto-comment-area-btn%5C%22%20style=%5C%22font-size:80%25;%20margin-top:0.75rem;%5C%22%3E%F0%9F%A7%9D%20speak%20via%20character%3C/button%3E%5Cn%20%20%3Cdiv%20class=%5C%22tabbed-comments-auto-comment-ctn%5C%22%20style=%5C%22display:none;%20flex-direction:column;%20border:1px%20solid%20grey;%20border-radius:2px;%20width:400px;%20max-width:98%25;%20margin:0%20auto;%20margin-top:1.5rem;%5C%22%3E%5Cn%20%20%20%20%3Cdiv%20style=%5C%22display:%20flex;%20align-items:%20center;%20justify-content:%20center;%20padding:0.25rem;%20width:100%25;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20style=%5C%22%20display:%20flex;%20align-items:%20center;%20justify-content:%20center;%20flex-direction:%20column;%20gap:0.25rem;%20width:100%25;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%20gap:0.25rem;%20width:100%25;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cbutton%20class=%5C%22tabbed-comments-auto-comment-char-btn%5C%22%20onclick=%5C%22window.__$%7BglobalFnsId%7D_tabbedCommentsPluginAutoComment(%7Bname:this.closest('.tabbed-comments-plugin-outer-ctn').querySelector('.tabbed-comments-auto-comment-char-name').value,%20description:this.closest('.tabbed-comments-plugin-outer-ctn').querySelector('.tabbed-comments-auto-comment-char-description').value%7D)%5C%22%20style=%5C%22flex-grow:1;%20min-width:max-content;%5C%22%3E%F0%9F%A7%9D%20write%20as%20character%3C/button%3E%5Cn%20%20%20%20%20%20%20%20%20%20%3Cselect%20class=%5C%22tabbed-comments-auto-comment-char-select%5C%22%20onchange=%5C%22window.__$%7BglobalFnsId%7D_tabbedCommentsPluginSwitchToAutoCommentCharByIndex(this.value)%5C%22%20style=%5C%22max-width:90px;%5C%22%3E%3C/select%3E%5Cn%20%20%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%20%20%20%20%3Cinput%20class=%5C%22tabbed-comments-auto-comment-char-name%5C%22%20oninput=%5C%22window.__$%7BglobalFnsId%7D_tabbedCommentsPluginSaveAutoCommentCharInfo()%5C%22%20placeholder=%5C%22Character%20name...%5C%22%20style=%5C%22width:100%25;%5C%22%3E%5Cn%20%20%20%20%20%20%20%20%3Ctextarea%20class=%5C%22tabbed-comments-auto-comment-char-description%5C%22%20oninput=%5C%22window.__$%7BglobalFnsId%7D_tabbedCommentsPluginSaveAutoCommentCharInfo()%5C%22%20placeholder=%5C%22Character%20description...%5C%22%20style=%5C%22width:100%25;%20height:100px;%20z-index:5;%5C%22%3E%3C/textarea%3E%5Cn%20%20%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%20%20%3Cdiv%20style=%5C%22display:flex;%20justify-content:center;%20align-items:center;%20border-top:1px%20solid%20grey;%20padding:0.25rem;%5C%22%3E%5Cn%20%20%20%20%20%20%3Cinput%20class=%5C%22tabbed-comments-auto-comment-auto-send-checkbox%5C%22%20onchange=%5C%22localStorage.__tabbedCommentsAutoCommentAutoSendCheckboxValue=this.checked?'1':'';%20%5C%22%20style=%5C%22cursor:pointer;%5C%22%20type=%5C%22checkbox%5C%22%3E%5Cn%20%20%20%20%20%20%3Cdiv%20onclick=%5C%22this.closest('.tabbed-comments-plugin-outer-ctn').querySelector('.tabbed-comments-auto-comment-auto-send-checkbox').click()%5C%22%20style=%5C%22margin-left:0.25rem;%20cursor:pointer;%20user-select:none;%5C%22%3Eauto-send?%3C/div%3E%5Cn%20%20%20%20%3C/div%3E%5Cn%20%20%3C/div%3E%60;%5Cn%20%20%5Cn%20%20let%20rightCtn%20=%20outerCtn.querySelector('.tabbed-comments-ctn-right');%5Cn%20%20let%20middleCtn%20=%20outerCtn.querySelector('.tabbed-comments-ctn-middle');%5Cn%20%20let%20leftCtn%20=%20outerCtn.querySelector('.tabbed-comments-ctn-left');%5Cn%20%20%5Cn%20%20let%20showAutoCommentAreaBtn%20=%20outerCtn.querySelector('.tabbed-comments-show-auto-comment-area-btn');%5Cn%20%20let%20autoCommentCtn%20=%20outerCtn.querySelector('.tabbed-comments-auto-comment-ctn');%5Cn%20%20let%20autoCommentCharBtn%20=%20outerCtn.querySelector('.tabbed-comments-auto-comment-char-btn');%5Cn%20%20let%20autoCommentCharSelectEl%20=%20outerCtn.querySelector('.tabbed-comments-auto-comment-char-select');%5Cn%20%20let%20autoCommentCharNameEl%20=%20outerCtn.querySelector('.tabbed-comments-auto-comment-char-name');%5Cn%20%20let%20autoCommentCharNameDescriptionEl%20=%20outerCtn.querySelector('.tabbed-comments-auto-comment-char-description');%5Cn%20%20let%20autoCommentAutoSendCheckboxEl%20=%20outerCtn.querySelector('.tabbed-comments-auto-comment-auto-send-checkbox');%5Cn%20%20%5Cn%20%20let%20middleCtnCurrentlyShownCommentsChannelName;%5Cn%20%20%5Cn%20%20let%20sidePanelObjs%20=%20new%20Set();%5Cn%20%20let%20middlePanelObj;%5Cn%20%20let%20middleCtnChannelNameToObj%20=%20%7B%7D;%5Cn%20%20%5Cn%20%20function%20updateColorScheme()%20%7B%5Cn%20%20%20%20let%20systemColorScheme%20=%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22dark%5C%22%20:%20%5C%22light%5C%22;%5Cn%20%20%20%20if(localStorage.forceColorScheme%20===%20%5C%22dark%5C%22%20%7C%7C%20(!localStorage.forceColorScheme%20&&%20systemColorScheme%20===%20%5C%22dark%5C%22))%20%7B%5Cn%20%20%20%20%20%20outerCtn.style.setProperty('--tabbed-comments-plugin-text-color',%20'#efefef');%5Cn%20%20%20%20%20%20outerCtn.style.setProperty('--tabbed-comments-plugin-box-color',%20'#2a2a2a');%5Cn%20%20%20%20%20%20outerCtn.style.setProperty('--tabbed-comments-plugin-active-comment-channel-tab-color',%20'#3f3f3f');%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20outerCtn.style.setProperty('--tabbed-comments-plugin-text-color',%20'#222');%5Cn%20%20%20%20%20%20outerCtn.style.setProperty('--tabbed-comments-plugin-box-color',%20'#ebebeb');%5Cn%20%20%20%20%20%20outerCtn.style.setProperty('--tabbed-comments-plugin-active-comment-channel-tab-color',%20'#c6c6c6');%5Cn%20%20%20%20%7D%5Cn%20%20%20%20outerCtn.querySelectorAll(%5C%22%5Bdata-tabbed-comments-direct-parent-of-comments-plugin-putput='1'%5D%5C%22).forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20commentOptions%20=%20el.__commentOptionsUsed;%5Cn%20%20%20%20%20%20commentOptions.forceColorScheme%20=%20defaultChannelOptions.forceColorScheme%20??%20localStorage.forceColorScheme%20??%20null%5Cn%20%20%20%20%20%20el.innerHTML%20=%20commentsPlugin(commentOptions);%5Cn%20%20%20%20%7D);%5Cn%20%20%7D%5Cn%20%20updateColorScheme();%5Cn%20%20%5Cn%20%20let%20colorSchemeMediaQuery%20=%20window.matchMedia(%5C%22(prefers-color-scheme:%20dark)%5C%22);%20%5Cn%20%20colorSchemeMediaQuery.addEventListener(%5C%22change%5C%22,%20updateColorScheme);%5Cn%20%20%5Cn%20%20let%20localStorageChangeHandler%20=%20function(e)%20%7B%20%5Cn%20%20%20%20if(!document.body.contains(outerCtn))%20%7B%20//%20prevent%20memory%20leak%5Cn%20%20%20%20%20%20window.removeEventListener(%5C%22storage%5C%22,%20localStorageChangeHandler);%5Cn%20%20%20%20%20%20colorSchemeMediaQuery.removeEventListener(%5C%22change%5C%22,%20updateColorScheme);%5Cn%20%20%20%20%20%20return;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(e.key%20===%20%5C%22forceColorScheme%5C%22)%20%7B%5Cn%20%20%20%20%20%20updateColorScheme();%5Cn%20%20%20%20%7D%5Cn%20%20%7D;%5Cn%20%20window.addEventListener(%5C%22storage%5C%22,%20localStorageChangeHandler);%5Cn%20%20let%20storageListenerInterval%20=%20setInterval(()%20=%3E%20%7B%5Cn%20%20%20%20if(!document.body.contains(outerCtn))%20%7B%20//%20prevent%20memory%20leak%5Cn%20%20%20%20%20%20window.removeEventListener(%5C%22storage%5C%22,%20localStorageChangeHandler);%5Cn%20%20%20%20%20%20colorSchemeMediaQuery.removeEventListener(%5C%22change%5C%22,%20updateColorScheme);%5Cn%20%20%20%20%20%20clearInterval(storageListenerInterval);%5Cn%20%20%20%20%7D%5Cn%20%20%7D,%201000*30);%5Cn%20%20%5Cn%20%20function%20updateMiddleTabModuleWidth()%20%7B%5Cn%20%20%20%20if(leftCtn.querySelector(%5C%22.tabbed-comments-plugin-add-tabs-module-button%5C%22)%20&&%20rightCtn.querySelector(%5C%22.tabbed-comments-plugin-add-tabs-module-button%5C%22))%20%7B%5Cn%20%20%20%20%20%20//%20both%20side%20modules%20are%20closed,%20so%20prevent%20it%20from%20getting%20too%20big:%5Cn%20%20%20%20%20%20middleCtn.style.maxWidth%20=%20%5C%22min(800px,%20100vw)%5C%22;%5Cn%20%20%20%20%20%20leftCtn.style.width%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20middleCtn.style.width%20=%20%5C%22100%25%5C%22;%5Cn%20%20%20%20%20%20rightCtn.style.width%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20//%20at%20least%20one%20is%20open,%20so%20make%20them%20take%20up%20thirds%5Cn%20%20%20%20%20%20middleCtn.style.maxWidth%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20leftCtn.style.width%20=%20%5C%2233.3%25%5C%22;%5Cn%20%20%20%20%20%20middleCtn.style.width%20=%20%5C%2233.3%25%5C%22;%5Cn%20%20%20%20%20%20rightCtn.style.width%20=%20%5C%2233.3%25%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(!opts.fillHeight)%20%7B%5Cn%20%20%20%20%20%20if(leftCtn.querySelector(%5C%22.tabbed-comments-plugin-add-tabs-module-button%5C%22)%20%7C%7C%20rightCtn.querySelector(%5C%22.tabbed-comments-plugin-add-tabs-module-button%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20//%20at%20least%20one%20is%20closed,%20so%20restore%20normal%20height%5Cn%20%20%20%20%20%20%20%20middleCtn.style.minHeight%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20leftCtn.style.minHeight%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20rightCtn.style.minHeight%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20//%20both%20side%20panels%20are%20open,%20so%20make%20the%20whole%20section%20taller%5Cn%20%20%20%20%20%20%20%20middleCtn.style.minHeight%20=%20%5C%2290vh%5C%22;%5Cn%20%20%20%20%20%20%20%20leftCtn.style.minHeight%20=%20%5C%2290vh%5C%22;%5Cn%20%20%20%20%20%20%20%20rightCtn.style.minHeight%20=%20%5C%2290vh%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20function%20initSideButton(side)%20%7B%5Cn%20%20%20%20let%20buttonHtml%20=%20%60%3Cbutton%20class=%5C%22tabbed-comments-plugin-add-tabs-module-button%5C%22%20style=%5C%22margin-$%7Bside===%5C%22left%5C%22%20?%20%5C%22right%5C%22%20:%20%5C%22left%5C%22%7D:0.5rem;%20padding:1px%206px;%5C%22%3E+%3C/button%3E%60;%5Cn%20%20%20%20let%20ctn%20=%20outerCtn.querySelector(%5C%22.tabbed-comments-ctn-%5C%22+side);%5Cn%20%20%20%20ctn.innerHTML%20=%20buttonHtml;%5Cn%20%20%20%20ctn.querySelector(%5C%22button%5C%22).onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20ctn.innerHTML%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20let%20obj%20=%20createTabbedCommentsPanel(%7B%5Cn%20%20%20%20%20%20%20%20addCloseButton:true,%5Cn%20%20%20%20%20%20%20%20onClose:%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20sidePanelObjs.delete(obj);%5Cn%20%20%20%20%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20initSideButton(side);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20updateMiddleTabModuleWidth();%5Cn%20%20%20%20%20%20%20%20%20%20%7D,%2010);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20ctn.appendChild(obj.element);%5Cn%20%20%20%20%20%20sidePanelObjs.add(obj);%5Cn%20%20%20%20%20%20updateMiddleTabModuleWidth();%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%20%20initSideButton(%5C%22left%5C%22);%5Cn%20%20initSideButton(%5C%22right%5C%22);%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20/////////////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20CHANNEL%20MENTIONS,%20SEEN/UNSEEN%20COUNTING,%20ETC.%20%20%20%20//%5Cn%20%20/////////////////////////////////////////////////////////%5Cn%20%20let%20unseenCommentCountByChannel%20=%20%7B%7D;%5Cn%20%20function%20updateUnseenCountHtml(channel)%20%7B%5Cn%20%20%20%20let%20count%20=%20unseenCommentCountByChannel%5Bchannel%5D;%5Cn%20%20%20%20for(let%20tabCtn%20of%20%5B...outerCtn.querySelectorAll(%5C%22.tabbed-comments-plugin-ctn%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20let%20countEl%20=%20tabCtn.querySelector(%60.tabbed-comments-plugin-tab%5Bdata-channel='$%7Bchannel%7D'%5D%20.tabbed-comments-plugin-unseen-count%60);%5Cn%20%20%20%20%20%20if(countEl)%20%7B%20//%20since%20this%20tabCtn%20may%20not%20have%20that%20particular%20tab%5Cn%20%20%20%20%20%20%20%20countEl.textContent%20=%20count;%5Cn%20%20%20%20%20%20%20%20countEl.style.background%20=%20(count%20%3E%200)%20?%20%5C%22#ab0e0e%5C%22%20:%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20countEl.style.display%20=%20(count%20%3E%200)%20?%20%5C%22inline%5C%22%20:%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20let%20temporaryMentionedChannels%20=%20new%20Set();%5Cn%20%20let%20knownMessageIdsByChannel%20=%20%7B%7D;%5Cn%20%20let%20lastCurrentUserCommentTime%20=%20null;%5Cn%20%20function%20commentsPluginOnLoadHandler(comments)%20%7B%5Cn%20%20%20%20for(let%20comment%20of%20comments)%20%7B%5Cn%20%20%20%20%20%20processCommentForUnseenCounts(comment);%5Cn%20%20%20%20%20%20if(comment.byCurrentUser)%20%7B%5Cn%20%20%20%20%20%20%20%20lastCurrentUserCommentTime%20=%20Date.now();%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20if(comments%5B0%5D)%20unseenCommentCountByChannel%5Bcomments%5B0%5D.channel%5D%20=%200;%20//%20reset%20unseen%20count%20since%20above%20%60processCommentForUnseenCounts%60%20has%20incremented%20it%5Cn%20%20%20%20processCommentsForTempChannels(comments.slice(-30));%5Cn%20%20%7D%5Cn%20%20function%20commentsPluginOnCommentHandler(comment)%20%7B%5Cn%20%20%20%20processCommentForUnseenCounts(comment);%5Cn%20%20%20%20if(comment.byCurrentUser)%20%7B%5Cn%20%20%20%20%20%20lastCurrentUserCommentTime%20=%20Date.now();%5Cn%20%20%20%20%7D%5Cn%20%20%20%20processCommentsForTempChannels(%5Bcomment%5D);%5Cn%20%20%7D%5Cn%20%20function%20processCommentForUnseenCounts(comment)%20%7B%5Cn%20%20%20%20//%20console.log(%5C%22new%20comment:%5C%22,%20comment);%5Cn%20%20%20%20let%20channel%20=%20comment.channel;%5Cn%20%20%20%20//%20initialize%20if%20we%20haven't%20yet:%5Cn%20%20%20%20if(!knownMessageIdsByChannel%5Bcomment.channel%5D)%20knownMessageIdsByChannel%5Bchannel%5D%20=%20new%20Set();%5Cn%5Cn%20%20%20%20//%20increment%20the%20unseen%20count%20if%20we%20haven't%20seen%20this%20comment%20id%20before:%5Cn%20%20%20%20if(!knownMessageIdsByChannel%5Bchannel%5D.has(comment.id))%20%7B%5Cn%20%20%20%20%20%20knownMessageIdsByChannel%5Bchannel%5D.add(comment.id);%5Cn%20%20%20%20%20%20unseenCommentCountByChannel%5Bchannel%5D%20=%20(unseenCommentCountByChannel%5Bchannel%5D%20%7C%7C%200)%20+%201;%5Cn%5Cn%20%20%20%20%20%20let%20tabIsVisible%20=%20false;%20//%20check%20if%20it's%20visible%20in%20any%20of%20the%20tabbedCommentsCtn%20elements%5Cn%20%20%20%20%20%20for(let%20tabCtn%20of%20%5B...outerCtn.querySelectorAll(%5C%22.tabbed-comments-plugin-ctn%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20tabContentEl%20=%20tabCtn.querySelector(%60.tabbed-comments-plugin-content%5Bdata-channel='$%7Bchannel%7D'%5D%60);%5Cn%20%20%20%20%20%20%20%20if(tabContentEl%20&&%20tabContentEl.offsetHeight%20!==%200)%20tabIsVisible%20=%20true;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(tabIsVisible)%20%7B%20//%20set%20unseen%20count%20to%200%20if%20tab%20is%20visible%5Cn%20%20%20%20%20%20%20%20unseenCommentCountByChannel%5Bchannel%5D%20=%200;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20updateUnseenCountHtml(channel);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20function%20attachEventsToTemporaryMentionedChannelTab(tabEl,%20channelName)%20%7B%5Cn%20%20%20%20tabEl.addEventListener(%5C%22click%5C%22,%20function()%20%7B%5Cn%20%20%20%20%20%20temporaryMentionedChannels.delete(channelName);%5Cn%20%20%20%20%20%20for(let%20t%20of%20%5B...outerCtn.querySelectorAll(%60.tabbed-comments-plugin-ctn%20.tabbed-comments-plugin-header%20.tabbed-comments-plugin-tab%5Bdata-channel='$%7BchannelName%7D'%5D%60)%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20t.dataset.tabbedCommentsPluginIsTemporaryMentionedChannel%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20window.addEventListener(%5C%22beforeunload%5C%22,%20function()%20%7B%5Cn%20%20%20%20%20%20if(tabEl.dataset.tabbedCommentsPluginIsTemporaryMentionedChannel)%20%7B%5Cn%20%20%20%20%20%20%20%20temporaryMentionedChannels.delete(channelName);%5Cn%20%20%20%20%20%20%20%20for(let%20obj%20of%20%5B...sidePanelObjs,%20middlePanelObj%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20obj.deleteCommentsChannel(channelName);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20//%20to%20rate%20limit%20mentions:%5Cn%20%20let%20userIdToMentionedChannelsInLast2Minutes%20=%20%7B%7D;%5Cn%20%20setInterval(()%20=%3E%20%7B%5Cn%20%20%20%20userIdToMentionedChannelsInLast2Minutes%20=%20%7B%7D;%5Cn%20%20%7D,%201000*60*2);%5Cn%20%20%5Cn%20%20function%20processCommentsForTempChannels(comments)%20%7B%5Cn%20%20%20%20for(let%20comment%20of%20comments)%20%7B%5Cn%20%20%20%20%20%20let%20mentionedChannelName%20=%20comment.message.match(/(%5C%5Cs%7C%5E)#%5Ba-z0-9%5C%5C-%5D+(%5C%5Cs%7C$)/g)?.%5B0%5D;%5Cn%20%20%20%20%20%20if(mentionedChannelName%20&&%20!/%5E%5B0-9%5D+$/.test(mentionedChannelName))%20%7B%20//%20if%20it's%20all%20numbers,%20ignore%5Cn%20%20%20%20%20%20%20%20mentionedChannelName%20=%20mentionedChannelName.trim().replace(/%5E#/,%20%5C%22%5C%22).trim();%20//%20remove%20the%20hash%20from%20the%20start%20and%20whitespace%20from%20start/end%5Cn%20%20%20%20%20%20%20%20if(mentionedChannelName%20===%20%5C%22feedback%5C%22)%20continue;%5Cn%20%20%20%20%20%20%20%20if(!userIdToMentionedChannelsInLast2Minutes%5Bcomment.user.id%5D)%20userIdToMentionedChannelsInLast2Minutes%5Bcomment.user.id%5D%20=%20%5B%5D;%5Cn%20%20%20%20%20%20%20%20if(userIdToMentionedChannelsInLast2Minutes%5Bcomment.user.id%5D.length%20%3E=%2010)%20continue;%5Cn%20%20%20%20%20%20%20%20//%20add%20it%20as%20a%20temporary%20channel%20which%20self-deletes%20after%202%20minutes.%5Cn%20%20%20%20%20%20%20%20//%20it%20upgrades%20to%20a%20real%20one%20when%20clicked.%5Cn%20%20%20%20%20%20%20%20if(middlePanelObj)%20%7B%20//%20%3C--%20just%20in%20case%20somehow%20hasn't%20initialized%20yet,%20or%20whatever%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20//%20If%20they've%20got%20the%20tab%20*somewhere*%20(e.g.%20in%20side%20module),%20then%20we%20don't%20add%20it%20as%20a%20temporary%20channel.%5Cn%20%20%20%20%20%20%20%20%20%20let%20alreadyExistsSomewhere%20=%20!!outerCtn.querySelector(%60.tabbed-comments-plugin-ctn%20.tabbed-comments-plugin-header%20.tabbed-comments-plugin-tab%5Bdata-channel='$%7BmentionedChannelName%7D'%5D%60);%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20let%20%7B%20tab,%20alreadyExisted%20%7D%20=%20middlePanelObj.addCommentsChannel(mentionedChannelName);%5Cn%20%20%20%20%20%20%20%20%20%20userIdToMentionedChannelsInLast2Minutes%5Bcomment.user.id%5D.push(mentionedChannelName);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20if(!alreadyExisted%20&&%20!alreadyExistsSomewhere)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20temporaryMentionedChannels.add(mentionedChannelName);%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20newTabs%20=%20%5B%5D;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20newTabs.push(tab);%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%20//%20because%20it's%20new%20code%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20for(let%20obj%20of%20sidePanelObjs)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20let%20%7B%20tab%20%7D%20=%20obj.addCommentsChannel(mentionedChannelName);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20newTabs.push(tab);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch(e)%20%7B%20console.error(e);%20%7D%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20for(let%20newTab%20of%20newTabs)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20newTab.dataset.tabbedCommentsPluginIsTemporaryMentionedChannel%20=%20%5C%221%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20attachEventsToTemporaryMentionedChannelTab(newTab,%20mentionedChannelName);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20//%20make%20its%20background%20blink%20for%20a%20couple%20of%20seconds:%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20blinkCount%20=%200;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20let%20blinkInterval%20=%20setInterval(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20tab.style.background%20=%20blinkCount%252===0%20?%20%5C%22#043a9b%5C%22%20:%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20blinkCount++;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(blinkCount%20%3E%205)%20clearInterval(blinkInterval);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D,%20300);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20temporaryMentionedChannels.delete(mentionedChannelName);%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(document.body.contains(tab)%20&&%20tab.dataset.tabbedCommentsPluginIsTemporaryMentionedChannel)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for(let%20obj%20of%20%5B...sidePanelObjs,%20middlePanelObj%5D)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20obj.deleteCommentsChannel(mentionedChannelName);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D,%201000*40);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20/////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20%20%20BOT/AUTO-COMMENT%20STUFF%20%20%20%20%20%20%20%20%20%20//%5Cn%20%20/////////////////////////////////////////////%5Cn%20%20let%20autoCommentChars%20=%20%5B%5D;%5Cn%20%20if(localStorage.autoCommentChars)%20%7B%5Cn%20%20%20%20try%20%7B%20autoCommentChars%20=%20JSON.parse(localStorage.autoCommentChars);%20%7D%20catch(e)%20%7B%20alert(e);%20%7D%5Cn%20%20%20%20autoCommentChars%20=%20autoCommentChars.filter(c%20=%3E%20c%20&&%20c.name);%5Cn%20%20%7D%5Cn%20%20function%20getAutoCommentNameFromNickname(nickname)%20%7B%5Cn%20%20%20%20let%20nicknameWithoutNonNameCharacters%20=%20nickname.replace(/%5B%5C%5Cn%5C%5C-:%7C()!%7B%7D*%5D/g,%20%5C%22%5C%22).replace(/(?!%5B*#0-9%5D+)%5B%5C%5Cp%7BEmoji%7D%5C%5Cp%7BEmoji_Modifier%7D%5C%5Cp%7BEmoji_Component%7D%5C%5Cp%7BEmoji_Modifier_Base%7D%5C%5Cp%7BEmoji_Presentation%7D%5D/gu,%20'');%5Cn%20%20%20%20let%20words%20=%20nicknameWithoutNonNameCharacters.split(/%5B%7C/%20%5C%5C-%7D)%5D/g).map(w%20=%3E%20w.trim()).filter(w%20=%3E%20w);%5Cn%20%20%20%20while(words.slice(0,%20-1).join(%5C%22_%5C%22).length%20%3E%2025)%20words.pop();%20//%20we%20remove%20the%20last%20one%20for%20the%20length%20check%20in%20case%20it's%20a%20name%20like%20One%20Supercalifragilisticexpialidocious%20-%20better%20for%20userTag%20to%20be%20%5C%22OneSupercalif%5C%22%20than%20%5C%22One%5C%22%5Cn%20%20%20%20if(words.slice(0,%20-1).join(%5C%22_%5C%22).length%20%3E%2015)%20words.pop();%20//%20we%20probably%20don't%20need%20the%20last%20word%20if%20all%20the%20earlier%20ones%20are%20over%2015%20characters%5Cn%20%20%20%20let%20name%20=%20words.join(%5C%22_%5C%22).trim().toLowerCase();%5Cn%20%20%20%20return%20name%20+%20(nickname.length%20%3E%2025%20?%20%5C%22%E2%80%A6%5C%22%20:%20%5C%22%5C%22);%5Cn%20%20%7D%5Cn%20%20window%5B%60__$%7BglobalFnsId%7D_tabbedCommentsPluginAutoComment%60%5D%20=%20function(character)%20%7B%5Cn%20%20%20%20let%20commentsBox%20=%20middleCtnChannelNameToObj%5BmiddleCtnCurrentlyShownCommentsChannelName%5D;%5Cn%20%20%20%20if(commentsBox.channel%20===%20%5C%22n/o/-/a/i%5C%22.replaceAll(%5C%22/%5C%22,%20%5C%22%5C%22))%20return;%5Cn%5Cn%20%20%20%20let%20startTime%20=%20Date.now();%5Cn%20%20%20%20autoCommentCharBtn.disabled%20=%20true;%5Cn%20%20%20%20autoCommentCharBtn.textContent%20=%20%5C%22%E2%8F%B3%20just%20a%20sec...%5C%22;%5Cn%5Cn%20%20%20%20let%20currentUser%20=%20commentsBox.comments.find(c%20=%3E%20c.byCurrentUser)?.user;%5Cn%20%20%20%20let%20comments%20=%20commentsBox.comments.slice(-500).map(c%20=%3E%20%7B%5Cn%20%20%20%20%20%20let%20userTag%20=%20c.user.visualId.toUpperCase();%5Cn%20%20%20%20%20%20if(c.user.nickname)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20name%20=%20getAutoCommentNameFromNickname(c.user.nickname);%5Cn%20%20%20%20%20%20%20%20if(name)%20userTag%20=%20%60$%7Bc.user.visualId.toUpperCase()%7D($%7Bname%7D)%60%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20return%20%60$%7BuserTag%7D:%20$%7Bc.message.trim().replace(/%5C%5Cn%7B3,%7D/g,%20%5C%22%5C%5Cn%5C%5Cn%5C%22)%7D%60;%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20while(comments.join(%5C%22%5C%22).length%20%3E%2010000)%20comments.shift();%5Cn%5Cn%20%20%20%20let%20nicknameOverride%20=%20character.name.replace(/%5C%5Cs+/g,%20%5C%22%20%5C%22).slice(0,%2050);%5Cn%20%20%20%20let%20currentUserVisualId%20=%20currentUser%20?%20currentUser.visualId.toUpperCase()%20:%20%5C%22U7OP%5C%22;%20//%20just%20use%20a%20random/arbitrary%20tag%20if%20we%20don't%20have%20the%20user's%20actual%20one%20(we'll%20get%20it%20once%20they've%20made%20their%20first%20comment)%5Cn%20%20%20%20let%20respondingUserTag%20=%20%60$%7BcurrentUserVisualId%7D($%7Bcharacter.name%7D)%60;%5Cn%20%20%20%20let%20characterDescription%20=%20character.description.replace(/%5C%5Cn/g,%20%5C%22%20%5C%22).slice(0,%205000);%5Cn%5Cn%20%20%20%20let%20newCommentText%20=%20%5C%22%5C%22;%20//commentsBox.inputText.trim().replace(/%5C%5Cn/g,%20%5C%22%20%5C%22).split(%5C%22%20%5C%22).slice(0,%203);%5Cn%20%20%20%20let%20obj%20=%20generateText(%7B%20//%20NOTE:%20perchance%20removes%20all%20leading%20spaces%20from%20lines,%20so%20we%20don't%20need%20to%20dedent%20the%20lines%20below%5Cn%20%20%20%20%20%20instruction:%20%60%5Cn%20%20%20%20%20%20Your%20task%20is%20to%20write%20the%20next%205%20messages%20in%20the%20following%20chat/roleplay.%20Keep%20it%20interesting.%20Stay%20in%20character%20based%20on%20the%20previous%20messages.%20You%20are%20**NOT**%20an%20AI.%20You%20are%20writing%20as%20a%20regular%20chat%20participant,%20not%20as%20an%20AI.%20When%20writing%20$%7BrespondingUserTag%7D's%20messages,%20you%20can%20ignore%20the%20off-topic/OOC/spam/commentary%20chat%20messages%20and%20focus%20on%20the%20roleplay%20messages%20that%20are%20actually%20a%20part%20of%20the%20story.%20Predict%20what%20the%20characters%20in%20this%20chat/roleplay%20are%20most%20likely%20to%20say%20next,%20and%20then%20write%20it%20**EXACTLY**%20as%20the%20chat%20participants%20would,%20based%20on%20what%20they've%20previously%20said.%5Cn%20%20%20%20%20%20IMPORTANT:%20Here's%20a%20description%20of%20$%7BrespondingUserTag%7D:%20$%7BcharacterDescription%7D.%5Cn%5Cn%20%20%20%20%20%20%3CMESSAGES%3E%5Cn%20%20%20%20%20%20$%7Bcomments.slice(0,%20-4).join(%5C%22%5C%5Cn%5C%5Cn---%5C%5Cn%5C%5Cn%5C%22).trim()%20%7C%7C%20%60(None%20yet.%20Start%20the%20chat/roleplay%20with%20an%20interesting%20starter%20message.)%60%7D%5Cn%20%20%20%20%20%20%3C/MESSAGES%3E%5Cn%5Cn%20%20%20%20%20%20Again,%20your%20task%20is%20to%20write%20the%20next%205%20messages.%20Make%20sure%20your%20writing%20is%20interesting,%20authentic,%20descriptive,%20natural,%20engaging,%20and%20creative.%20Create%20a%20captivating%20and%20genuinely%20fascinating%20roleplay,%20and%20always%20stay%20in-character%20and%20write%20responses%20based%20on%20the%20previous%20chat%20context.%20Don't%20be%20boring.%20Keep%20the%20roleplay%20flowing!%5Cn%20%20%20%20%20%20As%20a%20reminder%20about%20the%20$%7BrespondingUserTag%7D%20character:%20$%7BcharacterDescription.slice(0,%20500)%20+%20(characterDescription.length%20%3E%201000%20?%20%5C%22...%5C%22%20:%20%5C%22%5C%22)%7D%5Cn%20%20%20%20%20%20%60.trim(),%5Cn%20%20%20%20%20%20startWith:%20comments.slice(-4).join(%5C%22%5C%5Cn%5C%5Cn---%5C%5Cn%5C%5Cn%5C%22)+%5C%22%5C%5Cn%5C%5Cn---%5C%5Cn%5C%5Cn%5C%22+respondingUserTag+%5C%22:%20%5C%22+newCommentText,%5Cn%20%20%20%20%20%20stopSequences:%20%5B%5C%22%5C%5Cn%5C%5Cn%5C%22,%20%5C%22%3C/MESSAGES%3E%5C%22%5D,%5Cn%20%20%20%20%20%20onChunk:%20function(data)%20%7B%5Cn%20%20%20%20%20%20%20%20if(data.isFromStartWith)%20return;%5Cn%20%20%20%20%20%20%20%20newCommentText%20+=%20data.textChunk;%20%5Cn%20%20%20%20%20%20%20%20if(newCommentText.includes(%5C%22%3C/MESSAGES%3E%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20newCommentText%20=%20newCommentText.replace(/%3C%5C%5C/MESSAGES%3E/g,%20%5C%22%5C%22).trim();%5Cn%20%20%20%20%20%20%20%20%20%20obj.stop();%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20commentsBox.inputText%20=%20newCommentText.trim();%5Cn%5Cn%20%20%20%20%20%20%20%20//%20if%20really%20long,%20or%20repeating%20a%20single%20character,%20stop:%5Cn%20%20%20%20%20%20%20%20if(newCommentText.length%20%3E%20800%20%7C%7C%20newCommentText.slice(-30)%20===%20newCommentText%5BnewCommentText.length-1%5D.repeat(30))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20obj.stop();%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%20%20onFinish:%20async%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20autoCommentCharBtn.disabled%20=%20false;%5Cn%20%20%20%20%20%20%20%20autoCommentCharBtn.textContent%20=%20%5C%22%F0%9F%A7%9D%20write%20as%20character%5C%22;%5Cn%5Cn%20%20%20%20%20%20%20%20if(/%5C%5Cn---%5C%5Cs*$/.test(commentsBox.inputText))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20commentsBox.inputText%20=%20commentsBox.inputText.replace(/%5C%5Cn---%5C%5Cs*$/g,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20newCommentText%20=%20newCommentText.replace(/%5C%5Cn---%5C%5Cs*$/g,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20%20%20if(autoCommentAutoSendCheckboxEl.checked)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(newCommentText.trim())%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20if(lastCurrentUserCommentTime%20&&%20Date.now()-lastCurrentUserCommentTime%20%3C%203000)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20too%20soon%20to%20submit%20again,%20so%20just%20set%20nickname%20and%20let%20them%20click%20submit%20manually%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20commentsBox.setNicknameForNextComment(nicknameOverride);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20autoCommentCharBtn.textContent%20=%20%5C%22submitting%20too%20fast%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20autoCommentCharBtn.textContent%20=%20%5C%22%F0%9F%A7%9D%20write%20as%20character%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D,%201000);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20commentsBox.submit(newCommentText.trim(),%20%7Bnickname:nicknameOverride%7D).then(r%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(!r.success)%20commentsBox.inputText%20=%20newCommentText.trim();%20//%20recover%20comment%20text%20if%20it%20failed%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%20%20commentsBox.inputText%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20No%20auto-submit,%20but%20we%20still%20set%20the%20nickname%20to%20their%20character%5Cn%20%20%20%20%20%20%20%20%20%20commentsBox.setNicknameForNextComment(nicknameOverride);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D,%5Cn%20%20%20%20%7D);%5Cn%20%20%7D%5Cn%20%20let%20saveAutoCommentCharInfoDebounceTimeout;%5Cn%20%20window%5B%60__$%7BglobalFnsId%7D_tabbedCommentsPluginSaveAutoCommentCharInfo%60%5D%20=%20function()%20%7B%5Cn%20%20%20%20autoCommentCharSelectEl.selectedOptions%5B0%5D.textContent%20=%20autoCommentCharNameEl.value;%5Cn%20%20%20%20autoCommentChars%5BautoCommentCharSelectEl.value%5D%20=%20%7Bname:autoCommentCharNameEl.value,%20description:autoCommentCharNameDescriptionEl.value%7D;%5Cn%20%20%20%20clearTimeout(saveAutoCommentCharInfoDebounceTimeout);%5Cn%20%20%20%20saveAutoCommentCharInfoDebounceTimeout%20=%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20localStorage.autoCommentChars%20=%20JSON.stringify(autoCommentChars);%5Cn%20%20%20%20%7D,%20500);%5Cn%20%20%7D%5Cn%20%20window%5B%60__$%7BglobalFnsId%7D_tabbedCommentsPluginSwitchToAutoCommentCharByIndex%60%5D%20=%20function(index)%20%7B%5Cn%20%20%20%20if(index%20===%20%5C%22#%5C%22)%20%7B%5Cn%20%20%20%20%20%20//%20add%20a%20new%20%3Coption%3E%20with%20an%20index%201%20higher%20than%20the%20current%20highest:%5Cn%20%20%20%20%20%20let%20newIndex%20=%20autoCommentChars.length;%5Cn%20%20%20%20%20%20let%20selectedOptionEl%20=%20autoCommentCharSelectEl.selectedOptions%5B0%5D;%5Cn%20%20%20%20%20%20selectedOptionEl.value%20=%20newIndex;%5Cn%20%20%20%20%20%20selectedOptionEl.textContent%20=%20%5C%22Unnamed%5C%22;%5Cn%20%20%20%20%20%20autoCommentCharNameEl.value%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20autoCommentCharNameDescriptionEl.value%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20autoCommentCharSelectEl.innerHTML%20+=%20%60%3Coption%20value=%5C%22#%5C%22%3EAdd%20char...%3C/option%3E%60;%5Cn%20%20%20%20%20%20autoCommentCharSelectEl.value%20=%20newIndex;%5Cn%20%20%20%20%20%20localStorage.__tabbedCommentsLastActiveAutoCommentCharIndex%20=%20newIndex;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20autoCommentCharNameEl.value%20=%20autoCommentChars%5Bindex%5D.name;%5Cn%20%20%20%20%20%20autoCommentCharNameDescriptionEl.value%20=%20autoCommentChars%5Bindex%5D.description;%5Cn%20%20%20%20%20%20autoCommentCharSelectEl.value%20=%20index;%5Cn%20%20%20%20%20%20localStorage.__tabbedCommentsLastActiveAutoCommentCharIndex%20=%20index;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20if(autoCommentChars.length%20===%200)%20%7B%5Cn%20%20%20%20autoCommentChars.push(%7Bname:%5C%22Unnamed%5C%22,%20description:%5C%22%5C%22%7D);%5Cn%20%20%20%20autoCommentCharSelectEl.innerHTML%20=%20%60%3Coption%20value=%5C%220%5C%22%3EUnnamed%3C/option%3E%60;%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20autoCommentCharSelectEl.innerHTML%20=%20autoCommentChars.map((o,%20i)%20=%3E%20%60%3Coption%20value=%5C%22$%7Bi%7D%5C%22%3E$%7Bo.name%7D%3C/option%3E%60).join(%5C%22%5C%22);%5Cn%20%20%7D%5Cn%20%20autoCommentCharSelectEl.innerHTML%20+=%20%60%3Coption%20value=%5C%22#%5C%22%3EAdd%20char...%3C/option%3E%60;%5Cn%20%20try%20%7B%5Cn%20%20%20%20let%20charIndex%20=%20Number(localStorage.__tabbedCommentsLastActiveAutoCommentCharIndex%20%7C%7C%200);%5Cn%20%20%20%20if(isNaN(charIndex))%20charIndex%20=%200;%5Cn%20%20%20%20if(!autoCommentChars%5BcharIndex%5D)%20charIndex%20=%200;%5Cn%20%20%20%20if(!autoCommentChars%5BcharIndex%5D)%20%7B%5Cn%20%20%20%20%20%20charIndex%20=%200;%5Cn%20%20%20%20%20%20autoCommentChars%5B0%5D%20=%20%7Bname:%5C%22Unnamed%5C%22,%20description:%5C%22%5C%22%7D;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20localStorage.__tabbedCommentsLastActiveAutoCommentCharIndex%20=%20charIndex;%5Cn%20%20%20%20window%5B%60__$%7BglobalFnsId%7D_tabbedCommentsPluginSwitchToAutoCommentCharByIndex%60%5D(charIndex);%5Cn%20%20%20%20autoCommentAutoSendCheckboxEl.checked%20=%20!!localStorage.__tabbedCommentsAutoCommentAutoSendCheckboxValue;%5Cn%20%20%7D%20catch(e)%20%7B%20alert(e);%20%7D%5Cn%5Cn%20%20function%20createTabbedCommentsPanel(panelOpts)%20%7B%20//%20takes%20*list*%20of%20commentOptions%20as%20input%5Cn%20%20%20%20if(!panelOpts)%20panelOpts%20=%20%7B%7D;%5Cn%20%20%20%20let%20panelCtn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20panelCtn.innerHTML%20=%20%60%5Cn%20%20%20%20%20%20%3Cdiv%20class=%5C%22tabbed-comments-plugin-header%5C%22%3E%3C/div%3E%5Cn%20%20%20%20%20%20%3Cdiv%20class=%5C%22tabbed-comments-plugin-body%5C%22%3E%3C/div%3E%5Cn%20%20%20%20%60;%5Cn%20%20%20%20%5Cn%5Cn%20%20%20%20let%20commentsChannelNameToObj%20=%20%7B%7D;%5Cn%5Cn%20%20%20%20const%20tabsHeaderEl%20=%20panelCtn.querySelector('.tabbed-comments-plugin-header');%5Cn%20%20%20%20const%20tabsContentEl%20=%20panelCtn.querySelector('.tabbed-comments-plugin-body');%5Cn%5Cn%20%20%20%20function%20deleteCommentsChannel(channel)%20%7B%5Cn%20%20%20%20%20%20if(!localStorage.__tabbedCommentsPluginCustomChannels)%20localStorage.__tabbedCommentsPluginCustomChannels%20=%20%5C%22%7B%7D%5C%22;%5Cn%20%20%20%20%20%20let%20customChannels%20=%20%7B%7D;%5Cn%20%20%20%20%20%20try%20%7B%20customChannels%20=%20JSON.parse(localStorage.__tabbedCommentsPluginCustomChannels)%20%7D%20catch(e)%20%7B%20console.error(%5C%22Failed%20to%20parse%20custom%20channels%20from%20localStorage:%5C%22,%20e);%20%7D%5Cn%5Cn%20%20%20%20%20%20delete%20customChannels%5Bchannel%5D;%5Cn%20%20%20%20%20%20localStorage.__tabbedCommentsPluginCustomChannels%20=%20JSON.stringify(customChannels);%5Cn%5Cn%20%20%20%20%20%20tabsHeaderEl.querySelector(%60.tabbed-comments-plugin-tab%5Bdata-channel='$%7Bchannel%7D'%5D%60)?.remove();%5Cn%20%20%20%20%20%20tabsContentEl.querySelector(%60.tabbed-comments-plugin-content%5Bdata-channel='$%7Bchannel%7D'%5D%60)?.remove();%5Cn%5Cn%20%20%20%20%20%20tabsHeaderEl.append(tabsHeaderEl.querySelector(%5C%22.tabbed-comments-plugin-add-custom-channel%5C%22));%20//%20move%20%5C%22+%5C%22%20button%20to%20the%20end%5Cn%20%20%20%20%20%20tabsHeaderEl.prepend(tabsHeaderEl.querySelector(%5C%22.tabbed-comments-plugin-close-panel-btn%5C%22));%20//%20move%20close%20panel%20button%20to%20the%20start%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20function%20addCommentsChannel(channel)%20%7B%5Cn%20%20%20%20%20%20if(!localStorage.__tabbedCommentsPluginCustomChannels)%20localStorage.__tabbedCommentsPluginCustomChannels%20=%20%5C%22%7B%7D%5C%22;%5Cn%20%20%20%20%20%20let%20customChannels%20=%20%7B%7D;%5Cn%20%20%20%20%20%20try%20%7B%20customChannels%20=%20JSON.parse(localStorage.__tabbedCommentsPluginCustomChannels)%20%7D%20catch(e)%20%7B%20console.error(%5C%22Failed%20to%20parse%20custom%20channels%20from%20localStorage:%5C%22,%20e);%20%7D%5Cn%5Cn%20%20%20%20%20%20let%20alreadyExisted%20=%20true;%5Cn%5Cn%20%20%20%20%20%20let%20existingTabEl%20=%20tabsHeaderEl.querySelector(%60.tabbed-comments-plugin-tab%5Bdata-channel='$%7Bchannel%7D'%5D%60);%5Cn%20%20%20%20%20%20if(!existingTabEl%20&&%20channel%20!==%20%5C%22%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20alreadyExisted%20=%20false;%5Cn%20%20%20%20%20%20%20%20customChannels%5Bchannel%5D%20=%20%7Bchannel:channel%7D;%5Cn%20%20%20%20%20%20%20%20let%20commentOptions%20=%20JSON.parse(JSON.stringify(customChannels%5Bchannel%5D));%5Cn%20%20%20%20%20%20%20%20addTab(commentOptions);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20localStorage.__tabbedCommentsPluginCustomChannels%20=%20JSON.stringify(customChannels);%5Cn%5Cn%20%20%20%20%20%20tabsHeaderEl.append(tabsHeaderEl.querySelector(%5C%22.tabbed-comments-plugin-add-custom-channel%5C%22));%20//%20move%20%5C%22+%5C%22%20button%20to%20the%20end%5Cn%20%20%20%20%20%20tabsHeaderEl.prepend(tabsHeaderEl.querySelector(%5C%22.tabbed-comments-plugin-close-panel-btn%5C%22));%20//%20move%20close%20panel%20button%20to%20the%20start%5Cn%5Cn%20%20%20%20%20%20let%20tab%20=%20tabsHeaderEl.querySelector(%60.tabbed-comments-plugin-tab%5Bdata-channel='$%7Bchannel%7D'%5D%60);%5Cn%20%20%20%20%20%20let%20tabContent%20=%20tabsContentEl.querySelector(%60.tabbed-comments-plugin-content%5Bdata-channel='$%7Bchannel%7D'%5D%60);%5Cn%5Cn%20%20%20%20%20%20return%20%7Btab,%20tabContent,%20alreadyExisted%7D;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20Function%20to%20react%20to%20tab%20clicks%5Cn%20%20%20%20function%20handleTabClick(event)%20%7B%5Cn%20%20%20%20%20%20let%20clickedTab%20=%20event.target;%5Cn%20%20%20%20%20%20if(!clickedTab.classList.contains('tabbed-comments-plugin-tab'))%20return;%20//%20they%20didn't%20click%20directly%20on%20a%20tab%5Cn%5Cn%20%20%20%20%20%20if(event.target.classList.contains('tabbed-comments-plugin-add-custom-channel'))%20%7B%5Cn%20%20%20%20%20%20%20%20//%20They%20clicked%20on%20the%20%5C%22+%5C%22%20icon%20to%20add%20a%20new%20channel.%5Cn%20%20%20%20%20%20%20%20let%20channel%20=%20prompt(%5C%22Choose%20a%20channel%20name.%20Note:%20You%20can%20type%20#channelname%20in%20the%20chat%20to%20share%20your%20channel.%5C%22);%5Cn%20%20%20%20%20%20%20%20if(channel)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20removeChannel%20=%20false;%5Cn%20%20%20%20%20%20%20%20%20%20if(channel.startsWith(%5C%22!%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20removeChannel%20=%20true;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20channel%20=%20channel.slice(1);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20channel%20=%20channel.toLowerCase();%5Cn%20%20%20%20%20%20%20%20%20%20channel%20=%20channel.replace(/%5B%5Ea-z0-9%5C%5C-%5D/g,%20%5C%22%5C%22);%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20if(!channel)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20alert(%5C%22Channel%20names%20can%20only%20contain%20lower-case%20letters,%20numbers%20and%20hyphens.%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20if(channel%20===%20%5C%22feedback%5C%22)%20return;%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20if(removeChannel)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20deleteCommentsChannel(channel);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20showTabByChannelName(tabsHeaderEl.firstElementChild.dataset.channel);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20addCommentsChannel(channel);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20showTabByChannelName(channel);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20alert(%60The%20'$%7Bchannel%7D'%20channel%20has%20been%20added.%20Type%20#$%7Bchannel%7D%20in%20the%20chat%20to%20share%20it.%60)%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%7D%20else%20if(event.target.classList.contains('tabbed-comments-plugin-channel-tab'))%20%7B%5Cn%20%20%20%20%20%20%20%20showTabByChannelName(clickedTab.dataset.channel);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20Given%20the%20channel%20of%20a%20tab,%20it%20shows%20the%20tab%20content:%5Cn%20%20%20%20function%20showTabByChannelName(channel)%20%7B%5Cn%20%20%20%20%20%20localStorage.__tabbedCommentsPluginLastViewedChannel%20=%20channel;%5Cn%20%20%20%20%20%20tabsHeaderEl.querySelectorAll('.tabbed-comments-plugin-tab').forEach(el%20=%3E%20el.classList.remove('tabbed-comments-plugin-active-tab'));%5Cn%20%20%20%20%20%20let%20activeTab%20=%20tabsHeaderEl.querySelector(%60.tabbed-comments-plugin-tab%5Bdata-channel='$%7Bchannel%7D'%5D%60);%5Cn%20%20%20%20%20%20activeTab.classList.add('tabbed-comments-plugin-active-tab');%5Cn%5Cn%20%20%20%20%20%20tabsContentEl.querySelectorAll('.tabbed-comments-plugin-content').forEach(el%20=%3E%20el.classList.remove('tabbed-comments-plugin-active-content'));%5Cn%20%20%20%20%20%20tabsContentEl.querySelector(%60.tabbed-comments-plugin-content%5Bdata-channel='$%7Bchannel%7D'%5D%60).classList.add('tabbed-comments-plugin-active-content');%5Cn%5Cn%20%20%20%20%20%20unseenCommentCountByChannel%5Bchannel%5D%20=%200;%5Cn%5Cn%20%20%20%20%20%20updateUnseenCountHtml(channel);%5Cn%5Cn%20%20%20%20%20%20if(!tabsHeaderEl.channelDeleteBtn)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20btn%20=%20tabsHeaderEl.channelDeleteBtn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20%20%20btn.style.cssText%20=%20%5C%22cursor:pointer;%20width:min-content;%20display:flex;%20align-items:center;%20justify-content:center;%20padding-right:0.6rem;%20padding-left:0.1rem;%5C%22;%5Cn%20%20%20%20%20%20%20%20btn.innerHTML%20=%20%5C%22%F0%9F%97%91%EF%B8%8F%5C%22;%5Cn%20%20%20%20%20%20%20%20btn.onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20channel%20=%20this.dataset.channelToDelete;%5Cn%20%20%20%20%20%20%20%20%20%20if(confirm(%60Hide/unpin%20the%20'$%7Bchannel%7D'%20channel?%60))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20deleteCommentsChannel(channel);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20showTabByChannelName(tabsHeaderEl.querySelector('.tabbed-comments-plugin-channel-tab').dataset.channel);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20btn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20//%20add%20delete%20button%20if%20it's%20not%20a%20main%20channel:%5Cn%20%20%20%20%20%20if(channel%20!==%20%5C%22%5C%22%20&&%20!commentsChannels.selectAll.map(c%20=%3E%20c.getName).includes(channel))%20%7B%5Cn%20%20%20%20%20%20%20%20let%20btn%20=%20tabsHeaderEl.channelDeleteBtn;%5Cn%20%20%20%20%20%20%20%20btn.style.display%20=%20%5C%22flex%5C%22;%5Cn%20%20%20%20%20%20%20%20btn.dataset.channelToDelete%20=%20channel;%5Cn%20%20%20%20%20%20%20%20activeTab.after(btn);%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20tabsHeaderEl.channelDeleteBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(panelOpts.onShowTab)%20panelOpts.onShowTab(%7Bchannel%7D);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20Adds%20a%20new%20tab%20to%20the%20module%5Cn%20%20%20%20function%20addTab(commentOptions)%20%7B%5Cn%20%20%20%20%5Cn%20%20%20%20%20%20commentOptions.width%20=%20%5C%22100%25%5C%22;%5Cn%20%20%20%20%20%20commentOptions.height%20=%20%5C%22100%25%5C%22;%20//%20only%20makes%20sense%20to%20set%20height%20via%20defaultChannelOptions,%20and%20that%20controls%20overall%20comments%20container%20height%5Cn%20%20%20%20%20%20if(!commentOptions.customEmojis)%20commentOptions.customEmojis%20=%20defaultChannelOptions.customEmojis%20%7C%7C%20defaultCustomEmojis;%5Cn%20%20%20%20%20%20commentOptions.forceColorScheme%20=%20defaultChannelOptions.forceColorScheme%20??%20localStorage.forceColorScheme%20??%20null;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20originalOnCommentHandler%20=%20commentOptions.onComment%20%7C%7C%20defaultChannelOptions.onComment;%5Cn%20%20%20%20%20%20let%20originalOnLoadHandler%20=%20commentOptions.onLoad%20%7C%7C%20defaultChannelOptions.onLoad%5Cn%20%20%20%20%20%20commentOptions.onComment%20=%20function(...args)%20%7B%5Cn%20%20%20%20%20%20%20%20commentsPluginOnCommentHandler(...args);%20//%20for%20counting%20unseen,%20channel%20mentions,%20etc.%5Cn%20%20%20%20%20%20%20%20try%20%7B%20if(originalOnCommentHandler)%20originalOnCommentHandler(...args);%20%7D%20catch(e)%20%7B%20console.error(e)%20%7D%20//%20userland%20code%5Cn%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20commentOptions.onLoad%20=%20function(...args)%20%7B%5Cn%20%20%20%20%20%20%20%20commentsPluginOnLoadHandler(...args);%20//%20for%20counting%20unseen,%20channel%20mentions,%20etc.%5Cn%20%20%20%20%20%20%20%20try%20%7B%20if(originalOnLoadHandler)%20originalOnLoadHandler(...args);%20%20%7D%20catch(e)%20%7B%20console.error(e)%20%7D%20//%20userland%20code%5Cn%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%5Cn%20%20%20%20%20%20commentOptions.replacedDuringUpdate%20=%20true;%20//%20needed%20to%20allow%20multiple%20instances%20of%20the%20same%20channel%20(since%20we%20have%20multiple%20tabbed-comments-modules)%5Cn%20%20%20%20%20%20for(let%20key%20of%20defaultChannelOptions.getAllKeys%20%7C%7C%20Object.keys(defaultChannelOptions))%20%7B%5Cn%20%20%20%20%20%20%20%20if(!commentOptions%5Bkey%5D%20&&%20!commentOptions.hasOwnProperty(key))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20getter,%20because%20the%20default%20options%20could%20be%20dynamic%20(e.g.%20dark/light%20mode%20using%20localStorage),%20and%20this%20createTabbedCommentsPanel%20function%20is%20(as%20of%20writing)%20called%20every%20time%20the%20dark/light%20mode%20is%20switched.%5Cn%20%20%20%20%20%20%20%20%20%20Object.defineProperty(commentOptions,%20key,%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20get:%20()%20=%3E%20defaultChannelOptions%5Bkey%5D,%5Cn%20%20%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20commentsPluginOutput%20=%20commentsPlugin(commentOptions);%5Cn%20%20%20%20%20%20commentsChannelNameToObj%5BcommentOptions.channel%5D%20=%20commentsPluginOutput;%5Cn%5Cn%20%20%20%20%20%20const%20tab%20=%20document.createElement('div');%5Cn%20%20%20%20%20%20tab.className%20=%20'tabbed-comments-plugin-tab%20tabbed-comments-plugin-channel-tab';%20//%20note%20that%20non-channel%20tabs/buttons%20are%20possible%20-%20e.g.%20close%20tab%20button,%20close%20panel%20button%5Cn%20%20%20%20%20%20tab.textContent%20=%20commentOptions.label%20%7C%7C%20commentOptions.channel%20%7C%7C%20%5C%22general%5C%22;%5Cn%20%20%20%20%20%20tab.innerHTML%20+=%20%60%3Cspan%20class=%5C%22tabbed-comments-plugin-unseen-count%5C%22%3E?%3C/span%3E%60;%5Cn%20%20%20%20%20%20tab.dataset.channel%20=%20commentOptions.channel;%5Cn%5Cn%20%20%20%20%20%20const%20tabContent%20=%20document.createElement('div');%5Cn%20%20%20%20%20%20tabContent.className%20=%20'tabbed-comments-plugin-content';%5Cn%20%20%20%20%20%20tabContent.innerHTML%20=%20commentsPluginOutput;%5Cn%20%20%20%20%20%20tabContent.dataset.channel%20=%20commentOptions.channel;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20for%20refreshing%20the%20comments%20if%20needed%20(e.g.%20when%20dark/light%20mode%20changes%20-%20see%20updateColorScheme%20function)%5Cn%20%20%20%20%20%20tabContent.dataset.tabbedCommentsDirectParentOfCommentsPluginOutput%20=%20%5C%221%5C%22;%5Cn%20%20%20%20%20%20tabContent.__commentOptionsUsed%20=%20commentOptions;%20//%20this%20should%20probably%20not%20be%20'concrete'%20ones%20because%20we%20want%20a%20reference%20to%20the%20dynamic%20onces%20for%20if/when%20we%20need%20to%20reload%20it%5Cn%5Cn%20%20%20%20%20%20tabsHeaderEl.appendChild(tab);%5Cn%20%20%20%20%20%20tabsContentEl.appendChild(tabContent);%5Cn%20%20%20%20%20%20return%20%7Btab,%20tabContent%7D;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20let%20existingChannelNames%20=%20%5B%5D;%5Cn%20%20%20%20let%20channelNameToChannelData%20=%20%7B%7D;%5Cn%20%20%20%20for(let%20commentOptions%20of%20commentsChannels.selectAll)%20%7B%5Cn%20%20%20%20%20%20if(!commentOptions.channel)%20commentOptions.channel%20=%20commentOptions.getName===%5C%22general%5C%22%20?%20%5C%22%5C%22%20:%20commentOptions.getName;%20//%20use%20name%20of%20commentOptions%20object%20as%20channel%20name%20by%20default%5Cn%20%20%20%20%20%20let%20channelName%20=%20commentOptions.channel.toString();%5Cn%20%20%20%20%20%20let%20%7Btab,%20tabContent%7D%20=%20addTab(commentOptions);%5Cn%20%20%20%20%20%20channelNameToChannelData%5BchannelName%5D%20=%20%7Btab,%20tabContent,%20channelName%7D;%5Cn%20%20%20%20%20%20existingChannelNames.push(channelName);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20Add%20the%20%5C%22+%5C%22%20button:%5Cn%20%20%20%20if(commentsChannels.allowCustomChannels%20!==%20false)%20%7B%5Cn%5Cn%20%20%20%20%20%20//%20add%20user-specified%20custom%20channels:%5Cn%20%20%20%20%20%20if(!localStorage.__tabbedCommentsPluginCustomChannels)%20localStorage.__tabbedCommentsPluginCustomChannels%20=%20%5C%22%7B%7D%5C%22;%5Cn%20%20%20%20%20%20let%20customChannels%20=%20%7B%7D;%5Cn%20%20%20%20%20%20try%20%7B%20customChannels%20=%20JSON.parse(localStorage.__tabbedCommentsPluginCustomChannels)%20%7D%20catch(e)%20%7B%20console.error(%5C%22Failed%20to%20parse%20custom%20channels%20from%20localStorage:%5C%22,%20e);%20%7D%5Cn%20%20%20%20%20%20for(let%20commentOptions%20of%20Object.values(customChannels))%20%7B%5Cn%20%20%20%20%20%20%20%20if(existingChannelNames.includes(commentOptions.channel))%20continue;%20//%20already%20got%20that%20channel%5Cn%20%20%20%20%20%20%20%20let%20channelName%20=%20commentOptions.channel.toString();%5Cn%20%20%20%20%20%20%20%20let%20%7Btab,%20tabContent%7D%20=%20addTab(commentOptions);%5Cn%20%20%20%20%20%20%20%20channelNameToChannelData%5BchannelName%5D%20=%20%7Btab,%20tabContent,%20channelName%7D;%5Cn%5Cn%20%20%20%20%20%20%20%20if(temporaryMentionedChannels.has(channelName))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20tab.dataset.tabbedCommentsPluginIsTemporaryMentionedChannel%20=%20%5C%221%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20attachEventsToTemporaryMentionedChannelTab(tab,%20channelName);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20//%20add%20the%20%5C%22+%5C%22%20button:%5Cn%20%20%20%20%20%20const%20tab%20=%20document.createElement('div');%5Cn%20%20%20%20%20%20tab.className%20=%20'tabbed-comments-plugin-tab%20tabbed-comments-plugin-add-custom-channel';%5Cn%20%20%20%20%20%20tab.textContent%20=%20%5C%22+%5C%22;%5Cn%20%20%20%20%20%20tab.style.cssText%20=%20%5C%22min-width:1.4rem;%5C%22;%5Cn%20%20%20%20%20%20tabsHeaderEl.appendChild(tab);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20//%20add%20the%20close-panel%20button%20if%20needed:%5Cn%20%20%20%20%7B%5Cn%20%20%20%20%20%20const%20tab%20=%20document.createElement('div');%5Cn%20%20%20%20%20%20tab.className%20=%20'tabbed-comments-plugin-tab%20tabbed-comments-plugin-close-panel-btn';%5Cn%20%20%20%20%20%20tab.textContent%20=%20%5C%22%E2%9D%8C%5C%22;%5Cn%20%20%20%20%20%20tab.title%20=%20%5C%22Close%20this%20panel%5C%22;%5Cn%20%20%20%20%20%20//%20NOTE:%20rather%20than%20not%20adding%20the%20button,%20or%20using%20display:none;%20we%20just%20remove%20it's%20width%20+%20opacity%20+%20pointer-events,%20because%20otherwise%20the%20height%20of%20the%20header%20can%20change%20due%20to%20emoji%20font%20size,%20which%20vertically%20offsets%20the%20panels%20by%20a%20pixel%20or%20two,%20which%20looks%20bad.%5Cn%20%20%20%20%20%20tab.style.cssText%20=%20panelOpts.addCloseButton%20?%20%5C%22min-width:1.4rem;%5C%22%20:%20%5C%22width:0px;%20max-width:0px;%20pointer-events:none;%20margin-left:0;%20margin-right:0;%20padding-left:0;%20padding-right:0;%20min-width:0px;%20opacity:0;%5C%22;%5Cn%20%20%20%20%20%20tab.onclick%20=%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20panelCtn.remove();%5Cn%20%20%20%20%20%20%20%20if(panelOpts.onClose)%20panelOpts.onClose();%5Cn%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20tabsHeaderEl.prepend(tab);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20let%20defaultStartChannelIndex%20=%200;%5Cn%5Cn%20%20%20%20let%20activeChannelData%20=%20channelNameToChannelData%5BlocalStorage.__tabbedCommentsPluginLastViewedChannel%20??%20existingChannelNames%5BdefaultStartChannelIndex%5D%5D;%5Cn%20%20%20%20if(!activeChannelData)%20%7B%5Cn%20%20%20%20%20%20console.error(%5C%22localstorage%20had%20__tabbedCommentsPluginLastViewedChannel,%20but%20that%20channel%20doesn't%20exist?%5C%22);%5Cn%20%20%20%20%20%20activeChannelData%20=%20channelNameToChannelData%5BexistingChannelNames%5B0%5D%5D;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20while(!document.body.contains(panelCtn))%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20100));%5Cn%20%20%20%20%20%20showTabByChannelName(activeChannelData.channelName);%5Cn%20%20%20%20%7D,%2010);%5Cn%5Cn%20%20%20%20tabsHeaderEl.addEventListener('click',%20handleTabClick);%5Cn%5Cn%20%20%20%20let%20styleEl%20=%20document.createElement(%5C%22style%5C%22);%5Cn%20%20%20%20styleEl.textContent%20=%20%60%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-header%20%7B%5Cn%20%20%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20%20%20font-size:%2070%25;%5Cn%20%20%20%20%20%20%20%20overflow:auto;%5Cn%20%20%20%20%20%20%20%20color:var(--tabbed-comments-plugin-text-color);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-body%20%7B%5Cn%20%20%20%20%20%20%20%20flex-grow:1;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-tab%20%7B%5Cn%20%20%20%20%20%20%20%20padding:%200.25rem;%5Cn%20%20%20%20%20%20%20%20cursor:%20pointer;%5Cn%20%20%20%20%20%20%20%20background:%20var(--tabbed-comments-plugin-box-color,%20#ebebeb);%5Cn%20%20%20%20%20%20%20%20border-radius:%200.25rem;%5Cn%20%20%20%20%20%20%20%20margin:%200.25rem;%5Cn%20%20%20%20%20%20%20%20user-select:%20none;%5Cn%20%20%20%20%20%20%20%20min-width:%20max-content;%5Cn%20%20%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-tab%5Bdata-tabbed-comments-plugin-is-temporary-mentioned-channel='1'%5D%20%7B%5Cn%20%20%20%20%20%20%20%20opacity:0.6;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-unseen-count%20%7B%5Cn%20%20%20%20%20%20%20%20border-radius:%20100px;%5Cn%20%20%20%20%20%20%20%20padding:%200.05rem%200.15rem;%5Cn%20%20%20%20%20%20%20%20font-size:80%25;%5Cn%20%20%20%20%20%20%20%20background:grey;%5Cn%20%20%20%20%20%20%20%20margin-left:%200.1rem;%5Cn%20%20%20%20%20%20%20%20pointer-events:none;%5Cn%20%20%20%20%20%20%20%20color:white;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-active-tab%20%7B%5Cn%20%20%20%20%20%20%20%20background:%20var(--tabbed-comments-plugin-active-comment-channel-tab-color,%20#c6c6c6);%5Cn%20%20%20%20%20%20%20%20outline:%202px%20solid%20#0086c9;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-content%20%7B%5Cn%20%20%20%20%20%20%20%20display:%20none;%5Cn%20%20%20%20%20%20%20%20height:100%25;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-plugin-active-content%20%7B%5Cn%20%20%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20@media%20only%20screen%20and%20(max-width:%20650px)%20%7B%5Cn%20%20%20%20%20%20%20%20.tabbed-comments-auto-comment-ctn%20%7B%20flex-direction:column;%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-ctn-left%20%7B%20display:none;%20%7D%5Cn%20%20%20%20%20%20.tabbed-comments-ctn-right%20%7B%20display:none;%20%7D%5Cn%20%20%20%20%20%20$%7BCSS.supports(%5C%22container-type%5C%22,%20%5C%22inline-size%5C%22)%20?%20%60@container%60%20:%20%60@media%20only%20screen%20and%60%7D%20(min-width:%201100px)%20%7B%5Cn%20%20%20%20%20%20%20%20.tabbed-comments-ctn-left%20%7B%20display:flex;%20%7D%5Cn%20%20%20%20%20%20%20%20.tabbed-comments-ctn-right%20%7B%20display:flex;%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%60;%5Cn%20%20%20%20panelCtn.append(styleEl);%5Cn%20%20%20%20panelCtn.style.cssText%20=%20%5C%22height:100%25;%20width:100%25;%20display:flex;%20flex-direction:column;%5C%22%5Cn%20%20%20%20return%20%7Belement:panelCtn,%20addCommentsChannel,%20deleteCommentsChannel,%20commentsChannelNameToObj%7D;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20middlePanelObj%20=%20createTabbedCommentsPanel(%7B%5Cn%20%20%20%20onShowTab:%20(%7Bchannel%7D)%20=%3E%20%7B%5Cn%20%20%20%20%20%20middleCtnCurrentlyShownCommentsChannelName%20=%20channel;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20channelData%20=%20commentsChannels%5Bchannel%20%7C%7C%20%5C%22general%5C%22%5D;%5Cn%20%20%20%20%20%20if(!channelData)%20channelData%20=%20defaultChannelOptions;%5Cn%20%20%20%20%20%20let%20allowBots%20=%20channelData.allowBots;%5Cn%20%20%20%20%20%20if(channel%20===%20%5C%22%5C%22%20%7C%7C%20channel%20===%20%5C%22general%5C%22%20%7C%7C%20opts.allowBots%20===%20false)%20%7B%5Cn%20%20%20%20%20%20%20%20if(allowBots%20===%20undefined)%20allowBots%20=%20false;%20//%20by%20default,%20don't%20allow%20bots%20on%20main/general/chat%20channel%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20autoCommentCtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20if(allowBots%20!==%20false)%20%7B%5Cn%20%20%20%20%20%20%20%20showAutoCommentAreaBtn.style.display%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20showAutoCommentAreaBtn.style.display%20=%20%5C%22none%5C%22;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D,%5Cn%20%20%7D);%5Cn%20%20middleCtnChannelNameToObj%20=%20middlePanelObj.commentsChannelNameToObj;%5Cn%20%20middleCtn.appendChild(middlePanelObj.element);%5Cn%20%20return%20outerCtn;%22,%22imports%22:%5B%22ai-text-plugin%22,%22comments-plugin%22,%22huge-emoji-list%22%5D,%22lastEditTime%22:1730342042590,%22found%22:true%7D,%7B%22name%22:%22text-to-image-plugin%22,%22modelText%22:%22%5Cn//%20NOTE%20TO%20SELF:%20If%20you%20add%20more%20properties,%20make%20sure%20you%20add%20to%20the%20regex%20below,%20and%20the%20variable%20declarations%20in%20each%20'branch'%5Cn%5Cn$output(data)%20=%3E%5Cn%20%20if(data%20===%20undefined)%20return%20%5C%22(Error:%20you've%20input%20an%20empty%20value/variable%20into%20the%20text-to-image-plugin)%5C%22;%5Cn%20%20//%20if(options%20===%20undefined)%20options%20=%20%7B%7D;%5Cn%20%20%5Cn%20%20let%20serverOrigin%20=%20%5C%22https://image-generation.perchance.org%5C%22;%5Cn%20%20%5Cn%20%20let%20evaluatedInputs;%5Cn%20%20%5Cn%20%20//%20This%20is%20used%20for%20the%20heart-button%20gallery.%20It's%20a%20bit%20hacky,%20but%20most%20often%20devs%20will%20want%20the%20%5C%22open%20gallery%5C%22%20button%20to%20show%20a%20gallery%20with%20e.g.%20the%20same%20moderation%20options%20as%20the%20gallery%20that%20they've%20displayed%20on%20the%20page,%20if%20any.%5Cn%20%20window.lastUsedTextToImagePluginGalleryIframeUrl%20=%20null;%5Cn%20%20%5Cn%20%20let%20shouldRemoveIframeOnFinish%20=%20false;%20//%20for%20the%20case%20where%20the%20iframe%20was%20added%20automatically%20-%20i.e.%20when%20called%20like:%20%20%60let%20result%20=%20await%20image(%7Bprompt:%5C%22a%20cute%20mouse%5C%22%7D)%60%5Cn%5Cn%20%20////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20set%20up%20handler%20for%20gallery%20%20%20%20%20%20%20%20%20%20%20//%5Cn%20%20////////////////////////////////////////////////%5Cn%5Cn%20%20if(!window.___addedTextToImagePluginFirstTimeCode98420274)%20%7B%5Cn%20%20%20%20window.addEventListener(%5C%22message%5C%22,%20function(e)%20%7B%5Cn%20%20%20%20%20%20let%20origin%20=%20e.origin%20%7C%7C%20e.originalEvent.origin;%20//%20For%20Chrome,%20the%20origin%20property%20is%20in%20the%20event.originalEvent%20object.%5Cn%20%20%20%20%20%20if(origin%20!==%20serverOrigin)%20%7B%5Cn%20%20%20%20%20%20%20%20return;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(e.data.openGallerySignal)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20ctn%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20%20%20let%20subChannelName%20=%20e.data.subChannelName;%5Cn%20%20%20%20%20%20%20%20let%20url;%5Cn%20%20%20%20%20%20%20%20if(window.lastUsedTextToImagePluginGalleryIframeUrl)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20url%20=%20new%20URL(window.lastUsedTextToImagePluginGalleryIframeUrl);%5Cn%20%20%20%20%20%20%20%20%20%20url.searchParams.set(%5C%22subChannelName%5C%22,%20subChannelName);%5Cn%20%20%20%20%20%20%20%20%20%20url%20=%20url.href;%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20url%20=%20%60$%7BserverOrigin%7D/gallery?channel=$%7Bwindow.generatorName%7D&subChannel=$%7BencodeURIComponent(subChannelName)%7D&sort=trending&timeRange=1-month&contentFilter=pg13%60;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20let%20backgroundColor%20=%20window.matchMedia%20&&%20window.matchMedia('(prefers-color-scheme:%20dark)').matches%20?%20%5C%22#242424%5C%22%20:%20%5C%22white%5C%22;%5Cn%20%20%20%20%20%20%20%20ctn.innerHTML%20=%20%60%3Cdiv%20onclick=%5C%22this.remove()%5C%22%20style=%5C%22backdrop-filter:brightness(0.3);position:fixed;top:0;left:0;right:0;bottom:0;z-index:999;%5C%22%3E%3Cdiv%20style=%5C%22position:fixed;top:5vh;bottom:5vh;left:5vh;right:5vh;background:$%7BbackgroundColor%7D;border-radius:3px;%5C%22%3E%3Ciframe%20src=%5C%22$%7Burl%7D%5C%22%20style=%5C%22border:0;width:100%25;height:100%25;%5C%22%3E%3C/iframe%3E%3C/div%3E%3C/div%3E%60;%5Cn%20%20%20%20%20%20%20%20document.body.appendChild(ctn.firstElementChild);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(e.data.savedImageToGallerySignal)%20%7B%5Cn%20%20%20%20%20%20%20%20document.querySelectorAll(%5C%22.text-to-image-plugin-gallery%5C%22).forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20let%20targetOrigin%20=%20serverOrigin;%5Cn%20%20%20%20%20%20%20%20%20%20el.contentWindow.postMessage(%7BdoRefreshIfSortingByRecent:true%7D,%20targetOrigin);%5Cn%20%20%20%20%20%20%20%20%20%20%5Cn%20%20%20%20%20%20%20%20%20%20//%20the%20code%20below%20is%20commented%20out%20because%20it%20doesn't%20work%20for%20the%20case%20where%20the%20user%20has%20switched%20the%20sort%20to%20recent%20(since,%20counter-intuitively,%20iframe's%20window.location%20can%20change,%20while%20iframe.src%20stays%20as%20the%20original%20value%20-%20I'm%20assuming%20this%20is%20due%20to%20cross-origin%20security%20stuff)%5Cn%20%20%20%20%20%20%20%20%20%20//%20if(el.src.includes(%5C%22sort=recent%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20%20%20//%20refresh%20galleries%20that%20are%20sorted%20by%20recent%20if%20the%20user%20makes%20a%20submission%5Cn%20%20%20%20%20%20%20%20%20%20//%20%20%20let%20url%20=%20new%20URL(el.src);%5Cn%20%20%20%20%20%20%20%20%20%20//%20%20%20url.searchParams.set(%5C%22cacheBust%5C%22,%20Math.random().toString());%5Cn%20%20%20%20%20%20%20%20%20%20//%20%20%20el.src%20=%20%5C%22%5C%22;%20//%20we%20do%20this%20instead%20of%20el.src=el.src%20because%20that%20doesn't%20work%20if%20the%20URL%20has%20a%20hash%20in%20it,%20and%20I%20might%20need%20to%20add%20data%20in%20the%20hash%20later%5Cn%20%20%20%20%20%20%20%20%20%20//%20%20%20setTimeout(()%20=%3Eel.src=url.href,%20700);%20//%20we%20need%20to%20wait%20a%20bit%20for%20the%20iframe%20to%20actually%20initiate%20a%20reload/refresh%20before%20setting%20the%20src%20again%5Cn%20%20%20%20%20%20%20%20%20%20//%20%7D%5Cn%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(e.data.documentHeightChanged)%20%7B%5Cn%20%20%20%20%20%20%20%20document.querySelectorAll(%5C%22.text-to-image-plugin-gallery%5C%22).forEach(el%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(el.dataset.adaptiveHeight%20===%20%5C%22yes%5C%22)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20el.style.height%20=%20(e.data.newHeight+1)+%5C%22px%5C%22;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20console.debug(%5C%22Updated%20gallery%20height%5C%22,%20e.data.newHeight);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%20%20%20%20window.___addedTextToImagePluginFirstTimeCode98420274%20=%20true;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(data.gallery)%20%7B%5Cn%20%20%20%20//%20NOTE:%20this%20is%20a%20somewhat%20'breaking'%20change,%20but%20I'm%20no%20longer%20allowing%20unfiltered%20content%20to%20be%20shown%20by%20default.%5Cn%20%20%20%20//%20The%20user%20must%20specifically%20choose%20to%20switch%20the%20gallery%20to%20unfiltered%20mode.%5Cn%20%20%20%20data.contentFilter%20=%20%5C%22pg13%5C%22;%5Cn%20%20%5Cn%20%20%20%20let%20sort%20=%20data.sort%20?%20data.sort.evaluateItem%20:%20%5C%22recent%5C%22;%5Cn%20%20%20%20if(sort%20===%20%5C%22best%5C%22)%20sort%20=%20%5C%22top%5C%22;%20//%20alias%5Cn%20%20%20%20%5Cn%20%20%20%20let%20contentFilter%20=%20data.contentFilter%20?%20data.contentFilter.evaluateItem.toLowerCase()%20:%20%5C%22pg13%5C%22;%5Cn%20%20%20%20if(contentFilter%20===%20%5C%22pg-13%5C%22)%20contentFilter%20=%20%5C%22pg13%5C%22;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20bannedUsers%20=%20data.bannedUsers%20?%20data.bannedUsers.selectAll.map(item%20=%3E%20item.toString())%20:%20%5B%5D;%5Cn%20%20%20%20let%20bannedPromptPhrases%20=%20data.bannedPromptPhrases%20?%20data.bannedPromptPhrases.selectAll.map(item%20=%3E%20item.getRawListText.replace(%5C%22/%5C%5C%5C%5C%5E%5C%22,%20%5C%22/%5E%5C%22))%20:%20%5B%5D;%5Cn%20%20%20%20let%20bannedNegativePromptPhrases%20=%20data.bannedNegativePromptPhrases%20?%20data.bannedNegativePromptPhrases.selectAll.map(item%20=%3E%20item.getRawListText.replace(%5C%22/%5C%5C%5C%5C%5E%5C%22,%20%5C%22/%5E%5C%22))%20:%20%5B%5D;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20timeRange%20=%20data.timeRange%20?%20data.timeRange.evaluateItem%20:%20(sort%20===%20%5C%22recent%5C%22%20?%20%5C%22all-time%5C%22%20:%20%5C%221-month%5C%22);%5Cn%20%20%20%20let%20hideIfScoreIsBelow%20=%20data.hideIfScoreIsBelow%20!==%20undefined%20?%20Number(data.hideIfScoreIsBelow.evaluateItem)%20:%20-1000000000;%5Cn%20%20%20%20if(isNaN(hideIfScoreIsBelow))%20hideIfScoreIsBelow%20=%20-1000000000;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20galleryOptions%20=%20%7Bsort,%20timeRange,%20hideIfScoreIsBelow,%20contentFilter,%20subChannel:%5C%22public%5C%22%7D;%20//%20this%20is%20also%20used%20for%20checking%20if%20gallery%20options%20have%20been%20udpated%20(see%20below)%5Cn%20%20%20%20if(data.forceColorScheme)%20galleryOptions.forceColorScheme%20=%20data.forceColorScheme;%5Cn%20%20%20%20%5Cn%20%20%20%20let%20hashData%20=%20%7BbannedUsers,%20bannedPromptPhrases,%20bannedNegativePromptPhrases,%20injectedStyles:%7B%7D%7D;%5Cn%20%20%20%20if(data.style)%20%7B%5Cn%20%20%20%20%20%20let%20style%20=%20data.style.evaluateItem.trim();%5Cn%20%20%20%20%20%20if(style.includes(%5C%22background:%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20hashData.injectedStyles.background%20=%20(style.match(/(?:%5E%7C;)%20*background:(.+?)(?:;%7C$)/)%20%7C%7C%20%5B%5D)%5B1%5D;%5Cn%20%20%20%20%20%20%7D%20else%20if(style.includes(%5C%22background-color:%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20hashData.injectedStyles.background%20=%20(style.match(/(?:%5E%7C;)%20*background-color:(.+?)(?:;%7C$)/)%20%7C%7C%20%5B%5D)%5B1%5D;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20let%20otherUrlParams%20=%20%7Bchannel:window.generatorName%7D;%5Cn%20%20%20%20let%20iframeUrl%20=%20new%20URL(%60$%7BserverOrigin%7D/gallery%60);%5Cn%20%20%20%20Object.entries(galleryOptions).forEach((%5Bkey,%20value%5D)%20=%3E%20iframeUrl.searchParams.set(key,%20value));%5Cn%20%20%20%20Object.entries(otherUrlParams).forEach((%5Bkey,%20value%5D)%20=%3E%20iframeUrl.searchParams.set(key,%20value));%5Cn%20%20%20%20%5Cn%20%20%20%20%5Cn%20%20%20%20function%20makeGalleryIframeHtml()%20%7B%5Cn%20%20%20%20%20%20let%20url%20=%20iframeUrl.href%20+%20%60#data=$%7BencodeURIComponent(JSON.stringify(hashData))%7D%60;%5Cn%20%20%20%20%20%20window.lastUsedTextToImagePluginGalleryIframeUrl%20=%20url;%5Cn%20%20%20%20%20%20return%20%60%3Ciframe%20data-gallery-options=%5C%22$%7BencodeURIComponent(JSON.stringify(galleryOptions))%7D%5C%22%20data-adaptive-height=%5C%22$%7Bdata.adaptiveHeight%20?%20%5C%22yes%5C%22%20:%20%5C%22no%5C%22%7D%5C%22%20style=%5C%22width:100%25;%20height:70vh;%20border:none;%20$%7Bdata.style%20%7C%7C%20%5C%22%5C%22%7D%5C%22%20class=%5C%22text-to-image-plugin-gallery%5C%22%20src=%5C%22$%7Burl%7D%5C%22%20allow=%5C%22clipboard-write%5C%22%3E%3C/iframe%3E%60;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(!document.querySelector(%5C%22.text-to-image-plugin-gallery%5C%22))%20%7B%5Cn%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20let%20marker%20=%20document.querySelector(%5C%22#temporaryMarkerElForTextToImageGallery84738932%5C%22);%5Cn%20%20%20%20%20%20%20%20if(marker)%20marker.outerHTML%20=%20makeGalleryIframeHtml()%5Cn%20%20%20%20%20%20%7D,%2050);%5Cn%20%20%20%20%20%20return%20%60%3Cspan%20id=%5C%22temporaryMarkerElForTextToImageGallery84738932%5C%22%3E%3C/span%3E%60;%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20//%20update%20any%20gallery%20parameters%20if%20they%20have%20been%20changed:%5Cn%20%20%20%20%20%20let%20galleryIframe%20=%20document.querySelector(%5C%22.text-to-image-plugin-gallery%5C%22);%5Cn%20%20%20%20%20%20let%20newGalleryOptionsText%20=%20encodeURIComponent(JSON.stringify(galleryOptions));%5Cn%20%20%20%20%20%20if(galleryIframe.dataset.galleryOptions%20!==%20newGalleryOptionsText)%20%7B%5Cn%20%20%20%20%20%20%20%20galleryIframe.outerHTML%20=%20makeGalleryIframeHtml();%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20return%20%5C%22%5C%22;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20///////////////////////////////////////////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20%20%20%20%20%20%20%20parse%20and%20evaluate%20prompt%20data/options%20from%20input%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%5Cn%20%20///////////////////////////////////////////////////////////////////////////////////////%5Cn%20%20const%20defaultGuidanceScale%20=%207;%5Cn%20%20%5Cn%20%20let%20d%20=%20%7B%7D;%20%5Cn%20%20//%20let%20dataInputWasNotAnOptionsObject%20=%20false;%5Cn%20%20%5Cn%20%20if(data.prompt%20===%20undefined)%20%7B%5Cn%20%20%20%20d.prompt%20=%20data.evaluateItem.toString();%20//%20they%20passed%20in%20some%20text%20directly%20like%20%5Bimage(%5C%22a%20carrot%5C%22)%5D%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20d.prompt%20=%20data.prompt.evaluateItem.toString();%5Cn%20%20%7D%5Cn%20%20//%20Apply%20some%20covenience%20fixes%20to%20the%20prompt,%20even%20though%20the%20plugin%20user%20should%20ideally%20fix%20this%20on%20their%20end:%5Cn%20%20d.prompt%20=%20d.prompt.replace(/%3Cspan%20%5B%5E%3E%5D+______tippy-tooltip-%5B%5E%3E%5D+%3E(.+?)%3C%5C%5C/span%3E/,%20%5C%22$1%5C%22);%5Cn%20%20%5Cn%20%20//%20parse%20values%20from%20prompts%20like:%20%60this%20is%20the%20prompt%20text%20(size:::400)%20(resolution:::512x768)%20(guidanceScale:::10)%60%5Cn%20%20if(d.prompt.includes(%5C%22:::%5C%22))%20%7B%5Cn%20%20%20%20let%20matches%20=%20%5B...d.prompt.matchAll(/%5C%5C((seed%7Csize%7Cstyle%7Cresolution%7Cwidth%7Cheight%7CguidanceScale%7CsaveTitle%7CsaveDescription)%5C%5C:%5C%5C:%5C%5C:/g)%5D;%5Cn%20%20%20%20//%20console.debug(%5C%22matches:%5C%22,%20matches);%5Cn%20%20%20%20const%20numericProps%20=%20%5B%5C%22seed%5C%22,%20%5C%22width%5C%22,%20%5C%22height%5C%22,%20%5C%22guidanceScale%5C%22,%20%5C%22width%5C%22,%20%5C%22height%5C%22,%20%5C%22size%5C%22%5D;%5Cn%20%20%20%20for(let%20match%20of%20matches)%20%7B%5Cn%20%20%20%20%20%20let%20re%20=%20new%20RegExp(%60%5C%5C%5C%5C($%7Bmatch%5B1%5D%7D%5C%5C%5C%5C:%5C%5C%5C%5C:%5C%5C%5C%5C:(.+?)%5C%5C%5C%5C).*?(?:%5C%5C%5C%5C:%5C%5C%5C%5C:%5C%5C%5C%5C:%7C$)%60);%5Cn%20%20%20%20%20%20let%20value%20=%20(d.prompt.match(re)%20%7C%7C%20%5B%5D)%5B1%5D%5Cn%20%20%20%20%20%20let%20key%20=%20match%5B1%5D;%5Cn%20%20%20%20%20%20if(value%20!==%20undefined)%20%7B%5Cn%20%20%20%20%20%20%20%20d%5Bkey%5D%20=%20numericProps.includes(key)%20?%20Number(value)%20:%20value;%5Cn%20%20%20%20%20%20%20%20d.prompt%20=%20d.prompt.replace(%60($%7Bkey%7D:::$%7Bvalue%7D)%60,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%20%20d.prompt%20=%20d.prompt.trim();%5Cn%20%20%7D%5Cn%20%20if(!window.___t2i__parseNegativePrompt)%20%7B%5Cn%20%20%20%20window.___t2i__parseNegativePrompt%20=%20function(str)%20%7B%5Cn%20%20%20%20%20%20const%20prefix%20=%20'(negativePrompt:::';%5Cn%20%20%20%20%20%20const%20start%20=%20str.indexOf(prefix);%5Cn%20%20%20%20%20%20if%20(start%20===%20-1)%20return%20null;%5Cn%20%20%20%20%20%20let%20depth%20=%200;%5Cn%20%20%20%20%20%20let%20result%20=%20'';%5Cn%20%20%20%20%20%20for(let%20i%20=%20start%20+%20prefix.length;%20i%20%3C%20str.length;%20i++)%20%7B%5Cn%20%20%20%20%20%20%20%20if(str%5Bi%5D%20===%20'(')%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20depth++;%5Cn%20%20%20%20%20%20%20%20%7D%20else%20if%20(str%5Bi%5D%20===%20')')%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(depth%20===%200)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20break;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%20%20depth--;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20result%20+=%20str%5Bi%5D;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20return%20result;%5Cn%20%20%20%20%7D;%5Cn%20%20%7D%5Cn%20%20if(d.prompt.includes(%5C%22(negativePrompt:::%5C%22))%20%7B%5Cn%20%20%20%20let%20result%20=%20window.___t2i__parseNegativePrompt(d.prompt);%5Cn%20%20%20%20if(result)%20%7B%5Cn%20%20%20%20%20%20d.negativePrompt%20=%20result;%5Cn%20%20%20%20%20%20d.prompt%20=%20d.prompt.replace(%60(negativePrompt:::$%7Bd.negativePrompt%7D)%60,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20d.prompt%20=%20d.prompt.replace(%60(negativePrompt:::$%7Bd.negativePrompt%7D%60,%20%5C%22%5C%22);%20//%20since%20if%20final%20bracket%20is%20missing,%20then%20all%20following%20text%20is%20considered%20the%20negative%20prompt%5Cn%20%20%20%20%7D%5Cn%20%20%20%20d.prompt%20=%20d.prompt.trim();%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(!data.prompt)%20%7B%20//%20they%20passed%20in%20some%20text%20directly%20like%20%5Bimage(%5C%22a%20carrot%5C%22)%5D,%20so%20add%20some%20defaults/fallbacks.%5Cn%20%20%20%20if(d.seed%20===%20undefined)%20d.seed%20=%20-1;%5Cn%20%20%20%20if(d.width%20===%20undefined)%20d.width%20=%20300;%5Cn%20%20%20%20if(d.height%20===%20undefined)%20d.height%20=%20300;%5Cn%20%20%20%20if(d.resolution%20===%20undefined)%20d.resolution%20=%20%5C%22512x512%5C%22;%20%20%20%5Cn%20%20%20%20if(d.guidanceScale%20===%20undefined)%20d.guidanceScale%20=%20defaultGuidanceScale;%5Cn%20%20%20%20if(d.negativePrompt%20===%20undefined)%20d.negativePrompt%20=%20%5C%22%5C%22;%5Cn%20%20%20%20if(d.style%20===%20undefined)%20d.style%20=%20%5C%22%5C%22;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20//%20EDIT:%20Not%20going%20ahead%20with%20this%20for%20now%20in%20favor%20of%20a%20setting%20a%20global%20variable%20which%20contains%20data%20on%20the%20last-used%20prompt.%5Cn%20%20//%20//%20NOTE:%20Originally%20%60data%60%20was%20the%20only%20param%20and%20it%20could%20be%20the%20prompt,%20or%20a%20promptOptions%20object/list.%5Cn%20%20//%20//%20But%20I%20realised%20that%20it's%20not%20very%20ergonomic%20(see%20e.g.%20reddit.com/r/perchance/comments/yta11r),%20so%20now,%20in%20a%20backwards-compatible%20way,%5Cn%20%20//%20//%20I'm%20allowing%20the%20user%20to%20pass%20the%20options%20as%20the%20second%20parameter%20instead.%20This%20just%20means%20that%20if%20data%20is%20a%20prompt%20(rather%20than%20a%5Cn%20%20//%20//%20promptOptions%20object),%20then%20we%20use%20the%20%60options%60%20parameter%20(which%20defaults%20to%20an%20empty%20object)%20for%20the%20generation%20options:%5Cn%20%20//%20if(dataInputWasNotAnOptionsObject)%20%7B%5Cn%20%20//%20%20%20data%20=%20options;%20//%20this%5Cn%20%20//%20%7D%5Cn%20%20%5Cn%20%20if(!d.seed)%20d.seed%20=%20data.seed%20?%20data.seed.evaluateItem%20:%20-1;%5Cn%20%20if(!d.resolution)%20d.resolution%20=%20data.resolution%20?%20data.resolution.evaluateItem%20:%20%5C%22512x512%5C%22;%5Cn%20%20if(!d.guidanceScale)%20d.guidanceScale%20=%20data.guidanceScale%20?%20data.guidanceScale.evaluateItem%20:%20defaultGuidanceScale;%5Cn%20%20if(!d.negativePrompt)%20d.negativePrompt%20=%20data.negativePrompt%20?%20data.negativePrompt.evaluateItem%20:%20%5C%22%5C%22;%5Cn%20%20if(!d.width)%20d.width%20=%20data.width%20?%20data.width.evaluateItem%20:%20undefined;%20%5Cn%20%20if(!d.height)%20d.height%20=%20data.height%20?%20data.height.evaluateItem%20:%20undefined;%20%5Cn%20%20if(!d.style)%20d.style%20=%20data.style%20?%20data.style.evaluateItem%20:%20%5C%22%5C%22;%5Cn%20%20if(!d.saveTitle)%20d.saveTitle%20=%20data.saveTitle%20?%20data.saveTitle.evaluateItem%20:%20%5C%22%5C%22;%5Cn%20%20if(!d.saveDescription)%20d.saveDescription%20=%20data.saveDescription%20?%20data.saveDescription.evaluateItem%20:%20%5C%22%5C%22;%5Cn%20%20%5Cn%20%20%5Cn%20%20//%20NOTE:%20This%20stuff%20is%20not%20longer%20needed%20because%20we%20do%20the%20parsing%20above%20regardless%20of%20whether%20they%20passed%20a%20plain%20string%20in,%20or%20a%20promptOptions%20object.%5Cn%20%20//%20//%20if%20seed%20is%20specified%20within%20the%20prompt%20with%20the%20(key:::value)%20format%20-%20i.e.%20they%20used%20promptOptions%20input%20but%20specified%20the%20seed%20within%20promptOptions.prompt,%20and%20so%20long%20as%20promptOptions.seed%20is%20not%20specified,%20then%20we%20set%20the%20seed%20to%20the%20one%20specified%20in%20the%20prompt:%5Cn%20%20//%20if(data.seed%20===%20undefined%20&&%20d.prompt.includes(%5C%22(seed:::%5C%22))%20%7B%5Cn%20%20//%20%20%20let%20seed%20=%20null;%5Cn%20%20//%20%20%20d.prompt%20=%20d.prompt.replace(/%5C%5C(seed:::(%5B0-9%5D+)%5C%5C)/g,%20(m,%20p1)%20=%3E%20%7B%20seed=Number(p1);%20return%20%5C%22%5C%22;%20%7D);%5Cn%20%20//%20%20%20if(seed)%20%7B%5Cn%20%20//%20%20%20%20%20d.seed%20=%20seed;%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%7D%5Cn%20%20//%20//%20same%20for%20guidanceScale:%5Cn%20%20//%20if(data.guidanceScale%20===%20undefined%20&&%20d.prompt.includes(%5C%22(guidanceScale:::%5C%22))%20%7B%5Cn%20%20//%20%20%20let%20guidanceScale%20=%20null;%5Cn%20%20//%20%20%20d.prompt%20=%20d.prompt.replace(/%5C%5C(guidanceScale:::(%5B0-9%5D+)%5C%5C)/g,%20(m,%20p1)%20=%3E%20%7B%20guidanceScale=Number(p1);%20return%20%5C%22%5C%22;%20%7D);%5Cn%20%20//%20%20%20if(guidanceScale)%20%7B%5Cn%20%20//%20%20%20%20%20d.guidanceScale%20=%20guidanceScale;%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%7D%5Cn%20%20//%20//%20same%20for%20width:%5Cn%20%20//%20if(data.guidanceScale%20===%20undefined%20&&%20d.prompt.includes(%5C%22(width:::%5C%22))%20%7B%5Cn%20%20//%20%20%20let%20width%20=%20null;%5Cn%20%20//%20%20%20d.prompt%20=%20d.prompt.replace(/%5C%5C(width:::(%5B0-9%5D+)%5C%5C)/g,%20(m,%20p1)%20=%3E%20%7B%20width=Number(p1);%20return%20%5C%22%5C%22;%20%7D);%5Cn%20%20//%20%20%20if(width)%20%7B%5Cn%20%20//%20%20%20%20%20d.width%20=%20width;%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%7D%5Cn%20%20//%20//%20same%20for%20height:%5Cn%20%20//%20if(data.guidanceScale%20===%20undefined%20&&%20d.prompt.includes(%5C%22(height:::%5C%22))%20%7B%5Cn%20%20//%20%20%20let%20height%20=%20null;%5Cn%20%20//%20%20%20d.prompt%20=%20d.prompt.replace(/%5C%5C(height:::(%5B0-9%5D+)%5C%5C)/g,%20(m,%20p1)%20=%3E%20%7B%20height=Number(p1);%20return%20%5C%22%5C%22;%20%7D);%5Cn%20%20//%20%20%20if(height)%20%7B%5Cn%20%20//%20%20%20%20%20d.height%20=%20height;%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%7D%5Cn%20%20//%20//%20same%20for%20size:%5Cn%20%20//%20if(data.guidanceScale%20===%20undefined%20&&%20d.prompt.includes(%5C%22(size:::%5C%22))%20%7B%5Cn%20%20//%20%20%20let%20size%20=%20null;%5Cn%20%20//%20%20%20d.prompt%20=%20d.prompt.replace(/%5C%5C(size:::(%5B0-9%5D+)%5C%5C)/g,%20(m,%20p1)%20=%3E%20%7B%20size=Number(p1);%20return%20%5C%22%5C%22;%20%7D);%5Cn%20%20//%20%20%20if(size)%20%7B%5Cn%20%20//%20%20%20%20%20d.size%20=%20size;%5Cn%20%20//%20%20%20%7D%5Cn%20%20//%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20%20%20%20%20sanity%20checks%20on%20inputs%20%20%20%20%20%20%20%20%20%20//%5Cn%20%20////////////////////////////////////////////////%5Cn%20%20%5Cn%20%20if(d.size%20&&%20d.resolution%20&&%20d.resolution.split(%5C%22x%5C%22)%5B0%5D%20!==%20d.resolution.split(%5C%22x%5C%22)%5B1%5D)%20%7B%5Cn%20%20%20%20return%20%60(text-to-image-plugin:%20%3Cb%3Esize%3C/b%3E%20is%20only%20a%20valid%20parameter%20with%20square%20resolutions.%20use%20%3Cb%3Ewidth%3C/b%3E%20and%20%3Cb%3Eheight%3C/b%3E%20instead)%60;%5Cn%20%20%7D%5Cn%5Cn%20%20if(d.guidanceScale%20%3C%201%20%7C%7C%20Math.round(d.guidanceScale)%20!==%20d.guidanceScale)%20%7B%5Cn%20%20%20%20return%20%60(text-to-image-plugin:%20%3Cb%3EguidanceScale%3C/b%3E%20should%20be%20a%20whole%20number%20between%201%20and%2030,%20inclusive)%60;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(!%5B%5C%22512x512%5C%22,%20%5C%22512x768%5C%22,%20%5C%22768x512%5C%22%5D.includes(d.resolution))%20%7B%5Cn%20%20%20%20return%20%5C%22(text-to-image-plugin:%20Currently,%20the%20only%20valid%20resolutions%20are%20512x512,%20512x768%20and%20768x512)%5C%22;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%20%20////////////////////////////////////////////////%5Cn%20%20//%20%20%20%20%20%20%20%20un-shortcut%20size/width/height%20%20%20%20%20%20%20//%5Cn%20%20////////////////////////////////////////////////%5Cn%20%20let%20resW%20=%20Number(d.resolution.split(%5C%22x%5C%22)%5B0%5D);%5Cn%20%20let%20resH%20=%20Number(d.resolution.split(%5C%22x%5C%22)%5B1%5D);%5Cn%20%20let%20widthHeightCss%20=%20%5C%22%5C%22;%5Cn%20%20if(d.size)%20%7B%5Cn%20%20%20%20let%20size%20=%20d.size.evaluateItem;%5Cn%20%20%20%20if(typeof%20size%20===%20%5C%22number%5C%22)%20size%20+=%20%5C%22px%5C%22;%5Cn%20%20%20%20widthHeightCss%20=%20%60width:$%7Bsize%7D%60;%5Cn%20%20%7D%20else%20%7B%5Cn%20%20%20%20if(d.width%20&&%20!d.height)%20%7B%5Cn%20%20%20%20%20%20d.width%20=%20d.width.evaluateItem;%5Cn%20%20%20%20%20%20if(typeof%20d.width%20===%20%5C%22number%5C%22)%20d.width%20+=%20%5C%22px%5C%22;%5Cn%20%20%20%20%20%20widthHeightCss%20=%20%60width:$%7Bd.width%7D%60;%5Cn%20%20%20%20%20%20//%20d.height%20=%20d.width%20*%20(resH/resW);%5Cn%20%20%20%20%7D%20else%20if(!d.width%20&&%20d.height)%20%7B%5Cn%20%20%20%20%20%20d.height%20=%20d.height.evaluateItem;%5Cn%20%20%20%20%20%20if(typeof%20d.height%20===%20%5C%22number%5C%22)%20d.height%20+=%20%5C%22px%5C%22;%5Cn%20%20%20%20%20%20widthHeightCss%20=%20%60height:$%7Bd.height%7D%60;%5Cn%20%20%20%20%20%20//%20d.width%20=%20d.height%20*%20(resW/resH);%5Cn%20%20%20%20%7D%20else%20if(!d.width%20&&%20!d.height)%20%7B%5Cn%20%20%20%20%20%20//%20make%20the%20smallest%20side%20300px%20by%20default:%5Cn%20%20%20%20%20%20if(resW%20%3E%20resH)%20%7B%5Cn%20%20%20%20%20%20%20%20d.height%20=%20300;%5Cn%20%20%20%20%20%20%20%20widthHeightCss%20=%20%60height:$%7Bd.height%7Dpx%60;%5Cn%20%20%20%20%20%20%20%20//%20d.width%20=%20d.height%20*%20(resW/resH);%5Cn%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20d.width%20=%20300;%5Cn%20%20%20%20%20%20%20%20widthHeightCss%20=%20%60width:$%7Bd.width%7Dpx%60;%5Cn%20%20%20%20%20%20%20%20//%20d.height%20=%20d.width%20*%20(resH/resW);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%20else%20if(d.width%20&&%20d.height)%20%7B%5Cn%20%20%20%20%20%20if(typeof%20d.width%20===%20%5C%22number%5C%22)%20d.width%20+=%20%5C%22px%5C%22;%5Cn%20%20%20%20%20%20if(typeof%20d.height%20===%20%5C%22number%5C%22)%20d.height%20+=%20%5C%22px%5C%22;%5Cn%20%20%20%20%20%20widthHeightCss%20=%20%60width:$%7Bd.width%7D;%20height:$%7Bd.height%7D%60;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20if(d.style%20&&%20/%5B;%5C%5Cs%5D?(width%7Cheight):/.test(d.style))%20widthHeightCss%20=%20%5C%22%5C%22;%5Cn%20%20%5Cn%20%20if(!CSS.supports(%5C%22aspect-ratio%5C%22,%20%5C%221/2%5C%22))%20%7B%20//%20hackily%20help%20old%20browsers%20that%20don't%20support%20aspect-ratio%20if%20possible%5Cn%20%20%20%20let%20width%20=%20(widthHeightCss.match(/width:(%5B%5E;%5D+)px;?/)%20%7C%7C%20%5B%5D)%5B1%5D;%5Cn%20%20%20%20if(width%20&&%20!widthHeightCss.includes(%5C%22height%5C%22)%20&&%20!isNaN(Number(width)))%20%7B%5Cn%20%20%20%20%20%20widthHeightCss%20+=%20%60;%20height:$%7BNumber(width)%20*%20(resH/resW)%7Dpx;%60;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20let%20height%20=%20(widthHeightCss.match(/height:(%5B%5E;%5D+)px;?/)%20%7C%7C%20%5B%5D)%5B1%5D;%5Cn%20%20%20%20if(height%20&&%20!widthHeightCss.includes(%5C%22width%5C%22)%20&&%20!isNaN(Number(height)))%20%7B%5Cn%20%20%20%20%20%20widthHeightCss%20+=%20%60;%20width:$%7BNumber(height)%20*%20(resW/resH)%7Dpx;%60;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20requestId%20=%20Math.random().toString();%5Cn%20%20let%20privateIframeId%20=%20%5C%22id%5C%22%20+%20Math.random().toString().replace(%5C%22.%5C%22,%20%5C%22%5C%22);%5Cn%20%20%5Cn%20%20//%20let%20iframePromiseResolver;%5Cn%20%20//%20let%20iframePromise%20=%20new%20Promise(r%20=%3E%20iframePromiseResolver=r);%5Cn%20%20//%20let%20canvasPromiseResolver;%5Cn%20%20//%20let%20canvasPromise%20=%20new%20Promise(r%20=%3E%20canvasPromiseResolver=r);%5Cn%20%20//%20let%20dataUrlPromiseResolver;%5Cn%20%20//%20let%20dataUrlPromise%20=%20new%20Promise(r%20=%3E%20dataUrlPromiseResolver=r);%5Cn%20%20let%20onFinishPromiseResolver;%5Cn%20%20let%20onFinishPromise%20=%20new%20Promise(r%20=%3E%20onFinishPromiseResolver=r);%5Cn%20%20%5Cn%20%20window.addEventListener('message',%20async%20function(event)%20%7B%5Cn%20%20%20%20if(event.data.type%20===%20'finished'%20&&%20event.data.id%20===%20privateIframeId)%20%7B%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20function%20drawDataURLToCanvas(dataURL)%20%7B%5Cn%20%20%20%20%20%20%20%20return%20new%20Promise((resolve,%20reject)%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20const%20canvas%20=%20document.createElement(%5C%22canvas%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20const%20ctx%20=%20canvas.getContext(%5C%222d%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20const%20img%20=%20new%20Image();%5Cn%20%20%20%20%20%20%20%20%20%20img.onload%20=%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20canvas.width%20=%20img.width;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20canvas.height%20=%20img.height;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20ctx.drawImage(img,%200,%200);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20resolve(canvas);%5Cn%20%20%20%20%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%20%20%20%20%20%20img.src%20=%20dataURL;%5Cn%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%7D%5Cn%5Cn%20%20%20%20%20%20let%20canvas%20=%20await%20drawDataURLToCanvas(event.data.dataUrl);%5Cn%20%20%20%20%20%20let%20iframe%20=%20document.querySelector(%60iframe.$%7BprivateIframeId%7D%60);%20//%20NOTE:%20may%20be%20null%20if%20it%20has%20been%20removed!%20(todo:%20keep%20original%20reference%20around%20instead%20of%20querySelector?)%5Cn%20%20%20%20%20%20let%20dataUrl%20=%20event.data.dataUrl;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20outputData%20=%20new%20String(dataUrl);%5Cn%20%20%20%20%20%20outputData.canvas%20=%20canvas;%5Cn%20%20%20%20%20%20outputData.iframe%20=%20iframe;%5Cn%20%20%20%20%20%20outputData.dataUrl%20=%20dataUrl;%5Cn%20%20%20%20%20%20outputData.inputs%20=%20evaluatedInputs;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(iframe)%20iframe.textToImagePluginOutput%20=%20outputData;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(shouldRemoveIframeOnFinish)%20%7B%5Cn%20%20%20%20%20%20%20%20delete%20outputData.iframe;%5Cn%20%20%20%20%20%20%20%20iframe.remove();%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(data.onFinish)%20%7B%5Cn%20%20%20%20%20%20%20%20data.onFinish(outputData);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20onFinishPromiseResolver(outputData);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20EDIT:%20This%20is%20no%20longer%20needed%20-%20the%20fix%20is%20now%20within%20the%20iframe%20-%20basically%20just%20awaits%20a%20requestAnimationFrame%20before%20and%20after%20hiding%20the%20%5C%22Processing%5C%22%20facade.%5Cn%20%20%20%20%20%20//%20hack%20to%20fix%20weird%20bug%20in%20Windows%20causing%20iframe%20rendering%20to%20not%20update%20once%20image%20is%20done%20(stays%20on%20%5C%22Processing%5C%22%20frame,%20but%20weirdly%20with%20spinner%20still%20going):%5Cn%20%20%20%20%20%20//%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20//%20%20%20let%20originalTop%20=%20iframe.style.top;%5Cn%20%20%20%20%20%20//%20%20%20let%20originalPosition%20=%20iframe.style.position;%5Cn%20%20%20%20%20%20//%20%20%20let%20originalOffsetTop%20=%20iframe.offsetTop;%5Cn%20%20%20%20%20%20//%20%20%20iframe.style.top%20=%20%5C%221px%5C%22;%5Cn%20%20%20%20%20%20//%20%20%20iframe.style.position%20=%20%5C%22relative%5C%22;%5Cn%20%20%20%20%20%20//%20%20%20let%20waitedMs%20=%200;%5Cn%20%20%20%20%20%20//%20%20%20while(iframe.offsetTop%20===%20originalOffsetTop)%20%7B%5Cn%20%20%20%20%20%20//%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%202));%5Cn%20%20%20%20%20%20//%20%20%20%20%20waitedMs%20+=%202;%5Cn%20%20%20%20%20%20//%20%20%20%20%20if(waitedMs%20%3E%201000)%20break;%5Cn%20%20%20%20%20%20//%20%20%20%7D%5Cn%20%20%20%20%20%20//%20%20%20iframe.style.top%20=%20originalTop;%5Cn%20%20%20%20%20%20//%20%20%20iframe.style.position%20=%20originalPosition;%5Cn%20%20%20%20%20%20//%20%7D,%201);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20//%20dataUrlPromiseResolver(event.data.dataUrl);%5Cn%20%20%20%20%20%20//%20canvasPromiseResolver(canvas);%5Cn%20%20%20%20%20%20//%20iframePromiseResolver(document.querySelector(%60iframe.$%7BprivateIframeId%7D%60));%5Cn%20%20%20%20%7D%5Cn%20%20%7D);%5Cn%20%20%5Cn%20%20function%20blobToDataUrl(blob)%20%7B%5Cn%20%20%20%20return%20new%20Promise(r%20=%3E%20%7B%5Cn%20%20%20%20%20%20const%20reader%20=%20new%20FileReader();%5Cn%20%20%20%20%20%20reader.onload%20=%20()%20=%3E%20r(reader.result);%5Cn%20%20%20%20%20%20reader.readAsDataURL(blob);%5Cn%20%20%20%20%7D);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20referenceImage%20=%20null;%5Cn%20%20if(data.referenceImage)%20%7B%5Cn%20%20%20%20referenceImage%20=%20%7B%7D;%5Cn%20%20%20%20//%20url%20can%20actually%20be%20a%20blob%20or%20a%20blob%20URL,%20in%20which%20case%20we%20postMessage%20the%20data%20to%20the%20iframe%5Cn%20%20%20%20let%20isBlobby%20=%20data.referenceImage.url%20instanceof%20Blob;%20//%20blobby%20means%20Blob%20or%20blob%20URL%20string%5Cn%20%20%20%20let%20url,%20blobby;%5Cn%20%20%20%20%5Cn%20%20%20%20if(isBlobby)%20blobby%20=%20data.referenceImage.url;%5Cn%20%20%20%20else%20url%20=%20data.referenceImage.url.evaluateItem;%5Cn%20%20%20%20%5Cn%20%20%20%20if(url.startsWith(%5C%22blob:%5C%22))%20%7B%5Cn%20%20%20%20%20%20isBlobby%20=%20true;%5Cn%20%20%20%20%20%20blobby%20=%20url;%5Cn%20%20%20%20%20%20url%20=%20null;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20if(isBlobby)%20%7B%5Cn%20%20%20%20%20%20referenceImage.url%20=%20%5C%22%3Cdata-via-postmessage%3E%5C%22;%5Cn%20%20%20%20%20%20(async%20()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20let%20blob;%5Cn%20%20%20%20%20%20%20%20if(typeof%20blobby%20===%20%5C%22string%5C%22%20&&%20blobby.startsWith(%5C%22blob:%5C%22))%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20blob%20=%20await%20fetch(blobby).then(r%20=%3E%20r.blob());%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20blob%20=%20blobby;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20let%20dataUrl%20=%20await%20blobToDataUrl(blob);%5Cn%20%20%20%20%20%20%20%20window.addEventListener('message',%20function(event)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20if(event.data.type%20===%20'readyForData'%20&&%20event.data.id%20===%20privateIframeId)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20document.querySelector(%60iframe.$%7BprivateIframeId%7D%60).contentWindow.postMessage(%7Bid:privateIframeId,%20referenceImageDataUrl:dataUrl%7D,%20serverOrigin);%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20%7D)();%5Cn%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20referenceImage.url%20=%20url;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20referenceImage.blur%20=%20data.referenceImage.blur.evaluateItem;%5Cn%20%20%20%20if(referenceImage.url%20%3E%201%20%7C%7C%20referenceImage.url%20%3C%200)%20return%20%60referenceImage.url%20must%20either%20be%20a%20'data%20URL'%20(starting%20with%20'data:')%20or%20a%20https://user-uploads.perchance.org%20URL%20-%20i.e.%20an%20image%20that%20has%20been%20uploaded%20to%20https://perchance.org/upload%20-%20the%20URL%20you've%20used%20is:%20'$%7BreferenceImage.url%20&&%20typeof%20referenceImage.url%20===%20%5C%22string%5C%22%20&&%20referenceImage.url.length%20%3E%2030%20?%20referenceImage.url.slice(0,%2030)+%5C%22...%5C%22%20:%20referenceImage.url%7D'.%60;%5Cn%20%20%20%20if(referenceImage.blur%20%3E%201%20%7C%7C%20referenceImage.blur%20%3C%200)%20return%20%60referenceImage.blur%20must%20be%20between%200%20and%201,%20but%20is%20instead%20'$%7BreferenceImage.blur%20%3E%201%7D'.%60%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20window.addEventListener('message',%20function(event)%20%7B%5Cn%20%20%20%20if(event.data.type%20===%20'readyForData'%20&&%20event.data.id%20===%20privateIframeId)%20%7B%5Cn%20%20%20%20%20%20let%20iframe%20=%20document.querySelector(%60iframe.$%7BprivateIframeId%7D%60);%5Cn%20%20%20%20%20%20if(iframe)%20iframe.contentWindow.postMessage(%7Btype:%5C%22originNotify%5C%22,%20frameId:privateIframeId%7D,%20serverOrigin);%5Cn%20%20%20%20%7D%5Cn%20%20%7D);%5Cn%20%20%5Cn%20%20let%20urlHashData%20=%20%7B%5Cn%20%20%20%20saveChannel:%20window.generatorName,%5Cn%20%20%20%20saveTitle:%20d.saveTitle,%5Cn%20%20%20%20saveDescription:%20d.saveDescription,%5Cn%20%20%20%20prompt:%20d.prompt,%5Cn%20%20%20%20seed:%20d.seed,%5Cn%20%20%20%20resolution:%20d.resolution,%5Cn%20%20%20%20guidanceScale:%20d.guidanceScale,%5Cn%20%20%20%20defaultGuidanceScale,%5Cn%20%20%20%20negativePrompt:%20d.negativePrompt,%5Cn%20%20%20%20requestId:%20requestId,%5Cn%20%20%20%20forceColorScheme:%20data.forceColorScheme,%5Cn%20%20%20%20verifyOnly:%20data.verifyOnly,%5Cn%20%20%20%20iframeId:%20privateIframeId,%5Cn%20%20%20%20hideGalleryButtons:%20data.hideGalleryButtons,%5Cn%20%20%20%20referenceImage,%5Cn%20%20%7D;%5Cn%20%20%5Cn%20%20//%20clone%20input%20for%20onFinish%20data:%5Cn%20%20evaluatedInputs%20=%20JSON.parse(JSON.stringify(d));%5Cn%20%20%5Cn%20%20let%20iframeId%20=%20data.id%20?%20data.id.evaluateItem%20:%20%5C%22%5C%22;%5Cn%20%20if(iframeId)%20%7B%5Cn%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20document.querySelector(%5C%22#%5C%22+iframeId).reload%20=%20function()%20%7B%5Cn%20%20%20%20%20%20%20%20let%20src%20=%20this.src;%5Cn%20%20%20%20%20%20%20%20this.src%20=%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20setTimeout(()%20=%3Ethis.src=src,%20700);%5Cn%20%20%20%20%20%20%7D;%5Cn%20%20%20%20%7D,%20500);%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20window.lastTextToImagePrompt%20=%20d.prompt;%5Cn%20%20if(data.prompt)%20%7B%20//%20%3C--%20i.e.%20if%20they%20passed%20a%20promptOptions%20object%5Cn%20%20%20%20data.lastUsedPrompt%20=%20d.prompt;%5Cn%20%20%20%20data.lastUsedNegativePrompt%20=%20d.negativePrompt;%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20//%20VERY%20lazily%20load%20the%20iframe%20(only%20when%20screen%20actually%20intersects)%20because%20some%20people%20add%20a%20lot%20of%20images%20in%20subsections%20and%20in%20several%20different%20tabs%20of%20tabs-plugin,%20etc.%5Cn%20%20//%20This%20ensures%20they%20don't%20spam%20the%20server,%20and%20the%20visible%20ones%20get%20generated%20first.%5Cn%20%20setTimeout(async%20()%20=%3E%20%7B%5Cn%20%20%20%20//%20the%20dev%20may%20have%20generated%20the%20HTML,%20but%20not%20actually%20added%20it%20to%20the%20DOM%20for%20a%20while,%20so%20we%20wait%20up%20to%205%20mins%20for%20it%5Cn%20%20%20%20let%20waitedSeconds%20=%200;%5Cn%20%20%20%20while(%5B...document.querySelectorAll(%5C%22.text-to-image-plugin-image-iframe%5C%22)%5D.filter(el%20=%3E%20el.dataset.alreadyAddedIntersectionObserver%20===%20%5C%22no%5C%22).length%20===%200)%20%7B%5Cn%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20%20%20waitedSeconds%20+=%200.5;%5Cn%20%20%20%20%20%20if(waitedSeconds%20%3E%2060*5)%20return;%5Cn%20%20%20%20%7D%5Cn%20%20%20%20for(let%20el%20of%20%5B...document.querySelectorAll(%5C%22.text-to-image-plugin-image-iframe%5C%22)%5D)%20%7B%5Cn%20%20%20%20%20%20if(el.dataset.alreadyAddedIntersectionObserver%20===%20%5C%22yes%5C%22)%20continue;%5Cn%20%20%20%20%20%20el.dataset.alreadyAddedIntersectionObserver%20=%20%5C%22yes%5C%22;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20observer1,%20observer2;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20rootMarginSize%20=%20Math.min(1000,%20(window.innerHeight*2));%5Cn%20%20%20%20%20%20if(window.innerWidth%20%3C%20600)%20%7B%5Cn%20%20%20%20%20%20%20%20rootMarginSize%20=%20Math.min(1500,%20(window.innerHeight*3));%20//%20larger%20on%20mobile%20because%20e.g.%20images%20that%20might%20otherwise%20be%20displayed%20side%20by%20side%20are%20instead%20displayed%20vertically%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20function%20handler(entries)%20%7B%5Cn%20%20%20%20%20%20%20%20if(entries%5B0%5D.isIntersecting)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20console.debug(%5C%22t2i%20iframe:%20Visible%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20if(!el.src)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20el.removeAttribute(%5C%22srcdoc%5C%22);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20el.src%20=%20el.dataset.src;%5Cn%20%20%20%20%20%20%20%20%20%20%20%20observer1.disconnect();%5Cn%20%20%20%20%20%20%20%20%20%20%20%20observer2.disconnect();%20%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20//%20console.debug(%5C%22t2i%20iframe:%20NOT%20Visible%5C%22);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20observer1%20=%20new%20IntersectionObserver(handler,%20%7B%5Cn%20%20%20%20%20%20%20%20root:%20document.documentElement,%20//%20otherwise%20I%20think%20it%20uses%20the%20top-level%20viewport?%20either%20way,%20it%20doesn't%20seem%20to%20work%20without%20specifying%20this.%5Cn%20%20%20%20%20%20%20%20rootMargin:%20rootMarginSize+%5C%22px%5C%22,%20//%20it's%20important%20that%20this%20is%20quite%20big%20-%20so%20that%20e.g.%20mobile%20users%20don't%20have%20to%20scroll%20down%20to%20trigger%20stuff.%20we%20basically%20want%20to%20trigger%20~all%20visible%20elements%20anyway%20-%20just%20not%20stuff%20hidden%20within%20e.g.%20tabs%20plugin%20or%20whatever.%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20observer1.observe(el);%5Cn%20%20%20%20%20%20//%20for%20some%20reason,%20in%20some%20situations,%20the%20above%20intersection%20observer%20was%20reporting%20the%20%60root%60%20and%20%60el%60%20bounding%20rects%20as%200x0x0x0.%20Adding%20a%20second%20observer%20using%20the%20viewport%20root%20fixes%20this:%5Cn%20%20%20%20%20%20observer2%20=%20new%20IntersectionObserver(handler,%20%7B%5Cn%20%20%20%20%20%20%20%20rootMargin:%20rootMarginSize+%5C%22px%5C%22,%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%20%20observer2.observe(el);%5Cn%20%20%20%20%7D%5Cn%20%20%7D,%20100);%20//%20CAUTION:%20do%20not%20remove/lower%20this%20delay.%20Some%20generators%20may%20create%20a%20large%20%5C%22feed%5C%22%20of%20images,%20and%20expect%20them%20to%20be%20lazy-loaded%20when%20scrolled%20to%20(e.g.%20AI%20chat%20feeds),%20so%20if%20you%20add%20the%20intersection%20observers%20~synchronously,%20they%20could%20be%20triggered%20during%20the%20process%20of%20actually%20generating%20the%20feed,%20which%20would%20cause%20them%20to%20all%20start%20generating%20during%20page%20load.%5Cn%20%20%5Cn%20%20//%20let%20outputString%20=%20new%20String(%60%3Ciframe%20$%7BiframeId%20?%20%60id=%5C%22$%7BiframeId%7D%5C%22%60%20:%20%5C%22%5C%22%7D%20class=%5C%22text-to-image-plugin-image-iframe%20$%7BprivateIframeId%7D%5C%22%20data-already-added-intersection-observer=%5C%22no%5C%22%20data-src=%5C%22$%7BserverOrigin%7D/embed#$%7BencodeURIComponent(JSON.stringify(urlHashData))%7D%5C%22%20style=%5C%22border:0;%20background:transparent;%20$%7BwidthHeightCss%7D;%20aspect-ratio:$%7BresW%7D/$%7BresH%7D;%20$%7Bd.style%7D%5C%22%3E%3C/iframe%3E%60);%5Cn%20%20//%20//%20leaving%20these%20out%20for%20now%20in%20favor%20of%20'onFinish'%20in%20prompt%20options%5Cn%20%20//%20//%20outputString.dataUrl%20=%20dataUrlPromise;%5Cn%20%20//%20//%20outputString.canvas%20=%20canvasPromise;%5Cn%20%20//%20outputString.onFinishPromise%20=%20onFinishPromise;%5Cn%20%20//%20outputString.iframeHtml%20=%20outputString;%5Cn%20%20//%20return%20outputString;%5Cn%20%20%5Cn%20%20//%20we%20return%20the%20promise%20which%20stringifies%20into%20the%20iframe%20html,%20we%20can%20write%20%5BtextToImage(promptOptions)%5D%20and%20while%20also%20being%20able%20to%20write%20%60let%20result%20=%20await%20textToImage(promptOptions);%60%5Cn%20%20let%20outputString%20=%20%60%3Ciframe%20$%7BiframeId%20?%20%60id=%5C%22$%7BiframeId%7D%5C%22%60%20:%20%5C%22%5C%22%7D%20class=%5C%22text-to-image-plugin-image-iframe%20$%7BprivateIframeId%7D%5C%22%20data-already-added-intersection-observer=%5C%22no%5C%22%20data-src=%5C%22$%7BserverOrigin%7D/embed#$%7BencodeURIComponent(JSON.stringify(urlHashData))%7D%5C%22%20style=%5C%22border:0;%20background:transparent;%20$%7BwidthHeightCss%7D;%20aspect-ratio:$%7BresW%7D/$%7BresH%7D;%20$%7Bd.style%7D%5C%22%3E%3C/iframe%3E%60;%5Cn%20%20let%20outputStringHasBeenRead%20=%20false;%5Cn%20%20onFinishPromise.toString%20=%20function()%20%7B%5Cn%20%20%20%20outputStringHasBeenRead%20=%20true;%5Cn%20%20%20%20return%20outputString;%5Cn%20%20%7D;%5Cn%20%20//%20onFinishPromise.iframeHtml%20=%20outputString;%5Cn%20%20Object.defineProperty(onFinishPromise,%20'iframeHtml',%20%7B%5Cn%20%20%20%20get:%20function()%20%7B%5Cn%20%20%20%20%20%20outputStringHasBeenRead%20=%20true;%5Cn%20%20%20%20%20%20return%20outputString;%5Cn%20%20%20%20%7D%5Cn%20%20%7D);%5Cn%20%20Object.defineProperty(onFinishPromise,%20'evaluateItem',%20%7B%5Cn%20%20%20%20get:%20function()%20%7B%5Cn%20%20%20%20%20%20outputStringHasBeenRead%20=%20true;%5Cn%20%20%20%20%20%20return%20outputString;%5Cn%20%20%20%20%7D%5Cn%20%20%7D);%5Cn%20%20onFinishPromise.onFinishPromise%20=%20onFinishPromise;%5Cn%20%20%5Cn%20%20//%20trigger%20the%20loading%20automatically%20if%20they%20haven't%20added%20the%20iframe%20to%20the%20document:%5Cn%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20if(!outputStringHasBeenRead%20&&%20!iframeId%20&&%20!document.querySelector(%60.$%7BprivateIframeId%7D%60))%20%7B%5Cn%20%20%20%20%20%20shouldRemoveIframeOnFinish%20=%20true;%5Cn%20%20%20%20%20%20let%20div%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20div.innerHTML%20=%20outputString.replace(%60data-already-added-intersection-observer=%5C%22no%5C%22%60,%20%5C%22%5C%22);%5Cn%20%20%20%20%20%20let%20iframe%20=%20div.firstElementChild;%5Cn%20%20%20%20%20%20iframe.style.cssText%20=%20%60opacity:0;%20pointer-events:none;%20position:fixed;%20top:0;%20left:0;%60;%5Cn%20%20%20%20%20%20document.body.append(iframe);%5Cn%20%20%20%20%20%20iframe.src%20=%20iframe.dataset.src;%5Cn%20%20%20%20%7D%5Cn%20%20%7D,%20150);%20//%20this%20should%20be%20longer%20than%20100ms%20for%20backward-compat%20because%20then%20it%20runs%20after%20the%20intersection%20observer%20is%20added,%20which%20means%20it%20wouldn't%20have%20loaded%20anyway,%20so%20it%20guards%20against%20the%20case%20where%20they're%20just%20a%20bit%20slow%20to%20add%20it%20to%20the%20HTML%20doc.%5Cn%20%20%5Cn%20%20return%20onFinishPromise;%5Cn%5Cn%5Cncharacter%5Cn%20%20a%20%7Bmech%7Cdemon%7Ccyberpunk%7D%20%7Bwarrior%7Cminion%7Csamurai%7D%5Cn%5Cnplace%5Cn%20%20soviet%20russia%5Cn%20%20a%20small%20village%5Cn%20%20a%20mountainous%20region%5Cn%20%20an%20underwater%20cavern%5Cn%5Cnseason%5Cn%20%20winter%5Cn%20%20summer%5Cn%20%20%5Cnprompt%5Cn%20%20detailed%20painting%20of%20%5Bcharacter%5D%20in%20%5Bplace%5D,%20%5Bseason%5D%5Cn%20%20%5Cn%20%20%5Cn%20%20%5Cn%22,%22imports%22:%5B%5D,%22lastEditTime%22:1731146130955,%22found%22:true%7D,%7B%22name%22:%22upload-plugin%22,%22modelText%22:%22$output(data,%20opts)%20=%3E%5Cn%20%20if(!opts)%20opts%20=%20%7B%7D;%5Cn%20%20//%20if(typeof%20data%20!==%20%5C%22string%5C%22)%20return%20alert(%5C%22error:%20only%20text/strings%20are%20supported%20by%20the%20upload%20plugin%20for%20now.%20please%20request%20other%20types%20on%20the%20forum.%5C%22);%5Cn%20%20%5Cn%20%20if(!window.__alreadyLoadedUploadPluginStuff0435342908)%20%7B%5Cn%20%20%20%20window.__alreadyLoadedUploadPluginStuff0435342908%20=%20true;%5Cn%20%20%20%20%5Cn%20%20%20%20window.__uploadPluginIframe0435342908%20=%20document.createElement('iframe');%20%5Cn%5Cn%20%20%20%20window.addEventListener('message',%20(event)%20=%3E%20%7B%5Cn%20%20%20%20%20%20if(event.source%20!==%20window.__uploadPluginIframe0435342908.contentWindow)%20return;%5Cn%20%20%20%20%20%20if(event.origin%20!==%20%5C%22https://upload.perchance.org%5C%22)%20return;%5Cn%20%20%20%20%20%20console.log(%5C%22upload%20plugin%20got%20message:%5C%22,%20event);%5Cn%5Cn%20%20%20%20%20%20if(event.data.type%20===%20%5C%22uploadEmbedIsReady%5C%22)%20%7B%20%20%20%5Cn%20%20%20%20%20%20%20%20window.__uploadPluginEmbedIsReady%20=%20true;%5Cn%20%20%20%20%20%20%20%20console.log(%5C%22upload%20plugin%20embedIsReady%5C%22);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D);%5Cn%5Cn%20%20%20%20function%20initIframeAttributes(iframe)%20%7B%5Cn%20%20%20%20%20%20//%20email==false%20implies%20anon%20upload%5Cn%20%20%20%20%20%20iframe.src%20=%20%60https://upload.perchance.org/embed#$%7BJSON.stringify(%7Bemail:false,%20sessionToken:false%7D)%7D%60;%5Cn%20%20%20%20%20%20iframe.style.cssText%20=%20'width:1px;%20height:1px;%20border:none;%20top:-100px;%20left:-100px;%20position:fixed;';%5Cn%20%20%20%20%7D%5Cn%20%20%20%20initIframeAttributes(window.__uploadPluginIframe0435342908);%5Cn%20%20%20%20document.body.appendChild(window.__uploadPluginIframe0435342908);%5Cn%5Cn%20%20%20%20//%20ping%20embed%20until%20it%20is%20ready%20(hacky%20way%20to%20wait%20for%20it%20to%20load)%5Cn%20%20%20%20(async%20function()%20%7B%5Cn%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20%20%20let%20waitedTime%20=%200;%5Cn%20%20%20%20%20%20while(!window.__uploadPluginEmbedIsReady)%20%7B%5Cn%20%20%20%20%20%20%20%20if(waitedTime%20%3E%201000*20)%20%7B%20//%20if%20we've%20waited%20too%20long%20(perhaps%20due%20to%20upload%20server%20error%20response),%20try%20deleting%20the%20iframe%20and%20adding%20it%20again%5Cn%20%20%20%20%20%20%20%20%20%20window.__uploadPluginIframe0435342908.remove();%5Cn%20%20%20%20%20%20%20%20%20%20window.__uploadPluginIframe0435342908%20=%20document.createElement('iframe');%5Cn%20%20%20%20%20%20%20%20%20%20initIframeAttributes(window.__uploadPluginIframe0435342908);%5Cn%20%20%20%20%20%20%20%20%20%20document.body.appendChild(window.__uploadPluginIframe0435342908);%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20500));%5Cn%20%20%20%20%20%20%20%20waitedTime%20+=%20500;%5Cn%20%20%20%20%20%20%20%20window.__uploadPluginIframe0435342908.contentWindow.postMessage(%7Btype:%5C%22init%5C%22%7D,%20'https://upload.perchance.org');%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D)();%5Cn%20%20%7D%5Cn%20%20%5Cn%20%20let%20requestId%20=%20%5C%22id%5C%22+(Math.random().toString()+Math.random().toString()).replaceAll(%5C%22.%5C%22,%20%5C%22%5C%22);%5Cn%20%20%5Cn%20%20let%20promiseResolver,%20promiseRejecter;%5Cn%20%20let%20promise%20=%20new%20Promise((resolve,%20reject)%20=%3E%20%7B%5Cn%20%20%20%20promiseResolver%20=%20resolve;%5Cn%20%20%20%20promiseRejecter%20=%20reject;%20//%20unused.%5Cn%20%20%7D);%5Cn%20%20%5Cn%20%20function%20messageHandler(event)%20%7B%5Cn%20%20%20%20if(event.source%20!==%20window.__uploadPluginIframe0435342908.contentWindow)%20return;%5Cn%20%20%20%20if(event.origin%20!==%20%5C%22https://upload.perchance.org%5C%22)%20return;%5Cn%5Cn%20%20%20%20if(event.data.type%20===%20%5C%22anonUploadResponse%5C%22%20&&%20event.data.requestId%20===%20requestId)%20%7B%5Cn%20%20%20%20%20%20let%20url%20=%20event.data.result.url;%5Cn%20%20%20%20%20%20let%20error%20=%20event.data.result.error;%5Cn%20%20%20%20%20%20let%20message%20=%20event.data.result.message;%5Cn%20%20%20%20%20%20let%20size%20=%20event.data.result.size;%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20if(!error)%20error%20=%20null;%20//%20just%20make%20sure%20it's%20null%20rather%20than%20'undefined',%20since%20that's%20part%20of%20the%20specified%20behavior%5Cn%20%20%20%20%20%20promiseResolver(%7Burl,%20error,%20size%7D);%20//%20always%20'resolve'%20(i.e.%20we%20don't%20%60reject%60%20on%20error).%20easier%20for%20people%20to%20handle%20errors%20without%20knowing%20about%20try/catch%20stuff%20-%20they%20just%20check%20if%20%60error%60%20is%20null%5Cn%20%20%20%20%20%20window.removeEventListener('message',%20messageHandler);%5Cn%20%20%20%20%20%20%5Cn%20%20%20%20%20%20let%20el%20=%20document.querySelector(%60#$%7BrequestId%7D%60);%5Cn%20%20%20%20%20%20if(el)%20%7B%5Cn%20%20%20%20%20%20%20%20if(error)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20el.innerHTML%20=%20error;%5Cn%20%20%20%20%20%20%20%20%7D%20else%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20el.innerHTML%20=%20%60%3Ca%20href=%5C%22$%7Burl%7D%5C%22%20target=%5C%22_blank%5C%22%3E$%7Burl%7D%3C/a%3E%60;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20if(error)%20%7B%5Cn%20%20%20%20%20%20%20%20let%20div%20=%20document.createElement(%5C%22div%5C%22);%5Cn%20%20%20%20%20%20%20%20let%20errorMessageHtml%20=%20message%20?%20%60%20($%7Bmessage%7D)%60%20:%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20%20%20div.innerHTML%20=%20%60%3Cdiv%20style=%5C%22z-index:1000;%20position:%20fixed;%20bottom:%201rem;%20width:%20100%25;%20pointer-events:none;%5C%22%3E%3Cspan%20style=%5C%22%20padding:%200.5rem;%20background:%20#ac2c2c;%20border-radius:%203px;%20color:%20white;%20pointer-events:auto;%5C%22%3Eupload%20error:%20$%7Berror.replaceAll(%5C%22_%5C%22,%20%5C%22%20%5C%22)%7D$%7BerrorMessageHtml%7D%3C/span%3E%3C/div%3E%60;%5Cn%20%20%20%20%20%20%20%20div%20=%20div.firstElementChild;%5Cn%20%20%20%20%20%20%20%20document.body.appendChild(div);%5Cn%20%20%20%20%20%20%20%20setTimeout(()%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20div.remove();%5Cn%20%20%20%20%20%20%20%20%7D,%201000*5);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%20%20window.addEventListener('message',%20messageHandler);%5Cn%20%20%5Cn%20%20(async%20function()%20%7B%5Cn%20%20%20%20while(!window.__uploadPluginEmbedIsReady)%20%7B%5Cn%20%20%20%20%20%20console.log(%5C%22waiting%20for%20upload%20iframe%20embed%20to%20be%20ready%5C%22);%5Cn%20%20%20%20%20%20await%20new%20Promise(r%20=%3E%20setTimeout(r,%20100));%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20function%20blobToDataUrl(blob)%20%7B%5Cn%20%20%20%20%20%20return%20new%20Promise((resolve,%20_)%20=%3E%20%7B%5Cn%20%20%20%20%20%20%20%20const%20reader%20=%20new%20FileReader();%5Cn%20%20%20%20%20%20%20%20reader.onloadend%20=%20()%20=%3E%20resolve(reader.result);%5Cn%20%20%20%20%20%20%20%20reader.readAsDataURL(blob);%5Cn%20%20%20%20%20%20%7D);%5Cn%20%20%20%20%7D%5Cn%20%20%20%20%5Cn%20%20%20%20let%20dataUrl;%5Cn%20%20%20%20if(typeof%20data%20===%20%5C%22string%5C%22)%20dataUrl%20=%20%60data:text/plain;charset=utf-8,$%7BencodeURIComponent(data)%7D%60;%5Cn%20%20%20%20if(data%20instanceof%20Blob)%20dataUrl%20=%20await%20blobToDataUrl(data);%5Cn%20%20%20%20%5Cn%20%20%20%20window.__uploadPluginIframe0435342908.contentWindow.postMessage(%7Btype:%5C%22anonUploadRequest%5C%22,%20requestId,%20dataUrl,%20expires:opts.expires,%20generatorName:window.generatorName%7D,%20'https://upload.perchance.org');%5Cn%20%20%7D)();%5Cn%20%20%5Cn%20%20promise.toString%20=%20function()%20%7B%5Cn%20%20%20%20return%20%60%3Cspan%20id=%5C%22$%7BrequestId%7D%5C%22%3Euploading...%3C/span%3E%60;%5Cn%20%20%7D;%5Cn%20%20return%20promise;%5Cn%5Cn%5Cn%5Cn%22,%22imports%22:%5B%5D,%22lastEditTime%22:1730327359752,%22found%22:true%7D,%7B%22name%22:%22huge-emoji-list%22,%22modelText%22:%22$output%20=%20https://user-uploads.perchance.org/file/cdf7f21f64fba53bd86d598c5f26a962.txt%5Cn%5Cn//%20The%20reason%20I%20put%20this%20simple%20URL%20into%20its%20own%20generator%20is%20so%20that%20I%20can%20update%20the%20URL%5Cn//%20here%20(e.g.%20when%20I%20add/remove%20emojis)%20and%20the%20update%20automatically%20propagates%20to%20all%20my%20generators.%5Cn%5Cn//%20You%20can%20import%20this%20into%20your%20own%20generator%20by%20putting%20this%20line%20in%20your%20comments%20options:%5Cn//%20%20%20%20customEmojis%20=%20%7Bimport:huge-emoji-list%7D%5Cn//%20But%20do%20note%20that%20I%20may%20add/remove%20emojis%20to%20improve%20the%20list,%20remove%20some%20NSFW%20that%20I%20missed,%20etc.%22,%22imports%22:%5B%5D,%22lastEditTime%22:1730339202589,%22found%22:true%7D%5D</script>
        <script id="imported-generator-names" type="notjs">%5B%22t2i-framework-plugin-v2%22,%22t2i-styles%22,%22ai-text-plugin%22,%22comments-plugin%22,%22fullscreen-button-plugin%22,%22prompt2-plugin%22,%22select-leaf-plugin%22,%22tabbed-comments-plugin-v1%22,%22text-to-image-plugin%22,%22upload-plugin%22,%22huge-emoji-list%22%5D</script>
        <script id="static-meta-data" type="notjs">%7B%22title%22:%22AI%20P%20GEN%20(nsfw,%2018+,%20realistic,%20uncensored,%20free,%20no%20limits)%22,%22description%22:%22Uncensored%20AI%20P%20Generator%20on%20base%20of%20Stable%20Diffusion.%20This%20AI%20Image%20Generator%20can%20generate%20Explicit,%20NSFW,%2018+%20content!%20It's%20Free!%20No%20sign-up!%20No%20limits!%20No%20watermark!%20Fast%20generation!%20Uncensored!%20(Have%20in%20mind%20that%20this%20AI%20P%20Image%20Generator%20can't%20generate%20content%20with%20illegal%20things/themes,%20and%20will%20never%20be%20able%20to!%20Because%20restrictions%20installed%20directly%20on%20Stable%20Diffusion.)%22,%22image%22:%22https://files.catbox.moe/u02cyx.jpg%22%7D</script>
        <script id="this-html-server-render-time" type="notjs">1734173839589</script> 
        
        
        <script>window.generatorPublicId = "d873b020cf1c788608c57afc66b7eb00";</script> 
        <script>window.generatorLastSaveTime = Number(`1700668497715`);</script>
        <script>window.shouldLiftGeneratorHtmlFromEmbed = `false` === "true";</script>


        <script>
          window.currentInterfaceMode = "view"; 

          window.generatorData = window.js0nparse( decodeURI( document.querySelector("#preloaded-generator-data").innerText ) );
          window.generatorName = window.generatorData.name;
          window.generatorCanLinkWithRelFollow = generatorData.canLink; // make it global so the iframe-based description update has access to it.

          window.generatorStaticMetaData = {}; 
          try {
            window.generatorStaticMetaData = window.js0nparse( decodeURI( document.querySelector("#static-meta-data").innerText ) );
          } catch(e) { console.error(e); }

          // For crawlers that don't have es6 support and thus can't execute the iframe:
          if(!window.canExecuteModernJavascript) {
            window.addEventListener("DOMContentLoaded", function() {
              var data = window.generatorData;

              window.document.querySelector("#generator-description").innerHTML = DOMPurify.sanitize(data.outputTemplate, {ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'p', 'div', 'pre', 'button', 'i', 'b', 'a', 'ul', 'li', 'br', 'ol', 'hr', 'span'], ALLOWED_ATTR: ['href']});
              var pre = document.createElement('pre');
              pre.innerText = data.modelText.slice(0, 10000);
              window.document.querySelector("#generator-description").appendChild(pre);
              
              window.document.querySelector("#generator-description").style.cssText = "";

              // EDIT: Removed, since title is hardcoded in HTML now.
              // var h1 = window.document.querySelector("#generator-description h1");
              // if(!h1) h1 = window.document.querySelector("#generator-description h2");
              // if(h1) {
              //   var h1Text = h1.textContent;
              //   if(h1Text !== "Your Generator's Title" && h1Text !== "Minimal Example" && h1Text.indexOf("[") === -1 && h1Text.indexOf("]") === -1) {
              //     document.title = h1Text+" ― Perchance" + (h1Text.toLowerCase().includes("gener") ? "" : " Generator");
              //   }
              // } else {
              //   let title = window.location.pathname.slice(1).split("-").filter(function(a){return a;}).map(function(word){return word[0].toUpperCase()+word.slice(1); }).join(" ");
              //   document.title = title+" ― Perchance" + (title.toLowerCase().includes("gener") ? "" : " Generator");
              // }

              if(!window.generatorCanLinkWithRelFollow) {
                var links = window.document.querySelectorAll("#generator-description a");
                for(var i = 0; i < links.length; i++) {
                  links[i].rel = "nofollow";
                }
              }
            });
          }
        </script>  

        <!-- CODEMIRROR (stylesheets must come before javascript init) -->
        <style>
/* BASICS */

.CodeMirror {
  /* Set height, width, borders, and global font properties here */
  font-family: monospace;
  height: 300px;
  color: black;
  direction: ltr;
}

/* PADDING */

.CodeMirror-lines {
  padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
  padding: 0 4px; /* Horizontal padding of content */
}

.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
  background-color: white; /* The little square between H and V scrollbars */
}

/* GUTTER */

.CodeMirror-gutters {
  border-right: 1px solid #ddd;
  background-color: #f7f7f7;
  white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
  padding: 0 3px 0 5px;
  min-width: 20px;
  text-align: right;
  color: #999;
  white-space: nowrap;
}

.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }

/* CURSOR */

.CodeMirror-cursor {
  border-left: 1px solid black;
  border-right: none;
  width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
  border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
  width: auto;
  border: 0 !important;
  background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
  z-index: 1;
}
.cm-fat-cursor .CodeMirror-line::selection,
.cm-fat-cursor .CodeMirror-line > span::selection, 
.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
.cm-fat-cursor .CodeMirror-line::-moz-selection,
.cm-fat-cursor .CodeMirror-line > span::-moz-selection,
.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
.cm-fat-cursor { caret-color: transparent; }
@-moz-keyframes blink {
  0% {}
  50% { background-color: transparent; }
  100% {}
}
@-webkit-keyframes blink {
  0% {}
  50% { background-color: transparent; }
  100% {}
}
@keyframes blink {
  0% {}
  50% { background-color: transparent; }
  100% {}
}

/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}

.cm-tab { display: inline-block; text-decoration: inherit; }

.CodeMirror-rulers {
  position: absolute;
  left: 0; right: 0; top: -50px; bottom: 0;
  overflow: hidden;
}
.CodeMirror-ruler {
  border-left: 1px solid #ccc;
  top: 0; bottom: 0;
  position: absolute;
}

/* DEFAULT THEME */

.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}

.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}

.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}

.CodeMirror-composing { border-bottom: 2px solid; }

/* Default styles for common addons */

div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}

/* STOP */

/* The rest of this file contains styles related to the mechanics of
   the editor. You probably shouldn't touch them. */

.CodeMirror {
  position: relative;
  overflow: hidden;
  background: white;
}

.CodeMirror-scroll {
  overflow: scroll !important; /* Things will break if this is overridden */
  /* 50px is the magic margin used to hide the element's real scrollbars */
  /* See overflow: hidden in .CodeMirror */
  margin-bottom: -50px; margin-right: -50px;
  padding-bottom: 50px;
  height: 100%;
  outline: none; /* Prevent dragging from highlighting the element */
  position: relative;
  z-index: 0;
}
.CodeMirror-sizer {
  position: relative;
  border-right: 50px solid transparent;
}

/* The fake, visible scrollbars. Used to force redraw during scrolling
   before actual scrolling happens, thus preventing shaking and
   flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
  position: absolute;
  z-index: 6;
  display: none;
  outline: none;
}
.CodeMirror-vscrollbar {
  right: 0; top: 0;
  overflow-x: hidden;
  overflow-y: scroll;
}
.CodeMirror-hscrollbar {
  bottom: 0; left: 0;
  overflow-y: hidden;
  overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
  right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
  left: 0; bottom: 0;
}

.CodeMirror-gutters {
  position: absolute; left: 0; top: 0;
  min-height: 100%;
  z-index: 3;
}
.CodeMirror-gutter {
  white-space: normal;
  height: 100%;
  display: inline-block;
  vertical-align: top;
  margin-bottom: -50px;
}
.CodeMirror-gutter-wrapper {
  position: absolute;
  z-index: 4;
  background: none !important;
  border: none !important;
}
.CodeMirror-gutter-background {
  position: absolute;
  top: 0; bottom: 0;
  z-index: 4;
}
.CodeMirror-gutter-elt {
  position: absolute;
  cursor: default;
  z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }

.CodeMirror-lines {
  cursor: text;
  min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
  /* Reset some styles that the rest of the page might have set */
  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
  border-width: 0;
  background: transparent;
  font-family: inherit;
  font-size: inherit;
  margin: 0;
  white-space: pre;
  word-wrap: normal;
  line-height: inherit;
  color: inherit;
  z-index: 2;
  position: relative;
  overflow: visible;
  -webkit-tap-highlight-color: transparent;
  -webkit-font-variant-ligatures: contextual;
  font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre.CodeMirror-line,
.CodeMirror-wrap pre.CodeMirror-line-like {
  word-wrap: break-word;
  white-space: pre-wrap;
  word-break: normal;
}

.CodeMirror-linebackground {
  position: absolute;
  left: 0; right: 0; top: 0; bottom: 0;
  z-index: 0;
}

.CodeMirror-linewidget {
  position: relative;
  z-index: 2;
  padding: 0.1px; /* Force widget margins to stay inside of the container */
}

.CodeMirror-widget {}

.CodeMirror-rtl pre { direction: rtl; }

.CodeMirror-code {
  outline: none;
}

/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
}

.CodeMirror-measure {
  position: absolute;
  width: 100%;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}

.CodeMirror-cursor {
  position: absolute;
  pointer-events: none;
}
.CodeMirror-measure pre { position: static; }

div.CodeMirror-cursors {
  visibility: hidden;
  position: relative;
  z-index: 3;
}
div.CodeMirror-dragcursors {
  visibility: visible;
}

.CodeMirror-focused div.CodeMirror-cursors {
  visibility: visible;
}

.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }

.cm-searching {
  background-color: #ffa;
  background-color: rgba(255, 255, 0, .4);
}

/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }

@media print {
  /* Hide the cursor when printing */
  .CodeMirror div.CodeMirror-cursors {
    visibility: hidden;
  }
}

/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }

/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }

.CodeMirror-dialog {
  position: absolute;
  left: 0; right: 0;
  background: inherit;
  z-index: 15;
  padding: .1em .8em;
  overflow: hidden;
  color: inherit;
}

.CodeMirror-dialog-top {
  border-bottom: 1px solid #eee;
  top: 0;
}

.CodeMirror-dialog-bottom {
  border-top: 1px solid #eee;
  bottom: 0;
}

.CodeMirror-dialog input {
  border: none;
  outline: none;
  background: transparent;
  width: 20em;
  color: inherit;
  font-family: monospace;
}

.CodeMirror-dialog button {
  font-size: 70%;
}
/*
    Name:       one-light 1.0.0
    Author:     Yohan de Rose (https://github.com/yohanderose/)
				-> originally Török Ádám (http://github.com/Aerobird98)
    Original Atom One Dark Theme (https://github.com/atom/one-dark-ui & https://github.com/atom/one-dark-syntax)
*/

/* basic */
.cm-s-one-light {
  font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace;
  /*font-weight: 350;*/
  /*font-size: 18px;*/
  color: #383a42;
  background-color: #fafafa;
}

.cm-s-one-light .CodeMirror-selected {background-color: #d0d1d5;}
.cm-s-one-light .CodeMirror-gutter,
.cm-s-one-light .CodeMirror-gutters {
  border: none;
  background-color: #fafafa;
}

.cm-s-one-light .CodeMirror-linenumber,
.cm-s-one-light .CodeMirror-linenumbers {
  color: #9a9b9f !important;
  background-color: transparent;
}

.cm-s-one-light .CodeMirror-lines {
  color: #383a42 !important;
  background-color: transparent;
}

.cm-s-one-light .CodeMirror-cursor {border-left: 2px solid #0184bb !important;}

/* addon: edit/machingbrackets.js & addon: edit/matchtags.js */
.cm-s-one-light .CodeMirror-matchingbracket,
.cm-s-one-light .CodeMirror-matchingtag {
  border-bottom: 2px solid #0184bb;
  color: #383a42 !important;
  background-color: transparent;
}

.cm-s-one-light .CodeMirror-nonmatchingbracket {
  border-bottom: 2px solid #e45649;
  color: #383a42 !important;
  background-color: transparent;
}

/* addon: fold/foldgutter.js */
.cm-s-one-light .CodeMirror-foldmarker,
.cm-s-one-light .CodeMirror-foldgutter,
.cm-s-one-light .CodeMirror-foldgutter-open,
.cm-s-one-light .CodeMirror-foldgutter-folded {
  border: none;
  text-shadow: none;
  color: #9a9b9f !important;
  background-color: transparent;
}

/* addon: selection/active-line.js */
.cm-s-one-light .CodeMirror-activeline-background {background-color: rgba(0, 123, 255, 0.04);}

/* basic syntax */
.cm-s-one-light .cm-header {color: #e45649;}
.cm-s-one-light .cm-quote {color: #9a9b9f;font-style: italic;}
.cm-s-one-light .cm-negative {color: #e45649;}
.cm-s-one-light .cm-positive {color: #50a14f;}
.cm-s-one-light .cm-strong {color: #c18401;font-weight: bold;}
.cm-s-one-light .cm-header .cm-strong {color: #c18401;font-weight: bold;}
.cm-s-one-light .cm-em {color: #986801;font-style: italic;}
.cm-s-one-light .cm-header .cm-em {color: #986801;font-style: italic;}
.cm-s-one-light .cm-tag {color: #e45649;}
.cm-s-one-light .cm-attribute {color: #c18401;}
.cm-s-one-light .cm-link {color: #0184bb;border-bottom: solid 1px #0184bb;}
.cm-s-one-light .cm-builtin {color: #0184bb;}
.cm-s-one-light .cm-keyword {color: #a626a4;}
.cm-s-one-light .cm-def {color: #4078f2;}
.cm-s-one-light .cm-atom {color: #986801;}
.cm-s-one-light .cm-number {color: #986801;}
.cm-s-one-light .cm-property {color: #0184bb;}
.cm-s-one-light .cm-qualifier {color: #c18401;}
.cm-s-one-light .cm-variable {color: #e45649;}
.cm-s-one-light .cm-string {color: #50a14f;}
.cm-s-one-light .cm-punctuation {color: #383a42;}
.cm-s-one-light .cm-operator {color: #0184bb;}
.cm-s-one-light .cm-meta {color: #383a42;}
.cm-s-one-light .cm-bracket {color: #383a42;}
.cm-s-one-light .cm-comment {color: #a0a1a7;font-style: italic;}
.cm-s-one-light .cm-error {color: #e45649;}

/* css syntax corrections */
.cm-s-one-light .cm-m-css.cm-variable {color: #383a42;}
.cm-s-one-light .cm-m-css.cm-property {color: #383a42;}
.cm-s-one-light .cm-m-css.cm-atom {color: #0184bb;}
.cm-s-one-light .cm-m-css.cm-builtin {color: #0184bb;}

/* lua syntax corrections */
.cm-s-one-light .cm-m-lua.cm-variable {color: #0184bb;}.CodeMirror-search-match {
  background: gold;
  border-top: 1px solid orange;
  border-bottom: 1px solid orange;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  opacity: .5;
}
/*
    Name:       one-dark 1.1.1
    Author:     Török Ádám (http://github.com/Aerobird98)
    Original Atom One Dark Theme (https://github.com/atom/one-dark-ui & https://github.com/atom/one-dark-syntax)
*/

/* basic */
.cm-s-one-dark {
  font-family: Menlo, Consolas, 'DejaVu Sans Mono', monospace;
  /*font-weight: 350;*/
  /*font-size: 18px;*/
  color: #abb2bf;
  background-color: #282c34;
}
.cm-s-one-dark .CodeMirror-selected {background-color: #3e4451;}
.cm-s-one-dark .CodeMirror-gutter,
.cm-s-one-dark .CodeMirror-gutters {
  border: none;
  background-color: #282c34;
}
.cm-s-one-dark .CodeMirror-linenumber,
.cm-s-one-dark .CodeMirror-linenumbers {
  color: #5c6370 !important;
  background-color: transparent;
}
.cm-s-one-dark .CodeMirror-lines {
  color: #abb2bf !important;
  background-color: transparent;
}
.cm-s-one-dark .CodeMirror-cursor {border-left: 2px solid #56b6c2 !important;}
/* addon: edit/machingbrackets.js & addon: edit/matchtags.js */
.cm-s-one-dark .CodeMirror-matchingbracket,
.cm-s-one-dark .CodeMirror-matchingtag {
  border-bottom: 2px solid #56b6c2;
  color: #abb2bf !important;
  background-color: transparent;
}
.cm-s-one-dark .CodeMirror-nonmatchingbracket {
  border-bottom: 2px solid #e06c75;
  color: #abb2bf !important;
  background-color: transparent;
}
/* addon: fold/foldgutter.js */
.cm-s-one-dark .CodeMirror-foldmarker,
.cm-s-one-dark .CodeMirror-foldgutter,
.cm-s-one-dark .CodeMirror-foldgutter-open,
.cm-s-one-dark .CodeMirror-foldgutter-folded {
  border: none;
  text-shadow: none;
  color: #5c6370 !important;
  background-color: transparent;
}
/* addon: selection/active-line.js */
.cm-s-one-dark .CodeMirror-activeline-background {background-color: rgba(153, 187, 255, 0.04);}
/* basic syntax */
.cm-s-one-dark .cm-header {color: #e06c75;}
.cm-s-one-dark .cm-quote {color: #5c6370;font-style: italic;}
.cm-s-one-dark .cm-negative {color: #e06c75;}
.cm-s-one-dark .cm-positive {color: #e06c75;}
.cm-s-one-dark .cm-strong {color: #d19a66;font-weight: bold;}
.cm-s-one-dark .cm-header .cm-strong {color: #d19a66;font-weight: bold;}
.cm-s-one-dark .cm-em {color: #c678dd;font-style: italic;}
.cm-s-one-dark .cm-header .cm-em {color: #c678dd;font-style: italic;}
.cm-s-one-dark .cm-tag {color: #e06c75;}
.cm-s-one-dark .cm-attribute {color: #d19a66;}
.cm-s-one-dark .cm-link {color: #98c379;border-bottom: solid 1px #98c379;}
.cm-s-one-dark .cm-builtin {color: #e06c75;}
.cm-s-one-dark .cm-keyword {color: #c678dd;}
.cm-s-one-dark .cm-def {color: #e5c07b;} /* original:  #d19a66; */
.cm-s-one-dark .cm-atom {color: #d19a66;}
.cm-s-one-dark .cm-number {color: #d19a66;}
.cm-s-one-dark .cm-property {color: #56b6c2;} /* original: #abb2bf */
.cm-s-one-dark .cm-qualifier {color: #d19a66;}
.cm-s-one-dark .cm-variable {color: #e06c75;}
.cm-s-one-dark .cm-string {color: #98c379;}
.cm-s-one-dark .cm-punctuation {color: #abb2bf;}
.cm-s-one-dark .cm-operator {color: #56b6c2;} /* original: #abb2bf */
.cm-s-one-dark .cm-meta {color: #abb2bf;}
.cm-s-one-dark .cm-bracket {color: #abb2bf;}
.cm-s-one-dark .cm-comment {color: #5c6370;font-style: italic;}
.cm-s-one-dark .cm-error {color: #e06c75;}
/* css syntax corrections */
.cm-s-one-dark .cm-m-css.cm-variable {color: #828997;}
.cm-s-one-dark .cm-m-css.cm-property  {color: #abb2bf;}
.cm-s-one-dark .cm-m-css.cm-atom  {color: #56b6c2;}
.cm-s-one-dark .cm-m-css.cm-builtin {color: #56b6c2;}
/* lua syntax corrections */
.cm-s-one-dark .cm-m-lua.cm-variable {color: #56b6c2;}.CodeMirror-foldmarker {
  color: blue;
  text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
  font-family: arial;
  line-height: .3;
  cursor: pointer;
}
.CodeMirror-foldgutter {
  width: .7em;
}
.CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded {
  cursor: pointer;
}
.CodeMirror-foldgutter-open:after {
  content: "\25BE";
}
.CodeMirror-foldgutter-folded:after {
  content: "\25B8";
}

</style><script>
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=global||self,global.CodeMirror=factory())})(this,(function(){"use strict";var userAgent=navigator.userAgent;var platform=navigator.platform;var gecko=/gecko\/\d/i.test(userAgent);var ie_upto10=/MSIE \d/.test(userAgent);var ie_11up=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);var edge=/Edge\/(\d+)/.exec(userAgent);var ie=ie_upto10||ie_11up||edge;var ie_version=ie&&(ie_upto10?document.documentMode||6:+(edge||ie_11up)[1]);var webkit=!edge&&/WebKit\//.test(userAgent);var qtwebkit=webkit&&/Qt\/\d+\.\d+/.test(userAgent);var chrome=!edge&&/Chrome\/(\d+)/.exec(userAgent);var chrome_version=chrome&&+chrome[1];var presto=/Opera\//.test(userAgent);var safari=/Apple Computer/.test(navigator.vendor);var mac_geMountainLion=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);var phantom=/PhantomJS/.test(userAgent);var ios=safari&&(/Mobile\/\w+/.test(userAgent)||navigator.maxTouchPoints>2);var android=/Android/.test(userAgent);var mobile=ios||android||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);var mac=ios||/Mac/.test(platform);var chromeOS=/\bCrOS\b/.test(userAgent);var windows=/win/i.test(platform);var presto_version=presto&&userAgent.match(/Version\/(\d*\.\d*)/);if(presto_version){presto_version=Number(presto_version[1])}if(presto_version&&presto_version>=15){presto=false;webkit=true}var flipCtrlCmd=mac&&(qtwebkit||presto&&(presto_version==null||presto_version<12.11));var captureRightClick=gecko||ie&&ie_version>=9;function classTest(cls){return new RegExp("(^|\\s)"+cls+"(?:$|\\s)\\s*")}var rmClass=function(node,cls){var current=node.className;var match=classTest(cls).exec(current);if(match){var after=current.slice(match.index+match[0].length);node.className=current.slice(0,match.index)+(after?match[1]+after:"")}};function removeChildren(e){for(var count=e.childNodes.length;count>0;--count){e.removeChild(e.firstChild)}return e}function removeChildrenAndAdd(parent,e){return removeChildren(parent).appendChild(e)}function elt(tag,content,className,style){var e=document.createElement(tag);if(className){e.className=className}if(style){e.style.cssText=style}if(typeof content=="string"){e.appendChild(document.createTextNode(content))}else if(content){for(var i=0;i<content.length;++i){e.appendChild(content[i])}}return e}function eltP(tag,content,className,style){var e=elt(tag,content,className,style);e.setAttribute("role","presentation");return e}var range;if(document.createRange){range=function(node,start,end,endNode){var r=document.createRange();r.setEnd(endNode||node,end);r.setStart(node,start);return r}}else{range=function(node,start,end){var r=document.body.createTextRange();try{r.moveToElementText(node.parentNode)}catch(e){return r}r.collapse(true);r.moveEnd("character",end);r.moveStart("character",start);return r}}function contains(parent,child){if(child.nodeType==3){child=child.parentNode}if(parent.contains){return parent.contains(child)}do{if(child.nodeType==11){child=child.host}if(child==parent){return true}}while(child=child.parentNode)}function activeElt(doc){var activeElement;try{activeElement=doc.activeElement}catch(e){activeElement=doc.body||null}while(activeElement&&activeElement.shadowRoot&&activeElement.shadowRoot.activeElement){activeElement=activeElement.shadowRoot.activeElement}return activeElement}function addClass(node,cls){var current=node.className;if(!classTest(cls).test(current)){node.className+=(current?" ":"")+cls}}function joinClasses(a,b){var as=a.split(" ");for(var i=0;i<as.length;i++){if(as[i]&&!classTest(as[i]).test(b)){b+=" "+as[i]}}return b}var selectInput=function(node){node.select()};if(ios){selectInput=function(node){node.selectionStart=0;node.selectionEnd=node.value.length}}else if(ie){selectInput=function(node){try{node.select()}catch(_e){}}}function doc(cm){return cm.display.wrapper.ownerDocument}function win(cm){return doc(cm).defaultView}function bind(f){var args=Array.prototype.slice.call(arguments,1);return function(){return f.apply(null,args)}}function copyObj(obj,target,overwrite){if(!target){target={}}for(var prop in obj){if(obj.hasOwnProperty(prop)&&(overwrite!==false||!target.hasOwnProperty(prop))){target[prop]=obj[prop]}}return target}function countColumn(string,end,tabSize,startIndex,startValue){if(end==null){end=string.search(/[^\s\u00a0]/);if(end==-1){end=string.length}}for(var i=startIndex||0,n=startValue||0;;){var nextTab=string.indexOf("\t",i);if(nextTab<0||nextTab>=end){return n+(end-i)}n+=nextTab-i;n+=tabSize-n%tabSize;i=nextTab+1}}var Delayed=function(){this.id=null;this.f=null;this.time=0;this.handler=bind(this.onTimeout,this)};Delayed.prototype.onTimeout=function(self){self.id=0;if(self.time<=+new Date){self.f()}else{setTimeout(self.handler,self.time-+new Date)}};Delayed.prototype.set=function(ms,f){this.f=f;var time=+new Date+ms;if(!this.id||time<this.time){clearTimeout(this.id);this.id=setTimeout(this.handler,ms);this.time=time}};function indexOf(array,elt){for(var i=0;i<array.length;++i){if(array[i]==elt){return i}}return-1}var scrollerGap=50;var Pass={toString:function(){return"CodeMirror.Pass"}};var sel_dontScroll={scroll:false},sel_mouse={origin:"*mouse"},sel_move={origin:"+move"};function findColumn(string,goal,tabSize){for(var pos=0,col=0;;){var nextTab=string.indexOf("\t",pos);if(nextTab==-1){nextTab=string.length}var skipped=nextTab-pos;if(nextTab==string.length||col+skipped>=goal){return pos+Math.min(skipped,goal-col)}col+=nextTab-pos;col+=tabSize-col%tabSize;pos=nextTab+1;if(col>=goal){return pos}}}var spaceStrs=[""];function spaceStr(n){while(spaceStrs.length<=n){spaceStrs.push(lst(spaceStrs)+" ")}return spaceStrs[n]}function lst(arr){return arr[arr.length-1]}function map(array,f){var out=[];for(var i=0;i<array.length;i++){out[i]=f(array[i],i)}return out}function insertSorted(array,value,score){var pos=0,priority=score(value);while(pos<array.length&&score(array[pos])<=priority){pos++}array.splice(pos,0,value)}function nothing(){}function createObj(base,props){var inst;if(Object.create){inst=Object.create(base)}else{nothing.prototype=base;inst=new nothing}if(props){copyObj(props,inst)}return inst}var nonASCIISingleCaseWordChar=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;function isWordCharBasic(ch){return/\w/.test(ch)||ch>"€"&&(ch.toUpperCase()!=ch.toLowerCase()||nonASCIISingleCaseWordChar.test(ch))}function isWordChar(ch,helper){if(!helper){return isWordCharBasic(ch)}if(helper.source.indexOf("\\w")>-1&&isWordCharBasic(ch)){return true}return helper.test(ch)}function isEmpty(obj){for(var n in obj){if(obj.hasOwnProperty(n)&&obj[n]){return false}}return true}var extendingChars=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function isExtendingChar(ch){return ch.charCodeAt(0)>=768&&extendingChars.test(ch)}function skipExtendingChars(str,pos,dir){while((dir<0?pos>0:pos<str.length)&&isExtendingChar(str.charAt(pos))){pos+=dir}return pos}function findFirst(pred,from,to){var dir=from>to?-1:1;for(;;){if(from==to){return from}var midF=(from+to)/2,mid=dir<0?Math.ceil(midF):Math.floor(midF);if(mid==from){return pred(mid)?from:to}if(pred(mid)){to=mid}else{from=mid+dir}}}function iterateBidiSections(order,from,to,f){if(!order){return f(from,to,"ltr",0)}var found=false;for(var i=0;i<order.length;++i){var part=order[i];if(part.from<to&&part.to>from||from==to&&part.to==from){f(Math.max(part.from,from),Math.min(part.to,to),part.level==1?"rtl":"ltr",i);found=true}}if(!found){f(from,to,"ltr")}}var bidiOther=null;function getBidiPartAt(order,ch,sticky){var found;bidiOther=null;for(var i=0;i<order.length;++i){var cur=order[i];if(cur.from<ch&&cur.to>ch){return i}if(cur.to==ch){if(cur.from!=cur.to&&sticky=="before"){found=i}else{bidiOther=i}}if(cur.from==ch){if(cur.from!=cur.to&&sticky!="before"){found=i}else{bidiOther=i}}}return found!=null?found:bidiOther}var bidiOrdering=function(){var lowTypes="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";var arabicTypes="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";function charType(code){if(code<=247){return lowTypes.charAt(code)}else if(1424<=code&&code<=1524){return"R"}else if(1536<=code&&code<=1785){return arabicTypes.charAt(code-1536)}else if(1774<=code&&code<=2220){return"r"}else if(8192<=code&&code<=8203){return"w"}else if(code==8204){return"b"}else{return"L"}}var bidiRE=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;var isNeutral=/[stwN]/,isStrong=/[LRr]/,countsAsLeft=/[Lb1n]/,countsAsNum=/[1n]/;function BidiSpan(level,from,to){this.level=level;this.from=from;this.to=to}return function(str,direction){var outerType=direction=="ltr"?"L":"R";if(str.length==0||direction=="ltr"&&!bidiRE.test(str)){return false}var len=str.length,types=[];for(var i=0;i<len;++i){types.push(charType(str.charCodeAt(i)))}for(var i$1=0,prev=outerType;i$1<len;++i$1){var type=types[i$1];if(type=="m"){types[i$1]=prev}else{prev=type}}for(var i$2=0,cur=outerType;i$2<len;++i$2){var type$1=types[i$2];if(type$1=="1"&&cur=="r"){types[i$2]="n"}else if(isStrong.test(type$1)){cur=type$1;if(type$1=="r"){types[i$2]="R"}}}for(var i$3=1,prev$1=types[0];i$3<len-1;++i$3){var type$2=types[i$3];if(type$2=="+"&&prev$1=="1"&&types[i$3+1]=="1"){types[i$3]="1"}else if(type$2==","&&prev$1==types[i$3+1]&&(prev$1=="1"||prev$1=="n")){types[i$3]=prev$1}prev$1=type$2}for(var i$4=0;i$4<len;++i$4){var type$3=types[i$4];if(type$3==","){types[i$4]="N"}else if(type$3=="%"){var end=void 0;for(end=i$4+1;end<len&&types[end]=="%";++end){}var replace=i$4&&types[i$4-1]=="!"||end<len&&types[end]=="1"?"1":"N";for(var j=i$4;j<end;++j){types[j]=replace}i$4=end-1}}for(var i$5=0,cur$1=outerType;i$5<len;++i$5){var type$4=types[i$5];if(cur$1=="L"&&type$4=="1"){types[i$5]="L"}else if(isStrong.test(type$4)){cur$1=type$4}}for(var i$6=0;i$6<len;++i$6){if(isNeutral.test(types[i$6])){var end$1=void 0;for(end$1=i$6+1;end$1<len&&isNeutral.test(types[end$1]);++end$1){}var before=(i$6?types[i$6-1]:outerType)=="L";var after=(end$1<len?types[end$1]:outerType)=="L";var replace$1=before==after?before?"L":"R":outerType;for(var j$1=i$6;j$1<end$1;++j$1){types[j$1]=replace$1}i$6=end$1-1}}var order=[],m;for(var i$7=0;i$7<len;){if(countsAsLeft.test(types[i$7])){var start=i$7;for(++i$7;i$7<len&&countsAsLeft.test(types[i$7]);++i$7){}order.push(new BidiSpan(0,start,i$7))}else{var pos=i$7,at=order.length,isRTL=direction=="rtl"?1:0;for(++i$7;i$7<len&&types[i$7]!="L";++i$7){}for(var j$2=pos;j$2<i$7;){if(countsAsNum.test(types[j$2])){if(pos<j$2){order.splice(at,0,new BidiSpan(1,pos,j$2));at+=isRTL}var nstart=j$2;for(++j$2;j$2<i$7&&countsAsNum.test(types[j$2]);++j$2){}order.splice(at,0,new BidiSpan(2,nstart,j$2));at+=isRTL;pos=j$2}else{++j$2}}if(pos<i$7){order.splice(at,0,new BidiSpan(1,pos,i$7))}}}if(direction=="ltr"){if(order[0].level==1&&(m=str.match(/^\s+/))){order[0].from=m[0].length;order.unshift(new BidiSpan(0,0,m[0].length))}if(lst(order).level==1&&(m=str.match(/\s+$/))){lst(order).to-=m[0].length;order.push(new BidiSpan(0,len-m[0].length,len))}}return direction=="rtl"?order.reverse():order}}();function getOrder(line,direction){var order=line.order;if(order==null){order=line.order=bidiOrdering(line.text,direction)}return order}var noHandlers=[];var on=function(emitter,type,f){if(emitter.addEventListener){emitter.addEventListener(type,f,false)}else if(emitter.attachEvent){emitter.attachEvent("on"+type,f)}else{var map=emitter._handlers||(emitter._handlers={});map[type]=(map[type]||noHandlers).concat(f)}};function getHandlers(emitter,type){return emitter._handlers&&emitter._handlers[type]||noHandlers}function off(emitter,type,f){if(emitter.removeEventListener){emitter.removeEventListener(type,f,false)}else if(emitter.detachEvent){emitter.detachEvent("on"+type,f)}else{var map=emitter._handlers,arr=map&&map[type];if(arr){var index=indexOf(arr,f);if(index>-1){map[type]=arr.slice(0,index).concat(arr.slice(index+1))}}}}function signal(emitter,type){var handlers=getHandlers(emitter,type);if(!handlers.length){return}var args=Array.prototype.slice.call(arguments,2);for(var i=0;i<handlers.length;++i){handlers[i].apply(null,args)}}function signalDOMEvent(cm,e,override){if(typeof e=="string"){e={type:e,preventDefault:function(){this.defaultPrevented=true}}}signal(cm,override||e.type,cm,e);return e_defaultPrevented(e)||e.codemirrorIgnore}function signalCursorActivity(cm){var arr=cm._handlers&&cm._handlers.cursorActivity;if(!arr){return}var set=cm.curOp.cursorActivityHandlers||(cm.curOp.cursorActivityHandlers=[]);for(var i=0;i<arr.length;++i){if(indexOf(set,arr[i])==-1){set.push(arr[i])}}}function hasHandler(emitter,type){return getHandlers(emitter,type).length>0}function eventMixin(ctor){ctor.prototype.on=function(type,f){on(this,type,f)};ctor.prototype.off=function(type,f){off(this,type,f)}}function e_preventDefault(e){if(e.preventDefault){e.preventDefault()}else{e.returnValue=false}}function e_stopPropagation(e){if(e.stopPropagation){e.stopPropagation()}else{e.cancelBubble=true}}function e_defaultPrevented(e){return e.defaultPrevented!=null?e.defaultPrevented:e.returnValue==false}function e_stop(e){e_preventDefault(e);e_stopPropagation(e)}function e_target(e){return e.target||e.srcElement}function e_button(e){var b=e.which;if(b==null){if(e.button&1){b=1}else if(e.button&2){b=3}else if(e.button&4){b=2}}if(mac&&e.ctrlKey&&b==1){b=3}return b}var dragAndDrop=function(){if(ie&&ie_version<9){return false}var div=elt("div");return"draggable"in div||"dragDrop"in div}();var zwspSupported;function zeroWidthElement(measure){if(zwspSupported==null){var test=elt("span","​");removeChildrenAndAdd(measure,elt("span",[test,document.createTextNode("x")]));if(measure.firstChild.offsetHeight!=0){zwspSupported=test.offsetWidth<=1&&test.offsetHeight>2&&!(ie&&ie_version<8)}}var node=zwspSupported?elt("span","​"):elt("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");node.setAttribute("cm-text","");return node}var badBidiRects;function hasBadBidiRects(measure){if(badBidiRects!=null){return badBidiRects}var txt=removeChildrenAndAdd(measure,document.createTextNode("AخA"));var r0=range(txt,0,1).getBoundingClientRect();var r1=range(txt,1,2).getBoundingClientRect();removeChildren(measure);if(!r0||r0.left==r0.right){return false}return badBidiRects=r1.right-r0.right<3}var splitLinesAuto="\n\nb".split(/\n/).length!=3?function(string){var pos=0,result=[],l=string.length;while(pos<=l){var nl=string.indexOf("\n",pos);if(nl==-1){nl=string.length}var line=string.slice(pos,string.charAt(nl-1)=="\r"?nl-1:nl);var rt=line.indexOf("\r");if(rt!=-1){result.push(line.slice(0,rt));pos+=rt+1}else{result.push(line);pos=nl+1}}return result}:function(string){return string.split(/\r\n?|\n/)};var hasSelection=window.getSelection?function(te){try{return te.selectionStart!=te.selectionEnd}catch(e){return false}}:function(te){var range;try{range=te.ownerDocument.selection.createRange()}catch(e){}if(!range||range.parentElement()!=te){return false}return range.compareEndPoints("StartToEnd",range)!=0};var hasCopyEvent=function(){var e=elt("div");if("oncopy"in e){return true}e.setAttribute("oncopy","return;");return typeof e.oncopy=="function"}();var badZoomedRects=null;function hasBadZoomedRects(measure){if(badZoomedRects!=null){return badZoomedRects}var node=removeChildrenAndAdd(measure,elt("span","x"));var normal=node.getBoundingClientRect();var fromRange=range(node,0,1).getBoundingClientRect();return badZoomedRects=Math.abs(normal.left-fromRange.left)>1}var modes={},mimeModes={};function defineMode(name,mode){if(arguments.length>2){mode.dependencies=Array.prototype.slice.call(arguments,2)}modes[name]=mode}function defineMIME(mime,spec){mimeModes[mime]=spec}function resolveMode(spec){if(typeof spec=="string"&&mimeModes.hasOwnProperty(spec)){spec=mimeModes[spec]}else if(spec&&typeof spec.name=="string"&&mimeModes.hasOwnProperty(spec.name)){var found=mimeModes[spec.name];if(typeof found=="string"){found={name:found}}spec=createObj(found,spec);spec.name=found.name}else if(typeof spec=="string"&&/^[\w\-]+\/[\w\-]+\+xml$/.test(spec)){return resolveMode("application/xml")}else if(typeof spec=="string"&&/^[\w\-]+\/[\w\-]+\+json$/.test(spec)){return resolveMode("application/json")}if(typeof spec=="string"){return{name:spec}}else{return spec||{name:"null"}}}function getMode(options,spec){spec=resolveMode(spec);var mfactory=modes[spec.name];if(!mfactory){return getMode(options,"text/plain")}var modeObj=mfactory(options,spec);if(modeExtensions.hasOwnProperty(spec.name)){var exts=modeExtensions[spec.name];for(var prop in exts){if(!exts.hasOwnProperty(prop)){continue}if(modeObj.hasOwnProperty(prop)){modeObj["_"+prop]=modeObj[prop]}modeObj[prop]=exts[prop]}}modeObj.name=spec.name;if(spec.helperType){modeObj.helperType=spec.helperType}if(spec.modeProps){for(var prop$1 in spec.modeProps){modeObj[prop$1]=spec.modeProps[prop$1]}}return modeObj}var modeExtensions={};function extendMode(mode,properties){var exts=modeExtensions.hasOwnProperty(mode)?modeExtensions[mode]:modeExtensions[mode]={};copyObj(properties,exts)}function copyState(mode,state){if(state===true){return state}if(mode.copyState){return mode.copyState(state)}var nstate={};for(var n in state){var val=state[n];if(val instanceof Array){val=val.concat([])}nstate[n]=val}return nstate}function innerMode(mode,state){var info;while(mode.innerMode){info=mode.innerMode(state);if(!info||info.mode==mode){break}state=info.state;mode=info.mode}return info||{mode:mode,state:state}}function startState(mode,a1,a2){return mode.startState?mode.startState(a1,a2):true}var StringStream=function(string,tabSize,lineOracle){this.pos=this.start=0;this.string=string;this.tabSize=tabSize||8;this.lastColumnPos=this.lastColumnValue=0;this.lineStart=0;this.lineOracle=lineOracle};StringStream.prototype.eol=function(){return this.pos>=this.string.length};StringStream.prototype.sol=function(){return this.pos==this.lineStart};StringStream.prototype.peek=function(){return this.string.charAt(this.pos)||undefined};StringStream.prototype.next=function(){if(this.pos<this.string.length){return this.string.charAt(this.pos++)}};StringStream.prototype.eat=function(match){var ch=this.string.charAt(this.pos);var ok;if(typeof match=="string"){ok=ch==match}else{ok=ch&&(match.test?match.test(ch):match(ch))}if(ok){++this.pos;return ch}};StringStream.prototype.eatWhile=function(match){var start=this.pos;while(this.eat(match)){}return this.pos>start};StringStream.prototype.eatSpace=function(){var start=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos))){++this.pos}return this.pos>start};StringStream.prototype.skipToEnd=function(){this.pos=this.string.length};StringStream.prototype.skipTo=function(ch){var found=this.string.indexOf(ch,this.pos);if(found>-1){this.pos=found;return true}};StringStream.prototype.backUp=function(n){this.pos-=n};StringStream.prototype.column=function(){if(this.lastColumnPos<this.start){this.lastColumnValue=countColumn(this.string,this.start,this.tabSize,this.lastColumnPos,this.lastColumnValue);this.lastColumnPos=this.start}return this.lastColumnValue-(this.lineStart?countColumn(this.string,this.lineStart,this.tabSize):0)};StringStream.prototype.indentation=function(){return countColumn(this.string,null,this.tabSize)-(this.lineStart?countColumn(this.string,this.lineStart,this.tabSize):0)};StringStream.prototype.match=function(pattern,consume,caseInsensitive){if(typeof pattern=="string"){var cased=function(str){return caseInsensitive?str.toLowerCase():str};var substr=this.string.substr(this.pos,pattern.length);if(cased(substr)==cased(pattern)){if(consume!==false){this.pos+=pattern.length}return true}}else{var match=this.string.slice(this.pos).match(pattern);if(match&&match.index>0){return null}if(match&&consume!==false){this.pos+=match[0].length}return match}};StringStream.prototype.current=function(){return this.string.slice(this.start,this.pos)};StringStream.prototype.hideFirstChars=function(n,inner){this.lineStart+=n;try{return inner()}finally{this.lineStart-=n}};StringStream.prototype.lookAhead=function(n){var oracle=this.lineOracle;return oracle&&oracle.lookAhead(n)};StringStream.prototype.baseToken=function(){var oracle=this.lineOracle;return oracle&&oracle.baseToken(this.pos)};function getLine(doc,n){n-=doc.first;if(n<0||n>=doc.size){throw new Error("There is no line "+(n+doc.first)+" in the document.")}var chunk=doc;while(!chunk.lines){for(var i=0;;++i){var child=chunk.children[i],sz=child.chunkSize();if(n<sz){chunk=child;break}n-=sz}}return chunk.lines[n]}function getBetween(doc,start,end){var out=[],n=start.line;doc.iter(start.line,end.line+1,(function(line){var text=line.text;if(n==end.line){text=text.slice(0,end.ch)}if(n==start.line){text=text.slice(start.ch)}out.push(text);++n}));return out}function getLines(doc,from,to){var out=[];doc.iter(from,to,(function(line){out.push(line.text)}));return out}function updateLineHeight(line,height){var diff=height-line.height;if(diff){for(var n=line;n;n=n.parent){n.height+=diff}}}function lineNo(line){if(line.parent==null){return null}var cur=line.parent,no=indexOf(cur.lines,line);for(var chunk=cur.parent;chunk;cur=chunk,chunk=chunk.parent){for(var i=0;;++i){if(chunk.children[i]==cur){break}no+=chunk.children[i].chunkSize()}}return no+cur.first}function lineAtHeight(chunk,h){var n=chunk.first;outer:do{for(var i$1=0;i$1<chunk.children.length;++i$1){var child=chunk.children[i$1],ch=child.height;if(h<ch){chunk=child;continue outer}h-=ch;n+=child.chunkSize()}return n}while(!chunk.lines);var i=0;for(;i<chunk.lines.length;++i){var line=chunk.lines[i],lh=line.height;if(h<lh){break}h-=lh}return n+i}function isLine(doc,l){return l>=doc.first&&l<doc.first+doc.size}function lineNumberFor(options,i){return String(options.lineNumberFormatter(i+options.firstLineNumber))}function Pos(line,ch,sticky){if(sticky===void 0)sticky=null;if(!(this instanceof Pos)){return new Pos(line,ch,sticky)}this.line=line;this.ch=ch;this.sticky=sticky}function cmp(a,b){return a.line-b.line||a.ch-b.ch}function equalCursorPos(a,b){return a.sticky==b.sticky&&cmp(a,b)==0}function copyPos(x){return Pos(x.line,x.ch)}function maxPos(a,b){return cmp(a,b)<0?b:a}function minPos(a,b){return cmp(a,b)<0?a:b}function clipLine(doc,n){return Math.max(doc.first,Math.min(n,doc.first+doc.size-1))}function clipPos(doc,pos){if(pos.line<doc.first){return Pos(doc.first,0)}var last=doc.first+doc.size-1;if(pos.line>last){return Pos(last,getLine(doc,last).text.length)}return clipToLen(pos,getLine(doc,pos.line).text.length)}function clipToLen(pos,linelen){var ch=pos.ch;if(ch==null||ch>linelen){return Pos(pos.line,linelen)}else if(ch<0){return Pos(pos.line,0)}else{return pos}}function clipPosArray(doc,array){var out=[];for(var i=0;i<array.length;i++){out[i]=clipPos(doc,array[i])}return out}var SavedContext=function(state,lookAhead){this.state=state;this.lookAhead=lookAhead};var Context=function(doc,state,line,lookAhead){this.state=state;this.doc=doc;this.line=line;this.maxLookAhead=lookAhead||0;this.baseTokens=null;this.baseTokenPos=1};Context.prototype.lookAhead=function(n){var line=this.doc.getLine(this.line+n);if(line!=null&&n>this.maxLookAhead){this.maxLookAhead=n}return line};Context.prototype.baseToken=function(n){if(!this.baseTokens){return null}while(this.baseTokens[this.baseTokenPos]<=n){this.baseTokenPos+=2}var type=this.baseTokens[this.baseTokenPos+1];return{type:type&&type.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-n}};Context.prototype.nextLine=function(){this.line++;if(this.maxLookAhead>0){this.maxLookAhead--}};Context.fromSaved=function(doc,saved,line){if(saved instanceof SavedContext){return new Context(doc,copyState(doc.mode,saved.state),line,saved.lookAhead)}else{return new Context(doc,copyState(doc.mode,saved),line)}};Context.prototype.save=function(copy){var state=copy!==false?copyState(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new SavedContext(state,this.maxLookAhead):state};function highlightLine(cm,line,context,forceToEnd){var st=[cm.state.modeGen],lineClasses={};runMode(cm,line.text,cm.doc.mode,context,(function(end,style){return st.push(end,style)}),lineClasses,forceToEnd);var state=context.state;var loop=function(o){context.baseTokens=st;var overlay=cm.state.overlays[o],i=1,at=0;context.state=true;runMode(cm,line.text,overlay.mode,context,(function(end,style){var start=i;while(at<end){var i_end=st[i];if(i_end>end){st.splice(i,1,end,st[i+1],i_end)}i+=2;at=Math.min(end,i_end)}if(!style){return}if(overlay.opaque){st.splice(start,i-start,end,"overlay "+style);i=start+2}else{for(;start<i;start+=2){var cur=st[start+1];st[start+1]=(cur?cur+" ":"")+"overlay "+style}}}),lineClasses);context.state=state;context.baseTokens=null;context.baseTokenPos=1};for(var o=0;o<cm.state.overlays.length;++o)loop(o);return{styles:st,classes:lineClasses.bgClass||lineClasses.textClass?lineClasses:null}}function getLineStyles(cm,line,updateFrontier){if(!line.styles||line.styles[0]!=cm.state.modeGen){var context=getContextBefore(cm,lineNo(line));var resetState=line.text.length>cm.options.maxHighlightLength&&copyState(cm.doc.mode,context.state);var result=highlightLine(cm,line,context);if(resetState){context.state=resetState}line.stateAfter=context.save(!resetState);line.styles=result.styles;if(result.classes){line.styleClasses=result.classes}else if(line.styleClasses){line.styleClasses=null}if(updateFrontier===cm.doc.highlightFrontier){cm.doc.modeFrontier=Math.max(cm.doc.modeFrontier,++cm.doc.highlightFrontier)}}return line.styles}function getContextBefore(cm,n,precise){var doc=cm.doc,display=cm.display;if(!doc.mode.startState){return new Context(doc,true,n)}var start=findStartLine(cm,n,precise);var saved=start>doc.first&&getLine(doc,start-1).stateAfter;var context=saved?Context.fromSaved(doc,saved,start):new Context(doc,startState(doc.mode),start);doc.iter(start,n,(function(line){processLine(cm,line.text,context);var pos=context.line;line.stateAfter=pos==n-1||pos%5==0||pos>=display.viewFrom&&pos<display.viewTo?context.save():null;context.nextLine()}));if(precise){doc.modeFrontier=context.line}return context}function processLine(cm,text,context,startAt){var mode=cm.doc.mode;var stream=new StringStream(text,cm.options.tabSize,context);stream.start=stream.pos=startAt||0;if(text==""){callBlankLine(mode,context.state)}while(!stream.eol()){readToken(mode,stream,context.state);stream.start=stream.pos}}function callBlankLine(mode,state){if(mode.blankLine){return mode.blankLine(state)}if(!mode.innerMode){return}var inner=innerMode(mode,state);if(inner.mode.blankLine){return inner.mode.blankLine(inner.state)}}function readToken(mode,stream,state,inner){for(var i=0;i<10;i++){if(inner){inner[0]=innerMode(mode,state).mode}var style=mode.token(stream,state);if(stream.pos>stream.start){return style}}throw new Error("Mode "+mode.name+" failed to advance stream.")}var Token=function(stream,type,state){this.start=stream.start;this.end=stream.pos;this.string=stream.current();this.type=type||null;this.state=state};function takeToken(cm,pos,precise,asArray){var doc=cm.doc,mode=doc.mode,style;pos=clipPos(doc,pos);var line=getLine(doc,pos.line),context=getContextBefore(cm,pos.line,precise);var stream=new StringStream(line.text,cm.options.tabSize,context),tokens;if(asArray){tokens=[]}while((asArray||stream.pos<pos.ch)&&!stream.eol()){stream.start=stream.pos;style=readToken(mode,stream,context.state);if(asArray){tokens.push(new Token(stream,style,copyState(doc.mode,context.state)))}}return asArray?tokens:new Token(stream,style,context.state)}function extractLineClasses(type,output){if(type){for(;;){var lineClass=type.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!lineClass){break}type=type.slice(0,lineClass.index)+type.slice(lineClass.index+lineClass[0].length);var prop=lineClass[1]?"bgClass":"textClass";if(output[prop]==null){output[prop]=lineClass[2]}else if(!new RegExp("(?:^|\\s)"+lineClass[2]+"(?:$|\\s)").test(output[prop])){output[prop]+=" "+lineClass[2]}}}return type}function runMode(cm,text,mode,context,f,lineClasses,forceToEnd){var flattenSpans=mode.flattenSpans;if(flattenSpans==null){flattenSpans=cm.options.flattenSpans}var curStart=0,curStyle=null;var stream=new StringStream(text,cm.options.tabSize,context),style;var inner=cm.options.addModeClass&&[null];if(text==""){extractLineClasses(callBlankLine(mode,context.state),lineClasses)}while(!stream.eol()){if(stream.pos>cm.options.maxHighlightLength){flattenSpans=false;if(forceToEnd){processLine(cm,text,context,stream.pos)}stream.pos=text.length;style=null}else{style=extractLineClasses(readToken(mode,stream,context.state,inner),lineClasses)}if(inner){var mName=inner[0].name;if(mName){style="m-"+(style?mName+" "+style:mName)}}if(!flattenSpans||curStyle!=style){while(curStart<stream.start){curStart=Math.min(stream.start,curStart+5e3);f(curStart,curStyle)}curStyle=style}stream.start=stream.pos}while(curStart<stream.pos){var pos=Math.min(stream.pos,curStart+5e3);f(pos,curStyle);curStart=pos}}function findStartLine(cm,n,precise){var minindent,minline,doc=cm.doc;var lim=precise?-1:n-(cm.doc.mode.innerMode?1e3:100);for(var search=n;search>lim;--search){if(search<=doc.first){return doc.first}var line=getLine(doc,search-1),after=line.stateAfter;if(after&&(!precise||search+(after instanceof SavedContext?after.lookAhead:0)<=doc.modeFrontier)){return search}var indented=countColumn(line.text,null,cm.options.tabSize);if(minline==null||minindent>indented){minline=search-1;minindent=indented}}return minline}function retreatFrontier(doc,n){doc.modeFrontier=Math.min(doc.modeFrontier,n);if(doc.highlightFrontier<n-10){return}var start=doc.first;for(var line=n-1;line>start;line--){var saved=getLine(doc,line).stateAfter;if(saved&&(!(saved instanceof SavedContext)||line+saved.lookAhead<n)){start=line+1;break}}doc.highlightFrontier=Math.min(doc.highlightFrontier,start)}var sawReadOnlySpans=false,sawCollapsedSpans=false;function seeReadOnlySpans(){sawReadOnlySpans=true}function seeCollapsedSpans(){sawCollapsedSpans=true}function MarkedSpan(marker,from,to){this.marker=marker;this.from=from;this.to=to}function getMarkedSpanFor(spans,marker){if(spans){for(var i=0;i<spans.length;++i){var span=spans[i];if(span.marker==marker){return span}}}}function removeMarkedSpan(spans,span){var r;for(var i=0;i<spans.length;++i){if(spans[i]!=span){(r||(r=[])).push(spans[i])}}return r}function addMarkedSpan(line,span,op){var inThisOp=op&&window.WeakSet&&(op.markedSpans||(op.markedSpans=new WeakSet));if(inThisOp&&line.markedSpans&&inThisOp.has(line.markedSpans)){line.markedSpans.push(span)}else{line.markedSpans=line.markedSpans?line.markedSpans.concat([span]):[span];if(inThisOp){inThisOp.add(line.markedSpans)}}span.marker.attachLine(line)}function markedSpansBefore(old,startCh,isInsert){var nw;if(old){for(var i=0;i<old.length;++i){var span=old[i],marker=span.marker;var startsBefore=span.from==null||(marker.inclusiveLeft?span.from<=startCh:span.from<startCh);if(startsBefore||span.from==startCh&&marker.type=="bookmark"&&(!isInsert||!span.marker.insertLeft)){var endsAfter=span.to==null||(marker.inclusiveRight?span.to>=startCh:span.to>startCh);(nw||(nw=[])).push(new MarkedSpan(marker,span.from,endsAfter?null:span.to))}}}return nw}function markedSpansAfter(old,endCh,isInsert){var nw;if(old){for(var i=0;i<old.length;++i){var span=old[i],marker=span.marker;var endsAfter=span.to==null||(marker.inclusiveRight?span.to>=endCh:span.to>endCh);if(endsAfter||span.from==endCh&&marker.type=="bookmark"&&(!isInsert||span.marker.insertLeft)){var startsBefore=span.from==null||(marker.inclusiveLeft?span.from<=endCh:span.from<endCh);(nw||(nw=[])).push(new MarkedSpan(marker,startsBefore?null:span.from-endCh,span.to==null?null:span.to-endCh))}}}return nw}function stretchSpansOverChange(doc,change){if(change.full){return null}var oldFirst=isLine(doc,change.from.line)&&getLine(doc,change.from.line).markedSpans;var oldLast=isLine(doc,change.to.line)&&getLine(doc,change.to.line).markedSpans;if(!oldFirst&&!oldLast){return null}var startCh=change.from.ch,endCh=change.to.ch,isInsert=cmp(change.from,change.to)==0;var first=markedSpansBefore(oldFirst,startCh,isInsert);var last=markedSpansAfter(oldLast,endCh,isInsert);var sameLine=change.text.length==1,offset=lst(change.text).length+(sameLine?startCh:0);if(first){for(var i=0;i<first.length;++i){var span=first[i];if(span.to==null){var found=getMarkedSpanFor(last,span.marker);if(!found){span.to=startCh}else if(sameLine){span.to=found.to==null?null:found.to+offset}}}}if(last){for(var i$1=0;i$1<last.length;++i$1){var span$1=last[i$1];if(span$1.to!=null){span$1.to+=offset}if(span$1.from==null){var found$1=getMarkedSpanFor(first,span$1.marker);if(!found$1){span$1.from=offset;if(sameLine){(first||(first=[])).push(span$1)}}}else{span$1.from+=offset;if(sameLine){(first||(first=[])).push(span$1)}}}}if(first){first=clearEmptySpans(first)}if(last&&last!=first){last=clearEmptySpans(last)}var newMarkers=[first];if(!sameLine){var gap=change.text.length-2,gapMarkers;if(gap>0&&first){for(var i$2=0;i$2<first.length;++i$2){if(first[i$2].to==null){(gapMarkers||(gapMarkers=[])).push(new MarkedSpan(first[i$2].marker,null,null))}}}for(var i$3=0;i$3<gap;++i$3){newMarkers.push(gapMarkers)}newMarkers.push(last)}return newMarkers}function clearEmptySpans(spans){for(var i=0;i<spans.length;++i){var span=spans[i];if(span.from!=null&&span.from==span.to&&span.marker.clearWhenEmpty!==false){spans.splice(i--,1)}}if(!spans.length){return null}return spans}function removeReadOnlyRanges(doc,from,to){var markers=null;doc.iter(from.line,to.line+1,(function(line){if(line.markedSpans){for(var i=0;i<line.markedSpans.length;++i){var mark=line.markedSpans[i].marker;if(mark.readOnly&&(!markers||indexOf(markers,mark)==-1)){(markers||(markers=[])).push(mark)}}}}));if(!markers){return null}var parts=[{from:from,to:to}];for(var i=0;i<markers.length;++i){var mk=markers[i],m=mk.find(0);for(var j=0;j<parts.length;++j){var p=parts[j];if(cmp(p.to,m.from)<0||cmp(p.from,m.to)>0){continue}var newParts=[j,1],dfrom=cmp(p.from,m.from),dto=cmp(p.to,m.to);if(dfrom<0||!mk.inclusiveLeft&&!dfrom){newParts.push({from:p.from,to:m.from})}if(dto>0||!mk.inclusiveRight&&!dto){newParts.push({from:m.to,to:p.to})}parts.splice.apply(parts,newParts);j+=newParts.length-3}}return parts}function detachMarkedSpans(line){var spans=line.markedSpans;if(!spans){return}for(var i=0;i<spans.length;++i){spans[i].marker.detachLine(line)}line.markedSpans=null}function attachMarkedSpans(line,spans){if(!spans){return}for(var i=0;i<spans.length;++i){spans[i].marker.attachLine(line)}line.markedSpans=spans}function extraLeft(marker){return marker.inclusiveLeft?-1:0}function extraRight(marker){return marker.inclusiveRight?1:0}function compareCollapsedMarkers(a,b){var lenDiff=a.lines.length-b.lines.length;if(lenDiff!=0){return lenDiff}var aPos=a.find(),bPos=b.find();var fromCmp=cmp(aPos.from,bPos.from)||extraLeft(a)-extraLeft(b);if(fromCmp){return-fromCmp}var toCmp=cmp(aPos.to,bPos.to)||extraRight(a)-extraRight(b);if(toCmp){return toCmp}return b.id-a.id}function collapsedSpanAtSide(line,start){var sps=sawCollapsedSpans&&line.markedSpans,found;if(sps){for(var sp=void 0,i=0;i<sps.length;++i){sp=sps[i];if(sp.marker.collapsed&&(start?sp.from:sp.to)==null&&(!found||compareCollapsedMarkers(found,sp.marker)<0)){found=sp.marker}}}return found}function collapsedSpanAtStart(line){return collapsedSpanAtSide(line,true)}function collapsedSpanAtEnd(line){return collapsedSpanAtSide(line,false)}function collapsedSpanAround(line,ch){var sps=sawCollapsedSpans&&line.markedSpans,found;if(sps){for(var i=0;i<sps.length;++i){var sp=sps[i];if(sp.marker.collapsed&&(sp.from==null||sp.from<ch)&&(sp.to==null||sp.to>ch)&&(!found||compareCollapsedMarkers(found,sp.marker)<0)){found=sp.marker}}}return found}function conflictingCollapsedRange(doc,lineNo,from,to,marker){var line=getLine(doc,lineNo);var sps=sawCollapsedSpans&&line.markedSpans;if(sps){for(var i=0;i<sps.length;++i){var sp=sps[i];if(!sp.marker.collapsed){continue}var found=sp.marker.find(0);var fromCmp=cmp(found.from,from)||extraLeft(sp.marker)-extraLeft(marker);var toCmp=cmp(found.to,to)||extraRight(sp.marker)-extraRight(marker);if(fromCmp>=0&&toCmp<=0||fromCmp<=0&&toCmp>=0){continue}if(fromCmp<=0&&(sp.marker.inclusiveRight&&marker.inclusiveLeft?cmp(found.to,from)>=0:cmp(found.to,from)>0)||fromCmp>=0&&(sp.marker.inclusiveRight&&marker.inclusiveLeft?cmp(found.from,to)<=0:cmp(found.from,to)<0)){return true}}}}function visualLine(line){var merged;while(merged=collapsedSpanAtStart(line)){line=merged.find(-1,true).line}return line}function visualLineEnd(line){var merged;while(merged=collapsedSpanAtEnd(line)){line=merged.find(1,true).line}return line}function visualLineContinued(line){var merged,lines;while(merged=collapsedSpanAtEnd(line)){line=merged.find(1,true).line;(lines||(lines=[])).push(line)}return lines}function visualLineNo(doc,lineN){var line=getLine(doc,lineN),vis=visualLine(line);if(line==vis){return lineN}return lineNo(vis)}function visualLineEndNo(doc,lineN){if(lineN>doc.lastLine()){return lineN}var line=getLine(doc,lineN),merged;if(!lineIsHidden(doc,line)){return lineN}while(merged=collapsedSpanAtEnd(line)){line=merged.find(1,true).line}return lineNo(line)+1}function lineIsHidden(doc,line){var sps=sawCollapsedSpans&&line.markedSpans;if(sps){for(var sp=void 0,i=0;i<sps.length;++i){sp=sps[i];if(!sp.marker.collapsed){continue}if(sp.from==null){return true}if(sp.marker.widgetNode){continue}if(sp.from==0&&sp.marker.inclusiveLeft&&lineIsHiddenInner(doc,line,sp)){return true}}}}function lineIsHiddenInner(doc,line,span){if(span.to==null){var end=span.marker.find(1,true);return lineIsHiddenInner(doc,end.line,getMarkedSpanFor(end.line.markedSpans,span.marker))}if(span.marker.inclusiveRight&&span.to==line.text.length){return true}for(var sp=void 0,i=0;i<line.markedSpans.length;++i){sp=line.markedSpans[i];if(sp.marker.collapsed&&!sp.marker.widgetNode&&sp.from==span.to&&(sp.to==null||sp.to!=span.from)&&(sp.marker.inclusiveLeft||span.marker.inclusiveRight)&&lineIsHiddenInner(doc,line,sp)){return true}}}function heightAtLine(lineObj){lineObj=visualLine(lineObj);var h=0,chunk=lineObj.parent;for(var i=0;i<chunk.lines.length;++i){var line=chunk.lines[i];if(line==lineObj){break}else{h+=line.height}}for(var p=chunk.parent;p;chunk=p,p=chunk.parent){for(var i$1=0;i$1<p.children.length;++i$1){var cur=p.children[i$1];if(cur==chunk){break}else{h+=cur.height}}}return h}function lineLength(line){if(line.height==0){return 0}var len=line.text.length,merged,cur=line;while(merged=collapsedSpanAtStart(cur)){var found=merged.find(0,true);cur=found.from.line;len+=found.from.ch-found.to.ch}cur=line;while(merged=collapsedSpanAtEnd(cur)){var found$1=merged.find(0,true);len-=cur.text.length-found$1.from.ch;cur=found$1.to.line;len+=cur.text.length-found$1.to.ch}return len}function findMaxLine(cm){var d=cm.display,doc=cm.doc;d.maxLine=getLine(doc,doc.first);d.maxLineLength=lineLength(d.maxLine);d.maxLineChanged=true;doc.iter((function(line){var len=lineLength(line);if(len>d.maxLineLength){d.maxLineLength=len;d.maxLine=line}}))}var Line=function(text,markedSpans,estimateHeight){this.text=text;attachMarkedSpans(this,markedSpans);this.height=estimateHeight?estimateHeight(this):1};Line.prototype.lineNo=function(){return lineNo(this)};eventMixin(Line);function updateLine(line,text,markedSpans,estimateHeight){line.text=text;if(line.stateAfter){line.stateAfter=null}if(line.styles){line.styles=null}if(line.order!=null){line.order=null}detachMarkedSpans(line);attachMarkedSpans(line,markedSpans);var estHeight=estimateHeight?estimateHeight(line):1;if(estHeight!=line.height){updateLineHeight(line,estHeight)}}function cleanUpLine(line){line.parent=null;detachMarkedSpans(line)}var styleToClassCache={},styleToClassCacheWithMode={};function interpretTokenStyle(style,options){if(!style||/^\s*$/.test(style)){return null}var cache=options.addModeClass?styleToClassCacheWithMode:styleToClassCache;return cache[style]||(cache[style]=style.replace(/\S+/g,"cm-$&"))}function buildLineContent(cm,lineView){var content=eltP("span",null,null,webkit?"padding-right: .1px":null);var builder={pre:eltP("pre",[content],"CodeMirror-line"),content:content,col:0,pos:0,cm:cm,trailingSpace:false,splitSpaces:cm.getOption("lineWrapping")};lineView.measure={};for(var i=0;i<=(lineView.rest?lineView.rest.length:0);i++){var line=i?lineView.rest[i-1]:lineView.line,order=void 0;builder.pos=0;builder.addToken=buildToken;if(hasBadBidiRects(cm.display.measure)&&(order=getOrder(line,cm.doc.direction))){builder.addToken=buildTokenBadBidi(builder.addToken,order)}builder.map=[];var allowFrontierUpdate=lineView!=cm.display.externalMeasured&&lineNo(line);insertLineContent(line,builder,getLineStyles(cm,line,allowFrontierUpdate));if(line.styleClasses){if(line.styleClasses.bgClass){builder.bgClass=joinClasses(line.styleClasses.bgClass,builder.bgClass||"")}if(line.styleClasses.textClass){builder.textClass=joinClasses(line.styleClasses.textClass,builder.textClass||"")}}if(builder.map.length==0){builder.map.push(0,0,builder.content.appendChild(zeroWidthElement(cm.display.measure)))}if(i==0){lineView.measure.map=builder.map;lineView.measure.cache={}}else{(lineView.measure.maps||(lineView.measure.maps=[])).push(builder.map);(lineView.measure.caches||(lineView.measure.caches=[])).push({})}}if(webkit){var last=builder.content.lastChild;if(/\bcm-tab\b/.test(last.className)||last.querySelector&&last.querySelector(".cm-tab")){builder.content.className="cm-tab-wrap-hack"}}signal(cm,"renderLine",cm,lineView.line,builder.pre);if(builder.pre.className){builder.textClass=joinClasses(builder.pre.className,builder.textClass||"")}return builder}function defaultSpecialCharPlaceholder(ch){var token=elt("span","•","cm-invalidchar");token.title="\\u"+ch.charCodeAt(0).toString(16);token.setAttribute("aria-label",token.title);return token}function buildToken(builder,text,style,startStyle,endStyle,css,attributes){if(!text){return}var displayText=builder.splitSpaces?splitSpaces(text,builder.trailingSpace):text;var special=builder.cm.state.specialChars,mustWrap=false;var content;if(!special.test(text)){builder.col+=text.length;content=document.createTextNode(displayText);builder.map.push(builder.pos,builder.pos+text.length,content);if(ie&&ie_version<9){mustWrap=true}builder.pos+=text.length}else{content=document.createDocumentFragment();var pos=0;while(true){special.lastIndex=pos;var m=special.exec(text);var skipped=m?m.index-pos:text.length-pos;if(skipped){var txt=document.createTextNode(displayText.slice(pos,pos+skipped));if(ie&&ie_version<9){content.appendChild(elt("span",[txt]))}else{content.appendChild(txt)}builder.map.push(builder.pos,builder.pos+skipped,txt);builder.col+=skipped;builder.pos+=skipped}if(!m){break}pos+=skipped+1;var txt$1=void 0;if(m[0]=="\t"){var tabSize=builder.cm.options.tabSize,tabWidth=tabSize-builder.col%tabSize;txt$1=content.appendChild(elt("span",spaceStr(tabWidth),"cm-tab"));txt$1.setAttribute("role","presentation");txt$1.setAttribute("cm-text","\t");builder.col+=tabWidth}else if(m[0]=="\r"||m[0]=="\n"){txt$1=content.appendChild(elt("span",m[0]=="\r"?"␍":"␤","cm-invalidchar"));txt$1.setAttribute("cm-text",m[0]);builder.col+=1}else{txt$1=builder.cm.options.specialCharPlaceholder(m[0]);txt$1.setAttribute("cm-text",m[0]);if(ie&&ie_version<9){content.appendChild(elt("span",[txt$1]))}else{content.appendChild(txt$1)}builder.col+=1}builder.map.push(builder.pos,builder.pos+1,txt$1);builder.pos++}}builder.trailingSpace=displayText.charCodeAt(text.length-1)==32;if(style||startStyle||endStyle||mustWrap||css||attributes){var fullStyle=style||"";if(startStyle){fullStyle+=startStyle}if(endStyle){fullStyle+=endStyle}var token=elt("span",[content],fullStyle,css);if(attributes){for(var attr in attributes){if(attributes.hasOwnProperty(attr)&&attr!="style"&&attr!="class"){token.setAttribute(attr,attributes[attr])}}}return builder.content.appendChild(token)}builder.content.appendChild(content)}function splitSpaces(text,trailingBefore){if(text.length>1&&!/  /.test(text)){return text}var spaceBefore=trailingBefore,result="";for(var i=0;i<text.length;i++){var ch=text.charAt(i);if(ch==" "&&spaceBefore&&(i==text.length-1||text.charCodeAt(i+1)==32)){ch=" "}result+=ch;spaceBefore=ch==" "}return result}function buildTokenBadBidi(inner,order){return function(builder,text,style,startStyle,endStyle,css,attributes){style=style?style+" cm-force-border":"cm-force-border";var start=builder.pos,end=start+text.length;for(;;){var part=void 0;for(var i=0;i<order.length;i++){part=order[i];if(part.to>start&&part.from<=start){break}}if(part.to>=end){return inner(builder,text,style,startStyle,endStyle,css,attributes)}inner(builder,text.slice(0,part.to-start),style,startStyle,null,css,attributes);startStyle=null;text=text.slice(part.to-start);start=part.to}}}function buildCollapsedSpan(builder,size,marker,ignoreWidget){var widget=!ignoreWidget&&marker.widgetNode;if(widget){builder.map.push(builder.pos,builder.pos+size,widget)}if(!ignoreWidget&&builder.cm.display.input.needsContentAttribute){if(!widget){widget=builder.content.appendChild(document.createElement("span"))}widget.setAttribute("cm-marker",marker.id)}if(widget){builder.cm.display.input.setUneditable(widget);builder.content.appendChild(widget)}builder.pos+=size;builder.trailingSpace=false}function insertLineContent(line,builder,styles){var spans=line.markedSpans,allText=line.text,at=0;if(!spans){for(var i$1=1;i$1<styles.length;i$1+=2){builder.addToken(builder,allText.slice(at,at=styles[i$1]),interpretTokenStyle(styles[i$1+1],builder.cm.options))}return}var len=allText.length,pos=0,i=1,text="",style,css;var nextChange=0,spanStyle,spanEndStyle,spanStartStyle,collapsed,attributes;for(;;){if(nextChange==pos){spanStyle=spanEndStyle=spanStartStyle=css="";attributes=null;collapsed=null;nextChange=Infinity;var foundBookmarks=[],endStyles=void 0;for(var j=0;j<spans.length;++j){var sp=spans[j],m=sp.marker;if(m.type=="bookmark"&&sp.from==pos&&m.widgetNode){foundBookmarks.push(m)}else if(sp.from<=pos&&(sp.to==null||sp.to>pos||m.collapsed&&sp.to==pos&&sp.from==pos)){if(sp.to!=null&&sp.to!=pos&&nextChange>sp.to){nextChange=sp.to;spanEndStyle=""}if(m.className){spanStyle+=" "+m.className}if(m.css){css=(css?css+";":"")+m.css}if(m.startStyle&&sp.from==pos){spanStartStyle+=" "+m.startStyle}if(m.endStyle&&sp.to==nextChange){(endStyles||(endStyles=[])).push(m.endStyle,sp.to)}if(m.title){(attributes||(attributes={})).title=m.title}if(m.attributes){for(var attr in m.attributes){(attributes||(attributes={}))[attr]=m.attributes[attr]}}if(m.collapsed&&(!collapsed||compareCollapsedMarkers(collapsed.marker,m)<0)){collapsed=sp}}else if(sp.from>pos&&nextChange>sp.from){nextChange=sp.from}}if(endStyles){for(var j$1=0;j$1<endStyles.length;j$1+=2){if(endStyles[j$1+1]==nextChange){spanEndStyle+=" "+endStyles[j$1]}}}if(!collapsed||collapsed.from==pos){for(var j$2=0;j$2<foundBookmarks.length;++j$2){buildCollapsedSpan(builder,0,foundBookmarks[j$2])}}if(collapsed&&(collapsed.from||0)==pos){buildCollapsedSpan(builder,(collapsed.to==null?len+1:collapsed.to)-pos,collapsed.marker,collapsed.from==null);if(collapsed.to==null){return}if(collapsed.to==pos){collapsed=false}}}if(pos>=len){break}var upto=Math.min(len,nextChange);while(true){if(text){var end=pos+text.length;if(!collapsed){var tokenText=end>upto?text.slice(0,upto-pos):text;builder.addToken(builder,tokenText,style?style+spanStyle:spanStyle,spanStartStyle,pos+tokenText.length==nextChange?spanEndStyle:"",css,attributes)}if(end>=upto){text=text.slice(upto-pos);pos=upto;break}pos=end;spanStartStyle=""}text=allText.slice(at,at=styles[i++]);style=interpretTokenStyle(styles[i++],builder.cm.options)}}}function LineView(doc,line,lineN){this.line=line;this.rest=visualLineContinued(line);this.size=this.rest?lineNo(lst(this.rest))-lineN+1:1;this.node=this.text=null;this.hidden=lineIsHidden(doc,line)}function buildViewArray(cm,from,to){var array=[],nextPos;for(var pos=from;pos<to;pos=nextPos){var view=new LineView(cm.doc,getLine(cm.doc,pos),pos);nextPos=pos+view.size;array.push(view)}return array}var operationGroup=null;function pushOperation(op){if(operationGroup){operationGroup.ops.push(op)}else{op.ownsGroup=operationGroup={ops:[op],delayedCallbacks:[]}}}function fireCallbacksForOps(group){var callbacks=group.delayedCallbacks,i=0;do{for(;i<callbacks.length;i++){callbacks[i].call(null)}for(var j=0;j<group.ops.length;j++){var op=group.ops[j];if(op.cursorActivityHandlers){while(op.cursorActivityCalled<op.cursorActivityHandlers.length){op.cursorActivityHandlers[op.cursorActivityCalled++].call(null,op.cm)}}}}while(i<callbacks.length)}function finishOperation(op,endCb){var group=op.ownsGroup;if(!group){return}try{fireCallbacksForOps(group)}finally{operationGroup=null;endCb(group)}}var orphanDelayedCallbacks=null;function signalLater(emitter,type){var arr=getHandlers(emitter,type);if(!arr.length){return}var args=Array.prototype.slice.call(arguments,2),list;if(operationGroup){list=operationGroup.delayedCallbacks}else if(orphanDelayedCallbacks){list=orphanDelayedCallbacks}else{list=orphanDelayedCallbacks=[];setTimeout(fireOrphanDelayed,0)}var loop=function(i){list.push((function(){return arr[i].apply(null,args)}))};for(var i=0;i<arr.length;++i)loop(i)}function fireOrphanDelayed(){var delayed=orphanDelayedCallbacks;orphanDelayedCallbacks=null;for(var i=0;i<delayed.length;++i){delayed[i]()}}function updateLineForChanges(cm,lineView,lineN,dims){for(var j=0;j<lineView.changes.length;j++){var type=lineView.changes[j];if(type=="text"){updateLineText(cm,lineView)}else if(type=="gutter"){updateLineGutter(cm,lineView,lineN,dims)}else if(type=="class"){updateLineClasses(cm,lineView)}else if(type=="widget"){updateLineWidgets(cm,lineView,dims)}}lineView.changes=null}function ensureLineWrapped(lineView){if(lineView.node==lineView.text){lineView.node=elt("div",null,null,"position: relative");if(lineView.text.parentNode){lineView.text.parentNode.replaceChild(lineView.node,lineView.text)}lineView.node.appendChild(lineView.text);if(ie&&ie_version<8){lineView.node.style.zIndex=2}}return lineView.node}function updateLineBackground(cm,lineView){var cls=lineView.bgClass?lineView.bgClass+" "+(lineView.line.bgClass||""):lineView.line.bgClass;if(cls){cls+=" CodeMirror-linebackground"}if(lineView.background){if(cls){lineView.background.className=cls}else{lineView.background.parentNode.removeChild(lineView.background);lineView.background=null}}else if(cls){var wrap=ensureLineWrapped(lineView);lineView.background=wrap.insertBefore(elt("div",null,cls),wrap.firstChild);cm.display.input.setUneditable(lineView.background)}}function getLineContent(cm,lineView){var ext=cm.display.externalMeasured;if(ext&&ext.line==lineView.line){cm.display.externalMeasured=null;lineView.measure=ext.measure;return ext.built}return buildLineContent(cm,lineView)}function updateLineText(cm,lineView){var cls=lineView.text.className;var built=getLineContent(cm,lineView);if(lineView.text==lineView.node){lineView.node=built.pre}lineView.text.parentNode.replaceChild(built.pre,lineView.text);lineView.text=built.pre;if(built.bgClass!=lineView.bgClass||built.textClass!=lineView.textClass){lineView.bgClass=built.bgClass;lineView.textClass=built.textClass;updateLineClasses(cm,lineView)}else if(cls){lineView.text.className=cls}}function updateLineClasses(cm,lineView){updateLineBackground(cm,lineView);if(lineView.line.wrapClass){ensureLineWrapped(lineView).className=lineView.line.wrapClass}else if(lineView.node!=lineView.text){lineView.node.className=""}var textClass=lineView.textClass?lineView.textClass+" "+(lineView.line.textClass||""):lineView.line.textClass;lineView.text.className=textClass||""}function updateLineGutter(cm,lineView,lineN,dims){if(lineView.gutter){lineView.node.removeChild(lineView.gutter);lineView.gutter=null}if(lineView.gutterBackground){lineView.node.removeChild(lineView.gutterBackground);lineView.gutterBackground=null}if(lineView.line.gutterClass){var wrap=ensureLineWrapped(lineView);lineView.gutterBackground=elt("div",null,"CodeMirror-gutter-background "+lineView.line.gutterClass,"left: "+(cm.options.fixedGutter?dims.fixedPos:-dims.gutterTotalWidth)+"px; width: "+dims.gutterTotalWidth+"px");cm.display.input.setUneditable(lineView.gutterBackground);wrap.insertBefore(lineView.gutterBackground,lineView.text)}var markers=lineView.line.gutterMarkers;if(cm.options.lineNumbers||markers){var wrap$1=ensureLineWrapped(lineView);var gutterWrap=lineView.gutter=elt("div",null,"CodeMirror-gutter-wrapper","left: "+(cm.options.fixedGutter?dims.fixedPos:-dims.gutterTotalWidth)+"px");gutterWrap.setAttribute("aria-hidden","true");cm.display.input.setUneditable(gutterWrap);wrap$1.insertBefore(gutterWrap,lineView.text);if(lineView.line.gutterClass){gutterWrap.className+=" "+lineView.line.gutterClass}if(cm.options.lineNumbers&&(!markers||!markers["CodeMirror-linenumbers"])){lineView.lineNumber=gutterWrap.appendChild(elt("div",lineNumberFor(cm.options,lineN),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+dims.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+cm.display.lineNumInnerWidth+"px"))}if(markers){for(var k=0;k<cm.display.gutterSpecs.length;++k){var id=cm.display.gutterSpecs[k].className,found=markers.hasOwnProperty(id)&&markers[id];if(found){gutterWrap.appendChild(elt("div",[found],"CodeMirror-gutter-elt","left: "+dims.gutterLeft[id]+"px; width: "+dims.gutterWidth[id]+"px"))}}}}}function updateLineWidgets(cm,lineView,dims){if(lineView.alignable){lineView.alignable=null}var isWidget=classTest("CodeMirror-linewidget");for(var node=lineView.node.firstChild,next=void 0;node;node=next){next=node.nextSibling;if(isWidget.test(node.className)){lineView.node.removeChild(node)}}insertLineWidgets(cm,lineView,dims)}function buildLineElement(cm,lineView,lineN,dims){var built=getLineContent(cm,lineView);lineView.text=lineView.node=built.pre;if(built.bgClass){lineView.bgClass=built.bgClass}if(built.textClass){lineView.textClass=built.textClass}updateLineClasses(cm,lineView);updateLineGutter(cm,lineView,lineN,dims);insertLineWidgets(cm,lineView,dims);return lineView.node}function insertLineWidgets(cm,lineView,dims){insertLineWidgetsFor(cm,lineView.line,lineView,dims,true);if(lineView.rest){for(var i=0;i<lineView.rest.length;i++){insertLineWidgetsFor(cm,lineView.rest[i],lineView,dims,false)}}}function insertLineWidgetsFor(cm,line,lineView,dims,allowAbove){if(!line.widgets){return}var wrap=ensureLineWrapped(lineView);for(var i=0,ws=line.widgets;i<ws.length;++i){var widget=ws[i],node=elt("div",[widget.node],"CodeMirror-linewidget"+(widget.className?" "+widget.className:""));if(!widget.handleMouseEvents){node.setAttribute("cm-ignore-events","true")}positionLineWidget(widget,node,lineView,dims);cm.display.input.setUneditable(node);if(allowAbove&&widget.above){wrap.insertBefore(node,lineView.gutter||lineView.text)}else{wrap.appendChild(node)}signalLater(widget,"redraw")}}function positionLineWidget(widget,node,lineView,dims){if(widget.noHScroll){(lineView.alignable||(lineView.alignable=[])).push(node);var width=dims.wrapperWidth;node.style.left=dims.fixedPos+"px";if(!widget.coverGutter){width-=dims.gutterTotalWidth;node.style.paddingLeft=dims.gutterTotalWidth+"px"}node.style.width=width+"px"}if(widget.coverGutter){node.style.zIndex=5;node.style.position="relative";if(!widget.noHScroll){node.style.marginLeft=-dims.gutterTotalWidth+"px"}}}function widgetHeight(widget){if(widget.height!=null){return widget.height}var cm=widget.doc.cm;if(!cm){return 0}if(!contains(document.body,widget.node)){var parentStyle="position: relative;";if(widget.coverGutter){parentStyle+="margin-left: -"+cm.display.gutters.offsetWidth+"px;"}if(widget.noHScroll){parentStyle+="width: "+cm.display.wrapper.clientWidth+"px;"}removeChildrenAndAdd(cm.display.measure,elt("div",[widget.node],null,parentStyle))}return widget.height=widget.node.parentNode.offsetHeight}function eventInWidget(display,e){for(var n=e_target(e);n!=display.wrapper;n=n.parentNode){if(!n||n.nodeType==1&&n.getAttribute("cm-ignore-events")=="true"||n.parentNode==display.sizer&&n!=display.mover){return true}}}function paddingTop(display){return display.lineSpace.offsetTop}function paddingVert(display){return display.mover.offsetHeight-display.lineSpace.offsetHeight}function paddingH(display){if(display.cachedPaddingH){return display.cachedPaddingH}var e=removeChildrenAndAdd(display.measure,elt("pre","x","CodeMirror-line-like"));var style=window.getComputedStyle?window.getComputedStyle(e):e.currentStyle;var data={left:parseInt(style.paddingLeft),right:parseInt(style.paddingRight)};if(!isNaN(data.left)&&!isNaN(data.right)){display.cachedPaddingH=data}return data}function scrollGap(cm){return scrollerGap-cm.display.nativeBarWidth}function displayWidth(cm){return cm.display.scroller.clientWidth-scrollGap(cm)-cm.display.barWidth}function displayHeight(cm){return cm.display.scroller.clientHeight-scrollGap(cm)-cm.display.barHeight}function ensureLineHeights(cm,lineView,rect){var wrapping=cm.options.lineWrapping;var curWidth=wrapping&&displayWidth(cm);if(!lineView.measure.heights||wrapping&&lineView.measure.width!=curWidth){var heights=lineView.measure.heights=[];if(wrapping){lineView.measure.width=curWidth;var rects=lineView.text.firstChild.getClientRects();for(var i=0;i<rects.length-1;i++){var cur=rects[i],next=rects[i+1];if(Math.abs(cur.bottom-next.bottom)>2){heights.push((cur.bottom+next.top)/2-rect.top)}}}heights.push(rect.bottom-rect.top)}}function mapFromLineView(lineView,line,lineN){if(lineView.line==line){return{map:lineView.measure.map,cache:lineView.measure.cache}}if(lineView.rest){for(var i=0;i<lineView.rest.length;i++){if(lineView.rest[i]==line){return{map:lineView.measure.maps[i],cache:lineView.measure.caches[i]}}}for(var i$1=0;i$1<lineView.rest.length;i$1++){if(lineNo(lineView.rest[i$1])>lineN){return{map:lineView.measure.maps[i$1],cache:lineView.measure.caches[i$1],before:true}}}}}function updateExternalMeasurement(cm,line){line=visualLine(line);var lineN=lineNo(line);var view=cm.display.externalMeasured=new LineView(cm.doc,line,lineN);view.lineN=lineN;var built=view.built=buildLineContent(cm,view);view.text=built.pre;removeChildrenAndAdd(cm.display.lineMeasure,built.pre);return view}function measureChar(cm,line,ch,bias){return measureCharPrepared(cm,prepareMeasureForLine(cm,line),ch,bias)}function findViewForLine(cm,lineN){if(lineN>=cm.display.viewFrom&&lineN<cm.display.viewTo){return cm.display.view[findViewIndex(cm,lineN)]}var ext=cm.display.externalMeasured;if(ext&&lineN>=ext.lineN&&lineN<ext.lineN+ext.size){return ext}}function prepareMeasureForLine(cm,line){var lineN=lineNo(line);var view=findViewForLine(cm,lineN);if(view&&!view.text){view=null}else if(view&&view.changes){updateLineForChanges(cm,view,lineN,getDimensions(cm));cm.curOp.forceUpdate=true}if(!view){view=updateExternalMeasurement(cm,line)}var info=mapFromLineView(view,line,lineN);return{line:line,view:view,rect:null,map:info.map,cache:info.cache,before:info.before,hasHeights:false}}function measureCharPrepared(cm,prepared,ch,bias,varHeight){if(prepared.before){ch=-1}var key=ch+(bias||""),found;if(prepared.cache.hasOwnProperty(key)){found=prepared.cache[key]}else{if(!prepared.rect){prepared.rect=prepared.view.text.getBoundingClientRect()}if(!prepared.hasHeights){ensureLineHeights(cm,prepared.view,prepared.rect);prepared.hasHeights=true}found=measureCharInner(cm,prepared,ch,bias);if(!found.bogus){prepared.cache[key]=found}}return{left:found.left,right:found.right,top:varHeight?found.rtop:found.top,bottom:varHeight?found.rbottom:found.bottom}}var nullRect={left:0,right:0,top:0,bottom:0};function nodeAndOffsetInLineMap(map,ch,bias){var node,start,end,collapse,mStart,mEnd;for(var i=0;i<map.length;i+=3){mStart=map[i];mEnd=map[i+1];if(ch<mStart){start=0;end=1;collapse="left"}else if(ch<mEnd){start=ch-mStart;end=start+1}else if(i==map.length-3||ch==mEnd&&map[i+3]>ch){end=mEnd-mStart;start=end-1;if(ch>=mEnd){collapse="right"}}if(start!=null){node=map[i+2];if(mStart==mEnd&&bias==(node.insertLeft?"left":"right")){collapse=bias}if(bias=="left"&&start==0){while(i&&map[i-2]==map[i-3]&&map[i-1].insertLeft){node=map[(i-=3)+2];collapse="left"}}if(bias=="right"&&start==mEnd-mStart){while(i<map.length-3&&map[i+3]==map[i+4]&&!map[i+5].insertLeft){node=map[(i+=3)+2];collapse="right"}}break}}return{node:node,start:start,end:end,collapse:collapse,coverStart:mStart,coverEnd:mEnd}}function getUsefulRect(rects,bias){var rect=nullRect;if(bias=="left"){for(var i=0;i<rects.length;i++){if((rect=rects[i]).left!=rect.right){break}}}else{for(var i$1=rects.length-1;i$1>=0;i$1--){if((rect=rects[i$1]).left!=rect.right){break}}}return rect}function measureCharInner(cm,prepared,ch,bias){var place=nodeAndOffsetInLineMap(prepared.map,ch,bias);var node=place.node,start=place.start,end=place.end,collapse=place.collapse;var rect;if(node.nodeType==3){for(var i$1=0;i$1<4;i$1++){while(start&&isExtendingChar(prepared.line.text.charAt(place.coverStart+start))){--start}while(place.coverStart+end<place.coverEnd&&isExtendingChar(prepared.line.text.charAt(place.coverStart+end))){++end}if(ie&&ie_version<9&&start==0&&end==place.coverEnd-place.coverStart){rect=node.parentNode.getBoundingClientRect()}else{rect=getUsefulRect(range(node,start,end).getClientRects(),bias)}if(rect.left||rect.right||start==0){break}end=start;start=start-1;collapse="right"}if(ie&&ie_version<11){rect=maybeUpdateRectForZooming(cm.display.measure,rect)}}else{if(start>0){collapse=bias="right"}var rects;if(cm.options.lineWrapping&&(rects=node.getClientRects()).length>1){rect=rects[bias=="right"?rects.length-1:0]}else{rect=node.getBoundingClientRect()}}if(ie&&ie_version<9&&!start&&(!rect||!rect.left&&!rect.right)){var rSpan=node.parentNode.getClientRects()[0];if(rSpan){rect={left:rSpan.left,right:rSpan.left+charWidth(cm.display),top:rSpan.top,bottom:rSpan.bottom}}else{rect=nullRect}}var rtop=rect.top-prepared.rect.top,rbot=rect.bottom-prepared.rect.top;var mid=(rtop+rbot)/2;var heights=prepared.view.measure.heights;var i=0;for(;i<heights.length-1;i++){if(mid<heights[i]){break}}var top=i?heights[i-1]:0,bot=heights[i];var result={left:(collapse=="right"?rect.right:rect.left)-prepared.rect.left,right:(collapse=="left"?rect.left:rect.right)-prepared.rect.left,top:top,bottom:bot};if(!rect.left&&!rect.right){result.bogus=true}if(!cm.options.singleCursorHeightPerLine){result.rtop=rtop;result.rbottom=rbot}return result}function maybeUpdateRectForZooming(measure,rect){if(!window.screen||screen.logicalXDPI==null||screen.logicalXDPI==screen.deviceXDPI||!hasBadZoomedRects(measure)){return rect}var scaleX=screen.logicalXDPI/screen.deviceXDPI;var scaleY=screen.logicalYDPI/screen.deviceYDPI;return{left:rect.left*scaleX,right:rect.right*scaleX,top:rect.top*scaleY,bottom:rect.bottom*scaleY}}function clearLineMeasurementCacheFor(lineView){if(lineView.measure){lineView.measure.cache={};lineView.measure.heights=null;if(lineView.rest){for(var i=0;i<lineView.rest.length;i++){lineView.measure.caches[i]={}}}}}function clearLineMeasurementCache(cm){cm.display.externalMeasure=null;removeChildren(cm.display.lineMeasure);for(var i=0;i<cm.display.view.length;i++){clearLineMeasurementCacheFor(cm.display.view[i])}}function clearCaches(cm){clearLineMeasurementCache(cm);cm.display.cachedCharWidth=cm.display.cachedTextHeight=cm.display.cachedPaddingH=null;if(!cm.options.lineWrapping){cm.display.maxLineChanged=true}cm.display.lineNumChars=null}function pageScrollX(doc){if(chrome&&android){return-(doc.body.getBoundingClientRect().left-parseInt(getComputedStyle(doc.body).marginLeft))}return doc.defaultView.pageXOffset||(doc.documentElement||doc.body).scrollLeft}function pageScrollY(doc){if(chrome&&android){return-(doc.body.getBoundingClientRect().top-parseInt(getComputedStyle(doc.body).marginTop))}return doc.defaultView.pageYOffset||(doc.documentElement||doc.body).scrollTop}function widgetTopHeight(lineObj){var ref=visualLine(lineObj);var widgets=ref.widgets;var height=0;if(widgets){for(var i=0;i<widgets.length;++i){if(widgets[i].above){height+=widgetHeight(widgets[i])}}}return height}function intoCoordSystem(cm,lineObj,rect,context,includeWidgets){if(!includeWidgets){var height=widgetTopHeight(lineObj);rect.top+=height;rect.bottom+=height}if(context=="line"){return rect}if(!context){context="local"}var yOff=heightAtLine(lineObj);if(context=="local"){yOff+=paddingTop(cm.display)}else{yOff-=cm.display.viewOffset}if(context=="page"||context=="window"){var lOff=cm.display.lineSpace.getBoundingClientRect();yOff+=lOff.top+(context=="window"?0:pageScrollY(doc(cm)));var xOff=lOff.left+(context=="window"?0:pageScrollX(doc(cm)));rect.left+=xOff;rect.right+=xOff}rect.top+=yOff;rect.bottom+=yOff;return rect}function fromCoordSystem(cm,coords,context){if(context=="div"){return coords}var left=coords.left,top=coords.top;if(context=="page"){left-=pageScrollX(doc(cm));top-=pageScrollY(doc(cm))}else if(context=="local"||!context){var localBox=cm.display.sizer.getBoundingClientRect();left+=localBox.left;top+=localBox.top}var lineSpaceBox=cm.display.lineSpace.getBoundingClientRect();return{left:left-lineSpaceBox.left,top:top-lineSpaceBox.top}}function charCoords(cm,pos,context,lineObj,bias){if(!lineObj){lineObj=getLine(cm.doc,pos.line)}return intoCoordSystem(cm,lineObj,measureChar(cm,lineObj,pos.ch,bias),context)}function cursorCoords(cm,pos,context,lineObj,preparedMeasure,varHeight){lineObj=lineObj||getLine(cm.doc,pos.line);if(!preparedMeasure){preparedMeasure=prepareMeasureForLine(cm,lineObj)}function get(ch,right){var m=measureCharPrepared(cm,preparedMeasure,ch,right?"right":"left",varHeight);if(right){m.left=m.right}else{m.right=m.left}return intoCoordSystem(cm,lineObj,m,context)}var order=getOrder(lineObj,cm.doc.direction),ch=pos.ch,sticky=pos.sticky;if(ch>=lineObj.text.length){ch=lineObj.text.length;sticky="before"}else if(ch<=0){ch=0;sticky="after"}if(!order){return get(sticky=="before"?ch-1:ch,sticky=="before")}function getBidi(ch,partPos,invert){var part=order[partPos],right=part.level==1;return get(invert?ch-1:ch,right!=invert)}var partPos=getBidiPartAt(order,ch,sticky);var other=bidiOther;var val=getBidi(ch,partPos,sticky=="before");if(other!=null){val.other=getBidi(ch,other,sticky!="before")}return val}function estimateCoords(cm,pos){var left=0;pos=clipPos(cm.doc,pos);if(!cm.options.lineWrapping){left=charWidth(cm.display)*pos.ch}var lineObj=getLine(cm.doc,pos.line);var top=heightAtLine(lineObj)+paddingTop(cm.display);return{left:left,right:left,top:top,bottom:top+lineObj.height}}function PosWithInfo(line,ch,sticky,outside,xRel){var pos=Pos(line,ch,sticky);pos.xRel=xRel;if(outside){pos.outside=outside}return pos}function coordsChar(cm,x,y){var doc=cm.doc;y+=cm.display.viewOffset;if(y<0){return PosWithInfo(doc.first,0,null,-1,-1)}var lineN=lineAtHeight(doc,y),last=doc.first+doc.size-1;if(lineN>last){return PosWithInfo(doc.first+doc.size-1,getLine(doc,last).text.length,null,1,1)}if(x<0){x=0}var lineObj=getLine(doc,lineN);for(;;){var found=coordsCharInner(cm,lineObj,lineN,x,y);var collapsed=collapsedSpanAround(lineObj,found.ch+(found.xRel>0||found.outside>0?1:0));if(!collapsed){return found}var rangeEnd=collapsed.find(1);if(rangeEnd.line==lineN){return rangeEnd}lineObj=getLine(doc,lineN=rangeEnd.line)}}function wrappedLineExtent(cm,lineObj,preparedMeasure,y){y-=widgetTopHeight(lineObj);var end=lineObj.text.length;var begin=findFirst((function(ch){return measureCharPrepared(cm,preparedMeasure,ch-1).bottom<=y}),end,0);end=findFirst((function(ch){return measureCharPrepared(cm,preparedMeasure,ch).top>y}),begin,end);return{begin:begin,end:end}}function wrappedLineExtentChar(cm,lineObj,preparedMeasure,target){if(!preparedMeasure){preparedMeasure=prepareMeasureForLine(cm,lineObj)}var targetTop=intoCoordSystem(cm,lineObj,measureCharPrepared(cm,preparedMeasure,target),"line").top;return wrappedLineExtent(cm,lineObj,preparedMeasure,targetTop)}function boxIsAfter(box,x,y,left){return box.bottom<=y?false:box.top>y?true:(left?box.left:box.right)>x}function coordsCharInner(cm,lineObj,lineNo,x,y){y-=heightAtLine(lineObj);var preparedMeasure=prepareMeasureForLine(cm,lineObj);var widgetHeight=widgetTopHeight(lineObj);var begin=0,end=lineObj.text.length,ltr=true;var order=getOrder(lineObj,cm.doc.direction);if(order){var part=(cm.options.lineWrapping?coordsBidiPartWrapped:coordsBidiPart)(cm,lineObj,lineNo,preparedMeasure,order,x,y);ltr=part.level!=1;begin=ltr?part.from:part.to-1;end=ltr?part.to:part.from-1}var chAround=null,boxAround=null;var ch=findFirst((function(ch){var box=measureCharPrepared(cm,preparedMeasure,ch);box.top+=widgetHeight;box.bottom+=widgetHeight;if(!boxIsAfter(box,x,y,false)){return false}if(box.top<=y&&box.left<=x){chAround=ch;boxAround=box}return true}),begin,end);var baseX,sticky,outside=false;if(boxAround){var atLeft=x-boxAround.left<boxAround.right-x,atStart=atLeft==ltr;ch=chAround+(atStart?0:1);sticky=atStart?"after":"before";baseX=atLeft?boxAround.left:boxAround.right}else{if(!ltr&&(ch==end||ch==begin)){ch++}sticky=ch==0?"after":ch==lineObj.text.length?"before":measureCharPrepared(cm,preparedMeasure,ch-(ltr?1:0)).bottom+widgetHeight<=y==ltr?"after":"before";var coords=cursorCoords(cm,Pos(lineNo,ch,sticky),"line",lineObj,preparedMeasure);baseX=coords.left;outside=y<coords.top?-1:y>=coords.bottom?1:0}ch=skipExtendingChars(lineObj.text,ch,1);return PosWithInfo(lineNo,ch,sticky,outside,x-baseX)}function coordsBidiPart(cm,lineObj,lineNo,preparedMeasure,order,x,y){var index=findFirst((function(i){var part=order[i],ltr=part.level!=1;return boxIsAfter(cursorCoords(cm,Pos(lineNo,ltr?part.to:part.from,ltr?"before":"after"),"line",lineObj,preparedMeasure),x,y,true)}),0,order.length-1);var part=order[index];if(index>0){var ltr=part.level!=1;var start=cursorCoords(cm,Pos(lineNo,ltr?part.from:part.to,ltr?"after":"before"),"line",lineObj,preparedMeasure);if(boxIsAfter(start,x,y,true)&&start.top>y){part=order[index-1]}}return part}function coordsBidiPartWrapped(cm,lineObj,_lineNo,preparedMeasure,order,x,y){var ref=wrappedLineExtent(cm,lineObj,preparedMeasure,y);var begin=ref.begin;var end=ref.end;if(/\s/.test(lineObj.text.charAt(end-1))){end--}var part=null,closestDist=null;for(var i=0;i<order.length;i++){var p=order[i];if(p.from>=end||p.to<=begin){continue}var ltr=p.level!=1;var endX=measureCharPrepared(cm,preparedMeasure,ltr?Math.min(end,p.to)-1:Math.max(begin,p.from)).right;var dist=endX<x?x-endX+1e9:endX-x;if(!part||closestDist>dist){part=p;closestDist=dist}}if(!part){part=order[order.length-1]}if(part.from<begin){part={from:begin,to:part.to,level:part.level}}if(part.to>end){part={from:part.from,to:end,level:part.level}}return part}var measureText;function textHeight(display){if(display.cachedTextHeight!=null){return display.cachedTextHeight}if(measureText==null){measureText=elt("pre",null,"CodeMirror-line-like");for(var i=0;i<49;++i){measureText.appendChild(document.createTextNode("x"));measureText.appendChild(elt("br"))}measureText.appendChild(document.createTextNode("x"))}removeChildrenAndAdd(display.measure,measureText);var height=measureText.offsetHeight/50;if(height>3){display.cachedTextHeight=height}removeChildren(display.measure);return height||1}function charWidth(display){if(display.cachedCharWidth!=null){return display.cachedCharWidth}var anchor=elt("span","xxxxxxxxxx");var pre=elt("pre",[anchor],"CodeMirror-line-like");removeChildrenAndAdd(display.measure,pre);var rect=anchor.getBoundingClientRect(),width=(rect.right-rect.left)/10;if(width>2){display.cachedCharWidth=width}return width||10}function getDimensions(cm){var d=cm.display,left={},width={};var gutterLeft=d.gutters.clientLeft;for(var n=d.gutters.firstChild,i=0;n;n=n.nextSibling,++i){var id=cm.display.gutterSpecs[i].className;left[id]=n.offsetLeft+n.clientLeft+gutterLeft;width[id]=n.clientWidth}return{fixedPos:compensateForHScroll(d),gutterTotalWidth:d.gutters.offsetWidth,gutterLeft:left,gutterWidth:width,wrapperWidth:d.wrapper.clientWidth}}function compensateForHScroll(display){return display.scroller.getBoundingClientRect().left-display.sizer.getBoundingClientRect().left}function estimateHeight(cm){var th=textHeight(cm.display),wrapping=cm.options.lineWrapping;var perLine=wrapping&&Math.max(5,cm.display.scroller.clientWidth/charWidth(cm.display)-3);return function(line){if(lineIsHidden(cm.doc,line)){return 0}var widgetsHeight=0;if(line.widgets){for(var i=0;i<line.widgets.length;i++){if(line.widgets[i].height){widgetsHeight+=line.widgets[i].height}}}if(wrapping){return widgetsHeight+(Math.ceil(line.text.length/perLine)||1)*th}else{return widgetsHeight+th}}}function estimateLineHeights(cm){var doc=cm.doc,est=estimateHeight(cm);doc.iter((function(line){var estHeight=est(line);if(estHeight!=line.height){updateLineHeight(line,estHeight)}}))}function posFromMouse(cm,e,liberal,forRect){var display=cm.display;if(!liberal&&e_target(e).getAttribute("cm-not-content")=="true"){return null}var x,y,space=display.lineSpace.getBoundingClientRect();try{x=e.clientX-space.left;y=e.clientY-space.top}catch(e$1){return null}var coords=coordsChar(cm,x,y),line;if(forRect&&coords.xRel>0&&(line=getLine(cm.doc,coords.line).text).length==coords.ch){var colDiff=countColumn(line,line.length,cm.options.tabSize)-line.length;coords=Pos(coords.line,Math.max(0,Math.round((x-paddingH(cm.display).left)/charWidth(cm.display))-colDiff))}return coords}function findViewIndex(cm,n){if(n>=cm.display.viewTo){return null}n-=cm.display.viewFrom;if(n<0){return null}var view=cm.display.view;for(var i=0;i<view.length;i++){n-=view[i].size;if(n<0){return i}}}function regChange(cm,from,to,lendiff){if(from==null){from=cm.doc.first}if(to==null){to=cm.doc.first+cm.doc.size}if(!lendiff){lendiff=0}var display=cm.display;if(lendiff&&to<display.viewTo&&(display.updateLineNumbers==null||display.updateLineNumbers>from)){display.updateLineNumbers=from}cm.curOp.viewChanged=true;if(from>=display.viewTo){if(sawCollapsedSpans&&visualLineNo(cm.doc,from)<display.viewTo){resetView(cm)}}else if(to<=display.viewFrom){if(sawCollapsedSpans&&visualLineEndNo(cm.doc,to+lendiff)>display.viewFrom){resetView(cm)}else{display.viewFrom+=lendiff;display.viewTo+=lendiff}}else if(from<=display.viewFrom&&to>=display.viewTo){resetView(cm)}else if(from<=display.viewFrom){var cut=viewCuttingPoint(cm,to,to+lendiff,1);if(cut){display.view=display.view.slice(cut.index);display.viewFrom=cut.lineN;display.viewTo+=lendiff}else{resetView(cm)}}else if(to>=display.viewTo){var cut$1=viewCuttingPoint(cm,from,from,-1);if(cut$1){display.view=display.view.slice(0,cut$1.index);display.viewTo=cut$1.lineN}else{resetView(cm)}}else{var cutTop=viewCuttingPoint(cm,from,from,-1);var cutBot=viewCuttingPoint(cm,to,to+lendiff,1);if(cutTop&&cutBot){display.view=display.view.slice(0,cutTop.index).concat(buildViewArray(cm,cutTop.lineN,cutBot.lineN)).concat(display.view.slice(cutBot.index));display.viewTo+=lendiff}else{resetView(cm)}}var ext=display.externalMeasured;if(ext){if(to<ext.lineN){ext.lineN+=lendiff}else if(from<ext.lineN+ext.size){display.externalMeasured=null}}}function regLineChange(cm,line,type){cm.curOp.viewChanged=true;var display=cm.display,ext=cm.display.externalMeasured;if(ext&&line>=ext.lineN&&line<ext.lineN+ext.size){display.externalMeasured=null}if(line<display.viewFrom||line>=display.viewTo){return}var lineView=display.view[findViewIndex(cm,line)];if(lineView.node==null){return}var arr=lineView.changes||(lineView.changes=[]);if(indexOf(arr,type)==-1){arr.push(type)}}function resetView(cm){cm.display.viewFrom=cm.display.viewTo=cm.doc.first;cm.display.view=[];cm.display.viewOffset=0}function viewCuttingPoint(cm,oldN,newN,dir){var index=findViewIndex(cm,oldN),diff,view=cm.display.view;if(!sawCollapsedSpans||newN==cm.doc.first+cm.doc.size){return{index:index,lineN:newN}}var n=cm.display.viewFrom;for(var i=0;i<index;i++){n+=view[i].size}if(n!=oldN){if(dir>0){if(index==view.length-1){return null}diff=n+view[index].size-oldN;index++}else{diff=n-oldN}oldN+=diff;newN+=diff}while(visualLineNo(cm.doc,newN)!=newN){if(index==(dir<0?0:view.length-1)){return null}newN+=dir*view[index-(dir<0?1:0)].size;index+=dir}return{index:index,lineN:newN}}function adjustView(cm,from,to){var display=cm.display,view=display.view;if(view.length==0||from>=display.viewTo||to<=display.viewFrom){display.view=buildViewArray(cm,from,to);display.viewFrom=from}else{if(display.viewFrom>from){display.view=buildViewArray(cm,from,display.viewFrom).concat(display.view)}else if(display.viewFrom<from){display.view=display.view.slice(findViewIndex(cm,from))}display.viewFrom=from;if(display.viewTo<to){display.view=display.view.concat(buildViewArray(cm,display.viewTo,to))}else if(display.viewTo>to){display.view=display.view.slice(0,findViewIndex(cm,to))}}display.viewTo=to}function countDirtyView(cm){var view=cm.display.view,dirty=0;for(var i=0;i<view.length;i++){var lineView=view[i];if(!lineView.hidden&&(!lineView.node||lineView.changes)){++dirty}}return dirty}function updateSelection(cm){cm.display.input.showSelection(cm.display.input.prepareSelection())}function prepareSelection(cm,primary){if(primary===void 0)primary=true;var doc=cm.doc,result={};var curFragment=result.cursors=document.createDocumentFragment();var selFragment=result.selection=document.createDocumentFragment();var customCursor=cm.options.$customCursor;if(customCursor){primary=true}for(var i=0;i<doc.sel.ranges.length;i++){if(!primary&&i==doc.sel.primIndex){continue}var range=doc.sel.ranges[i];if(range.from().line>=cm.display.viewTo||range.to().line<cm.display.viewFrom){continue}var collapsed=range.empty();if(customCursor){var head=customCursor(cm,range);if(head){drawSelectionCursor(cm,head,curFragment)}}else if(collapsed||cm.options.showCursorWhenSelecting){drawSelectionCursor(cm,range.head,curFragment)}if(!collapsed){drawSelectionRange(cm,range,selFragment)}}return result}function drawSelectionCursor(cm,head,output){var pos=cursorCoords(cm,head,"div",null,null,!cm.options.singleCursorHeightPerLine);var cursor=output.appendChild(elt("div"," ","CodeMirror-cursor"));cursor.style.left=pos.left+"px";cursor.style.top=pos.top+"px";cursor.style.height=Math.max(0,pos.bottom-pos.top)*cm.options.cursorHeight+"px";if(/\bcm-fat-cursor\b/.test(cm.getWrapperElement().className)){var charPos=charCoords(cm,head,"div",null,null);var width=charPos.right-charPos.left;cursor.style.width=(width>0?width:cm.defaultCharWidth())+"px"}if(pos.other){var otherCursor=output.appendChild(elt("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));otherCursor.style.display="";otherCursor.style.left=pos.other.left+"px";otherCursor.style.top=pos.other.top+"px";otherCursor.style.height=(pos.other.bottom-pos.other.top)*.85+"px"}}function cmpCoords(a,b){return a.top-b.top||a.left-b.left}function drawSelectionRange(cm,range,output){var display=cm.display,doc=cm.doc;var fragment=document.createDocumentFragment();var padding=paddingH(cm.display),leftSide=padding.left;var rightSide=Math.max(display.sizerWidth,displayWidth(cm)-display.sizer.offsetLeft)-padding.right;var docLTR=doc.direction=="ltr";function add(left,top,width,bottom){if(top<0){top=0}top=Math.round(top);bottom=Math.round(bottom);fragment.appendChild(elt("div",null,"CodeMirror-selected","position: absolute; left: "+left+"px;\n                             top: "+top+"px; width: "+(width==null?rightSide-left:width)+"px;\n                             height: "+(bottom-top)+"px"))}function drawForLine(line,fromArg,toArg){var lineObj=getLine(doc,line);var lineLen=lineObj.text.length;var start,end;function coords(ch,bias){return charCoords(cm,Pos(line,ch),"div",lineObj,bias)}function wrapX(pos,dir,side){var extent=wrappedLineExtentChar(cm,lineObj,null,pos);var prop=dir=="ltr"==(side=="after")?"left":"right";var ch=side=="after"?extent.begin:extent.end-(/\s/.test(lineObj.text.charAt(extent.end-1))?2:1);return coords(ch,prop)[prop]}var order=getOrder(lineObj,doc.direction);iterateBidiSections(order,fromArg||0,toArg==null?lineLen:toArg,(function(from,to,dir,i){var ltr=dir=="ltr";var fromPos=coords(from,ltr?"left":"right");var toPos=coords(to-1,ltr?"right":"left");var openStart=fromArg==null&&from==0,openEnd=toArg==null&&to==lineLen;var first=i==0,last=!order||i==order.length-1;if(toPos.top-fromPos.top<=3){var openLeft=(docLTR?openStart:openEnd)&&first;var openRight=(docLTR?openEnd:openStart)&&last;var left=openLeft?leftSide:(ltr?fromPos:toPos).left;var right=openRight?rightSide:(ltr?toPos:fromPos).right;add(left,fromPos.top,right-left,fromPos.bottom)}else{var topLeft,topRight,botLeft,botRight;if(ltr){topLeft=docLTR&&openStart&&first?leftSide:fromPos.left;topRight=docLTR?rightSide:wrapX(from,dir,"before");botLeft=docLTR?leftSide:wrapX(to,dir,"after");botRight=docLTR&&openEnd&&last?rightSide:toPos.right}else{topLeft=!docLTR?leftSide:wrapX(from,dir,"before");topRight=!docLTR&&openStart&&first?rightSide:fromPos.right;botLeft=!docLTR&&openEnd&&last?leftSide:toPos.left;botRight=!docLTR?rightSide:wrapX(to,dir,"after")}add(topLeft,fromPos.top,topRight-topLeft,fromPos.bottom);if(fromPos.bottom<toPos.top){add(leftSide,fromPos.bottom,null,toPos.top)}add(botLeft,toPos.top,botRight-botLeft,toPos.bottom)}if(!start||cmpCoords(fromPos,start)<0){start=fromPos}if(cmpCoords(toPos,start)<0){start=toPos}if(!end||cmpCoords(fromPos,end)<0){end=fromPos}if(cmpCoords(toPos,end)<0){end=toPos}}));return{start:start,end:end}}var sFrom=range.from(),sTo=range.to();if(sFrom.line==sTo.line){drawForLine(sFrom.line,sFrom.ch,sTo.ch)}else{var fromLine=getLine(doc,sFrom.line),toLine=getLine(doc,sTo.line);var singleVLine=visualLine(fromLine)==visualLine(toLine);var leftEnd=drawForLine(sFrom.line,sFrom.ch,singleVLine?fromLine.text.length+1:null).end;var rightStart=drawForLine(sTo.line,singleVLine?0:null,sTo.ch).start;if(singleVLine){if(leftEnd.top<rightStart.top-2){add(leftEnd.right,leftEnd.top,null,leftEnd.bottom);add(leftSide,rightStart.top,rightStart.left,rightStart.bottom)}else{add(leftEnd.right,leftEnd.top,rightStart.left-leftEnd.right,leftEnd.bottom)}}if(leftEnd.bottom<rightStart.top){add(leftSide,leftEnd.bottom,null,rightStart.top)}}output.appendChild(fragment)}function restartBlink(cm){if(!cm.state.focused){return}var display=cm.display;clearInterval(display.blinker);var on=true;display.cursorDiv.style.visibility="";if(cm.options.cursorBlinkRate>0){display.blinker=setInterval((function(){if(!cm.hasFocus()){onBlur(cm)}display.cursorDiv.style.visibility=(on=!on)?"":"hidden"}),cm.options.cursorBlinkRate)}else if(cm.options.cursorBlinkRate<0){display.cursorDiv.style.visibility="hidden"}}function ensureFocus(cm){if(!cm.hasFocus()){cm.display.input.focus();if(!cm.state.focused){onFocus(cm)}}}function delayBlurEvent(cm){cm.state.delayingBlurEvent=true;setTimeout((function(){if(cm.state.delayingBlurEvent){cm.state.delayingBlurEvent=false;if(cm.state.focused){onBlur(cm)}}}),100)}function onFocus(cm,e){if(cm.state.delayingBlurEvent&&!cm.state.draggingText){cm.state.delayingBlurEvent=false}if(cm.options.readOnly=="nocursor"){return}if(!cm.state.focused){signal(cm,"focus",cm,e);cm.state.focused=true;addClass(cm.display.wrapper,"CodeMirror-focused");if(!cm.curOp&&cm.display.selForContextMenu!=cm.doc.sel){cm.display.input.reset();if(webkit){setTimeout((function(){return cm.display.input.reset(true)}),20)}}cm.display.input.receivedFocus()}restartBlink(cm)}function onBlur(cm,e){if(cm.state.delayingBlurEvent){return}if(cm.state.focused){signal(cm,"blur",cm,e);cm.state.focused=false;rmClass(cm.display.wrapper,"CodeMirror-focused")}clearInterval(cm.display.blinker);setTimeout((function(){if(!cm.state.focused){cm.display.shift=false}}),150)}function updateHeightsInViewport(cm){var display=cm.display;var prevBottom=display.lineDiv.offsetTop;var viewTop=Math.max(0,display.scroller.getBoundingClientRect().top);var oldHeight=display.lineDiv.getBoundingClientRect().top;var mustScroll=0;for(var i=0;i<display.view.length;i++){var cur=display.view[i],wrapping=cm.options.lineWrapping;var height=void 0,width=0;if(cur.hidden){continue}oldHeight+=cur.line.height;if(ie&&ie_version<8){var bot=cur.node.offsetTop+cur.node.offsetHeight;height=bot-prevBottom;prevBottom=bot}else{var box=cur.node.getBoundingClientRect();height=box.bottom-box.top;if(!wrapping&&cur.text.firstChild){width=cur.text.firstChild.getBoundingClientRect().right-box.left-1}}var diff=cur.line.height-height;if(diff>.005||diff<-.005){if(oldHeight<viewTop){mustScroll-=diff}updateLineHeight(cur.line,height);updateWidgetHeight(cur.line);if(cur.rest){for(var j=0;j<cur.rest.length;j++){updateWidgetHeight(cur.rest[j])}}}if(width>cm.display.sizerWidth){var chWidth=Math.ceil(width/charWidth(cm.display));if(chWidth>cm.display.maxLineLength){cm.display.maxLineLength=chWidth;cm.display.maxLine=cur.line;cm.display.maxLineChanged=true}}}if(Math.abs(mustScroll)>2){display.scroller.scrollTop+=mustScroll}}function updateWidgetHeight(line){if(line.widgets){for(var i=0;i<line.widgets.length;++i){var w=line.widgets[i],parent=w.node.parentNode;if(parent){w.height=parent.offsetHeight}}}}function visibleLines(display,doc,viewport){var top=viewport&&viewport.top!=null?Math.max(0,viewport.top):display.scroller.scrollTop;top=Math.floor(top-paddingTop(display));var bottom=viewport&&viewport.bottom!=null?viewport.bottom:top+display.wrapper.clientHeight;var from=lineAtHeight(doc,top),to=lineAtHeight(doc,bottom);if(viewport&&viewport.ensure){var ensureFrom=viewport.ensure.from.line,ensureTo=viewport.ensure.to.line;if(ensureFrom<from){from=ensureFrom;to=lineAtHeight(doc,heightAtLine(getLine(doc,ensureFrom))+display.wrapper.clientHeight)}else if(Math.min(ensureTo,doc.lastLine())>=to){from=lineAtHeight(doc,heightAtLine(getLine(doc,ensureTo))-display.wrapper.clientHeight);to=ensureTo}}return{from:from,to:Math.max(to,from+1)}}function maybeScrollWindow(cm,rect){if(signalDOMEvent(cm,"scrollCursorIntoView")){return}var display=cm.display,box=display.sizer.getBoundingClientRect(),doScroll=null;var doc=display.wrapper.ownerDocument;if(rect.top+box.top<0){doScroll=true}else if(rect.bottom+box.top>(doc.defaultView.innerHeight||doc.documentElement.clientHeight)){doScroll=false}if(doScroll!=null&&!phantom){var scrollNode=elt("div","​",null,"position: absolute;\n                         top: "+(rect.top-display.viewOffset-paddingTop(cm.display))+"px;\n                         height: "+(rect.bottom-rect.top+scrollGap(cm)+display.barHeight)+"px;\n                         left: "+rect.left+"px; width: "+Math.max(2,rect.right-rect.left)+"px;");cm.display.lineSpace.appendChild(scrollNode);scrollNode.scrollIntoView(doScroll);cm.display.lineSpace.removeChild(scrollNode)}}function scrollPosIntoView(cm,pos,end,margin){if(margin==null){margin=0}var rect;if(!cm.options.lineWrapping&&pos==end){end=pos.sticky=="before"?Pos(pos.line,pos.ch+1,"before"):pos;pos=pos.ch?Pos(pos.line,pos.sticky=="before"?pos.ch-1:pos.ch,"after"):pos}for(var limit=0;limit<5;limit++){var changed=false;var coords=cursorCoords(cm,pos);var endCoords=!end||end==pos?coords:cursorCoords(cm,end);rect={left:Math.min(coords.left,endCoords.left),top:Math.min(coords.top,endCoords.top)-margin,right:Math.max(coords.left,endCoords.left),bottom:Math.max(coords.bottom,endCoords.bottom)+margin};var scrollPos=calculateScrollPos(cm,rect);var startTop=cm.doc.scrollTop,startLeft=cm.doc.scrollLeft;if(scrollPos.scrollTop!=null){updateScrollTop(cm,scrollPos.scrollTop);if(Math.abs(cm.doc.scrollTop-startTop)>1){changed=true}}if(scrollPos.scrollLeft!=null){setScrollLeft(cm,scrollPos.scrollLeft);if(Math.abs(cm.doc.scrollLeft-startLeft)>1){changed=true}}if(!changed){break}}return rect}function scrollIntoView(cm,rect){var scrollPos=calculateScrollPos(cm,rect);if(scrollPos.scrollTop!=null){updateScrollTop(cm,scrollPos.scrollTop)}if(scrollPos.scrollLeft!=null){setScrollLeft(cm,scrollPos.scrollLeft)}}function calculateScrollPos(cm,rect){var display=cm.display,snapMargin=textHeight(cm.display);if(rect.top<0){rect.top=0}var screentop=cm.curOp&&cm.curOp.scrollTop!=null?cm.curOp.scrollTop:display.scroller.scrollTop;var screen=displayHeight(cm),result={};if(rect.bottom-rect.top>screen){rect.bottom=rect.top+screen}var docBottom=cm.doc.height+paddingVert(display);var atTop=rect.top<snapMargin,atBottom=rect.bottom>docBottom-snapMargin;if(rect.top<screentop){result.scrollTop=atTop?0:rect.top}else if(rect.bottom>screentop+screen){var newTop=Math.min(rect.top,(atBottom?docBottom:rect.bottom)-screen);if(newTop!=screentop){result.scrollTop=newTop}}var gutterSpace=cm.options.fixedGutter?0:display.gutters.offsetWidth;var screenleft=cm.curOp&&cm.curOp.scrollLeft!=null?cm.curOp.scrollLeft:display.scroller.scrollLeft-gutterSpace;var screenw=displayWidth(cm)-display.gutters.offsetWidth;var tooWide=rect.right-rect.left>screenw;if(tooWide){rect.right=rect.left+screenw}if(rect.left<10){result.scrollLeft=0}else if(rect.left<screenleft){result.scrollLeft=Math.max(0,rect.left+gutterSpace-(tooWide?0:10))}else if(rect.right>screenw+screenleft-3){result.scrollLeft=rect.right+(tooWide?0:10)-screenw}return result}function addToScrollTop(cm,top){if(top==null){return}resolveScrollToPos(cm);cm.curOp.scrollTop=(cm.curOp.scrollTop==null?cm.doc.scrollTop:cm.curOp.scrollTop)+top}function ensureCursorVisible(cm){resolveScrollToPos(cm);var cur=cm.getCursor();cm.curOp.scrollToPos={from:cur,to:cur,margin:cm.options.cursorScrollMargin}}function scrollToCoords(cm,x,y){if(x!=null||y!=null){resolveScrollToPos(cm)}if(x!=null){cm.curOp.scrollLeft=x}if(y!=null){cm.curOp.scrollTop=y}}function scrollToRange(cm,range){resolveScrollToPos(cm);cm.curOp.scrollToPos=range}function resolveScrollToPos(cm){var range=cm.curOp.scrollToPos;if(range){cm.curOp.scrollToPos=null;var from=estimateCoords(cm,range.from),to=estimateCoords(cm,range.to);scrollToCoordsRange(cm,from,to,range.margin)}}function scrollToCoordsRange(cm,from,to,margin){var sPos=calculateScrollPos(cm,{left:Math.min(from.left,to.left),top:Math.min(from.top,to.top)-margin,right:Math.max(from.right,to.right),bottom:Math.max(from.bottom,to.bottom)+margin});scrollToCoords(cm,sPos.scrollLeft,sPos.scrollTop)}function updateScrollTop(cm,val){if(Math.abs(cm.doc.scrollTop-val)<2){return}if(!gecko){updateDisplaySimple(cm,{top:val})}setScrollTop(cm,val,true);if(gecko){updateDisplaySimple(cm)}startWorker(cm,100)}function setScrollTop(cm,val,forceScroll){val=Math.max(0,Math.min(cm.display.scroller.scrollHeight-cm.display.scroller.clientHeight,val));if(cm.display.scroller.scrollTop==val&&!forceScroll){return}cm.doc.scrollTop=val;cm.display.scrollbars.setScrollTop(val);if(cm.display.scroller.scrollTop!=val){cm.display.scroller.scrollTop=val}}function setScrollLeft(cm,val,isScroller,forceScroll){val=Math.max(0,Math.min(val,cm.display.scroller.scrollWidth-cm.display.scroller.clientWidth));if((isScroller?val==cm.doc.scrollLeft:Math.abs(cm.doc.scrollLeft-val)<2)&&!forceScroll){return}cm.doc.scrollLeft=val;alignHorizontally(cm);if(cm.display.scroller.scrollLeft!=val){cm.display.scroller.scrollLeft=val}cm.display.scrollbars.setScrollLeft(val)}function measureForScrollbars(cm){var d=cm.display,gutterW=d.gutters.offsetWidth;var docH=Math.round(cm.doc.height+paddingVert(cm.display));return{clientHeight:d.scroller.clientHeight,viewHeight:d.wrapper.clientHeight,scrollWidth:d.scroller.scrollWidth,clientWidth:d.scroller.clientWidth,viewWidth:d.wrapper.clientWidth,barLeft:cm.options.fixedGutter?gutterW:0,docHeight:docH,scrollHeight:docH+scrollGap(cm)+d.barHeight,nativeBarWidth:d.nativeBarWidth,gutterWidth:gutterW}}var NativeScrollbars=function(place,scroll,cm){this.cm=cm;var vert=this.vert=elt("div",[elt("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar");var horiz=this.horiz=elt("div",[elt("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");vert.tabIndex=horiz.tabIndex=-1;place(vert);place(horiz);on(vert,"scroll",(function(){if(vert.clientHeight){scroll(vert.scrollTop,"vertical")}}));on(horiz,"scroll",(function(){if(horiz.clientWidth){scroll(horiz.scrollLeft,"horizontal")}}));this.checkedZeroWidth=false;if(ie&&ie_version<8){this.horiz.style.minHeight=this.vert.style.minWidth="18px"}};NativeScrollbars.prototype.update=function(measure){var needsH=measure.scrollWidth>measure.clientWidth+1;var needsV=measure.scrollHeight>measure.clientHeight+1;var sWidth=measure.nativeBarWidth;if(needsV){this.vert.style.display="block";this.vert.style.bottom=needsH?sWidth+"px":"0";var totalHeight=measure.viewHeight-(needsH?sWidth:0);this.vert.firstChild.style.height=Math.max(0,measure.scrollHeight-measure.clientHeight+totalHeight)+"px"}else{this.vert.scrollTop=0;this.vert.style.display="";this.vert.firstChild.style.height="0"}if(needsH){this.horiz.style.display="block";this.horiz.style.right=needsV?sWidth+"px":"0";this.horiz.style.left=measure.barLeft+"px";var totalWidth=measure.viewWidth-measure.barLeft-(needsV?sWidth:0);this.horiz.firstChild.style.width=Math.max(0,measure.scrollWidth-measure.clientWidth+totalWidth)+"px"}else{this.horiz.style.display="";this.horiz.firstChild.style.width="0"}if(!this.checkedZeroWidth&&measure.clientHeight>0){if(sWidth==0){this.zeroWidthHack()}this.checkedZeroWidth=true}return{right:needsV?sWidth:0,bottom:needsH?sWidth:0}};NativeScrollbars.prototype.setScrollLeft=function(pos){if(this.horiz.scrollLeft!=pos){this.horiz.scrollLeft=pos}if(this.disableHoriz){this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")}};NativeScrollbars.prototype.setScrollTop=function(pos){if(this.vert.scrollTop!=pos){this.vert.scrollTop=pos}if(this.disableVert){this.enableZeroWidthBar(this.vert,this.disableVert,"vert")}};NativeScrollbars.prototype.zeroWidthHack=function(){var w=mac&&!mac_geMountainLion?"12px":"18px";this.horiz.style.height=this.vert.style.width=w;this.horiz.style.visibility=this.vert.style.visibility="hidden";this.disableHoriz=new Delayed;this.disableVert=new Delayed};NativeScrollbars.prototype.enableZeroWidthBar=function(bar,delay,type){bar.style.visibility="";function maybeDisable(){var box=bar.getBoundingClientRect();var elt=type=="vert"?document.elementFromPoint(box.right-1,(box.top+box.bottom)/2):document.elementFromPoint((box.right+box.left)/2,box.bottom-1);if(elt!=bar){bar.style.visibility="hidden"}else{delay.set(1e3,maybeDisable)}}delay.set(1e3,maybeDisable)};NativeScrollbars.prototype.clear=function(){var parent=this.horiz.parentNode;parent.removeChild(this.horiz);parent.removeChild(this.vert)};var NullScrollbars=function(){};NullScrollbars.prototype.update=function(){return{bottom:0,right:0}};NullScrollbars.prototype.setScrollLeft=function(){};NullScrollbars.prototype.setScrollTop=function(){};NullScrollbars.prototype.clear=function(){};function updateScrollbars(cm,measure){if(!measure){measure=measureForScrollbars(cm)}var startWidth=cm.display.barWidth,startHeight=cm.display.barHeight;updateScrollbarsInner(cm,measure);for(var i=0;i<4&&startWidth!=cm.display.barWidth||startHeight!=cm.display.barHeight;i++){if(startWidth!=cm.display.barWidth&&cm.options.lineWrapping){updateHeightsInViewport(cm)}updateScrollbarsInner(cm,measureForScrollbars(cm));startWidth=cm.display.barWidth;startHeight=cm.display.barHeight}}function updateScrollbarsInner(cm,measure){var d=cm.display;var sizes=d.scrollbars.update(measure);d.sizer.style.paddingRight=(d.barWidth=sizes.right)+"px";d.sizer.style.paddingBottom=(d.barHeight=sizes.bottom)+"px";d.heightForcer.style.borderBottom=sizes.bottom+"px solid transparent";if(sizes.right&&sizes.bottom){d.scrollbarFiller.style.display="block";d.scrollbarFiller.style.height=sizes.bottom+"px";d.scrollbarFiller.style.width=sizes.right+"px"}else{d.scrollbarFiller.style.display=""}if(sizes.bottom&&cm.options.coverGutterNextToScrollbar&&cm.options.fixedGutter){d.gutterFiller.style.display="block";d.gutterFiller.style.height=sizes.bottom+"px";d.gutterFiller.style.width=measure.gutterWidth+"px"}else{d.gutterFiller.style.display=""}}var scrollbarModel={native:NativeScrollbars,null:NullScrollbars};function initScrollbars(cm){if(cm.display.scrollbars){cm.display.scrollbars.clear();if(cm.display.scrollbars.addClass){rmClass(cm.display.wrapper,cm.display.scrollbars.addClass)}}cm.display.scrollbars=new scrollbarModel[cm.options.scrollbarStyle]((function(node){cm.display.wrapper.insertBefore(node,cm.display.scrollbarFiller);on(node,"mousedown",(function(){if(cm.state.focused){setTimeout((function(){return cm.display.input.focus()}),0)}}));node.setAttribute("cm-not-content","true")}),(function(pos,axis){if(axis=="horizontal"){setScrollLeft(cm,pos)}else{updateScrollTop(cm,pos)}}),cm);if(cm.display.scrollbars.addClass){addClass(cm.display.wrapper,cm.display.scrollbars.addClass)}}var nextOpId=0;function startOperation(cm){cm.curOp={cm:cm,viewChanged:false,startHeight:cm.doc.height,forceUpdate:false,updateInput:0,typing:false,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:false,updateMaxLine:false,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:false,id:++nextOpId,markArrays:null};pushOperation(cm.curOp)}function endOperation(cm){var op=cm.curOp;if(op){finishOperation(op,(function(group){for(var i=0;i<group.ops.length;i++){group.ops[i].cm.curOp=null}endOperations(group)}))}}function endOperations(group){var ops=group.ops;for(var i=0;i<ops.length;i++){endOperation_R1(ops[i])}for(var i$1=0;i$1<ops.length;i$1++){endOperation_W1(ops[i$1])}for(var i$2=0;i$2<ops.length;i$2++){endOperation_R2(ops[i$2])}for(var i$3=0;i$3<ops.length;i$3++){endOperation_W2(ops[i$3])}for(var i$4=0;i$4<ops.length;i$4++){endOperation_finish(ops[i$4])}}function endOperation_R1(op){var cm=op.cm,display=cm.display;maybeClipScrollbars(cm);if(op.updateMaxLine){findMaxLine(cm)}op.mustUpdate=op.viewChanged||op.forceUpdate||op.scrollTop!=null||op.scrollToPos&&(op.scrollToPos.from.line<display.viewFrom||op.scrollToPos.to.line>=display.viewTo)||display.maxLineChanged&&cm.options.lineWrapping;op.update=op.mustUpdate&&new DisplayUpdate(cm,op.mustUpdate&&{top:op.scrollTop,ensure:op.scrollToPos},op.forceUpdate)}function endOperation_W1(op){op.updatedDisplay=op.mustUpdate&&updateDisplayIfNeeded(op.cm,op.update)}function endOperation_R2(op){var cm=op.cm,display=cm.display;if(op.updatedDisplay){updateHeightsInViewport(cm)}op.barMeasure=measureForScrollbars(cm);if(display.maxLineChanged&&!cm.options.lineWrapping){op.adjustWidthTo=measureChar(cm,display.maxLine,display.maxLine.text.length).left+3;cm.display.sizerWidth=op.adjustWidthTo;op.barMeasure.scrollWidth=Math.max(display.scroller.clientWidth,display.sizer.offsetLeft+op.adjustWidthTo+scrollGap(cm)+cm.display.barWidth);op.maxScrollLeft=Math.max(0,display.sizer.offsetLeft+op.adjustWidthTo-displayWidth(cm))}if(op.updatedDisplay||op.selectionChanged){op.preparedSelection=display.input.prepareSelection()}}function endOperation_W2(op){var cm=op.cm;if(op.adjustWidthTo!=null){cm.display.sizer.style.minWidth=op.adjustWidthTo+"px";if(op.maxScrollLeft<cm.doc.scrollLeft){setScrollLeft(cm,Math.min(cm.display.scroller.scrollLeft,op.maxScrollLeft),true)}cm.display.maxLineChanged=false}var takeFocus=op.focus&&op.focus==activeElt(doc(cm));if(op.preparedSelection){cm.display.input.showSelection(op.preparedSelection,takeFocus)}if(op.updatedDisplay||op.startHeight!=cm.doc.height){updateScrollbars(cm,op.barMeasure)}if(op.updatedDisplay){setDocumentHeight(cm,op.barMeasure)}if(op.selectionChanged){restartBlink(cm)}if(cm.state.focused&&op.updateInput){cm.display.input.reset(op.typing)}if(takeFocus){ensureFocus(op.cm)}}function endOperation_finish(op){var cm=op.cm,display=cm.display,doc=cm.doc;if(op.updatedDisplay){postUpdateDisplay(cm,op.update)}if(display.wheelStartX!=null&&(op.scrollTop!=null||op.scrollLeft!=null||op.scrollToPos)){display.wheelStartX=display.wheelStartY=null}if(op.scrollTop!=null){setScrollTop(cm,op.scrollTop,op.forceScroll)}if(op.scrollLeft!=null){setScrollLeft(cm,op.scrollLeft,true,true)}if(op.scrollToPos){var rect=scrollPosIntoView(cm,clipPos(doc,op.scrollToPos.from),clipPos(doc,op.scrollToPos.to),op.scrollToPos.margin);maybeScrollWindow(cm,rect)}var hidden=op.maybeHiddenMarkers,unhidden=op.maybeUnhiddenMarkers;if(hidden){for(var i=0;i<hidden.length;++i){if(!hidden[i].lines.length){signal(hidden[i],"hide")}}}if(unhidden){for(var i$1=0;i$1<unhidden.length;++i$1){if(unhidden[i$1].lines.length){signal(unhidden[i$1],"unhide")}}}if(display.wrapper.offsetHeight){doc.scrollTop=cm.display.scroller.scrollTop}if(op.changeObjs){signal(cm,"changes",cm,op.changeObjs)}if(op.update){op.update.finish()}}function runInOp(cm,f){if(cm.curOp){return f()}startOperation(cm);try{return f()}finally{endOperation(cm)}}function operation(cm,f){return function(){if(cm.curOp){return f.apply(cm,arguments)}startOperation(cm);try{return f.apply(cm,arguments)}finally{endOperation(cm)}}}function methodOp(f){return function(){if(this.curOp){return f.apply(this,arguments)}startOperation(this);try{return f.apply(this,arguments)}finally{endOperation(this)}}}function docMethodOp(f){return function(){var cm=this.cm;if(!cm||cm.curOp){return f.apply(this,arguments)}startOperation(cm);try{return f.apply(this,arguments)}finally{endOperation(cm)}}}function startWorker(cm,time){if(cm.doc.highlightFrontier<cm.display.viewTo){cm.state.highlight.set(time,bind(highlightWorker,cm))}}function highlightWorker(cm){var doc=cm.doc;if(doc.highlightFrontier>=cm.display.viewTo){return}var end=+new Date+cm.options.workTime;var context=getContextBefore(cm,doc.highlightFrontier);var changedLines=[];doc.iter(context.line,Math.min(doc.first+doc.size,cm.display.viewTo+500),(function(line){if(context.line>=cm.display.viewFrom){var oldStyles=line.styles;var resetState=line.text.length>cm.options.maxHighlightLength?copyState(doc.mode,context.state):null;var highlighted=highlightLine(cm,line,context,true);if(resetState){context.state=resetState}line.styles=highlighted.styles;var oldCls=line.styleClasses,newCls=highlighted.classes;if(newCls){line.styleClasses=newCls}else if(oldCls){line.styleClasses=null}var ischange=!oldStyles||oldStyles.length!=line.styles.length||oldCls!=newCls&&(!oldCls||!newCls||oldCls.bgClass!=newCls.bgClass||oldCls.textClass!=newCls.textClass);for(var i=0;!ischange&&i<oldStyles.length;++i){ischange=oldStyles[i]!=line.styles[i]}if(ischange){changedLines.push(context.line)}line.stateAfter=context.save();context.nextLine()}else{if(line.text.length<=cm.options.maxHighlightLength){processLine(cm,line.text,context)}line.stateAfter=context.line%5==0?context.save():null;context.nextLine()}if(+new Date>end){startWorker(cm,cm.options.workDelay);return true}}));doc.highlightFrontier=context.line;doc.modeFrontier=Math.max(doc.modeFrontier,context.line);if(changedLines.length){runInOp(cm,(function(){for(var i=0;i<changedLines.length;i++){regLineChange(cm,changedLines[i],"text")}}))}}var DisplayUpdate=function(cm,viewport,force){var display=cm.display;this.viewport=viewport;this.visible=visibleLines(display,cm.doc,viewport);this.editorIsHidden=!display.wrapper.offsetWidth;this.wrapperHeight=display.wrapper.clientHeight;this.wrapperWidth=display.wrapper.clientWidth;this.oldDisplayWidth=displayWidth(cm);this.force=force;this.dims=getDimensions(cm);this.events=[]};DisplayUpdate.prototype.signal=function(emitter,type){if(hasHandler(emitter,type)){this.events.push(arguments)}};DisplayUpdate.prototype.finish=function(){for(var i=0;i<this.events.length;i++){signal.apply(null,this.events[i])}};function maybeClipScrollbars(cm){var display=cm.display;if(!display.scrollbarsClipped&&display.scroller.offsetWidth){display.nativeBarWidth=display.scroller.offsetWidth-display.scroller.clientWidth;display.heightForcer.style.height=scrollGap(cm)+"px";display.sizer.style.marginBottom=-display.nativeBarWidth+"px";display.sizer.style.borderRightWidth=scrollGap(cm)+"px";display.scrollbarsClipped=true}}function selectionSnapshot(cm){if(cm.hasFocus()){return null}var active=activeElt(doc(cm));if(!active||!contains(cm.display.lineDiv,active)){return null}var result={activeElt:active};if(window.getSelection){var sel=win(cm).getSelection();if(sel.anchorNode&&sel.extend&&contains(cm.display.lineDiv,sel.anchorNode)){result.anchorNode=sel.anchorNode;result.anchorOffset=sel.anchorOffset;result.focusNode=sel.focusNode;result.focusOffset=sel.focusOffset}}return result}function restoreSelection(snapshot){if(!snapshot||!snapshot.activeElt||snapshot.activeElt==activeElt(snapshot.activeElt.ownerDocument)){return}snapshot.activeElt.focus();if(!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName)&&snapshot.anchorNode&&contains(document.body,snapshot.anchorNode)&&contains(document.body,snapshot.focusNode)){var doc=snapshot.activeElt.ownerDocument;var sel=doc.defaultView.getSelection(),range=doc.createRange();range.setEnd(snapshot.anchorNode,snapshot.anchorOffset);range.collapse(false);sel.removeAllRanges();sel.addRange(range);sel.extend(snapshot.focusNode,snapshot.focusOffset)}}function updateDisplayIfNeeded(cm,update){var display=cm.display,doc=cm.doc;if(update.editorIsHidden){resetView(cm);return false}if(!update.force&&update.visible.from>=display.viewFrom&&update.visible.to<=display.viewTo&&(display.updateLineNumbers==null||display.updateLineNumbers>=display.viewTo)&&display.renderedView==display.view&&countDirtyView(cm)==0){return false}if(maybeUpdateLineNumberWidth(cm)){resetView(cm);update.dims=getDimensions(cm)}var end=doc.first+doc.size;var from=Math.max(update.visible.from-cm.options.viewportMargin,doc.first);var to=Math.min(end,update.visible.to+cm.options.viewportMargin);if(display.viewFrom<from&&from-display.viewFrom<20){from=Math.max(doc.first,display.viewFrom)}if(display.viewTo>to&&display.viewTo-to<20){to=Math.min(end,display.viewTo)}if(sawCollapsedSpans){from=visualLineNo(cm.doc,from);to=visualLineEndNo(cm.doc,to)}var different=from!=display.viewFrom||to!=display.viewTo||display.lastWrapHeight!=update.wrapperHeight||display.lastWrapWidth!=update.wrapperWidth;adjustView(cm,from,to);display.viewOffset=heightAtLine(getLine(cm.doc,display.viewFrom));cm.display.mover.style.top=display.viewOffset+"px";var toUpdate=countDirtyView(cm);if(!different&&toUpdate==0&&!update.force&&display.renderedView==display.view&&(display.updateLineNumbers==null||display.updateLineNumbers>=display.viewTo)){return false}var selSnapshot=selectionSnapshot(cm);if(toUpdate>4){display.lineDiv.style.display="none"}patchDisplay(cm,display.updateLineNumbers,update.dims);if(toUpdate>4){display.lineDiv.style.display=""}display.renderedView=display.view;restoreSelection(selSnapshot);removeChildren(display.cursorDiv);removeChildren(display.selectionDiv);display.gutters.style.height=display.sizer.style.minHeight=0;if(different){display.lastWrapHeight=update.wrapperHeight;display.lastWrapWidth=update.wrapperWidth;startWorker(cm,400)}display.updateLineNumbers=null;return true}function postUpdateDisplay(cm,update){var viewport=update.viewport;for(var first=true;;first=false){if(!first||!cm.options.lineWrapping||update.oldDisplayWidth==displayWidth(cm)){if(viewport&&viewport.top!=null){viewport={top:Math.min(cm.doc.height+paddingVert(cm.display)-displayHeight(cm),viewport.top)}}update.visible=visibleLines(cm.display,cm.doc,viewport);if(update.visible.from>=cm.display.viewFrom&&update.visible.to<=cm.display.viewTo){break}}else if(first){update.visible=visibleLines(cm.display,cm.doc,viewport)}if(!updateDisplayIfNeeded(cm,update)){break}updateHeightsInViewport(cm);var barMeasure=measureForScrollbars(cm);updateSelection(cm);updateScrollbars(cm,barMeasure);setDocumentHeight(cm,barMeasure);update.force=false}update.signal(cm,"update",cm);if(cm.display.viewFrom!=cm.display.reportedViewFrom||cm.display.viewTo!=cm.display.reportedViewTo){update.signal(cm,"viewportChange",cm,cm.display.viewFrom,cm.display.viewTo);cm.display.reportedViewFrom=cm.display.viewFrom;cm.display.reportedViewTo=cm.display.viewTo}}function updateDisplaySimple(cm,viewport){var update=new DisplayUpdate(cm,viewport);if(updateDisplayIfNeeded(cm,update)){updateHeightsInViewport(cm);postUpdateDisplay(cm,update);var barMeasure=measureForScrollbars(cm);updateSelection(cm);updateScrollbars(cm,barMeasure);setDocumentHeight(cm,barMeasure);update.finish()}}function patchDisplay(cm,updateNumbersFrom,dims){var display=cm.display,lineNumbers=cm.options.lineNumbers;var container=display.lineDiv,cur=container.firstChild;function rm(node){var next=node.nextSibling;if(webkit&&mac&&cm.display.currentWheelTarget==node){node.style.display="none"}else{node.parentNode.removeChild(node)}return next}var view=display.view,lineN=display.viewFrom;for(var i=0;i<view.length;i++){var lineView=view[i];if(lineView.hidden);else if(!lineView.node||lineView.node.parentNode!=container){var node=buildLineElement(cm,lineView,lineN,dims);container.insertBefore(node,cur)}else{while(cur!=lineView.node){cur=rm(cur)}var updateNumber=lineNumbers&&updateNumbersFrom!=null&&updateNumbersFrom<=lineN&&lineView.lineNumber;if(lineView.changes){if(indexOf(lineView.changes,"gutter")>-1){updateNumber=false}updateLineForChanges(cm,lineView,lineN,dims)}if(updateNumber){removeChildren(lineView.lineNumber);lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options,lineN)))}cur=lineView.node.nextSibling}lineN+=lineView.size}while(cur){cur=rm(cur)}}function updateGutterSpace(display){var width=display.gutters.offsetWidth;display.sizer.style.marginLeft=width+"px";signalLater(display,"gutterChanged",display)}function setDocumentHeight(cm,measure){cm.display.sizer.style.minHeight=measure.docHeight+"px";cm.display.heightForcer.style.top=measure.docHeight+"px";cm.display.gutters.style.height=measure.docHeight+cm.display.barHeight+scrollGap(cm)+"px"}function alignHorizontally(cm){var display=cm.display,view=display.view;if(!display.alignWidgets&&(!display.gutters.firstChild||!cm.options.fixedGutter)){return}var comp=compensateForHScroll(display)-display.scroller.scrollLeft+cm.doc.scrollLeft;var gutterW=display.gutters.offsetWidth,left=comp+"px";for(var i=0;i<view.length;i++){if(!view[i].hidden){if(cm.options.fixedGutter){if(view[i].gutter){view[i].gutter.style.left=left}if(view[i].gutterBackground){view[i].gutterBackground.style.left=left}}var align=view[i].alignable;if(align){for(var j=0;j<align.length;j++){align[j].style.left=left}}}}if(cm.options.fixedGutter){display.gutters.style.left=comp+gutterW+"px"}}function maybeUpdateLineNumberWidth(cm){if(!cm.options.lineNumbers){return false}var doc=cm.doc,last=lineNumberFor(cm.options,doc.first+doc.size-1),display=cm.display;if(last.length!=display.lineNumChars){var test=display.measure.appendChild(elt("div",[elt("div",last)],"CodeMirror-linenumber CodeMirror-gutter-elt"));var innerW=test.firstChild.offsetWidth,padding=test.offsetWidth-innerW;display.lineGutter.style.width="";display.lineNumInnerWidth=Math.max(innerW,display.lineGutter.offsetWidth-padding)+1;display.lineNumWidth=display.lineNumInnerWidth+padding;display.lineNumChars=display.lineNumInnerWidth?last.length:-1;display.lineGutter.style.width=display.lineNumWidth+"px";updateGutterSpace(cm.display);return true}return false}function getGutters(gutters,lineNumbers){var result=[],sawLineNumbers=false;for(var i=0;i<gutters.length;i++){var name=gutters[i],style=null;if(typeof name!="string"){style=name.style;name=name.className}if(name=="CodeMirror-linenumbers"){if(!lineNumbers){continue}else{sawLineNumbers=true}}result.push({className:name,style:style})}if(lineNumbers&&!sawLineNumbers){result.push({className:"CodeMirror-linenumbers",style:null})}return result}function renderGutters(display){var gutters=display.gutters,specs=display.gutterSpecs;removeChildren(gutters);display.lineGutter=null;for(var i=0;i<specs.length;++i){var ref=specs[i];var className=ref.className;var style=ref.style;var gElt=gutters.appendChild(elt("div",null,"CodeMirror-gutter "+className));if(style){gElt.style.cssText=style}if(className=="CodeMirror-linenumbers"){display.lineGutter=gElt;gElt.style.width=(display.lineNumWidth||1)+"px"}}gutters.style.display=specs.length?"":"none";updateGutterSpace(display)}function updateGutters(cm){renderGutters(cm.display);regChange(cm);alignHorizontally(cm)}function Display(place,doc,input,options){var d=this;this.input=input;d.scrollbarFiller=elt("div",null,"CodeMirror-scrollbar-filler");d.scrollbarFiller.setAttribute("cm-not-content","true");d.gutterFiller=elt("div",null,"CodeMirror-gutter-filler");d.gutterFiller.setAttribute("cm-not-content","true");d.lineDiv=eltP("div",null,"CodeMirror-code");d.selectionDiv=elt("div",null,null,"position: relative; z-index: 1");d.cursorDiv=elt("div",null,"CodeMirror-cursors");d.measure=elt("div",null,"CodeMirror-measure");d.lineMeasure=elt("div",null,"CodeMirror-measure");d.lineSpace=eltP("div",[d.measure,d.lineMeasure,d.selectionDiv,d.cursorDiv,d.lineDiv],null,"position: relative; outline: none");var lines=eltP("div",[d.lineSpace],"CodeMirror-lines");d.mover=elt("div",[lines],null,"position: relative");d.sizer=elt("div",[d.mover],"CodeMirror-sizer");d.sizerWidth=null;d.heightForcer=elt("div",null,null,"position: absolute; height: "+scrollerGap+"px; width: 1px;");d.gutters=elt("div",null,"CodeMirror-gutters");d.lineGutter=null;d.scroller=elt("div",[d.sizer,d.heightForcer,d.gutters],"CodeMirror-scroll");d.scroller.setAttribute("tabIndex","-1");d.wrapper=elt("div",[d.scrollbarFiller,d.gutterFiller,d.scroller],"CodeMirror");if(chrome&&chrome_version>=105){d.wrapper.style.clipPath="inset(0px)"}d.wrapper.setAttribute("translate","no");if(ie&&ie_version<8){d.gutters.style.zIndex=-1;d.scroller.style.paddingRight=0}if(!webkit&&!(gecko&&mobile)){d.scroller.draggable=true}if(place){if(place.appendChild){place.appendChild(d.wrapper)}else{place(d.wrapper)}}d.viewFrom=d.viewTo=doc.first;d.reportedViewFrom=d.reportedViewTo=doc.first;d.view=[];d.renderedView=null;d.externalMeasured=null;d.viewOffset=0;d.lastWrapHeight=d.lastWrapWidth=0;d.updateLineNumbers=null;d.nativeBarWidth=d.barHeight=d.barWidth=0;d.scrollbarsClipped=false;d.lineNumWidth=d.lineNumInnerWidth=d.lineNumChars=null;d.alignWidgets=false;d.cachedCharWidth=d.cachedTextHeight=d.cachedPaddingH=null;d.maxLine=null;d.maxLineLength=0;d.maxLineChanged=false;d.wheelDX=d.wheelDY=d.wheelStartX=d.wheelStartY=null;d.shift=false;d.selForContextMenu=null;d.activeTouch=null;d.gutterSpecs=getGutters(options.gutters,options.lineNumbers);renderGutters(d);input.init(d)}var wheelSamples=0,wheelPixelsPerUnit=null;if(ie){wheelPixelsPerUnit=-.53}else if(gecko){wheelPixelsPerUnit=15}else if(chrome){wheelPixelsPerUnit=-.7}else if(safari){wheelPixelsPerUnit=-1/3}function wheelEventDelta(e){var dx=e.wheelDeltaX,dy=e.wheelDeltaY;if(dx==null&&e.detail&&e.axis==e.HORIZONTAL_AXIS){dx=e.detail}if(dy==null&&e.detail&&e.axis==e.VERTICAL_AXIS){dy=e.detail}else if(dy==null){dy=e.wheelDelta}return{x:dx,y:dy}}function wheelEventPixels(e){var delta=wheelEventDelta(e);delta.x*=wheelPixelsPerUnit;delta.y*=wheelPixelsPerUnit;return delta}function onScrollWheel(cm,e){if(chrome&&chrome_version==102){if(cm.display.chromeScrollHack==null){cm.display.sizer.style.pointerEvents="none"}else{clearTimeout(cm.display.chromeScrollHack)}cm.display.chromeScrollHack=setTimeout((function(){cm.display.chromeScrollHack=null;cm.display.sizer.style.pointerEvents=""}),100)}var delta=wheelEventDelta(e),dx=delta.x,dy=delta.y;var pixelsPerUnit=wheelPixelsPerUnit;if(e.deltaMode===0){dx=e.deltaX;dy=e.deltaY;pixelsPerUnit=1}var display=cm.display,scroll=display.scroller;var canScrollX=scroll.scrollWidth>scroll.clientWidth;var canScrollY=scroll.scrollHeight>scroll.clientHeight;if(!(dx&&canScrollX||dy&&canScrollY)){return}if(dy&&mac&&webkit){outer:for(var cur=e.target,view=display.view;cur!=scroll;cur=cur.parentNode){for(var i=0;i<view.length;i++){if(view[i].node==cur){cm.display.currentWheelTarget=cur;break outer}}}}if(dx&&!gecko&&!presto&&pixelsPerUnit!=null){if(dy&&canScrollY){updateScrollTop(cm,Math.max(0,scroll.scrollTop+dy*pixelsPerUnit))}setScrollLeft(cm,Math.max(0,scroll.scrollLeft+dx*pixelsPerUnit));if(!dy||dy&&canScrollY){e_preventDefault(e)}display.wheelStartX=null;return}if(dy&&pixelsPerUnit!=null){var pixels=dy*pixelsPerUnit;var top=cm.doc.scrollTop,bot=top+display.wrapper.clientHeight;if(pixels<0){top=Math.max(0,top+pixels-50)}else{bot=Math.min(cm.doc.height,bot+pixels+50)}updateDisplaySimple(cm,{top:top,bottom:bot})}if(wheelSamples<20&&e.deltaMode!==0){if(display.wheelStartX==null){display.wheelStartX=scroll.scrollLeft;display.wheelStartY=scroll.scrollTop;display.wheelDX=dx;display.wheelDY=dy;setTimeout((function(){if(display.wheelStartX==null){return}var movedX=scroll.scrollLeft-display.wheelStartX;var movedY=scroll.scrollTop-display.wheelStartY;var sample=movedY&&display.wheelDY&&movedY/display.wheelDY||movedX&&display.wheelDX&&movedX/display.wheelDX;display.wheelStartX=display.wheelStartY=null;if(!sample){return}wheelPixelsPerUnit=(wheelPixelsPerUnit*wheelSamples+sample)/(wheelSamples+1);++wheelSamples}),200)}else{display.wheelDX+=dx;display.wheelDY+=dy}}}var Selection=function(ranges,primIndex){this.ranges=ranges;this.primIndex=primIndex};Selection.prototype.primary=function(){return this.ranges[this.primIndex]};Selection.prototype.equals=function(other){if(other==this){return true}if(other.primIndex!=this.primIndex||other.ranges.length!=this.ranges.length){return false}for(var i=0;i<this.ranges.length;i++){var here=this.ranges[i],there=other.ranges[i];if(!equalCursorPos(here.anchor,there.anchor)||!equalCursorPos(here.head,there.head)){return false}}return true};Selection.prototype.deepCopy=function(){var out=[];for(var i=0;i<this.ranges.length;i++){out[i]=new Range(copyPos(this.ranges[i].anchor),copyPos(this.ranges[i].head))}return new Selection(out,this.primIndex)};Selection.prototype.somethingSelected=function(){for(var i=0;i<this.ranges.length;i++){if(!this.ranges[i].empty()){return true}}return false};Selection.prototype.contains=function(pos,end){if(!end){end=pos}for(var i=0;i<this.ranges.length;i++){var range=this.ranges[i];if(cmp(end,range.from())>=0&&cmp(pos,range.to())<=0){return i}}return-1};var Range=function(anchor,head){this.anchor=anchor;this.head=head};Range.prototype.from=function(){return minPos(this.anchor,this.head)};Range.prototype.to=function(){return maxPos(this.anchor,this.head)};Range.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch};function normalizeSelection(cm,ranges,primIndex){var mayTouch=cm&&cm.options.selectionsMayTouch;var prim=ranges[primIndex];ranges.sort((function(a,b){return cmp(a.from(),b.from())}));primIndex=indexOf(ranges,prim);for(var i=1;i<ranges.length;i++){var cur=ranges[i],prev=ranges[i-1];var diff=cmp(prev.to(),cur.from());if(mayTouch&&!cur.empty()?diff>0:diff>=0){var from=minPos(prev.from(),cur.from()),to=maxPos(prev.to(),cur.to());var inv=prev.empty()?cur.from()==cur.head:prev.from()==prev.head;if(i<=primIndex){--primIndex}ranges.splice(--i,2,new Range(inv?to:from,inv?from:to))}}return new Selection(ranges,primIndex)}function simpleSelection(anchor,head){return new Selection([new Range(anchor,head||anchor)],0)}function changeEnd(change){if(!change.text){return change.to}return Pos(change.from.line+change.text.length-1,lst(change.text).length+(change.text.length==1?change.from.ch:0))}function adjustForChange(pos,change){if(cmp(pos,change.from)<0){return pos}if(cmp(pos,change.to)<=0){return changeEnd(change)}var line=pos.line+change.text.length-(change.to.line-change.from.line)-1,ch=pos.ch;if(pos.line==change.to.line){ch+=changeEnd(change).ch-change.to.ch}return Pos(line,ch)}function computeSelAfterChange(doc,change){var out=[];for(var i=0;i<doc.sel.ranges.length;i++){var range=doc.sel.ranges[i];out.push(new Range(adjustForChange(range.anchor,change),adjustForChange(range.head,change)))}return normalizeSelection(doc.cm,out,doc.sel.primIndex)}function offsetPos(pos,old,nw){if(pos.line==old.line){return Pos(nw.line,pos.ch-old.ch+nw.ch)}else{return Pos(nw.line+(pos.line-old.line),pos.ch)}}function computeReplacedSel(doc,changes,hint){var out=[];var oldPrev=Pos(doc.first,0),newPrev=oldPrev;for(var i=0;i<changes.length;i++){var change=changes[i];var from=offsetPos(change.from,oldPrev,newPrev);var to=offsetPos(changeEnd(change),oldPrev,newPrev);oldPrev=change.to;newPrev=to;if(hint=="around"){var range=doc.sel.ranges[i],inv=cmp(range.head,range.anchor)<0;out[i]=new Range(inv?to:from,inv?from:to)}else{out[i]=new Range(from,from)}}return new Selection(out,doc.sel.primIndex)}function loadMode(cm){cm.doc.mode=getMode(cm.options,cm.doc.modeOption);resetModeState(cm)}function resetModeState(cm){cm.doc.iter((function(line){if(line.stateAfter){line.stateAfter=null}if(line.styles){line.styles=null}}));cm.doc.modeFrontier=cm.doc.highlightFrontier=cm.doc.first;startWorker(cm,100);cm.state.modeGen++;if(cm.curOp){regChange(cm)}}function isWholeLineUpdate(doc,change){return change.from.ch==0&&change.to.ch==0&&lst(change.text)==""&&(!doc.cm||doc.cm.options.wholeLineUpdateBefore)}function updateDoc(doc,change,markedSpans,estimateHeight){function spansFor(n){return markedSpans?markedSpans[n]:null}function update(line,text,spans){updateLine(line,text,spans,estimateHeight);signalLater(line,"change",line,change)}function linesFor(start,end){var result=[];for(var i=start;i<end;++i){result.push(new Line(text[i],spansFor(i),estimateHeight))}return result}var from=change.from,to=change.to,text=change.text;var firstLine=getLine(doc,from.line),lastLine=getLine(doc,to.line);var lastText=lst(text),lastSpans=spansFor(text.length-1),nlines=to.line-from.line;if(change.full){doc.insert(0,linesFor(0,text.length));doc.remove(text.length,doc.size-text.length)}else if(isWholeLineUpdate(doc,change)){var added=linesFor(0,text.length-1);update(lastLine,lastLine.text,lastSpans);if(nlines){doc.remove(from.line,nlines)}if(added.length){doc.insert(from.line,added)}}else if(firstLine==lastLine){if(text.length==1){update(firstLine,firstLine.text.slice(0,from.ch)+lastText+firstLine.text.slice(to.ch),lastSpans)}else{var added$1=linesFor(1,text.length-1);added$1.push(new Line(lastText+firstLine.text.slice(to.ch),lastSpans,estimateHeight));update(firstLine,firstLine.text.slice(0,from.ch)+text[0],spansFor(0));doc.insert(from.line+1,added$1)}}else if(text.length==1){update(firstLine,firstLine.text.slice(0,from.ch)+text[0]+lastLine.text.slice(to.ch),spansFor(0));doc.remove(from.line+1,nlines)}else{update(firstLine,firstLine.text.slice(0,from.ch)+text[0],spansFor(0));update(lastLine,lastText+lastLine.text.slice(to.ch),lastSpans);var added$2=linesFor(1,text.length-1);if(nlines>1){doc.remove(from.line+1,nlines-1)}doc.insert(from.line+1,added$2)}signalLater(doc,"change",doc,change)}function linkedDocs(doc,f,sharedHistOnly){function propagate(doc,skip,sharedHist){if(doc.linked){for(var i=0;i<doc.linked.length;++i){var rel=doc.linked[i];if(rel.doc==skip){continue}var shared=sharedHist&&rel.sharedHist;if(sharedHistOnly&&!shared){continue}f(rel.doc,shared);propagate(rel.doc,doc,shared)}}}propagate(doc,null,true)}function attachDoc(cm,doc){if(doc.cm){throw new Error("This document is already in use.")}cm.doc=doc;doc.cm=cm;estimateLineHeights(cm);loadMode(cm);setDirectionClass(cm);cm.options.direction=doc.direction;if(!cm.options.lineWrapping){findMaxLine(cm)}cm.options.mode=doc.modeOption;regChange(cm)}function setDirectionClass(cm){(cm.doc.direction=="rtl"?addClass:rmClass)(cm.display.lineDiv,"CodeMirror-rtl")}function directionChanged(cm){runInOp(cm,(function(){setDirectionClass(cm);regChange(cm)}))}function History(prev){this.done=[];this.undone=[];this.undoDepth=prev?prev.undoDepth:Infinity;this.lastModTime=this.lastSelTime=0;this.lastOp=this.lastSelOp=null;this.lastOrigin=this.lastSelOrigin=null;this.generation=this.maxGeneration=prev?prev.maxGeneration:1}function historyChangeFromChange(doc,change){var histChange={from:copyPos(change.from),to:changeEnd(change),text:getBetween(doc,change.from,change.to)};attachLocalSpans(doc,histChange,change.from.line,change.to.line+1);linkedDocs(doc,(function(doc){return attachLocalSpans(doc,histChange,change.from.line,change.to.line+1)}),true);return histChange}function clearSelectionEvents(array){while(array.length){var last=lst(array);if(last.ranges){array.pop()}else{break}}}function lastChangeEvent(hist,force){if(force){clearSelectionEvents(hist.done);return lst(hist.done)}else if(hist.done.length&&!lst(hist.done).ranges){return lst(hist.done)}else if(hist.done.length>1&&!hist.done[hist.done.length-2].ranges){hist.done.pop();return lst(hist.done)}}function addChangeToHistory(doc,change,selAfter,opId){var hist=doc.history;hist.undone.length=0;var time=+new Date,cur;var last;if((hist.lastOp==opId||hist.lastOrigin==change.origin&&change.origin&&(change.origin.charAt(0)=="+"&&hist.lastModTime>time-(doc.cm?doc.cm.options.historyEventDelay:500)||change.origin.charAt(0)=="*"))&&(cur=lastChangeEvent(hist,hist.lastOp==opId))){last=lst(cur.changes);if(cmp(change.from,change.to)==0&&cmp(change.from,last.to)==0){last.to=changeEnd(change)}else{cur.changes.push(historyChangeFromChange(doc,change))}}else{var before=lst(hist.done);if(!before||!before.ranges){pushSelectionToHistory(doc.sel,hist.done)}cur={changes:[historyChangeFromChange(doc,change)],generation:hist.generation};hist.done.push(cur);while(hist.done.length>hist.undoDepth){hist.done.shift();if(!hist.done[0].ranges){hist.done.shift()}}}hist.done.push(selAfter);hist.generation=++hist.maxGeneration;hist.lastModTime=hist.lastSelTime=time;hist.lastOp=hist.lastSelOp=opId;hist.lastOrigin=hist.lastSelOrigin=change.origin;if(!last){signal(doc,"historyAdded")}}function selectionEventCanBeMerged(doc,origin,prev,sel){var ch=origin.charAt(0);return ch=="*"||ch=="+"&&prev.ranges.length==sel.ranges.length&&prev.somethingSelected()==sel.somethingSelected()&&new Date-doc.history.lastSelTime<=(doc.cm?doc.cm.options.historyEventDelay:500)}function addSelectionToHistory(doc,sel,opId,options){var hist=doc.history,origin=options&&options.origin;if(opId==hist.lastSelOp||origin&&hist.lastSelOrigin==origin&&(hist.lastModTime==hist.lastSelTime&&hist.lastOrigin==origin||selectionEventCanBeMerged(doc,origin,lst(hist.done),sel))){hist.done[hist.done.length-1]=sel}else{pushSelectionToHistory(sel,hist.done)}hist.lastSelTime=+new Date;hist.lastSelOrigin=origin;hist.lastSelOp=opId;if(options&&options.clearRedo!==false){clearSelectionEvents(hist.undone)}}function pushSelectionToHistory(sel,dest){var top=lst(dest);if(!(top&&top.ranges&&top.equals(sel))){dest.push(sel)}}function attachLocalSpans(doc,change,from,to){var existing=change["spans_"+doc.id],n=0;doc.iter(Math.max(doc.first,from),Math.min(doc.first+doc.size,to),(function(line){if(line.markedSpans){(existing||(existing=change["spans_"+doc.id]={}))[n]=line.markedSpans}++n}))}function removeClearedSpans(spans){if(!spans){return null}var out;for(var i=0;i<spans.length;++i){if(spans[i].marker.explicitlyCleared){if(!out){out=spans.slice(0,i)}}else if(out){out.push(spans[i])}}return!out?spans:out.length?out:null}function getOldSpans(doc,change){var found=change["spans_"+doc.id];if(!found){return null}var nw=[];for(var i=0;i<change.text.length;++i){nw.push(removeClearedSpans(found[i]))}return nw}function mergeOldSpans(doc,change){var old=getOldSpans(doc,change);var stretched=stretchSpansOverChange(doc,change);if(!old){return stretched}if(!stretched){return old}for(var i=0;i<old.length;++i){var oldCur=old[i],stretchCur=stretched[i];if(oldCur&&stretchCur){spans:for(var j=0;j<stretchCur.length;++j){var span=stretchCur[j];for(var k=0;k<oldCur.length;++k){if(oldCur[k].marker==span.marker){continue spans}}oldCur.push(span)}}else if(stretchCur){old[i]=stretchCur}}return old}function copyHistoryArray(events,newGroup,instantiateSel){var copy=[];for(var i=0;i<events.length;++i){var event=events[i];if(event.ranges){copy.push(instantiateSel?Selection.prototype.deepCopy.call(event):event);continue}var changes=event.changes,newChanges=[];copy.push({changes:newChanges});for(var j=0;j<changes.length;++j){var change=changes[j],m=void 0;newChanges.push({from:change.from,to:change.to,text:change.text});if(newGroup){for(var prop in change){if(m=prop.match(/^spans_(\d+)$/)){if(indexOf(newGroup,Number(m[1]))>-1){lst(newChanges)[prop]=change[prop];delete change[prop]}}}}}}return copy}function extendRange(range,head,other,extend){if(extend){var anchor=range.anchor;if(other){var posBefore=cmp(head,anchor)<0;if(posBefore!=cmp(other,anchor)<0){anchor=head;head=other}else if(posBefore!=cmp(head,other)<0){head=other}}return new Range(anchor,head)}else{return new Range(other||head,head)}}function extendSelection(doc,head,other,options,extend){if(extend==null){extend=doc.cm&&(doc.cm.display.shift||doc.extend)}setSelection(doc,new Selection([extendRange(doc.sel.primary(),head,other,extend)],0),options)}function extendSelections(doc,heads,options){var out=[];var extend=doc.cm&&(doc.cm.display.shift||doc.extend);for(var i=0;i<doc.sel.ranges.length;i++){out[i]=extendRange(doc.sel.ranges[i],heads[i],null,extend)}var newSel=normalizeSelection(doc.cm,out,doc.sel.primIndex);setSelection(doc,newSel,options)}function replaceOneSelection(doc,i,range,options){var ranges=doc.sel.ranges.slice(0);ranges[i]=range;setSelection(doc,normalizeSelection(doc.cm,ranges,doc.sel.primIndex),options)}function setSimpleSelection(doc,anchor,head,options){setSelection(doc,simpleSelection(anchor,head),options)}function filterSelectionChange(doc,sel,options){var obj={ranges:sel.ranges,update:function(ranges){this.ranges=[];for(var i=0;i<ranges.length;i++){this.ranges[i]=new Range(clipPos(doc,ranges[i].anchor),clipPos(doc,ranges[i].head))}},origin:options&&options.origin};signal(doc,"beforeSelectionChange",doc,obj);if(doc.cm){signal(doc.cm,"beforeSelectionChange",doc.cm,obj)}if(obj.ranges!=sel.ranges){return normalizeSelection(doc.cm,obj.ranges,obj.ranges.length-1)}else{return sel}}function setSelectionReplaceHistory(doc,sel,options){var done=doc.history.done,last=lst(done);if(last&&last.ranges){done[done.length-1]=sel;setSelectionNoUndo(doc,sel,options)}else{setSelection(doc,sel,options)}}function setSelection(doc,sel,options){setSelectionNoUndo(doc,sel,options);addSelectionToHistory(doc,doc.sel,doc.cm?doc.cm.curOp.id:NaN,options)}function setSelectionNoUndo(doc,sel,options){if(hasHandler(doc,"beforeSelectionChange")||doc.cm&&hasHandler(doc.cm,"beforeSelectionChange")){sel=filterSelectionChange(doc,sel,options)}var bias=options&&options.bias||(cmp(sel.primary().head,doc.sel.primary().head)<0?-1:1);setSelectionInner(doc,skipAtomicInSelection(doc,sel,bias,true));if(!(options&&options.scroll===false)&&doc.cm&&doc.cm.getOption("readOnly")!="nocursor"){ensureCursorVisible(doc.cm)}}function setSelectionInner(doc,sel){if(sel.equals(doc.sel)){return}doc.sel=sel;if(doc.cm){doc.cm.curOp.updateInput=1;doc.cm.curOp.selectionChanged=true;signalCursorActivity(doc.cm)}signalLater(doc,"cursorActivity",doc)}function reCheckSelection(doc){setSelectionInner(doc,skipAtomicInSelection(doc,doc.sel,null,false))}function skipAtomicInSelection(doc,sel,bias,mayClear){var out;for(var i=0;i<sel.ranges.length;i++){var range=sel.ranges[i];var old=sel.ranges.length==doc.sel.ranges.length&&doc.sel.ranges[i];var newAnchor=skipAtomic(doc,range.anchor,old&&old.anchor,bias,mayClear);var newHead=range.head==range.anchor?newAnchor:skipAtomic(doc,range.head,old&&old.head,bias,mayClear);if(out||newAnchor!=range.anchor||newHead!=range.head){if(!out){out=sel.ranges.slice(0,i)}out[i]=new Range(newAnchor,newHead)}}return out?normalizeSelection(doc.cm,out,sel.primIndex):sel}function skipAtomicInner(doc,pos,oldPos,dir,mayClear){var line=getLine(doc,pos.line);if(line.markedSpans){for(var i=0;i<line.markedSpans.length;++i){var sp=line.markedSpans[i],m=sp.marker;var preventCursorLeft="selectLeft"in m?!m.selectLeft:m.inclusiveLeft;var preventCursorRight="selectRight"in m?!m.selectRight:m.inclusiveRight;if((sp.from==null||(preventCursorLeft?sp.from<=pos.ch:sp.from<pos.ch))&&(sp.to==null||(preventCursorRight?sp.to>=pos.ch:sp.to>pos.ch))){if(mayClear){signal(m,"beforeCursorEnter");if(m.explicitlyCleared){if(!line.markedSpans){break}else{--i;continue}}}if(!m.atomic){continue}if(oldPos){var near=m.find(dir<0?1:-1),diff=void 0;if(dir<0?preventCursorRight:preventCursorLeft){near=movePos(doc,near,-dir,near&&near.line==pos.line?line:null)}if(near&&near.line==pos.line&&(diff=cmp(near,oldPos))&&(dir<0?diff<0:diff>0)){return skipAtomicInner(doc,near,pos,dir,mayClear)}}var far=m.find(dir<0?-1:1);if(dir<0?preventCursorLeft:preventCursorRight){far=movePos(doc,far,dir,far.line==pos.line?line:null)}return far?skipAtomicInner(doc,far,pos,dir,mayClear):null}}}return pos}function skipAtomic(doc,pos,oldPos,bias,mayClear){var dir=bias||1;var found=skipAtomicInner(doc,pos,oldPos,dir,mayClear)||!mayClear&&skipAtomicInner(doc,pos,oldPos,dir,true)||skipAtomicInner(doc,pos,oldPos,-dir,mayClear)||!mayClear&&skipAtomicInner(doc,pos,oldPos,-dir,true);if(!found){doc.cantEdit=true;return Pos(doc.first,0)}return found}function movePos(doc,pos,dir,line){if(dir<0&&pos.ch==0){if(pos.line>doc.first){return clipPos(doc,Pos(pos.line-1))}else{return null}}else if(dir>0&&pos.ch==(line||getLine(doc,pos.line)).text.length){if(pos.line<doc.first+doc.size-1){return Pos(pos.line+1,0)}else{return null}}else{return new Pos(pos.line,pos.ch+dir)}}function selectAll(cm){cm.setSelection(Pos(cm.firstLine(),0),Pos(cm.lastLine()),sel_dontScroll)}function filterChange(doc,change,update){var obj={canceled:false,from:change.from,to:change.to,text:change.text,origin:change.origin,cancel:function(){return obj.canceled=true}};if(update){obj.update=function(from,to,text,origin){if(from){obj.from=clipPos(doc,from)}if(to){obj.to=clipPos(doc,to)}if(text){obj.text=text}if(origin!==undefined){obj.origin=origin}}}signal(doc,"beforeChange",doc,obj);if(doc.cm){signal(doc.cm,"beforeChange",doc.cm,obj)}if(obj.canceled){if(doc.cm){doc.cm.curOp.updateInput=2}return null}return{from:obj.from,to:obj.to,text:obj.text,origin:obj.origin}}function makeChange(doc,change,ignoreReadOnly){if(doc.cm){if(!doc.cm.curOp){return operation(doc.cm,makeChange)(doc,change,ignoreReadOnly)}if(doc.cm.state.suppressEdits){return}}if(hasHandler(doc,"beforeChange")||doc.cm&&hasHandler(doc.cm,"beforeChange")){change=filterChange(doc,change,true);if(!change){return}}var split=sawReadOnlySpans&&!ignoreReadOnly&&removeReadOnlyRanges(doc,change.from,change.to);if(split){for(var i=split.length-1;i>=0;--i){makeChangeInner(doc,{from:split[i].from,to:split[i].to,text:i?[""]:change.text,origin:change.origin})}}else{makeChangeInner(doc,change)}}function makeChangeInner(doc,change){if(change.text.length==1&&change.text[0]==""&&cmp(change.from,change.to)==0){return}var selAfter=computeSelAfterChange(doc,change);addChangeToHistory(doc,change,selAfter,doc.cm?doc.cm.curOp.id:NaN);makeChangeSingleDoc(doc,change,selAfter,stretchSpansOverChange(doc,change));var rebased=[];linkedDocs(doc,(function(doc,sharedHist){if(!sharedHist&&indexOf(rebased,doc.history)==-1){rebaseHist(doc.history,change);rebased.push(doc.history)}makeChangeSingleDoc(doc,change,null,stretchSpansOverChange(doc,change))}))}function makeChangeFromHistory(doc,type,allowSelectionOnly){var suppress=doc.cm&&doc.cm.state.suppressEdits;if(suppress&&!allowSelectionOnly){return}var hist=doc.history,event,selAfter=doc.sel;var source=type=="undo"?hist.done:hist.undone,dest=type=="undo"?hist.undone:hist.done;var i=0;for(;i<source.length;i++){event=source[i];if(allowSelectionOnly?event.ranges&&!event.equals(doc.sel):!event.ranges){break}}if(i==source.length){return}hist.lastOrigin=hist.lastSelOrigin=null;for(;;){event=source.pop();if(event.ranges){pushSelectionToHistory(event,dest);if(allowSelectionOnly&&!event.equals(doc.sel)){setSelection(doc,event,{clearRedo:false});return}selAfter=event}else if(suppress){source.push(event);return}else{break}}var antiChanges=[];pushSelectionToHistory(selAfter,dest);dest.push({changes:antiChanges,generation:hist.generation});hist.generation=event.generation||++hist.maxGeneration;var filter=hasHandler(doc,"beforeChange")||doc.cm&&hasHandler(doc.cm,"beforeChange");var loop=function(i){var change=event.changes[i];change.origin=type;if(filter&&!filterChange(doc,change,false)){source.length=0;return{}}antiChanges.push(historyChangeFromChange(doc,change));var after=i?computeSelAfterChange(doc,change):lst(source);makeChangeSingleDoc(doc,change,after,mergeOldSpans(doc,change));if(!i&&doc.cm){doc.cm.scrollIntoView({from:change.from,to:changeEnd(change)})}var rebased=[];linkedDocs(doc,(function(doc,sharedHist){if(!sharedHist&&indexOf(rebased,doc.history)==-1){rebaseHist(doc.history,change);rebased.push(doc.history)}makeChangeSingleDoc(doc,change,null,mergeOldSpans(doc,change))}))};for(var i$1=event.changes.length-1;i$1>=0;--i$1){var returned=loop(i$1);if(returned)return returned.v}}function shiftDoc(doc,distance){if(distance==0){return}doc.first+=distance;doc.sel=new Selection(map(doc.sel.ranges,(function(range){return new Range(Pos(range.anchor.line+distance,range.anchor.ch),Pos(range.head.line+distance,range.head.ch))})),doc.sel.primIndex);if(doc.cm){regChange(doc.cm,doc.first,doc.first-distance,distance);for(var d=doc.cm.display,l=d.viewFrom;l<d.viewTo;l++){regLineChange(doc.cm,l,"gutter")}}}function makeChangeSingleDoc(doc,change,selAfter,spans){if(doc.cm&&!doc.cm.curOp){return operation(doc.cm,makeChangeSingleDoc)(doc,change,selAfter,spans)}if(change.to.line<doc.first){shiftDoc(doc,change.text.length-1-(change.to.line-change.from.line));return}if(change.from.line>doc.lastLine()){return}if(change.from.line<doc.first){var shift=change.text.length-1-(doc.first-change.from.line);shiftDoc(doc,shift);change={from:Pos(doc.first,0),to:Pos(change.to.line+shift,change.to.ch),text:[lst(change.text)],origin:change.origin}}var last=doc.lastLine();if(change.to.line>last){change={from:change.from,to:Pos(last,getLine(doc,last).text.length),text:[change.text[0]],origin:change.origin}}change.removed=getBetween(doc,change.from,change.to);if(!selAfter){selAfter=computeSelAfterChange(doc,change)}if(doc.cm){makeChangeSingleDocInEditor(doc.cm,change,spans)}else{updateDoc(doc,change,spans)}setSelectionNoUndo(doc,selAfter,sel_dontScroll);if(doc.cantEdit&&skipAtomic(doc,Pos(doc.firstLine(),0))){doc.cantEdit=false}}function makeChangeSingleDocInEditor(cm,change,spans){var doc=cm.doc,display=cm.display,from=change.from,to=change.to;var recomputeMaxLength=false,checkWidthStart=from.line;if(!cm.options.lineWrapping){checkWidthStart=lineNo(visualLine(getLine(doc,from.line)));doc.iter(checkWidthStart,to.line+1,(function(line){if(line==display.maxLine){recomputeMaxLength=true;return true}}))}if(doc.sel.contains(change.from,change.to)>-1){signalCursorActivity(cm)}updateDoc(doc,change,spans,estimateHeight(cm));if(!cm.options.lineWrapping){doc.iter(checkWidthStart,from.line+change.text.length,(function(line){var len=lineLength(line);if(len>display.maxLineLength){display.maxLine=line;display.maxLineLength=len;display.maxLineChanged=true;recomputeMaxLength=false}}));if(recomputeMaxLength){cm.curOp.updateMaxLine=true}}retreatFrontier(doc,from.line);startWorker(cm,400);var lendiff=change.text.length-(to.line-from.line)-1;if(change.full){regChange(cm)}else if(from.line==to.line&&change.text.length==1&&!isWholeLineUpdate(cm.doc,change)){regLineChange(cm,from.line,"text")}else{regChange(cm,from.line,to.line+1,lendiff)}var changesHandler=hasHandler(cm,"changes"),changeHandler=hasHandler(cm,"change");if(changeHandler||changesHandler){var obj={from:from,to:to,text:change.text,removed:change.removed,origin:change.origin};if(changeHandler){signalLater(cm,"change",cm,obj)}if(changesHandler){(cm.curOp.changeObjs||(cm.curOp.changeObjs=[])).push(obj)}}cm.display.selForContextMenu=null}function replaceRange(doc,code,from,to,origin){var assign;if(!to){to=from}if(cmp(to,from)<0){assign=[to,from],from=assign[0],to=assign[1]}if(typeof code=="string"){code=doc.splitLines(code)}makeChange(doc,{from:from,to:to,text:code,origin:origin})}function rebaseHistSelSingle(pos,from,to,diff){if(to<pos.line){pos.line+=diff}else if(from<pos.line){pos.line=from;pos.ch=0}}function rebaseHistArray(array,from,to,diff){for(var i=0;i<array.length;++i){var sub=array[i],ok=true;if(sub.ranges){if(!sub.copied){sub=array[i]=sub.deepCopy();sub.copied=true}for(var j=0;j<sub.ranges.length;j++){rebaseHistSelSingle(sub.ranges[j].anchor,from,to,diff);rebaseHistSelSingle(sub.ranges[j].head,from,to,diff)}continue}for(var j$1=0;j$1<sub.changes.length;++j$1){var cur=sub.changes[j$1];if(to<cur.from.line){cur.from=Pos(cur.from.line+diff,cur.from.ch);cur.to=Pos(cur.to.line+diff,cur.to.ch)}else if(from<=cur.to.line){ok=false;break}}if(!ok){array.splice(0,i+1);i=0}}}function rebaseHist(hist,change){var from=change.from.line,to=change.to.line,diff=change.text.length-(to-from)-1;rebaseHistArray(hist.done,from,to,diff);rebaseHistArray(hist.undone,from,to,diff)}function changeLine(doc,handle,changeType,op){var no=handle,line=handle;if(typeof handle=="number"){line=getLine(doc,clipLine(doc,handle))}else{no=lineNo(handle)}if(no==null){return null}if(op(line,no)&&doc.cm){regLineChange(doc.cm,no,changeType)}return line}function LeafChunk(lines){this.lines=lines;this.parent=null;var height=0;for(var i=0;i<lines.length;++i){lines[i].parent=this;height+=lines[i].height}this.height=height}LeafChunk.prototype={chunkSize:function(){return this.lines.length},removeInner:function(at,n){for(var i=at,e=at+n;i<e;++i){var line=this.lines[i];this.height-=line.height;cleanUpLine(line);signalLater(line,"delete")}this.lines.splice(at,n)},collapse:function(lines){lines.push.apply(lines,this.lines)},insertInner:function(at,lines,height){this.height+=height;this.lines=this.lines.slice(0,at).concat(lines).concat(this.lines.slice(at));for(var i=0;i<lines.length;++i){lines[i].parent=this}},iterN:function(at,n,op){for(var e=at+n;at<e;++at){if(op(this.lines[at])){return true}}}};function BranchChunk(children){this.children=children;var size=0,height=0;for(var i=0;i<children.length;++i){var ch=children[i];size+=ch.chunkSize();height+=ch.height;ch.parent=this}this.size=size;this.height=height;this.parent=null}BranchChunk.prototype={chunkSize:function(){return this.size},removeInner:function(at,n){this.size-=n;for(var i=0;i<this.children.length;++i){var child=this.children[i],sz=child.chunkSize();if(at<sz){var rm=Math.min(n,sz-at),oldHeight=child.height;child.removeInner(at,rm);this.height-=oldHeight-child.height;if(sz==rm){this.children.splice(i--,1);child.parent=null}if((n-=rm)==0){break}at=0}else{at-=sz}}if(this.size-n<25&&(this.children.length>1||!(this.children[0]instanceof LeafChunk))){var lines=[];this.collapse(lines);this.children=[new LeafChunk(lines)];this.children[0].parent=this}},collapse:function(lines){for(var i=0;i<this.children.length;++i){this.children[i].collapse(lines)}},insertInner:function(at,lines,height){this.size+=lines.length;this.height+=height;for(var i=0;i<this.children.length;++i){var child=this.children[i],sz=child.chunkSize();if(at<=sz){child.insertInner(at,lines,height);if(child.lines&&child.lines.length>50){var remaining=child.lines.length%25+25;for(var pos=remaining;pos<child.lines.length;){var leaf=new LeafChunk(child.lines.slice(pos,pos+=25));child.height-=leaf.height;this.children.splice(++i,0,leaf);leaf.parent=this}child.lines=child.lines.slice(0,remaining);this.maybeSpill()}break}at-=sz}},maybeSpill:function(){if(this.children.length<=10){return}var me=this;do{var spilled=me.children.splice(me.children.length-5,5);var sibling=new BranchChunk(spilled);if(!me.parent){var copy=new BranchChunk(me.children);copy.parent=me;me.children=[copy,sibling];me=copy}else{me.size-=sibling.size;me.height-=sibling.height;var myIndex=indexOf(me.parent.children,me);me.parent.children.splice(myIndex+1,0,sibling)}sibling.parent=me.parent}while(me.children.length>10);me.parent.maybeSpill()},iterN:function(at,n,op){for(var i=0;i<this.children.length;++i){var child=this.children[i],sz=child.chunkSize();if(at<sz){var used=Math.min(n,sz-at);if(child.iterN(at,used,op)){return true}if((n-=used)==0){break}at=0}else{at-=sz}}}};var LineWidget=function(doc,node,options){if(options){for(var opt in options){if(options.hasOwnProperty(opt)){this[opt]=options[opt]}}}this.doc=doc;this.node=node};LineWidget.prototype.clear=function(){var cm=this.doc.cm,ws=this.line.widgets,line=this.line,no=lineNo(line);if(no==null||!ws){return}for(var i=0;i<ws.length;++i){if(ws[i]==this){ws.splice(i--,1)}}if(!ws.length){line.widgets=null}var height=widgetHeight(this);updateLineHeight(line,Math.max(0,line.height-height));if(cm){runInOp(cm,(function(){adjustScrollWhenAboveVisible(cm,line,-height);regLineChange(cm,no,"widget")}));signalLater(cm,"lineWidgetCleared",cm,this,no)}};LineWidget.prototype.changed=function(){var this$1=this;var oldH=this.height,cm=this.doc.cm,line=this.line;this.height=null;var diff=widgetHeight(this)-oldH;if(!diff){return}if(!lineIsHidden(this.doc,line)){updateLineHeight(line,line.height+diff)}if(cm){runInOp(cm,(function(){cm.curOp.forceUpdate=true;adjustScrollWhenAboveVisible(cm,line,diff);signalLater(cm,"lineWidgetChanged",cm,this$1,lineNo(line))}))}};eventMixin(LineWidget);function adjustScrollWhenAboveVisible(cm,line,diff){if(heightAtLine(line)<(cm.curOp&&cm.curOp.scrollTop||cm.doc.scrollTop)){addToScrollTop(cm,diff)}}function addLineWidget(doc,handle,node,options){var widget=new LineWidget(doc,node,options);var cm=doc.cm;if(cm&&widget.noHScroll){cm.display.alignWidgets=true}changeLine(doc,handle,"widget",(function(line){var widgets=line.widgets||(line.widgets=[]);if(widget.insertAt==null){widgets.push(widget)}else{widgets.splice(Math.min(widgets.length,Math.max(0,widget.insertAt)),0,widget)}widget.line=line;if(cm&&!lineIsHidden(doc,line)){var aboveVisible=heightAtLine(line)<doc.scrollTop;updateLineHeight(line,line.height+widgetHeight(widget));if(aboveVisible){addToScrollTop(cm,widget.height)}cm.curOp.forceUpdate=true}return true}));if(cm){signalLater(cm,"lineWidgetAdded",cm,widget,typeof handle=="number"?handle:lineNo(handle))}return widget}var nextMarkerId=0;var TextMarker=function(doc,type){this.lines=[];this.type=type;this.doc=doc;this.id=++nextMarkerId};TextMarker.prototype.clear=function(){if(this.explicitlyCleared){return}var cm=this.doc.cm,withOp=cm&&!cm.curOp;if(withOp){startOperation(cm)}if(hasHandler(this,"clear")){var found=this.find();if(found){signalLater(this,"clear",found.from,found.to)}}var min=null,max=null;for(var i=0;i<this.lines.length;++i){var line=this.lines[i];var span=getMarkedSpanFor(line.markedSpans,this);if(cm&&!this.collapsed){regLineChange(cm,lineNo(line),"text")}else if(cm){if(span.to!=null){max=lineNo(line)}if(span.from!=null){min=lineNo(line)}}line.markedSpans=removeMarkedSpan(line.markedSpans,span);if(span.from==null&&this.collapsed&&!lineIsHidden(this.doc,line)&&cm){updateLineHeight(line,textHeight(cm.display))}}if(cm&&this.collapsed&&!cm.options.lineWrapping){for(var i$1=0;i$1<this.lines.length;++i$1){var visual=visualLine(this.lines[i$1]),len=lineLength(visual);if(len>cm.display.maxLineLength){cm.display.maxLine=visual;cm.display.maxLineLength=len;cm.display.maxLineChanged=true}}}if(min!=null&&cm&&this.collapsed){regChange(cm,min,max+1)}this.lines.length=0;this.explicitlyCleared=true;if(this.atomic&&this.doc.cantEdit){this.doc.cantEdit=false;if(cm){reCheckSelection(cm.doc)}}if(cm){signalLater(cm,"markerCleared",cm,this,min,max)}if(withOp){endOperation(cm)}if(this.parent){this.parent.clear()}};TextMarker.prototype.find=function(side,lineObj){if(side==null&&this.type=="bookmark"){side=1}var from,to;for(var i=0;i<this.lines.length;++i){var line=this.lines[i];var span=getMarkedSpanFor(line.markedSpans,this);if(span.from!=null){from=Pos(lineObj?line:lineNo(line),span.from);if(side==-1){return from}}if(span.to!=null){to=Pos(lineObj?line:lineNo(line),span.to);if(side==1){return to}}}return from&&{from:from,to:to}};TextMarker.prototype.changed=function(){var this$1=this;var pos=this.find(-1,true),widget=this,cm=this.doc.cm;if(!pos||!cm){return}runInOp(cm,(function(){var line=pos.line,lineN=lineNo(pos.line);var view=findViewForLine(cm,lineN);if(view){clearLineMeasurementCacheFor(view);cm.curOp.selectionChanged=cm.curOp.forceUpdate=true}cm.curOp.updateMaxLine=true;if(!lineIsHidden(widget.doc,line)&&widget.height!=null){var oldHeight=widget.height;widget.height=null;var dHeight=widgetHeight(widget)-oldHeight;if(dHeight){updateLineHeight(line,line.height+dHeight)}}signalLater(cm,"markerChanged",cm,this$1)}))};TextMarker.prototype.attachLine=function(line){if(!this.lines.length&&this.doc.cm){var op=this.doc.cm.curOp;if(!op.maybeHiddenMarkers||indexOf(op.maybeHiddenMarkers,this)==-1){(op.maybeUnhiddenMarkers||(op.maybeUnhiddenMarkers=[])).push(this)}}this.lines.push(line)};TextMarker.prototype.detachLine=function(line){this.lines.splice(indexOf(this.lines,line),1);if(!this.lines.length&&this.doc.cm){var op=this.doc.cm.curOp;(op.maybeHiddenMarkers||(op.maybeHiddenMarkers=[])).push(this)}};eventMixin(TextMarker);function markText(doc,from,to,options,type){if(options&&options.shared){return markTextShared(doc,from,to,options,type)}if(doc.cm&&!doc.cm.curOp){return operation(doc.cm,markText)(doc,from,to,options,type)}var marker=new TextMarker(doc,type),diff=cmp(from,to);if(options){copyObj(options,marker,false)}if(diff>0||diff==0&&marker.clearWhenEmpty!==false){return marker}if(marker.replacedWith){marker.collapsed=true;marker.widgetNode=eltP("span",[marker.replacedWith],"CodeMirror-widget");if(!options.handleMouseEvents){marker.widgetNode.setAttribute("cm-ignore-events","true")}if(options.insertLeft){marker.widgetNode.insertLeft=true}}if(marker.collapsed){if(conflictingCollapsedRange(doc,from.line,from,to,marker)||from.line!=to.line&&conflictingCollapsedRange(doc,to.line,from,to,marker)){throw new Error("Inserting collapsed marker partially overlapping an existing one")}seeCollapsedSpans()}if(marker.addToHistory){addChangeToHistory(doc,{from:from,to:to,origin:"markText"},doc.sel,NaN)}var curLine=from.line,cm=doc.cm,updateMaxLine;doc.iter(curLine,to.line+1,(function(line){if(cm&&marker.collapsed&&!cm.options.lineWrapping&&visualLine(line)==cm.display.maxLine){updateMaxLine=true}if(marker.collapsed&&curLine!=from.line){updateLineHeight(line,0)}addMarkedSpan(line,new MarkedSpan(marker,curLine==from.line?from.ch:null,curLine==to.line?to.ch:null),doc.cm&&doc.cm.curOp);++curLine}));if(marker.collapsed){doc.iter(from.line,to.line+1,(function(line){if(lineIsHidden(doc,line)){updateLineHeight(line,0)}}))}if(marker.clearOnEnter){on(marker,"beforeCursorEnter",(function(){return marker.clear()}))}if(marker.readOnly){seeReadOnlySpans();if(doc.history.done.length||doc.history.undone.length){doc.clearHistory()}}if(marker.collapsed){marker.id=++nextMarkerId;marker.atomic=true}if(cm){if(updateMaxLine){cm.curOp.updateMaxLine=true}if(marker.collapsed){regChange(cm,from.line,to.line+1)}else if(marker.className||marker.startStyle||marker.endStyle||marker.css||marker.attributes||marker.title){for(var i=from.line;i<=to.line;i++){regLineChange(cm,i,"text")}}if(marker.atomic){reCheckSelection(cm.doc)}signalLater(cm,"markerAdded",cm,marker)}return marker}var SharedTextMarker=function(markers,primary){this.markers=markers;this.primary=primary;for(var i=0;i<markers.length;++i){markers[i].parent=this}};SharedTextMarker.prototype.clear=function(){if(this.explicitlyCleared){return}this.explicitlyCleared=true;for(var i=0;i<this.markers.length;++i){this.markers[i].clear()}signalLater(this,"clear")};SharedTextMarker.prototype.find=function(side,lineObj){return this.primary.find(side,lineObj)};eventMixin(SharedTextMarker);function markTextShared(doc,from,to,options,type){options=copyObj(options);options.shared=false;var markers=[markText(doc,from,to,options,type)],primary=markers[0];var widget=options.widgetNode;linkedDocs(doc,(function(doc){if(widget){options.widgetNode=widget.cloneNode(true)}markers.push(markText(doc,clipPos(doc,from),clipPos(doc,to),options,type));for(var i=0;i<doc.linked.length;++i){if(doc.linked[i].isParent){return}}primary=lst(markers)}));return new SharedTextMarker(markers,primary)}function findSharedMarkers(doc){return doc.findMarks(Pos(doc.first,0),doc.clipPos(Pos(doc.lastLine())),(function(m){return m.parent}))}function copySharedMarkers(doc,markers){for(var i=0;i<markers.length;i++){var marker=markers[i],pos=marker.find();var mFrom=doc.clipPos(pos.from),mTo=doc.clipPos(pos.to);if(cmp(mFrom,mTo)){var subMark=markText(doc,mFrom,mTo,marker.primary,marker.primary.type);marker.markers.push(subMark);subMark.parent=marker}}}function detachSharedMarkers(markers){var loop=function(i){var marker=markers[i],linked=[marker.primary.doc];linkedDocs(marker.primary.doc,(function(d){return linked.push(d)}));for(var j=0;j<marker.markers.length;j++){var subMarker=marker.markers[j];if(indexOf(linked,subMarker.doc)==-1){subMarker.parent=null;marker.markers.splice(j--,1)}}};for(var i=0;i<markers.length;i++)loop(i)}var nextDocId=0;var Doc=function(text,mode,firstLine,lineSep,direction){if(!(this instanceof Doc)){return new Doc(text,mode,firstLine,lineSep,direction)}if(firstLine==null){firstLine=0}BranchChunk.call(this,[new LeafChunk([new Line("",null)])]);this.first=firstLine;this.scrollTop=this.scrollLeft=0;this.cantEdit=false;this.cleanGeneration=1;this.modeFrontier=this.highlightFrontier=firstLine;var start=Pos(firstLine,0);this.sel=simpleSelection(start);this.history=new History(null);this.id=++nextDocId;this.modeOption=mode;this.lineSep=lineSep;this.direction=direction=="rtl"?"rtl":"ltr";this.extend=false;if(typeof text=="string"){text=this.splitLines(text)}updateDoc(this,{from:start,to:start,text:text});setSelection(this,simpleSelection(start),sel_dontScroll)};Doc.prototype=createObj(BranchChunk.prototype,{constructor:Doc,iter:function(from,to,op){if(op){this.iterN(from-this.first,to-from,op)}else{this.iterN(this.first,this.first+this.size,from)}},insert:function(at,lines){var height=0;for(var i=0;i<lines.length;++i){height+=lines[i].height}this.insertInner(at-this.first,lines,height)},remove:function(at,n){this.removeInner(at-this.first,n)},getValue:function(lineSep){var lines=getLines(this,this.first,this.first+this.size);if(lineSep===false){return lines}return lines.join(lineSep||this.lineSeparator())},setValue:docMethodOp((function(code){var top=Pos(this.first,0),last=this.first+this.size-1;makeChange(this,{from:top,to:Pos(last,getLine(this,last).text.length),text:this.splitLines(code),origin:"setValue",full:true},true);if(this.cm){scrollToCoords(this.cm,0,0)}setSelection(this,simpleSelection(top),sel_dontScroll)})),replaceRange:function(code,from,to,origin){from=clipPos(this,from);to=to?clipPos(this,to):from;replaceRange(this,code,from,to,origin)},getRange:function(from,to,lineSep){var lines=getBetween(this,clipPos(this,from),clipPos(this,to));if(lineSep===false){return lines}if(lineSep===""){return lines.join("")}return lines.join(lineSep||this.lineSeparator())},getLine:function(line){var l=this.getLineHandle(line);return l&&l.text},getLineHandle:function(line){if(isLine(this,line)){return getLine(this,line)}},getLineNumber:function(line){return lineNo(line)},getLineHandleVisualStart:function(line){if(typeof line=="number"){line=getLine(this,line)}return visualLine(line)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(pos){return clipPos(this,pos)},getCursor:function(start){var range=this.sel.primary(),pos;if(start==null||start=="head"){pos=range.head}else if(start=="anchor"){pos=range.anchor}else if(start=="end"||start=="to"||start===false){pos=range.to()}else{pos=range.from()}return pos},listSelections:function(){return this.sel.ranges},somethingSelected:function(){return this.sel.somethingSelected()},setCursor:docMethodOp((function(line,ch,options){setSimpleSelection(this,clipPos(this,typeof line=="number"?Pos(line,ch||0):line),null,options)})),setSelection:docMethodOp((function(anchor,head,options){setSimpleSelection(this,clipPos(this,anchor),clipPos(this,head||anchor),options)})),extendSelection:docMethodOp((function(head,other,options){extendSelection(this,clipPos(this,head),other&&clipPos(this,other),options)})),extendSelections:docMethodOp((function(heads,options){extendSelections(this,clipPosArray(this,heads),options)})),extendSelectionsBy:docMethodOp((function(f,options){var heads=map(this.sel.ranges,f);extendSelections(this,clipPosArray(this,heads),options)})),setSelections:docMethodOp((function(ranges,primary,options){if(!ranges.length){return}var out=[];for(var i=0;i<ranges.length;i++){out[i]=new Range(clipPos(this,ranges[i].anchor),clipPos(this,ranges[i].head||ranges[i].anchor))}if(primary==null){primary=Math.min(ranges.length-1,this.sel.primIndex)}setSelection(this,normalizeSelection(this.cm,out,primary),options)})),addSelection:docMethodOp((function(anchor,head,options){var ranges=this.sel.ranges.slice(0);ranges.push(new Range(clipPos(this,anchor),clipPos(this,head||anchor)));setSelection(this,normalizeSelection(this.cm,ranges,ranges.length-1),options)})),getSelection:function(lineSep){var ranges=this.sel.ranges,lines;for(var i=0;i<ranges.length;i++){var sel=getBetween(this,ranges[i].from(),ranges[i].to());lines=lines?lines.concat(sel):sel}if(lineSep===false){return lines}else{return lines.join(lineSep||this.lineSeparator())}},getSelections:function(lineSep){var parts=[],ranges=this.sel.ranges;for(var i=0;i<ranges.length;i++){var sel=getBetween(this,ranges[i].from(),ranges[i].to());if(lineSep!==false){sel=sel.join(lineSep||this.lineSeparator())}parts[i]=sel}return parts},replaceSelection:function(code,collapse,origin){var dup=[];for(var i=0;i<this.sel.ranges.length;i++){dup[i]=code}this.replaceSelections(dup,collapse,origin||"+input")},replaceSelections:docMethodOp((function(code,collapse,origin){var changes=[],sel=this.sel;for(var i=0;i<sel.ranges.length;i++){var range=sel.ranges[i];changes[i]={from:range.from(),to:range.to(),text:this.splitLines(code[i]),origin:origin}}var newSel=collapse&&collapse!="end"&&computeReplacedSel(this,changes,collapse);for(var i$1=changes.length-1;i$1>=0;i$1--){makeChange(this,changes[i$1])}if(newSel){setSelectionReplaceHistory(this,newSel)}else if(this.cm){ensureCursorVisible(this.cm)}})),undo:docMethodOp((function(){makeChangeFromHistory(this,"undo")})),redo:docMethodOp((function(){makeChangeFromHistory(this,"redo")})),undoSelection:docMethodOp((function(){makeChangeFromHistory(this,"undo",true)})),redoSelection:docMethodOp((function(){makeChangeFromHistory(this,"redo",true)})),setExtending:function(val){this.extend=val},getExtending:function(){return this.extend},historySize:function(){var hist=this.history,done=0,undone=0;for(var i=0;i<hist.done.length;i++){if(!hist.done[i].ranges){++done}}for(var i$1=0;i$1<hist.undone.length;i$1++){if(!hist.undone[i$1].ranges){++undone}}return{undo:done,redo:undone}},clearHistory:function(){var this$1=this;this.history=new History(this.history);linkedDocs(this,(function(doc){return doc.history=this$1.history}),true)},markClean:function(){this.cleanGeneration=this.changeGeneration(true)},changeGeneration:function(forceSplit){if(forceSplit){this.history.lastOp=this.history.lastSelOp=this.history.lastOrigin=null}return this.history.generation},isClean:function(gen){return this.history.generation==(gen||this.cleanGeneration)},getHistory:function(){return{done:copyHistoryArray(this.history.done),undone:copyHistoryArray(this.history.undone)}},setHistory:function(histData){var hist=this.history=new History(this.history);hist.done=copyHistoryArray(histData.done.slice(0),null,true);hist.undone=copyHistoryArray(histData.undone.slice(0),null,true)},setGutterMarker:docMethodOp((function(line,gutterID,value){return changeLine(this,line,"gutter",(function(line){var markers=line.gutterMarkers||(line.gutterMarkers={});markers[gutterID]=value;if(!value&&isEmpty(markers)){line.gutterMarkers=null}return true}))})),clearGutter:docMethodOp((function(gutterID){var this$1=this;this.iter((function(line){if(line.gutterMarkers&&line.gutterMarkers[gutterID]){changeLine(this$1,line,"gutter",(function(){line.gutterMarkers[gutterID]=null;if(isEmpty(line.gutterMarkers)){line.gutterMarkers=null}return true}))}}))})),lineInfo:function(line){var n;if(typeof line=="number"){if(!isLine(this,line)){return null}n=line;line=getLine(this,line);if(!line){return null}}else{n=lineNo(line);if(n==null){return null}}return{line:n,handle:line,text:line.text,gutterMarkers:line.gutterMarkers,textClass:line.textClass,bgClass:line.bgClass,wrapClass:line.wrapClass,widgets:line.widgets}},addLineClass:docMethodOp((function(handle,where,cls){return changeLine(this,handle,where=="gutter"?"gutter":"class",(function(line){var prop=where=="text"?"textClass":where=="background"?"bgClass":where=="gutter"?"gutterClass":"wrapClass";if(!line[prop]){line[prop]=cls}else if(classTest(cls).test(line[prop])){return false}else{line[prop]+=" "+cls}return true}))})),removeLineClass:docMethodOp((function(handle,where,cls){return changeLine(this,handle,where=="gutter"?"gutter":"class",(function(line){var prop=where=="text"?"textClass":where=="background"?"bgClass":where=="gutter"?"gutterClass":"wrapClass";var cur=line[prop];if(!cur){return false}else if(cls==null){line[prop]=null}else{var found=cur.match(classTest(cls));if(!found){return false}var end=found.index+found[0].length;line[prop]=cur.slice(0,found.index)+(!found.index||end==cur.length?"":" ")+cur.slice(end)||null}return true}))})),addLineWidget:docMethodOp((function(handle,node,options){return addLineWidget(this,handle,node,options)})),removeLineWidget:function(widget){widget.clear()},markText:function(from,to,options){return markText(this,clipPos(this,from),clipPos(this,to),options,options&&options.type||"range")},setBookmark:function(pos,options){var realOpts={replacedWith:options&&(options.nodeType==null?options.widget:options),insertLeft:options&&options.insertLeft,clearWhenEmpty:false,shared:options&&options.shared,handleMouseEvents:options&&options.handleMouseEvents};pos=clipPos(this,pos);return markText(this,pos,pos,realOpts,"bookmark")},findMarksAt:function(pos){pos=clipPos(this,pos);var markers=[],spans=getLine(this,pos.line).markedSpans;if(spans){for(var i=0;i<spans.length;++i){var span=spans[i];if((span.from==null||span.from<=pos.ch)&&(span.to==null||span.to>=pos.ch)){markers.push(span.marker.parent||span.marker)}}}return markers},findMarks:function(from,to,filter){from=clipPos(this,from);to=clipPos(this,to);var found=[],lineNo=from.line;this.iter(from.line,to.line+1,(function(line){var spans=line.markedSpans;if(spans){for(var i=0;i<spans.length;i++){var span=spans[i];if(!(span.to!=null&&lineNo==from.line&&from.ch>=span.to||span.from==null&&lineNo!=from.line||span.from!=null&&lineNo==to.line&&span.from>=to.ch)&&(!filter||filter(span.marker))){found.push(span.marker.parent||span.marker)}}}++lineNo}));return found},getAllMarks:function(){var markers=[];this.iter((function(line){var sps=line.markedSpans;if(sps){for(var i=0;i<sps.length;++i){if(sps[i].from!=null){markers.push(sps[i].marker)}}}}));return markers},posFromIndex:function(off){var ch,lineNo=this.first,sepSize=this.lineSeparator().length;this.iter((function(line){var sz=line.text.length+sepSize;if(sz>off){ch=off;return true}off-=sz;++lineNo}));return clipPos(this,Pos(lineNo,ch))},indexFromPos:function(coords){coords=clipPos(this,coords);var index=coords.ch;if(coords.line<this.first||coords.ch<0){return 0}var sepSize=this.lineSeparator().length;this.iter(this.first,coords.line,(function(line){index+=line.text.length+sepSize}));return index},copy:function(copyHistory){var doc=new Doc(getLines(this,this.first,this.first+this.size),this.modeOption,this.first,this.lineSep,this.direction);doc.scrollTop=this.scrollTop;doc.scrollLeft=this.scrollLeft;doc.sel=this.sel;doc.extend=false;if(copyHistory){doc.history.undoDepth=this.history.undoDepth;doc.setHistory(this.getHistory())}return doc},linkedDoc:function(options){if(!options){options={}}var from=this.first,to=this.first+this.size;if(options.from!=null&&options.from>from){from=options.from}if(options.to!=null&&options.to<to){to=options.to}var copy=new Doc(getLines(this,from,to),options.mode||this.modeOption,from,this.lineSep,this.direction);if(options.sharedHist){copy.history=this.history}(this.linked||(this.linked=[])).push({doc:copy,sharedHist:options.sharedHist});copy.linked=[{doc:this,isParent:true,sharedHist:options.sharedHist}];copySharedMarkers(copy,findSharedMarkers(this));return copy},unlinkDoc:function(other){if(other instanceof CodeMirror){other=other.doc}if(this.linked){for(var i=0;i<this.linked.length;++i){var link=this.linked[i];if(link.doc!=other){continue}this.linked.splice(i,1);other.unlinkDoc(this);detachSharedMarkers(findSharedMarkers(this));break}}if(other.history==this.history){var splitIds=[other.id];linkedDocs(other,(function(doc){return splitIds.push(doc.id)}),true);other.history=new History(null);other.history.done=copyHistoryArray(this.history.done,splitIds);other.history.undone=copyHistoryArray(this.history.undone,splitIds)}},iterLinkedDocs:function(f){linkedDocs(this,f)},getMode:function(){return this.mode},getEditor:function(){return this.cm},splitLines:function(str){if(this.lineSep){return str.split(this.lineSep)}return splitLinesAuto(str)},lineSeparator:function(){return this.lineSep||"\n"},setDirection:docMethodOp((function(dir){if(dir!="rtl"){dir="ltr"}if(dir==this.direction){return}this.direction=dir;this.iter((function(line){return line.order=null}));if(this.cm){directionChanged(this.cm)}}))});Doc.prototype.eachLine=Doc.prototype.iter;var lastDrop=0;function onDrop(e){var cm=this;clearDragCursor(cm);if(signalDOMEvent(cm,e)||eventInWidget(cm.display,e)){return}e_preventDefault(e);if(ie){lastDrop=+new Date}var pos=posFromMouse(cm,e,true),files=e.dataTransfer.files;if(!pos||cm.isReadOnly()){return}if(files&&files.length&&window.FileReader&&window.File){var n=files.length,text=Array(n),read=0;var markAsReadAndPasteIfAllFilesAreRead=function(){if(++read==n){operation(cm,(function(){pos=clipPos(cm.doc,pos);var change={from:pos,to:pos,text:cm.doc.splitLines(text.filter((function(t){return t!=null})).join(cm.doc.lineSeparator())),origin:"paste"};makeChange(cm.doc,change);setSelectionReplaceHistory(cm.doc,simpleSelection(clipPos(cm.doc,pos),clipPos(cm.doc,changeEnd(change))))}))()}};var readTextFromFile=function(file,i){if(cm.options.allowDropFileTypes&&indexOf(cm.options.allowDropFileTypes,file.type)==-1){markAsReadAndPasteIfAllFilesAreRead();return}var reader=new FileReader;reader.onerror=function(){return markAsReadAndPasteIfAllFilesAreRead()};reader.onload=function(){var content=reader.result;if(/[\x00-\x08\x0e-\x1f]{2}/.test(content)){markAsReadAndPasteIfAllFilesAreRead();return}text[i]=content;markAsReadAndPasteIfAllFilesAreRead()};reader.readAsText(file)};for(var i=0;i<files.length;i++){readTextFromFile(files[i],i)}}else{if(cm.state.draggingText&&cm.doc.sel.contains(pos)>-1){cm.state.draggingText(e);setTimeout((function(){return cm.display.input.focus()}),20);return}try{var text$1=e.dataTransfer.getData("Text");if(text$1){var selected;if(cm.state.draggingText&&!cm.state.draggingText.copy){selected=cm.listSelections()}setSelectionNoUndo(cm.doc,simpleSelection(pos,pos));if(selected){for(var i$1=0;i$1<selected.length;++i$1){replaceRange(cm.doc,"",selected[i$1].anchor,selected[i$1].head,"drag")}}cm.replaceSelection(text$1,"around","paste");cm.display.input.focus()}}catch(e$1){}}}function onDragStart(cm,e){if(ie&&(!cm.state.draggingText||+new Date-lastDrop<100)){e_stop(e);return}if(signalDOMEvent(cm,e)||eventInWidget(cm.display,e)){return}e.dataTransfer.setData("Text",cm.getSelection());e.dataTransfer.effectAllowed="copyMove";if(e.dataTransfer.setDragImage&&!safari){var img=elt("img",null,null,"position: fixed; left: 0; top: 0;");img.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";if(presto){img.width=img.height=1;cm.display.wrapper.appendChild(img);img._top=img.offsetTop}e.dataTransfer.setDragImage(img,0,0);if(presto){img.parentNode.removeChild(img)}}}function onDragOver(cm,e){var pos=posFromMouse(cm,e);if(!pos){return}var frag=document.createDocumentFragment();drawSelectionCursor(cm,pos,frag);if(!cm.display.dragCursor){cm.display.dragCursor=elt("div",null,"CodeMirror-cursors CodeMirror-dragcursors");cm.display.lineSpace.insertBefore(cm.display.dragCursor,cm.display.cursorDiv)}removeChildrenAndAdd(cm.display.dragCursor,frag)}function clearDragCursor(cm){if(cm.display.dragCursor){cm.display.lineSpace.removeChild(cm.display.dragCursor);cm.display.dragCursor=null}}function forEachCodeMirror(f){if(!document.getElementsByClassName){return}var byClass=document.getElementsByClassName("CodeMirror"),editors=[];for(var i=0;i<byClass.length;i++){var cm=byClass[i].CodeMirror;if(cm){editors.push(cm)}}if(editors.length){editors[0].operation((function(){for(var i=0;i<editors.length;i++){f(editors[i])}}))}}var globalsRegistered=false;function ensureGlobalHandlers(){if(globalsRegistered){return}registerGlobalHandlers();globalsRegistered=true}function registerGlobalHandlers(){var resizeTimer;on(window,"resize",(function(){if(resizeTimer==null){resizeTimer=setTimeout((function(){resizeTimer=null;forEachCodeMirror(onResize)}),100)}}));on(window,"blur",(function(){return forEachCodeMirror(onBlur)}))}function onResize(cm){var d=cm.display;d.cachedCharWidth=d.cachedTextHeight=d.cachedPaddingH=null;d.scrollbarsClipped=false;cm.setSize()}var keyNames={3:"Pause",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",61:"=",91:"Mod",92:"Mod",93:"Mod",106:"*",107:"=",109:"-",110:".",111:"/",145:"ScrollLock",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",224:"Mod",63232:"Up",63233:"Down",63234:"Left",63235:"Right",63272:"Delete",63273:"Home",63275:"End",63276:"PageUp",63277:"PageDown",63302:"Insert"};for(var i=0;i<10;i++){keyNames[i+48]=keyNames[i+96]=String(i)}for(var i$1=65;i$1<=90;i$1++){keyNames[i$1]=String.fromCharCode(i$1)}for(var i$2=1;i$2<=12;i$2++){keyNames[i$2+111]=keyNames[i$2+63235]="F"+i$2}var keyMap={};keyMap.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"};keyMap.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"};keyMap.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"};keyMap.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]};keyMap["default"]=mac?keyMap.macDefault:keyMap.pcDefault;function normalizeKeyName(name){var parts=name.split(/-(?!$)/);name=parts[parts.length-1];var alt,ctrl,shift,cmd;for(var i=0;i<parts.length-1;i++){var mod=parts[i];if(/^(cmd|meta|m)$/i.test(mod)){cmd=true}else if(/^a(lt)?$/i.test(mod)){alt=true}else if(/^(c|ctrl|control)$/i.test(mod)){ctrl=true}else if(/^s(hift)?$/i.test(mod)){shift=true}else{throw new Error("Unrecognized modifier name: "+mod)}}if(alt){name="Alt-"+name}if(ctrl){name="Ctrl-"+name}if(cmd){name="Cmd-"+name}if(shift){name="Shift-"+name}return name}function normalizeKeyMap(keymap){var copy={};for(var keyname in keymap){if(keymap.hasOwnProperty(keyname)){var value=keymap[keyname];if(/^(name|fallthrough|(de|at)tach)$/.test(keyname)){continue}if(value=="..."){delete keymap[keyname];continue}var keys=map(keyname.split(" "),normalizeKeyName);for(var i=0;i<keys.length;i++){var val=void 0,name=void 0;if(i==keys.length-1){name=keys.join(" ");val=value}else{name=keys.slice(0,i+1).join(" ");val="..."}var prev=copy[name];if(!prev){copy[name]=val}else if(prev!=val){throw new Error("Inconsistent bindings for "+name)}}delete keymap[keyname]}}for(var prop in copy){keymap[prop]=copy[prop]}return keymap}function lookupKey(key,map,handle,context){map=getKeyMap(map);var found=map.call?map.call(key,context):map[key];if(found===false){return"nothing"}if(found==="..."){return"multi"}if(found!=null&&handle(found)){return"handled"}if(map.fallthrough){if(Object.prototype.toString.call(map.fallthrough)!="[object Array]"){return lookupKey(key,map.fallthrough,handle,context)}for(var i=0;i<map.fallthrough.length;i++){var result=lookupKey(key,map.fallthrough[i],handle,context);if(result){return result}}}}function isModifierKey(value){var name=typeof value=="string"?value:keyNames[value.keyCode];return name=="Ctrl"||name=="Alt"||name=="Shift"||name=="Mod"}function addModifierNames(name,event,noShift){var base=name;if(event.altKey&&base!="Alt"){name="Alt-"+name}if((flipCtrlCmd?event.metaKey:event.ctrlKey)&&base!="Ctrl"){name="Ctrl-"+name}if((flipCtrlCmd?event.ctrlKey:event.metaKey)&&base!="Mod"){name="Cmd-"+name}if(!noShift&&event.shiftKey&&base!="Shift"){name="Shift-"+name}return name}function keyName(event,noShift){if(presto&&event.keyCode==34&&event["char"]){return false}var name=keyNames[event.keyCode];if(name==null||event.altGraphKey){return false}if(event.keyCode==3&&event.code){name=event.code}return addModifierNames(name,event,noShift)}function getKeyMap(val){return typeof val=="string"?keyMap[val]:val}function deleteNearSelection(cm,compute){var ranges=cm.doc.sel.ranges,kill=[];for(var i=0;i<ranges.length;i++){var toKill=compute(ranges[i]);while(kill.length&&cmp(toKill.from,lst(kill).to)<=0){var replaced=kill.pop();if(cmp(replaced.from,toKill.from)<0){toKill.from=replaced.from;break}}kill.push(toKill)}runInOp(cm,(function(){for(var i=kill.length-1;i>=0;i--){replaceRange(cm.doc,"",kill[i].from,kill[i].to,"+delete")}ensureCursorVisible(cm)}))}function moveCharLogically(line,ch,dir){var target=skipExtendingChars(line.text,ch+dir,dir);return target<0||target>line.text.length?null:target}function moveLogically(line,start,dir){var ch=moveCharLogically(line,start.ch,dir);return ch==null?null:new Pos(start.line,ch,dir<0?"after":"before")}function endOfLine(visually,cm,lineObj,lineNo,dir){if(visually){if(cm.doc.direction=="rtl"){dir=-dir}var order=getOrder(lineObj,cm.doc.direction);if(order){var part=dir<0?lst(order):order[0];var moveInStorageOrder=dir<0==(part.level==1);var sticky=moveInStorageOrder?"after":"before";var ch;if(part.level>0||cm.doc.direction=="rtl"){var prep=prepareMeasureForLine(cm,lineObj);ch=dir<0?lineObj.text.length-1:0;var targetTop=measureCharPrepared(cm,prep,ch).top;ch=findFirst((function(ch){return measureCharPrepared(cm,prep,ch).top==targetTop}),dir<0==(part.level==1)?part.from:part.to-1,ch);if(sticky=="before"){ch=moveCharLogically(lineObj,ch,1)}}else{ch=dir<0?part.to:part.from}return new Pos(lineNo,ch,sticky)}}return new Pos(lineNo,dir<0?lineObj.text.length:0,dir<0?"before":"after")}function moveVisually(cm,line,start,dir){var bidi=getOrder(line,cm.doc.direction);if(!bidi){return moveLogically(line,start,dir)}if(start.ch>=line.text.length){start.ch=line.text.length;start.sticky="before"}else if(start.ch<=0){start.ch=0;start.sticky="after"}var partPos=getBidiPartAt(bidi,start.ch,start.sticky),part=bidi[partPos];if(cm.doc.direction=="ltr"&&part.level%2==0&&(dir>0?part.to>start.ch:part.from<start.ch)){return moveLogically(line,start,dir)}var mv=function(pos,dir){return moveCharLogically(line,pos instanceof Pos?pos.ch:pos,dir)};var prep;var getWrappedLineExtent=function(ch){if(!cm.options.lineWrapping){return{begin:0,end:line.text.length}}prep=prep||prepareMeasureForLine(cm,line);return wrappedLineExtentChar(cm,line,prep,ch)};var wrappedLineExtent=getWrappedLineExtent(start.sticky=="before"?mv(start,-1):start.ch);if(cm.doc.direction=="rtl"||part.level==1){var moveInStorageOrder=part.level==1==dir<0;var ch=mv(start,moveInStorageOrder?1:-1);if(ch!=null&&(!moveInStorageOrder?ch>=part.from&&ch>=wrappedLineExtent.begin:ch<=part.to&&ch<=wrappedLineExtent.end)){var sticky=moveInStorageOrder?"before":"after";return new Pos(start.line,ch,sticky)}}var searchInVisualLine=function(partPos,dir,wrappedLineExtent){var getRes=function(ch,moveInStorageOrder){return moveInStorageOrder?new Pos(start.line,mv(ch,1),"before"):new Pos(start.line,ch,"after")};for(;partPos>=0&&partPos<bidi.length;partPos+=dir){var part=bidi[partPos];var moveInStorageOrder=dir>0==(part.level!=1);var ch=moveInStorageOrder?wrappedLineExtent.begin:mv(wrappedLineExtent.end,-1);if(part.from<=ch&&ch<part.to){return getRes(ch,moveInStorageOrder)}ch=moveInStorageOrder?part.from:mv(part.to,-1);if(wrappedLineExtent.begin<=ch&&ch<wrappedLineExtent.end){return getRes(ch,moveInStorageOrder)}}};var res=searchInVisualLine(partPos+dir,dir,wrappedLineExtent);if(res){return res}var nextCh=dir>0?wrappedLineExtent.end:mv(wrappedLineExtent.begin,-1);if(nextCh!=null&&!(dir>0&&nextCh==line.text.length)){res=searchInVisualLine(dir>0?0:bidi.length-1,dir,getWrappedLineExtent(nextCh));if(res){return res}}return null}var commands={selectAll:selectAll,singleSelection:function(cm){return cm.setSelection(cm.getCursor("anchor"),cm.getCursor("head"),sel_dontScroll)},killLine:function(cm){return deleteNearSelection(cm,(function(range){if(range.empty()){var len=getLine(cm.doc,range.head.line).text.length;if(range.head.ch==len&&range.head.line<cm.lastLine()){return{from:range.head,to:Pos(range.head.line+1,0)}}else{return{from:range.head,to:Pos(range.head.line,len)}}}else{return{from:range.from(),to:range.to()}}}))},deleteLine:function(cm){return deleteNearSelection(cm,(function(range){return{from:Pos(range.from().line,0),to:clipPos(cm.doc,Pos(range.to().line+1,0))}}))},delLineLeft:function(cm){return deleteNearSelection(cm,(function(range){return{from:Pos(range.from().line,0),to:range.from()}}))},delWrappedLineLeft:function(cm){return deleteNearSelection(cm,(function(range){var top=cm.charCoords(range.head,"div").top+5;var leftPos=cm.coordsChar({left:0,top:top},"div");return{from:leftPos,to:range.from()}}))},delWrappedLineRight:function(cm){return deleteNearSelection(cm,(function(range){var top=cm.charCoords(range.head,"div").top+5;var rightPos=cm.coordsChar({left:cm.display.lineDiv.offsetWidth+100,top:top},"div");return{from:range.from(),to:rightPos}}))},undo:function(cm){return cm.undo()},redo:function(cm){return cm.redo()},undoSelection:function(cm){return cm.undoSelection()},redoSelection:function(cm){return cm.redoSelection()},goDocStart:function(cm){return cm.extendSelection(Pos(cm.firstLine(),0))},goDocEnd:function(cm){return cm.extendSelection(Pos(cm.lastLine()))},goLineStart:function(cm){return cm.extendSelectionsBy((function(range){return lineStart(cm,range.head.line)}),{origin:"+move",bias:1})},goLineStartSmart:function(cm){return cm.extendSelectionsBy((function(range){return lineStartSmart(cm,range.head)}),{origin:"+move",bias:1})},goLineEnd:function(cm){return cm.extendSelectionsBy((function(range){return lineEnd(cm,range.head.line)}),{origin:"+move",bias:-1})},goLineRight:function(cm){return cm.extendSelectionsBy((function(range){var top=cm.cursorCoords(range.head,"div").top+5;return cm.coordsChar({left:cm.display.lineDiv.offsetWidth+100,top:top},"div")}),sel_move)},goLineLeft:function(cm){return cm.extendSelectionsBy((function(range){var top=cm.cursorCoords(range.head,"div").top+5;return cm.coordsChar({left:0,top:top},"div")}),sel_move)},goLineLeftSmart:function(cm){return cm.extendSelectionsBy((function(range){var top=cm.cursorCoords(range.head,"div").top+5;var pos=cm.coordsChar({left:0,top:top},"div");if(pos.ch<cm.getLine(pos.line).search(/\S/)){return lineStartSmart(cm,range.head)}return pos}),sel_move)},goLineUp:function(cm){return cm.moveV(-1,"line")},goLineDown:function(cm){return cm.moveV(1,"line")},goPageUp:function(cm){return cm.moveV(-1,"page")},goPageDown:function(cm){return cm.moveV(1,"page")},goCharLeft:function(cm){return cm.moveH(-1,"char")},goCharRight:function(cm){return cm.moveH(1,"char")},goColumnLeft:function(cm){return cm.moveH(-1,"column")},goColumnRight:function(cm){return cm.moveH(1,"column")},goWordLeft:function(cm){return cm.moveH(-1,"word")},goGroupRight:function(cm){return cm.moveH(1,"group")},goGroupLeft:function(cm){return cm.moveH(-1,"group")},goWordRight:function(cm){return cm.moveH(1,"word")},delCharBefore:function(cm){return cm.deleteH(-1,"codepoint")},delCharAfter:function(cm){return cm.deleteH(1,"char")},delWordBefore:function(cm){return cm.deleteH(-1,"word")},delWordAfter:function(cm){return cm.deleteH(1,"word")},delGroupBefore:function(cm){return cm.deleteH(-1,"group")},delGroupAfter:function(cm){return cm.deleteH(1,"group")},indentAuto:function(cm){return cm.indentSelection("smart")},indentMore:function(cm){return cm.indentSelection("add")},indentLess:function(cm){return cm.indentSelection("subtract")},insertTab:function(cm){return cm.replaceSelection("\t")},insertSoftTab:function(cm){var spaces=[],ranges=cm.listSelections(),tabSize=cm.options.tabSize;for(var i=0;i<ranges.length;i++){var pos=ranges[i].from();var col=countColumn(cm.getLine(pos.line),pos.ch,tabSize);spaces.push(spaceStr(tabSize-col%tabSize))}cm.replaceSelections(spaces)},defaultTab:function(cm){if(cm.somethingSelected()){cm.indentSelection("add")}else{cm.execCommand("insertTab")}},transposeChars:function(cm){return runInOp(cm,(function(){var ranges=cm.listSelections(),newSel=[];for(var i=0;i<ranges.length;i++){if(!ranges[i].empty()){continue}var cur=ranges[i].head,line=getLine(cm.doc,cur.line).text;if(line){if(cur.ch==line.length){cur=new Pos(cur.line,cur.ch-1)}if(cur.ch>0){cur=new Pos(cur.line,cur.ch+1);cm.replaceRange(line.charAt(cur.ch-1)+line.charAt(cur.ch-2),Pos(cur.line,cur.ch-2),cur,"+transpose")}else if(cur.line>cm.doc.first){var prev=getLine(cm.doc,cur.line-1).text;if(prev){cur=new Pos(cur.line,1);cm.replaceRange(line.charAt(0)+cm.doc.lineSeparator()+prev.charAt(prev.length-1),Pos(cur.line-1,prev.length-1),cur,"+transpose")}}}newSel.push(new Range(cur,cur))}cm.setSelections(newSel)}))},newlineAndIndent:function(cm){return runInOp(cm,(function(){var sels=cm.listSelections();for(var i=sels.length-1;i>=0;i--){cm.replaceRange(cm.doc.lineSeparator(),sels[i].anchor,sels[i].head,"+input")}sels=cm.listSelections();for(var i$1=0;i$1<sels.length;i$1++){cm.indentLine(sels[i$1].from().line,null,true)}ensureCursorVisible(cm)}))},openLine:function(cm){return cm.replaceSelection("\n","start")},toggleOverwrite:function(cm){return cm.toggleOverwrite()}};function lineStart(cm,lineN){var line=getLine(cm.doc,lineN);var visual=visualLine(line);if(visual!=line){lineN=lineNo(visual)}return endOfLine(true,cm,visual,lineN,1)}function lineEnd(cm,lineN){var line=getLine(cm.doc,lineN);var visual=visualLineEnd(line);if(visual!=line){lineN=lineNo(visual)}return endOfLine(true,cm,line,lineN,-1)}function lineStartSmart(cm,pos){var start=lineStart(cm,pos.line);var line=getLine(cm.doc,start.line);var order=getOrder(line,cm.doc.direction);if(!order||order[0].level==0){var firstNonWS=Math.max(start.ch,line.text.search(/\S/));var inWS=pos.line==start.line&&pos.ch<=firstNonWS&&pos.ch;return Pos(start.line,inWS?0:firstNonWS,start.sticky)}return start}function doHandleBinding(cm,bound,dropShift){if(typeof bound=="string"){bound=commands[bound];if(!bound){return false}}cm.display.input.ensurePolled();var prevShift=cm.display.shift,done=false;try{if(cm.isReadOnly()){cm.state.suppressEdits=true}if(dropShift){cm.display.shift=false}done=bound(cm)!=Pass}finally{cm.display.shift=prevShift;cm.state.suppressEdits=false}return done}function lookupKeyForEditor(cm,name,handle){for(var i=0;i<cm.state.keyMaps.length;i++){var result=lookupKey(name,cm.state.keyMaps[i],handle,cm);if(result){return result}}return cm.options.extraKeys&&lookupKey(name,cm.options.extraKeys,handle,cm)||lookupKey(name,cm.options.keyMap,handle,cm)}var stopSeq=new Delayed;function dispatchKey(cm,name,e,handle){var seq=cm.state.keySeq;if(seq){if(isModifierKey(name)){return"handled"}if(/\'$/.test(name)){cm.state.keySeq=null}else{stopSeq.set(50,(function(){if(cm.state.keySeq==seq){cm.state.keySeq=null;cm.display.input.reset()}}))}if(dispatchKeyInner(cm,seq+" "+name,e,handle)){return true}}return dispatchKeyInner(cm,name,e,handle)}function dispatchKeyInner(cm,name,e,handle){var result=lookupKeyForEditor(cm,name,handle);if(result=="multi"){cm.state.keySeq=name}if(result=="handled"){signalLater(cm,"keyHandled",cm,name,e)}if(result=="handled"||result=="multi"){e_preventDefault(e);restartBlink(cm)}return!!result}function handleKeyBinding(cm,e){var name=keyName(e,true);if(!name){return false}if(e.shiftKey&&!cm.state.keySeq){return dispatchKey(cm,"Shift-"+name,e,(function(b){return doHandleBinding(cm,b,true)}))||dispatchKey(cm,name,e,(function(b){if(typeof b=="string"?/^go[A-Z]/.test(b):b.motion){return doHandleBinding(cm,b)}}))}else{return dispatchKey(cm,name,e,(function(b){return doHandleBinding(cm,b)}))}}function handleCharBinding(cm,e,ch){return dispatchKey(cm,"'"+ch+"'",e,(function(b){return doHandleBinding(cm,b,true)}))}var lastStoppedKey=null;function onKeyDown(e){var cm=this;if(e.target&&e.target!=cm.display.input.getField()){return}cm.curOp.focus=activeElt(doc(cm));if(signalDOMEvent(cm,e)){return}if(ie&&ie_version<11&&e.keyCode==27){e.returnValue=false}var code=e.keyCode;cm.display.shift=code==16||e.shiftKey;var handled=handleKeyBinding(cm,e);if(presto){lastStoppedKey=handled?code:null;if(!handled&&code==88&&!hasCopyEvent&&(mac?e.metaKey:e.ctrlKey)){cm.replaceSelection("",null,"cut")}}if(gecko&&!mac&&!handled&&code==46&&e.shiftKey&&!e.ctrlKey&&document.execCommand){document.execCommand("cut")}if(code==18&&!/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)){showCrossHair(cm)}}function showCrossHair(cm){var lineDiv=cm.display.lineDiv;addClass(lineDiv,"CodeMirror-crosshair");function up(e){if(e.keyCode==18||!e.altKey){rmClass(lineDiv,"CodeMirror-crosshair");off(document,"keyup",up);off(document,"mouseover",up)}}on(document,"keyup",up);on(document,"mouseover",up)}function onKeyUp(e){if(e.keyCode==16){this.doc.sel.shift=false}signalDOMEvent(this,e)}function onKeyPress(e){var cm=this;if(e.target&&e.target!=cm.display.input.getField()){return}if(eventInWidget(cm.display,e)||signalDOMEvent(cm,e)||e.ctrlKey&&!e.altKey||mac&&e.metaKey){return}var keyCode=e.keyCode,charCode=e.charCode;if(presto&&keyCode==lastStoppedKey){lastStoppedKey=null;e_preventDefault(e);return}if(presto&&(!e.which||e.which<10)&&handleKeyBinding(cm,e)){return}var ch=String.fromCharCode(charCode==null?keyCode:charCode);if(ch=="\b"){return}if(handleCharBinding(cm,e,ch)){return}cm.display.input.onKeyPress(e)}var DOUBLECLICK_DELAY=400;var PastClick=function(time,pos,button){this.time=time;this.pos=pos;this.button=button};PastClick.prototype.compare=function(time,pos,button){return this.time+DOUBLECLICK_DELAY>time&&cmp(pos,this.pos)==0&&button==this.button};var lastClick,lastDoubleClick;function clickRepeat(pos,button){var now=+new Date;if(lastDoubleClick&&lastDoubleClick.compare(now,pos,button)){lastClick=lastDoubleClick=null;return"triple"}else if(lastClick&&lastClick.compare(now,pos,button)){lastDoubleClick=new PastClick(now,pos,button);lastClick=null;return"double"}else{lastClick=new PastClick(now,pos,button);lastDoubleClick=null;return"single"}}function onMouseDown(e){var cm=this,display=cm.display;if(signalDOMEvent(cm,e)||display.activeTouch&&display.input.supportsTouch()){return}display.input.ensurePolled();display.shift=e.shiftKey;if(eventInWidget(display,e)){if(!webkit){display.scroller.draggable=false;setTimeout((function(){return display.scroller.draggable=true}),100)}return}if(clickInGutter(cm,e)){return}var pos=posFromMouse(cm,e),button=e_button(e),repeat=pos?clickRepeat(pos,button):"single";win(cm).focus();if(button==1&&cm.state.selectingText){cm.state.selectingText(e)}if(pos&&handleMappedButton(cm,button,pos,repeat,e)){return}if(button==1){if(pos){leftButtonDown(cm,pos,repeat,e)}else if(e_target(e)==display.scroller){e_preventDefault(e)}}else if(button==2){if(pos){extendSelection(cm.doc,pos)}setTimeout((function(){return display.input.focus()}),20)}else if(button==3){if(captureRightClick){cm.display.input.onContextMenu(e)}else{delayBlurEvent(cm)}}}function handleMappedButton(cm,button,pos,repeat,event){var name="Click";if(repeat=="double"){name="Double"+name}else if(repeat=="triple"){name="Triple"+name}name=(button==1?"Left":button==2?"Middle":"Right")+name;return dispatchKey(cm,addModifierNames(name,event),event,(function(bound){if(typeof bound=="string"){bound=commands[bound]}if(!bound){return false}var done=false;try{if(cm.isReadOnly()){cm.state.suppressEdits=true}done=bound(cm,pos)!=Pass}finally{cm.state.suppressEdits=false}return done}))}function configureMouse(cm,repeat,event){var option=cm.getOption("configureMouse");var value=option?option(cm,repeat,event):{};if(value.unit==null){var rect=chromeOS?event.shiftKey&&event.metaKey:event.altKey;value.unit=rect?"rectangle":repeat=="single"?"char":repeat=="double"?"word":"line"}if(value.extend==null||cm.doc.extend){value.extend=cm.doc.extend||event.shiftKey}if(value.addNew==null){value.addNew=mac?event.metaKey:event.ctrlKey||event.altKey}if(value.moveOnDrag==null){value.moveOnDrag=!(mac?event.altKey:event.ctrlKey)}return value}function leftButtonDown(cm,pos,repeat,event){if(ie){setTimeout(bind(ensureFocus,cm),0)}else{cm.curOp.focus=activeElt(doc(cm))}var behavior=configureMouse(cm,repeat,event);var sel=cm.doc.sel,contained;if(cm.options.dragDrop&&dragAndDrop&&!cm.isReadOnly()&&repeat=="single"&&(contained=sel.contains(pos))>-1&&(cmp((contained=sel.ranges[contained]).from(),pos)<0||pos.xRel>0)&&(cmp(contained.to(),pos)>0||pos.xRel<0)){leftButtonStartDrag(cm,event,pos,behavior)}else{leftButtonSelect(cm,event,pos,behavior)}}function leftButtonStartDrag(cm,event,pos,behavior){var display=cm.display,moved=false;var dragEnd=operation(cm,(function(e){if(webkit){display.scroller.draggable=false}cm.state.draggingText=false;if(cm.state.delayingBlurEvent){if(cm.hasFocus()){cm.state.delayingBlurEvent=false}else{delayBlurEvent(cm)}}off(display.wrapper.ownerDocument,"mouseup",dragEnd);off(display.wrapper.ownerDocument,"mousemove",mouseMove);off(display.scroller,"dragstart",dragStart);off(display.scroller,"drop",dragEnd);if(!moved){e_preventDefault(e);if(!behavior.addNew){extendSelection(cm.doc,pos,null,null,behavior.extend)}if(webkit&&!safari||ie&&ie_version==9){setTimeout((function(){display.wrapper.ownerDocument.body.focus({preventScroll:true});display.input.focus()}),20)}else{display.input.focus()}}}));var mouseMove=function(e2){moved=moved||Math.abs(event.clientX-e2.clientX)+Math.abs(event.clientY-e2.clientY)>=10};var dragStart=function(){return moved=true};if(webkit){display.scroller.draggable=true}cm.state.draggingText=dragEnd;dragEnd.copy=!behavior.moveOnDrag;on(display.wrapper.ownerDocument,"mouseup",dragEnd);on(display.wrapper.ownerDocument,"mousemove",mouseMove);on(display.scroller,"dragstart",dragStart);on(display.scroller,"drop",dragEnd);cm.state.delayingBlurEvent=true;setTimeout((function(){return display.input.focus()}),20);if(display.scroller.dragDrop){display.scroller.dragDrop()}}function rangeForUnit(cm,pos,unit){if(unit=="char"){return new Range(pos,pos)}if(unit=="word"){return cm.findWordAt(pos)}if(unit=="line"){return new Range(Pos(pos.line,0),clipPos(cm.doc,Pos(pos.line+1,0)))}var result=unit(cm,pos);return new Range(result.from,result.to)}function leftButtonSelect(cm,event,start,behavior){if(ie){delayBlurEvent(cm)}var display=cm.display,doc$1=cm.doc;e_preventDefault(event);var ourRange,ourIndex,startSel=doc$1.sel,ranges=startSel.ranges;if(behavior.addNew&&!behavior.extend){ourIndex=doc$1.sel.contains(start);if(ourIndex>-1){ourRange=ranges[ourIndex]}else{ourRange=new Range(start,start)}}else{ourRange=doc$1.sel.primary();ourIndex=doc$1.sel.primIndex}if(behavior.unit=="rectangle"){if(!behavior.addNew){ourRange=new Range(start,start)}start=posFromMouse(cm,event,true,true);ourIndex=-1}else{var range=rangeForUnit(cm,start,behavior.unit);if(behavior.extend){ourRange=extendRange(ourRange,range.anchor,range.head,behavior.extend)}else{ourRange=range}}if(!behavior.addNew){ourIndex=0;setSelection(doc$1,new Selection([ourRange],0),sel_mouse);startSel=doc$1.sel}else if(ourIndex==-1){ourIndex=ranges.length;setSelection(doc$1,normalizeSelection(cm,ranges.concat([ourRange]),ourIndex),{scroll:false,origin:"*mouse"})}else if(ranges.length>1&&ranges[ourIndex].empty()&&behavior.unit=="char"&&!behavior.extend){setSelection(doc$1,normalizeSelection(cm,ranges.slice(0,ourIndex).concat(ranges.slice(ourIndex+1)),0),{scroll:false,origin:"*mouse"});startSel=doc$1.sel}else{replaceOneSelection(doc$1,ourIndex,ourRange,sel_mouse)}var lastPos=start;function extendTo(pos){if(cmp(lastPos,pos)==0){return}lastPos=pos;if(behavior.unit=="rectangle"){var ranges=[],tabSize=cm.options.tabSize;var startCol=countColumn(getLine(doc$1,start.line).text,start.ch,tabSize);var posCol=countColumn(getLine(doc$1,pos.line).text,pos.ch,tabSize);var left=Math.min(startCol,posCol),right=Math.max(startCol,posCol);for(var line=Math.min(start.line,pos.line),end=Math.min(cm.lastLine(),Math.max(start.line,pos.line));line<=end;line++){var text=getLine(doc$1,line).text,leftPos=findColumn(text,left,tabSize);if(left==right){ranges.push(new Range(Pos(line,leftPos),Pos(line,leftPos)))}else if(text.length>leftPos){ranges.push(new Range(Pos(line,leftPos),Pos(line,findColumn(text,right,tabSize))))}}if(!ranges.length){ranges.push(new Range(start,start))}setSelection(doc$1,normalizeSelection(cm,startSel.ranges.slice(0,ourIndex).concat(ranges),ourIndex),{origin:"*mouse",scroll:false});cm.scrollIntoView(pos)}else{var oldRange=ourRange;var range=rangeForUnit(cm,pos,behavior.unit);var anchor=oldRange.anchor,head;if(cmp(range.anchor,anchor)>0){head=range.head;anchor=minPos(oldRange.from(),range.anchor)}else{head=range.anchor;anchor=maxPos(oldRange.to(),range.head)}var ranges$1=startSel.ranges.slice(0);ranges$1[ourIndex]=bidiSimplify(cm,new Range(clipPos(doc$1,anchor),head));setSelection(doc$1,normalizeSelection(cm,ranges$1,ourIndex),sel_mouse)}}var editorSize=display.wrapper.getBoundingClientRect();var counter=0;function extend(e){var curCount=++counter;var cur=posFromMouse(cm,e,true,behavior.unit=="rectangle");if(!cur){return}if(cmp(cur,lastPos)!=0){cm.curOp.focus=activeElt(doc(cm));extendTo(cur);var visible=visibleLines(display,doc$1);if(cur.line>=visible.to||cur.line<visible.from){setTimeout(operation(cm,(function(){if(counter==curCount){extend(e)}})),150)}}else{var outside=e.clientY<editorSize.top?-20:e.clientY>editorSize.bottom?20:0;if(outside){setTimeout(operation(cm,(function(){if(counter!=curCount){return}display.scroller.scrollTop+=outside;extend(e)})),50)}}}function done(e){cm.state.selectingText=false;counter=Infinity;if(e){e_preventDefault(e);display.input.focus()}off(display.wrapper.ownerDocument,"mousemove",move);off(display.wrapper.ownerDocument,"mouseup",up);doc$1.history.lastSelOrigin=null}var move=operation(cm,(function(e){if(e.buttons===0||!e_button(e)){done(e)}else{extend(e)}}));var up=operation(cm,done);cm.state.selectingText=up;on(display.wrapper.ownerDocument,"mousemove",move);on(display.wrapper.ownerDocument,"mouseup",up)}function bidiSimplify(cm,range){var anchor=range.anchor;var head=range.head;var anchorLine=getLine(cm.doc,anchor.line);if(cmp(anchor,head)==0&&anchor.sticky==head.sticky){return range}var order=getOrder(anchorLine);if(!order){return range}var index=getBidiPartAt(order,anchor.ch,anchor.sticky),part=order[index];if(part.from!=anchor.ch&&part.to!=anchor.ch){return range}var boundary=index+(part.from==anchor.ch==(part.level!=1)?0:1);if(boundary==0||boundary==order.length){return range}var leftSide;if(head.line!=anchor.line){leftSide=(head.line-anchor.line)*(cm.doc.direction=="ltr"?1:-1)>0}else{var headIndex=getBidiPartAt(order,head.ch,head.sticky);var dir=headIndex-index||(head.ch-anchor.ch)*(part.level==1?-1:1);if(headIndex==boundary-1||headIndex==boundary){leftSide=dir<0}else{leftSide=dir>0}}var usePart=order[boundary+(leftSide?-1:0)];var from=leftSide==(usePart.level==1);var ch=from?usePart.from:usePart.to,sticky=from?"after":"before";return anchor.ch==ch&&anchor.sticky==sticky?range:new Range(new Pos(anchor.line,ch,sticky),head)}function gutterEvent(cm,e,type,prevent){var mX,mY;if(e.touches){mX=e.touches[0].clientX;mY=e.touches[0].clientY}else{try{mX=e.clientX;mY=e.clientY}catch(e$1){return false}}if(mX>=Math.floor(cm.display.gutters.getBoundingClientRect().right)){return false}if(prevent){e_preventDefault(e)}var display=cm.display;var lineBox=display.lineDiv.getBoundingClientRect();if(mY>lineBox.bottom||!hasHandler(cm,type)){return e_defaultPrevented(e)}mY-=lineBox.top-display.viewOffset;for(var i=0;i<cm.display.gutterSpecs.length;++i){var g=display.gutters.childNodes[i];if(g&&g.getBoundingClientRect().right>=mX){var line=lineAtHeight(cm.doc,mY);var gutter=cm.display.gutterSpecs[i];signal(cm,type,cm,line,gutter.className,e);return e_defaultPrevented(e)}}}function clickInGutter(cm,e){return gutterEvent(cm,e,"gutterClick",true)}function onContextMenu(cm,e){if(eventInWidget(cm.display,e)||contextMenuInGutter(cm,e)){return}if(signalDOMEvent(cm,e,"contextmenu")){return}if(!captureRightClick){cm.display.input.onContextMenu(e)}}function contextMenuInGutter(cm,e){if(!hasHandler(cm,"gutterContextMenu")){return false}return gutterEvent(cm,e,"gutterContextMenu",false)}function themeChanged(cm){cm.display.wrapper.className=cm.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+cm.options.theme.replace(/(^|\s)\s*/g," cm-s-");clearCaches(cm)}var Init={toString:function(){return"CodeMirror.Init"}};var defaults={};var optionHandlers={};function defineOptions(CodeMirror){var optionHandlers=CodeMirror.optionHandlers;function option(name,deflt,handle,notOnInit){CodeMirror.defaults[name]=deflt;if(handle){optionHandlers[name]=notOnInit?function(cm,val,old){if(old!=Init){handle(cm,val,old)}}:handle}}CodeMirror.defineOption=option;CodeMirror.Init=Init;option("value","",(function(cm,val){return cm.setValue(val)}),true);option("mode",null,(function(cm,val){cm.doc.modeOption=val;loadMode(cm)}),true);option("indentUnit",2,loadMode,true);option("indentWithTabs",false);option("smartIndent",true);option("tabSize",4,(function(cm){resetModeState(cm);clearCaches(cm);regChange(cm)}),true);option("lineSeparator",null,(function(cm,val){cm.doc.lineSep=val;if(!val){return}var newBreaks=[],lineNo=cm.doc.first;cm.doc.iter((function(line){for(var pos=0;;){var found=line.text.indexOf(val,pos);if(found==-1){break}pos=found+val.length;newBreaks.push(Pos(lineNo,found))}lineNo++}));for(var i=newBreaks.length-1;i>=0;i--){replaceRange(cm.doc,val,newBreaks[i],Pos(newBreaks[i].line,newBreaks[i].ch+val.length))}}));option("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/g,(function(cm,val,old){cm.state.specialChars=new RegExp(val.source+(val.test("\t")?"":"|\t"),"g");if(old!=Init){cm.refresh()}}));option("specialCharPlaceholder",defaultSpecialCharPlaceholder,(function(cm){return cm.refresh()}),true);option("electricChars",true);option("inputStyle",mobile?"contenteditable":"textarea",(function(){throw new Error("inputStyle can not (yet) be changed in a running editor")}),true);option("spellcheck",false,(function(cm,val){return cm.getInputField().spellcheck=val}),true);option("autocorrect",false,(function(cm,val){return cm.getInputField().autocorrect=val}),true);option("autocapitalize",false,(function(cm,val){return cm.getInputField().autocapitalize=val}),true);option("rtlMoveVisually",!windows);option("wholeLineUpdateBefore",true);option("theme","default",(function(cm){themeChanged(cm);updateGutters(cm)}),true);option("keyMap","default",(function(cm,val,old){var next=getKeyMap(val);var prev=old!=Init&&getKeyMap(old);if(prev&&prev.detach){prev.detach(cm,next)}if(next.attach){next.attach(cm,prev||null)}}));option("extraKeys",null);option("configureMouse",null);option("lineWrapping",false,wrappingChanged,true);option("gutters",[],(function(cm,val){cm.display.gutterSpecs=getGutters(val,cm.options.lineNumbers);updateGutters(cm)}),true);option("fixedGutter",true,(function(cm,val){cm.display.gutters.style.left=val?compensateForHScroll(cm.display)+"px":"0";cm.refresh()}),true);option("coverGutterNextToScrollbar",false,(function(cm){return updateScrollbars(cm)}),true);option("scrollbarStyle","native",(function(cm){initScrollbars(cm);updateScrollbars(cm);cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft)}),true);option("lineNumbers",false,(function(cm,val){cm.display.gutterSpecs=getGutters(cm.options.gutters,val);updateGutters(cm)}),true);option("firstLineNumber",1,updateGutters,true);option("lineNumberFormatter",(function(integer){return integer}),updateGutters,true);option("showCursorWhenSelecting",false,updateSelection,true);option("resetSelectionOnContextMenu",true);option("lineWiseCopyCut",true);option("pasteLinesPerSelection",true);option("selectionsMayTouch",false);option("readOnly",false,(function(cm,val){if(val=="nocursor"){onBlur(cm);cm.display.input.blur()}cm.display.input.readOnlyChanged(val)}));option("screenReaderLabel",null,(function(cm,val){val=val===""?null:val;cm.display.input.screenReaderLabelChanged(val)}));option("disableInput",false,(function(cm,val){if(!val){cm.display.input.reset()}}),true);option("dragDrop",true,dragDropChanged);option("allowDropFileTypes",null);option("cursorBlinkRate",530);option("cursorScrollMargin",0);option("cursorHeight",1,updateSelection,true);option("singleCursorHeightPerLine",true,updateSelection,true);option("workTime",100);option("workDelay",100);option("flattenSpans",true,resetModeState,true);option("addModeClass",false,resetModeState,true);option("pollInterval",100);option("undoDepth",200,(function(cm,val){return cm.doc.history.undoDepth=val}));option("historyEventDelay",1250);option("viewportMargin",10,(function(cm){return cm.refresh()}),true);option("maxHighlightLength",1e4,resetModeState,true);option("moveInputWithCursor",true,(function(cm,val){if(!val){cm.display.input.resetPosition()}}));option("tabindex",null,(function(cm,val){return cm.display.input.getField().tabIndex=val||""}));option("autofocus",null);option("direction","ltr",(function(cm,val){return cm.doc.setDirection(val)}),true);option("phrases",null)}function dragDropChanged(cm,value,old){var wasOn=old&&old!=Init;if(!value!=!wasOn){var funcs=cm.display.dragFunctions;var toggle=value?on:off;toggle(cm.display.scroller,"dragstart",funcs.start);toggle(cm.display.scroller,"dragenter",funcs.enter);toggle(cm.display.scroller,"dragover",funcs.over);toggle(cm.display.scroller,"dragleave",funcs.leave);toggle(cm.display.scroller,"drop",funcs.drop)}}function wrappingChanged(cm){if(cm.options.lineWrapping){addClass(cm.display.wrapper,"CodeMirror-wrap");cm.display.sizer.style.minWidth="";cm.display.sizerWidth=null}else{rmClass(cm.display.wrapper,"CodeMirror-wrap");findMaxLine(cm)}estimateLineHeights(cm);regChange(cm);clearCaches(cm);setTimeout((function(){return updateScrollbars(cm)}),100)}function CodeMirror(place,options){var this$1=this;if(!(this instanceof CodeMirror)){return new CodeMirror(place,options)}this.options=options=options?copyObj(options):{};copyObj(defaults,options,false);var doc=options.value;if(typeof doc=="string"){doc=new Doc(doc,options.mode,null,options.lineSeparator,options.direction)}else if(options.mode){doc.modeOption=options.mode}this.doc=doc;var input=new CodeMirror.inputStyles[options.inputStyle](this);var display=this.display=new Display(place,doc,input,options);display.wrapper.CodeMirror=this;themeChanged(this);if(options.lineWrapping){this.display.wrapper.className+=" CodeMirror-wrap"}initScrollbars(this);this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:false,delayingBlurEvent:false,focused:false,suppressEdits:false,pasteIncoming:-1,cutIncoming:-1,selectingText:false,draggingText:false,highlight:new Delayed,keySeq:null,specialChars:null};if(options.autofocus&&!mobile){display.input.focus()}if(ie&&ie_version<11){setTimeout((function(){return this$1.display.input.reset(true)}),20)}registerEventHandlers(this);ensureGlobalHandlers();startOperation(this);this.curOp.forceUpdate=true;attachDoc(this,doc);if(options.autofocus&&!mobile||this.hasFocus()){setTimeout((function(){if(this$1.hasFocus()&&!this$1.state.focused){onFocus(this$1)}}),20)}else{onBlur(this)}for(var opt in optionHandlers){if(optionHandlers.hasOwnProperty(opt)){optionHandlers[opt](this,options[opt],Init)}}maybeUpdateLineNumberWidth(this);if(options.finishInit){options.finishInit(this)}for(var i=0;i<initHooks.length;++i){initHooks[i](this)}endOperation(this);if(webkit&&options.lineWrapping&&getComputedStyle(display.lineDiv).textRendering=="optimizelegibility"){display.lineDiv.style.textRendering="auto"}}CodeMirror.defaults=defaults;CodeMirror.optionHandlers=optionHandlers;function registerEventHandlers(cm){var d=cm.display;on(d.scroller,"mousedown",operation(cm,onMouseDown));if(ie&&ie_version<11){on(d.scroller,"dblclick",operation(cm,(function(e){if(signalDOMEvent(cm,e)){return}var pos=posFromMouse(cm,e);if(!pos||clickInGutter(cm,e)||eventInWidget(cm.display,e)){return}e_preventDefault(e);var word=cm.findWordAt(pos);extendSelection(cm.doc,word.anchor,word.head)})))}else{on(d.scroller,"dblclick",(function(e){return signalDOMEvent(cm,e)||e_preventDefault(e)}))}on(d.scroller,"contextmenu",(function(e){return onContextMenu(cm,e)}));on(d.input.getField(),"contextmenu",(function(e){if(!d.scroller.contains(e.target)){onContextMenu(cm,e)}}));var touchFinished,prevTouch={end:0};function finishTouch(){if(d.activeTouch){touchFinished=setTimeout((function(){return d.activeTouch=null}),1e3);prevTouch=d.activeTouch;prevTouch.end=+new Date}}function isMouseLikeTouchEvent(e){if(e.touches.length!=1){return false}var touch=e.touches[0];return touch.radiusX<=1&&touch.radiusY<=1}function farAway(touch,other){if(other.left==null){return true}var dx=other.left-touch.left,dy=other.top-touch.top;return dx*dx+dy*dy>20*20}on(d.scroller,"touchstart",(function(e){if(!signalDOMEvent(cm,e)&&!isMouseLikeTouchEvent(e)&&!clickInGutter(cm,e)){d.input.ensurePolled();clearTimeout(touchFinished);var now=+new Date;d.activeTouch={start:now,moved:false,prev:now-prevTouch.end<=300?prevTouch:null};if(e.touches.length==1){d.activeTouch.left=e.touches[0].pageX;d.activeTouch.top=e.touches[0].pageY}}}));on(d.scroller,"touchmove",(function(){if(d.activeTouch){d.activeTouch.moved=true}}));on(d.scroller,"touchend",(function(e){var touch=d.activeTouch;if(touch&&!eventInWidget(d,e)&&touch.left!=null&&!touch.moved&&new Date-touch.start<300){var pos=cm.coordsChar(d.activeTouch,"page"),range;if(!touch.prev||farAway(touch,touch.prev)){range=new Range(pos,pos)}else if(!touch.prev.prev||farAway(touch,touch.prev.prev)){range=cm.findWordAt(pos)}else{range=new Range(Pos(pos.line,0),clipPos(cm.doc,Pos(pos.line+1,0)))}cm.setSelection(range.anchor,range.head);cm.focus();e_preventDefault(e)}finishTouch()}));on(d.scroller,"touchcancel",finishTouch);on(d.scroller,"scroll",(function(){if(d.scroller.clientHeight){updateScrollTop(cm,d.scroller.scrollTop);setScrollLeft(cm,d.scroller.scrollLeft,true);signal(cm,"scroll",cm)}}));on(d.scroller,"mousewheel",(function(e){return onScrollWheel(cm,e)}));on(d.scroller,"DOMMouseScroll",(function(e){return onScrollWheel(cm,e)}));on(d.wrapper,"scroll",(function(){return d.wrapper.scrollTop=d.wrapper.scrollLeft=0}));d.dragFunctions={enter:function(e){if(!signalDOMEvent(cm,e)){e_stop(e)}},over:function(e){if(!signalDOMEvent(cm,e)){onDragOver(cm,e);e_stop(e)}},start:function(e){return onDragStart(cm,e)},drop:operation(cm,onDrop),leave:function(e){if(!signalDOMEvent(cm,e)){clearDragCursor(cm)}}};var inp=d.input.getField();on(inp,"keyup",(function(e){return onKeyUp.call(cm,e)}));on(inp,"keydown",operation(cm,onKeyDown));on(inp,"keypress",operation(cm,onKeyPress));on(inp,"focus",(function(e){return onFocus(cm,e)}));on(inp,"blur",(function(e){return onBlur(cm,e)}))}var initHooks=[];CodeMirror.defineInitHook=function(f){return initHooks.push(f)};function indentLine(cm,n,how,aggressive){var doc=cm.doc,state;if(how==null){how="add"}if(how=="smart"){if(!doc.mode.indent){how="prev"}else{state=getContextBefore(cm,n).state}}var tabSize=cm.options.tabSize;var line=getLine(doc,n),curSpace=countColumn(line.text,null,tabSize);if(line.stateAfter){line.stateAfter=null}var curSpaceString=line.text.match(/^\s*/)[0],indentation;if(!aggressive&&!/\S/.test(line.text)){indentation=0;how="not"}else if(how=="smart"){indentation=doc.mode.indent(state,line.text.slice(curSpaceString.length),line.text);if(indentation==Pass||indentation>150){if(!aggressive){return}how="prev"}}if(how=="prev"){if(n>doc.first){indentation=countColumn(getLine(doc,n-1).text,null,tabSize)}else{indentation=0}}else if(how=="add"){indentation=curSpace+cm.options.indentUnit}else if(how=="subtract"){indentation=curSpace-cm.options.indentUnit}else if(typeof how=="number"){indentation=curSpace+how}indentation=Math.max(0,indentation);var indentString="",pos=0;if(cm.options.indentWithTabs){for(var i=Math.floor(indentation/tabSize);i;--i){pos+=tabSize;indentString+="\t"}}if(pos<indentation){indentString+=spaceStr(indentation-pos)}if(indentString!=curSpaceString){replaceRange(doc,indentString,Pos(n,0),Pos(n,curSpaceString.length),"+input");line.stateAfter=null;return true}else{for(var i$1=0;i$1<doc.sel.ranges.length;i$1++){var range=doc.sel.ranges[i$1];if(range.head.line==n&&range.head.ch<curSpaceString.length){var pos$1=Pos(n,curSpaceString.length);replaceOneSelection(doc,i$1,new Range(pos$1,pos$1));break}}}}var lastCopied=null;function setLastCopied(newLastCopied){lastCopied=newLastCopied}function applyTextInput(cm,inserted,deleted,sel,origin){var doc=cm.doc;cm.display.shift=false;if(!sel){sel=doc.sel}var recent=+new Date-200;var paste=origin=="paste"||cm.state.pasteIncoming>recent;var textLines=splitLinesAuto(inserted),multiPaste=null;if(paste&&sel.ranges.length>1){if(lastCopied&&lastCopied.text.join("\n")==inserted){if(sel.ranges.length%lastCopied.text.length==0){multiPaste=[];for(var i=0;i<lastCopied.text.length;i++){multiPaste.push(doc.splitLines(lastCopied.text[i]))}}}else if(textLines.length==sel.ranges.length&&cm.options.pasteLinesPerSelection){multiPaste=map(textLines,(function(l){return[l]}))}}var updateInput=cm.curOp.updateInput;for(var i$1=sel.ranges.length-1;i$1>=0;i$1--){var range=sel.ranges[i$1];var from=range.from(),to=range.to();if(range.empty()){if(deleted&&deleted>0){from=Pos(from.line,from.ch-deleted)}else if(cm.state.overwrite&&!paste){to=Pos(to.line,Math.min(getLine(doc,to.line).text.length,to.ch+lst(textLines).length))}else if(paste&&lastCopied&&lastCopied.lineWise&&lastCopied.text.join("\n")==textLines.join("\n")){from=to=Pos(from.line,0)}}var changeEvent={from:from,to:to,text:multiPaste?multiPaste[i$1%multiPaste.length]:textLines,origin:origin||(paste?"paste":cm.state.cutIncoming>recent?"cut":"+input")};makeChange(cm.doc,changeEvent);signalLater(cm,"inputRead",cm,changeEvent)}if(inserted&&!paste){triggerElectric(cm,inserted)}ensureCursorVisible(cm);if(cm.curOp.updateInput<2){cm.curOp.updateInput=updateInput}cm.curOp.typing=true;cm.state.pasteIncoming=cm.state.cutIncoming=-1}function handlePaste(e,cm){var pasted=e.clipboardData&&e.clipboardData.getData("Text");if(pasted){e.preventDefault();if(!cm.isReadOnly()&&!cm.options.disableInput&&cm.hasFocus()){runInOp(cm,(function(){return applyTextInput(cm,pasted,0,null,"paste")}))}return true}}function triggerElectric(cm,inserted){if(!cm.options.electricChars||!cm.options.smartIndent){return}var sel=cm.doc.sel;for(var i=sel.ranges.length-1;i>=0;i--){var range=sel.ranges[i];if(range.head.ch>100||i&&sel.ranges[i-1].head.line==range.head.line){continue}var mode=cm.getModeAt(range.head);var indented=false;if(mode.electricChars){for(var j=0;j<mode.electricChars.length;j++){if(inserted.indexOf(mode.electricChars.charAt(j))>-1){indented=indentLine(cm,range.head.line,"smart");break}}}else if(mode.electricInput){if(mode.electricInput.test(getLine(cm.doc,range.head.line).text.slice(0,range.head.ch))){indented=indentLine(cm,range.head.line,"smart")}}if(indented){signalLater(cm,"electricInput",cm,range.head.line)}}}function copyableRanges(cm){var text=[],ranges=[];for(var i=0;i<cm.doc.sel.ranges.length;i++){var line=cm.doc.sel.ranges[i].head.line;var lineRange={anchor:Pos(line,0),head:Pos(line+1,0)};ranges.push(lineRange);text.push(cm.getRange(lineRange.anchor,lineRange.head))}return{text:text,ranges:ranges}}function disableBrowserMagic(field,spellcheck,autocorrect,autocapitalize){field.setAttribute("autocorrect",autocorrect?"on":"off");field.setAttribute("autocapitalize",autocapitalize?"on":"off");field.setAttribute("spellcheck",!!spellcheck)}function hiddenTextarea(){var te=elt("textarea",null,null,"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; min-height: 1em; outline: none");var div=elt("div",[te],null,"overflow: hidden; position: relative; width: 3px; height: 0px;");if(webkit){te.style.width="1000px"}else{te.setAttribute("wrap","off")}if(ios){te.style.border="1px solid black"}return div}function addEditorMethods(CodeMirror){var optionHandlers=CodeMirror.optionHandlers;var helpers=CodeMirror.helpers={};CodeMirror.prototype={constructor:CodeMirror,focus:function(){win(this).focus();this.display.input.focus()},setOption:function(option,value){var options=this.options,old=options[option];if(options[option]==value&&option!="mode"){return}options[option]=value;if(optionHandlers.hasOwnProperty(option)){operation(this,optionHandlers[option])(this,value,old)}signal(this,"optionChange",this,option)},getOption:function(option){return this.options[option]},getDoc:function(){return this.doc},addKeyMap:function(map,bottom){this.state.keyMaps[bottom?"push":"unshift"](getKeyMap(map))},removeKeyMap:function(map){var maps=this.state.keyMaps;for(var i=0;i<maps.length;++i){if(maps[i]==map||maps[i].name==map){maps.splice(i,1);return true}}},addOverlay:methodOp((function(spec,options){var mode=spec.token?spec:CodeMirror.getMode(this.options,spec);if(mode.startState){throw new Error("Overlays may not be stateful.")}insertSorted(this.state.overlays,{mode:mode,modeSpec:spec,opaque:options&&options.opaque,priority:options&&options.priority||0},(function(overlay){return overlay.priority}));this.state.modeGen++;regChange(this)})),removeOverlay:methodOp((function(spec){var overlays=this.state.overlays;for(var i=0;i<overlays.length;++i){var cur=overlays[i].modeSpec;if(cur==spec||typeof spec=="string"&&cur.name==spec){overlays.splice(i,1);this.state.modeGen++;regChange(this);return}}})),indentLine:methodOp((function(n,dir,aggressive){if(typeof dir!="string"&&typeof dir!="number"){if(dir==null){dir=this.options.smartIndent?"smart":"prev"}else{dir=dir?"add":"subtract"}}if(isLine(this.doc,n)){indentLine(this,n,dir,aggressive)}})),indentSelection:methodOp((function(how){var ranges=this.doc.sel.ranges,end=-1;for(var i=0;i<ranges.length;i++){var range=ranges[i];if(!range.empty()){var from=range.from(),to=range.to();var start=Math.max(end,from.line);end=Math.min(this.lastLine(),to.line-(to.ch?0:1))+1;for(var j=start;j<end;++j){indentLine(this,j,how)}var newRanges=this.doc.sel.ranges;if(from.ch==0&&ranges.length==newRanges.length&&newRanges[i].from().ch>0){replaceOneSelection(this.doc,i,new Range(from,newRanges[i].to()),sel_dontScroll)}}else if(range.head.line>end){indentLine(this,range.head.line,how,true);end=range.head.line;if(i==this.doc.sel.primIndex){ensureCursorVisible(this)}}}})),getTokenAt:function(pos,precise){return takeToken(this,pos,precise)},getLineTokens:function(line,precise){return takeToken(this,Pos(line),precise,true)},getTokenTypeAt:function(pos){pos=clipPos(this.doc,pos);var styles=getLineStyles(this,getLine(this.doc,pos.line));var before=0,after=(styles.length-1)/2,ch=pos.ch;var type;if(ch==0){type=styles[2]}else{for(;;){var mid=before+after>>1;if((mid?styles[mid*2-1]:0)>=ch){after=mid}else if(styles[mid*2+1]<ch){before=mid+1}else{type=styles[mid*2+2];break}}}var cut=type?type.indexOf("overlay "):-1;return cut<0?type:cut==0?null:type.slice(0,cut-1)},getModeAt:function(pos){var mode=this.doc.mode;if(!mode.innerMode){return mode}return CodeMirror.innerMode(mode,this.getTokenAt(pos).state).mode},getHelper:function(pos,type){return this.getHelpers(pos,type)[0]},getHelpers:function(pos,type){var found=[];if(!helpers.hasOwnProperty(type)){return found}var help=helpers[type],mode=this.getModeAt(pos);if(typeof mode[type]=="string"){if(help[mode[type]]){found.push(help[mode[type]])}}else if(mode[type]){for(var i=0;i<mode[type].length;i++){var val=help[mode[type][i]];if(val){found.push(val)}}}else if(mode.helperType&&help[mode.helperType]){found.push(help[mode.helperType])}else if(help[mode.name]){found.push(help[mode.name])}for(var i$1=0;i$1<help._global.length;i$1++){var cur=help._global[i$1];if(cur.pred(mode,this)&&indexOf(found,cur.val)==-1){found.push(cur.val)}}return found},getStateAfter:function(line,precise){var doc=this.doc;line=clipLine(doc,line==null?doc.first+doc.size-1:line);return getContextBefore(this,line+1,precise).state},cursorCoords:function(start,mode){var pos,range=this.doc.sel.primary();if(start==null){pos=range.head}else if(typeof start=="object"){pos=clipPos(this.doc,start)}else{pos=start?range.from():range.to()}return cursorCoords(this,pos,mode||"page")},charCoords:function(pos,mode){return charCoords(this,clipPos(this.doc,pos),mode||"page")},coordsChar:function(coords,mode){coords=fromCoordSystem(this,coords,mode||"page");return coordsChar(this,coords.left,coords.top)},lineAtHeight:function(height,mode){height=fromCoordSystem(this,{top:height,left:0},mode||"page").top;return lineAtHeight(this.doc,height+this.display.viewOffset)},heightAtLine:function(line,mode,includeWidgets){var end=false,lineObj;if(typeof line=="number"){var last=this.doc.first+this.doc.size-1;if(line<this.doc.first){line=this.doc.first}else if(line>last){line=last;end=true}lineObj=getLine(this.doc,line)}else{lineObj=line}return intoCoordSystem(this,lineObj,{top:0,left:0},mode||"page",includeWidgets||end).top+(end?this.doc.height-heightAtLine(lineObj):0)},defaultTextHeight:function(){return textHeight(this.display)},defaultCharWidth:function(){return charWidth(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(pos,node,scroll,vert,horiz){var display=this.display;pos=cursorCoords(this,clipPos(this.doc,pos));var top=pos.bottom,left=pos.left;node.style.position="absolute";node.setAttribute("cm-ignore-events","true");this.display.input.setUneditable(node);display.sizer.appendChild(node);if(vert=="over"){top=pos.top}else if(vert=="above"||vert=="near"){var vspace=Math.max(display.wrapper.clientHeight,this.doc.height),hspace=Math.max(display.sizer.clientWidth,display.lineSpace.clientWidth);if((vert=="above"||pos.bottom+node.offsetHeight>vspace)&&pos.top>node.offsetHeight){top=pos.top-node.offsetHeight}else if(pos.bottom+node.offsetHeight<=vspace){top=pos.bottom}if(left+node.offsetWidth>hspace){left=hspace-node.offsetWidth}}node.style.top=top+"px";node.style.left=node.style.right="";if(horiz=="right"){left=display.sizer.clientWidth-node.offsetWidth;node.style.right="0px"}else{if(horiz=="left"){left=0}else if(horiz=="middle"){left=(display.sizer.clientWidth-node.offsetWidth)/2}node.style.left=left+"px"}if(scroll){scrollIntoView(this,{left:left,top:top,right:left+node.offsetWidth,bottom:top+node.offsetHeight})}},triggerOnKeyDown:methodOp(onKeyDown),triggerOnKeyPress:methodOp(onKeyPress),triggerOnKeyUp:onKeyUp,triggerOnMouseDown:methodOp(onMouseDown),execCommand:function(cmd){if(commands.hasOwnProperty(cmd)){return commands[cmd].call(null,this)}},triggerElectric:methodOp((function(text){triggerElectric(this,text)})),findPosH:function(from,amount,unit,visually){var dir=1;if(amount<0){dir=-1;amount=-amount}var cur=clipPos(this.doc,from);for(var i=0;i<amount;++i){cur=findPosH(this.doc,cur,dir,unit,visually);if(cur.hitSide){break}}return cur},moveH:methodOp((function(dir,unit){var this$1=this;this.extendSelectionsBy((function(range){if(this$1.display.shift||this$1.doc.extend||range.empty()){return findPosH(this$1.doc,range.head,dir,unit,this$1.options.rtlMoveVisually)}else{return dir<0?range.from():range.to()}}),sel_move)})),deleteH:methodOp((function(dir,unit){var sel=this.doc.sel,doc=this.doc;if(sel.somethingSelected()){doc.replaceSelection("",null,"+delete")}else{deleteNearSelection(this,(function(range){var other=findPosH(doc,range.head,dir,unit,false);return dir<0?{from:other,to:range.head}:{from:range.head,to:other}}))}})),findPosV:function(from,amount,unit,goalColumn){var dir=1,x=goalColumn;if(amount<0){dir=-1;amount=-amount}var cur=clipPos(this.doc,from);for(var i=0;i<amount;++i){var coords=cursorCoords(this,cur,"div");if(x==null){x=coords.left}else{coords.left=x}cur=findPosV(this,coords,dir,unit);if(cur.hitSide){break}}return cur},moveV:methodOp((function(dir,unit){var this$1=this;var doc=this.doc,goals=[];var collapse=!this.display.shift&&!doc.extend&&doc.sel.somethingSelected();doc.extendSelectionsBy((function(range){if(collapse){return dir<0?range.from():range.to()}var headPos=cursorCoords(this$1,range.head,"div");if(range.goalColumn!=null){headPos.left=range.goalColumn}goals.push(headPos.left);var pos=findPosV(this$1,headPos,dir,unit);if(unit=="page"&&range==doc.sel.primary()){addToScrollTop(this$1,charCoords(this$1,pos,"div").top-headPos.top)}return pos}),sel_move);if(goals.length){for(var i=0;i<doc.sel.ranges.length;i++){doc.sel.ranges[i].goalColumn=goals[i]}}})),findWordAt:function(pos){var doc=this.doc,line=getLine(doc,pos.line).text;var start=pos.ch,end=pos.ch;if(line){var helper=this.getHelper(pos,"wordChars");if((pos.sticky=="before"||end==line.length)&&start){--start}else{++end}var startChar=line.charAt(start);var check=isWordChar(startChar,helper)?function(ch){return isWordChar(ch,helper)}:/\s/.test(startChar)?function(ch){return/\s/.test(ch)}:function(ch){return!/\s/.test(ch)&&!isWordChar(ch)};while(start>0&&check(line.charAt(start-1))){--start}while(end<line.length&&check(line.charAt(end))){++end}}return new Range(Pos(pos.line,start),Pos(pos.line,end))},toggleOverwrite:function(value){if(value!=null&&value==this.state.overwrite){return}if(this.state.overwrite=!this.state.overwrite){addClass(this.display.cursorDiv,"CodeMirror-overwrite")}else{rmClass(this.display.cursorDiv,"CodeMirror-overwrite")}signal(this,"overwriteToggle",this,this.state.overwrite)},hasFocus:function(){return this.display.input.getField()==activeElt(doc(this))},isReadOnly:function(){return!!(this.options.readOnly||this.doc.cantEdit)},scrollTo:methodOp((function(x,y){scrollToCoords(this,x,y)})),getScrollInfo:function(){var scroller=this.display.scroller;return{left:scroller.scrollLeft,top:scroller.scrollTop,height:scroller.scrollHeight-scrollGap(this)-this.display.barHeight,width:scroller.scrollWidth-scrollGap(this)-this.display.barWidth,clientHeight:displayHeight(this),clientWidth:displayWidth(this)}},scrollIntoView:methodOp((function(range,margin){if(range==null){range={from:this.doc.sel.primary().head,to:null};if(margin==null){margin=this.options.cursorScrollMargin}}else if(typeof range=="number"){range={from:Pos(range,0),to:null}}else if(range.from==null){range={from:range,to:null}}if(!range.to){range.to=range.from}range.margin=margin||0;if(range.from.line!=null){scrollToRange(this,range)}else{scrollToCoordsRange(this,range.from,range.to,range.margin)}})),setSize:methodOp((function(width,height){var this$1=this;var interpret=function(val){return typeof val=="number"||/^\d+$/.test(String(val))?val+"px":val};if(width!=null){this.display.wrapper.style.width=interpret(width)}if(height!=null){this.display.wrapper.style.height=interpret(height)}if(this.options.lineWrapping){clearLineMeasurementCache(this)}var lineNo=this.display.viewFrom;this.doc.iter(lineNo,this.display.viewTo,(function(line){if(line.widgets){for(var i=0;i<line.widgets.length;i++){if(line.widgets[i].noHScroll){regLineChange(this$1,lineNo,"widget");break}}}++lineNo}));this.curOp.forceUpdate=true;signal(this,"refresh",this)})),operation:function(f){return runInOp(this,f)},startOperation:function(){return startOperation(this)},endOperation:function(){return endOperation(this)},refresh:methodOp((function(){var oldHeight=this.display.cachedTextHeight;regChange(this);this.curOp.forceUpdate=true;clearCaches(this);scrollToCoords(this,this.doc.scrollLeft,this.doc.scrollTop);updateGutterSpace(this.display);if(oldHeight==null||Math.abs(oldHeight-textHeight(this.display))>.5||this.options.lineWrapping){estimateLineHeights(this)}signal(this,"refresh",this)})),swapDoc:methodOp((function(doc){var old=this.doc;old.cm=null;if(this.state.selectingText){this.state.selectingText()}attachDoc(this,doc);clearCaches(this);this.display.input.reset();scrollToCoords(this,doc.scrollLeft,doc.scrollTop);this.curOp.forceScroll=true;signalLater(this,"swapDoc",this,old);return old})),phrase:function(phraseText){var phrases=this.options.phrases;return phrases&&Object.prototype.hasOwnProperty.call(phrases,phraseText)?phrases[phraseText]:phraseText},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}};eventMixin(CodeMirror);CodeMirror.registerHelper=function(type,name,value){if(!helpers.hasOwnProperty(type)){helpers[type]=CodeMirror[type]={_global:[]}}helpers[type][name]=value};CodeMirror.registerGlobalHelper=function(type,name,predicate,value){CodeMirror.registerHelper(type,name,value);helpers[type]._global.push({pred:predicate,val:value})}}function findPosH(doc,pos,dir,unit,visually){var oldPos=pos;var origDir=dir;var lineObj=getLine(doc,pos.line);var lineDir=visually&&doc.direction=="rtl"?-dir:dir;function findNextLine(){var l=pos.line+lineDir;if(l<doc.first||l>=doc.first+doc.size){return false}pos=new Pos(l,pos.ch,pos.sticky);return lineObj=getLine(doc,l)}function moveOnce(boundToLine){var next;if(unit=="codepoint"){var ch=lineObj.text.charCodeAt(pos.ch+(dir>0?0:-1));if(isNaN(ch)){next=null}else{var astral=dir>0?ch>=55296&&ch<56320:ch>=56320&&ch<57343;next=new Pos(pos.line,Math.max(0,Math.min(lineObj.text.length,pos.ch+dir*(astral?2:1))),-dir)}}else if(visually){next=moveVisually(doc.cm,lineObj,pos,dir)}else{next=moveLogically(lineObj,pos,dir)}if(next==null){if(!boundToLine&&findNextLine()){pos=endOfLine(visually,doc.cm,lineObj,pos.line,lineDir)}else{return false}}else{pos=next}return true}if(unit=="char"||unit=="codepoint"){moveOnce()}else if(unit=="column"){moveOnce(true)}else if(unit=="word"||unit=="group"){var sawType=null,group=unit=="group";var helper=doc.cm&&doc.cm.getHelper(pos,"wordChars");for(var first=true;;first=false){if(dir<0&&!moveOnce(!first)){break}var cur=lineObj.text.charAt(pos.ch)||"\n";var type=isWordChar(cur,helper)?"w":group&&cur=="\n"?"n":!group||/\s/.test(cur)?null:"p";if(group&&!first&&!type){type="s"}if(sawType&&sawType!=type){if(dir<0){dir=1;moveOnce();pos.sticky="after"}break}if(type){sawType=type}if(dir>0&&!moveOnce(!first)){break}}}var result=skipAtomic(doc,pos,oldPos,origDir,true);if(equalCursorPos(oldPos,result)){result.hitSide=true}return result}function findPosV(cm,pos,dir,unit){var doc=cm.doc,x=pos.left,y;if(unit=="page"){var pageSize=Math.min(cm.display.wrapper.clientHeight,win(cm).innerHeight||doc(cm).documentElement.clientHeight);var moveAmount=Math.max(pageSize-.5*textHeight(cm.display),3);y=(dir>0?pos.bottom:pos.top)+dir*moveAmount}else if(unit=="line"){y=dir>0?pos.bottom+3:pos.top-3}var target;for(;;){target=coordsChar(cm,x,y);if(!target.outside){break}if(dir<0?y<=0:y>=doc.height){target.hitSide=true;break}y+=dir*5}return target}var ContentEditableInput=function(cm){this.cm=cm;this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null;this.polling=new Delayed;this.composing=null;this.gracePeriod=false;this.readDOMTimeout=null};ContentEditableInput.prototype.init=function(display){var this$1=this;var input=this,cm=input.cm;var div=input.div=display.lineDiv;div.contentEditable=true;disableBrowserMagic(div,cm.options.spellcheck,cm.options.autocorrect,cm.options.autocapitalize);function belongsToInput(e){for(var t=e.target;t;t=t.parentNode){if(t==div){return true}if(/\bCodeMirror-(?:line)?widget\b/.test(t.className)){break}}return false}on(div,"paste",(function(e){if(!belongsToInput(e)||signalDOMEvent(cm,e)||handlePaste(e,cm)){return}if(ie_version<=11){setTimeout(operation(cm,(function(){return this$1.updateFromDOM()})),20)}}));on(div,"compositionstart",(function(e){this$1.composing={data:e.data,done:false}}));on(div,"compositionupdate",(function(e){if(!this$1.composing){this$1.composing={data:e.data,done:false}}}));on(div,"compositionend",(function(e){if(this$1.composing){if(e.data!=this$1.composing.data){this$1.readFromDOMSoon()}this$1.composing.done=true}}));on(div,"touchstart",(function(){return input.forceCompositionEnd()}));on(div,"input",(function(){if(!this$1.composing){this$1.readFromDOMSoon()}}));function onCopyCut(e){if(!belongsToInput(e)||signalDOMEvent(cm,e)){return}if(cm.somethingSelected()){setLastCopied({lineWise:false,text:cm.getSelections()});if(e.type=="cut"){cm.replaceSelection("",null,"cut")}}else if(!cm.options.lineWiseCopyCut){return}else{var ranges=copyableRanges(cm);setLastCopied({lineWise:true,text:ranges.text});if(e.type=="cut"){cm.operation((function(){cm.setSelections(ranges.ranges,0,sel_dontScroll);cm.replaceSelection("",null,"cut")}))}}if(e.clipboardData){e.clipboardData.clearData();var content=lastCopied.text.join("\n");e.clipboardData.setData("Text",content);if(e.clipboardData.getData("Text")==content){e.preventDefault();return}}var kludge=hiddenTextarea(),te=kludge.firstChild;disableBrowserMagic(te);cm.display.lineSpace.insertBefore(kludge,cm.display.lineSpace.firstChild);te.value=lastCopied.text.join("\n");var hadFocus=activeElt(div.ownerDocument);selectInput(te);setTimeout((function(){cm.display.lineSpace.removeChild(kludge);hadFocus.focus();if(hadFocus==div){input.showPrimarySelection()}}),50)}on(div,"copy",onCopyCut);on(div,"cut",onCopyCut)};ContentEditableInput.prototype.screenReaderLabelChanged=function(label){if(label){this.div.setAttribute("aria-label",label)}else{this.div.removeAttribute("aria-label")}};ContentEditableInput.prototype.prepareSelection=function(){var result=prepareSelection(this.cm,false);result.focus=activeElt(this.div.ownerDocument)==this.div;return result};ContentEditableInput.prototype.showSelection=function(info,takeFocus){if(!info||!this.cm.display.view.length){return}if(info.focus||takeFocus){this.showPrimarySelection()}this.showMultipleSelections(info)};ContentEditableInput.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()};ContentEditableInput.prototype.showPrimarySelection=function(){var sel=this.getSelection(),cm=this.cm,prim=cm.doc.sel.primary();var from=prim.from(),to=prim.to();if(cm.display.viewTo==cm.display.viewFrom||from.line>=cm.display.viewTo||to.line<cm.display.viewFrom){sel.removeAllRanges();return}var curAnchor=domToPos(cm,sel.anchorNode,sel.anchorOffset);var curFocus=domToPos(cm,sel.focusNode,sel.focusOffset);if(curAnchor&&!curAnchor.bad&&curFocus&&!curFocus.bad&&cmp(minPos(curAnchor,curFocus),from)==0&&cmp(maxPos(curAnchor,curFocus),to)==0){return}var view=cm.display.view;var start=from.line>=cm.display.viewFrom&&posToDOM(cm,from)||{node:view[0].measure.map[2],offset:0};var end=to.line<cm.display.viewTo&&posToDOM(cm,to);if(!end){var measure=view[view.length-1].measure;var map=measure.maps?measure.maps[measure.maps.length-1]:measure.map;end={node:map[map.length-1],offset:map[map.length-2]-map[map.length-3]}}if(!start||!end){sel.removeAllRanges();return}var old=sel.rangeCount&&sel.getRangeAt(0),rng;try{rng=range(start.node,start.offset,end.offset,end.node)}catch(e){}if(rng){if(!gecko&&cm.state.focused){sel.collapse(start.node,start.offset);if(!rng.collapsed){sel.removeAllRanges();sel.addRange(rng)}}else{sel.removeAllRanges();sel.addRange(rng)}if(old&&sel.anchorNode==null){sel.addRange(old)}else if(gecko){this.startGracePeriod()}}this.rememberSelection()};ContentEditableInput.prototype.startGracePeriod=function(){var this$1=this;clearTimeout(this.gracePeriod);this.gracePeriod=setTimeout((function(){this$1.gracePeriod=false;if(this$1.selectionChanged()){this$1.cm.operation((function(){return this$1.cm.curOp.selectionChanged=true}))}}),20)};ContentEditableInput.prototype.showMultipleSelections=function(info){removeChildrenAndAdd(this.cm.display.cursorDiv,info.cursors);removeChildrenAndAdd(this.cm.display.selectionDiv,info.selection)};ContentEditableInput.prototype.rememberSelection=function(){var sel=this.getSelection();this.lastAnchorNode=sel.anchorNode;this.lastAnchorOffset=sel.anchorOffset;this.lastFocusNode=sel.focusNode;this.lastFocusOffset=sel.focusOffset};ContentEditableInput.prototype.selectionInEditor=function(){var sel=this.getSelection();if(!sel.rangeCount){return false}var node=sel.getRangeAt(0).commonAncestorContainer;return contains(this.div,node)};ContentEditableInput.prototype.focus=function(){if(this.cm.options.readOnly!="nocursor"){if(!this.selectionInEditor()||activeElt(this.div.ownerDocument)!=this.div){this.showSelection(this.prepareSelection(),true)}this.div.focus()}};ContentEditableInput.prototype.blur=function(){this.div.blur()};ContentEditableInput.prototype.getField=function(){return this.div};ContentEditableInput.prototype.supportsTouch=function(){return true};ContentEditableInput.prototype.receivedFocus=function(){var this$1=this;var input=this;if(this.selectionInEditor()){setTimeout((function(){return this$1.pollSelection()}),20)}else{runInOp(this.cm,(function(){return input.cm.curOp.selectionChanged=true}))}function poll(){if(input.cm.state.focused){input.pollSelection();input.polling.set(input.cm.options.pollInterval,poll)}}this.polling.set(this.cm.options.pollInterval,poll)};ContentEditableInput.prototype.selectionChanged=function(){var sel=this.getSelection();return sel.anchorNode!=this.lastAnchorNode||sel.anchorOffset!=this.lastAnchorOffset||sel.focusNode!=this.lastFocusNode||sel.focusOffset!=this.lastFocusOffset};ContentEditableInput.prototype.pollSelection=function(){if(this.readDOMTimeout!=null||this.gracePeriod||!this.selectionChanged()){return}var sel=this.getSelection(),cm=this.cm;if(android&&chrome&&this.cm.display.gutterSpecs.length&&isInGutter(sel.anchorNode)){this.cm.triggerOnKeyDown({type:"keydown",keyCode:8,preventDefault:Math.abs});this.blur();this.focus();return}if(this.composing){return}this.rememberSelection();var anchor=domToPos(cm,sel.anchorNode,sel.anchorOffset);var head=domToPos(cm,sel.focusNode,sel.focusOffset);if(anchor&&head){runInOp(cm,(function(){setSelection(cm.doc,simpleSelection(anchor,head),sel_dontScroll);if(anchor.bad||head.bad){cm.curOp.selectionChanged=true}}))}};ContentEditableInput.prototype.pollContent=function(){if(this.readDOMTimeout!=null){clearTimeout(this.readDOMTimeout);this.readDOMTimeout=null}var cm=this.cm,display=cm.display,sel=cm.doc.sel.primary();var from=sel.from(),to=sel.to();if(from.ch==0&&from.line>cm.firstLine()){from=Pos(from.line-1,getLine(cm.doc,from.line-1).length)}if(to.ch==getLine(cm.doc,to.line).text.length&&to.line<cm.lastLine()){to=Pos(to.line+1,0)}if(from.line<display.viewFrom||to.line>display.viewTo-1){return false}var fromIndex,fromLine,fromNode;if(from.line==display.viewFrom||(fromIndex=findViewIndex(cm,from.line))==0){fromLine=lineNo(display.view[0].line);fromNode=display.view[0].node}else{fromLine=lineNo(display.view[fromIndex].line);fromNode=display.view[fromIndex-1].node.nextSibling}var toIndex=findViewIndex(cm,to.line);var toLine,toNode;if(toIndex==display.view.length-1){toLine=display.viewTo-1;toNode=display.lineDiv.lastChild}else{toLine=lineNo(display.view[toIndex+1].line)-1;toNode=display.view[toIndex+1].node.previousSibling}if(!fromNode){return false}var newText=cm.doc.splitLines(domTextBetween(cm,fromNode,toNode,fromLine,toLine));var oldText=getBetween(cm.doc,Pos(fromLine,0),Pos(toLine,getLine(cm.doc,toLine).text.length));while(newText.length>1&&oldText.length>1){if(lst(newText)==lst(oldText)){newText.pop();oldText.pop();toLine--}else if(newText[0]==oldText[0]){newText.shift();oldText.shift();fromLine++}else{break}}var cutFront=0,cutEnd=0;var newTop=newText[0],oldTop=oldText[0],maxCutFront=Math.min(newTop.length,oldTop.length);while(cutFront<maxCutFront&&newTop.charCodeAt(cutFront)==oldTop.charCodeAt(cutFront)){++cutFront}var newBot=lst(newText),oldBot=lst(oldText);var maxCutEnd=Math.min(newBot.length-(newText.length==1?cutFront:0),oldBot.length-(oldText.length==1?cutFront:0));while(cutEnd<maxCutEnd&&newBot.charCodeAt(newBot.length-cutEnd-1)==oldBot.charCodeAt(oldBot.length-cutEnd-1)){++cutEnd}if(newText.length==1&&oldText.length==1&&fromLine==from.line){while(cutFront&&cutFront>from.ch&&newBot.charCodeAt(newBot.length-cutEnd-1)==oldBot.charCodeAt(oldBot.length-cutEnd-1)){cutFront--;cutEnd++}}newText[newText.length-1]=newBot.slice(0,newBot.length-cutEnd).replace(/^\u200b+/,"");newText[0]=newText[0].slice(cutFront).replace(/\u200b+$/,"");var chFrom=Pos(fromLine,cutFront);var chTo=Pos(toLine,oldText.length?lst(oldText).length-cutEnd:0);if(newText.length>1||newText[0]||cmp(chFrom,chTo)){replaceRange(cm.doc,newText,chFrom,chTo,"+input");return true}};ContentEditableInput.prototype.ensurePolled=function(){this.forceCompositionEnd()};ContentEditableInput.prototype.reset=function(){this.forceCompositionEnd()};ContentEditableInput.prototype.forceCompositionEnd=function(){if(!this.composing){return}clearTimeout(this.readDOMTimeout);this.composing=null;this.updateFromDOM();this.div.blur();this.div.focus()};ContentEditableInput.prototype.readFromDOMSoon=function(){var this$1=this;if(this.readDOMTimeout!=null){return}this.readDOMTimeout=setTimeout((function(){this$1.readDOMTimeout=null;if(this$1.composing){if(this$1.composing.done){this$1.composing=null}else{return}}this$1.updateFromDOM()}),80)};ContentEditableInput.prototype.updateFromDOM=function(){var this$1=this;if(this.cm.isReadOnly()||!this.pollContent()){runInOp(this.cm,(function(){return regChange(this$1.cm)}))}};ContentEditableInput.prototype.setUneditable=function(node){node.contentEditable="false"};ContentEditableInput.prototype.onKeyPress=function(e){if(e.charCode==0||this.composing){return}e.preventDefault();if(!this.cm.isReadOnly()){operation(this.cm,applyTextInput)(this.cm,String.fromCharCode(e.charCode==null?e.keyCode:e.charCode),0)}};ContentEditableInput.prototype.readOnlyChanged=function(val){this.div.contentEditable=String(val!="nocursor")};ContentEditableInput.prototype.onContextMenu=function(){};ContentEditableInput.prototype.resetPosition=function(){};ContentEditableInput.prototype.needsContentAttribute=true;function posToDOM(cm,pos){var view=findViewForLine(cm,pos.line);if(!view||view.hidden){return null}var line=getLine(cm.doc,pos.line);var info=mapFromLineView(view,line,pos.line);var order=getOrder(line,cm.doc.direction),side="left";if(order){var partPos=getBidiPartAt(order,pos.ch);side=partPos%2?"right":"left"}var result=nodeAndOffsetInLineMap(info.map,pos.ch,side);result.offset=result.collapse=="right"?result.end:result.start;return result}function isInGutter(node){for(var scan=node;scan;scan=scan.parentNode){if(/CodeMirror-gutter-wrapper/.test(scan.className)){return true}}return false}function badPos(pos,bad){if(bad){pos.bad=true}return pos}function domTextBetween(cm,from,to,fromLine,toLine){var text="",closing=false,lineSep=cm.doc.lineSeparator(),extraLinebreak=false;function recognizeMarker(id){return function(marker){return marker.id==id}}function close(){if(closing){text+=lineSep;if(extraLinebreak){text+=lineSep}closing=extraLinebreak=false}}function addText(str){if(str){close();text+=str}}function walk(node){if(node.nodeType==1){var cmText=node.getAttribute("cm-text");if(cmText){addText(cmText);return}var markerID=node.getAttribute("cm-marker"),range;if(markerID){var found=cm.findMarks(Pos(fromLine,0),Pos(toLine+1,0),recognizeMarker(+markerID));if(found.length&&(range=found[0].find(0))){addText(getBetween(cm.doc,range.from,range.to).join(lineSep))}return}if(node.getAttribute("contenteditable")=="false"){return}var isBlock=/^(pre|div|p|li|table|br)$/i.test(node.nodeName);if(!/^br$/i.test(node.nodeName)&&node.textContent.length==0){return}if(isBlock){close()}for(var i=0;i<node.childNodes.length;i++){walk(node.childNodes[i])}if(/^(pre|p)$/i.test(node.nodeName)){extraLinebreak=true}if(isBlock){closing=true}}else if(node.nodeType==3){addText(node.nodeValue.replace(/\u200b/g,"").replace(/\u00a0/g," "))}}for(;;){walk(from);if(from==to){break}from=from.nextSibling;extraLinebreak=false}return text}function domToPos(cm,node,offset){var lineNode;if(node==cm.display.lineDiv){lineNode=cm.display.lineDiv.childNodes[offset];if(!lineNode){return badPos(cm.clipPos(Pos(cm.display.viewTo-1)),true)}node=null;offset=0}else{for(lineNode=node;;lineNode=lineNode.parentNode){if(!lineNode||lineNode==cm.display.lineDiv){return null}if(lineNode.parentNode&&lineNode.parentNode==cm.display.lineDiv){break}}}for(var i=0;i<cm.display.view.length;i++){var lineView=cm.display.view[i];if(lineView.node==lineNode){return locateNodeInLineView(lineView,node,offset)}}}function locateNodeInLineView(lineView,node,offset){var wrapper=lineView.text.firstChild,bad=false;if(!node||!contains(wrapper,node)){return badPos(Pos(lineNo(lineView.line),0),true)}if(node==wrapper){bad=true;node=wrapper.childNodes[offset];offset=0;if(!node){var line=lineView.rest?lst(lineView.rest):lineView.line;return badPos(Pos(lineNo(line),line.text.length),bad)}}var textNode=node.nodeType==3?node:null,topNode=node;if(!textNode&&node.childNodes.length==1&&node.firstChild.nodeType==3){textNode=node.firstChild;if(offset){offset=textNode.nodeValue.length}}while(topNode.parentNode!=wrapper){topNode=topNode.parentNode}var measure=lineView.measure,maps=measure.maps;function find(textNode,topNode,offset){for(var i=-1;i<(maps?maps.length:0);i++){var map=i<0?measure.map:maps[i];for(var j=0;j<map.length;j+=3){var curNode=map[j+2];if(curNode==textNode||curNode==topNode){var line=lineNo(i<0?lineView.line:lineView.rest[i]);var ch=map[j]+offset;if(offset<0||curNode!=textNode){ch=map[j+(offset?1:0)]}return Pos(line,ch)}}}}var found=find(textNode,topNode,offset);if(found){return badPos(found,bad)}for(var after=topNode.nextSibling,dist=textNode?textNode.nodeValue.length-offset:0;after;after=after.nextSibling){found=find(after,after.firstChild,0);if(found){return badPos(Pos(found.line,found.ch-dist),bad)}else{dist+=after.textContent.length}}for(var before=topNode.previousSibling,dist$1=offset;before;before=before.previousSibling){found=find(before,before.firstChild,-1);if(found){return badPos(Pos(found.line,found.ch+dist$1),bad)}else{dist$1+=before.textContent.length}}}var TextareaInput=function(cm){this.cm=cm;this.prevInput="";this.pollingFast=false;this.polling=new Delayed;this.hasSelection=false;this.composing=null;this.resetting=false};TextareaInput.prototype.init=function(display){var this$1=this;var input=this,cm=this.cm;this.createField(display);var te=this.textarea;display.wrapper.insertBefore(this.wrapper,display.wrapper.firstChild);if(ios){te.style.width="0px"}on(te,"input",(function(){if(ie&&ie_version>=9&&this$1.hasSelection){this$1.hasSelection=null}input.poll()}));on(te,"paste",(function(e){if(signalDOMEvent(cm,e)||handlePaste(e,cm)){return}cm.state.pasteIncoming=+new Date;input.fastPoll()}));function prepareCopyCut(e){if(signalDOMEvent(cm,e)){return}if(cm.somethingSelected()){setLastCopied({lineWise:false,text:cm.getSelections()})}else if(!cm.options.lineWiseCopyCut){return}else{var ranges=copyableRanges(cm);setLastCopied({lineWise:true,text:ranges.text});if(e.type=="cut"){cm.setSelections(ranges.ranges,null,sel_dontScroll)}else{input.prevInput="";te.value=ranges.text.join("\n");selectInput(te)}}if(e.type=="cut"){cm.state.cutIncoming=+new Date}}on(te,"cut",prepareCopyCut);on(te,"copy",prepareCopyCut);on(display.scroller,"paste",(function(e){if(eventInWidget(display,e)||signalDOMEvent(cm,e)){return}if(!te.dispatchEvent){cm.state.pasteIncoming=+new Date;input.focus();return}var event=new Event("paste");event.clipboardData=e.clipboardData;te.dispatchEvent(event)}));on(display.lineSpace,"selectstart",(function(e){if(!eventInWidget(display,e)){e_preventDefault(e)}}));on(te,"compositionstart",(function(){var start=cm.getCursor("from");if(input.composing){input.composing.range.clear()}input.composing={start:start,range:cm.markText(start,cm.getCursor("to"),{className:"CodeMirror-composing"})}}));on(te,"compositionend",(function(){if(input.composing){input.poll();input.composing.range.clear();input.composing=null}}))};TextareaInput.prototype.createField=function(_display){this.wrapper=hiddenTextarea();this.textarea=this.wrapper.firstChild;var opts=this.cm.options;disableBrowserMagic(this.textarea,opts.spellcheck,opts.autocorrect,opts.autocapitalize)};TextareaInput.prototype.screenReaderLabelChanged=function(label){if(label){this.textarea.setAttribute("aria-label",label)}else{this.textarea.removeAttribute("aria-label")}};TextareaInput.prototype.prepareSelection=function(){var cm=this.cm,display=cm.display,doc=cm.doc;var result=prepareSelection(cm);if(cm.options.moveInputWithCursor){var headPos=cursorCoords(cm,doc.sel.primary().head,"div");var wrapOff=display.wrapper.getBoundingClientRect(),lineOff=display.lineDiv.getBoundingClientRect();result.teTop=Math.max(0,Math.min(display.wrapper.clientHeight-10,headPos.top+lineOff.top-wrapOff.top));result.teLeft=Math.max(0,Math.min(display.wrapper.clientWidth-10,headPos.left+lineOff.left-wrapOff.left))}return result};TextareaInput.prototype.showSelection=function(drawn){var cm=this.cm,display=cm.display;removeChildrenAndAdd(display.cursorDiv,drawn.cursors);removeChildrenAndAdd(display.selectionDiv,drawn.selection);if(drawn.teTop!=null){this.wrapper.style.top=drawn.teTop+"px";this.wrapper.style.left=drawn.teLeft+"px"}};TextareaInput.prototype.reset=function(typing){if(this.contextMenuPending||this.composing&&typing){return}var cm=this.cm;this.resetting=true;if(cm.somethingSelected()){this.prevInput="";var content=cm.getSelection();this.textarea.value=content;if(cm.state.focused){selectInput(this.textarea)}if(ie&&ie_version>=9){this.hasSelection=content}}else if(!typing){this.prevInput=this.textarea.value="";if(ie&&ie_version>=9){this.hasSelection=null}}this.resetting=false};TextareaInput.prototype.getField=function(){return this.textarea};TextareaInput.prototype.supportsTouch=function(){return false};TextareaInput.prototype.focus=function(){if(this.cm.options.readOnly!="nocursor"&&(!mobile||activeElt(this.textarea.ownerDocument)!=this.textarea)){try{this.textarea.focus()}catch(e){}}};TextareaInput.prototype.blur=function(){this.textarea.blur()};TextareaInput.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0};TextareaInput.prototype.receivedFocus=function(){this.slowPoll()};TextareaInput.prototype.slowPoll=function(){var this$1=this;if(this.pollingFast){return}this.polling.set(this.cm.options.pollInterval,(function(){this$1.poll();if(this$1.cm.state.focused){this$1.slowPoll()}}))};TextareaInput.prototype.fastPoll=function(){var missed=false,input=this;input.pollingFast=true;function p(){var changed=input.poll();if(!changed&&!missed){missed=true;input.polling.set(60,p)}else{input.pollingFast=false;input.slowPoll()}}input.polling.set(20,p)};TextareaInput.prototype.poll=function(){var this$1=this;var cm=this.cm,input=this.textarea,prevInput=this.prevInput;if(this.contextMenuPending||this.resetting||!cm.state.focused||hasSelection(input)&&!prevInput&&!this.composing||cm.isReadOnly()||cm.options.disableInput||cm.state.keySeq){return false}var text=input.value;if(text==prevInput&&!cm.somethingSelected()){return false}if(ie&&ie_version>=9&&this.hasSelection===text||mac&&/[\uf700-\uf7ff]/.test(text)){cm.display.input.reset();return false}if(cm.doc.sel==cm.display.selForContextMenu){var first=text.charCodeAt(0);if(first==8203&&!prevInput){prevInput="​"}if(first==8666){this.reset();return this.cm.execCommand("undo")}}var same=0,l=Math.min(prevInput.length,text.length);while(same<l&&prevInput.charCodeAt(same)==text.charCodeAt(same)){++same}runInOp(cm,(function(){applyTextInput(cm,text.slice(same),prevInput.length-same,null,this$1.composing?"*compose":null);if(text.length>1e3||text.indexOf("\n")>-1){input.value=this$1.prevInput=""}else{this$1.prevInput=text}if(this$1.composing){this$1.composing.range.clear();this$1.composing.range=cm.markText(this$1.composing.start,cm.getCursor("to"),{className:"CodeMirror-composing"})}}));return true};TextareaInput.prototype.ensurePolled=function(){if(this.pollingFast&&this.poll()){this.pollingFast=false}};TextareaInput.prototype.onKeyPress=function(){if(ie&&ie_version>=9){this.hasSelection=null}this.fastPoll()};TextareaInput.prototype.onContextMenu=function(e){var input=this,cm=input.cm,display=cm.display,te=input.textarea;if(input.contextMenuPending){input.contextMenuPending()}var pos=posFromMouse(cm,e),scrollPos=display.scroller.scrollTop;if(!pos||presto){return}var reset=cm.options.resetSelectionOnContextMenu;if(reset&&cm.doc.sel.contains(pos)==-1){operation(cm,setSelection)(cm.doc,simpleSelection(pos),sel_dontScroll)}var oldCSS=te.style.cssText,oldWrapperCSS=input.wrapper.style.cssText;var wrapperBox=input.wrapper.offsetParent.getBoundingClientRect();input.wrapper.style.cssText="position: static";te.style.cssText="position: absolute; width: 30px; height: 30px;\n      top: "+(e.clientY-wrapperBox.top-5)+"px; left: "+(e.clientX-wrapperBox.left-5)+"px;\n      z-index: 1000; background: "+(ie?"rgba(255, 255, 255, .05)":"transparent")+";\n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";var oldScrollY;if(webkit){oldScrollY=te.ownerDocument.defaultView.scrollY}display.input.focus();if(webkit){te.ownerDocument.defaultView.scrollTo(null,oldScrollY)}display.input.reset();if(!cm.somethingSelected()){te.value=input.prevInput=" "}input.contextMenuPending=rehide;display.selForContextMenu=cm.doc.sel;clearTimeout(display.detectingSelectAll);function prepareSelectAllHack(){if(te.selectionStart!=null){var selected=cm.somethingSelected();var extval="​"+(selected?te.value:"");te.value="⇚";te.value=extval;input.prevInput=selected?"":"​";te.selectionStart=1;te.selectionEnd=extval.length;display.selForContextMenu=cm.doc.sel}}function rehide(){if(input.contextMenuPending!=rehide){return}input.contextMenuPending=false;input.wrapper.style.cssText=oldWrapperCSS;te.style.cssText=oldCSS;if(ie&&ie_version<9){display.scrollbars.setScrollTop(display.scroller.scrollTop=scrollPos)}if(te.selectionStart!=null){if(!ie||ie&&ie_version<9){prepareSelectAllHack()}var i=0,poll=function(){if(display.selForContextMenu==cm.doc.sel&&te.selectionStart==0&&te.selectionEnd>0&&input.prevInput=="​"){operation(cm,selectAll)(cm)}else if(i++<10){display.detectingSelectAll=setTimeout(poll,500)}else{display.selForContextMenu=null;display.input.reset()}};display.detectingSelectAll=setTimeout(poll,200)}}if(ie&&ie_version>=9){prepareSelectAllHack()}if(captureRightClick){e_stop(e);var mouseup=function(){off(window,"mouseup",mouseup);setTimeout(rehide,20)};on(window,"mouseup",mouseup)}else{setTimeout(rehide,50)}};TextareaInput.prototype.readOnlyChanged=function(val){if(!val){this.reset()}this.textarea.disabled=val=="nocursor";this.textarea.readOnly=!!val};TextareaInput.prototype.setUneditable=function(){};TextareaInput.prototype.needsContentAttribute=false;function fromTextArea(textarea,options){options=options?copyObj(options):{};options.value=textarea.value;if(!options.tabindex&&textarea.tabIndex){options.tabindex=textarea.tabIndex}if(!options.placeholder&&textarea.placeholder){options.placeholder=textarea.placeholder}if(options.autofocus==null){var hasFocus=activeElt(textarea.ownerDocument);options.autofocus=hasFocus==textarea||textarea.getAttribute("autofocus")!=null&&hasFocus==document.body}function save(){textarea.value=cm.getValue()}var realSubmit;if(textarea.form){on(textarea.form,"submit",save);if(!options.leaveSubmitMethodAlone){var form=textarea.form;realSubmit=form.submit;try{var wrappedSubmit=form.submit=function(){save();form.submit=realSubmit;form.submit();form.submit=wrappedSubmit}}catch(e){}}}options.finishInit=function(cm){cm.save=save;cm.getTextArea=function(){return textarea};cm.toTextArea=function(){cm.toTextArea=isNaN;save();textarea.parentNode.removeChild(cm.getWrapperElement());textarea.style.display="";if(textarea.form){off(textarea.form,"submit",save);if(!options.leaveSubmitMethodAlone&&typeof textarea.form.submit=="function"){textarea.form.submit=realSubmit}}}};textarea.style.display="none";var cm=CodeMirror((function(node){return textarea.parentNode.insertBefore(node,textarea.nextSibling)}),options);return cm}function addLegacyProps(CodeMirror){CodeMirror.off=off;CodeMirror.on=on;CodeMirror.wheelEventPixels=wheelEventPixels;CodeMirror.Doc=Doc;CodeMirror.splitLines=splitLinesAuto;CodeMirror.countColumn=countColumn;CodeMirror.findColumn=findColumn;CodeMirror.isWordChar=isWordCharBasic;CodeMirror.Pass=Pass;CodeMirror.signal=signal;CodeMirror.Line=Line;CodeMirror.changeEnd=changeEnd;CodeMirror.scrollbarModel=scrollbarModel;CodeMirror.Pos=Pos;CodeMirror.cmpPos=cmp;CodeMirror.modes=modes;CodeMirror.mimeModes=mimeModes;CodeMirror.resolveMode=resolveMode;CodeMirror.getMode=getMode;CodeMirror.modeExtensions=modeExtensions;CodeMirror.extendMode=extendMode;CodeMirror.copyState=copyState;CodeMirror.startState=startState;CodeMirror.innerMode=innerMode;CodeMirror.commands=commands;CodeMirror.keyMap=keyMap;CodeMirror.keyName=keyName;CodeMirror.isModifierKey=isModifierKey;CodeMirror.lookupKey=lookupKey;CodeMirror.normalizeKeyMap=normalizeKeyMap;CodeMirror.StringStream=StringStream;CodeMirror.SharedTextMarker=SharedTextMarker;CodeMirror.TextMarker=TextMarker;CodeMirror.LineWidget=LineWidget;CodeMirror.e_preventDefault=e_preventDefault;CodeMirror.e_stopPropagation=e_stopPropagation;CodeMirror.e_stop=e_stop;CodeMirror.addClass=addClass;CodeMirror.contains=contains;CodeMirror.rmClass=rmClass;CodeMirror.keyNames=keyNames}defineOptions(CodeMirror);addEditorMethods(CodeMirror);var dontDelegate="iter insert remove copy getEditor constructor".split(" ");for(var prop in Doc.prototype){if(Doc.prototype.hasOwnProperty(prop)&&indexOf(dontDelegate,prop)<0){CodeMirror.prototype[prop]=function(method){return function(){return method.apply(this.doc,arguments)}}(Doc.prototype[prop])}}eventMixin(Doc);CodeMirror.inputStyles={textarea:TextareaInput,contenteditable:ContentEditableInput};CodeMirror.defineMode=function(name){if(!CodeMirror.defaults.mode&&name!="null"){CodeMirror.defaults.mode=name}defineMode.apply(this,arguments)};CodeMirror.defineMIME=defineMIME;CodeMirror.defineMode("null",(function(){return{token:function(stream){return stream.skipToEnd()}}}));CodeMirror.defineMIME("text/plain","null");CodeMirror.defineExtension=function(name,func){CodeMirror.prototype[name]=func};CodeMirror.defineDocExtension=function(name,func){Doc.prototype[name]=func};CodeMirror.fromTextArea=fromTextArea;addLegacyProps(CodeMirror);CodeMirror.version="5.65.15";return CodeMirror}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../lib/codemirror"),require("../addon/search/searchcursor"),require("../addon/edit/matchbrackets"));else if(typeof define=="function"&&define.amd)define(["../lib/codemirror","../addon/search/searchcursor","../addon/edit/matchbrackets"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var cmds=CodeMirror.commands;var Pos=CodeMirror.Pos;function findPosSubword(doc,start,dir){if(dir<0&&start.ch==0)return doc.clipPos(Pos(start.line-1));var line=doc.getLine(start.line);if(dir>0&&start.ch>=line.length)return doc.clipPos(Pos(start.line+1,0));var state="start",type,startPos=start.ch;for(var pos=startPos,e=dir<0?0:line.length,i=0;pos!=e;pos+=dir,i++){var next=line.charAt(dir<0?pos-1:pos);var cat=next!="_"&&CodeMirror.isWordChar(next)?"w":"o";if(cat=="w"&&next.toUpperCase()==next)cat="W";if(state=="start"){if(cat!="o"){state="in";type=cat}else startPos=pos+dir}else if(state=="in"){if(type!=cat){if(type=="w"&&cat=="W"&&dir<0)pos--;if(type=="W"&&cat=="w"&&dir>0){if(pos==startPos+1){type="w";continue}else pos--}break}}}return Pos(start.line,pos)}function moveSubword(cm,dir){cm.extendSelectionsBy((function(range){if(cm.display.shift||cm.doc.extend||range.empty())return findPosSubword(cm.doc,range.head,dir);else return dir<0?range.from():range.to()}))}cmds.goSubwordLeft=function(cm){moveSubword(cm,-1)};cmds.goSubwordRight=function(cm){moveSubword(cm,1)};cmds.scrollLineUp=function(cm){var info=cm.getScrollInfo();if(!cm.somethingSelected()){var visibleBottomLine=cm.lineAtHeight(info.top+info.clientHeight,"local");if(cm.getCursor().line>=visibleBottomLine)cm.execCommand("goLineUp")}cm.scrollTo(null,info.top-cm.defaultTextHeight())};cmds.scrollLineDown=function(cm){var info=cm.getScrollInfo();if(!cm.somethingSelected()){var visibleTopLine=cm.lineAtHeight(info.top,"local")+1;if(cm.getCursor().line<=visibleTopLine)cm.execCommand("goLineDown")}cm.scrollTo(null,info.top+cm.defaultTextHeight())};cmds.splitSelectionByLine=function(cm){var ranges=cm.listSelections(),lineRanges=[];for(var i=0;i<ranges.length;i++){var from=ranges[i].from(),to=ranges[i].to();for(var line=from.line;line<=to.line;++line)if(!(to.line>from.line&&line==to.line&&to.ch==0))lineRanges.push({anchor:line==from.line?from:Pos(line,0),head:line==to.line?to:Pos(line)})}cm.setSelections(lineRanges,0)};cmds.singleSelectionTop=function(cm){var range=cm.listSelections()[0];cm.setSelection(range.anchor,range.head,{scroll:false})};cmds.selectLine=function(cm){var ranges=cm.listSelections(),extended=[];for(var i=0;i<ranges.length;i++){var range=ranges[i];extended.push({anchor:Pos(range.from().line,0),head:Pos(range.to().line+1,0)})}cm.setSelections(extended)};function insertLine(cm,above){if(cm.isReadOnly())return CodeMirror.Pass;cm.operation((function(){var len=cm.listSelections().length,newSelection=[],last=-1;for(var i=0;i<len;i++){var head=cm.listSelections()[i].head;if(head.line<=last)continue;var at=Pos(head.line+(above?0:1),0);cm.replaceRange("\n",at,null,"+insertLine");cm.indentLine(at.line,null,true);newSelection.push({head:at,anchor:at});last=head.line+1}cm.setSelections(newSelection)}));cm.execCommand("indentAuto")}cmds.insertLineAfter=function(cm){return insertLine(cm,false)};cmds.insertLineBefore=function(cm){return insertLine(cm,true)};function wordAt(cm,pos){var start=pos.ch,end=start,line=cm.getLine(pos.line);while(start&&CodeMirror.isWordChar(line.charAt(start-1)))--start;while(end<line.length&&CodeMirror.isWordChar(line.charAt(end)))++end;return{from:Pos(pos.line,start),to:Pos(pos.line,end),word:line.slice(start,end)}}cmds.selectNextOccurrence=function(cm){var from=cm.getCursor("from"),to=cm.getCursor("to");var fullWord=cm.state.sublimeFindFullWord==cm.doc.sel;if(CodeMirror.cmpPos(from,to)==0){var word=wordAt(cm,from);if(!word.word)return;cm.setSelection(word.from,word.to);fullWord=true}else{var text=cm.getRange(from,to);var query=fullWord?new RegExp("\\b"+text+"\\b"):text;var cur=cm.getSearchCursor(query,to);var found=cur.findNext();if(!found){cur=cm.getSearchCursor(query,Pos(cm.firstLine(),0));found=cur.findNext()}if(!found||isSelectedRange(cm.listSelections(),cur.from(),cur.to()))return;cm.addSelection(cur.from(),cur.to())}if(fullWord)cm.state.sublimeFindFullWord=cm.doc.sel};cmds.skipAndSelectNextOccurrence=function(cm){var prevAnchor=cm.getCursor("anchor"),prevHead=cm.getCursor("head");cmds.selectNextOccurrence(cm);if(CodeMirror.cmpPos(prevAnchor,prevHead)!=0){cm.doc.setSelections(cm.doc.listSelections().filter((function(sel){return sel.anchor!=prevAnchor||sel.head!=prevHead})))}};function addCursorToSelection(cm,dir){var ranges=cm.listSelections(),newRanges=[];for(var i=0;i<ranges.length;i++){var range=ranges[i];var newAnchor=cm.findPosV(range.anchor,dir,"line",range.anchor.goalColumn);var newHead=cm.findPosV(range.head,dir,"line",range.head.goalColumn);newAnchor.goalColumn=range.anchor.goalColumn!=null?range.anchor.goalColumn:cm.cursorCoords(range.anchor,"div").left;newHead.goalColumn=range.head.goalColumn!=null?range.head.goalColumn:cm.cursorCoords(range.head,"div").left;var newRange={anchor:newAnchor,head:newHead};newRanges.push(range);newRanges.push(newRange)}cm.setSelections(newRanges)}cmds.addCursorToPrevLine=function(cm){addCursorToSelection(cm,-1)};cmds.addCursorToNextLine=function(cm){addCursorToSelection(cm,1)};function isSelectedRange(ranges,from,to){for(var i=0;i<ranges.length;i++)if(CodeMirror.cmpPos(ranges[i].from(),from)==0&&CodeMirror.cmpPos(ranges[i].to(),to)==0)return true;return false}var mirror="(){}[]";function selectBetweenBrackets(cm){var ranges=cm.listSelections(),newRanges=[];for(var i=0;i<ranges.length;i++){var range=ranges[i],pos=range.head,opening=cm.scanForBracket(pos,-1);if(!opening)return false;for(;;){var closing=cm.scanForBracket(pos,1);if(!closing)return false;if(closing.ch==mirror.charAt(mirror.indexOf(opening.ch)+1)){var startPos=Pos(opening.pos.line,opening.pos.ch+1);if(CodeMirror.cmpPos(startPos,range.from())==0&&CodeMirror.cmpPos(closing.pos,range.to())==0){opening=cm.scanForBracket(opening.pos,-1);if(!opening)return false}else{newRanges.push({anchor:startPos,head:closing.pos});break}}pos=Pos(closing.pos.line,closing.pos.ch+1)}}cm.setSelections(newRanges);return true}cmds.selectScope=function(cm){selectBetweenBrackets(cm)||cm.execCommand("selectAll")};cmds.selectBetweenBrackets=function(cm){if(!selectBetweenBrackets(cm))return CodeMirror.Pass};function puncType(type){return!type?null:/\bpunctuation\b/.test(type)?type:undefined}cmds.goToBracket=function(cm){cm.extendSelectionsBy((function(range){var next=cm.scanForBracket(range.head,1,puncType(cm.getTokenTypeAt(range.head)));if(next&&CodeMirror.cmpPos(next.pos,range.head)!=0)return next.pos;var prev=cm.scanForBracket(range.head,-1,puncType(cm.getTokenTypeAt(Pos(range.head.line,range.head.ch+1))));return prev&&Pos(prev.pos.line,prev.pos.ch+1)||range.head}))};cmds.swapLineUp=function(cm){if(cm.isReadOnly())return CodeMirror.Pass;var ranges=cm.listSelections(),linesToMove=[],at=cm.firstLine()-1,newSels=[];for(var i=0;i<ranges.length;i++){var range=ranges[i],from=range.from().line-1,to=range.to().line;newSels.push({anchor:Pos(range.anchor.line-1,range.anchor.ch),head:Pos(range.head.line-1,range.head.ch)});if(range.to().ch==0&&!range.empty())--to;if(from>at)linesToMove.push(from,to);else if(linesToMove.length)linesToMove[linesToMove.length-1]=to;at=to}cm.operation((function(){for(var i=0;i<linesToMove.length;i+=2){var from=linesToMove[i],to=linesToMove[i+1];var line=cm.getLine(from);cm.replaceRange("",Pos(from,0),Pos(from+1,0),"+swapLine");if(to>cm.lastLine())cm.replaceRange("\n"+line,Pos(cm.lastLine()),null,"+swapLine");else cm.replaceRange(line+"\n",Pos(to,0),null,"+swapLine")}cm.setSelections(newSels);cm.scrollIntoView()}))};cmds.swapLineDown=function(cm){if(cm.isReadOnly())return CodeMirror.Pass;var ranges=cm.listSelections(),linesToMove=[],at=cm.lastLine()+1;for(var i=ranges.length-1;i>=0;i--){var range=ranges[i],from=range.to().line+1,to=range.from().line;if(range.to().ch==0&&!range.empty())from--;if(from<at)linesToMove.push(from,to);else if(linesToMove.length)linesToMove[linesToMove.length-1]=to;at=to}cm.operation((function(){for(var i=linesToMove.length-2;i>=0;i-=2){var from=linesToMove[i],to=linesToMove[i+1];var line=cm.getLine(from);if(from==cm.lastLine())cm.replaceRange("",Pos(from-1),Pos(from),"+swapLine");else cm.replaceRange("",Pos(from,0),Pos(from+1,0),"+swapLine");cm.replaceRange(line+"\n",Pos(to,0),null,"+swapLine")}cm.scrollIntoView()}))};cmds.toggleCommentIndented=function(cm){cm.toggleComment({indent:true})};cmds.joinLines=function(cm){var ranges=cm.listSelections(),joined=[];for(var i=0;i<ranges.length;i++){var range=ranges[i],from=range.from();var start=from.line,end=range.to().line;while(i<ranges.length-1&&ranges[i+1].from().line==end)end=ranges[++i].to().line;joined.push({start:start,end:end,anchor:!range.empty()&&from})}cm.operation((function(){var offset=0,ranges=[];for(var i=0;i<joined.length;i++){var obj=joined[i];var anchor=obj.anchor&&Pos(obj.anchor.line-offset,obj.anchor.ch),head;for(var line=obj.start;line<=obj.end;line++){var actual=line-offset;if(line==obj.end)head=Pos(actual,cm.getLine(actual).length+1);if(actual<cm.lastLine()){cm.replaceRange(" ",Pos(actual),Pos(actual+1,/^\s*/.exec(cm.getLine(actual+1))[0].length));++offset}}ranges.push({anchor:anchor||head,head:head})}cm.setSelections(ranges,0)}))};cmds.duplicateLine=function(cm){cm.operation((function(){var rangeCount=cm.listSelections().length;for(var i=0;i<rangeCount;i++){var range=cm.listSelections()[i];if(range.empty())cm.replaceRange(cm.getLine(range.head.line)+"\n",Pos(range.head.line,0));else cm.replaceRange(cm.getRange(range.from(),range.to()),range.from())}cm.scrollIntoView()}))};function sortLines(cm,caseSensitive,direction){if(cm.isReadOnly())return CodeMirror.Pass;var ranges=cm.listSelections(),toSort=[],selected;for(var i=0;i<ranges.length;i++){var range=ranges[i];if(range.empty())continue;var from=range.from().line,to=range.to().line;while(i<ranges.length-1&&ranges[i+1].from().line==to)to=ranges[++i].to().line;if(!ranges[i].to().ch)to--;toSort.push(from,to)}if(toSort.length)selected=true;else toSort.push(cm.firstLine(),cm.lastLine());cm.operation((function(){var ranges=[];for(var i=0;i<toSort.length;i+=2){var from=toSort[i],to=toSort[i+1];var start=Pos(from,0),end=Pos(to);var lines=cm.getRange(start,end,false);if(caseSensitive)lines.sort((function(a,b){return a<b?-direction:a==b?0:direction}));else lines.sort((function(a,b){var au=a.toUpperCase(),bu=b.toUpperCase();if(au!=bu){a=au;b=bu}return a<b?-direction:a==b?0:direction}));cm.replaceRange(lines,start,end);if(selected)ranges.push({anchor:start,head:Pos(to+1,0)})}if(selected)cm.setSelections(ranges,0)}))}cmds.sortLines=function(cm){sortLines(cm,true,1)};cmds.reverseSortLines=function(cm){sortLines(cm,true,-1)};cmds.sortLinesInsensitive=function(cm){sortLines(cm,false,1)};cmds.reverseSortLinesInsensitive=function(cm){sortLines(cm,false,-1)};cmds.nextBookmark=function(cm){var marks=cm.state.sublimeBookmarks;if(marks)while(marks.length){var current=marks.shift();var found=current.find();if(found){marks.push(current);return cm.setSelection(found.from,found.to)}}};cmds.prevBookmark=function(cm){var marks=cm.state.sublimeBookmarks;if(marks)while(marks.length){marks.unshift(marks.pop());var found=marks[marks.length-1].find();if(!found)marks.pop();else return cm.setSelection(found.from,found.to)}};cmds.toggleBookmark=function(cm){var ranges=cm.listSelections();var marks=cm.state.sublimeBookmarks||(cm.state.sublimeBookmarks=[]);for(var i=0;i<ranges.length;i++){var from=ranges[i].from(),to=ranges[i].to();var found=ranges[i].empty()?cm.findMarksAt(from):cm.findMarks(from,to);for(var j=0;j<found.length;j++){if(found[j].sublimeBookmark){found[j].clear();for(var k=0;k<marks.length;k++)if(marks[k]==found[j])marks.splice(k--,1);break}}if(j==found.length)marks.push(cm.markText(from,to,{sublimeBookmark:true,clearWhenEmpty:false}))}};cmds.clearBookmarks=function(cm){var marks=cm.state.sublimeBookmarks;if(marks)for(var i=0;i<marks.length;i++)marks[i].clear();marks.length=0};cmds.selectBookmarks=function(cm){var marks=cm.state.sublimeBookmarks,ranges=[];if(marks)for(var i=0;i<marks.length;i++){var found=marks[i].find();if(!found)marks.splice(i--,0);else ranges.push({anchor:found.from,head:found.to})}if(ranges.length)cm.setSelections(ranges,0)};function modifyWordOrSelection(cm,mod){cm.operation((function(){var ranges=cm.listSelections(),indices=[],replacements=[];for(var i=0;i<ranges.length;i++){var range=ranges[i];if(range.empty()){indices.push(i);replacements.push("")}else replacements.push(mod(cm.getRange(range.from(),range.to())))}cm.replaceSelections(replacements,"around","case");for(var i=indices.length-1,at;i>=0;i--){var range=ranges[indices[i]];if(at&&CodeMirror.cmpPos(range.head,at)>0)continue;var word=wordAt(cm,range.head);at=word.from;cm.replaceRange(mod(word.word),word.from,word.to)}}))}cmds.smartBackspace=function(cm){if(cm.somethingSelected())return CodeMirror.Pass;cm.operation((function(){var cursors=cm.listSelections();var indentUnit=cm.getOption("indentUnit");for(var i=cursors.length-1;i>=0;i--){var cursor=cursors[i].head;var toStartOfLine=cm.getRange({line:cursor.line,ch:0},cursor);var column=CodeMirror.countColumn(toStartOfLine,null,cm.getOption("tabSize"));var deletePos=cm.findPosH(cursor,-1,"char",false);if(toStartOfLine&&!/\S/.test(toStartOfLine)&&column%indentUnit==0){var prevIndent=new Pos(cursor.line,CodeMirror.findColumn(toStartOfLine,column-indentUnit,indentUnit));if(prevIndent.ch!=cursor.ch)deletePos=prevIndent}cm.replaceRange("",deletePos,cursor,"+delete")}}))};cmds.delLineRight=function(cm){cm.operation((function(){var ranges=cm.listSelections();for(var i=ranges.length-1;i>=0;i--)cm.replaceRange("",ranges[i].anchor,Pos(ranges[i].to().line),"+delete");cm.scrollIntoView()}))};cmds.upcaseAtCursor=function(cm){modifyWordOrSelection(cm,(function(str){return str.toUpperCase()}))};cmds.downcaseAtCursor=function(cm){modifyWordOrSelection(cm,(function(str){return str.toLowerCase()}))};cmds.setSublimeMark=function(cm){if(cm.state.sublimeMark)cm.state.sublimeMark.clear();cm.state.sublimeMark=cm.setBookmark(cm.getCursor())};cmds.selectToSublimeMark=function(cm){var found=cm.state.sublimeMark&&cm.state.sublimeMark.find();if(found)cm.setSelection(cm.getCursor(),found)};cmds.deleteToSublimeMark=function(cm){var found=cm.state.sublimeMark&&cm.state.sublimeMark.find();if(found){var from=cm.getCursor(),to=found;if(CodeMirror.cmpPos(from,to)>0){var tmp=to;to=from;from=tmp}cm.state.sublimeKilled=cm.getRange(from,to);cm.replaceRange("",from,to)}};cmds.swapWithSublimeMark=function(cm){var found=cm.state.sublimeMark&&cm.state.sublimeMark.find();if(found){cm.state.sublimeMark.clear();cm.state.sublimeMark=cm.setBookmark(cm.getCursor());cm.setCursor(found)}};cmds.sublimeYank=function(cm){if(cm.state.sublimeKilled!=null)cm.replaceSelection(cm.state.sublimeKilled,null,"paste")};cmds.showInCenter=function(cm){var pos=cm.cursorCoords(null,"local");cm.scrollTo(null,(pos.top+pos.bottom)/2-cm.getScrollInfo().clientHeight/2)};function getTarget(cm){var from=cm.getCursor("from"),to=cm.getCursor("to");if(CodeMirror.cmpPos(from,to)==0){var word=wordAt(cm,from);if(!word.word)return;from=word.from;to=word.to}return{from:from,to:to,query:cm.getRange(from,to),word:word}}function findAndGoTo(cm,forward){var target=getTarget(cm);if(!target)return;var query=target.query;var cur=cm.getSearchCursor(query,forward?target.to:target.from);if(forward?cur.findNext():cur.findPrevious()){cm.setSelection(cur.from(),cur.to())}else{cur=cm.getSearchCursor(query,forward?Pos(cm.firstLine(),0):cm.clipPos(Pos(cm.lastLine())));if(forward?cur.findNext():cur.findPrevious())cm.setSelection(cur.from(),cur.to());else if(target.word)cm.setSelection(target.from,target.to)}}cmds.findUnder=function(cm){findAndGoTo(cm,true)};cmds.findUnderPrevious=function(cm){findAndGoTo(cm,false)};cmds.findAllUnder=function(cm){var target=getTarget(cm);if(!target)return;var cur=cm.getSearchCursor(target.query);var matches=[];var primaryIndex=-1;while(cur.findNext()){matches.push({anchor:cur.from(),head:cur.to()});if(cur.from().line<=target.from.line&&cur.from().ch<=target.from.ch)primaryIndex++}cm.setSelections(matches,primaryIndex)};var keyMap=CodeMirror.keyMap;keyMap.macSublime={"Cmd-Left":"goLineStartSmart","Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Ctrl-Alt-Up":"scrollLineUp","Ctrl-Alt-Down":"scrollLineDown","Cmd-L":"selectLine","Shift-Cmd-L":"splitSelectionByLine",Esc:"singleSelectionTop","Cmd-Enter":"insertLineAfter","Shift-Cmd-Enter":"insertLineBefore","Cmd-D":"selectNextOccurrence","Shift-Cmd-Space":"selectScope","Shift-Cmd-M":"selectBetweenBrackets","Cmd-M":"goToBracket","Cmd-Ctrl-Up":"swapLineUp","Cmd-Ctrl-Down":"swapLineDown","Cmd-/":"toggleCommentIndented","Cmd-J":"joinLines","Shift-Cmd-D":"duplicateLine",F5:"sortLines","Shift-F5":"reverseSortLines","Cmd-F5":"sortLinesInsensitive","Shift-Cmd-F5":"reverseSortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Cmd-F2":"toggleBookmark","Shift-Cmd-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Cmd-K Cmd-D":"skipAndSelectNextOccurrence","Cmd-K Cmd-K":"delLineRight","Cmd-K Cmd-U":"upcaseAtCursor","Cmd-K Cmd-L":"downcaseAtCursor","Cmd-K Cmd-Space":"setSublimeMark","Cmd-K Cmd-A":"selectToSublimeMark","Cmd-K Cmd-W":"deleteToSublimeMark","Cmd-K Cmd-X":"swapWithSublimeMark","Cmd-K Cmd-Y":"sublimeYank","Cmd-K Cmd-C":"showInCenter","Cmd-K Cmd-G":"clearBookmarks","Cmd-K Cmd-Backspace":"delLineLeft","Cmd-K Cmd-1":"foldAll","Cmd-K Cmd-0":"unfoldAll","Cmd-K Cmd-J":"unfoldAll","Ctrl-Shift-Up":"addCursorToPrevLine","Ctrl-Shift-Down":"addCursorToNextLine","Cmd-F3":"findUnder","Shift-Cmd-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Cmd-[":"fold","Shift-Cmd-]":"unfold","Cmd-I":"findIncremental","Shift-Cmd-I":"findIncrementalReverse","Cmd-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"macDefault"};CodeMirror.normalizeKeyMap(keyMap.macSublime);keyMap.pcSublime={"Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-T":"transposeChars","Alt-Left":"goSubwordLeft","Alt-Right":"goSubwordRight","Ctrl-Up":"scrollLineUp","Ctrl-Down":"scrollLineDown","Ctrl-L":"selectLine","Shift-Ctrl-L":"splitSelectionByLine",Esc:"singleSelectionTop","Ctrl-Enter":"insertLineAfter","Shift-Ctrl-Enter":"insertLineBefore","Ctrl-D":"selectNextOccurrence","Shift-Ctrl-Space":"selectScope","Shift-Ctrl-M":"selectBetweenBrackets","Ctrl-M":"goToBracket","Shift-Ctrl-Up":"swapLineUp","Shift-Ctrl-Down":"swapLineDown","Ctrl-/":"toggleCommentIndented","Ctrl-J":"joinLines","Shift-Ctrl-D":"duplicateLine",F9:"sortLines","Shift-F9":"reverseSortLines","Ctrl-F9":"sortLinesInsensitive","Shift-Ctrl-F9":"reverseSortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Ctrl-F2":"toggleBookmark","Shift-Ctrl-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Ctrl-K Ctrl-D":"skipAndSelectNextOccurrence","Ctrl-K Ctrl-K":"delLineRight","Ctrl-K Ctrl-U":"upcaseAtCursor","Ctrl-K Ctrl-L":"downcaseAtCursor","Ctrl-K Ctrl-Space":"setSublimeMark","Ctrl-K Ctrl-A":"selectToSublimeMark","Ctrl-K Ctrl-W":"deleteToSublimeMark","Ctrl-K Ctrl-X":"swapWithSublimeMark","Ctrl-K Ctrl-Y":"sublimeYank","Ctrl-K Ctrl-C":"showInCenter","Ctrl-K Ctrl-G":"clearBookmarks","Ctrl-K Ctrl-Backspace":"delLineLeft","Ctrl-K Ctrl-1":"foldAll","Ctrl-K Ctrl-0":"unfoldAll","Ctrl-K Ctrl-J":"unfoldAll","Ctrl-Alt-Up":"addCursorToPrevLine","Ctrl-Alt-Down":"addCursorToNextLine","Ctrl-F3":"findUnder","Shift-Ctrl-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Ctrl-[":"fold","Shift-Ctrl-]":"unfold","Ctrl-I":"findIncremental","Shift-Ctrl-I":"findIncrementalReverse","Ctrl-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"pcDefault"};CodeMirror.normalizeKeyMap(keyMap.pcSublime);var mac=keyMap.default==keyMap.macDefault;keyMap.sublime=mac?keyMap.macSublime:keyMap.pcSublime}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"),require("./searchcursor"),require("../scroll/annotatescrollbar"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror","./searchcursor","../scroll/annotatescrollbar"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineExtension("showMatchesOnScrollbar",(function(query,caseFold,options){if(typeof options=="string")options={className:options};if(!options)options={};return new SearchAnnotation(this,query,caseFold,options)}));function SearchAnnotation(cm,query,caseFold,options){this.cm=cm;this.options=options;var annotateOptions={listenForChanges:false};for(var prop in options)annotateOptions[prop]=options[prop];if(!annotateOptions.className)annotateOptions.className="CodeMirror-search-match";this.annotation=cm.annotateScrollbar(annotateOptions);this.query=query;this.caseFold=caseFold;this.gap={from:cm.firstLine(),to:cm.lastLine()+1};this.matches=[];this.update=null;this.findMatches();this.annotation.update(this.matches);var self=this;cm.on("change",this.changeHandler=function(_cm,change){self.onChange(change)})}var MAX_MATCHES=1e3;SearchAnnotation.prototype.findMatches=function(){if(!this.gap)return;for(var i=0;i<this.matches.length;i++){var match=this.matches[i];if(match.from.line>=this.gap.to)break;if(match.to.line>=this.gap.from)this.matches.splice(i--,1)}var cursor=this.cm.getSearchCursor(this.query,CodeMirror.Pos(this.gap.from,0),{caseFold:this.caseFold,multiline:this.options.multiline});var maxMatches=this.options&&this.options.maxMatches||MAX_MATCHES;while(cursor.findNext()){var match={from:cursor.from(),to:cursor.to()};if(match.from.line>=this.gap.to)break;this.matches.splice(i++,0,match);if(this.matches.length>maxMatches)break}this.gap=null};function offsetLine(line,changeStart,sizeChange){if(line<=changeStart)return line;return Math.max(changeStart,line+sizeChange)}SearchAnnotation.prototype.onChange=function(change){var startLine=change.from.line;var endLine=CodeMirror.changeEnd(change).line;var sizeChange=endLine-change.to.line;if(this.gap){this.gap.from=Math.min(offsetLine(this.gap.from,startLine,sizeChange),change.from.line);this.gap.to=Math.max(offsetLine(this.gap.to,startLine,sizeChange),change.from.line)}else{this.gap={from:change.from.line,to:endLine+1}}if(sizeChange)for(var i=0;i<this.matches.length;i++){var match=this.matches[i];var newFrom=offsetLine(match.from.line,startLine,sizeChange);if(newFrom!=match.from.line)match.from=CodeMirror.Pos(newFrom,match.from.ch);var newTo=offsetLine(match.to.line,startLine,sizeChange);if(newTo!=match.to.line)match.to=CodeMirror.Pos(newTo,match.to.ch)}clearTimeout(this.update);var self=this;this.update=setTimeout((function(){self.updateAfterChange()}),250)};SearchAnnotation.prototype.updateAfterChange=function(){this.findMatches();this.annotation.update(this.matches)};SearchAnnotation.prototype.clear=function(){this.cm.off("change",this.changeHandler);this.annotation.clear()}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"),require("./foldcode"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror","./foldcode"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineOption("foldGutter",false,(function(cm,val,old){if(old&&old!=CodeMirror.Init){cm.clearGutter(cm.state.foldGutter.options.gutter);cm.state.foldGutter=null;cm.off("gutterClick",onGutterClick);cm.off("changes",onChange);cm.off("viewportChange",onViewportChange);cm.off("fold",onFold);cm.off("unfold",onFold);cm.off("swapDoc",onChange);cm.off("optionChange",optionChange)}if(val){cm.state.foldGutter=new State(parseOptions(val));updateInViewport(cm);cm.on("gutterClick",onGutterClick);cm.on("changes",onChange);cm.on("viewportChange",onViewportChange);cm.on("fold",onFold);cm.on("unfold",onFold);cm.on("swapDoc",onChange);cm.on("optionChange",optionChange)}}));var Pos=CodeMirror.Pos;function State(options){this.options=options;this.from=this.to=0}function parseOptions(opts){if(opts===true)opts={};if(opts.gutter==null)opts.gutter="CodeMirror-foldgutter";if(opts.indicatorOpen==null)opts.indicatorOpen="CodeMirror-foldgutter-open";if(opts.indicatorFolded==null)opts.indicatorFolded="CodeMirror-foldgutter-folded";return opts}function isFolded(cm,line){var marks=cm.findMarks(Pos(line,0),Pos(line+1,0));for(var i=0;i<marks.length;++i){if(marks[i].__isFold){var fromPos=marks[i].find(-1);if(fromPos&&fromPos.line===line)return marks[i]}}}function marker(spec){if(typeof spec=="string"){var elt=document.createElement("div");elt.className=spec+" CodeMirror-guttermarker-subtle";return elt}else{return spec.cloneNode(true)}}function updateFoldInfo(cm,from,to){var opts=cm.state.foldGutter.options,cur=from-1;var minSize=cm.foldOption(opts,"minFoldSize");var func=cm.foldOption(opts,"rangeFinder");var clsFolded=typeof opts.indicatorFolded=="string"&&classTest(opts.indicatorFolded);var clsOpen=typeof opts.indicatorOpen=="string"&&classTest(opts.indicatorOpen);cm.eachLine(from,to,(function(line){++cur;var mark=null;var old=line.gutterMarkers;if(old)old=old[opts.gutter];if(isFolded(cm,cur)){if(clsFolded&&old&&clsFolded.test(old.className))return;mark=marker(opts.indicatorFolded)}else{var pos=Pos(cur,0);var range=func&&func(cm,pos);if(range&&range.to.line-range.from.line>=minSize){if(clsOpen&&old&&clsOpen.test(old.className))return;mark=marker(opts.indicatorOpen)}}if(!mark&&!old)return;cm.setGutterMarker(line,opts.gutter,mark)}))}function classTest(cls){return new RegExp("(^|\\s)"+cls+"(?:$|\\s)\\s*")}function updateInViewport(cm){var vp=cm.getViewport(),state=cm.state.foldGutter;if(!state)return;cm.operation((function(){updateFoldInfo(cm,vp.from,vp.to)}));state.from=vp.from;state.to=vp.to}function onGutterClick(cm,line,gutter){var state=cm.state.foldGutter;if(!state)return;var opts=state.options;if(gutter!=opts.gutter)return;var folded=isFolded(cm,line);if(folded)folded.clear();else cm.foldCode(Pos(line,0),opts)}function optionChange(cm,option){if(option=="mode")onChange(cm)}function onChange(cm){var state=cm.state.foldGutter;if(!state)return;var opts=state.options;state.from=state.to=0;clearTimeout(state.changeUpdate);state.changeUpdate=setTimeout((function(){updateInViewport(cm)}),opts.foldOnChangeTimeSpan||600)}function onViewportChange(cm){var state=cm.state.foldGutter;if(!state)return;var opts=state.options;clearTimeout(state.changeUpdate);state.changeUpdate=setTimeout((function(){var vp=cm.getViewport();if(state.from==state.to||vp.from-state.to>20||state.from-vp.to>20){updateInViewport(cm)}else{cm.operation((function(){if(vp.from<state.from){updateFoldInfo(cm,vp.from,state.from);state.from=vp.from}if(vp.to>state.to){updateFoldInfo(cm,state.to,vp.to);state.to=vp.to}}))}}),opts.updateViewportTimeSpan||400)}function onFold(cm,from){var state=cm.state.foldGutter;if(!state)return;var line=from.line;if(line>=state.from&&line<state.to)updateFoldInfo(cm,line,line+1)}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"),require("../dialog/dialog"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror","../dialog/dialog"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineOption("search",{bottom:false});function dialog(cm,text,shortText,deflt,f){if(cm.openDialog)cm.openDialog(text,f,{value:deflt,selectValueOnOpen:true,bottom:cm.options.search.bottom});else f(prompt(shortText,deflt))}function getJumpDialog(cm){return cm.phrase("Jump to line:")+' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">'+cm.phrase("(Use line:column or scroll% syntax)")+"</span>"}function interpretLine(cm,string){var num=Number(string);if(/^[-+]/.test(string))return cm.getCursor().line+num;else return num-1}CodeMirror.commands.jumpToLine=function(cm){var cur=cm.getCursor();dialog(cm,getJumpDialog(cm),cm.phrase("Jump to line:"),cur.line+1+":"+cur.ch,(function(posStr){if(!posStr)return;var match;if(match=/^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)){cm.setCursor(interpretLine(cm,match[1]),Number(match[2]))}else if(match=/^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)){var line=Math.round(cm.lineCount()*Number(match[1])/100);if(/^[-+]/.test(match[1]))line=cur.line+line+1;cm.setCursor(line-1,cur.ch)}else if(match=/^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)){cm.setCursor(interpretLine(cm,match[1]),cur.ch)}}))};CodeMirror.keyMap["default"]["Alt-G"]="jumpToLine"}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var noOptions={};var nonWS=/[^\s\u00a0]/;var Pos=CodeMirror.Pos,cmp=CodeMirror.cmpPos;function firstNonWS(str){var found=str.search(nonWS);return found==-1?0:found}CodeMirror.commands.toggleComment=function(cm){cm.toggleComment()};CodeMirror.defineExtension("toggleComment",(function(options){if(!options)options=noOptions;var cm=this;var minLine=Infinity,ranges=this.listSelections(),mode=null;for(var i=ranges.length-1;i>=0;i--){var from=ranges[i].from(),to=ranges[i].to();if(from.line>=minLine)continue;if(to.line>=minLine)to=Pos(minLine,0);minLine=from.line;if(mode==null){if(cm.uncomment(from,to,options))mode="un";else{cm.lineComment(from,to,options);mode="line"}}else if(mode=="un"){cm.uncomment(from,to,options)}else{cm.lineComment(from,to,options)}}}));function probablyInsideString(cm,pos,line){return/\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line,0)))&&!/^[\'\"\`]/.test(line)}function getMode(cm,pos){var mode=cm.getMode();return mode.useInnerComments===false||!mode.innerMode?mode:cm.getModeAt(pos)}CodeMirror.defineExtension("lineComment",(function(from,to,options){if(!options)options=noOptions;var self=this,mode=getMode(self,from);var firstLine=self.getLine(from.line);if(firstLine==null||probablyInsideString(self,from,firstLine))return;var commentString=options.lineComment||mode.lineComment;if(!commentString){if(options.blockCommentStart||mode.blockCommentStart){options.fullLines=true;self.blockComment(from,to,options)}return}var end=Math.min(to.ch!=0||to.line==from.line?to.line+1:to.line,self.lastLine()+1);var pad=options.padding==null?" ":options.padding;var blankLines=options.commentBlankLines||from.line==to.line;self.operation((function(){if(options.indent){var baseString=null;for(var i=from.line;i<end;++i){var line=self.getLine(i);var whitespace=line.search(nonWS)===-1?line:line.slice(0,firstNonWS(line));if(baseString==null||baseString.length>whitespace.length){baseString=whitespace}}for(var i=from.line;i<end;++i){var line=self.getLine(i),cut=baseString.length;if(!blankLines&&!nonWS.test(line))continue;if(line.slice(0,cut)!=baseString)cut=firstNonWS(line);self.replaceRange(baseString+commentString+pad,Pos(i,0),Pos(i,cut))}}else{for(var i=from.line;i<end;++i){if(blankLines||nonWS.test(self.getLine(i)))self.replaceRange(commentString+pad,Pos(i,0))}}}))}));CodeMirror.defineExtension("blockComment",(function(from,to,options){if(!options)options=noOptions;var self=this,mode=getMode(self,from);var startString=options.blockCommentStart||mode.blockCommentStart;var endString=options.blockCommentEnd||mode.blockCommentEnd;if(!startString||!endString){if((options.lineComment||mode.lineComment)&&options.fullLines!=false)self.lineComment(from,to,options);return}if(/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line,0))))return;var end=Math.min(to.line,self.lastLine());if(end!=from.line&&to.ch==0&&nonWS.test(self.getLine(end)))--end;var pad=options.padding==null?" ":options.padding;if(from.line>end)return;self.operation((function(){if(options.fullLines!=false){var lastLineHasText=nonWS.test(self.getLine(end));self.replaceRange(pad+endString,Pos(end));self.replaceRange(startString+pad,Pos(from.line,0));var lead=options.blockCommentLead||mode.blockCommentLead;if(lead!=null)for(var i=from.line+1;i<=end;++i)if(i!=end||lastLineHasText)self.replaceRange(lead+pad,Pos(i,0))}else{var atCursor=cmp(self.getCursor("to"),to)==0,empty=!self.somethingSelected();self.replaceRange(endString,to);if(atCursor)self.setSelection(empty?to:self.getCursor("from"),to);self.replaceRange(startString,from)}}))}));CodeMirror.defineExtension("uncomment",(function(from,to,options){if(!options)options=noOptions;var self=this,mode=getMode(self,from);var end=Math.min(to.ch!=0||to.line==from.line?to.line:to.line-1,self.lastLine()),start=Math.min(from.line,end);var lineString=options.lineComment||mode.lineComment,lines=[];var pad=options.padding==null?" ":options.padding,didSomething;lineComment:{if(!lineString)break lineComment;for(var i=start;i<=end;++i){var line=self.getLine(i);var found=line.indexOf(lineString);if(found>-1&&!/comment/.test(self.getTokenTypeAt(Pos(i,found+1))))found=-1;if(found==-1&&nonWS.test(line))break lineComment;if(found>-1&&nonWS.test(line.slice(0,found)))break lineComment;lines.push(line)}self.operation((function(){for(var i=start;i<=end;++i){var line=lines[i-start];var pos=line.indexOf(lineString),endPos=pos+lineString.length;if(pos<0)continue;if(line.slice(endPos,endPos+pad.length)==pad)endPos+=pad.length;didSomething=true;self.replaceRange("",Pos(i,pos),Pos(i,endPos))}}));if(didSomething)return true}var startString=options.blockCommentStart||mode.blockCommentStart;var endString=options.blockCommentEnd||mode.blockCommentEnd;if(!startString||!endString)return false;var lead=options.blockCommentLead||mode.blockCommentLead;var startLine=self.getLine(start),open=startLine.indexOf(startString);if(open==-1)return false;var endLine=end==start?startLine:self.getLine(end);var close=endLine.indexOf(endString,end==start?open+startString.length:0);var insideStart=Pos(start,open+1),insideEnd=Pos(end,close+1);if(close==-1||!/comment/.test(self.getTokenTypeAt(insideStart))||!/comment/.test(self.getTokenTypeAt(insideEnd))||self.getRange(insideStart,insideEnd,"\n").indexOf(endString)>-1)return false;var lastStart=startLine.lastIndexOf(startString,from.ch);var firstEnd=lastStart==-1?-1:startLine.slice(0,from.ch).indexOf(endString,lastStart+startString.length);if(lastStart!=-1&&firstEnd!=-1&&firstEnd+endString.length!=from.ch)return false;firstEnd=endLine.indexOf(endString,to.ch);var almostLastStart=endLine.slice(to.ch).lastIndexOf(startString,firstEnd-to.ch);lastStart=firstEnd==-1||almostLastStart==-1?-1:to.ch+almostLastStart;if(firstEnd!=-1&&lastStart!=-1&&lastStart!=to.ch)return false;self.operation((function(){self.replaceRange("",Pos(end,close-(pad&&endLine.slice(close-pad.length,close)==pad?pad.length:0)),Pos(end,close+endString.length));var openEnd=open+startString.length;if(pad&&startLine.slice(openEnd,openEnd+pad.length)==pad)openEnd+=pad.length;self.replaceRange("",Pos(start,open),Pos(start,openEnd));if(lead)for(var i=start+1;i<=end;++i){var line=self.getLine(i),found=line.indexOf(lead);if(found==-1||nonWS.test(line.slice(0,found)))continue;var foundEnd=found+lead.length;if(pad&&line.slice(foundEnd,foundEnd+pad.length)==pad)foundEnd+=pad.length;self.replaceRange("",Pos(i,found),Pos(i,foundEnd))}}));return true}))}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"),require("./matchesonscrollbar"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror","./matchesonscrollbar"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var defaults={style:"matchhighlight",minChars:2,delay:100,wordsOnly:false,annotateScrollbar:false,showToken:false,trim:true};function State(options){this.options={};for(var name in defaults)this.options[name]=(options&&options.hasOwnProperty(name)?options:defaults)[name];this.overlay=this.timeout=null;this.matchesonscroll=null;this.active=false}CodeMirror.defineOption("highlightSelectionMatches",false,(function(cm,val,old){if(old&&old!=CodeMirror.Init){removeOverlay(cm);clearTimeout(cm.state.matchHighlighter.timeout);cm.state.matchHighlighter=null;cm.off("cursorActivity",cursorActivity);cm.off("focus",onFocus)}if(val){var state=cm.state.matchHighlighter=new State(val);if(cm.hasFocus()){state.active=true;highlightMatches(cm)}else{cm.on("focus",onFocus)}cm.on("cursorActivity",cursorActivity)}}));function cursorActivity(cm){var state=cm.state.matchHighlighter;if(state.active||cm.hasFocus())scheduleHighlight(cm,state)}function onFocus(cm){var state=cm.state.matchHighlighter;if(!state.active){state.active=true;scheduleHighlight(cm,state)}}function scheduleHighlight(cm,state){clearTimeout(state.timeout);state.timeout=setTimeout((function(){highlightMatches(cm)}),state.options.delay)}function addOverlay(cm,query,hasBoundary,style){var state=cm.state.matchHighlighter;cm.addOverlay(state.overlay=makeOverlay(query,hasBoundary,style));if(state.options.annotateScrollbar&&cm.showMatchesOnScrollbar){var searchFor=hasBoundary?new RegExp((/\w/.test(query.charAt(0))?"\\b":"")+query.replace(/[\\\[.+*?(){|^$]/g,"\\$&")+(/\w/.test(query.charAt(query.length-1))?"\\b":"")):query;state.matchesonscroll=cm.showMatchesOnScrollbar(searchFor,false,{className:"CodeMirror-selection-highlight-scrollbar"})}}function removeOverlay(cm){var state=cm.state.matchHighlighter;if(state.overlay){cm.removeOverlay(state.overlay);state.overlay=null;if(state.matchesonscroll){state.matchesonscroll.clear();state.matchesonscroll=null}}}function highlightMatches(cm){cm.operation((function(){var state=cm.state.matchHighlighter;removeOverlay(cm);if(!cm.somethingSelected()&&state.options.showToken){var re=state.options.showToken===true?/[\w$]/:state.options.showToken;var cur=cm.getCursor(),line=cm.getLine(cur.line),start=cur.ch,end=start;while(start&&re.test(line.charAt(start-1)))--start;while(end<line.length&&re.test(line.charAt(end)))++end;if(start<end)addOverlay(cm,line.slice(start,end),re,state.options.style);return}var from=cm.getCursor("from"),to=cm.getCursor("to");if(from.line!=to.line)return;if(state.options.wordsOnly&&!isWord(cm,from,to))return;var selection=cm.getRange(from,to);if(state.options.trim)selection=selection.replace(/^\s+|\s+$/g,"");if(selection.length>=state.options.minChars)addOverlay(cm,selection,false,state.options.style)}))}function isWord(cm,from,to){var str=cm.getRange(from,to);if(str.match(/^\w+$/)!==null){if(from.ch>0){var pos={line:from.line,ch:from.ch-1};var chr=cm.getRange(pos,from);if(chr.match(/\W/)===null)return false}if(to.ch<cm.getLine(from.line).length){var pos={line:to.line,ch:to.ch+1};var chr=cm.getRange(to,pos);if(chr.match(/\W/)===null)return false}return true}else return false}function boundariesAround(stream,re){return(!stream.start||!re.test(stream.string.charAt(stream.start-1)))&&(stream.pos==stream.string.length||!re.test(stream.string.charAt(stream.pos)))}function makeOverlay(query,hasBoundary,style){return{token:function(stream){if(stream.match(query)&&(!hasBoundary||boundariesAround(stream,hasBoundary)))return style;stream.next();stream.skipTo(query.charAt(0))||stream.skipToEnd()}}}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){function dialogDiv(cm,template,bottom){var wrap=cm.getWrapperElement();var dialog;dialog=wrap.appendChild(document.createElement("div"));if(bottom)dialog.className="CodeMirror-dialog CodeMirror-dialog-bottom";else dialog.className="CodeMirror-dialog CodeMirror-dialog-top";if(typeof template=="string"){dialog.innerHTML=template}else{dialog.appendChild(template)}CodeMirror.addClass(wrap,"dialog-opened");return dialog}function closeNotification(cm,newVal){if(cm.state.currentNotificationClose)cm.state.currentNotificationClose();cm.state.currentNotificationClose=newVal}CodeMirror.defineExtension("openDialog",(function(template,callback,options){if(!options)options={};closeNotification(this,null);var dialog=dialogDiv(this,template,options.bottom);var closed=false,me=this;function close(newVal){if(typeof newVal=="string"){inp.value=newVal}else{if(closed)return;closed=true;CodeMirror.rmClass(dialog.parentNode,"dialog-opened");dialog.parentNode.removeChild(dialog);me.focus();if(options.onClose)options.onClose(dialog)}}var inp=dialog.getElementsByTagName("input")[0],button;if(inp){inp.focus();if(options.value){inp.value=options.value;if(options.selectValueOnOpen!==false){inp.select()}}if(options.onInput)CodeMirror.on(inp,"input",(function(e){options.onInput(e,inp.value,close)}));if(options.onKeyUp)CodeMirror.on(inp,"keyup",(function(e){options.onKeyUp(e,inp.value,close)}));CodeMirror.on(inp,"keydown",(function(e){if(options&&options.onKeyDown&&options.onKeyDown(e,inp.value,close)){return}if(e.keyCode==27||options.closeOnEnter!==false&&e.keyCode==13){inp.blur();CodeMirror.e_stop(e);close()}if(e.keyCode==13)callback(inp.value,e)}));if(options.closeOnBlur!==false)CodeMirror.on(dialog,"focusout",(function(evt){if(evt.relatedTarget!==null)close()}))}else if(button=dialog.getElementsByTagName("button")[0]){CodeMirror.on(button,"click",(function(){close();me.focus()}));if(options.closeOnBlur!==false)CodeMirror.on(button,"blur",close);button.focus()}return close}));CodeMirror.defineExtension("openConfirm",(function(template,callbacks,options){closeNotification(this,null);var dialog=dialogDiv(this,template,options&&options.bottom);var buttons=dialog.getElementsByTagName("button");var closed=false,me=this,blurring=1;function close(){if(closed)return;closed=true;CodeMirror.rmClass(dialog.parentNode,"dialog-opened");dialog.parentNode.removeChild(dialog);me.focus()}buttons[0].focus();for(var i=0;i<buttons.length;++i){var b=buttons[i];(function(callback){CodeMirror.on(b,"click",(function(e){CodeMirror.e_preventDefault(e);close();if(callback)callback(me)}))})(callbacks[i]);CodeMirror.on(b,"blur",(function(){--blurring;setTimeout((function(){if(blurring<=0)close()}),200)}));CodeMirror.on(b,"focus",(function(){++blurring}))}}));CodeMirror.defineExtension("openNotification",(function(template,options){closeNotification(this,close);var dialog=dialogDiv(this,template,options&&options.bottom);var closed=false,doneTimer;var duration=options&&typeof options.duration!=="undefined"?options.duration:5e3;function close(){if(closed)return;closed=true;clearTimeout(doneTimer);CodeMirror.rmClass(dialog.parentNode,"dialog-opened");dialog.parentNode.removeChild(dialog)}CodeMirror.on(dialog,"click",(function(e){CodeMirror.e_preventDefault(e);close()}));if(duration)doneTimer=setTimeout(close,duration);return close}))}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";function lineIndent(cm,lineNo){var text=cm.getLine(lineNo);var spaceTo=text.search(/\S/);if(spaceTo==-1||/\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo,spaceTo+1))))return-1;return CodeMirror.countColumn(text,null,cm.getOption("tabSize"))}CodeMirror.registerHelper("fold","indent",(function(cm,start){var myIndent=lineIndent(cm,start.line);if(myIndent<0)return;var lastLineInFold=null;for(var i=start.line+1,end=cm.lastLine();i<=end;++i){var indent=lineIndent(cm,i);if(indent==-1){}else if(indent>myIndent){lastLineInFold=i}else{break}}if(lastLineInFold)return{from:CodeMirror.Pos(start.line,cm.getLine(start.line).length),to:CodeMirror.Pos(lastLineInFold,cm.getLine(lastLineInFold).length)}}))}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var Pos=CodeMirror.Pos;function regexpFlags(regexp){var flags=regexp.flags;return flags!=null?flags:(regexp.ignoreCase?"i":"")+(regexp.global?"g":"")+(regexp.multiline?"m":"")}function ensureFlags(regexp,flags){var current=regexpFlags(regexp),target=current;for(var i=0;i<flags.length;i++)if(target.indexOf(flags.charAt(i))==-1)target+=flags.charAt(i);return current==target?regexp:new RegExp(regexp.source,target)}function maybeMultiline(regexp){return/\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)}function searchRegexpForward(doc,regexp,start){regexp=ensureFlags(regexp,"g");for(var line=start.line,ch=start.ch,last=doc.lastLine();line<=last;line++,ch=0){regexp.lastIndex=ch;var string=doc.getLine(line),match=regexp.exec(string);if(match)return{from:Pos(line,match.index),to:Pos(line,match.index+match[0].length),match:match}}}function searchRegexpForwardMultiline(doc,regexp,start){if(!maybeMultiline(regexp))return searchRegexpForward(doc,regexp,start);regexp=ensureFlags(regexp,"gm");var string,chunk=1;for(var line=start.line,last=doc.lastLine();line<=last;){for(var i=0;i<chunk;i++){if(line>last)break;var curLine=doc.getLine(line++);string=string==null?curLine:string+"\n"+curLine}chunk=chunk*2;regexp.lastIndex=start.ch;var match=regexp.exec(string);if(match){var before=string.slice(0,match.index).split("\n"),inside=match[0].split("\n");var startLine=start.line+before.length-1,startCh=before[before.length-1].length;return{from:Pos(startLine,startCh),to:Pos(startLine+inside.length-1,inside.length==1?startCh+inside[0].length:inside[inside.length-1].length),match:match}}}}function lastMatchIn(string,regexp,endMargin){var match,from=0;while(from<=string.length){regexp.lastIndex=from;var newMatch=regexp.exec(string);if(!newMatch)break;var end=newMatch.index+newMatch[0].length;if(end>string.length-endMargin)break;if(!match||end>match.index+match[0].length)match=newMatch;from=newMatch.index+1}return match}function searchRegexpBackward(doc,regexp,start){regexp=ensureFlags(regexp,"g");for(var line=start.line,ch=start.ch,first=doc.firstLine();line>=first;line--,ch=-1){var string=doc.getLine(line);var match=lastMatchIn(string,regexp,ch<0?0:string.length-ch);if(match)return{from:Pos(line,match.index),to:Pos(line,match.index+match[0].length),match:match}}}function searchRegexpBackwardMultiline(doc,regexp,start){if(!maybeMultiline(regexp))return searchRegexpBackward(doc,regexp,start);regexp=ensureFlags(regexp,"gm");var string,chunkSize=1,endMargin=doc.getLine(start.line).length-start.ch;for(var line=start.line,first=doc.firstLine();line>=first;){for(var i=0;i<chunkSize&&line>=first;i++){var curLine=doc.getLine(line--);string=string==null?curLine:curLine+"\n"+string}chunkSize*=2;var match=lastMatchIn(string,regexp,endMargin);if(match){var before=string.slice(0,match.index).split("\n"),inside=match[0].split("\n");var startLine=line+before.length,startCh=before[before.length-1].length;return{from:Pos(startLine,startCh),to:Pos(startLine+inside.length-1,inside.length==1?startCh+inside[0].length:inside[inside.length-1].length),match:match}}}}var doFold,noFold;if(String.prototype.normalize){doFold=function(str){return str.normalize("NFD").toLowerCase()};noFold=function(str){return str.normalize("NFD")}}else{doFold=function(str){return str.toLowerCase()};noFold=function(str){return str}}function adjustPos(orig,folded,pos,foldFunc){if(orig.length==folded.length)return pos;for(var min=0,max=pos+Math.max(0,orig.length-folded.length);;){if(min==max)return min;var mid=min+max>>1;var len=foldFunc(orig.slice(0,mid)).length;if(len==pos)return mid;else if(len>pos)max=mid;else min=mid+1}}function searchStringForward(doc,query,start,caseFold){if(!query.length)return null;var fold=caseFold?doFold:noFold;var lines=fold(query).split(/\r|\n\r?/);search:for(var line=start.line,ch=start.ch,last=doc.lastLine()+1-lines.length;line<=last;line++,ch=0){var orig=doc.getLine(line).slice(ch),string=fold(orig);if(lines.length==1){var found=string.indexOf(lines[0]);if(found==-1)continue search;var start=adjustPos(orig,string,found,fold)+ch;return{from:Pos(line,adjustPos(orig,string,found,fold)+ch),to:Pos(line,adjustPos(orig,string,found+lines[0].length,fold)+ch)}}else{var cutFrom=string.length-lines[0].length;if(string.slice(cutFrom)!=lines[0])continue search;for(var i=1;i<lines.length-1;i++)if(fold(doc.getLine(line+i))!=lines[i])continue search;var end=doc.getLine(line+lines.length-1),endString=fold(end),lastLine=lines[lines.length-1];if(endString.slice(0,lastLine.length)!=lastLine)continue search;return{from:Pos(line,adjustPos(orig,string,cutFrom,fold)+ch),to:Pos(line+lines.length-1,adjustPos(end,endString,lastLine.length,fold))}}}}function searchStringBackward(doc,query,start,caseFold){if(!query.length)return null;var fold=caseFold?doFold:noFold;var lines=fold(query).split(/\r|\n\r?/);search:for(var line=start.line,ch=start.ch,first=doc.firstLine()-1+lines.length;line>=first;line--,ch=-1){var orig=doc.getLine(line);if(ch>-1)orig=orig.slice(0,ch);var string=fold(orig);if(lines.length==1){var found=string.lastIndexOf(lines[0]);if(found==-1)continue search;return{from:Pos(line,adjustPos(orig,string,found,fold)),to:Pos(line,adjustPos(orig,string,found+lines[0].length,fold))}}else{var lastLine=lines[lines.length-1];if(string.slice(0,lastLine.length)!=lastLine)continue search;for(var i=1,start=line-lines.length+1;i<lines.length-1;i++)if(fold(doc.getLine(start+i))!=lines[i])continue search;var top=doc.getLine(line+1-lines.length),topString=fold(top);if(topString.slice(topString.length-lines[0].length)!=lines[0])continue search;return{from:Pos(line+1-lines.length,adjustPos(top,topString,top.length-lines[0].length,fold)),to:Pos(line,adjustPos(orig,string,lastLine.length,fold))}}}}function SearchCursor(doc,query,pos,options){this.atOccurrence=false;this.afterEmptyMatch=false;this.doc=doc;pos=pos?doc.clipPos(pos):Pos(0,0);this.pos={from:pos,to:pos};var caseFold;if(typeof options=="object"){caseFold=options.caseFold}else{caseFold=options;options=null}if(typeof query=="string"){if(caseFold==null)caseFold=false;this.matches=function(reverse,pos){return(reverse?searchStringBackward:searchStringForward)(doc,query,pos,caseFold)}}else{query=ensureFlags(query,"gm");if(!options||options.multiline!==false)this.matches=function(reverse,pos){return(reverse?searchRegexpBackwardMultiline:searchRegexpForwardMultiline)(doc,query,pos)};else this.matches=function(reverse,pos){return(reverse?searchRegexpBackward:searchRegexpForward)(doc,query,pos)}}}SearchCursor.prototype={findNext:function(){return this.find(false)},findPrevious:function(){return this.find(true)},find:function(reverse){var head=this.doc.clipPos(reverse?this.pos.from:this.pos.to);if(this.afterEmptyMatch&&this.atOccurrence){head=Pos(head.line,head.ch);if(reverse){head.ch--;if(head.ch<0){head.line--;head.ch=(this.doc.getLine(head.line)||"").length}}else{head.ch++;if(head.ch>(this.doc.getLine(head.line)||"").length){head.ch=0;head.line++}}if(CodeMirror.cmpPos(head,this.doc.clipPos(head))!=0){return this.atOccurrence=false}}var result=this.matches(reverse,head);this.afterEmptyMatch=result&&CodeMirror.cmpPos(result.from,result.to)==0;if(result){this.pos=result;this.atOccurrence=true;return this.pos.match||true}else{var end=Pos(reverse?this.doc.firstLine():this.doc.lastLine()+1,0);this.pos={from:end,to:end};return this.atOccurrence=false}},from:function(){if(this.atOccurrence)return this.pos.from},to:function(){if(this.atOccurrence)return this.pos.to},replace:function(newText,origin){if(!this.atOccurrence)return;var lines=CodeMirror.splitLines(newText);this.doc.replaceRange(lines,this.pos.from,this.pos.to,origin);this.pos.to=Pos(this.pos.from.line+lines.length-1,lines[lines.length-1].length+(lines.length==1?this.pos.from.ch:0))}};CodeMirror.defineExtension("getSearchCursor",(function(query,pos,caseFold){return new SearchCursor(this.doc,query,pos,caseFold)}));CodeMirror.defineDocExtension("getSearchCursor",(function(query,pos,caseFold){return new SearchCursor(this,query,pos,caseFold)}));CodeMirror.defineExtension("selectMatches",(function(query,caseFold){var ranges=[];var cur=this.getSearchCursor(query,this.getCursor("from"),caseFold);while(cur.findNext()){if(CodeMirror.cmpPos(cur.to(),this.getCursor("to"))>0)break;ranges.push({anchor:cur.from(),head:cur.to()})}if(ranges.length)this.setSelections(ranges,0)}))}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineMode("javascript",(function(config,parserConfig){var indentUnit=config.indentUnit;var statementIndent=parserConfig.statementIndent;var jsonldMode=parserConfig.jsonld;var jsonMode=parserConfig.json||jsonldMode;var trackScope=parserConfig.trackScope!==false;var isTS=parserConfig.typescript;var wordRE=parserConfig.wordCharacters||/[\w$\xa1-\uffff]/;var keywords=function(){function kw(type){return{type:type,style:"keyword"}}var A=kw("keyword a"),B=kw("keyword b"),C=kw("keyword c"),D=kw("keyword d");var operator=kw("operator"),atom={type:"atom",style:"atom"};return{if:kw("if"),while:A,with:A,else:B,do:B,try:B,finally:B,return:D,break:D,continue:D,new:kw("new"),delete:C,void:C,throw:C,debugger:kw("debugger"),var:kw("var"),const:kw("var"),let:kw("var"),function:kw("function"),catch:kw("catch"),for:kw("for"),switch:kw("switch"),case:kw("case"),default:kw("default"),in:operator,typeof:operator,instanceof:operator,true:atom,false:atom,null:atom,undefined:atom,NaN:atom,Infinity:atom,this:kw("this"),class:kw("class"),super:kw("atom"),yield:C,export:kw("export"),import:kw("import"),extends:C,await:C}}();var isOperatorChar=/[+\-*&%=<>!?|~^@]/;var isJsonldKeyword=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function readRegexp(stream){var escaped=false,next,inSet=false;while((next=stream.next())!=null){if(!escaped){if(next=="/"&&!inSet)return;if(next=="[")inSet=true;else if(inSet&&next=="]")inSet=false}escaped=!escaped&&next=="\\"}}var type,content;function ret(tp,style,cont){type=tp;content=cont;return style}function tokenBase(stream,state){var ch=stream.next();if(ch=='"'||ch=="'"){state.tokenize=tokenString(ch);return state.tokenize(stream,state)}else if(ch=="."&&stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)){return ret("number","number")}else if(ch=="."&&stream.match("..")){return ret("spread","meta")}else if(/[\[\]{}\(\),;\:\.]/.test(ch)){return ret(ch)}else if(ch=="="&&stream.eat(">")){return ret("=>","operator")}else if(ch=="0"&&stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)){return ret("number","number")}else if(/\d/.test(ch)){stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/);return ret("number","number")}else if(ch=="/"){if(stream.eat("*")){state.tokenize=tokenComment;return tokenComment(stream,state)}else if(stream.eat("/")){stream.skipToEnd();return ret("comment","comment")}else if(expressionAllowed(stream,state,1)){readRegexp(stream);stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/);return ret("regexp","string-2")}else{stream.eat("=");return ret("operator","operator",stream.current())}}else if(ch=="`"){state.tokenize=tokenQuasi;return tokenQuasi(stream,state)}else if(ch=="#"&&stream.peek()=="!"){stream.skipToEnd();return ret("meta","meta")}else if(ch=="#"&&stream.eatWhile(wordRE)){return ret("variable","property")}else if(ch=="<"&&stream.match("!--")||ch=="-"&&stream.match("->")&&!/\S/.test(stream.string.slice(0,stream.start))){stream.skipToEnd();return ret("comment","comment")}else if(isOperatorChar.test(ch)){if(ch!=">"||!state.lexical||state.lexical.type!=">"){if(stream.eat("=")){if(ch=="!"||ch=="=")stream.eat("=")}else if(/[<>*+\-|&?]/.test(ch)){stream.eat(ch);if(ch==">")stream.eat(ch)}}if(ch=="?"&&stream.eat("."))return ret(".");return ret("operator","operator",stream.current())}else if(wordRE.test(ch)){stream.eatWhile(wordRE);var word=stream.current();if(state.lastType!="."){if(keywords.propertyIsEnumerable(word)){var kw=keywords[word];return ret(kw.type,kw.style,word)}if(word=="async"&&stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,false))return ret("async","keyword",word)}return ret("variable","variable",word)}}function tokenString(quote){return function(stream,state){var escaped=false,next;if(jsonldMode&&stream.peek()=="@"&&stream.match(isJsonldKeyword)){state.tokenize=tokenBase;return ret("jsonld-keyword","meta")}while((next=stream.next())!=null){if(next==quote&&!escaped)break;escaped=!escaped&&next=="\\"}if(!escaped)state.tokenize=tokenBase;return ret("string","string")}}function tokenComment(stream,state){var maybeEnd=false,ch;while(ch=stream.next()){if(ch=="/"&&maybeEnd){state.tokenize=tokenBase;break}maybeEnd=ch=="*"}return ret("comment","comment")}function tokenQuasi(stream,state){var escaped=false,next;while((next=stream.next())!=null){if(!escaped&&(next=="`"||next=="$"&&stream.eat("{"))){state.tokenize=tokenBase;break}escaped=!escaped&&next=="\\"}return ret("quasi","string-2",stream.current())}var brackets="([{}])";function findFatArrow(stream,state){if(state.fatArrowAt)state.fatArrowAt=null;var arrow=stream.string.indexOf("=>",stream.start);if(arrow<0)return;if(isTS){var m=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start,arrow));if(m)arrow=m.index}var depth=0,sawSomething=false;for(var pos=arrow-1;pos>=0;--pos){var ch=stream.string.charAt(pos);var bracket=brackets.indexOf(ch);if(bracket>=0&&bracket<3){if(!depth){++pos;break}if(--depth==0){if(ch=="(")sawSomething=true;break}}else if(bracket>=3&&bracket<6){++depth}else if(wordRE.test(ch)){sawSomething=true}else if(/["'\/`]/.test(ch)){for(;;--pos){if(pos==0)return;var next=stream.string.charAt(pos-1);if(next==ch&&stream.string.charAt(pos-2)!="\\"){pos--;break}}}else if(sawSomething&&!depth){++pos;break}}if(sawSomething&&!depth)state.fatArrowAt=pos}var atomicTypes={atom:true,number:true,variable:true,string:true,regexp:true,this:true,import:true,"jsonld-keyword":true};function JSLexical(indented,column,type,align,prev,info){this.indented=indented;this.column=column;this.type=type;this.prev=prev;this.info=info;if(align!=null)this.align=align}function inScope(state,varname){if(!trackScope)return false;for(var v=state.localVars;v;v=v.next)if(v.name==varname)return true;for(var cx=state.context;cx;cx=cx.prev){for(var v=cx.vars;v;v=v.next)if(v.name==varname)return true}}function parseJS(state,style,type,content,stream){var cc=state.cc;cx.state=state;cx.stream=stream;cx.marked=null,cx.cc=cc;cx.style=style;if(!state.lexical.hasOwnProperty("align"))state.lexical.align=true;while(true){var combinator=cc.length?cc.pop():jsonMode?expression:statement;if(combinator(type,content)){while(cc.length&&cc[cc.length-1].lex)cc.pop()();if(cx.marked)return cx.marked;if(type=="variable"&&inScope(state,content))return"variable-2";return style}}}var cx={state:null,column:null,marked:null,cc:null};function pass(){for(var i=arguments.length-1;i>=0;i--)cx.cc.push(arguments[i])}function cont(){pass.apply(null,arguments);return true}function inList(name,list){for(var v=list;v;v=v.next)if(v.name==name)return true;return false}function register(varname){var state=cx.state;cx.marked="def";if(!trackScope)return;if(state.context){if(state.lexical.info=="var"&&state.context&&state.context.block){var newContext=registerVarScoped(varname,state.context);if(newContext!=null){state.context=newContext;return}}else if(!inList(varname,state.localVars)){state.localVars=new Var(varname,state.localVars);return}}if(parserConfig.globalVars&&!inList(varname,state.globalVars))state.globalVars=new Var(varname,state.globalVars)}function registerVarScoped(varname,context){if(!context){return null}else if(context.block){var inner=registerVarScoped(varname,context.prev);if(!inner)return null;if(inner==context.prev)return context;return new Context(inner,context.vars,true)}else if(inList(varname,context.vars)){return context}else{return new Context(context.prev,new Var(varname,context.vars),false)}}function isModifier(name){return name=="public"||name=="private"||name=="protected"||name=="abstract"||name=="readonly"}function Context(prev,vars,block){this.prev=prev;this.vars=vars;this.block=block}function Var(name,next){this.name=name;this.next=next}var defaultVars=new Var("this",new Var("arguments",null));function pushcontext(){cx.state.context=new Context(cx.state.context,cx.state.localVars,false);cx.state.localVars=defaultVars}function pushblockcontext(){cx.state.context=new Context(cx.state.context,cx.state.localVars,true);cx.state.localVars=null}pushcontext.lex=pushblockcontext.lex=true;function popcontext(){cx.state.localVars=cx.state.context.vars;cx.state.context=cx.state.context.prev}popcontext.lex=true;function pushlex(type,info){var result=function(){var state=cx.state,indent=state.indented;if(state.lexical.type=="stat")indent=state.lexical.indented;else for(var outer=state.lexical;outer&&outer.type==")"&&outer.align;outer=outer.prev)indent=outer.indented;state.lexical=new JSLexical(indent,cx.stream.column(),type,null,state.lexical,info)};result.lex=true;return result}function poplex(){var state=cx.state;if(state.lexical.prev){if(state.lexical.type==")")state.indented=state.lexical.indented;state.lexical=state.lexical.prev}}poplex.lex=true;function expect(wanted){function exp(type){if(type==wanted)return cont();else if(wanted==";"||type=="}"||type==")"||type=="]")return pass();else return cont(exp)}return exp}function statement(type,value){if(type=="var")return cont(pushlex("vardef",value),vardef,expect(";"),poplex);if(type=="keyword a")return cont(pushlex("form"),parenExpr,statement,poplex);if(type=="keyword b")return cont(pushlex("form"),statement,poplex);if(type=="keyword d")return cx.stream.match(/^\s*$/,false)?cont():cont(pushlex("stat"),maybeexpression,expect(";"),poplex);if(type=="debugger")return cont(expect(";"));if(type=="{")return cont(pushlex("}"),pushblockcontext,block,poplex,popcontext);if(type==";")return cont();if(type=="if"){if(cx.state.lexical.info=="else"&&cx.state.cc[cx.state.cc.length-1]==poplex)cx.state.cc.pop()();return cont(pushlex("form"),parenExpr,statement,poplex,maybeelse)}if(type=="function")return cont(functiondef);if(type=="for")return cont(pushlex("form"),pushblockcontext,forspec,statement,popcontext,poplex);if(type=="class"||isTS&&value=="interface"){cx.marked="keyword";return cont(pushlex("form",type=="class"?type:value),className,poplex)}if(type=="variable"){if(isTS&&value=="declare"){cx.marked="keyword";return cont(statement)}else if(isTS&&(value=="module"||value=="enum"||value=="type")&&cx.stream.match(/^\s*\w/,false)){cx.marked="keyword";if(value=="enum")return cont(enumdef);else if(value=="type")return cont(typename,expect("operator"),typeexpr,expect(";"));else return cont(pushlex("form"),pattern,expect("{"),pushlex("}"),block,poplex,poplex)}else if(isTS&&value=="namespace"){cx.marked="keyword";return cont(pushlex("form"),expression,statement,poplex)}else if(isTS&&value=="abstract"){cx.marked="keyword";return cont(statement)}else{return cont(pushlex("stat"),maybelabel)}}if(type=="switch")return cont(pushlex("form"),parenExpr,expect("{"),pushlex("}","switch"),pushblockcontext,block,poplex,poplex,popcontext);if(type=="case")return cont(expression,expect(":"));if(type=="default")return cont(expect(":"));if(type=="catch")return cont(pushlex("form"),pushcontext,maybeCatchBinding,statement,poplex,popcontext);if(type=="export")return cont(pushlex("stat"),afterExport,poplex);if(type=="import")return cont(pushlex("stat"),afterImport,poplex);if(type=="async")return cont(statement);if(value=="@")return cont(expression,statement);return pass(pushlex("stat"),expression,expect(";"),poplex)}function maybeCatchBinding(type){if(type=="(")return cont(funarg,expect(")"))}function expression(type,value){return expressionInner(type,value,false)}function expressionNoComma(type,value){return expressionInner(type,value,true)}function parenExpr(type){if(type!="(")return pass();return cont(pushlex(")"),maybeexpression,expect(")"),poplex)}function expressionInner(type,value,noComma){if(cx.state.fatArrowAt==cx.stream.start){var body=noComma?arrowBodyNoComma:arrowBody;if(type=="(")return cont(pushcontext,pushlex(")"),commasep(funarg,")"),poplex,expect("=>"),body,popcontext);else if(type=="variable")return pass(pushcontext,pattern,expect("=>"),body,popcontext)}var maybeop=noComma?maybeoperatorNoComma:maybeoperatorComma;if(atomicTypes.hasOwnProperty(type))return cont(maybeop);if(type=="function")return cont(functiondef,maybeop);if(type=="class"||isTS&&value=="interface"){cx.marked="keyword";return cont(pushlex("form"),classExpression,poplex)}if(type=="keyword c"||type=="async")return cont(noComma?expressionNoComma:expression);if(type=="(")return cont(pushlex(")"),maybeexpression,expect(")"),poplex,maybeop);if(type=="operator"||type=="spread")return cont(noComma?expressionNoComma:expression);if(type=="[")return cont(pushlex("]"),arrayLiteral,poplex,maybeop);if(type=="{")return contCommasep(objprop,"}",null,maybeop);if(type=="quasi")return pass(quasi,maybeop);if(type=="new")return cont(maybeTarget(noComma));return cont()}function maybeexpression(type){if(type.match(/[;\}\)\],]/))return pass();return pass(expression)}function maybeoperatorComma(type,value){if(type==",")return cont(maybeexpression);return maybeoperatorNoComma(type,value,false)}function maybeoperatorNoComma(type,value,noComma){var me=noComma==false?maybeoperatorComma:maybeoperatorNoComma;var expr=noComma==false?expression:expressionNoComma;if(type=="=>")return cont(pushcontext,noComma?arrowBodyNoComma:arrowBody,popcontext);if(type=="operator"){if(/\+\+|--/.test(value)||isTS&&value=="!")return cont(me);if(isTS&&value=="<"&&cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,false))return cont(pushlex(">"),commasep(typeexpr,">"),poplex,me);if(value=="?")return cont(expression,expect(":"),expr);return cont(expr)}if(type=="quasi"){return pass(quasi,me)}if(type==";")return;if(type=="(")return contCommasep(expressionNoComma,")","call",me);if(type==".")return cont(property,me);if(type=="[")return cont(pushlex("]"),maybeexpression,expect("]"),poplex,me);if(isTS&&value=="as"){cx.marked="keyword";return cont(typeexpr,me)}if(type=="regexp"){cx.state.lastType=cx.marked="operator";cx.stream.backUp(cx.stream.pos-cx.stream.start-1);return cont(expr)}}function quasi(type,value){if(type!="quasi")return pass();if(value.slice(value.length-2)!="${")return cont(quasi);return cont(maybeexpression,continueQuasi)}function continueQuasi(type){if(type=="}"){cx.marked="string-2";cx.state.tokenize=tokenQuasi;return cont(quasi)}}function arrowBody(type){findFatArrow(cx.stream,cx.state);return pass(type=="{"?statement:expression)}function arrowBodyNoComma(type){findFatArrow(cx.stream,cx.state);return pass(type=="{"?statement:expressionNoComma)}function maybeTarget(noComma){return function(type){if(type==".")return cont(noComma?targetNoComma:target);else if(type=="variable"&&isTS)return cont(maybeTypeArgs,noComma?maybeoperatorNoComma:maybeoperatorComma);else return pass(noComma?expressionNoComma:expression)}}function target(_,value){if(value=="target"){cx.marked="keyword";return cont(maybeoperatorComma)}}function targetNoComma(_,value){if(value=="target"){cx.marked="keyword";return cont(maybeoperatorNoComma)}}function maybelabel(type){if(type==":")return cont(poplex,statement);return pass(maybeoperatorComma,expect(";"),poplex)}function property(type){if(type=="variable"){cx.marked="property";return cont()}}function objprop(type,value){if(type=="async"){cx.marked="property";return cont(objprop)}else if(type=="variable"||cx.style=="keyword"){cx.marked="property";if(value=="get"||value=="set")return cont(getterSetter);var m;if(isTS&&cx.state.fatArrowAt==cx.stream.start&&(m=cx.stream.match(/^\s*:\s*/,false)))cx.state.fatArrowAt=cx.stream.pos+m[0].length;return cont(afterprop)}else if(type=="number"||type=="string"){cx.marked=jsonldMode?"property":cx.style+" property";return cont(afterprop)}else if(type=="jsonld-keyword"){return cont(afterprop)}else if(isTS&&isModifier(value)){cx.marked="keyword";return cont(objprop)}else if(type=="["){return cont(expression,maybetype,expect("]"),afterprop)}else if(type=="spread"){return cont(expressionNoComma,afterprop)}else if(value=="*"){cx.marked="keyword";return cont(objprop)}else if(type==":"){return pass(afterprop)}}function getterSetter(type){if(type!="variable")return pass(afterprop);cx.marked="property";return cont(functiondef)}function afterprop(type){if(type==":")return cont(expressionNoComma);if(type=="(")return pass(functiondef)}function commasep(what,end,sep){function proceed(type,value){if(sep?sep.indexOf(type)>-1:type==","){var lex=cx.state.lexical;if(lex.info=="call")lex.pos=(lex.pos||0)+1;return cont((function(type,value){if(type==end||value==end)return pass();return pass(what)}),proceed)}if(type==end||value==end)return cont();if(sep&&sep.indexOf(";")>-1)return pass(what);return cont(expect(end))}return function(type,value){if(type==end||value==end)return cont();return pass(what,proceed)}}function contCommasep(what,end,info){for(var i=3;i<arguments.length;i++)cx.cc.push(arguments[i]);return cont(pushlex(end,info),commasep(what,end),poplex)}function block(type){if(type=="}")return cont();return pass(statement,block)}function maybetype(type,value){if(isTS){if(type==":")return cont(typeexpr);if(value=="?")return cont(maybetype)}}function maybetypeOrIn(type,value){if(isTS&&(type==":"||value=="in"))return cont(typeexpr)}function mayberettype(type){if(isTS&&type==":"){if(cx.stream.match(/^\s*\w+\s+is\b/,false))return cont(expression,isKW,typeexpr);else return cont(typeexpr)}}function isKW(_,value){if(value=="is"){cx.marked="keyword";return cont()}}function typeexpr(type,value){if(value=="keyof"||value=="typeof"||value=="infer"||value=="readonly"){cx.marked="keyword";return cont(value=="typeof"?expressionNoComma:typeexpr)}if(type=="variable"||value=="void"){cx.marked="type";return cont(afterType)}if(value=="|"||value=="&")return cont(typeexpr);if(type=="string"||type=="number"||type=="atom")return cont(afterType);if(type=="[")return cont(pushlex("]"),commasep(typeexpr,"]",","),poplex,afterType);if(type=="{")return cont(pushlex("}"),typeprops,poplex,afterType);if(type=="(")return cont(commasep(typearg,")"),maybeReturnType,afterType);if(type=="<")return cont(commasep(typeexpr,">"),typeexpr);if(type=="quasi"){return pass(quasiType,afterType)}}function maybeReturnType(type){if(type=="=>")return cont(typeexpr)}function typeprops(type){if(type.match(/[\}\)\]]/))return cont();if(type==","||type==";")return cont(typeprops);return pass(typeprop,typeprops)}function typeprop(type,value){if(type=="variable"||cx.style=="keyword"){cx.marked="property";return cont(typeprop)}else if(value=="?"||type=="number"||type=="string"){return cont(typeprop)}else if(type==":"){return cont(typeexpr)}else if(type=="["){return cont(expect("variable"),maybetypeOrIn,expect("]"),typeprop)}else if(type=="("){return pass(functiondecl,typeprop)}else if(!type.match(/[;\}\)\],]/)){return cont()}}function quasiType(type,value){if(type!="quasi")return pass();if(value.slice(value.length-2)!="${")return cont(quasiType);return cont(typeexpr,continueQuasiType)}function continueQuasiType(type){if(type=="}"){cx.marked="string-2";cx.state.tokenize=tokenQuasi;return cont(quasiType)}}function typearg(type,value){if(type=="variable"&&cx.stream.match(/^\s*[?:]/,false)||value=="?")return cont(typearg);if(type==":")return cont(typeexpr);if(type=="spread")return cont(typearg);return pass(typeexpr)}function afterType(type,value){if(value=="<")return cont(pushlex(">"),commasep(typeexpr,">"),poplex,afterType);if(value=="|"||type=="."||value=="&")return cont(typeexpr);if(type=="[")return cont(typeexpr,expect("]"),afterType);if(value=="extends"||value=="implements"){cx.marked="keyword";return cont(typeexpr)}if(value=="?")return cont(typeexpr,expect(":"),typeexpr)}function maybeTypeArgs(_,value){if(value=="<")return cont(pushlex(">"),commasep(typeexpr,">"),poplex,afterType)}function typeparam(){return pass(typeexpr,maybeTypeDefault)}function maybeTypeDefault(_,value){if(value=="=")return cont(typeexpr)}function vardef(_,value){if(value=="enum"){cx.marked="keyword";return cont(enumdef)}return pass(pattern,maybetype,maybeAssign,vardefCont)}function pattern(type,value){if(isTS&&isModifier(value)){cx.marked="keyword";return cont(pattern)}if(type=="variable"){register(value);return cont()}if(type=="spread")return cont(pattern);if(type=="[")return contCommasep(eltpattern,"]");if(type=="{")return contCommasep(proppattern,"}")}function proppattern(type,value){if(type=="variable"&&!cx.stream.match(/^\s*:/,false)){register(value);return cont(maybeAssign)}if(type=="variable")cx.marked="property";if(type=="spread")return cont(pattern);if(type=="}")return pass();if(type=="[")return cont(expression,expect("]"),expect(":"),proppattern);return cont(expect(":"),pattern,maybeAssign)}function eltpattern(){return pass(pattern,maybeAssign)}function maybeAssign(_type,value){if(value=="=")return cont(expressionNoComma)}function vardefCont(type){if(type==",")return cont(vardef)}function maybeelse(type,value){if(type=="keyword b"&&value=="else")return cont(pushlex("form","else"),statement,poplex)}function forspec(type,value){if(value=="await")return cont(forspec);if(type=="(")return cont(pushlex(")"),forspec1,poplex)}function forspec1(type){if(type=="var")return cont(vardef,forspec2);if(type=="variable")return cont(forspec2);return pass(forspec2)}function forspec2(type,value){if(type==")")return cont();if(type==";")return cont(forspec2);if(value=="in"||value=="of"){cx.marked="keyword";return cont(expression,forspec2)}return pass(expression,forspec2)}function functiondef(type,value){if(value=="*"){cx.marked="keyword";return cont(functiondef)}if(type=="variable"){register(value);return cont(functiondef)}if(type=="(")return cont(pushcontext,pushlex(")"),commasep(funarg,")"),poplex,mayberettype,statement,popcontext);if(isTS&&value=="<")return cont(pushlex(">"),commasep(typeparam,">"),poplex,functiondef)}function functiondecl(type,value){if(value=="*"){cx.marked="keyword";return cont(functiondecl)}if(type=="variable"){register(value);return cont(functiondecl)}if(type=="(")return cont(pushcontext,pushlex(")"),commasep(funarg,")"),poplex,mayberettype,popcontext);if(isTS&&value=="<")return cont(pushlex(">"),commasep(typeparam,">"),poplex,functiondecl)}function typename(type,value){if(type=="keyword"||type=="variable"){cx.marked="type";return cont(typename)}else if(value=="<"){return cont(pushlex(">"),commasep(typeparam,">"),poplex)}}function funarg(type,value){if(value=="@")cont(expression,funarg);if(type=="spread")return cont(funarg);if(isTS&&isModifier(value)){cx.marked="keyword";return cont(funarg)}if(isTS&&type=="this")return cont(maybetype,maybeAssign);return pass(pattern,maybetype,maybeAssign)}function classExpression(type,value){if(type=="variable")return className(type,value);return classNameAfter(type,value)}function className(type,value){if(type=="variable"){register(value);return cont(classNameAfter)}}function classNameAfter(type,value){if(value=="<")return cont(pushlex(">"),commasep(typeparam,">"),poplex,classNameAfter);if(value=="extends"||value=="implements"||isTS&&type==","){if(value=="implements")cx.marked="keyword";return cont(isTS?typeexpr:expression,classNameAfter)}if(type=="{")return cont(pushlex("}"),classBody,poplex)}function classBody(type,value){if(type=="async"||type=="variable"&&(value=="static"||value=="get"||value=="set"||isTS&&isModifier(value))&&cx.stream.match(/^\s+#?[\w$\xa1-\uffff]/,false)){cx.marked="keyword";return cont(classBody)}if(type=="variable"||cx.style=="keyword"){cx.marked="property";return cont(classfield,classBody)}if(type=="number"||type=="string")return cont(classfield,classBody);if(type=="[")return cont(expression,maybetype,expect("]"),classfield,classBody);if(value=="*"){cx.marked="keyword";return cont(classBody)}if(isTS&&type=="(")return pass(functiondecl,classBody);if(type==";"||type==",")return cont(classBody);if(type=="}")return cont();if(value=="@")return cont(expression,classBody)}function classfield(type,value){if(value=="!")return cont(classfield);if(value=="?")return cont(classfield);if(type==":")return cont(typeexpr,maybeAssign);if(value=="=")return cont(expressionNoComma);var context=cx.state.lexical.prev,isInterface=context&&context.info=="interface";return pass(isInterface?functiondecl:functiondef)}function afterExport(type,value){if(value=="*"){cx.marked="keyword";return cont(maybeFrom,expect(";"))}if(value=="default"){cx.marked="keyword";return cont(expression,expect(";"))}if(type=="{")return cont(commasep(exportField,"}"),maybeFrom,expect(";"));return pass(statement)}function exportField(type,value){if(value=="as"){cx.marked="keyword";return cont(expect("variable"))}if(type=="variable")return pass(expressionNoComma,exportField)}function afterImport(type){if(type=="string")return cont();if(type=="(")return pass(expression);if(type==".")return pass(maybeoperatorComma);return pass(importSpec,maybeMoreImports,maybeFrom)}function importSpec(type,value){if(type=="{")return contCommasep(importSpec,"}");if(type=="variable")register(value);if(value=="*")cx.marked="keyword";return cont(maybeAs)}function maybeMoreImports(type){if(type==",")return cont(importSpec,maybeMoreImports)}function maybeAs(_type,value){if(value=="as"){cx.marked="keyword";return cont(importSpec)}}function maybeFrom(_type,value){if(value=="from"){cx.marked="keyword";return cont(expression)}}function arrayLiteral(type){if(type=="]")return cont();return pass(commasep(expressionNoComma,"]"))}function enumdef(){return pass(pushlex("form"),pattern,expect("{"),pushlex("}"),commasep(enummember,"}"),poplex,poplex)}function enummember(){return pass(pattern,maybeAssign)}function isContinuedStatement(state,textAfter){return state.lastType=="operator"||state.lastType==","||isOperatorChar.test(textAfter.charAt(0))||/[,.]/.test(textAfter.charAt(0))}function expressionAllowed(stream,state,backUp){return state.tokenize==tokenBase&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType)||state.lastType=="quasi"&&/\{\s*$/.test(stream.string.slice(0,stream.pos-(backUp||0)))}return{startState:function(basecolumn){var state={tokenize:tokenBase,lastType:"sof",cc:[],lexical:new JSLexical((basecolumn||0)-indentUnit,0,"block",false),localVars:parserConfig.localVars,context:parserConfig.localVars&&new Context(null,null,false),indented:basecolumn||0};if(parserConfig.globalVars&&typeof parserConfig.globalVars=="object")state.globalVars=parserConfig.globalVars;return state},token:function(stream,state){if(stream.sol()){if(!state.lexical.hasOwnProperty("align"))state.lexical.align=false;state.indented=stream.indentation();findFatArrow(stream,state)}if(state.tokenize!=tokenComment&&stream.eatSpace())return null;var style=state.tokenize(stream,state);if(type=="comment")return style;state.lastType=type=="operator"&&(content=="++"||content=="--")?"incdec":type;return parseJS(state,style,type,content,stream)},indent:function(state,textAfter){if(state.tokenize==tokenComment||state.tokenize==tokenQuasi)return CodeMirror.Pass;if(state.tokenize!=tokenBase)return 0;var firstChar=textAfter&&textAfter.charAt(0),lexical=state.lexical,top;if(!/^\s*else\b/.test(textAfter))for(var i=state.cc.length-1;i>=0;--i){var c=state.cc[i];if(c==poplex)lexical=lexical.prev;else if(c!=maybeelse&&c!=popcontext)break}while((lexical.type=="stat"||lexical.type=="form")&&(firstChar=="}"||(top=state.cc[state.cc.length-1])&&(top==maybeoperatorComma||top==maybeoperatorNoComma)&&!/^[,\.=+\-*:?[\(]/.test(textAfter)))lexical=lexical.prev;if(statementIndent&&lexical.type==")"&&lexical.prev.type=="stat")lexical=lexical.prev;var type=lexical.type,closing=firstChar==type;if(type=="vardef")return lexical.indented+(state.lastType=="operator"||state.lastType==","?lexical.info.length+1:0);else if(type=="form"&&firstChar=="{")return lexical.indented;else if(type=="form")return lexical.indented+indentUnit;else if(type=="stat")return lexical.indented+(isContinuedStatement(state,textAfter)?statementIndent||indentUnit:0);else if(lexical.info=="switch"&&!closing&&parserConfig.doubleIndentSwitch!=false)return lexical.indented+(/^(?:case|default)\b/.test(textAfter)?indentUnit:2*indentUnit);else if(lexical.align)return lexical.column+(closing?0:1);else return lexical.indented+(closing?0:indentUnit)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:jsonMode?null:"/*",blockCommentEnd:jsonMode?null:"*/",blockCommentContinue:jsonMode?null:" * ",lineComment:jsonMode?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:jsonMode?"json":"javascript",jsonldMode:jsonldMode,jsonMode:jsonMode,expressionAllowed:expressionAllowed,skipExpression:function(state){parseJS(state,"atom","atom","true",new CodeMirror.StringStream("",2,null))}}}));CodeMirror.registerHelper("wordChars","javascript",/[\w$]/);CodeMirror.defineMIME("text/javascript","javascript");CodeMirror.defineMIME("text/ecmascript","javascript");CodeMirror.defineMIME("application/javascript","javascript");CodeMirror.defineMIME("application/x-javascript","javascript");CodeMirror.defineMIME("application/ecmascript","javascript");CodeMirror.defineMIME("application/json",{name:"javascript",json:true});CodeMirror.defineMIME("application/x-json",{name:"javascript",json:true});CodeMirror.defineMIME("application/manifest+json",{name:"javascript",json:true});CodeMirror.defineMIME("application/ld+json",{name:"javascript",jsonld:true});CodeMirror.defineMIME("text/typescript",{name:"javascript",typescript:true});CodeMirror.defineMIME("application/typescript",{name:"javascript",typescript:true})}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineExtension("annotateScrollbar",(function(options){if(typeof options=="string")options={className:options};return new Annotation(this,options)}));CodeMirror.defineOption("scrollButtonHeight",0);function Annotation(cm,options){this.cm=cm;this.options=options;this.buttonHeight=options.scrollButtonHeight||cm.getOption("scrollButtonHeight");this.annotations=[];this.doRedraw=this.doUpdate=null;this.div=cm.getWrapperElement().appendChild(document.createElement("div"));this.div.style.cssText="position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";this.computeScale();function scheduleRedraw(delay){clearTimeout(self.doRedraw);self.doRedraw=setTimeout((function(){self.redraw()}),delay)}var self=this;cm.on("refresh",this.resizeHandler=function(){clearTimeout(self.doUpdate);self.doUpdate=setTimeout((function(){if(self.computeScale())scheduleRedraw(20)}),100)});cm.on("markerAdded",this.resizeHandler);cm.on("markerCleared",this.resizeHandler);if(options.listenForChanges!==false)cm.on("changes",this.changeHandler=function(){scheduleRedraw(250)})}Annotation.prototype.computeScale=function(){var cm=this.cm;var hScale=(cm.getWrapperElement().clientHeight-cm.display.barHeight-this.buttonHeight*2)/cm.getScrollerElement().scrollHeight;if(hScale!=this.hScale){this.hScale=hScale;return true}};Annotation.prototype.update=function(annotations){this.annotations=annotations;this.redraw()};Annotation.prototype.redraw=function(compute){if(compute!==false)this.computeScale();var cm=this.cm,hScale=this.hScale;var frag=document.createDocumentFragment(),anns=this.annotations;var wrapping=cm.getOption("lineWrapping");var singleLineH=wrapping&&cm.defaultTextHeight()*1.5;var curLine=null,curLineObj=null;function getY(pos,top){if(curLine!=pos.line){curLine=pos.line;curLineObj=cm.getLineHandle(pos.line);var visual=cm.getLineHandleVisualStart(curLineObj);if(visual!=curLineObj){curLine=cm.getLineNumber(visual);curLineObj=visual}}if(curLineObj.widgets&&curLineObj.widgets.length||wrapping&&curLineObj.height>singleLineH)return cm.charCoords(pos,"local")[top?"top":"bottom"];var topY=cm.heightAtLine(curLineObj,"local");return topY+(top?0:curLineObj.height)}var lastLine=cm.lastLine();if(cm.display.barWidth)for(var i=0,nextTop;i<anns.length;i++){var ann=anns[i];if(ann.to.line>lastLine)continue;var top=nextTop||getY(ann.from,true)*hScale;var bottom=getY(ann.to,false)*hScale;while(i<anns.length-1){if(anns[i+1].to.line>lastLine)break;nextTop=getY(anns[i+1].from,true)*hScale;if(nextTop>bottom+.9)break;ann=anns[++i];bottom=getY(ann.to,false)*hScale}if(bottom==top)continue;var height=Math.max(bottom-top,3);var elt=frag.appendChild(document.createElement("div"));elt.style.cssText="position: absolute; right: 0px; width: "+Math.max(cm.display.barWidth-1,2)+"px; top: "+(top+this.buttonHeight)+"px; height: "+height+"px";elt.className=this.options.className;if(ann.id){elt.setAttribute("annotation-id",ann.id)}}this.div.textContent="";this.div.appendChild(frag)};Annotation.prototype.clear=function(){this.cm.off("refresh",this.resizeHandler);this.cm.off("markerAdded",this.resizeHandler);this.cm.off("markerCleared",this.resizeHandler);if(this.changeHandler)this.cm.off("changes",this.changeHandler);this.div.parentNode.removeChild(this.div)}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";function doFold(cm,pos,options,force){if(options&&options.call){var finder=options;options=null}else{var finder=getOption(cm,options,"rangeFinder")}if(typeof pos=="number")pos=CodeMirror.Pos(pos,0);var minSize=getOption(cm,options,"minFoldSize");function getRange(allowFolded){var range=finder(cm,pos);if(!range||range.to.line-range.from.line<minSize)return null;if(force==="fold")return range;var marks=cm.findMarksAt(range.from);for(var i=0;i<marks.length;++i){if(marks[i].__isFold){if(!allowFolded)return null;range.cleared=true;marks[i].clear()}}return range}var range=getRange(true);if(getOption(cm,options,"scanUp"))while(!range&&pos.line>cm.firstLine()){pos=CodeMirror.Pos(pos.line-1,0);range=getRange(false)}if(!range||range.cleared||force==="unfold")return;var myWidget=makeWidget(cm,options,range);CodeMirror.on(myWidget,"mousedown",(function(e){myRange.clear();CodeMirror.e_preventDefault(e)}));var myRange=cm.markText(range.from,range.to,{replacedWith:myWidget,clearOnEnter:getOption(cm,options,"clearOnEnter"),__isFold:true});myRange.on("clear",(function(from,to){CodeMirror.signal(cm,"unfold",cm,from,to)}));CodeMirror.signal(cm,"fold",cm,range.from,range.to)}function makeWidget(cm,options,range){var widget=getOption(cm,options,"widget");if(typeof widget=="function"){widget=widget(range.from,range.to)}if(typeof widget=="string"){var text=document.createTextNode(widget);widget=document.createElement("span");widget.appendChild(text);widget.className="CodeMirror-foldmarker"}else if(widget){widget=widget.cloneNode(true)}return widget}CodeMirror.newFoldFunction=function(rangeFinder,widget){return function(cm,pos){doFold(cm,pos,{rangeFinder:rangeFinder,widget:widget})}};CodeMirror.defineExtension("foldCode",(function(pos,options,force){doFold(this,pos,options,force)}));CodeMirror.defineExtension("isFolded",(function(pos){var marks=this.findMarksAt(pos);for(var i=0;i<marks.length;++i)if(marks[i].__isFold)return true}));CodeMirror.commands.toggleFold=function(cm){cm.foldCode(cm.getCursor())};CodeMirror.commands.fold=function(cm){cm.foldCode(cm.getCursor(),null,"fold")};CodeMirror.commands.unfold=function(cm){cm.foldCode(cm.getCursor(),{scanUp:false},"unfold")};CodeMirror.commands.foldAll=function(cm){cm.operation((function(){for(var i=cm.firstLine(),e=cm.lastLine();i<=e;i++)cm.foldCode(CodeMirror.Pos(i,0),{scanUp:false},"fold")}))};CodeMirror.commands.unfoldAll=function(cm){cm.operation((function(){for(var i=cm.firstLine(),e=cm.lastLine();i<=e;i++)cm.foldCode(CodeMirror.Pos(i,0),{scanUp:false},"unfold")}))};CodeMirror.registerHelper("fold","combine",(function(){var funcs=Array.prototype.slice.call(arguments,0);return function(cm,start){for(var i=0;i<funcs.length;++i){var found=funcs[i](cm,start);if(found)return found}}}));CodeMirror.registerHelper("fold","auto",(function(cm,start){var helpers=cm.getHelpers(start,"fold");for(var i=0;i<helpers.length;i++){var cur=helpers[i](cm,start);if(cur)return cur}}));var defaultOptions={rangeFinder:CodeMirror.fold.auto,widget:"↔",minFoldSize:0,scanUp:false,clearOnEnter:true};CodeMirror.defineOption("foldOptions",null);function getOption(cm,options,name){if(options&&options[name]!==undefined)return options[name];var editorOptions=cm.options.foldOptions;if(editorOptions&&editorOptions[name]!==undefined)return editorOptions[name];return defaultOptions[name]}CodeMirror.defineExtension("foldOption",(function(options,name){return getOption(this,options,name)}))}));(function(mod){"use strict";if(typeof exports==="object"&&typeof module==="object")mod(require("codemirror"));else if(typeof define==="function"&&define.amd)define(["codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var cmEleToSearch=new Map;var ESCAPE_SPECIAL_CHARS=/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;CodeMirror.defineOption("searchbox",false,(function(cm){function ctrlFHandler(){var cmEle=cm.display.wrapper;var Search=cmEleToSearch.get(cmEle);if(!Search||!cmEle.parentElement.contains(Search.searchBox)){cmEleToSearch.set(cmEle,new SearchBox(cm));Search=cmEleToSearch.get(cmEle)}var isReplace=false;if(cmEle.parentElement.querySelector("[action=toggleReplace]")){isReplace=cmEle.parentElement.querySelector("[action=toggleReplace]").innerText==="-"}Search.show(cm.getSelection(),isReplace)}cm.addKeyMap({"Ctrl-F":ctrlFHandler,Esc:function(){var Search=cmEleToSearch.get(cm.display.wrapper);if(!Search||!Search.isVisible())return CodeMirror.Pass;Search.hide();if(typeof event!=="undefined")event.stopPropagation()},"Cmd-F":ctrlFHandler})}));function SearchBox(cm){var self=this;init();function initElements(el){self.searchBox=el.querySelector(".ace_search_form");self.replaceBox=el.querySelector(".ace_replace_form");self.searchOptions=el.querySelector(".ace_search_options");self.regExpOption=el.querySelector("[action=toggleRegexpMode]");self.caseSensitiveOption=el.querySelector("[action=toggleCaseSensitive]");self.wholeWordOption=el.querySelector("[action=toggleWholeWords]");self.searchInput=self.searchBox.querySelector(".ace_search_field");self.replaceInput=self.replaceBox.querySelector(".ace_search_field")}function init(){var el=self.element=addHtml();addStyle();initElements(el);bindKeys();el.addEventListener("mousedown",(function(e){setTimeout((function(){self.activeInput.focus()}),0);e.stopPropagation()}));el.addEventListener("click",(function(e){var t=e.target||e.srcElement;var action=t.getAttribute("action");if(action&&self[action])self[action]();else if(self.commands[action])self.commands[action]();e.stopPropagation()}));self.searchInput.addEventListener("input",(function(){self.$onChange.schedule(20)}));self.searchInput.addEventListener("focus",(function(){self.activeInput=self.searchInput}));self.replaceInput.addEventListener("focus",(function(){self.activeInput=self.replaceInput}));self.$onChange=delayedCall((function(){self.find(false,false)}))}function bindKeys(){var sb=self,obj={"Ctrl-F|Cmd-F|Command-Alt-F":function(){sb.searchInput.focus();sb.searchInput.select()},"Ctrl-H":function(){sb.replaceBox.style.display="";sb.replaceInput.focus();sb.replaceInput.select()},"Ctrl-G|Cmd-G":function(){sb.findNext()},"Ctrl-Shift-G|Cmd-Shift-G":function(){sb.findPrev()},Esc:function(){setTimeout((function(){sb.hide()}))},"Shift-Enter":function(){if(sb.activeInput===sb.replaceInput)sb.replace();sb.findPrev()},Enter:function(){if(sb.activeInput===sb.replaceInput)sb.replace();sb.findNext()},"Alt-Enter":function(){if(sb.activeInput===sb.replaceInput)sb.replaceAll();sb.findAll()},Tab:function(){if(self.activeInput===self.replaceInput)self.searchInput.focus();else self.replaceInput.focus()}};self.element.addEventListener("keydown",(function(event){Object.keys(obj).some((function(name){var is=key(name,event);if(is){event.stopPropagation();event.preventDefault();obj[name](event)}return is}))}))}this.commands={toggleRegexpMode:function(){self.regExpOption.checked=!self.regExpOption.checked;self.$syncOptions()},toggleCaseSensitive:function(){self.caseSensitiveOption.checked=!self.caseSensitiveOption.checked;self.$syncOptions()},toggleWholeWords:function(){self.wholeWordOption.checked=!self.wholeWordOption.checked;self.$syncOptions()}};this.$syncOptions=function(){setCssClass(this.regExpOption,"checked",this.regExpOption.checked);setCssClass(this.wholeWordOption,"checked",this.wholeWordOption.checked);setCssClass(this.caseSensitiveOption,"checked",this.caseSensitiveOption.checked);this.find(false,false)};this.find=function(skipCurrent,backwards){var value=this.searchInput.value,options={skipCurrent:skipCurrent,backwards:backwards,regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked};find(value,options,(function(searchCursor){var current=searchCursor.matches(false,searchCursor.from());cm.setSelection(current.from,current.to)}))};function find(value,options,callback){if(!value){clearSearch(cm);updateCount();setCssClass(self.searchBox,"ace_nomatch",false);return}var done,noMatch,searchCursor,next,prev,matches,cursor,position,val=value,o=options,is=true,caseSensitive=o.caseSensitive,regExp=o.regExp,wholeWord=o.wholeWord;if(regExp){val=val.replace(ESCAPE_SPECIAL_CHARS,"\\$&")}if(wholeWord){if(caseSensitive){val=val=RegExp("\\b"+val+"\\b")}else{val=RegExp("\\b"+val+"\\b","i")}}if(regExp){val=RegExp(val)}clearSearch(cm);doSearch(cm,val,caseSensitive);updateCount();if(o.backwards)position=o.skipCurrent?"from":"to";else position=o.skipCurrent?"to":"from";cursor=cm.getCursor(position);searchCursor=cm.getSearchCursor(val,cursor,!caseSensitive);next=searchCursor.findNext.bind(searchCursor),prev=searchCursor.findPrevious.bind(searchCursor),matches=searchCursor.matches.bind(searchCursor);if(o.backwards&&!prev()){is=next();if(is){cm.setCursor(cm.doc.size-1,0);find(value,options,callback);done=true}}else if(!o.backwards&&!next()){is=prev();if(is){cm.setCursor(0,0);find(value,options,callback);done=true}}noMatch=!is&&self.searchInput.value;setCssClass(self.searchBox,"ace_nomatch",noMatch);if(!done&&is)callback(searchCursor)}this.findNext=function(){this.find(true,false)};this.findPrev=function(){this.find(true,true)};this.findAll=function(){var value=this.searchInput.value,range,noMatch=!range&&this.searchInput.value;setCssClass(this.searchBox,"ace_nomatch",noMatch);if(cm.showMatchesOnScrollbar)cm.showMatchesOnScrollbar(value);this.hide()};this.replace=function(){var readOnly=cm.getOption("readOnly"),isSelection=!!cm.getSelection();if(!readOnly&&isSelection)cm.replaceSelection(this.replaceInput.value,"start");updateCount()};this.replaceAndFindNext=function(){var readOnly=cm.getOption("readOnly");if(!readOnly){this.replace();this.findNext()}};this.replaceAll=function(){var value,cursor,from=this.searchInput.value,to=this.replaceInput.value,reg=RegExp(from.replace(ESCAPE_SPECIAL_CHARS,"\\$&"),this.caseSensitiveOption.checked?"g":"gi");if(this.wholeWordOption.checked&&!this.regExpOption.checked){if(this.caseSensitiveOption.checked){reg=RegExp("\\b"+from+"\\b","g")}else{reg=RegExp("\\b"+from+"\\b","gi")}}if(!cm.getOption("readOnly")&&cm.getSelection()){cursor=cm.getCursor();value=cm.getValue();value=value.replace(reg,to);cm.setValue(value);cm.setCursor(cursor)}updateCount()};this.toggleReplace=function(){var cmEle=cm.display.wrapper;if(cmEle.parentElement.querySelector("[action=toggleReplace]").innerText==="+"){cmEle.parentElement.querySelector("[action=toggleReplace]").innerText="-";this.replaceBox.style.display="";this.isReplace=true}else{cmEle.parentElement.querySelector("[action=toggleReplace]").innerText="+";this.replaceBox.style.display="none";this.isReplace=false}};this.hide=function(){clearSearch(cm);var cmEle=cm.getWrapperElement();cmEleToSearch.set(cmEle,null);cmEle.removeChild(this.element);cm.focus();if(cmEle.parentElement.querySelector(".code-editor-buttons-ctn"))document.querySelector(".code-editor-buttons-ctn").style.display="";if(cmEle.parentElement.querySelector(".toggle-wrap-button-html"))document.querySelector(".toggle-wrap-button-html").style.display=""};this.isVisible=function(){var is=this.element.style.display==="";return is};this.show=function(value,isReplace){this.element.style.display="";if(!isReplace){this.replaceBox.style.display=isReplace?"":"none"}this.isReplace=isReplace;if(value){this.searchInput.value=value;this.find(false,false)}this.searchInput.focus();this.searchInput.select();var cmEle=cm.getWrapperElement();if(cmEle.parentElement.querySelector(".code-editor-buttons-ctn"))document.querySelector(".code-editor-buttons-ctn").style.display="none";if(cmEle.parentElement.querySelector(".toggle-wrap-button-html"))document.querySelector(".toggle-wrap-button-html").style.display="none"};this.isFocused=function(){var el=document.activeElement;return el===this.searchInput||el===this.replaceInput};function doSearch(cm,value,caseSensitive){var state=getSearchState(cm);var query=value;if(query&&query!==state.queryText){startSearch(cm,state,query,caseSensitive);state.posFrom=state.posTo=cm.getCursor()}}function parseString(string){return string.replace(/\\([nrt\\])/g,(function(match,ch){if(ch=="n")return"\n";if(ch=="r")return"\r";if(ch=="t")return"\t";if(ch=="\\")return"\\";return match}))}function parseQuery(query){var reStr=typeof query==="object"?query.toString():query;var isRE=reStr.match(/^\/(.*)\/([a-z]*)$/);if(isRE){try{query=new RegExp(isRE[1],isRE[2].indexOf("i")==-1?"":"i")}catch(e){}}else{query=parseString(query)}if(typeof query=="string"?query=="":query.test(""))query=/x^/;return query}function startSearch(cm,state,query,caseSensitive){state.queryText=query;state.query=parseQuery(query);cm.removeOverlay(state.overlay,queryCaseInsensitive(state.query,caseSensitive));state.overlay=searchOverlay(state.query,queryCaseInsensitive(state.query,caseSensitive));cm.addOverlay(state.overlay);if(cm.showMatchesOnScrollbar){if(state.annotate){state.annotate.clear();state.annotate=null}state.annotate=cm.showMatchesOnScrollbar(state.query,queryCaseInsensitive(state.query,caseSensitive))}}function queryCaseInsensitive(query,caseSensitive){return typeof query=="string"&&!caseSensitive}function searchOverlay(query,caseInsensitive){if(typeof query=="string")query=new RegExp(query.replace(ESCAPE_SPECIAL_CHARS,"\\$&"),caseInsensitive?"gi":"g");else if(!query.global)query=new RegExp(query.source,query.ignoreCase?"gi":"g");return{token:function(stream){query.lastIndex=stream.pos;var match=query.exec(stream.string);if(match&&match.index==stream.pos){stream.pos+=match[0].length||1;return"searching"}else if(match){stream.pos=match.index}else{stream.skipToEnd()}}}}function SearchState(){this.posFrom=this.posTo=this.lastQuery=this.query=null;this.overlay=null}function getSearchState(cm){return cm.state.search||(cm.state.search=new SearchState)}function clearSearch(cm){cm.operation((function(){var state=getSearchState(cm);state.lastQuery=state.query;if(!state.query)return;state.query=state.queryText=null;cm.removeOverlay(state.overlay);if(state.annotate){state.annotate.clear();state.annotate=null}}))}function updateCount(){var val=self.searchInput.value;var matches=[];if(val){val=val.replace(ESCAPE_SPECIAL_CHARS,"\\$&");var reg;if(self.caseSensitiveOption.checked){reg=RegExp(val,"g")}else{reg=RegExp(val,"gi")}if(self.wholeWordOption.checked){if(self.caseSensitiveOption.checked){reg=RegExp("\\b"+val+"\\b","g")}else{reg=RegExp("\\b"+val+"\\b","gi")}}if(self.regExpOption.checked){reg=RegExp(val,"gi")}matches=cm.getValue().match(reg)}var count=matches?matches.length:0;var cmEle=cm.display.wrapper;var countEle=cmEle.parentElement.querySelector(".ace_search_counter");if(countEle){countEle.innerText=count+" matches found."}if(count===0){}}function addStyle(){let isDarkMode=window.matchMedia("(prefers-color-scheme: dark)")?.matches;var style=document.createElement("style"),css=[".ace_search {",`background-color: ${isDarkMode?"#2c2c2c":"#ddd"};`,`border: 1px solid ${isDarkMode?"#575757":"#cbcbcb"};`,"border-top: 0 none;","max-width: 325px;","overflow: hidden;","margin: 0;","padding: 4px;","padding-right: 6px;","padding-bottom: 0;","position: absolute;","top: 0px;","z-index: 99;","white-space: normal;","font-size: 12px;","}",".ace_search.left {","border-left: 0 none;","border-radius: 0px 0px 5px 0px;","left: 0;","}",".ace_search.right {","border-radius: 0px 0px 0px 5px;","border-right: 0 none;","right: 0;","}",".ace_search_form, .ace_replace_form {","border-radius: 3px;",`border: 1px solid ${isDarkMode?"#575757":"#cbcbcb"};`,"float: left;","margin-bottom: 4px;","overflow: hidden;","}",".ace_search_form.ace_nomatch {","outline: 1px solid #c54832;","}",".ace_search_field {",`background-color: ${isDarkMode?"#272727":"white"};`,`border-right: 1px solid ${isDarkMode?"#575757":"#cbcbcb"};`,"border: 0 none;","-webkit-box-sizing: border-box;","-moz-box-sizing: border-box;","box-sizing: border-box;","float: left;","height: 22px;","outline: 0;","padding: 0 7px;","width: 238px;","margin: 0;","}",".ace_searchbtn, .ace_replacebtn { border:none !important; }",".ace_searchbtn,",".ace_replacebtn {",`background: ${isDarkMode?"#2c2c2c":"#fff"};`,"border: 0 none;",`border-left: 1px solid ${isDarkMode?"#575757":"#dcdcdc"};`,"cursor: pointer;","float: left;","height: 22px;","padding: 0 5px;","margin: 0;","position: relative;","width:27px","}",`.ace_searchbtn:hover, .ace_replacebtn:hover { background-color:${isDarkMode?"#3c3c3c":"#dcdcdc"}; border:none !important; }`,".ace_searchbtn:last-child,",".ace_replacebtn:last-child {","border-top-right-radius: 3px;","border-bottom-right-radius: 3px;","}",".ace_searchbtn:disabled {","background: none;","cursor: default;","}",".ace_searchbtn {","background-position: 50% 50%;","background-repeat: no-repeat;","width: 27px;","}",".ace_searchbtn.prev {","background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpiSU1NZUAC/6E0I0yACYskCpsJiySKIiY0SUZk40FyTEgCjGgKwTRAgAEAQJUIPCE+qfkAAAAASUVORK5CYII=);    ","}",".ace_searchbtn.next {","background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNpiTE1NZQCC/0DMyIAKwGJMUAYDEo3M/s+EpvM/mkKwCQxYjIeLMaELoLMBAgwAU7UJObTKsvAAAAAASUVORK5CYII=);    ","}",".ace_searchbtn_close {","background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;","border-radius: 50%;","border: 0 none;","color: #656565;","cursor: pointer;","float: right;","font: 16px/16px Arial;","height: 14px;","margin: 5px 1px 9px 5px;","padding: 0;","text-align: center;","width: 14px;","}",".ace_searchbtn_close:hover {","background-color: #656565;","background-position: 50% 100%;","color: white;","}",".ace_replacebtn.prev {","width: 54px","}",".ace_replacebtn.next {","width: 27px","}",".ace_button {","margin-left: 2px;","cursor: pointer;","-webkit-user-select: none;","-moz-user-select: none;","-o-user-select: none;","-ms-user-select: none;","user-select: none;","overflow: hidden;","opacity: 0.7;",`border: 1px solid ${isDarkMode?"#575757":"rgba(100,100,100,0.23)"};`,"padding: 1.4px;","-moz-box-sizing: border-box;","box-sizing:    border-box;",`color: ${isDarkMode?"white":"black"};`,`border-radius: 3px;`,"}",".ace_button:hover {",`background-color: ${isDarkMode?"#4a4a4a":"#eee"};`,"opacity:1;","}",".ace_button:active {","}",".ace_button.checked {","border-color: #3399ff;","opacity:1;","}",".ace_search_options{","clear: both;","margin: 4px 0;","text-align: right;","-webkit-user-select: none;","-moz-user-select: none;","-o-user-select: none;","-ms-user-select: none;","user-select: none;","}",".replace_toggle{","float: left;","margin-top: -2px;","padding: 0 5px;","border-radius: 3px;","margin-left: 0;",isDarkMode?"border-color:#575757;":""," }",".ace_search_counter{","float: left;","font-family: arial;","padding: 0 8px;","}","button svg,path {","pointer-events: none;","}"].join("");style.setAttribute("data-name","js-searchbox");style.textContent=css;document.head.appendChild(style)}function addHtml(){var elSearch,el=cm.getWrapperElement(),div=document.createElement("div"),html=['<div class="ace_search right">','<button type="button" action="hide" class="ace_searchbtn_close"></button>','<div class="ace_search_form">','<input class="ace_search_field" placeholder="Search for" spellcheck="false" autocomplete="one-time-code"></input>','<button type="button" action="findPrev" class="ace_searchbtn prev"></button>','<button type="button" action="findNext" class="ace_searchbtn next"></button>',"</div>",'<div class="ace_replace_form">','<input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>','<button type="button" action="replaceAndFindNext" title="Replace" class="ace_replacebtn">','<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">','<path fill-rule="evenodd" clip-rule="evenodd" d="M3.221 3.739L5.482 6.008L7.7 3.784L7 3.084L5.988 4.091L5.98 2.491C5.97909 2.35567 6.03068 2.22525 6.12392 2.12716C6.21716 2.02908 6.3448 1.97095 6.48 1.965H8V1H6.48C6.28496 1.00026 6.09189 1.03902 5.91186 1.11405C5.73183 1.18908 5.56838 1.29892 5.43088 1.43725C5.29338 1.57558 5.18455 1.73969 5.11061 1.92018C5.03667 2.10066 4.99908 2.29396 5 2.489V4.1L3.927 3.033L3.221 3.739ZM9.89014 5.53277H9.90141C10.0836 5.84426 10.3521 6 10.707 6C11.0995 6 11.4131 5.83236 11.6479 5.49708C11.8826 5.1618 12 4.71728 12 4.16353C12 3.65304 11.8995 3.2507 11.6986 2.95652C11.4977 2.66234 11.2113 2.51525 10.8394 2.51525C10.4338 2.51525 10.1211 2.70885 9.90141 3.09604H9.89014V1H9V5.91888H9.89014V5.53277ZM9.87606 4.47177V4.13108C9.87606 3.88449 9.93427 3.6844 10.0507 3.53082C10.169 3.37724 10.3174 3.30045 10.4958 3.30045C10.6854 3.30045 10.831 3.37833 10.9324 3.53407C11.0357 3.68765 11.0873 3.9018 11.0873 4.17651C11.0873 4.50746 11.031 4.76379 10.9183 4.94549C10.8075 5.12503 10.6507 5.2148 10.4479 5.2148C10.2808 5.2148 10.1437 5.14449 10.0366 5.00389C9.92958 4.86329 9.87606 4.68592 9.87606 4.47177ZM9 12.7691C8.74433 12.923 8.37515 13 7.89247 13C7.32855 13 6.87216 12.8225 6.5233 12.4674C6.17443 12.1124 6 11.6543 6 11.0931C6 10.4451 6.18638 9.93484 6.55914 9.5624C6.93429 9.18747 7.43489 9.00001 8.06093 9.00001C8.49343 9.00001 8.80645 9.0596 9 9.17878V10.1769C8.76344 9.99319 8.4994 9.90132 8.20789 9.90132C7.88292 9.90132 7.62485 10.0006 7.43369 10.1993C7.24492 10.3954 7.15054 10.6673 7.15054 11.0149C7.15054 11.3526 7.24134 11.6183 7.42294 11.8119C7.60454 12.0031 7.85424 12.0987 8.17204 12.0987C8.454 12.0987 8.72999 12.0068 9 11.8231V12.7691ZM4 7L3 8V14L4 15H11L12 14V8L11 7H4ZM4 8H5H10H11V9V13V14H10H5H4V13V9V8Z" fill="#656565"/>',"</svg></button>",'<button type="button" action="replaceAll" title="Replace All" class="ace_replacebtn">','<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">','<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6009 2.67683C11.7474 2.36708 11.9559 2.2122 12.2263 2.2122C12.4742 2.2122 12.6651 2.32987 12.7991 2.56522C12.933 2.80056 13 3.12243 13 3.53082C13 3.97383 12.9218 4.32944 12.7653 4.59766C12.6088 4.86589 12.3997 5 12.138 5C11.9014 5 11.7224 4.87541 11.6009 4.62622H11.5934V4.93511H11V1H11.5934V2.67683H11.6009ZM11.584 3.77742C11.584 3.94873 11.6197 4.09063 11.6911 4.20311C11.7624 4.3156 11.8538 4.37184 11.9653 4.37184C12.1005 4.37184 12.205 4.30002 12.2789 4.15639C12.354 4.01103 12.3915 3.80597 12.3915 3.54121C12.3915 3.32144 12.3571 3.15012 12.2883 3.02726C12.2207 2.90266 12.1236 2.84036 11.9972 2.84036C11.8782 2.84036 11.7793 2.9018 11.7005 3.02466C11.6228 3.14752 11.584 3.30759 11.584 3.50487V3.77742ZM4.11969 7.695L2 5.56781L2.66188 4.90594L3.66781 5.90625V4.39594C3.66695 4.21309 3.70219 4.03187 3.7715 3.86266C3.84082 3.69346 3.94286 3.53961 4.07176 3.40992C4.20066 3.28023 4.3539 3.17727 4.52268 3.10692C4.69146 3.03658 4.87246 3.00024 5.05531 3H7.39906V3.90469H5.05531C4.92856 3.91026 4.8089 3.96476 4.72149 4.05672C4.63408 4.14868 4.58571 4.27094 4.58656 4.39781L4.59406 5.89781L5.54281 4.95375L6.19906 5.61L4.11969 7.695ZM9.3556 4.93017H10V3.22067C10 2.40689 9.68534 2 9.05603 2C8.92098 2 8.77083 2.02421 8.6056 2.07263C8.44181 2.12104 8.3125 2.17691 8.21767 2.24022V2.90503C8.45474 2.70205 8.70474 2.60056 8.96767 2.60056C9.22917 2.60056 9.35991 2.75698 9.35991 3.06983L8.76078 3.17318C8.25359 3.25885 8 3.57914 8 4.13408C8 4.39665 8.06106 4.60708 8.18319 4.76536C8.30675 4.92179 8.47557 5 8.68966 5C8.97989 5 9.19899 4.83985 9.34698 4.51955H9.3556V4.93017ZM9.35991 3.57542V3.76816C9.35991 3.9432 9.31968 4.08845 9.23922 4.20391C9.15876 4.3175 9.0546 4.3743 8.92672 4.3743C8.83477 4.3743 8.76149 4.34264 8.7069 4.27933C8.65374 4.21415 8.62716 4.13128 8.62716 4.03073C8.62716 3.80912 8.73779 3.6797 8.95905 3.64246L9.35991 3.57542ZM7 12.9302H6.3556V12.5196H6.34698C6.19899 12.8399 5.97989 13 5.68966 13C5.47557 13 5.30675 12.9218 5.18319 12.7654C5.06106 12.6071 5 12.3966 5 12.1341C5 11.5791 5.25359 11.2588 5.76078 11.1732L6.35991 11.0698C6.35991 10.757 6.22917 10.6006 5.96767 10.6006C5.70474 10.6006 5.45474 10.702 5.21767 10.905V10.2402C5.3125 10.1769 5.44181 10.121 5.6056 10.0726C5.77083 10.0242 5.92098 10 6.05603 10C6.68534 10 7 10.4069 7 11.2207V12.9302ZM6.35991 11.7682V11.5754L5.95905 11.6425C5.73779 11.6797 5.62716 11.8091 5.62716 12.0307C5.62716 12.1313 5.65374 12.2142 5.7069 12.2793C5.76149 12.3426 5.83477 12.3743 5.92672 12.3743C6.0546 12.3743 6.15876 12.3175 6.23922 12.2039C6.31968 12.0885 6.35991 11.9432 6.35991 11.7682ZM9.26165 13C9.58343 13 9.82955 12.9423 10 12.8268V12.1173C9.81999 12.2551 9.636 12.324 9.44803 12.324C9.23616 12.324 9.06969 12.2523 8.94863 12.1089C8.82756 11.9637 8.76702 11.7644 8.76702 11.5112C8.76702 11.2505 8.82995 11.0466 8.95579 10.8994C9.08323 10.7505 9.25528 10.676 9.47192 10.676C9.66627 10.676 9.84229 10.7449 10 10.8827V10.1341C9.87097 10.0447 9.66229 10 9.37395 10C8.95659 10 8.62286 10.1406 8.37276 10.4218C8.12425 10.7011 8 11.0838 8 11.5698C8 11.9907 8.11629 12.3343 8.34887 12.6006C8.58144 12.8669 8.8857 13 9.26165 13ZM2 9L3 8H12L13 9V14L12 15H3L2 14V9ZM3 9V14H12V9H3ZM6 7L7 6H14L15 7V12L14 13V12V7H7H6Z" fill="#656565"/>',"</svg></button>","</div>",'<div class="ace_search_options">','<span action="toggleReplace" class="ace_button replace_toggle">+</span>','<span class="ace_search_counter">0 matches found.</span>','<span action="toggleRegexpMode" title="RegExp Search"></span>','<span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>','<span action="toggleWholeWords" title="Whole Word Search"></span>',"</div>","</div>"].join("");div.innerHTML=html;elSearch=div.firstChild;el.appendChild(elSearch);return elSearch}}function setCssClass(el,className,condition){var list=el.classList;list[condition?"add":"remove"](className)}function delayedCall(fcn,defaultTimeout){var timer,callback=function(){timer=null;fcn()},_self=function(timeout){if(!timer)timer=setTimeout(callback,timeout||defaultTimeout)};_self.delay=function(timeout){timer&&clearTimeout(timer);timer=setTimeout(callback,timeout||defaultTimeout)};_self.schedule=_self;_self.call=function(){this.cancel();fcn()};_self.cancel=function(){timer&&clearTimeout(timer);timer=null};_self.isPending=function(){return timer};return _self}function key(str,event){var right,KEY={BACKSPACE:8,TAB:9,ENTER:13,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,UP:38,DOWN:40,INSERT:45,DELETE:46,INSERT_MAC:96,ASTERISK:106,PLUS:107,MINUS:109,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,SLASH:191,TRA:192,BACKSLASH:220};keyCheck(str,event);right=str.split("|").some((function(combination){var wrong;wrong=combination.split("-").some((function(key){var right;switch(key){case"Ctrl":right=event.ctrlKey;break;case"Shift":right=event.shiftKey;break;case"Alt":right=event.altKey;break;case"Cmd":right=event.metaKey;break;default:if(key.length===1)right=event.keyCode===key.charCodeAt(0);else Object.keys(KEY).some((function(name){var up=key.toUpperCase();if(up===name)right=event.keyCode===KEY[name]}));break}return!right}));return!wrong}));return right}function keyCheck(str,event){if(typeof str!=="string")throw Error("str should be string!");if(typeof event!=="object")throw Error("event should be object!")}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var htmlConfig={autoSelfClosers:{area:true,base:true,br:true,col:true,command:true,embed:true,frame:true,hr:true,img:true,input:true,keygen:true,link:true,meta:true,param:true,source:true,track:true,wbr:true,menuitem:true},implicitlyClosed:{dd:true,li:true,optgroup:true,option:true,p:true,rp:true,rt:true,tbody:true,td:true,tfoot:true,th:true,tr:true},contextGrabbers:{dd:{dd:true,dt:true},dt:{dd:true,dt:true},li:{li:true},option:{option:true,optgroup:true},optgroup:{optgroup:true},p:{address:true,article:true,aside:true,blockquote:true,dir:true,div:true,dl:true,fieldset:true,footer:true,form:true,h1:true,h2:true,h3:true,h4:true,h5:true,h6:true,header:true,hgroup:true,hr:true,menu:true,nav:true,ol:true,p:true,pre:true,section:true,table:true,ul:true},rp:{rp:true,rt:true},rt:{rp:true,rt:true},tbody:{tbody:true,tfoot:true},td:{td:true,th:true},tfoot:{tbody:true},th:{td:true,th:true},thead:{tbody:true,tfoot:true},tr:{tr:true}},doNotIndent:{pre:true},allowUnquoted:true,allowMissing:true,caseFold:true};var xmlConfig={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:false,allowMissing:false,allowMissingTagName:false,caseFold:false};CodeMirror.defineMode("xml",(function(editorConf,config_){var indentUnit=editorConf.indentUnit;var config={};var defaults=config_.htmlMode?htmlConfig:xmlConfig;for(var prop in defaults)config[prop]=defaults[prop];for(var prop in config_)config[prop]=config_[prop];var type,setStyle;function inText(stream,state){function chain(parser){state.tokenize=parser;return parser(stream,state)}var ch=stream.next();if(ch=="<"){if(stream.eat("!")){if(stream.eat("[")){if(stream.match("CDATA["))return chain(inBlock("atom","]]>"));else return null}else if(stream.match("--")){return chain(inBlock("comment","--\x3e"))}else if(stream.match("DOCTYPE",true,true)){stream.eatWhile(/[\w\._\-]/);return chain(doctype(1))}else{return null}}else if(stream.eat("?")){stream.eatWhile(/[\w\._\-]/);state.tokenize=inBlock("meta","?>");return"meta"}else{type=stream.eat("/")?"closeTag":"openTag";state.tokenize=inTag;return"tag bracket"}}else if(ch=="&"){var ok;if(stream.eat("#")){if(stream.eat("x")){ok=stream.eatWhile(/[a-fA-F\d]/)&&stream.eat(";")}else{ok=stream.eatWhile(/[\d]/)&&stream.eat(";")}}else{ok=stream.eatWhile(/[\w\.\-:]/)&&stream.eat(";")}return ok?"atom":"error"}else{stream.eatWhile(/[^&<]/);return null}}inText.isInText=true;function inTag(stream,state){var ch=stream.next();if(ch==">"||ch=="/"&&stream.eat(">")){state.tokenize=inText;type=ch==">"?"endTag":"selfcloseTag";return"tag bracket"}else if(ch=="="){type="equals";return null}else if(ch=="<"){state.tokenize=inText;state.state=baseState;state.tagName=state.tagStart=null;var next=state.tokenize(stream,state);return next?next+" tag error":"tag error"}else if(/[\'\"]/.test(ch)){state.tokenize=inAttribute(ch);state.stringStartCol=stream.column();return state.tokenize(stream,state)}else{stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);return"word"}}function inAttribute(quote){var closure=function(stream,state){while(!stream.eol()){if(stream.next()==quote){state.tokenize=inTag;break}}return"string"};closure.isInAttribute=true;return closure}function inBlock(style,terminator){return function(stream,state){while(!stream.eol()){if(stream.match(terminator)){state.tokenize=inText;break}stream.next()}return style}}function doctype(depth){return function(stream,state){var ch;while((ch=stream.next())!=null){if(ch=="<"){state.tokenize=doctype(depth+1);return state.tokenize(stream,state)}else if(ch==">"){if(depth==1){state.tokenize=inText;break}else{state.tokenize=doctype(depth-1);return state.tokenize(stream,state)}}}return"meta"}}function lower(tagName){return tagName&&tagName.toLowerCase()}function Context(state,tagName,startOfLine){this.prev=state.context;this.tagName=tagName||"";this.indent=state.indented;this.startOfLine=startOfLine;if(config.doNotIndent.hasOwnProperty(tagName)||state.context&&state.context.noIndent)this.noIndent=true}function popContext(state){if(state.context)state.context=state.context.prev}function maybePopContext(state,nextTagName){var parentTagName;while(true){if(!state.context){return}parentTagName=state.context.tagName;if(!config.contextGrabbers.hasOwnProperty(lower(parentTagName))||!config.contextGrabbers[lower(parentTagName)].hasOwnProperty(lower(nextTagName))){return}popContext(state)}}function baseState(type,stream,state){if(type=="openTag"){state.tagStart=stream.column();return tagNameState}else if(type=="closeTag"){return closeTagNameState}else{return baseState}}function tagNameState(type,stream,state){if(type=="word"){state.tagName=stream.current();setStyle="tag";return attrState}else if(config.allowMissingTagName&&type=="endTag"){setStyle="tag bracket";return attrState(type,stream,state)}else{setStyle="error";return tagNameState}}function closeTagNameState(type,stream,state){if(type=="word"){var tagName=stream.current();if(state.context&&state.context.tagName!=tagName&&config.implicitlyClosed.hasOwnProperty(lower(state.context.tagName)))popContext(state);if(state.context&&state.context.tagName==tagName||config.matchClosing===false){setStyle="tag";return closeState}else{setStyle="tag error";return closeStateErr}}else if(config.allowMissingTagName&&type=="endTag"){setStyle="tag bracket";return closeState(type,stream,state)}else{setStyle="error";return closeStateErr}}function closeState(type,_stream,state){if(type!="endTag"){setStyle="error";return closeState}popContext(state);return baseState}function closeStateErr(type,stream,state){setStyle="error";return closeState(type,stream,state)}function attrState(type,_stream,state){if(type=="word"){setStyle="attribute";return attrEqState}else if(type=="endTag"||type=="selfcloseTag"){var tagName=state.tagName,tagStart=state.tagStart;state.tagName=state.tagStart=null;if(type=="selfcloseTag"||config.autoSelfClosers.hasOwnProperty(lower(tagName))){maybePopContext(state,tagName)}else{maybePopContext(state,tagName);state.context=new Context(state,tagName,tagStart==state.indented)}return baseState}setStyle="error";return attrState}function attrEqState(type,stream,state){if(type=="equals")return attrValueState;if(!config.allowMissing)setStyle="error";return attrState(type,stream,state)}function attrValueState(type,stream,state){if(type=="string")return attrContinuedState;if(type=="word"&&config.allowUnquoted){setStyle="string";return attrState}setStyle="error";return attrState(type,stream,state)}function attrContinuedState(type,stream,state){if(type=="string")return attrContinuedState;return attrState(type,stream,state)}return{startState:function(baseIndent){var state={tokenize:inText,state:baseState,indented:baseIndent||0,tagName:null,tagStart:null,context:null};if(baseIndent!=null)state.baseIndent=baseIndent;return state},token:function(stream,state){if(!state.tagName&&stream.sol())state.indented=stream.indentation();if(stream.eatSpace())return null;type=null;var style=state.tokenize(stream,state);if((style||type)&&style!="comment"){setStyle=null;state.state=state.state(type||style,stream,state);if(setStyle)style=setStyle=="error"?style+" error":setStyle}return style},indent:function(state,textAfter,fullLine){var context=state.context;if(state.tokenize.isInAttribute){if(state.tagStart==state.indented)return state.stringStartCol+1;else return state.indented+indentUnit}if(context&&context.noIndent)return CodeMirror.Pass;if(state.tokenize!=inTag&&state.tokenize!=inText)return fullLine?fullLine.match(/^(\s*)/)[0].length:0;if(state.tagName){if(config.multilineTagIndentPastTag!==false)return state.tagStart+state.tagName.length+2;else return state.tagStart+indentUnit*(config.multilineTagIndentFactor||1)}if(config.alignCDATA&&/<!\[CDATA\[/.test(textAfter))return 0;var tagAfter=textAfter&&/^<(\/)?([\w_:\.-]*)/.exec(textAfter);if(tagAfter&&tagAfter[1]){while(context){if(context.tagName==tagAfter[2]){context=context.prev;break}else if(config.implicitlyClosed.hasOwnProperty(lower(context.tagName))){context=context.prev}else{break}}}else if(tagAfter){while(context){var grabbers=config.contextGrabbers[lower(context.tagName)];if(grabbers&&grabbers.hasOwnProperty(lower(tagAfter[2])))context=context.prev;else break}}while(context&&context.prev&&!context.startOfLine)context=context.prev;if(context)return context.indent+indentUnit;else return state.baseIndent||0},electricInput:/<\/[\s\w:]+>$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:config.htmlMode?"html":"xml",helperType:config.htmlMode?"html":"xml",skipAttribute:function(state){if(state.state==attrValueState)state.state=attrState},xmlCurrentTag:function(state){return state.tagName?{name:state.tagName,close:state.type=="closeTag"}:null},xmlCurrentContext:function(state){var context=[];for(var cx=state.context;cx;cx=cx.prev)context.push(cx.tagName);return context.reverse()}}}));CodeMirror.defineMIME("text/xml","xml");CodeMirror.defineMIME("application/xml","xml");if(!CodeMirror.mimeModes.hasOwnProperty("text/html"))CodeMirror.defineMIME("text/html",{name:"xml",htmlMode:true})}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var defaultTags={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],[null,null,"css"]]};function maybeBackup(stream,pat,style){var cur=stream.current(),close=cur.search(pat);if(close>-1){stream.backUp(cur.length-close)}else if(cur.match(/<\/?$/)){stream.backUp(cur.length);if(!stream.match(pat,false))stream.match(cur)}return style}var attrRegexpCache={};function getAttrRegexp(attr){var regexp=attrRegexpCache[attr];if(regexp)return regexp;return attrRegexpCache[attr]=new RegExp("\\s+"+attr+"\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*")}function getAttrValue(text,attr){var match=text.match(getAttrRegexp(attr));return match?/^\s*(.*?)\s*$/.exec(match[2])[1]:""}function getTagRegexp(tagName,anchored){return new RegExp((anchored?"^":"")+"</\\s*"+tagName+"\\s*>","i")}function addTags(from,to){for(var tag in from){var dest=to[tag]||(to[tag]=[]);var source=from[tag];for(var i=source.length-1;i>=0;i--)dest.unshift(source[i])}}function findMatchingMode(tagInfo,tagText){for(var i=0;i<tagInfo.length;i++){var spec=tagInfo[i];if(!spec[0]||spec[1].test(getAttrValue(tagText,spec[0])))return spec[2]}}CodeMirror.defineMode("htmlmixed",(function(config,parserConfig){var htmlMode=CodeMirror.getMode(config,{name:"xml",htmlMode:true,multilineTagIndentFactor:parserConfig.multilineTagIndentFactor,multilineTagIndentPastTag:parserConfig.multilineTagIndentPastTag,allowMissingTagName:parserConfig.allowMissingTagName});var tags={};var configTags=parserConfig&&parserConfig.tags,configScript=parserConfig&&parserConfig.scriptTypes;addTags(defaultTags,tags);if(configTags)addTags(configTags,tags);if(configScript)for(var i=configScript.length-1;i>=0;i--)tags.script.unshift(["type",configScript[i].matches,configScript[i].mode]);function html(stream,state){var style=htmlMode.token(stream,state.htmlState),tag=/\btag\b/.test(style),tagName;if(tag&&!/[<>\s\/]/.test(stream.current())&&(tagName=state.htmlState.tagName&&state.htmlState.tagName.toLowerCase())&&tags.hasOwnProperty(tagName)){state.inTag=tagName+" "}else if(state.inTag&&tag&&/>$/.test(stream.current())){var inTag=/^([\S]+) (.*)/.exec(state.inTag);state.inTag=null;var modeSpec=stream.current()==">"&&findMatchingMode(tags[inTag[1]],inTag[2]);var mode=CodeMirror.getMode(config,modeSpec);var endTagA=getTagRegexp(inTag[1],true),endTag=getTagRegexp(inTag[1],false);state.token=function(stream,state){if(stream.match(endTagA,false)){state.token=html;state.localState=state.localMode=null;return null}return maybeBackup(stream,endTag,state.localMode.token(stream,state.localState))};state.localMode=mode;state.localState=CodeMirror.startState(mode,htmlMode.indent(state.htmlState,"",""))}else if(state.inTag){state.inTag+=stream.current();if(stream.eol())state.inTag+=" "}return style}return{startState:function(){var state=CodeMirror.startState(htmlMode);return{token:html,inTag:null,localMode:null,localState:null,htmlState:state}},copyState:function(state){var local;if(state.localState){local=CodeMirror.copyState(state.localMode,state.localState)}return{token:state.token,inTag:state.inTag,localMode:state.localMode,localState:local,htmlState:CodeMirror.copyState(htmlMode,state.htmlState)}},token:function(stream,state){return state.token(stream,state)},indent:function(state,textAfter,line){if(!state.localMode||/^\s*<\//.test(textAfter))return htmlMode.indent(state.htmlState,textAfter,line);else if(state.localMode.indent)return state.localMode.indent(state.localState,textAfter,line);else return CodeMirror.Pass},innerMode:function(state){return{state:state.localState||state.htmlState,mode:state.localMode||htmlMode}}}}),"xml","javascript","css");CodeMirror.defineMIME("text/html","htmlmixed")}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineMode("css",(function(config,parserConfig){var inline=parserConfig.inline;if(!parserConfig.propertyKeywords)parserConfig=CodeMirror.resolveMode("text/css");var indentUnit=config.indentUnit,tokenHooks=parserConfig.tokenHooks,documentTypes=parserConfig.documentTypes||{},mediaTypes=parserConfig.mediaTypes||{},mediaFeatures=parserConfig.mediaFeatures||{},mediaValueKeywords=parserConfig.mediaValueKeywords||{},propertyKeywords=parserConfig.propertyKeywords||{},nonStandardPropertyKeywords=parserConfig.nonStandardPropertyKeywords||{},fontProperties=parserConfig.fontProperties||{},counterDescriptors=parserConfig.counterDescriptors||{},colorKeywords=parserConfig.colorKeywords||{},valueKeywords=parserConfig.valueKeywords||{},allowNested=parserConfig.allowNested,lineComment=parserConfig.lineComment,supportsAtComponent=parserConfig.supportsAtComponent===true,highlightNonStandardPropertyKeywords=config.highlightNonStandardPropertyKeywords!==false;var type,override;function ret(style,tp){type=tp;return style}function tokenBase(stream,state){var ch=stream.next();if(tokenHooks[ch]){var result=tokenHooks[ch](stream,state);if(result!==false)return result}if(ch=="@"){stream.eatWhile(/[\w\\\-]/);return ret("def",stream.current())}else if(ch=="="||(ch=="~"||ch=="|")&&stream.eat("=")){return ret(null,"compare")}else if(ch=='"'||ch=="'"){state.tokenize=tokenString(ch);return state.tokenize(stream,state)}else if(ch=="#"){stream.eatWhile(/[\w\\\-]/);return ret("atom","hash")}else if(ch=="!"){stream.match(/^\s*\w*/);return ret("keyword","important")}else if(/\d/.test(ch)||ch=="."&&stream.eat(/\d/)){stream.eatWhile(/[\w.%]/);return ret("number","unit")}else if(ch==="-"){if(/[\d.]/.test(stream.peek())){stream.eatWhile(/[\w.%]/);return ret("number","unit")}else if(stream.match(/^-[\w\\\-]*/)){stream.eatWhile(/[\w\\\-]/);if(stream.match(/^\s*:/,false))return ret("variable-2","variable-definition");return ret("variable-2","variable")}else if(stream.match(/^\w+-/)){return ret("meta","meta")}}else if(/[,+>*\/]/.test(ch)){return ret(null,"select-op")}else if(ch=="."&&stream.match(/^-?[_a-z][_a-z0-9-]*/i)){return ret("qualifier","qualifier")}else if(/[:;{}\[\]\(\)]/.test(ch)){return ret(null,ch)}else if(stream.match(/^[\w-.]+(?=\()/)){if(/^(url(-prefix)?|domain|regexp)$/i.test(stream.current())){state.tokenize=tokenParenthesized}return ret("variable callee","variable")}else if(/[\w\\\-]/.test(ch)){stream.eatWhile(/[\w\\\-]/);return ret("property","word")}else{return ret(null,null)}}function tokenString(quote){return function(stream,state){var escaped=false,ch;while((ch=stream.next())!=null){if(ch==quote&&!escaped){if(quote==")")stream.backUp(1);break}escaped=!escaped&&ch=="\\"}if(ch==quote||!escaped&&quote!=")")state.tokenize=null;return ret("string","string")}}function tokenParenthesized(stream,state){stream.next();if(!stream.match(/^\s*[\"\')]/,false))state.tokenize=tokenString(")");else state.tokenize=null;return ret(null,"(")}function Context(type,indent,prev){this.type=type;this.indent=indent;this.prev=prev}function pushContext(state,stream,type,indent){state.context=new Context(type,stream.indentation()+(indent===false?0:indentUnit),state.context);return type}function popContext(state){if(state.context.prev)state.context=state.context.prev;return state.context.type}function pass(type,stream,state){return states[state.context.type](type,stream,state)}function popAndPass(type,stream,state,n){for(var i=n||1;i>0;i--)state.context=state.context.prev;return pass(type,stream,state)}function wordAsValue(stream){var word=stream.current().toLowerCase();if(valueKeywords.hasOwnProperty(word))override="atom";else if(colorKeywords.hasOwnProperty(word))override="keyword";else override="variable"}var states={};states.top=function(type,stream,state){if(type=="{"){return pushContext(state,stream,"block")}else if(type=="}"&&state.context.prev){return popContext(state)}else if(supportsAtComponent&&/@component/i.test(type)){return pushContext(state,stream,"atComponentBlock")}else if(/^@(-moz-)?document$/i.test(type)){return pushContext(state,stream,"documentTypes")}else if(/^@(media|supports|(-moz-)?document|import)$/i.test(type)){return pushContext(state,stream,"atBlock")}else if(/^@(font-face|counter-style)/i.test(type)){state.stateArg=type;return"restricted_atBlock_before"}else if(/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)){return"keyframes"}else if(type&&type.charAt(0)=="@"){return pushContext(state,stream,"at")}else if(type=="hash"){override="builtin"}else if(type=="word"){override="tag"}else if(type=="variable-definition"){return"maybeprop"}else if(type=="interpolation"){return pushContext(state,stream,"interpolation")}else if(type==":"){return"pseudo"}else if(allowNested&&type=="("){return pushContext(state,stream,"parens")}return state.context.type};states.block=function(type,stream,state){if(type=="word"){var word=stream.current().toLowerCase();if(propertyKeywords.hasOwnProperty(word)){override="property";return"maybeprop"}else if(nonStandardPropertyKeywords.hasOwnProperty(word)){override=highlightNonStandardPropertyKeywords?"string-2":"property";return"maybeprop"}else if(allowNested){override=stream.match(/^\s*:(?:\s|$)/,false)?"property":"tag";return"block"}else{override+=" error";return"maybeprop"}}else if(type=="meta"){return"block"}else if(!allowNested&&(type=="hash"||type=="qualifier")){override="error";return"block"}else{return states.top(type,stream,state)}};states.maybeprop=function(type,stream,state){if(type==":")return pushContext(state,stream,"prop");return pass(type,stream,state)};states.prop=function(type,stream,state){if(type==";")return popContext(state);if(type=="{"&&allowNested)return pushContext(state,stream,"propBlock");if(type=="}"||type=="{")return popAndPass(type,stream,state);if(type=="(")return pushContext(state,stream,"parens");if(type=="hash"&&!/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(stream.current())){override+=" error"}else if(type=="word"){wordAsValue(stream)}else if(type=="interpolation"){return pushContext(state,stream,"interpolation")}return"prop"};states.propBlock=function(type,_stream,state){if(type=="}")return popContext(state);if(type=="word"){override="property";return"maybeprop"}return state.context.type};states.parens=function(type,stream,state){if(type=="{"||type=="}")return popAndPass(type,stream,state);if(type==")")return popContext(state);if(type=="(")return pushContext(state,stream,"parens");if(type=="interpolation")return pushContext(state,stream,"interpolation");if(type=="word")wordAsValue(stream);return"parens"};states.pseudo=function(type,stream,state){if(type=="meta")return"pseudo";if(type=="word"){override="variable-3";return state.context.type}return pass(type,stream,state)};states.documentTypes=function(type,stream,state){if(type=="word"&&documentTypes.hasOwnProperty(stream.current())){override="tag";return state.context.type}else{return states.atBlock(type,stream,state)}};states.atBlock=function(type,stream,state){if(type=="(")return pushContext(state,stream,"atBlock_parens");if(type=="}"||type==";")return popAndPass(type,stream,state);if(type=="{")return popContext(state)&&pushContext(state,stream,allowNested?"block":"top");if(type=="interpolation")return pushContext(state,stream,"interpolation");if(type=="word"){var word=stream.current().toLowerCase();if(word=="only"||word=="not"||word=="and"||word=="or")override="keyword";else if(mediaTypes.hasOwnProperty(word))override="attribute";else if(mediaFeatures.hasOwnProperty(word))override="property";else if(mediaValueKeywords.hasOwnProperty(word))override="keyword";else if(propertyKeywords.hasOwnProperty(word))override="property";else if(nonStandardPropertyKeywords.hasOwnProperty(word))override=highlightNonStandardPropertyKeywords?"string-2":"property";else if(valueKeywords.hasOwnProperty(word))override="atom";else if(colorKeywords.hasOwnProperty(word))override="keyword";else override="error"}return state.context.type};states.atComponentBlock=function(type,stream,state){if(type=="}")return popAndPass(type,stream,state);if(type=="{")return popContext(state)&&pushContext(state,stream,allowNested?"block":"top",false);if(type=="word")override="error";return state.context.type};states.atBlock_parens=function(type,stream,state){if(type==")")return popContext(state);if(type=="{"||type=="}")return popAndPass(type,stream,state,2);return states.atBlock(type,stream,state)};states.restricted_atBlock_before=function(type,stream,state){if(type=="{")return pushContext(state,stream,"restricted_atBlock");if(type=="word"&&state.stateArg=="@counter-style"){override="variable";return"restricted_atBlock_before"}return pass(type,stream,state)};states.restricted_atBlock=function(type,stream,state){if(type=="}"){state.stateArg=null;return popContext(state)}if(type=="word"){if(state.stateArg=="@font-face"&&!fontProperties.hasOwnProperty(stream.current().toLowerCase())||state.stateArg=="@counter-style"&&!counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))override="error";else override="property";return"maybeprop"}return"restricted_atBlock"};states.keyframes=function(type,stream,state){if(type=="word"){override="variable";return"keyframes"}if(type=="{")return pushContext(state,stream,"top");return pass(type,stream,state)};states.at=function(type,stream,state){if(type==";")return popContext(state);if(type=="{"||type=="}")return popAndPass(type,stream,state);if(type=="word")override="tag";else if(type=="hash")override="builtin";return"at"};states.interpolation=function(type,stream,state){if(type=="}")return popContext(state);if(type=="{"||type==";")return popAndPass(type,stream,state);if(type=="word")override="variable";else if(type!="variable"&&type!="("&&type!=")")override="error";return"interpolation"};return{startState:function(base){return{tokenize:null,state:inline?"block":"top",stateArg:null,context:new Context(inline?"block":"top",base||0,null)}},token:function(stream,state){if(!state.tokenize&&stream.eatSpace())return null;var style=(state.tokenize||tokenBase)(stream,state);if(style&&typeof style=="object"){type=style[1];style=style[0]}override=style;if(type!="comment")state.state=states[state.state](type,stream,state);return override},indent:function(state,textAfter){var cx=state.context,ch=textAfter&&textAfter.charAt(0);var indent=cx.indent;if(cx.type=="prop"&&(ch=="}"||ch==")"))cx=cx.prev;if(cx.prev){if(ch=="}"&&(cx.type=="block"||cx.type=="top"||cx.type=="interpolation"||cx.type=="restricted_atBlock")){cx=cx.prev;indent=cx.indent}else if(ch==")"&&(cx.type=="parens"||cx.type=="atBlock_parens")||ch=="{"&&(cx.type=="at"||cx.type=="atBlock")){indent=Math.max(0,cx.indent-indentUnit)}}return indent},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:lineComment,fold:"brace"}}));function keySet(array){var keys={};for(var i=0;i<array.length;++i){keys[array[i].toLowerCase()]=true}return keys}var documentTypes_=["domain","regexp","url","url-prefix"],documentTypes=keySet(documentTypes_);var mediaTypes_=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],mediaTypes=keySet(mediaTypes_);var mediaFeatures_=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid","orientation","device-pixel-ratio","min-device-pixel-ratio","max-device-pixel-ratio","pointer","any-pointer","hover","any-hover","prefers-color-scheme","dynamic-range","video-dynamic-range"],mediaFeatures=keySet(mediaFeatures_);var mediaValueKeywords_=["landscape","portrait","none","coarse","fine","on-demand","hover","interlace","progressive","dark","light","standard","high"],mediaValueKeywords=keySet(mediaValueKeywords_);var propertyKeywords_=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","all","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","binding","bleed","block-size","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-content","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-gap","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-gap","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","inset","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","left","letter-spacing","line-break","line-height","line-height-step","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","place-content","place-items","place-self","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotate","rotation","rotation-point","row-gap","ruby-align","ruby-overhang","ruby-position","ruby-span","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-type","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-orientation","text-outline","text-overflow","text-rendering","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","touch-action","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-select","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","paint-order","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],propertyKeywords=keySet(propertyKeywords_);var nonStandardPropertyKeywords_=["accent-color","aspect-ratio","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","content-visibility","margin-block","margin-block-end","margin-block-start","margin-inline","margin-inline-end","margin-inline-start","overflow-anchor","overscroll-behavior","padding-block","padding-block-end","padding-block-start","padding-inline","padding-inline-end","padding-inline-start","scroll-snap-stop","scrollbar-3d-light-color","scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-track-color","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","shape-inside","zoom"],nonStandardPropertyKeywords=keySet(nonStandardPropertyKeywords_);var fontProperties_=["font-display","font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"],fontProperties=keySet(fontProperties_);var counterDescriptors_=["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"],counterDescriptors=keySet(counterDescriptors_);var colorKeywords_=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],colorKeywords=keySet(colorKeywords_);var valueKeywords_=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","auto-flow","avoid","avoid-column","avoid-page","avoid-region","axis-pan","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","blur","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","brightness","bullets","button","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","color","color-burn","color-dodge","column","column-reverse","compact","condensed","conic-gradient","contain","content","contents","content-box","context-menu","continuous","contrast","copy","counter","counters","cover","crop","cross","crosshair","cubic-bezier","currentcolor","cursive","cyclic","darken","dashed","decimal","decimal-leading-zero","default","default-button","dense","destination-atop","destination-in","destination-out","destination-over","devanagari","difference","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","drop-shadow","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","exclusion","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fill-box","fixed","flat","flex","flex-end","flex-start","footnotes","forwards","from","geometricPrecision","georgian","grayscale","graytext","grid","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hard-light","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","hue","hue-rotate","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-grid","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","lighten","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","luminosity","malayalam","manipulation","match","matrix","matrix3d","media-play-button","media-slider","media-sliderthumb","media-volume-slider","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","multiple_mask_images","multiply","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","opacity","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","pinch-zoom","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeating-conic-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row","row-resize","row-reverse","rtl","run-in","running","s-resize","sans-serif","saturate","saturation","scale","scale3d","scaleX","scaleY","scaleZ","screen","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","self-start","self-end","semi-condensed","semi-expanded","separate","sepia","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","soft-light","solid","somali","source-atop","source-in","source-out","source-over","space","space-around","space-between","space-evenly","spell-out","square","square-button","start","static","status-bar","stretch","stroke","stroke-box","sub","subpixel-antialiased","svg_masks","super","sw-resize","symbolic","symbols","system-ui","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","transform","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","unidirectional-pan","unset","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","view-box","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","wrap","wrap-reverse","x-large","x-small","xor","xx-large","xx-small"],valueKeywords=keySet(valueKeywords_);var allWords=documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_).concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);CodeMirror.registerHelper("hintWords","css",allWords);function tokenCComment(stream,state){var maybeEnd=false,ch;while((ch=stream.next())!=null){if(maybeEnd&&ch=="/"){state.tokenize=null;break}maybeEnd=ch=="*"}return["comment","comment"]}CodeMirror.defineMIME("text/css",{documentTypes:documentTypes,mediaTypes:mediaTypes,mediaFeatures:mediaFeatures,mediaValueKeywords:mediaValueKeywords,propertyKeywords:propertyKeywords,nonStandardPropertyKeywords:nonStandardPropertyKeywords,fontProperties:fontProperties,counterDescriptors:counterDescriptors,colorKeywords:colorKeywords,valueKeywords:valueKeywords,tokenHooks:{"/":function(stream,state){if(!stream.eat("*"))return false;state.tokenize=tokenCComment;return tokenCComment(stream,state)}},name:"css"});CodeMirror.defineMIME("text/x-scss",{mediaTypes:mediaTypes,mediaFeatures:mediaFeatures,mediaValueKeywords:mediaValueKeywords,propertyKeywords:propertyKeywords,nonStandardPropertyKeywords:nonStandardPropertyKeywords,colorKeywords:colorKeywords,valueKeywords:valueKeywords,fontProperties:fontProperties,allowNested:true,lineComment:"//",tokenHooks:{"/":function(stream,state){if(stream.eat("/")){stream.skipToEnd();return["comment","comment"]}else if(stream.eat("*")){state.tokenize=tokenCComment;return tokenCComment(stream,state)}else{return["operator","operator"]}},":":function(stream){if(stream.match(/^\s*\{/,false))return[null,null];return false},$:function(stream){stream.match(/^[\w-]+/);if(stream.match(/^\s*:/,false))return["variable-2","variable-definition"];return["variable-2","variable"]},"#":function(stream){if(!stream.eat("{"))return false;return[null,"interpolation"]}},name:"css",helperType:"scss"});CodeMirror.defineMIME("text/x-less",{mediaTypes:mediaTypes,mediaFeatures:mediaFeatures,mediaValueKeywords:mediaValueKeywords,propertyKeywords:propertyKeywords,nonStandardPropertyKeywords:nonStandardPropertyKeywords,colorKeywords:colorKeywords,valueKeywords:valueKeywords,fontProperties:fontProperties,allowNested:true,lineComment:"//",tokenHooks:{"/":function(stream,state){if(stream.eat("/")){stream.skipToEnd();return["comment","comment"]}else if(stream.eat("*")){state.tokenize=tokenCComment;return tokenCComment(stream,state)}else{return["operator","operator"]}},"@":function(stream){if(stream.eat("{"))return[null,"interpolation"];if(stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i,false))return false;stream.eatWhile(/[\w\\\-]/);if(stream.match(/^\s*:/,false))return["variable-2","variable-definition"];return["variable-2","variable"]},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"});CodeMirror.defineMIME("text/x-gss",{documentTypes:documentTypes,mediaTypes:mediaTypes,mediaFeatures:mediaFeatures,propertyKeywords:propertyKeywords,nonStandardPropertyKeywords:nonStandardPropertyKeywords,fontProperties:fontProperties,counterDescriptors:counterDescriptors,colorKeywords:colorKeywords,valueKeywords:valueKeywords,supportsAtComponent:true,tokenHooks:{"/":function(stream,state){if(!stream.eat("*"))return false;state.tokenize=tokenCComment;return tokenCComment(stream,state)}},name:"css",helperType:"gss"})}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";var WRAP_CLASS="CodeMirror-activeline";var BACK_CLASS="CodeMirror-activeline-background";var GUTT_CLASS="CodeMirror-activeline-gutter";CodeMirror.defineOption("styleActiveLine",false,(function(cm,val,old){var prev=old==CodeMirror.Init?false:old;if(val==prev)return;if(prev){cm.off("beforeSelectionChange",selectionChange);clearActiveLines(cm);delete cm.state.activeLines}if(val){cm.state.activeLines=[];updateActiveLines(cm,cm.listSelections());cm.on("beforeSelectionChange",selectionChange)}}));function clearActiveLines(cm){for(var i=0;i<cm.state.activeLines.length;i++){cm.removeLineClass(cm.state.activeLines[i],"wrap",WRAP_CLASS);cm.removeLineClass(cm.state.activeLines[i],"background",BACK_CLASS);cm.removeLineClass(cm.state.activeLines[i],"gutter",GUTT_CLASS)}}function sameArray(a,b){if(a.length!=b.length)return false;for(var i=0;i<a.length;i++)if(a[i]!=b[i])return false;return true}function updateActiveLines(cm,ranges){var active=[];for(var i=0;i<ranges.length;i++){var range=ranges[i];var option=cm.getOption("styleActiveLine");if(typeof option=="object"&&option.nonEmpty?range.anchor.line!=range.head.line:!range.empty())continue;var line=cm.getLineHandleVisualStart(range.head.line);if(active[active.length-1]!=line)active.push(line)}if(sameArray(cm.state.activeLines,active))return;cm.operation((function(){clearActiveLines(cm);for(var i=0;i<active.length;i++){cm.addLineClass(active[i],"wrap",WRAP_CLASS);cm.addLineClass(active[i],"background",BACK_CLASS);cm.addLineClass(active[i],"gutter",GUTT_CLASS)}cm.state.activeLines=active}))}function selectionChange(cm,sel){updateActiveLines(cm,sel.ranges)}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){var nonspace=/\S/g;var repeat=String.prototype.repeat||function(n){return Array(n+1).join(this)};function continueComment(cm){if(cm.getOption("disableInput"))return CodeMirror.Pass;var ranges=cm.listSelections(),mode,inserts=[];for(var i=0;i<ranges.length;i++){var pos=ranges[i].head;if(!/\bcomment\b/.test(cm.getTokenTypeAt(pos)))return CodeMirror.Pass;var modeHere=cm.getModeAt(pos);if(!mode)mode=modeHere;else if(mode!=modeHere)return CodeMirror.Pass;var insert=null,line,found;var blockStart=mode.blockCommentStart,lineCmt=mode.lineComment;if(blockStart&&mode.blockCommentContinue){line=cm.getLine(pos.line);var end=line.lastIndexOf(mode.blockCommentEnd,pos.ch-mode.blockCommentEnd.length);if(end!=-1&&end==pos.ch-mode.blockCommentEnd.length||lineCmt&&(found=line.lastIndexOf(lineCmt,pos.ch-1))>-1&&/\bcomment\b/.test(cm.getTokenTypeAt({line:pos.line,ch:found+1}))){}else if(pos.ch>=blockStart.length&&(found=line.lastIndexOf(blockStart,pos.ch-blockStart.length))>-1&&found>end){if(nonspaceAfter(0,line)>=found){insert=line.slice(0,found)}else{var tabSize=cm.options.tabSize,numTabs;found=CodeMirror.countColumn(line,found,tabSize);insert=!cm.options.indentWithTabs?repeat.call(" ",found):repeat.call("\t",numTabs=Math.floor(found/tabSize))+repeat.call(" ",found-tabSize*numTabs)}}else if((found=line.indexOf(mode.blockCommentContinue))>-1&&found<=pos.ch&&found<=nonspaceAfter(0,line)){insert=line.slice(0,found)}if(insert!=null)insert+=mode.blockCommentContinue}if(insert==null&&lineCmt&&continueLineCommentEnabled(cm)){if(line==null)line=cm.getLine(pos.line);found=line.indexOf(lineCmt);if(!pos.ch&&!found)insert="";else if(found>-1&&nonspaceAfter(0,line)>=found){insert=nonspaceAfter(pos.ch,line)>-1;if(!insert){var next=cm.getLine(pos.line+1)||"",nextFound=next.indexOf(lineCmt);insert=nextFound>-1&&nonspaceAfter(0,next)>=nextFound||null}if(insert){insert=line.slice(0,found)+lineCmt+line.slice(found+lineCmt.length).match(/^\s*/)[0]}}}if(insert==null)return CodeMirror.Pass;inserts[i]="\n"+insert}cm.operation((function(){for(var i=ranges.length-1;i>=0;i--)cm.replaceRange(inserts[i],ranges[i].from(),ranges[i].to(),"+insert")}))}function nonspaceAfter(ch,str){nonspace.lastIndex=ch;var m=nonspace.exec(str);return m?m.index:-1}function continueLineCommentEnabled(cm){var opt=cm.getOption("continueComments");if(opt&&typeof opt=="object")return opt.continueLineComment!==false;return true}CodeMirror.defineOption("continueComments",null,(function(cm,val,prev){if(prev&&prev!=CodeMirror.Init)cm.removeKeyMap("continueComment");if(val){var key="Enter";if(typeof val=="string")key=val;else if(typeof val=="object"&&val.key)key=val.key;var map={name:"continueComment"};map[key]=continueComment;cm.addKeyMap(map)}}))}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){"use strict";CodeMirror.defineOption("selectionPointer",false,(function(cm,val){var data=cm.state.selectionPointer;if(data){CodeMirror.off(cm.getWrapperElement(),"mousemove",data.mousemove);CodeMirror.off(cm.getWrapperElement(),"mouseout",data.mouseout);CodeMirror.off(window,"scroll",data.windowScroll);cm.off("cursorActivity",reset);cm.off("scroll",reset);cm.state.selectionPointer=null;cm.display.lineDiv.style.cursor=""}if(val){data=cm.state.selectionPointer={value:typeof val=="string"?val:"default",mousemove:function(event){mousemove(cm,event)},mouseout:function(event){mouseout(cm,event)},windowScroll:function(){reset(cm)},rects:null,mouseX:null,mouseY:null,willUpdate:false};CodeMirror.on(cm.getWrapperElement(),"mousemove",data.mousemove);CodeMirror.on(cm.getWrapperElement(),"mouseout",data.mouseout);CodeMirror.on(window,"scroll",data.windowScroll);cm.on("cursorActivity",reset);cm.on("scroll",reset)}}));function mousemove(cm,event){var data=cm.state.selectionPointer;if(event.buttons==null?event.which:event.buttons){data.mouseX=data.mouseY=null}else{data.mouseX=event.clientX;data.mouseY=event.clientY}scheduleUpdate(cm)}function mouseout(cm,event){if(!cm.getWrapperElement().contains(event.relatedTarget)){var data=cm.state.selectionPointer;data.mouseX=data.mouseY=null;scheduleUpdate(cm)}}function reset(cm){cm.state.selectionPointer.rects=null;scheduleUpdate(cm)}function scheduleUpdate(cm){if(!cm.state.selectionPointer.willUpdate){cm.state.selectionPointer.willUpdate=true;setTimeout((function(){update(cm);cm.state.selectionPointer.willUpdate=false}),50)}}function update(cm){var data=cm.state.selectionPointer;if(!data)return;if(data.rects==null&&data.mouseX!=null){data.rects=[];if(cm.somethingSelected()){for(var sel=cm.display.selectionDiv.firstChild;sel;sel=sel.nextSibling)data.rects.push(sel.getBoundingClientRect())}}var inside=false;if(data.mouseX!=null)for(var i=0;i<data.rects.length;i++){var rect=data.rects[i];if(rect.left<=data.mouseX&&rect.right>=data.mouseX&&rect.top<=data.mouseY&&rect.bottom>=data.mouseY)inside=true}var cursor=inside?data.value:"";if(cm.display.lineDiv.style.cursor!=cursor)cm.display.lineDiv.style.cursor=cursor}}));(function(mod){if(typeof exports=="object"&&typeof module=="object")mod(require("../../lib/codemirror"));else if(typeof define=="function"&&define.amd)define(["../../lib/codemirror"],mod);else mod(CodeMirror)})((function(CodeMirror){var ie_lt8=/MSIE \d/.test(navigator.userAgent)&&(document.documentMode==null||document.documentMode<8);var Pos=CodeMirror.Pos;var matching={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function bracketRegex(config){return config&&config.bracketRegex||/[(){}[\]]/}function findMatchingBracket(cm,where,config){var line=cm.getLineHandle(where.line),pos=where.ch-1;var afterCursor=config&&config.afterCursor;if(afterCursor==null)afterCursor=/(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className);var re=bracketRegex(config);var match=!afterCursor&&pos>=0&&re.test(line.text.charAt(pos))&&matching[line.text.charAt(pos)]||re.test(line.text.charAt(pos+1))&&matching[line.text.charAt(++pos)];if(!match)return null;var dir=match.charAt(1)==">"?1:-1;if(config&&config.strict&&dir>0!=(pos==where.ch))return null;var style=cm.getTokenTypeAt(Pos(where.line,pos+1));var found=scanForBracket(cm,Pos(where.line,pos+(dir>0?1:0)),dir,style,config);if(found==null)return null;return{from:Pos(where.line,pos),to:found&&found.pos,match:found&&found.ch==match.charAt(0),forward:dir>0}}function scanForBracket(cm,where,dir,style,config){var maxScanLen=config&&config.maxScanLineLength||1e4;var maxScanLines=config&&config.maxScanLines||1e3;var stack=[];var re=bracketRegex(config);var lineEnd=dir>0?Math.min(where.line+maxScanLines,cm.lastLine()+1):Math.max(cm.firstLine()-1,where.line-maxScanLines);for(var lineNo=where.line;lineNo!=lineEnd;lineNo+=dir){var line=cm.getLine(lineNo);if(!line)continue;var pos=dir>0?0:line.length-1,end=dir>0?line.length:-1;if(line.length>maxScanLen)continue;if(lineNo==where.line)pos=where.ch-(dir<0?1:0);for(;pos!=end;pos+=dir){var ch=line.charAt(pos);if(re.test(ch)&&(style===undefined||(cm.getTokenTypeAt(Pos(lineNo,pos+1))||"")==(style||""))){var match=matching[ch];if(match&&match.charAt(1)==">"==dir>0)stack.push(ch);else if(!stack.length)return{pos:Pos(lineNo,pos),ch:ch};else stack.pop()}}}return lineNo-dir==(dir>0?cm.lastLine():cm.firstLine())?false:null}function matchBrackets(cm,autoclear,config){var maxHighlightLen=cm.state.matchBrackets.maxHighlightLineLength||1e3,highlightNonMatching=config&&config.highlightNonMatching;var marks=[],ranges=cm.listSelections();for(var i=0;i<ranges.length;i++){var match=ranges[i].empty()&&findMatchingBracket(cm,ranges[i].head,config);if(match&&(match.match||highlightNonMatching!==false)&&cm.getLine(match.from.line).length<=maxHighlightLen){var style=match.match?"CodeMirror-matchingbracket":"CodeMirror-nonmatchingbracket";marks.push(cm.markText(match.from,Pos(match.from.line,match.from.ch+1),{className:style}));if(match.to&&cm.getLine(match.to.line).length<=maxHighlightLen)marks.push(cm.markText(match.to,Pos(match.to.line,match.to.ch+1),{className:style}))}}if(marks.length){if(ie_lt8&&cm.state.focused)cm.focus();var clear=function(){cm.operation((function(){for(var i=0;i<marks.length;i++)marks[i].clear()}))};if(autoclear)setTimeout(clear,800);else return clear}}function doMatchBrackets(cm){cm.operation((function(){if(cm.state.matchBrackets.currentlyHighlighted){cm.state.matchBrackets.currentlyHighlighted();cm.state.matchBrackets.currentlyHighlighted=null}cm.state.matchBrackets.currentlyHighlighted=matchBrackets(cm,false,cm.state.matchBrackets)}))}function clearHighlighted(cm){if(cm.state.matchBrackets&&cm.state.matchBrackets.currentlyHighlighted){cm.state.matchBrackets.currentlyHighlighted();cm.state.matchBrackets.currentlyHighlighted=null}}CodeMirror.defineOption("matchBrackets",false,(function(cm,val,old){if(old&&old!=CodeMirror.Init){cm.off("cursorActivity",doMatchBrackets);cm.off("focus",doMatchBrackets);cm.off("blur",clearHighlighted);clearHighlighted(cm)}if(val){cm.state.matchBrackets=typeof val=="object"?val:{};cm.on("cursorActivity",doMatchBrackets);cm.on("focus",doMatchBrackets);cm.on("blur",clearHighlighted)}}));CodeMirror.defineExtension("matchBrackets",(function(){matchBrackets(this,true)}));CodeMirror.defineExtension("findMatchingBracket",(function(pos,config,oldConfig){if(oldConfig||typeof config=="boolean"){if(!oldConfig){config=config?{strict:true}:null}else{oldConfig.strict=config;config=oldConfig}}return findMatchingBracket(this,pos,config)}));CodeMirror.defineExtension("scanForBracket",(function(pos,dir,style,config){return scanForBracket(this,pos,dir,style,config)}))}));
</script>

        <script>
// for playing about and testing: http://jsfiddle.net/TcqAf/529/

// newer version: http://jsbin.com/filalidobe/1/edit?html,output
// problem is, even if I do work out this: https://stackoverflow.com/questions/52160551/way-to-overlay-multiple-tokens-rules-with-codemirror-simple-mode
//   i'll still have to sort out this [a = [], "hello"] - probably need to write a proper mode (using same logic that breaks up square blocks)

// CodeMirror.defineSimpleMode("simplemode", {
//   // The start state contains the rules that are intially used
//   start: [
//       // You can embed other modes with the mode property. This rule
//     // causes all code between << and >> to be highlighted with the XML
//     // mode.
// //    {regex: /(?:^|[^\\])(?:\\\\)*(\[)/, token: "variable-3", mode: {spec: "javascript", end: /(?:^|[^\\])(?:\\\\)*(\])/}},
//     // The regex matches the token, the token property contains the type
//     //{regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string"},
//     // You can match multiple tokens at once. Note that the captured
//     // groups must span the whole string in this case
//     {regex: /([a-zA-Z][a-zA-Z0-9$_]+)(\s*)(\()([^)]*)(\))(\s*)(=>)/,
//      token: ["variable-2", null, "keyword", null, "keyword", null, "keyword"]},

//     // curly
//     {regex: /\{[a-zA-Z]-[a-zA-Z]\}/, token: "syntax-style1"},
//     {regex: /\{[0-9]+-[0-9]+\}/, token: "syntax-style1"},
//     {regex: /\{/, token: "syntax-style1"},
//     {regex: /\}/, token: "syntax-style1"},

//     // square
//     //{regex: /\[[^\]]+\]/, token: "variable-3"},
//     {regex: /\[/, token: "syntax-style2"},
//     {regex: /\]/, token: "syntax-style2"},

//     // equals
//     {regex: /=/, token: "keyword"},

//     // not sure
//     {regex: /\$output\b/, token: "variable-2"},
//     {regex: /\$preprocess\b/, token: "variable-2"},
    
//     //{regex: /true|false|null|undefined/, token: "atom"},
//     //{regex: /0x[a-f\d]+|[-+]?(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i,
//      //token: "number"},
//     {regex: /[\s](\/\/.*)/, token: "syntax-style3-comment"},
//     {regex: /(\/\/.*)/, token: "syntax-style3-comment", sol:true},
//     //{regex: /\/(?:[^\\]|\\.)*?\//, token: "variable-3"},
//     //{regex: /[-+\/*=<>!]+/, token: "operator"},
//     // indent and dedent properties guide autoindentation
//     //{regex: /=>/, indent: true},
//     //{regex: /[\}\]\)]/, dedent: true},
//     //{regex: /[a-z$][\w$]*/, token: "variable"},
//   ],
//   // The meta property contains global information about the mode. It
//   // can contain properties like lineComment, which are supported by
//   // all modes, and also directives like dontIndentStates, which are
//   // specific to simple modes.
//   meta: {
//     dontIndentStates: ["comment"],
//     lineComment: "//",
//     fold: "indent",
//   }
// });


// CodeMirror.defineMode("mustache", function(config, parserConfig) {
//   var mustacheOverlay = {
//     token: function(stream, state) {
//       var ch;
//       if (stream.match("{")) {
//         while ((ch = stream.next()) != null)
//           if (stream.next() == "}") {
//             stream.eat("}");
//             return "variable-2";
//           }
//       }
//       while (stream.next() != null && !stream.match("{", false)) {}
//       return null;
//     }
//   };
//   return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay);
// });

try {

  CodeMirror.defineMode("perchancelists", function(config) {

    var jsMode = CodeMirror.getMode(config, "javascript");
  
    // this, in a sense, `trimStart`s the stream and then gets the next two characters
    function skipSpacesAndPeekTwo(stream) {
      let count = 0;
      let result = '';
      for (let i = stream.pos; i < stream.string.length; i++) {
        let char = stream.string.charAt(i);
        if (char !== ' ' && char !== '\t') {
          result += char;
          count++;
          if (count === 2) {
            return result;
          }
        }
      }
      return null;
    }
    
    function token(stream, state) {    
      if(state.inSquareBlock && state.inFunction) console.error("invalid state - cannot be both in function and square block at same time");
      if(stream.string.length > 50000) { // Consume the entire line if it's too long
        stream.skipToEnd();
        return null;  // No styling applied
      }
  
      if(stream.sol() && state.inSquareBlock) { // square blocks cannot span multiple lines
        state.bracketDepth = 0;
        state.inSquareBlock = false;
        state.localState = null;
        return null;
      }
  
      if(stream.sol() && state.inFunction && stream.indentation() <= state.functionIndent && skipSpacesAndPeekTwo(stream) !== "//") {
        state.inFunction = false;
        state.localState = null;
        stream.backUp(stream.current().length); // rewind to the beginning of the line (important)
        return null;
      }
    
      if(state.inSquareBlock || state.inFunction) {
        let style = jsMode.token(stream, state.localState);
        let current = stream.current();
    
        if(state.inFunction) {
          if(state.inSquareBlock) console.error("inSquareBlock while also inFunction");
          // note: we already early-exited in case of indentation-based function end, above, so we know we're still in the function here
          return style;
        } else if(state.inSquareBlock) {
          if(state.inFunction) console.error("inFunction while also inSquareBlock");
  
          // don't count square brackets that are in strings, regex, or comments:
          if(style !== "string" && style !== "string-2" && style !== "comment") {
            if(current === "]") {
              state.bracketDepth--;
              if (state.bracketDepth <= 0) {
                state.inSquareBlock = false;
                state.localState = null;
                return "square-bracket";
              }
            }
            if(current === "[") {
              state.bracketDepth++;
            }
            if(state.bracketDepth <= 0) {
              state.inSquareBlock = false;
              state.localState = null;
            }
          }
          
          return style;
        }
      } else {
        if(stream.sol() && stream.match(/\/\/.*/)) {
          return "comment";
        } else if (stream.match(/\s\/\/.*/)) {
          return "comment";
        }
        if(stream.peek() === "[") {
          state.bracketDepth = 1;
          state.inSquareBlock = true;
          state.localState = CodeMirror.startState(jsMode);
          stream.next();
          return "square-bracket";
        }
    
        // if(stream.match(/^\w*(?=\()/)) {
        //   return "def";
        // }
    
        if(stream.match(/^(async |)[a-zA-Z0-9$_]+ ?\([^\)]*\) *=> */)) {
          state.localState = CodeMirror.startState(jsMode);
          state.inFunction = true;
          state.functionIndent = stream.indentation();
          return "def";
        }
    
        if(stream.match('\\[') || stream.match('\\]')) {
          return "escaped-char";
        }
        if(stream.match('{') || stream.match('}')) {
          return "curly-bracket";
        }
        if(stream.match(/\$output\b/) || stream.match(/\$preprocess\b/)) {
          return "special-list-name";
        }
        stream.next();
        return null;
      }
    }
    
    return {
      startState: function() {
        return {
          inSquareBlock: false,
          localState: null,
          bracketDepth: 0,
          inFunction: false,
          functionIndent: 0,
        };
      },
      token: token,
      lineComment: "//",
      fold: "indent",
    };
  });

  // let systemIsInDarkMode = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
  // window.codeMirrorModelTextEditor = CodeMirror.fromTextArea(document.body.querySelector("#input"), {
  //   lineNumbers: true,
  //   foldGutter: true,
  //   extraKeys: {
  //     //"Ctrl-Q": cm => cm.foldCode(cm.getCursor()),
  //     //"Ctrl-Y": cm => CodeMirror.commands.foldAll(cm),
  //     //"Ctrl-I": cm => CodeMirror.commands.unfoldAll(cm),
  //   },
  //   gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
  //   tabSize: 2,
  //   indentUnit: 2,
  //   indentWithTabs: false,
  //   matchBrackets: true,
  //   mode: "perchancelists",
  //   styleActiveLine: true,
  //   // mode: "text",
  //   lineWrapping:false,
  //   theme: systemIsInDarkMode ? "one-dark" : "one-light",
  //   keyMap: "sublime",
  // });
  // window.codeMirrorModelTextEditor.setOption("mode", "perchancelists");





  // OLD:
  // CodeMirror.defineMode("perchancelists", function(config) {

  //   var jsMode = CodeMirror.getMode(config, "javascript");

  //   function token(stream, state) {    
  //     if(state.inSquareBlock && state.inFunction) console.error("invalid state - cannot be both in function and square block at same time");
  //     if(stream.string.length > 50000) { // Consume the entire line if it's too long
  //       stream.skipToEnd();
  //       return null;  // No styling applied
  //     }

  //     if(state.inSquareBlock || state.inFunction) {
  //       var style = jsMode.token(stream, state.localState);
  //       if (style === "string" || style === "string-2" || style === "comment") {
  //         return style;
  //       }
  //       var current = stream.current();

  //       if(state.inFunction) {
  //         if(state.inSquareBlock) console.error("inSquareBlock while also inFunction");
          
  //         if(stream.indentation() <= state.functionIndent) {
  //           state.localState = null;
  //           state.inFunction = false;
  //           stream.backUp(stream.current().length); // Rewind to the beginning of the line (important)
  //           return null;
  //         }
  //       } else if(state.inSquareBlock) {
  //         if(state.inFunction) console.error("inFunction while also inSquareBlock");
    
  //         if (current === "]") { // note: this square bracket is not inside a string/regex, since we early-returned above in those cases
  //           state.bracketDepth--;
  //           if (state.bracketDepth <= 0) {
  //             state.inSquareBlock = false;
  //             state.localState = null;
  //             return "square-bracket";
  //           }
  //         }
    
  //         if(current === "[") {
  //           state.bracketDepth++;
  //         }

  //         if(state.bracketDepth <= 0) {
  //           state.inSquareBlock = false;
  //           state.localState = null;
  //         }
  //       }

  //       return style;
  //     } else {
  //       if(stream.match(/\$output\b/) || stream.match(/\$preprocess\b/)) {
  //         return "special-list-name";
  //       }
  //       if(stream.sol() && stream.match(/\/\/.*/)) {
  //         return "comment";
  //       } else if (stream.match(/\s\/\/.*/)) {
  //         return "comment";
  //       }
  //       if(stream.peek() === "[") {
  //         state.bracketDepth = 1;
  //         state.inSquareBlock = true;
  //         state.localState = CodeMirror.startState(jsMode);
  //         stream.next();
  //         return "square-bracket";
  //       }

  //       if(stream.match(/^[a-zA-Z0-9$_]\w*(?=\()/)) {
  //         return "def";
  //       }

  //       if(stream.match(/\([^\)]*\) =>/)) {
  //         state.localState = CodeMirror.startState(jsMode);
  //         state.inFunction = true;
  //         state.functionIndent = stream.indentation();
  //         return "javascript";
  //       }

  //       if(stream.match('\\[') || stream.match('\\]')) {
  //         return "escaped-char";
  //       }
  //       if(stream.match('{') || stream.match('}')) {
  //         return "curly-bracket";
  //       }
  //       stream.next();
  //       return null;
  //     }
  //   }

  //   return {
  //     startState: function() {
  //       return {
  //         inSquareBlock: false,
  //         localState: null,
  //         bracketDepth: 0,
  //         inFunction: false,
  //         functionIndent: 0,
  //       };
  //     },
  //     token: token,
  //     lineComment: "//",
  //     fold: "indent",
  //   };
  // });

} catch(e) { console.error(e); }
</script>

        <!-- LIBS -->
        <script>
/*! Split.js - v1.6.5 */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Split=t()}(this,(function(){"use strict";var e="undefined"!=typeof window?window:null,t=null===e,n=t?void 0:e.document,i=function(){return!1},r=t?"calc":["","-webkit-","-moz-","-o-"].filter((function(e){var t=n.createElement("div");return t.style.cssText="width:"+e+"calc(9px)",!!t.style.length})).shift()+"calc",s=function(e){return"string"==typeof e||e instanceof String},o=function(e){if(s(e)){var t=n.querySelector(e);if(!t)throw new Error("Selector "+e+" did not match a DOM element");return t}return e},a=function(e,t,n){var i=e[t];return void 0!==i?i:n},u=function(e,t,n,i){if(t){if("end"===i)return 0;if("center"===i)return e/2}else if(n){if("start"===i)return 0;if("center"===i)return e/2}return e},l=function(e,t){var i=n.createElement("div");return i.className="gutter gutter-"+t,i},c=function(e,t,n){var i={};return s(t)?i[e]=t:i[e]=r+"("+t+"% - "+n+"px)",i},h=function(e,t){var n;return(n={})[e]=t+"px",n};return function(r,s){if(void 0===s&&(s={}),t)return{};var f,d,v,m,g,p,y=r;Array.from&&(y=Array.from(y));var z=o(y[0]).parentNode,S=getComputedStyle?getComputedStyle(z):null,b=S?S.flexDirection:null,E=a(s,"sizes")||y.map((function(){return 100/y.length})),_=a(s,"minSize",100),L=Array.isArray(_)?_:y.map((function(){return _})),w=a(s,"maxSize",1/0),x=Array.isArray(w)?w:y.map((function(){return w})),O=a(s,"expandToMin",!1),A=a(s,"gutterSize",10),k=a(s,"gutterAlign","center"),C=a(s,"snapOffset",30),M=Array.isArray(C)?C:y.map((function(){return C})),U=a(s,"dragInterval",1),D=a(s,"direction","horizontal"),B=a(s,"cursor","horizontal"===D?"col-resize":"row-resize"),T=a(s,"gutter",l),j=a(s,"elementStyle",c),F=a(s,"gutterStyle",h);function R(e,t,n,i){var r=j(f,t,n,i);Object.keys(r).forEach((function(t){e.style[t]=r[t]}))}function N(){return p.map((function(e){return e.size}))}function q(e){return"touches"in e?e.touches[0][d]:e[d]}function H(e){var t=p[this.a],n=p[this.b],i=t.size+n.size;t.size=e/this.size*i,n.size=i-e/this.size*i,R(t.element,t.size,this._b,t.i),R(n.element,n.size,this._c,n.i)}function I(e){var t,n=p[this.a],r=p[this.b];this.dragging&&(t=q(e)-this.start+(this._b-this.dragOffset),U>1&&(t=Math.round(t/U)*U),t<=n.minSize+n.snapOffset+this._b?t=n.minSize+this._b:t>=this.size-(r.minSize+r.snapOffset+this._c)&&(t=this.size-(r.minSize+this._c)),t>=n.maxSize-n.snapOffset+this._b?t=n.maxSize+this._b:t<=this.size-(r.maxSize-r.snapOffset+this._c)&&(t=this.size-(r.maxSize+this._c)),H.call(this,t),a(s,"onDrag",i)(N()))}function W(){var e=p[this.a].element,t=p[this.b].element,n=e.getBoundingClientRect(),i=t.getBoundingClientRect();this.size=n[f]+i[f]+this._b+this._c,this.start=n[v],this.end=n[m]}function X(e){var t=function(e){if(!getComputedStyle)return null;var t=getComputedStyle(e);if(!t)return null;var n=e[g];return 0===n?null:n-="horizontal"===D?parseFloat(t.paddingLeft)+parseFloat(t.paddingRight):parseFloat(t.paddingTop)+parseFloat(t.paddingBottom)}(z);if(null===t)return e;if(L.reduce((function(e,t){return e+t}),0)>t)return e;var n=0,i=[],r=e.map((function(r,s){var o=t*r/100,a=u(A,0===s,s===e.length-1,k),l=L[s]+a;return o<l?(n+=l-o,i.push(0),l):(i.push(o-l),o)}));return 0===n?e:r.map((function(e,r){var s=e;if(n>0&&i[r]-n>0){var o=Math.min(n,i[r]-n);n-=o,s=e-o}return s/t*100}))}function Y(){var t=p[this.a].element,r=p[this.b].element;this.dragging&&a(s,"onDragEnd",i)(N()),this.dragging=!1,e.removeEventListener("mouseup",this.stop),e.removeEventListener("touchend",this.stop),e.removeEventListener("touchcancel",this.stop),e.removeEventListener("mousemove",this.move),e.removeEventListener("touchmove",this.move),this.stop=null,this.move=null,t.removeEventListener("selectstart",i),t.removeEventListener("dragstart",i),r.removeEventListener("selectstart",i),r.removeEventListener("dragstart",i),t.style.userSelect="",t.style.webkitUserSelect="",t.style.MozUserSelect="",t.style.pointerEvents="",r.style.userSelect="",r.style.webkitUserSelect="",r.style.MozUserSelect="",r.style.pointerEvents="",this.gutter.style.cursor="",this.parent.style.cursor="",n.body.style.cursor=""}function G(t){if(!("button"in t)||0===t.button){var r=p[this.a].element,o=p[this.b].element;this.dragging||a(s,"onDragStart",i)(N()),t.preventDefault(),this.dragging=!0,this.move=I.bind(this),this.stop=Y.bind(this),e.addEventListener("mouseup",this.stop),e.addEventListener("touchend",this.stop),e.addEventListener("touchcancel",this.stop),e.addEventListener("mousemove",this.move),e.addEventListener("touchmove",this.move),r.addEventListener("selectstart",i),r.addEventListener("dragstart",i),o.addEventListener("selectstart",i),o.addEventListener("dragstart",i),r.style.userSelect="none",r.style.webkitUserSelect="none",r.style.MozUserSelect="none",r.style.pointerEvents="none",o.style.userSelect="none",o.style.webkitUserSelect="none",o.style.MozUserSelect="none",o.style.pointerEvents="none",this.gutter.style.cursor=B,this.parent.style.cursor=B,n.body.style.cursor=B,W.call(this),this.dragOffset=q(t)-this.end}}"horizontal"===D?(f="width",d="clientX",v="left",m="right",g="clientWidth"):"vertical"===D&&(f="height",d="clientY",v="top",m="bottom",g="clientHeight"),E=X(E);var J=[];function K(e){var t=e.i===J.length,n=t?J[e.i-1]:J[e.i];W.call(n);var i=t?n.size-e.minSize-n._c:e.minSize+n._b;H.call(n,i)}return(p=y.map((function(e,t){var n,i={element:o(e),size:E[t],minSize:L[t],maxSize:x[t],snapOffset:M[t],i:t};if(t>0&&((n={a:t-1,b:t,dragging:!1,direction:D,parent:z})._b=u(A,t-1==0,!1,k),n._c=u(A,!1,t===y.length-1,k),"row-reverse"===b||"column-reverse"===b)){var r=n.a;n.a=n.b,n.b=r}if(t>0){var s=T(t,D,i.element);!function(e,t,n){var i=F(f,t,n);Object.keys(i).forEach((function(t){e.style[t]=i[t]}))}(s,A,t),n._a=G.bind(n),s.addEventListener("mousedown",n._a),s.addEventListener("touchstart",n._a),z.insertBefore(s,i.element),n.gutter=s}return R(i.element,i.size,u(A,0===t,t===y.length-1,k),t),t>0&&J.push(n),i}))).forEach((function(e){var t=e.element.getBoundingClientRect()[f];t<e.minSize&&(O?K(e):e.minSize=t)})),{setSizes:function(e){var t=X(e);t.forEach((function(e,n){if(n>0){var i=J[n-1],r=p[i.a],s=p[i.b];r.size=t[n-1],s.size=e,R(r.element,r.size,i._b,r.i),R(s.element,s.size,i._c,s.i)}}))},getSizes:N,collapse:function(e){K(p[e])},destroy:function(e,t){J.forEach((function(n){if(!0!==t?n.parent.removeChild(n.gutter):(n.gutter.removeEventListener("mousedown",n._a),n.gutter.removeEventListener("touchstart",n._a)),!0!==e){var i=j(f,n.a.size,n._b);Object.keys(i).forEach((function(e){p[n.a].element.style[e]="",p[n.b].element.style[e]=""}))}}))},parent:z,pairs:J}}}));
//# sourceMappingURL=split.min.js.map
</script>
        <script>
function Store(name) {
  this.name = name;
  try {
    this.data = JSON.parse( localStorage.getItem(this.name+"-storage") ) || {};
  } catch(e) {
    console.error("Couldn't parse local storage data:", e);
    this.data = {};
  }
  //this.data = JSON.parse( LZString.decompress(localStorage.getItem(this.name+"-storage")) ) || {};

  this.save = function(key, value) {
    try {
      localStorage.setItem(this.name+"-storage", JSON.stringify(this.data) );
    } catch(e) {
      console.error("Failed to save data to local storage:", e);
    }
    //localStorage.setItem(this.name+"-storage", LZString.compress(JSON.stringify(this.data)) );
  }
  return this;
}

</script>
        <script>
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.DOMPurify=t()}(this,function(){"use strict";function e(e,t){for(var n=t.length;n--;)"string"==typeof t[n]&&(t[n]=t[n].toLowerCase()),e[t[n]]=!0;return e}function t(e){var t={},n=void 0;for(n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t}function n(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function o(){var x=arguments.length>0&&void 0!==arguments[0]?arguments[0]:A(),S=function(e){return o(e)};if(S.version="1.0.2",S.removed=[],!x||!x.document||9!==x.document.nodeType)return S.isSupported=!1,S;var k=x.document,E=!1,w=!1,O=x.document,L=x.DocumentFragment,M=x.HTMLTemplateElement,N=x.Node,_=x.NodeFilter,D=x.NamedNodeMap,R=void 0===D?x.NamedNodeMap||x.MozNamedAttrMap:D,C=x.Text,F=x.Comment,z=x.DOMParser,H=x.XMLHttpRequest,I=void 0===H?x.XMLHttpRequest:H,j=x.encodeURI,U=void 0===j?x.encodeURI:j;if("function"==typeof M){var W=O.createElement("template");W.content&&W.content.ownerDocument&&(O=W.content.ownerDocument)}var q=O,G=q.implementation,P=q.createNodeIterator,B=q.getElementsByTagName,X=q.createDocumentFragment,V=k.importNode,Y={};S.isSupported=G&&void 0!==G.createHTMLDocument&&9!==O.documentMode;var K=p,$=f,J=h,Q=g,Z=v,ee=b,te=y,ne=null,oe=e({},[].concat(n(r),n(i),n(a),n(l),n(s))),re=null,ie=e({},[].concat(n(c),n(d),n(u),n(m))),ae=null,le=null,se=!0,ce=!0,de=!1,ue=!1,me=!1,pe=!1,fe=!1,he=!1,ge=!1,ye=!1,ve=!1,be=!0,Te=!0,Ae={},xe=e({},["audio","head","math","script","style","template","svg","video"]),Se=e({},["audio","video","img","source","image"]),ke=e({},["alt","class","for","id","label","name","pattern","placeholder","summary","title","value","style","xmlns"]),Ee=null,we=O.createElement("form"),Oe=function(o){"object"!==(void 0===o?"undefined":T(o))&&(o={}),ne="ALLOWED_TAGS"in o?e({},o.ALLOWED_TAGS):oe,re="ALLOWED_ATTR"in o?e({},o.ALLOWED_ATTR):ie,ae="FORBID_TAGS"in o?e({},o.FORBID_TAGS):{},le="FORBID_ATTR"in o?e({},o.FORBID_ATTR):{},Ae="USE_PROFILES"in o&&o.USE_PROFILES,se=!1!==o.ALLOW_ARIA_ATTR,ce=!1!==o.ALLOW_DATA_ATTR,de=o.ALLOW_UNKNOWN_PROTOCOLS||!1,ue=o.SAFE_FOR_JQUERY||!1,me=o.SAFE_FOR_TEMPLATES||!1,pe=o.WHOLE_DOCUMENT||!1,ge=o.RETURN_DOM||!1,ye=o.RETURN_DOM_FRAGMENT||!1,ve=o.RETURN_DOM_IMPORT||!1,he=o.FORCE_BODY||!1,be=!1!==o.SANITIZE_DOM,Te=!1!==o.KEEP_CONTENT,te=o.ALLOWED_URI_REGEXP||te,me&&(ce=!1),ye&&(ge=!0),Ae&&(ne=e({},[].concat(n(s))),re=[],!0===Ae.html&&(e(ne,r),e(re,c)),!0===Ae.svg&&(e(ne,i),e(re,d),e(re,m)),!0===Ae.svgFilters&&(e(ne,a),e(re,d),e(re,m)),!0===Ae.mathMl&&(e(ne,l),e(re,u),e(re,m))),o.ADD_TAGS&&(ne===oe&&(ne=t(ne)),e(ne,o.ADD_TAGS)),o.ADD_ATTR&&(re===ie&&(re=t(re)),e(re,o.ADD_ATTR)),o.ADD_URI_SAFE_ATTR&&e(ke,o.ADD_URI_SAFE_ATTR),Te&&(ne["#text"]=!0),Object&&"freeze"in Object&&Object.freeze(o),Ee=o},Le=function(e){S.removed.push({element:e});try{e.parentNode.removeChild(e)}catch(t){e.outerHTML=""}},Me=function(e,t){S.removed.push({attribute:t.getAttributeNode(e),from:t}),t.removeAttribute(e)},Ne=function(e){var t=void 0,n=void 0;if(he&&(e="<remove></remove>"+e),w){try{e=U(e)}catch(e){}var o=new I;o.responseType="document",o.open("GET","data:text/html;charset=utf-8,"+e,!1),o.send(null),t=o.response}if(E)try{t=(new z).parseFromString(e,"text/html")}catch(e){}return t&&t.documentElement||((n=(t=G.createHTMLDocument("")).body).parentNode.removeChild(n.parentNode.firstElementChild),n.outerHTML=e),B.call(t,pe?"html":"body")[0]};S.isSupported&&function(){var e=Ne('<svg><g onload="this.parentNode.remove()"></g></svg>');e.querySelector("svg")||(w=!0);try{(e=Ne('<svg><p><style><img src="</style><img src=x onerror=alert(1)//">')).querySelector("svg img")&&(E=!0)}catch(e){}}();var _e=function(e){return P.call(e.ownerDocument||e,e,_.SHOW_ELEMENT|_.SHOW_COMMENT|_.SHOW_TEXT,function(){return _.FILTER_ACCEPT},!1)},De=function(e){return!(e instanceof C||e instanceof F)&&!("string"==typeof e.nodeName&&"string"==typeof e.textContent&&"function"==typeof e.removeChild&&e.attributes instanceof R&&"function"==typeof e.removeAttribute&&"function"==typeof e.setAttribute)},Re=function(e){return"object"===(void 0===N?"undefined":T(N))?e instanceof N:e&&"object"===(void 0===e?"undefined":T(e))&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName},Ce=function(e,t,n){Y[e]&&Y[e].forEach(function(e){e.call(S,t,n,Ee)})},Fe=function(e){var t=void 0;if(Ce("beforeSanitizeElements",e,null),De(e))return Le(e),!0;var n=e.nodeName.toLowerCase();if(Ce("uponSanitizeElement",e,{tagName:n,allowedTags:ne}),!ne[n]||ae[n]){if(Te&&!xe[n]&&"function"==typeof e.insertAdjacentHTML)try{e.insertAdjacentHTML("AfterEnd",e.innerHTML)}catch(e){}return Le(e),!0}return!ue||e.firstElementChild||e.content&&e.content.firstElementChild||!/</g.test(e.textContent)||(S.removed.push({element:e.cloneNode()}),e.innerHTML=e.textContent.replace(/</g,"&lt;")),me&&3===e.nodeType&&(t=(t=(t=e.textContent).replace(K," ")).replace($," "),e.textContent!==t&&(S.removed.push({element:e.cloneNode()}),e.textContent=t)),Ce("afterSanitizeElements",e,null),!1},ze=function(e){var t=void 0,n=void 0,o=void 0,r=void 0,i=void 0,a=void 0,l=void 0;if(Ce("beforeSanitizeAttributes",e,null),a=e.attributes){var s={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:re};for(l=a.length;l--;){if(t=a[l],n=t.name,o=t.value.trim(),r=n.toLowerCase(),s.attrName=r,s.attrValue=o,s.keepAttr=!0,Ce("uponSanitizeAttribute",e,s),o=s.attrValue,"name"===r&&"IMG"===e.nodeName&&a.id)i=a.id,a=Array.prototype.slice.apply(a),Me("id",e),Me(n,e),a.indexOf(i)>l&&e.setAttribute("id",i.value);else{if("INPUT"===e.nodeName&&"type"===r&&"file"===o&&(re[r]||!le[r]))continue;"id"===n&&e.setAttribute(n,""),Me(n,e)}if(s.keepAttr&&(!be||"id"!==r&&"name"!==r||!(o in x||o in O||o in we))){if(me&&(o=(o=o.replace(K," ")).replace($," ")),ce&&J.test(r));else if(se&&Q.test(r));else{if(!re[r]||le[r])continue;if(ke[r]);else if(te.test(o.replace(ee,"")));else if("src"!==r&&"xlink:href"!==r||0!==o.indexOf("data:")||!Se[e.nodeName.toLowerCase()]){if(de&&!Z.test(o.replace(ee,"")));else if(o)continue}else;}try{e.setAttribute(n,o),S.removed.pop()}catch(e){}}}Ce("afterSanitizeAttributes",e,null)}},He=function e(t){var n=void 0,o=_e(t);for(Ce("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)Ce("uponSanitizeShadowNode",n,null),Fe(n)||(n.content instanceof L&&e(n.content),ze(n));Ce("afterSanitizeShadowDOM",t,null)};return S.sanitize=function(e,t){var n=void 0,o=void 0,r=void 0,i=void 0,a=void 0;if(e||(e="\x3c!--\x3e"),"string"!=typeof e&&!Re(e)){if("function"!=typeof e.toString)throw new TypeError("toString is not a function");e=e.toString()}if(!S.isSupported){if("object"===T(x.toStaticHTML)||"function"==typeof x.toStaticHTML){if("string"==typeof e)return x.toStaticHTML(e);if(Re(e))return x.toStaticHTML(e.outerHTML)}return e}if(fe||Oe(t),S.removed=[],e instanceof N)1===(o=(n=Ne("\x3c!--\x3e")).ownerDocument.importNode(e,!0)).nodeType&&"BODY"===o.nodeName?n=o:n.appendChild(o);else{if(!ge&&!pe&&-1===e.indexOf("<"))return e;if(!(n=Ne(e)))return ge?null:""}he&&Le(n.firstChild);for(var l=_e(n);r=l.nextNode();)3===r.nodeType&&r===i||Fe(r)||(r.content instanceof L&&He(r.content),ze(r),i=r);if(ge){if(ye)for(a=X.call(n.ownerDocument);n.firstChild;)a.appendChild(n.firstChild);else a=n;return ve&&(a=V.call(k,a,!0)),a}return pe?n.outerHTML:n.innerHTML},S.setConfig=function(e){Oe(e),fe=!0},S.clearConfig=function(){Ee=null,fe=!1},S.addHook=function(e,t){"function"==typeof t&&(Y[e]=Y[e]||[],Y[e].push(t))},S.removeHook=function(e){Y[e]&&Y[e].pop()},S.removeHooks=function(e){Y[e]&&(Y[e]=[])},S.removeAllHooks=function(){Y={}},S}var r=["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"],i=["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","audio","canvas","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","video","view","vkern"],a=["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feMerge","feMergeNode","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence"],l=["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmuliscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mpspace","msqrt","mystyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover"],s=["#text"],c=["accept","action","align","alt","autocomplete","background","bgcolor","border","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","coords","datetime","default","dir","disabled","download","enctype","face","for","headers","height","hidden","high","href","hreflang","id","ismap","label","lang","list","loop","low","max","maxlength","media","method","min","multiple","name","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","type","usemap","valign","value","width","xmlns"],d=["accent-height","accumulate","additivive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","tabindex","targetx","targety","transform","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"],u=["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"],m=["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"],p=/\{\{[\s\S]*|[\s\S]*\}\}/gm,f=/<%[\s\S]*|[\s\S]*%>/gm,h=/^data-[\-\w.\u00B7-\uFFFF]/,g=/^aria-[\-\w]+$/,y=/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,v=/^(?:\w+script|data):/i,b=/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g,T="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},A=function(){return"undefined"==typeof window?null:window};return o()});
//# sourceMappingURL=purify.min.js.map

</script>


        <!-- CSS LOADING SPINNER -->
        <style>
          .ldspmzjfhueifssge-ring {
            display: inline-block;
            position: relative;
            width: 64px;
            height: 64px;
          }
          .ldspmzjfhueifssge-ring div {
            box-sizing: border-box;
            display: block;
            position: absolute;
            width: 51px;
            height: 51px;
            margin: 6px;
            border: 6px solid #444;
            border-radius: 50%;
            animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
            border-color: #444 transparent transparent transparent;
          }
          .ldspmzjfhueifssge-ring div:nth-child(1) {
            animation-delay: -0.45s;
          }
          .ldspmzjfhueifssge-ring div:nth-child(2) {
            animation-delay: -0.3s;
          }
          .ldspmzjfhueifssge-ring div:nth-child(3) {
            animation-delay: -0.15s;
          }
          @keyframes lds-ring {
            0% {
              transform: rotate(0deg);
            }
            100% {
              transform: rotate(360deg);
            }
          }
          @media (prefers-color-scheme: dark) {
            #outputLoadSpinner {
              filter: invert(1);
            }
          }
        </style>

        <script>
          let thisIsNotAnOldCachedPageResolver;
          window.thisIsNotAnOldCachedPagePromise = new Promise(r => thisIsNotAnOldCachedPageResolver=r);
          // CloudFlare sometimes has cache purging delays, and these can really mess things up (e.g. make it look like you've lost hours of work).
          // We check the `age` header of this document, and if it's older than the last save time of this generator, then we load a cache-busted URL
          // and then remove the added cacheBust string with history.replaceState
          (async function() {
            if(navigator.webdriver) return; // just in case this is what's confusing the Google crawler - RE the title bug
            if(window.location.href.includes("__cacheBust")) {
              thisIsNotAnOldCachedPageResolver(true);
              return; // no need to run this check if cache is already busted
            }

            let imports = window.js0nparse(decodeURI(document.querySelector("#imported-generator-names").textContent));
            let clientHtmlServerRenderTime = Number(document.querySelector("#this-html-server-render-time").textContent);
            
            await new Promise(r => setTimeout(r, 10)); // give the page a chance to load a bit before checking transferSize
            let transferSize = 1;
            try { transferSize = performance.getEntriesByType("navigation")[0].transferSize; } catch(e) {}
            console.debug("transferSize (likely partial):", transferSize);
            if(isNaN(transferSize)) transferSize = 1;
            // transferSize will be zero if it was loaded from browser cache, assuming the user's browser supports the API

            let checkStartTime = Date.now();
            let weHaveAnOldVersionOfThisGen = await fetch(`https://perchance.org/api/clearCacheIfGeneratorOrImportsHaveBeenUpdated?generatorName=${window.location.pathname.slice(1)}&importedGeneratorNames=${imports.join(",")}&clientHtmlServerRenderTime=${clientHtmlServerRenderTime}&transferSize=${transferSize}&queryParamString=${encodeURIComponent(window.location.search)}&__cacheBust=${Math.random()}`).then(r => r.json()).catch(e => { console.error(e); return "network-error"; });
            if(weHaveAnOldVersionOfThisGen === "network-error") {
              if(app.userOwnsThisGenerator) {
                alert("There was a network error while trying to determine whether the latest generator data has been loaded. You may be viewing/editing an older copy of the data. Try refreshing the page.");
              }
            } else if(weHaveAnOldVersionOfThisGen) {
              console.debug("This is an old version of this generator.");
              if(Date.now()-checkStartTime < 10000) {
                console.debug("Doing cache bust reload now...");
                let url = new URL(window.location.href);
                url.searchParams.set("__cacheBust", Math.random());
                window.location.href = url.href;  
              } else if(app.userOwnsThisGenerator) { 
                // don't want to disrupt them in case they're editing, but still need to let them know:
                alert("This is an old version of this generator. Please refresh the page to get the latest version.");
              }
            } else {
              thisIsNotAnOldCachedPageResolver(true);
            }
          })();
          if(location.href.includes("__cacheBust")) {
            window.needToBustCacheOfIframeOnInitialLoad = true;
            let url = new URL(window.location.href);
            url.searchParams.delete("__cacheBust");
            let newPath = url.href.replace(/^https:\/\/perchance\.org/, "");
            history.replaceState({}, "", newPath);
          }
        </script>

        <div id="editorLoadSpinnerEl" style="z-index:10; display:none; pointer-events:none; position:fixed; top:0; right:0; bottom:0; left:0; justify-content:center; align-items:center;"><div class="ldspmzjfhueifssge-ring"><div></div><div></div><div></div><div></div></div></div>


        <style>
/* NOTE: Changes marked with "CHANGE" */

/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */

/**
 * 1. Set default font family to sans-serif.
 * 2. Prevent iOS and IE text size adjust after device orientation change,
 *    without disabling user zoom.
 */

html {
  font-family: sans-serif; /* 1 */
  -ms-text-size-adjust: 100%; /* 2 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/**
 * Remove default margin.
 */

body {
  margin: 0;
}

/* HTML5 display definitions
   ========================================================================== */

/**
 * Correct `block` display not defined for any HTML5 element in IE 8/9.
 * Correct `block` display not defined for `details` or `summary` in IE 10/11
 * and Firefox.
 * Correct `block` display not defined for `main` in IE 11.
 */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
/* summary, CHANGE */
section {
  display: block;
}

/**
 * 1. Correct `inline-block` display not defined in IE 8/9.
 * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
 */

audio,
canvas,
progress,
video {
  display: inline-block; /* 1 */
  vertical-align: baseline; /* 2 */
}

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */

audio:not([controls]) {
  display: none;
  height: 0;
}

/**
 * Address `[hidden]` styling not present in IE 8/9/10.
 * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
 */

[hidden] {
  display: none !important; /* EDIT: added `!important` so you can e.g. have inline display:flex, and yet still toggle hidden/unhidden with `el.hidden = trueOrFalse` */
}
template {
  display: none;
}

/* Links
   ========================================================================== */

/**
 * Remove the gray background color from active links in IE 10.
 */

a {
  background-color: transparent;
}

/**
 * Improve readability of focused elements when they are also in an
 * active/hover state.
 */

a:active,
a:hover {
  outline: 0;
}

/* Text-level semantics
   ========================================================================== */

/**
 * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
 */

abbr[title] {
  border-bottom: 1px dotted;
}

/**
 * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
 */

b,
strong {
  font-weight: bold;
}

/**
 * Address styling not present in Safari and Chrome.
 */

dfn {
  font-style: italic;
}

/**
 * Address variable `h1` font-size and margin within `section` and `article`
 * contexts in Firefox 4+, Safari, and Chrome.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/**
 * Address styling not present in IE 8/9.
 */

mark {
  background: #ff0;
  color: #000;
}

/**
 * Address inconsistent and variable font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sup {
  top: -0.5em;
}

sub {
  bottom: -0.25em;
}

/* Embedded content
   ========================================================================== */

/**
 * Remove border when inside `a` element in IE 8/9/10.
 */

img {
  border: 0;
}

/**
 * Correct overflow not hidden in IE 9/10/11.
 */

svg:not(:root) {
  overflow: hidden;
}

/* Grouping content
   ========================================================================== */

/**
 * Address margin not present in IE 8/9 and Safari.
 */

figure {
  margin: 1em 40px;
}

/**
 * Address differences between Firefox and other browsers.
 */

hr {
  box-sizing: content-box;
  height: 0;
}

/**
 * Contain overflow in all browsers.
 */

pre {
  overflow: auto;
}

/**
 * Address odd `em`-unit font size rendering in all browsers.
 */

code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em;
}

/* Forms
   ========================================================================== */

/**
 * Known limitation: by default, Chrome and Safari on OS X allow very limited
 * styling of `select`, unless a `border` property is set.
 */

/**
 * 1. Correct color not being inherited.
 * 2. Correct font properties not being inherited.
 * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
 */

button:not([disabled]), input:not([disabled]), optgroup:not([disabled]), select:not([disabled]), textarea:not([disabled]) {
  color: inherit;
}



button,
input,
optgroup,
select,
textarea {
  font: inherit; /* 2 */
  margin: 0; /* 3 */
}

/**
 * Address `overflow` set to `hidden` in IE 8/9/10/11.
 */

button {
  overflow: visible;
}

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
 * Correct `select` style inheritance in Firefox.
 */

button,
select {
  text-transform: none;
}

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 */

button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button; /* 2 */
  cursor: pointer; /* 3 */
}

/**
 * Re-set default cursor for disabled elements.
 */

button[disabled],
html input[disabled] {
  cursor: default;
}

/**
 * Remove inner padding and border in Firefox 4+.
 */

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0;
}

/**
 * Address Firefox 4+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */

input {
  line-height: normal;
}

/**
 * It's recommended that you don't attempt to style these elements.
 * Firefox's implementation doesn't respect box-sizing, padding, or width.
 *
 * 1. Address box sizing set to `content-box` in IE 8/9/10.
 * 2. Remove excess padding in IE 8/9/10.
 */

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Fix the cursor style for Chrome's increment/decrement buttons. For certain
 * `font-size` values of the `input`, it causes the cursor style of the
 * decrement button to change from `default` to `text`.
 */

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
 */

input[type="search"] {
  -webkit-appearance: textfield; /* 1 */
  box-sizing: content-box; /* 2 */
}

/**
 * Remove inner padding and search cancel button in Safari and Chrome on OS X.
 * Safari (but not Chrome) clips the cancel button when the search input has
 * padding (and `textfield` appearance).
 */

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * Define consistent border, margin, and padding.
 */

fieldset {
  border: 1px solid #c0c0c0;
  margin: 0 2px;
  padding: 0.35em 0.625em 0.75em;
}

/**
 * 1. Correct `color` not being inherited in IE 8/9/10/11.
 * 2. Remove padding so people aren't caught out if they zero out fieldsets.
 */

legend {
  border: 0; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Remove default vertical scrollbar in IE 8/9/10/11.
 */

textarea {
  overflow: auto;
}

/**
 * Don't inherit the `font-weight` (applied by a rule above).
 * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
 */

optgroup {
  font-weight: bold;
}

/* Tables
   ========================================================================== */

/**
 * Remove most spacing between table cells.
 */

table {
  border-collapse: collapse;
  border-spacing: 0;
}

td,
th {
  padding: 0;
}

</style><style>
html { 
    color: #222;
    font-size: 1em;
    line-height: 1.4;
}

/*
 * A better looking default horizontal rule
 */
hr {
    display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;
}

/*
 * Remove the gap between audio, canvas, iframes,
 * images, videos and the bottom of their containers:
 * https://github.com/h5bp/html5-boilerplate/issues/440
 */

audio,
canvas,
iframe,
img,
svg,
video {
    vertical-align: middle;
}

/*
 * Remove default fieldset styles.
 */

fieldset {
    border: 0;
    margin: 0;
    padding: 0;
}

/*
 * Allow only vertical resizing of textareas.
 */

textarea {
    resize: vertical;
}


/* ==========================================================================
   Author's custom styles
   ========================================================================== */


html, body {
  height: 100%;
  overflow: hidden;
}

body {
  background-color: #f6f6f6;
  box-sizing: border-box;
  font-family: 'Cousine', monospace;
  line-height: 1.05rem;
  font-size: 0.75rem;
  color: #050505;
}

[hidden] {
  display: none !important;
}


/* =================================================== */
/* ================= DARK MODE STUFF ================= */
/* =================================================== */



/* button {
  padding: 0.135em 0.5em;
  border: 1px solid #afafaf;
  background: linear-gradient(to bottom, rgb(245, 245, 245) 0%, rgb(236, 236, 236) 47%, rgb(223, 223, 223) 100%);
  border-radius: 1px;
}
button:hover {
  border-color: #909090;
} */

</style><style type="text/css">@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/hebrew/400/normal.woff2);unicode-range:U+0590-05FF,U+200C-2010,U+20AA,U+25CC,U+FB1D-FB4F;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/cyrillic/400/normal.woff2);unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/greek-ext/400/normal.woff2);unicode-range:U+1F00-1FFF;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/latin-ext/400/normal.woff2);unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/vietnamese/400/normal.woff2);unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/greek/400/normal.woff2);unicode-range:U+0370-03FF;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/latin/400/normal.woff2);unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;font-display:swap;}@font-face {font-family:Cousine;font-style:normal;font-weight:400;src:url(/cf-fonts/s/cousine/5.0.18/cyrillic-ext/400/normal.woff2);unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;font-display:swap;}</style>
        <style>
          #menuBarEl { background:#f6f6f6; }
          #editorEl { background:#f6f6f6; }
          @media (prefers-color-scheme: dark) { 
            #menuBarEl { background:#282c33; }
            #editorEl { background:#282c33; }
          }

          #menuBarEl {
            border-bottom: 1px solid #cbcbcb;
          }
          @media (prefers-color-scheme: dark) { 
            #menuBarEl {
              border-bottom: 1px solid #3d3d3d;
            }
          }
          :root {
            --menu-bar-item-backdrop-filter: brightness(0.9);
            --menu-bar-item-backdrop-filter-hover: brightness(0.84);
            --menu-bar-item-backdrop-filter-dark: brightness(0.75);
            --menu-bar-item-backdrop-filter-hover-dark: brightness(0.6);
          }
          #menuBarEl .menu-item {
            backdrop-filter: var(--menu-bar-item-backdrop-filter);
            display: inline-flex;
            border-radius: 3px;
            align-items: center;
            justify-content: center;
            gap: 0.125rem;
            height: 100%;
            font-size: 80%;
            opacity: 0.9;
            min-width: max-content;
          }
          #menuBarEl .menu-item:hover {
            cursor:pointer;
            backdrop-filter: var(--menu-bar-item-backdrop-filter-hover);
            opacity: 1;
          }
          @media (prefers-color-scheme: dark) { 
            #menuBarEl .menu-item {
              backdrop-filter: var(--menu-bar-item-backdrop-filter-dark);
              color:#e3e3e3;
            }
            #menuBarEl .menu-item:hover {
              backdrop-filter: var(--menu-bar-item-backdrop-filter-hover-dark);
            }
          }
          #menuBarEl .menu-item-icon {
            padding-left: 0.25rem;
          }
          #menuBarEl .menu-item-label {
            padding-right: 0.25rem;
          }
          /* @media screen and (max-width: 690px) { #menuBarEl .menu-item.new { display:none; } }
          @media screen and (max-width: 640px) { #menuBarEl .menu-item.community { display:none; } }
          @media screen and (max-width: 590px) { #menuBarEl .menu-item.resources { display:none; } }
          @media screen and (max-width: 540px) { #menuBarEl .menu-item.hub { display:none; } }
          @media screen and (max-width: 490px) { #menuBarEl .menu-item.tutorial { display:none; } }
          @media screen and (max-width: 440px) { #menuBarEl .menu-item.generators { display:none; } } */

          @media screen and (max-width: 400px) {
            #menuBarEl .menu-item.tutorial { display:none; }
            #menuBarEl .menu-item.hub { display:none; }
            #menuBarEl .menu-item.community { display:none; }
          }
        </style>
        <style>
          #editorEl .warningsModal .warning-item {
            padding: 1rem;
            padding-bottom: 0;
          }
          #editorEl .warningsModal code {
            background: #ececec;
            font-size: 90%;
            padding: 0.07rem 0.2rem;
            border-radius: 2px;
          }
          /* WARNINGS MODAL */
          #editorEl .warningsModal .outer-wrapper {
            position:fixed;
            top:0;
            left:0;
            width:100%;
            z-index:2;
            padding: 1em;
            box-sizing: border-box;
          }
          #editorEl .warningsModal .background {
            position:fixed;
            top:0;
            left:0;
            width:100%;
            height:100%;
            opacity:0.2;
            background:#000;
            transition: opacity .15s linear;
          }
          #editorEl .warningsModal .content-wrapper {
            overflow:hidden;
            background:#fff;
            max-width:700px;
            width:100%;
            border-radius:3px;
            margin:0 auto;
          }
          #editorEl .warningsModal button,
          #editorEl .warningsModal input {
            height:3em;
          }
          #editorEl .warningsModal button {
            background:#4c4c4c;
            color:#fff;
            width:50%;
            border:none;
            outline:none;
            font-size: 90%;
          }
          #editorEl .warningsModal button:hover {
            background:#323232;
          }

          #editorEl .warningsModal .modal-header {
            padding:1em;
          }
          #editorEl .warningsModal .modal-header p {
            color:#444;
            margin:0;
            font-size: 90%
          }
          #editorEl .warningsModal button.main {
            background:#444;
            color:white;
          }
          #editorEl .warningsModal button.main:hover {
            background:#333;
          }
          #editorEl .warningsModal span.link {
            cursor:pointer;
            text-decoration:underline;
            color:#1212ff;
          }
          @media screen and (max-width: 590px) { 
            #editorEl #output-buttons-ctn {
              display: flex;
              flex-direction: column;
            }
            #editorEl #output-buttons-ctn > * {
              margin: 3px !important;
              white-space: nowrap;
              overflow: hidden;
            }
          }

          #editorEl #output { border: 1px solid #C0C0C0; border-bottom:none; }
          @media (prefers-color-scheme: dark) { #editorEl #output { border: 1px solid #575757; border-bottom:none; } }

          #editorEl #output-buttons-ctn { border-top: 1px solid #C0C0C0; }
          @media (prefers-color-scheme: dark) { #editorEl #output-buttons-ctn { border-top: 1px solid #575757; } }

          #adCtn { border-top: 1px solid #C0C0C0; }
          @media (prefers-color-scheme: dark) { #adCtn { border-top: 1px solid #575757; } }

          #editorEl .toggle-wrap-button-html {
            border: solid 1px #737373;
            color: #737373;
            padding: 0 0.3em;
            border-radius: 1px;
            cursor: pointer;
            background:white;
            text-align: center;
            position: absolute;
            top: 5px;
            right: 5px;
            z-index: 10;
          }
          #editorEl .toggle-wrap-button-html:hover {
            border: solid 1px black;
            color:black;
          }

          #editorEl .toggle-wrap-button {
            border: solid 1px #737373;
            color: #737373;
            padding: 0 0.3em;
            border-radius: 1px;
            cursor: pointer;
            background:white;
            text-align: center;
            display: inline-block;
          }
          #editorEl .toggle-wrap-button:hover {
            border: solid 1px black;
            color:black;
          }
          #editorEl .toggle-fold-button {
            border: solid 1px #737373;
            color: #737373;
            padding: 0 0.3em;
            border-radius: 1px;
            cursor: pointer;
            background:white;
            text-align: center;
            display: inline-block;
          }
          #editorEl .toggle-fold-button:hover {
            border: solid 1px black;
            color:black;
          }

          #editorEl .code-editor-buttons-ctn {
            position: absolute;
            top: 5px;
            right: 5px;
            z-index: 10;
          }

          #editorEl #output {
            /* position:absolute; */
            height: 100%;
            width: 100%;
            flex-grow:10;
            padding:0;
            margin:0;
            z-index: 20;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
            text-align:center;
            border-left: none;
            border-right: none;
          }

          #editorEl #output iframe {
            height:100%;
            width:100%;
            border:none;
          }
          @media (prefers-color-scheme: dark) {
            #editorEl #output iframe {
              background: #121212; /* this is chrome's default dark mode background color. Note: must only do this in dark mode due to this: https://lemmy.world/post/7512043 */
            }
          }

          #editorEl #main {
            
          }

          #editorEl .CodeMirror {
            height: 100%;
            width: 100%;
            background:#fbfbfb;
          }


          #editorEl .split {
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;

            overflow-y: auto;
            overflow-x: hidden;
          }

          #editorEl .content {
            border: 1px solid #C0C0C0;
            box-shadow: inset 0 1px 2px #e4e4e4;
            background-color: #fff;
          }

          #editorEl .gutter {
            background-color: transparent;

            background-repeat: no-repeat;
            background-position: 50%;
          }

          #editorEl .gutter.gutter-horizontal {
            cursor: col-resize;
            background-image: url('lib/splitjs/vertical.png');
            height: 100%;
            min-width: 8px;
            max-width: 8px;
          }

          #editorEl .gutter.gutter-vertical {
            cursor: row-resize;
            background-image: url('lib/splitjs/horizontal.png');
            width: 100%;
            min-height: 8px;
            max-height: 8px;
          }

          #editorEl .split.split-horizontal {
            height: 100%;
          }

          #revisionsModalEl ul li span.clickable {
            color:blue;
            text-decoration:underline;
            cursor: pointer;
          }
          #revisionsModalEl .content-wrapper {
            width:750px;
          }

          @media (prefers-color-scheme: dark) {
            body {
              color-scheme: dark;
              background-color: #282c33;
              color: #cdcdcd;
            }
            #editorEl .gutter.gutter-horizontal {
              opacity: 0.6 !important;
            }
            #editorEl .gutter.gutter-vertical {
              opacity: 0.6 !important;
            }
            #editorEl .content {
              border: 1px solid #575757;
              background-color: #282c34;
              box-shadow: none;
            }
            #editorEl .toggle-fold-button,
            #editorEl .toggle-wrap-button,
            #editorEl .toggle-wrap-button-html {
              background: #1f2024;
              color: #aaaaaa;
              border: 1px solid #575757;
            }
            #editorEl .toggle-fold-button:hover,
            #editorEl .toggle-wrap-button:hover,
            #editorEl .toggle-wrap-button-html:hover {
              color: #d8d8d8;
              border: solid 1px #bfbfbf;
            }

            #accountModalEl .content-wrapper,
            #settingsModalEl .content-wrapper,
            #revisionsModalEl .content-wrapper,
            #loginModalEl .content-wrapper {
              background: #2e3034;
            }
            #accountModalEl .modal-header p,
            #settingsModalEl .modal-header p,
            #revisionsModalEl .modal-header p,
            #loginModalEl .modal-header p {
              color: #8f8f8f;
            }
            #accountModalEl button,
            #settingsModalEl button,
            #revisionsModalEl button,
            #loginModalEl button {
              background: #474747;
            }
            #accountModalEl button:hover,
            #settingsModalEl button:hover,
            #revisionsModalEl button:hover,
            #loginModalEl button:hover {
              background: #565656;
            }
            #accountModalEl span.link,
            #settingsModalEl span.link,
            #revisionsModalEl span.link,
            #loginModalEl span.link,
            #revisionsModalEl ul li span.clickable {
              color: #6d6dee;
            }

            #perchanceConsoleEl #console-input {
              background: initial !important;
            }

            #output-buttons-ctn {
              background: #282c33 !important;
            }
            #output-buttons-ctn button:not([data-ref='warningsModalOpenButton']) {
              /* border: 1px solid #585858 !important;
              background: linear-gradient(to bottom, rgb(44 44 44) 0%, rgb(37 37 37) 47%, rgb(38 38 38) 100%) !important; */
            }
            #output-buttons-ctn > span { /* auto reload checkbox container */
              background-color: #404040 !important;
            }

            .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
              background-color: #282c33 !important;
            }

            #menuBarEl .menu-item.edit-generator-button {
              color: #00d300 !important;
            }
            #menuBarEl .menu-item.account-modal-open-button {
              color: #00d300 !important;
            }

            .warningsModal .modal-body > div {
              background-color: #282c33 !important;
            }
            .warningsModal .modal-body code {
              background-color: #4c4c4c !important;
            }
          }

          /* .cm-searching {
            background-color: rgba(255, 255, 0, .4) !important;
          } */

          /* .cm-square-bracket { color: #05a; }
          .cm-special-list-name { color: #05a; }
          .cm-curly-bracket { color: #f18c16; } */

          /* .cm-s-one-dark .cm-square-bracket { color: #61afef; }
          .cm-s-one-dark .cm-special-list-name { color: #61afef; }
          .cm-s-one-dark .cm-curly-bracket { color: #f18c16; }
          .CodeMirror.cm-s-one-dark { background-color: #282c34 !important; }
          .cm-s-one-dark .cm-string-2 { color: #98c379 !important; }
          .cm-s-one-dark .cm-matchhighlight { background-color: #ffde631c; }
          .cm-s-one-dark .CodeMirror-selection-highlight-scrollbar { background-color: #ffdd6333; } */

          /*
          .cm-s-one-light .cm-square-bracket { color: #05a; }
          .cm-s-one-light .cm-special-list-name { color: #05a; }
          .cm-s-one-light .cm-curly-bracket { color: #f18c16; }
          .cm-s-one-light .cm-string { color: #419c00 !important; }
          .cm-s-one-light .cm-string-2 { color: #419c00 !important; }
          .cm-s-one-light .cm-def { color: #05a !important; }
          .cm-s-one-light .cm-variable { color: #05a !important; }
          */

          /* .CodeMirror.cm-s-one-light { background-color: #fafafa !important; }
          .cm-s-one-light .cm-string-2 { color: #50a14f !important; }
          .cm-s-one-light .cm-matchhighlight { background-color: #ffe06d52; }
          .cm-s-one-light .CodeMirror-selection-highlight-scrollbar { background-color: #c0ab5d52; } */

          /*
          .cm-s-one-dark .cm-comment { color: #636a78 !important; }
          .cm-s-one-dark .cm-variable { color: #61afef !important; }
          .cm-s-one-dark .cm-variable-2 { color: #61afef !important; }
          */
          /*
          .cm-comment { color: #A0A1A7 !important; }
          .cm-variable { color: #05a !important; }
          .cm-def { color: #05a !important; }
          */
        </style>
        <!-- SHARED MODAL STYLES -->
        <style>
          /* WRAPPER/OUTER STYLES */
          .app-modal .outer-wrapper {
            position:fixed;
            top:0;
            left:0;
            width:100%;
            z-index:2;
            padding: 1em;
            box-sizing: border-box;
          }
          .app-modal .background {
            position:fixed;
            top:0;
            left:0;
            width:100%;
            height:100%;
            opacity:0.2;
            background:#000;
            transition: opacity .15s linear;
          }
          .app-modal .content-wrapper {
            overflow:hidden;
            background:#fff;
            max-width:95%;
            width:500px;
            border-radius:3px;
            margin:0 auto;
          }


          /* DEFAULT CONTENT STYLES */
          .app-modal button, .app-modal input {
            height:3em;
          }
          .app-modal input[type="text"],
          .app-modal input[type="password"],
          .app-modal input[type="email"] {
            margin: 0;
            padding:0;
            box-sizing:border-box;
            display:block;
            width:100%;
            border:none;
            border-top:1px solid #eee;
            border-top:1px solid light-dark(#eee, #323232);
            outline:none;
            padding-left: 0.6em;
          }
          .app-modal input.error {
            background-color: #ffcccc;
          }
          .app-modal button {
            background:#eee;
            color: inherit;
            width:50%;
            border:none;
            outline:none;
            font-size: 90%;
          }
          .app-modal button:hover {
            background:#e1e1e1;
          }

          .app-modal .modal-header {
            padding:1em;
          }
          .app-modal .modal-header p {
            color:#444;
            margin:0;
            font-size: 90%
          }
          .app-modal button.main {
            background:#444;
            color:white;
          }
          .app-modal button.main:hover {
            background:#333;
          }
          .app-modal span.link {
            cursor:pointer;
            text-decoration:underline;
            color:#1212ff;
          }
          #minimalModeMenuBtn {
            background: rgb(226 226 226);
            border: 1px solid rgb(162 162 162);
          }
          @media (prefers-color-scheme: dark) {
            #minimalModeMenuBtn {
              background: #303030;
              border: 1px solid #474747;
            }
          }
        </style>
        <div id="appEl" style="display:flex; flex-direction:column; height:100%;">  
          <div id="minimalModeMenuBtn" onclick="this.style.display='none'; menuBarEl.style.display='flex'; backToMinimalModeBtn.style.display='';" style="display:none; position: fixed; top: 0.21rem; right: 0.21rem; z-index: 1000; border-radius: 3px; cursor: pointer; font-size: 0.6rem; line-height: 0.96rem; aspect-ratio: 1 / 1; height: calc(var(--menu-bar-height) - 0.42rem - 2px); align-items: center; justify-content: center;">🛠️</div>
          <div id="menuBarEl" style="position:relative; height:var(--menu-bar-height); min-height:var(--menu-bar-height); width:100%; overflow:hidden; display:flex; align-items: center; justify-content: center;">
            <script>
              if(window.generatorStaticMetaData.header?.mode === "minimal") { 
                menuBarEl.style.display = "none";
                minimalModeMenuBtn.style.display = "flex"; 
              }  
              function enableRobustBackdropFilter() { // this is more robust to e.g. background images, light backgrounds in dark mode, etc. - only enabling if background is actually set because IIRC some browsers currently have significant performance issues with backdrop-filter blur
                document.querySelector(':root').style.setProperty('--menu-bar-item-backdrop-filter', "brightness(0.9) blur(4px)");
                document.querySelector(':root').style.setProperty('--menu-bar-item-backdrop-filter-hover', "brightness(0.84) blur(4px)");
                document.querySelector(':root').style.setProperty('--menu-bar-item-backdrop-filter-dark', "brightness(0.75) blur(4px)");
                document.querySelector(':root').style.setProperty('--menu-bar-item-backdrop-filter-hover-dark', "brightness(0.6) blur(4px)");
              }  
              function colorIsDark(bgColorStr) {
                let a = document.createElement('div');
                a.style.color = bgColorStr;
                let rgb = window.getComputedStyle( document.body.appendChild(a) ).color.match(/\d+/g).map(function(a){ return parseInt(a,10); });
                document.body.removeChild(a);
                let r = rgb[0];
                let g = rgb[1];
                let b = rgb[2];
                let uicolors = [r / 255, g / 255, b / 255];
                let c = uicolors.map((col) => {
                  if (col <= 0.03928) {
                    return col / 12.92;
                  }
                  return Math.pow((col + 0.055) / 1.055, 2.4);
                });
                let L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]);
                return L < 0.179;
              }
              if(typeof window.generatorStaticMetaData.header?.background === "string") {
                if(CSS.supports("background", window.generatorStaticMetaData.header.background)) {
                  menuBarEl.style.background = window.generatorStaticMetaData.header.background;
                  enableRobustBackdropFilter();
                  if(CSS.supports("color", window.generatorStaticMetaData.header.background)) {
                    menuBarEl.style.color = colorIsDark(window.generatorStaticMetaData.header.background) ? "#e3e3e3" : "#050505";
                  }
                }
              }

              {
                let isTouchDevice = window.matchMedia("(pointer: coarse)").matches;
                let maxSeenViewportHeight = window.visualViewport.height;
                window.visualViewport.addEventListener('resize', () => {
                  if(!isTouchDevice) return;
                  if(window.visualViewport.height > maxSeenViewportHeight) maxSeenViewportHeight = window.visualViewport.height;
                  menuBarEl.style.display = window.visualViewport.height < 0.8*maxSeenViewportHeight ? "none" : "flex";
                });
              }
            </script>
            <div class="container" style="height: calc(100% - 0.42rem); width: calc(100% - 0.42rem); display: flex;">
              <div style="display:flex; height:100%; gap:0.21rem; overflow:hidden; flex-wrap:wrap;">
                <div class="menu-item" style="aspect-ratio: 1 / 1;" onclick="window.open('/')" onmousedown="if(event.which===2) { this.click() }">
                  <span class="menu-item-icon" style="padding:0; font-size:0.9rem;">⚄︎</span>
                </div>
                <div data-ref="communityButton" class="menu-item community" onclick="window.open('https://lemmy.world/c/perchance')" onmousedown="if(event.which===2) { this.click() }" title="• &quot;[Suggestion] Make avatar/profile pic in comment plugin default or a guide&quot; (14h ago)
• &quot;[Bug] t2i bannedPromptPhrases jailbreak&quot; (15h ago)
• &quot;aichat, i have some questions about lore and rentry seems to need a access code.&quot; (1d ago)
• &quot;[BUG?] Why is importing on mobile so confusing and annoying&quot; (1d ago)
• &quot;Is there any way to make the background for the comments plugin transparent?&quot; (2d ago)
• &quot;[Suggestion] remove username restriction in comment plugin&quot; (4d ago)
• &quot;Unable to Export&quot; (4d ago)
• &quot;Any way to make AI RPG talk in first person?&quot; (5d ago)">
                  <span class="menu-item-icon">👥︎</span>
                  <span class="menu-item-label" style="padding-right:0;">forum</span>
                  <span style="font-size:70%; display:inline-block; text-align:center; opacity:0.7; padding-right:0.25rem;" data-ref="communityNotifications"> (14h)</span>
                </div>
                <div class="menu-item hub" onclick="window.open('/hub')" onmousedown="if(event.which===2) { this.click() }">
                  <span class="menu-item-icon">🌈</span>
                  <span class="menu-item-label">hub</span>
                </div>
                <div class="menu-item tutorial" onclick="window.open('/tutorial')" onmousedown="if(event.which===2) { this.click() }">
                  <span class="menu-item-icon">📚</span>
                  <span class="menu-item-label">learn</span>
                </div>
                <!-- <div class="menu-item tutorial" onclick="window.open('/resources')" onmousedown="if(event.which===2) { this.click() }">
                  <span class="menu-item-icon">🧰</span>
                  <span class="menu-item-label">resources</span>
                </div> -->
                <div class="menu-item generators" onclick="window.open('/generators')" onmousedown="if(event.which===2) { this.click() }">
                  <span class="menu-item-inner"><span class="menu-item-icon">🎲︎</span>
                  <span class="menu-item-label">generators</span></span>
                </div>
                <div class="menu-item new" onclick="window.open('/minimal#edit')" onmousedown="if(event.which===2) { this.click() }">
                  <span class="menu-item-icon">➕</span>
                  <span class="menu-item-label">new</span>
                </div><div class="menu-item promo" onclick="window.open('/ai-chat')" onmousedown="if(event.which===2) { this.click() }" style="background-color: rgb(255, 212, 164);">
                  <span class="menu-item-icon">🆕</span>
                  <span class="menu-item-label">ai chat</span>
                </div>
              </div>
              <div style="display:flex; height:100%; flex-grow:1; justify-content:end; gap:0.21rem;">
                <div data-ref="statusMessage" style="min-width:max-content; color:green; padding:0 0.5em; font-size: 80%; display:none; align-items: center; justify-content: center; font-weight: bold;"></div>
                <div data-ref="revisionsButton" class="menu-item" onclick="app.openRevisionsModal()" style="display:none;">
                  <span class="menu-item-icon">🗄️</span>
                  <span class="menu-item-label">backups</span>
                </div>
                <div data-ref="saveButton" class="menu-item" onclick="app.saveGenerator();" style="display:none; ">
                  <span class="menu-item-icon">💾</span>
                  <span class="menu-item-label" data-ref="saveText">save</span>
                </div>
                <div data-ref="settingsButton" onclick="app.openSettingsModal()" class="menu-item" style="display:none;">
                  <span class="menu-item-icon">⚙️</span>
                  <span class="menu-item-label">settings</span>
                </div>
                <div data-ref="editButton" class="menu-item edit-generator-button" onclick="window.lastEditButtonClickTime=Date.now(); app.goToEditMode()" style="color: green; display: inline-flex;">
                  <span class="menu-item-icon">🛠️</span>
                  <span class="menu-item-label">edit</span>
                </div>
                <div data-ref="accountButton" onclick="app.openAccountModal()" class="menu-item account-modal-open-button" style="display:none; color:green;">
                  <span class="menu-item-icon">👤</span>
                  <span class="menu-item-label">account</span>
                </div>
                <div data-ref="loginButton" onclick="app.openLoginModal()" class="menu-item" style="display: inline-flex;">
                  <span class="menu-item-icon">🔑</span>
                  <span class="menu-item-label">login</span>
                </div>
                <div id="backToMinimalModeBtn" class="menu-item" onclick="menuBarEl.style.display='none'; minimalModeMenuBtn.style.display='flex';" style="display:none; aspect-ratio: 1/1;">
                  <span class="menu-item-icon" style="padding: 0; font-size: 0.5rem; line-height: 0.4rem;">❌</span>
                </div>
              </div>
            </div>
            <script> 
              window.menuBar = {
                root: document.querySelector("#menuBarEl"),
                refs: new Proxy({}, {
                  get(target, prop, receiver) {
                    return document.querySelector(`#menuBarEl [data-ref='${prop}']`);
                  },
                }),
                init: function() {

                  try {
                    this.refs.editButton.addEventListener("mouseover", () => {
                      if(window.TEST_NEW_EDITOR_1 && !window.editorBundleImportPromise) window.editorBundleImportPromise = import("/lib/editors.bundle.min.js");
                    });
                  } catch(e) { console.error(e); }

                  this.updateMenuButtonsDisplay = function() {
                    this.refs.accountButton.style.display = app.store.data.user.loggedIn ? "inline-flex" : "none";
                    this.refs.loginButton.style.display = app.store.data.user.loggedIn ? "none" : "inline-flex";
                    this.refs.settingsButton.style.display = app.store.data.user.loggedIn && app.userOwnsThisGenerator && app.appInteractionState === "edit" ? "inline-flex" : "none";
                    this.refs.saveButton.style.display = app.appInteractionState === "edit" ? "inline-flex" : "none";
                    this.refs.revisionsButton.style.display = app.store.data.user.loggedIn && app.userOwnsThisGenerator && app.appInteractionState === "edit" ? "inline-flex" : "none";
                    this.refs.editButton.style.display = app.appInteractionState === "view" ? "inline-flex" : "none";
                  };
                  app.on("LoginStateChange", () => {
                    this.updateMenuButtonsDisplay();
                  });
                  app.on("AppInteractionStateChange", () => {
                    this.updateMenuButtonsDisplay();
                    if(app.interactionStateChange === "edit") {
                      this.updateSaveButtonStyle();
                    }
                  });
                  app.on("GeneratorOwnershipChange", () => {
                    this.updateMenuButtonsDisplay();
                  });

                  // this will be changed to "saved" if they are the owner:
                  window.perchanceSaveState = "unsaved";
                  this.saveState = "unsaved";
                
                  this.setSaveState = (state) => {
                    window.perchanceSaveState = state;
                    this.saveState = state;
                    this.updateSaveButtonStyle();
                  };
                  window.setSaveState = this.setSaveState.bind(this);
                
                  this.updateSaveButtonStyle = () => {
                
                    let state = this.saveState;
                
                    this.refs.saveButton.style.color = "";
                    this.refs.saveButton.style.cursor = "";
                    this.refs.saveButton.style.opacity = 1;
                
                    if(state === "saving") {
                      this.refs.saveText.innerText = "saving…";
                      this.refs.saveButton.style.opacity = 0.5;
                    } else if(state === "saved") {
                      this.refs.saveText.innerText = "saved";
                      this.refs.saveButton.style.opacity = 0.5;
                    } else if(state === "unsaved") {
                      this.refs.saveText.innerText = "save";
                      this.refs.saveButton.style.cursor = "pointer";
                    } else if(state === "error") {
                      this.refs.saveText.innerText = "error";
                      this.refs.saveButton.style.color = "red";
                    } else {
                      console.error("Invalid save state.");
                      this.setSaveState("INVALID!");
                      alert("There was an error while saving :S Please report this at lemmy.world/c/perchance if the problem persists.");
                      //this.saveState = "INVALID!";
                    }
                  };
                
                  this.updateCommunityData = async () => {
                    try {
                      let communityData = await (await fetch("/api/getCommunityData")).json();
                      if(communityData.status !== "success") throw communityData;
                      let data = communityData.data;
                      let str = "";
                      let isMostRecentPost = true;
                      let mostRecentPostTimeAgoStr = "";
                      for(let post of data.posts) {
                        let minsAgo = Math.ceil(post.secondsAgo/60);
                        let timeAgoStr = minsAgo > 60*24 ? Math.round(minsAgo/(60*24))+"d" : minsAgo > 60 ? Math.ceil(minsAgo/60)+"h" : minsAgo+"m";
                        if(isMostRecentPost) mostRecentPostTimeAgoStr = timeAgoStr;
                        str += `• "${post.title}" (${timeAgoStr} ago)\n`;
                        isMostRecentPost = false;
                      }
                      if(data.posts[0]/60 > 60*24) {
                        this.refs.communityNotifications.textContent = "";
                        this.refs.communityNotifications.style.display = "none";
                      } else {
                        this.refs.communityNotifications.textContent = " ("+mostRecentPostTimeAgoStr+")";
                        this.refs.communityNotifications.style.display = "inline-block";
                      }
                      this.refs.communityButton.title = str.trim(); // XSS no possible with setting title but CAREFUL if you change this code
                    } catch(e) {
                      console.error("Failed to update community data.");
                    }
                  };
                
                  this.updateCommunityData();
                  setInterval(this.updateCommunityData, 2*60*1000);
                },
              };
            </script>
          </div>




          <style>
            .cm-editor { height:100%; }
            .cm-cursor { border-left: 2px solid #56b6c2 !important; margin-left:-1px !important; }
            .cm-editor .cm-foldPlaceholder {
              height: 0.5rem;
              padding: 0 0.2rem;
              display: inline-flex;
              align-items: center;
              justify-content: center;
              background: light-dark(#309eff, #0070d3);
              color: light-dark(#e5e5e5, #ddd);
            }
            .cm-editor .cm-button {
              border: revert !important;
              background-image: revert !important;
              border-radius: revert !important;
              background: revert !important;
            }
            .cm-editor .cm-search {
              font-size: 1rem;
            }
            .cm-editor .cm-panel.cm-search label {
              display: inline-flex;
              align-items: center;
              justify-content: center;
              cursor: pointer;
            }
            .cm-editor .cm-panel.cm-search input {
              background-color: revert;
              border: revert;
              padding: 4px;
            }
            .cm-editor .cm-searchMatch.cm-searchMatch-selected {
              background-color: #ff00ff8a;
            }
            .cm-editor .cm-gutter.cm-gutter-lint {
              overflow: visible;
              width: 0;
              position: relative;
              left: -0.85rem;
            }
            .cm-editor .cm-gutter.cm-gutter-lint .cm-activeLineGutter {
              background-color: transparent;
            }
            .cm-editor .cm-gutter.cm-gutter-lint .cm-lint-marker { 
              transform: scale(0.75);
            }
            
            .cm-editor .cm-tooltip-autocomplete li[aria-selected] {
              background-color: light-dark(#a4dbff, #005b98) !important;
              color: light-dark(black, white) !important;
            }
            .cm-editor .cm-tooltip-autocomplete li:not([aria-selected]) {
              opacity: 0.65;
            }
            .cm-editor .cm-gutters {
              user-select: none;
            }

            .cm-search.cm-panel {
              display: flex;
              flex-wrap: wrap;
              gap: 0.25rem;
              font-size:16px;
            }

            .cm-search.cm-panel input[type='checkbox'] { cursor: pointer; }

            /* note: this relies on some js (below) to set these data attr values */
            .cm-search.cm-panel input.cm-textfield[name='search'] { width: 60px !important; }
            .cm-search.cm-panel input.cm-textfield[name='search'][data-last-search-textfield-interacted='1'] { width: 140px !important; }
            .cm-search.cm-panel input.cm-textfield[name='replace'] { width: 60px !important; }
            .cm-search.cm-panel input.cm-textfield[name='replace'][data-last-search-textfield-interacted='1'] { width: 140px !important; }

            .cm-search .cm-button[name='select'] { display:none !important; }

            .cm-search .cm-button[name='next'] { font-size: 0 !important; }
            .cm-search .cm-button[name='next']::before {
              content: "↓";
              font-size: 11.2px;
              padding: 3px 8px;
              display: inline-block;
              font-weight: bold;
            }

            .cm-search .cm-button[name='prev'] { font-size: 0 !important; } 
            .cm-search .cm-button[name='prev']::before {
              content: "↑";
              font-size: 11.2px;
              padding: 3px 8px;
              display: inline-block;
              font-weight: bold;
            }

            .cm-search .cm-button[name='replace'] { font-size: 0 !important; }
            .cm-search .cm-button[name='replace']::before {
              content: '→';
              font-size: 11.2px;
              padding: 3px 8px;
              display: inline-block;
              font-weight: bold;
            }

            .cm-search .cm-button[name='replaceAll'] { font-size: 0 !important; }
            .cm-search .cm-button[name='replaceAll']::before {
              content: 'all';
              font-size: 11.2px;
              padding: 3px 6px;
              display: inline-block;
            }

            .cm-search label:has(input[name='case']) {
              font-size: 0 !important;
              padding: 0 4.5px !important;
              position: relative !important;
              top: 3px !important;
            }
            .cm-search label:has(input[name='case'])::after {
              content: 'case';
              font-size: 8px;
              position: absolute;
              top: -6px;
            }

            .cm-search label:has(input[name='re']) {
              font-size: 0 !important;
              padding: 0 4.5px !important;
              position: relative !important;
              top: 3px !important;
            }
            .cm-search label:has(input[name='re'])::after {
              content: 'regex';
              font-size: 8px;
              position: absolute;
              top: -6px;
            }

            .cm-search label:has(input[name='word']) { display: none !important; }
            /* .cm-search label:has(input[name='word']) { font-size: 0 !important; }
            .cm-search label:has(input[name='word'])::after {
              content: 'word';
              font-size: 11.2px;
              margin-left: 3px;
            } */

            .cm-search .cm-textfield,
            .cm-search label,
            .cm-search .cm-button {
              margin: 0 !important;
            }
          </style>
          <script>
            // check if click is in search field, and if so set data-last-search-textfield-interacted to 1 and set others to 0
            window.addEventListener("click", (e) => {
              if(e.target.className !== "cm-textfield") return;
              let searchPanel = document.querySelector(".cm-search.cm-panel");
              if(!searchPanel.contains(e.target)) return;
              let searchFields = searchPanel.querySelectorAll(".cm-search.cm-panel input.cm-textfield");
              for(let field of searchFields) {
                field.dataset.lastSearchTextfieldInteracted = field === e.target ? "1" : "0";
              }
            });
            // same for typing:
            window.addEventListener("keydown", (e) => {
              if(e.target.className !== "cm-textfield") return;
              let searchPanel = e.target.closest(".cm-search.cm-panel");
              if(!searchPanel) return;
              let searchFields = searchPanel.querySelectorAll(".cm-search.cm-panel input.cm-textfield");
              for(let field of searchFields) {
                field.dataset.lastSearchTextfieldInteracted = field === e.target ? "1" : "0";
              }
            });
            // and same for focusin:
            window.addEventListener("focusin", (e) => {
              if(e.target.className !== "cm-textfield") return;
              let searchPanel = e.target.closest(".cm-search.cm-panel");
              if(!searchPanel) return;
              let searchFields = searchPanel.querySelectorAll(".cm-search.cm-panel input.cm-textfield");
              for(let field of searchFields) {
                field.dataset.lastSearchTextfieldInteracted = field === e.target ? "1" : "0";
              }
            });
          </script>
          
          <!-- fake fields are a workaround for chrome autofill getting the wrong fields -->
          <input style="display: none" type="email" name="fakeusernameremembered">
          <input style="display: none" type="password" name="fakepasswordremembered"> 

          <div id="editorEl" style="width:100%; flex-grow:1; min-height:0;">
            <div id="main" style="height:100%; display:flex; ">
              <div id="a" style="display:none; flex-direction:column;" class="split split-horizontal">
                <!-- MODEL TEXT -->
                <div id="c" style="height:100%;overflow:hidden;position:relative; border-left:none;" class="split content">
                  <!--<div id="customListEditorEl" style="display:none; position:absolute;top:0;left:0;right:0;bottom:0;background:blue;z-index: 100;">
                    <iframe srcdoc="hello world" sandbox="allow-scripts" style="border: none; margin: 0; padding: 0; outline: none; width: 100%; height: 100%;"></iframe>
                  </div>-->
                  <div class="code-editor-buttons-ctn">
                    <div class="toggle-fold-button" data-ref="codeEditorFoldRefButton" onclick="editor.toggleCodeEditorFold()">fold</div>
                    <div class="toggle-wrap-button" data-ref="codeEditorWrapRefButton" onclick="editor.toggleCodeEditorWrap()">wrap</div>
                  </div>
                  <textarea id="input"></textarea>
                  <!-- TODO***: fix the problem where the horizontal scoll bar doesn't show up sometimes -->
                </div>

                <!-- <div class="gutter-row gutter-row-1" style="display:none;"></div> -->

                <!-- CONSOLE -->
                <div id="perchanceConsoleEl" style="display:block; position:relative; overflow: hidden; border-bottom:none; border-left:none;" class="split content">
                  <div style="height:100%; width:100%; display:flex; flex-direction:column;">
                    <input style="display:none;" type="text" name="topreventchromesbadautofillalgorithm">
                    <input style="display:none;" type="password" name="topreventchromesbadautofillalgorithm">
                    <input class="console" id="console-input" placeholder="type some text here and press enter" type="text" autocomplete="off">
                    <!-- <expanding-textarea style="background: #eee;display:block;" class="console" id="console-input" placeholder="type an expression and press enter" /> -->
                    <iframe class="console" id="console-output" sandbox=""></iframe>
                    <select id="consoleInterpreterOption" style="position:absolute; bottom:4px; right:4px;">
                      <option value="html" selected="">html</option>
                      <option value="plaintext">plain text</option>
                    </select>
                    <style>
                      #perchanceConsoleEl .console {
                        font-size:1em;
                        font-family:inherit;
                        /* position:absolute; */
                        border:none;
                        outline:none;
                        padding:0;
                        margin:0;
                        box-sizing:border-box;
                      }
                      #perchanceConsoleEl #console-input {
                        background: #eee;
                        width:100%;
                        height:20px;
                        padding-left: 0.3em;
                      }

                      #perchanceConsoleEl #console-output {
                        flex-grow: 1;
                        width:100%;
                        /* height:100%; */
                        /* position:absolute; */
                        /* bottom:0; */
                        /* left:0; */
                        /* right:0; */
                        /* top:20px; */
                        border:none;
                      }
                      #e {
                        border-right: none !important;
                        border-top: none !important;
                        height: 100%;
                      }
                      #b {
                        width: 100%;
                      }
                      #output {
                        background: white;
                      }
                      @media (prefers-color-scheme: dark) {
                        #output {
                          background: #121212;
                        }
                      }
                    </style>
                  </div>
                </div>
              </div>

              <!-- <div class="gutter-col gutter-col-1" style="display:none;"></div> -->
          
              <div id="b" class="split split-horizontal" style="display:flex; flex-direction:column;">
                <!-- OUTPUT -->
                <div id="e" style="overflow:hidden; position:initial; display:flex; flex-direction:column; border:none;" class="split content">
                  <!-- WARNING: don't change the ID of this `output` element - there is code that relies on it (e.g. ad refresh focus bug fix stuff) -->
                  <div id="output" style="border-top:none;">
                    <div id="outputLoadSpinner" style="display:none; pointer-events:none; position:absolute; top:0; right:0; bottom:0; left:0; justify-content:center; align-items:center;"><div class="ldspmzjfhueifssge-ring"><div></div><div></div><div></div><div></div></div></div>
                    <script>
                      setTimeout(() => {
                        if(!window.perchanceOutputIframeFinishedFirstLoad) document.querySelector("#outputLoadSpinner").style.display = "flex";
                      }, 1500);
                      window.onNextOutputIframeReloadHandlers = [];
                      window.addEventListener("message", async (e) => {
                        let origin = e.origin || e.originalEvent.origin;
                        if(origin !== "https://null.perchance.org" && origin !== `https://${window.generatorPublicId}.perchance.org`) return;

                        if(e.data.type === "finishedLoading" || e.data.type === "failedToLoadDueToGeneratorErrors") {
                          window.perchanceOutputIframeFinishedFirstLoad = true;
                          document.querySelector("#outputLoadSpinner").style.display = "none";
                          for(let fn of window.onNextOutputIframeReloadHandlers) {
                            try { fn(); } catch(e) { console.error(e); }
                          }
                          window.onNextOutputIframeReloadHandlers = [];
                        }

                        if(e.data.type === "ensureEditorIsLoaded75383748") {
                          if(window.location.hash !== "#edit") {
                            let tmp = window.hasBeenInEditModeAtLeastOnce;
                            await app.goToEditMode();
                            app.goToViewMode();
                            window.hasBeenInEditModeAtLeastOnce = tmp;
                          }
                          outputIframeEl.contentWindow.postMessage({type:"ensureEditorIsLoaded75383748_response"}, "*");
                        }
                      });
                    </script>
                    <iframe id="outputIframeEl" src="https://d873b020cf1c788608c57afc66b7eb00.perchance.org/zb67bgo77s?__generatorLastEditTime=1700668497715" fetchpriority="high" style="user-select:none;" allowfullscreen="" webkitallowfullscreen="" mozallowfullscreen="" allow="fullscreen; clipboard-write; display-capture; camera; microphone" sandbox="allow-popups allow-popups-to-escape-sandbox allow-forms allow-scripts allow-same-origin allow-top-navigation-by-user-activation allow-modals allow-downloads"></iframe>
                    <script>
                      // Must add query string to iframe if it has one, since generator code may rely on that:
                      {
                        let url = document.querySelector("#outputIframeEl").src;
                        let different = false;
                        if(window.location.search) {
                          if(url.includes("?")) url += "&"+window.location.search.slice(1);
                          else url += "?"+window.location.search.slice(1);
                          different = true;
                        }
                        if(window.location.hash) {
                          url += window.location.hash;
                          different = true;
                        }
                        if(different) {
                          document.querySelector("#outputIframeEl").src = url;
                        }
                      }
                      {
                        const outputIframeEl = document.querySelector("#outputIframeEl");
                        // If hash to this top-level frame changes due to user typing in URL bar, tell the iframe to change its hash too:
                        window.addEventListener("hashchange", () => {
                          outputIframeEl.contentWindow.postMessage({type:"changeHash", hash:window.location.hash}, "*");
                        });
                        
                        window.firstIframePageInteractionPromise = new Promise(r => window.firstIframePageInteractionResolver=r);
                        
                        window.addEventListener("message", async (e) => {
                          if(e.source !== outputIframeEl.contentWindow) return;
                          if(e.origin !== `https://${window.generatorPublicId}.perchance.org`) return;
                          
                          // If iframe hash changes, change the top-level hash too
                          if(e.data.type === "changeHash") {
                            if(typeof e.data.hash !== "string") return;
                            if(window.location.hash !== e.data.hash) { // not sure if this is needed to prevent infinite loop, but can't hurt
                              window.location.hash = e.data.hash;
                            }
                          }

                          // Respond to replaceState (*without* allowing path change):
                          if(e.data.type === "changeUrl") {
                            if(typeof e.data.search !== "string" || typeof e.data.hash !== "string") return;
                            history.replaceState({}, "", window.location.pathname+e.data.search+e.data.hash);
                          }

                          if(e.data.type === "changePageTitle") {
                            document.title = e.data.pageTitle;
                          }

                          if(e.data.type === "firstPageInteraction") {
                            window.firstIframePageInteractionResolver();
                          }
                          
                          if(e.data.type === "changeFavicon") {
                            if(typeof e.data.href !== "string") return;
                            if(navigator.webdriver) return;

                            await window.metaDataIsLoadedPromise;
                            if(window.forceDisableAds) await window.firstIframePageInteractionPromise; // require page interaction first

                            document.querySelectorAll("link[rel~='icon']").forEach(el => el.remove());
                            let link = document.createElement('link');
                            link.rel = 'icon';
                            document.head.appendChild(link);
                            link.href = e.data.href || "/favicon-32x32-white-bg.png";
                          }
                        });
                      }
                    </script> 
                  </div>
                  <div id="output-buttons-ctn" style="display:none; padding: 4px; box-sizing:border-box; background: #e9e9e9;">
                    <button onclick="app.goToViewMode()" style="float:left; height:100%;">⇱︎ fullscreen</button>
                    <button data-ref="warningsModalOpenButton" onclick="editor.openWarningsModal()" style="float:left; height:100%; background:#ffd97c; margin-left: 4px; color:black; border:1px solid rgb(255 175 21); display:none;">⚠︎ warnings</button>
                    <button onclick="editor.handleReloadButtonClick()" style="float:right; height:100%;" title="FULL reload (Ctrl+R / Cmd+R)">⟳︎ reload</button>
                    <span title="Toggle partial 'in-place' reloads on each edit. Variables will *not* be cleared. Use the reload button for a 'full' refresh." style="display:inline-block; float:right; background-color:#d5d5d5; padding:4px; margin-right:4px;height: 100%;box-sizing: border-box; cursor:pointer; display: flex; align-items: center; justify-content: center; user-select:none;" onclick="if(event.target !== autoReloadCheckboxEl) autoReloadCheckboxEl.checked=!autoReloadCheckboxEl.checked, toggleOutputAutoReloadOnEdits(autoReloadCheckboxEl);"><input id="autoReloadCheckboxEl" data-ref="autoReloadCheckbox" style="" type="checkbox" onclick="toggleOutputAutoReloadOnEdits(this)">&nbsp;auto</span>
                  </div>
                </div>

                <!-- <div class="gutter-row gutter-row-2" style="display:none;"></div> -->

                <!-- OUTPUT TEXT/TEMPLATE -->
                <div id="f" style="height:100%;overflow:hidden;position:relative; display:none; border-right:none; border-bottom:none;" class="split content">
                  <button id="showAiHelperBtn" style="right: 5px; bottom: 5px; position: absolute; z-index: 10; font-size: 70%; padding: 0 0.1rem; line-height: 1.6;" onclick="this.hidden=true; aiHelperCtn.hidden=false; localStorage.aiHelperCtnHidden='';" hidden="">✨</button>
                  <div id="aiHelperCtn" style="display: flex; flex-direction: column; right: 5px; bottom: 5px; width: max-content; position: absolute; z-index: 100; gap: 0.125rem; padding: 0.25rem; border-radius: 3px; min-width: 200px; min-height: 80px;">
                    <div id="aiHelperFeedbackBtn" style="position:absolute;top:0;width:100%;left:0;right:0;height: 0;">
                      <button onclick="window.open('https://perchance.org/ai-coding-helper-feedback')" style="position:absolute; bottom:0.25rem; font-size:70%; right:0.25rem; margin:0; padding:0 0.125rem;">❓</button>
                    </div>
                    <div id="aiHelperCloseBtnCtn" style="position:absolute;top:0;left: 0;width:0;height:0;display:flex;align-items:center;justify-content:center;"><div onpointerdown="aiHelperCtn.hidden=true; showAiHelperBtn.hidden=false; localStorage.aiHelperCtnHidden=1" style="cursor:pointer; background:white; background:light-dark(white, black); color:black; color:light-dark(black, #bababa); border-radius:100%; border:1px solid light-dark(black, #bababa); min-width:1rem; min-height:1rem; display:flex; align-items:center; justify-content:center;"><svg width="10" height="10" viewBox="0 0 24 24"><path d="M6 6l12 12M6 18L18 6" stroke="currentColor" stroke-width="4" stroke-linecap="round"></path></svg></div></div>
                    <select id="aiHelpTypeSelect" onchange="aiHelperSubmitBtn.textContent=this.selectedOptions[0].dataset.submitText;" style="min-height: 1.5rem;">
                      <option value="edit" data-submit-text="🛠️ adjust">𝗲𝗱𝗶𝘁 the existing code</option>
                      <option value="new" data-submit-text="✨ create">write new code (𝘀𝘁𝗮𝗿𝘁 𝗳𝗿𝗲𝘀𝗵)</option>
                      <!-- <option value="question" data-submit-text="✨ ask">ask a question about the code</option> -->
                    </select>
                    <textarea id="aiHelperInputEl" placeholder="Create a simple snake game" style="font-size:85%;flex-grow:1;min-width: 200px;"></textarea>
                    <div style="display:flex; gap:0.25rem;">
                      <button hidden="" style="height:min-content;" id="aiHelperRedoBtn" onclick="undoAiHelper()">⏩ redo</button>
                      <button hidden="" style="height:min-content;" id="aiHelperUndoBtn" onclick="undoAiHelper()">🔙 undo</button>
                      <button style="height:min-content; flex-grow:1;" id="aiHelperSubmitBtn" onclick="executeAiHelper()">🛠️ adjust</button>
                    </div>
                  </div> 
                  <style>
                    #aiHelperCtn {
                      background: #e0e0e0;
                    }
                    @media (prefers-color-scheme: dark) { 
                      #aiHelperCtn {
                        background: rgb(32, 32, 32);
                      }
                    }
                    @keyframes rotate {
                      to { transform: rotate(360deg); }
                    }

                    .cm-editor .cm-highlight-change {
                      background: #d3ed8b;
                    }
                    @media (prefers-color-scheme: dark) { 
                      .cm-editor .cm-highlight-change {
                        background: #495232;
                      }
                    }
                    .cm-panel.cm-panel-lint ul {
                      background-color: transparent !important;
                    }
                    
                    .CodeMirror .cm-highlight-change {
                      background: #d3ed8b;
                    }
                    @media (prefers-color-scheme: dark) { 
                      .CodeMirror .cm-highlight-change {
                        background: #495232;
                      }
                    }
                  </style>
                  <script>
                    if(localStorage.aiHelperCtnHidden) {
                      aiHelperCtn.hidden = true;
                      showAiHelperBtn.hidden = false;
                    } else {
                      aiHelperCtn.hidden = false;
                      showAiHelperBtn.hidden = true;
                    }

                    function getChangeHighlightMarks(original, updated) {
                      const diff = Diff.diffLines(original, updated);
                      const markers = [];
                      let lineNumber = 0;
                      diff.forEach((part) => {
                        const lines = part.value.split('\n');
                        if (part.added) {
                          lines.forEach((line, index) => {
                            if(line.length > 0 || index < lines.length - 1) {
                              markers.push({
                                from: { line: lineNumber, ch: 0 },
                                to: { line: lineNumber, ch: line.length },
                                className: 'cm-highlight-change'
                              });
                              lineNumber++;
                            }
                          });
                        } else if(!part.removed) {
                          lineNumber += lines.length - 1;
                          if (lines[lines.length - 1].length > 0) lineNumber++; 
                        }
                      });
                      return markers;
                    }
                    function clearChangeHighlightMarks() {
                      if(window.outputTemplateEditor._clearMarks) { 
                        window.outputTemplateEditor._clearMarks();
                      } else {
                        window.outputTemplateEditor.getAllMarks().forEach(mark => {
                          if(mark.className === 'cm-highlight-add' || mark.className === 'cm-highlight-change') {
                            mark.clear();
                          }
                        });
                      }
                    }
                    
                    async function executeAiHelper() {
                      let type = aiHelpTypeSelect.value;
                      let instruction = aiHelperInputEl.value; 
                      if(!instruction) return;

                      const submitButtonOriginalText = aiHelperSubmitBtn.textContent;
                      aiHelperSubmitBtn.innerHTML = `⏳ loading…`;
                      aiHelperSubmitBtn.disabled = true;
                      aiHelpTypeSelect.disabled = true;

                      aiHelperUndoBtn.hidden = true;
                      aiHelperRedoBtn.hidden = true;
                      
                      let requestId = Math.random().toString()+Math.random().toString() + "-" + (localStorage.aiHelperRequestIdSuffix || ""); 
                      let data;
                      for(let i = 0; i < 3; i++) {
                        data = await fetch(`/api/aiHelper`, {
                          signal: window.AbortSignal?.timeout?.(5*60000),
                          method: "POST",
                          headers: { "Content-Type": "application/json" },
                          body: JSON.stringify({requestId, type, generatorName:window.generatorName, instruction, modelText:window.modelTextEditor.getValue(), outputTemplateText:window.outputTemplateEditor.getValue()}),
                        }).then(r => r.json()).catch(e => ({error:true, status:e.message}));
                        if(!data.error) break;
                      }

                      aiHelperSubmitBtn.disabled = false;
                      aiHelpTypeSelect.disabled = false;
                      aiHelperSubmitBtn.textContent = submitButtonOriginalText;

                      if(data.status !== "success") {
                        alert(`Sorry, there was an error with the AI helper: ${data.status}${data.status === "too-many-requests" ? " (could be caused by VPN)" : ""}`);
                        return;
                      }

                      window.outputTemplateEditorBeforeAiHelper = window.outputTemplateEditor.getValue();
                      window.modelTextEditorBeforeAiHelper = window.modelTextEditor.getValue();

                      if(type === "new" || type === "edit") {
                        window.outputTemplateEditor.setValue(data.outputTemplateText); 

                        if(data.outputTemplateText.includes("commentsPlugin(") && !/commentsPlugin *= *\{import:comments-plugin\}/.test(window.modelTextEditor.getValue())) window.modelTextEditor.setValue(`commentsPlugin = {import:comments-plugin}\n${window.modelTextEditor.getValue()}`);
                        if(data.outputTemplateText.includes("generateImage(") && !/generateImage *= *\{import:text-to-image-plugin\}/.test(window.modelTextEditor.getValue())) window.modelTextEditor.setValue(`generateImage = {import:text-to-image-plugin}\n${window.modelTextEditor.getValue()}`);
                        if(data.outputTemplateText.includes("generateText(") && !/generateText *= *\{import:ai-text-plugin\}/.test(window.modelTextEditor.getValue())) window.modelTextEditor.setValue(`generateText = {import:ai-text-plugin}\n${window.modelTextEditor.getValue()}`);
                        if(data.outputTemplateText.includes("superFetch(") && !/superFetch *= *\{import:super-fetch-plugin\}/.test(window.modelTextEditor.getValue())) window.modelTextEditor.setValue(`superFetch = {import:super-fetch-plugin}\n${window.modelTextEditor.getValue()}`);
                        
                        // check if we can remove generateImage and/or generateText imports:
                        let currentOutputTemplateText = window.outputTemplateEditor.getValue();
                        if(!currentOutputTemplateText.includes("generateImage(") && !window.modelTextEditor.getValue().replace(/generateImage *= *\{import:text-to-image-plugin\}/g, "").includes("generateImage(")) {
                          window.modelTextEditor.setValue(window.modelTextEditor.getValue().replace(/generateImage *= *\{import:text-to-image-plugin\}/g, ""));
                        }
                        if(!currentOutputTemplateText.includes("generateText(") && !window.modelTextEditor.getValue().replace(/generateText *= *\{import:ai-text-plugin\}/g, "").includes("generateText(")) {
                          window.modelTextEditor.setValue(window.modelTextEditor.getValue().replace(/generateText *= *\{import:ai-text-plugin\}/g, ""));
                        }

                        window.outputTemplateEditorAfterAiHelper = window.outputTemplateEditor.getValue();
                        window.modelTextEditorAfterAiHelper = window.modelTextEditor.getValue();

                        if(type === "edit") {
                          if(!window.Diff) {
                            let script = document.createElement('script');
                            script.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/diff.min.js";
                            document.body.appendChild(script);
                            while(!window.Diff) await new Promise(r => setTimeout(r, 200));
                          }
                          if(!window.addedHighlightChangeStuff84783) {
                            window.addedHighlightChangeStuff84783 = true;
                            window.outputTemplateEditor.on('change', (instance, changeObj) => {
                              clearChangeHighlightMarks();
                            });
                          }
                          clearChangeHighlightMarks(); 
                          let markers = getChangeHighlightMarks(window.outputTemplateEditorBeforeAiHelper, window.outputTemplateEditorAfterAiHelper);
                          markers.forEach(marker => {
                            if(window.outputTemplateEditor._markText) window.outputTemplateEditor._markText(marker.from, marker.to, { className: marker.className });
                            else window.outputTemplateEditor.markText(marker.from, marker.to, { className: marker.className });
                          });
                        }

                        editor.handleReloadButtonClick();
                        aiHelperUndoBtn.hidden = false;
                        aiHelperUndoBtn.onclick = function() {
                          clearChangeHighlightMarks();
                          window.outputTemplateEditor.setValue(window.outputTemplateEditorBeforeAiHelper);
                          window.modelTextEditor.setValue(window.modelTextEditorBeforeAiHelper);
                          editor.handleReloadButtonClick();
                          aiHelperUndoBtn.hidden = true;
                          aiHelperRedoBtn.hidden = false;
                        };
                        aiHelperRedoBtn.onclick = function() {
                          window.outputTemplateEditor.setValue(window.outputTemplateEditorAfterAiHelper);
                          window.modelTextEditor.setValue(window.modelTextEditorAfterAiHelper);
                          editor.handleReloadButtonClick();
                          aiHelperUndoBtn.hidden = false;
                          aiHelperRedoBtn.hidden = true;
                          if(type === "edit") {
                            clearChangeHighlightMarks();
                            let markers = getChangeHighlightMarks(window.outputTemplateEditorBeforeAiHelper, window.outputTemplateEditorAfterAiHelper);
                            markers.forEach(marker => window.outputTemplateEditor.markText(marker.from, marker.to, { className: marker.className }));
                          }
                        };
                      } else if(type === "question") {
                        // TODO
                      }
                    }
                    window.addEventListener("pointerdown", (e) => {
                      if(e.target.closest("#aiHelpTypeSelect") || e.target.closest("#aiHelperCloseBtnCtn")) return;
                      if(e.target.closest("#aiHelperUndoBtn") || e.target.closest("#aiHelperRedoBtn")) return;
                      if(e.target.closest("#aiHelperFeedbackBtn")) return;
                      if(e.target.closest("#aiHelperCtn")) { aiHelperCtn.style.minWidth='300px'; aiHelperCtn.style.minHeight='200px'; }
                      else { aiHelperCtn.style.minWidth='200px'; aiHelperCtn.style.minHeight='80px'; }
                    });
                    {
                      let aiHelpTypeToExamples = {
                        new: ["Create a simple snake game", "Create a cute profile page with 3 tabs. One for 'about me', one for 'links' and one for 'feedback' with a comments box. Add some kaomojis and pastel colors. Actually also add a 4th tab with a grid of toggleable checkboxes.", "Make an infinite scroller of AI generated images, with the old ones at the top being deleted as you scroll down far enough.", "create a simple centered template with a button which increments a counter", "make a wizard themed geocities homepage for me", "make a space invaders game using emojis"],
                        edit: ["Fix mistakes", "make it look nicer", "make it look better on smaller screens (like mobile phones)", "the button isn't centered properly. fix pls", "Make the button bigger and add a blue gradient background", "Make all the text on the page wobble around", "Add more code comments so I can understand everything better", "Add a loading thing to show when the images are loading", "make it more silly", "if it's june, make it rain transparent rainbow emojis on the page (and also add a little button to trigger it even if it's not june)", "Use this image as the background but blur it slightly: https://example.com/image.jpg", "reduce the number of lines of code", "add an optional dark mode"],
                        question: ["How does the code in the getPosition function work?", "What does display:flex do? How does it work?", "How can I make the background gradient change depending on the mouse position?"],
                      };
                      let i = 0;
                      setInterval(() => {
                        if(document.querySelector("#aiHelperInputEl").offsetHeight === 0) return;
                        let examples = aiHelpTypeToExamples[document.querySelector("#aiHelpTypeSelect").value];
                        i++;
                        if(i > examples.length-1) i = 0;
                        aiHelperInputEl.placeholder = examples[i];
                      }, 3000);
                    }
                  </script>
                  <div class="toggle-wrap-button-html" data-ref="outputEditorWrapRefButton" onclick="editor.toggleOutputEditorWrap()">wrap</div>
                  <textarea id="template"></textarea>
                </div>
              </div>
            </div>
          
            <div class="warningsModal" data-ref="warningsModal" style="display:none;">
              <div style="z-index:50;" class="background" onclick="editor.closeWarningsModal()"></div>
              <div style="z-index:51;" class="outer-wrapper" onclick="editor.handleWarningsModalOuterWrapperClick(event)">
                <div data-ref="warningsModalContentWrapper" class="content-wrapper">
                  <div class="view">
                    <div class="modal-body" style="max-height: 500px; overflow-y: auto;">
                      <div style="padding: 1rem; background: #eaeaea;"><span style="opacity:0.5;">The items listed below aren't errors - they're just "warnings". Perchance generates "warnings" when it detects code in your editor panel that looks like it may be a mistake, but which is technically not "erroneous" - that is, it's valid Perchance syntax, but it's "unusual" code and so might have been an accident on your part. Feel free to ignore these warnings if you know what you're doing! ꒰•ᴗ•꒱</span></div>
                      <div data-ref="warningsWrapper" style="padding-bottom: 1rem;"></div>
                    </div>
                    <div class="modal-footer">
                      <button style="width:100%;" onclick="editor.closeWarningsModal()">close</button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <script>
              window.editor = {
                root: document.querySelector("#editorEl"),
                refs: new Proxy({}, {
                  get(target, prop, receiver) {
                    return document.querySelector(`#editorEl [data-ref='${prop}']`);
                  },
                }),
                init: async function({startInEditMode}={}) {
                  if(this.alreadyInited) return;
                  this.alreadyInited = true;

                  document.querySelector("#editorEl #input").value = app.data.generator.modelText;
                  document.querySelector("#editorEl #template").value = app.data.generator.outputTemplate;

                  this.updateOutputDelayTimeout = null;
                  this.evaluateTextResolveMap = {};
                  this.outputIframe = null;

                  this.autoReload = JSON.parse( localStorage.getItem("editor-auto-reload") );
                  if(this.autoReload === null) {
                    this.autoReload = true; // defaults to true
                    localStorage.setItem("editor-auto-reload", this.autoReload);
                  }

                  window.toggleOutputAutoReloadOnEdits = (checkboxEl) => {
                    if(checkboxEl.checked) {
                      this.autoReload = true;
                      this.updateOutput({fullRefresh:false, removeUnfoundDeps:true});
                    } else {
                      this.autoReload = false;
                    }
                    localStorage.setItem("editor-auto-reload", this.autoReload);
                  }

                  document.addEventListener('keydown', function(event) {
                    if(event.ctrlKey || event.metaKey) {
                      if(event.key === 'r') {
                        if(window.currentInterfaceMode === "edit") {
                          event.preventDefault();
                          editor.handleReloadButtonClick();
                        }
                      }
                    }
                  });

                  let lastReloadButtonClickTime = 0;
                  this.handleReloadButtonClick = (e) => {
                    outputLoadSpinner.style.backgroundColor = "rgba(255,255,255,0.3)";
                    if(Date.now()-lastReloadButtonClickTime > 500) {
                      lastReloadButtonClickTime = Date.now();
                      window.onNextOutputIframeReloadHandlers.push(function() {
                        outputIframeEl.contentWindow.postMessage({type:"__triggerPageFocus8573946292"}, "*"); // for cases where e.g. the iframe requires focus for keyboard events (like arrow keys in a game)
                      });
                      window.triggerFocusOnNextIframeLoad = true; // for cases where e.g. the iframe requires focus for keyboard events (like arrow keys in a game)
                      this.updateOutput({fullRefresh:true, removeUnfoundDeps:true});
                    }

                    // NOTE: The below if/else is no longer needed due to the `__initWithDataFromParentWindow=1` stuff I'm now doing - i.e. the reload button tells the iframe to not use the data that is send along with the html file, and instead request the data from the parent during init.
                    // if(window.perchanceSaveState === "saved" || !window.editsHaveBeenMadeSincePageLoad) {
                    //   this.updateOutput({fullRefresh:true, removeUnfoundDeps:true});
                    // } else {
                    //   alert("To initiate a \"hard-reload\" you need to first save your generator. Please click save and then try again. Alternatively, you can reload the whole browser page using your browser's reload button, but this will discard your changes.");
                    // }
                  }

                  // function getScrollBarWidth() {
                  //   let el = document.createElement("div");
                  //   el.innerHTML = "\n".repeat(50)
                  //   el.style.cssText = "position:absolute; overflow:scroll; width:30px; height:30px;";
                  //   document.body.appendChild(el);
                  //   let scrollBarWidth = el.offsetWidth - el.clientWidth;
                  //   el.remove();
                  //   return scrollBarWidth;
                  // }
                  
                  // let scrollBarWidth = getScrollBarWidth();
                  // document.querySelectorAll(".toggle-wrap-button").forEach(el => {
                  //   el.style.
                  // });

                  let eSplitLastHeight = null;
                  this.switchToViewMode = () => {

                    document.querySelectorAll(".function-popup").forEach(el => el.style.display = "none"); // hide any open function popups

                    window.currentInterfaceMode = "view";
                    this.root.querySelector("#e").style.position = "initial";
                    this.root.querySelector("#e").style.border = "none";

                    // so we can recover it if they open the editor again:
                    eSplitLastHeight = this.root.querySelector("#e").style.maxHeight; 
                    this.root.querySelector("#e").style.minHeight = "";
                    this.root.querySelector("#e").style.maxHeight = "";

                    this.root.querySelector("#output-buttons-ctn").style.display = "none";
                    let output = this.root.querySelector("#output");
                    let systemIsInDarkMode = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
                    
                    // output.style.position = "absolute";

                    menuBarEl.style.borderBottom = "";
                    output.style.borderTop = "none";

                    if(systemIsInDarkMode) {
                      
                    } else {
                      output.querySelector("iframe").style.background = "white";
                      output.style.background = "white";
                    }
                    // output.style.height = "initial";
                    // output.style.borderLeft = "";
                    // output.style.borderRight = "";
                    // output.style.borderBottom = "none";

                    // if(window.shouldAddOutputBorderBottomInViewMode) {
                    //   document.querySelector("#editorEl #output").style.borderBottom = "";
                    // }

                    // need these because otherwise for some reason there's some weird `overscroll-behaviour` stuff near the edges of the screen (even with touch-action:none overlay workaround).
                    this.root.querySelectorAll("#main .gutter").forEach(el => el.style.display="none");
                    this.root.querySelector("#a").style.display = "none";
                    this.root.querySelector("#f").style.display = "none";
                  }
                  
                  this.alreadyInited = false; 
                  this.switchToEditMode = () => {

                    document.querySelectorAll(".function-popup").forEach(el => el.style.display = ""); // show any open function popups

                    window.hasBeenInEditModeAtLeastOnce = true; 
                    window.currentInterfaceMode = "edit";
                    let systemIsInDarkMode = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);

                    this.root.querySelector("#e").style.position = "relative";
                    this.root.querySelector("#e").style.border = "";

                    // recover last height/width:
                    if(eSplitLastHeight) {
                      this.root.querySelector("#e").style.minHeight = eSplitLastHeight;
                      this.root.querySelector("#e").style.maxHeight = eSplitLastHeight;
                    }

                    this.root.querySelector("#output-buttons-ctn").style.display = "";
                    let output = this.root.querySelector("#output");
                    output.style.position = "relative";

                    menuBarEl.style.display = "flex";
                    minimalModeMenuBtn.style.display = "none";

                    menuBarEl.style.borderBottom = "none";
                    output.style.borderTop = "";

                    if(systemIsInDarkMode) {
                      // output.style.borderTop = "1px solid #575757";
                    } else {
                      // output.style.borderTop = "1px solid #C0C0C0";
                    }
                    // output.style.top = "0px";
                    // output.style.bottom = "35px";
                    // output.style.border = "none";
                    //output.style.height = "100%";
                    // output.style.borderLeft = "none";
                    // output.style.borderRight = "none";
                    // output.style.borderBottom = "";

                    // need these because otherwise for some reason there's some weird `overscroll-behaviour` stuff near the edges of the screen (even with touch-action:none overlay workaround).
                    this.root.querySelectorAll("#main .gutter").forEach(el => el.style.display="");
                    this.root.querySelector("#a").style.display = "flex";
                    this.root.querySelector("#f").style.display = "flex";

                    if(!window.TEST_NEW_EDITOR_1) {
                      setTimeout(() => {
                        this.modelTextEditor.refresh();
                        this.outputTemplateEditor.refresh();
                      }, 10); 
                    }
                  }

                  this.openWarningsModal = function() {
                    this.refs.warningsModal.style.display = "block";
                  }
                  this.handleWarningsModalOuterWrapperClick = function(e) {
                    if(!this.refs.warningsModalContentWrapper.contains(e.target)) {
                      this.closeWarningsModal();
                    }
                  }
                  this.closeWarningsModal = function() {
                    this.refs.warningsModal.style.display = "none";
                  }

                  window.receivedIframeSelfReloadingResponses = {};

                  window.outputIframeHardReloadFinishedResolvers = [];
                  window.currentlyReloadingOutputIframePromise = null;
                  window.hardReloadOutputIframe = async () => { // must use arrow function for correct `this`
                    await window.currentlyReloadingOutputIframePromise; // wait for existing reload to finish if there is one

                    window.currentlyReloadingOutputIframePromise = new Promise(r => window.outputIframeHardReloadFinishedResolvers.push(r)); // (EDIT: the comment that follows this parenthetical is i think patched by just waiting for the previous promise, as I'm now doing above) this isn't actually ideal because if there are multiple concurrent calls then the first one that loads will resolve all of them, even if that "load" is actually "stale" (i.e. using older code). But it shouldn't be a problem "in practice". It'll hopefully do for now.
                    this.updateOutput({fullRefresh:true, removeUnfoundDeps:true});
                    await window.currentlyReloadingOutputIframePromise;
                  };

                  window.mostRecentFullRefreshUpdateDependenciesPromise = Promise.resolve();
                  this.updateOutput = async ({fullRefresh, removeUnfoundDeps, checkForNewDeps=true}={}) => {
                    let iframe = this.root.querySelector("#output iframe");
                    this.outputIframe = iframe;

                    if(removeUnfoundDeps) {
                      app.data.dependencies = app.data.dependencies.filter(d => d.found !== false);
                    }

                    if(fullRefresh) {
                      outputLoadSpinner.style.display = "flex";

                      // Note that we check *all dependencies*, not just direct imports/children of this generator, since any descendent may have been updated.
                      let depNames = app.data.dependencies.map(d => d.name);

                      // we await this in the `requestOutputUpdate` event (from iframe) handling so it can load in parallel with iframe reload for __initWithDataFromParentWindow stuff.
                      if(checkForNewDeps) {
                        window.mostRecentFullRefreshUpdateDependenciesPromise = this.updateDependencies(depNames, {checkForUpdatesToDepsWeAlreadyHave:true});
                      } else {
                        // leave it set to the last promise rather than e.g. Promise.resolve() because that allows other code to wait for last check to finish
                      }

                      iframe.onload = () => {
                        // previously thought we didn't need this request anymore because we embed the data in the loaded iframe,
                        // BUT WE STILL NEED IT for when they click the reload button but they haven't saved their changes to the server.
                        // the server can only render the the document with the data that it has.
                        // EDIT: I've commented this out because now I just tell them that they need to save before doing a "hard" reload. The
                        //       previous approach was causing script tags to be doubly-executed which caused all sorts of troubles (e.g. p5.js creating 2 "setup" canvases).
                        //this.updateOutputRequest();
                      }
                      if(false && window.location.hostname === "app.dev") { // "false &&" to disable this for now
                        iframe.src = "http://null.app.dev:3001/"+app.data.generator.name;
                      } else {
                        // iframe.src = "https://null.perchance.org/" + app.data.generator.name + "?__cacheBuster=" + Math.random().toString().slice(2); 
                        // iframe.src = `https://${window.generatorPublicId}.perchance.org/` + app.data.generator.name + "?__cacheBuster=" + Math.random().toString().slice(2);

                        let url = new URL(window.location.href);
                        url.hostname = `${window.generatorPublicId}.perchance.org`;

                        // EDIT: we no longer need to bust cache since we're using modelText and outputTemplate from parent window (and we do updateDependencies above in case they've edited an import)
                        // url.searchParams.set("__cacheBust", Math.random().toString()+Math.random().toString());
                        
                        let v = 1; // window.lastInitDataFromParentWindowValue==1 ? 2 : 1; // Toggle between 1 and 2 because if URL is same as it current src, then `iframe.src=url` won't cause iframe to reload.
                        // WARNING: I'm currently using this '__initWithDataFromParentWindow' query param on the server to know whether I should turn on Origin-Agent-Cluster stuff, since it's useful for devs (stops infinite loop freezes), but causes virtual keyboard bugs for users: https://issues.chromium.org/issues/339927578
                        url.searchParams.set("__initWithDataFromParentWindow", v);
                        window.lastInitDataFromParentWindowValue = v;

                        // Note that unlike in case of initial page load, we don't need __generatorLastEditTime stuff here because we're loading data from parent window, which has latest data.

                        if(iframe.src.split("#")[0] === url.toString().split("#")[0]) {
                          // this is faster, because it doesn't bust the cdn cache, and also prevents devtools source/context changing:
                          let requestId = Math.random().toString()+Math.random().toString();
                          iframe.contentWindow.postMessage({type:"__triggerPageReload857392947", requestId}, "*");
                          
                          // force reload (by removing and re-adding iframe to dom) e.g. to deal with case where it's frozen or paused in debugger
                          setTimeout(function() {
                            if(!window.receivedIframeSelfReloadingResponses[requestId]) {
                              console.debug("Forced hard-reload of iframe due to infinite loop or debugger paused.");
                              iframe.parentNode.insertBefore(iframe, iframe.nextSibling);
                            }
                          }, 300);

                        } else {
                          iframe.src = url.toString();
                        }

                      }
                    } else {
                      this.updateOutputRequest();
                    }
                  };

                  this.evaluateText = async (text) => {
                    let callerId = "id-" + Math.random() + "-" + Math.random();
                    this.outputIframe.contentWindow.postMessage({text, callerId, command:"evaluateText"}, '*');

                    return new Promise((resolve) => {
                      this.evaluateTextResolveMap[callerId] = resolve;
                    });
                  };

                  let existingDepsCheckAbortController = null;
                  this.updateDependencies = async (requiredDeps, opts={}) => {

                    // EDIT: We *cannot* do this (and we don't need to anyway), because, confusingly, requiredDeps *may* be a subset of deps - most notably only *direct* children of the generator.
                    // app.data.dependencies = app.data.dependencies.filter(d => requiredDeps.includes(d.name));

                    let currentDeps = app.data.dependencies.map(d => d.name);
                    
                    // see which new imports we need to do based on currentDeps and requiredDeps:
                    let depNamesToDownload;
                    if(opts.checkForUpdatesToDepsWeAlreadyHave) {
                      depNamesToDownload = requiredDeps; // check for updates to ALL required deps, in case they've since been edited
                    } else {
                      depNamesToDownload = requiredDeps.filter(d => !currentDeps.includes(d)); // only download data for generators we don't already have
                    }

                    if(depNamesToDownload.length === 0) return false;

                    // If another dependency request trails right behind this one then it'll override `this.latestDependencyRequestTime` and thus this request will be ignored (see the line below the fetch request)
                    let thisDependencyRequestStartTime = Date.now();
                    this.latestDependencyRequestStartTime = thisDependencyRequestStartTime;

                    // tell server about the data we've already got, and if it all matches latest data, then it'll send back `dataAlreadyUpToDate:true`, indicating that no updates are needed
                    let generatorNameToLastKnownEditTime = {};
                    for(let dep of app.data.dependencies) {
                      generatorNameToLastKnownEditTime[dep.name] = dep.lastEditTime;
                    } 
                    
                    if(existingDepsCheckAbortController) existingDepsCheckAbortController.abort("newer_request_obsoletes_this_one");
                    existingDepsCheckAbortController = new AbortController();
                    
                    let result;
                    for(let i = 0; i < 3; i++) {
                      result = await fetch("/api/getGeneratorsAndDependencies", {
                        signal: existingDepsCheckAbortController.signal,
                        method: 'POST',
                        body: JSON.stringify({generatorNames:depNamesToDownload, generatorNameToLastKnownEditTime}),
                        headers: { 'Content-Type': 'application/json' },
                      }).then(r => r.json()).catch(e => {
                        if(e === "newer_request_obsoletes_this_one") return e;
                        else console.error("Error while trying to get generator dependencies:", e);
                      });
                      existingDepsCheckAbortController = null;

                      if(result === "newer_request_obsoletes_this_one") return false;
                      if(result) break;
                    }
                    if(!result) {
                      if(window.location.hash.startsWith("#edit")) {
                        alert("Error while trying to get generator dependencies. This is likely a server bug. Please report on lemmy.world/c/perchance if this is happening often.");
                      }
                      throw new Error("Couldn't get generator dependencies.");
                    }
                    
                    /*just for debugging:*/if(thisDependencyRequestStartTime > this.latestDependencyRequestTime) throw new Error("this shouldn't be possible");
                    if(thisDependencyRequestStartTime !== this.latestDependencyRequestStartTime) return false;

                    if(result.status === "success") {

                      if(result.dataAlreadyUpToDate) {
                        console.debug("Dependencies were already up to date.");
                        return false; // false means "no new/updated dependencies"
                      }

                      for(let g of result.generators) {
                        if(g.found === false) {
                          console.warn("Couldn't find module named '"+g.name+"'.");
                        }
                      }

                      // Update dependencies with new data:
                      let generatorNameData = {};
                      for(let data of result.generators) {
                        generatorNameData[data.name] = data;
                      }
                      for(let data of app.data.dependencies) {
                        if(!generatorNameData[data.name]) generatorNameData[data.name] = data;
                      }
                      app.data.dependencies = Object.values(generatorNameData);

                      return true;

                    } else {
                      console.error("Error while trying to download dependencies:", newDeps);
                    }
                  }

                  this.updateOutputRequest = () => {
                    this.outputIframe.contentWindow.postMessage({
                      command:"updateOutput",
                      generator:{modelText:this.modelTextEditor.getValue(), outputTemplate:this.outputTemplateEditor.getValue(), name:app.data.generator.name},
                      dependencies: app.data.dependencies,
                    }, '*');
                  };

                  const warnings = {

                    "unescaped-equals-sign": `<div class="warning-item"><b style="color:#d58700">Warning:</b> Is the text on line number <b>###lineNumber###</b> (in ###generatorNameText### generator's code) meant to be a "property" of its parent (i.e. <code>property=value</code>), or it is just meant to be a regular item that happens to have an equals character (<code>=</code>) in it? If it's meant to be a regular item, then you'll want to put a "backslash" character (<code>\\</code>) before the equals sign like this: <code>\\=</code>. That's because the equals sign is a special character in Perchance that is used for creating "properties". You can read more about this in the <a target="_blank" href="/tutorial">tutorial</a>.</div>`,

                    "single-equals-in-dynamic-odds": `<div class="warning-item"><b style="color:#d58700">Warning:</b> The dynamic odds notation on line number <b>###lineNumber###</b> (in ###generatorNameText### generator's code) has a single equals sign instead of a double-equals sign. A single equals sign is used to put a value into a variable - for example <code>age = 10</code> means "put the value <code>10</code> into the <code>age</code> variable" whereas <code>age == 10</code> means "is <code>age</code> equal to <code>10</code>?".</div>`,
                    
                    "single-equals-in-if-else-condition": `<div class="warning-item"><b style="color:#d58700">Warning:</b> The if/else condition on line number <b>###lineNumber###</b> (in ###generatorNameText### generator's code) has a single equals sign instead of a double-equals sign. A single equals sign is used to put a value into a variable - for example <code>age = 10</code> means "put the value <code>10</code> into the <code>age</code> variable" whereas <code>age == 10</code> means "is <code>age</code> equal to <code>10</code>?".</div>`,
                    
                    "square-brackets-wrapping-variable-name-within-square-block": `<div class="warning-item"><b style="color:#d58700">Warning:</b> On line number <b>###lineNumber###</b> (in ###generatorNameText### generator's code), you've got a square block - i.e. some square brackets with some stuff inside. Nothing wrong with that. But inside that square block it looks like you've got another square block? Whenever you're writing stuff inside a square block, you can refer to variable and list name <u>directly</u> - no need to put them inside square blocks. So instead of <code style="white-space:nowrap">[[noun].pluralForm]</code>, you'd just write <code style="white-space:nowrap">[noun.pluralForm]</code>, and instead of <code style="white-space:nowrap">[[characterAge] + 3]</code>, you'd just write <code style="white-space:nowrap">[characterAge + 3]</code>, and instead of <code style="white-space:nowrap">^[[age] < 10]</code>, you'd just write <code style="white-space:nowrap">^[age < 10]</code>, and instead of <code style="white-space:nowrap">[[age] > 60 ? [oldDescription] : [youngDescription]]</code>, you'd just write <code style="white-space:nowrap">[age > 60 ? oldDescription : youngDescription]</code>. You should <b>use normal parentheses to group</b> calculations and conditions, like this: <code style="white-space:nowrap">[(age + 1) * height]</code> and this: <code style="white-space:nowrap">[isMammal || (isReptile && isBrown)]</code>. In fact, if you wrap list/variable names in square brackets when you're <i>already inside a square block</i> then this can sometimes cause all sorts of sneaky errors that are hard to "debug". Square brackets <u>can</u> "legally" be used within square brackets in <i>some</i> circumstances, but they have a special meaning (learn more about this on the <a href="https://perchance.org/examples" target="_blank">examples</a> page - especially the "Dynamic Sub-list Referencing" section). One final note: It's okay to use square brackets within square brackets if the <i>inner</i> square brackets are themselves within double-quotes, like so: <code style="white-space:nowrap">[n == 1 ? "[prefix]er" : "[prefix]ers"]</code>.</div>`,

                    "top-level-list-name-same-as-html-element-id": `<div class="warning-item"><b style="color:#d58700">Warning:</b> It looks like you have a list name on line number <b>###lineNumber###</b> that has the same name as an element's <code>id="..."</code> attribute? If so, note that these will conflict with one another and potentially cause errors. For example if you had a list called <code>animal</code>, then you shouldn't have an element like this: <code>&lt;p id="animal"&gt;...&lt;/p&gt;</code></div>`,

                    "duplicate-top-level-list-name": `<div class="warning-item"><b style="color:#d58700">Warning:</b> It looks like you have a list name on line number <b>###lineNumber###</b> (in ###generatorNameText### generator's code) that has the same name as an earlier list/import/variable?</div>`,

                  };

                  this.generatorMetaData = undefined;
                  
                  this.toggleOutputEditorWrap = function() {
                    let btn = this.refs.outputEditorWrapRefButton;
                    let state = this.outputTemplateEditor.getOption('lineWrapping');
                    if(state) {
                      btn.innerText = "wrap";
                    } else {
                      btn.innerText = "unwrap";
                    }
                    // record cursor position:
                    let cursorLine = this.outputTemplateEditor.getCursor().line;
                    let cursorTop = this.outputTemplateEditor.cursorCoords().top - this.outputTemplateEditor.display.wrapper.getBoundingClientRect().top;

                    this.outputTemplateEditor.setOption('lineWrapping', !state);
                    localStorage[`outputEditorWrap_${window.generatorName}`] = !state ? "1" : "";

                    // recover scroll to cursor position:
                    this.outputTemplateEditor.scrollIntoView({line:cursorLine, char:0}, cursorTop);
                  };
                  this.toggleCodeEditorWrap = function() {
                    let btn = this.refs.codeEditorWrapRefButton;
                    let state = this.modelTextEditor.getOption('lineWrapping');
                    if(state) {
                      btn.innerText = "wrap";
                    } else {
                      btn.innerText = "unwrap";
                    }
                    // record cursor position:
                    let cursorLine = this.modelTextEditor.getCursor().line;
                    let cursorTop = this.modelTextEditor.cursorCoords().top - this.modelTextEditor.display.wrapper.getBoundingClientRect().top;
                    
                    this.modelTextEditor.setOption('lineWrapping', !state);
                    localStorage[`codeEditorWrap_${window.generatorName}`] = !state ? "1" : "";

                    // recover scroll to cursor position:
                    this.modelTextEditor.scrollIntoView({line:cursorLine, char:0}, cursorTop);
                  };

                  this.allListsFolded = false;
                  this.toggleCodeEditorFold = function() {
                    let btn = this.refs.codeEditorFoldRefButton;
                    this.allListsFolded ? CodeMirror.commands.unfoldAll(this.modelTextEditor) : CodeMirror.commands.foldAll(this.modelTextEditor);
                    this.allListsFolded = !this.allListsFolded;
                    btn.innerText =  this.allListsFolded ? "unfold" : "fold";
                  };


                  this.outputIframe = this.root.querySelector("#output iframe");

                  this.refs.autoReloadCheckbox.checked = this.autoReload;

                  window.addEventListener("message", async (e) => {
                    let origin = e.origin || e.originalEvent.origin;
                    if(origin !== "https://null.perchance.org" && origin !== `https://${window.generatorPublicId}.perchance.org`) return;

                    if(e.data.type === "evaluateTextResponse" && typeof e.data.text === "string" && typeof e.data.callerId === "string") {
                      let resolveMap = this.evaluateTextResolveMap;
                      if(resolveMap[e.data.callerId]) {
                        resolveMap[e.data.callerId](e.data.text);
                        delete resolveMap[e.data.callerId]; 
                      } 
                    } 

                    if(e.data.type === "requestOutputUpdate") { // for 'hard reload' without having to first save data to server
                      // user clicks reload button which triggers a fullRefresh, but it adds __initWithDataFromParentWindow=1 to the URL, which causes the outputIframeContent.html code to not use the data embedded in the HTML, and instead request this parent frame for the 'fresh' data
                      if(window.shouldWaitForNewDepsBeforeRequestOutputUpdate) {
                        // this is a bit hacky. basically if the optimistic update failed (see below) then we set shouldWaitForNewDepsBeforeRequestOutputUpdate to true and do another hard reload, which will trigger this if condition
                        window.shouldWaitForNewDepsBeforeRequestOutputUpdate = false;
                        await window.mostRecentFullRefreshUpdateDependenciesPromise; // wait until we've got all dep data
                        this.updateOutputRequest();
                      } else {
                        this.updateOutputRequest(); // <-- optimistically assume no dep updates (which will be true most of the time), and we just reload again below if there were
                        let thereWereDepUpdates = await window.mostRecentFullRefreshUpdateDependenciesPromise; // so dependency stuff can load in parrallel with iframe for __initWithDataFromParentWindow fullRefresh
                        if(thereWereDepUpdates) {
                          window.shouldWaitForNewDepsBeforeRequestOutputUpdate = true;
                          this.updateOutput({fullRefresh:true}); // must hard-reload because otherwise script tags execute twice
                        }
                      }
                    }

                    if(e.data.type === "saveKeyboardShortcut") {
                      app.handleIframeSaveRequest();
                    }

                    if(e.data.type === "__triggerPageReloadResponse5792947") {
                      window.receivedIframeSelfReloadingResponses[e.data.requestId] = true;
                    }

                    // if(e.data.type === "finishedLoading") {
                    //   window.perchanceOutputIframeFinishedFirstLoad = true;
                    //   // initialPageLoadSpinner.style.display = "none";
                    //   outputLoadSpinner.style.display = "none";
                    // }

                    if(e.data.type === "finishedLoadingIncludingMetaData" || e.data.type === "failedToLoadDueToGeneratorErrors") {
                      
                      if(e.data.imports) { // <-- need to check because failedToLoadDueToGeneratorErrors doesn't give us imports
                        // we need to check if there are new imports before resolving the hard reload stuff because the saveGenerator function uses a hard reload before saving (which triggers these messages and resolves below), and we want to make sure we save the generator with all its up-to-date dependencies included.
                        let wereNewDeps = await window.lastImportsUpdateDependencyCheckPromise;
                        if(wereNewDeps) return; // don't want to resolve yet - the importsUpdate handler will trigger a second hard reload
                      }

                      for(let resolver of window.outputIframeHardReloadFinishedResolvers) {
                        resolver();
                      }
                      window.outputIframeHardReloadFinishedResolvers = [];
                    }

                    if(e.data.type === "importsUpdate" && Array.isArray(e.data.imports) && e.data.imports.filter(i => typeof i !== 'string').length === 0) {
                      await window.thisIsNotAnOldCachedPagePromise; // <-- wait until we've confirmed that this is the latest version of this generator. this prevents a weird race condition where an import update will happen fast during page load and beat the cache bust, which cause an auto-save (importsUpdates can do this), and overwrites the new code with old code.
                      // (note that the above promise won't resolve unless it's true)

                      window.lastImportsUpdateDependencyCheckPromise = this.updateDependencies(e.data.imports); // i think we only want to check for NEW deps here, not updates to existing deps, becuase a full iframe reload will do the latter anyway.

                      let wereNewDeps = await window.lastImportsUpdateDependencyCheckPromise; // <-- this actually downloads new dependencies (**if needed**, else returns false)
                      if(wereNewDeps) {
                        // we only update if there were new dependencies otherwise we will get into infinite loops
                        // (due to the way I've handled removing dependencies (I keep them cached still))
                        // TODO: this whole imports-update part is terrible and needs re-writing to make it simple and understandable.
                        // Wouldn't take toooo much work.
                        this.updateOutput({fullRefresh:true}); // <-- this triggers iframe updateOutput function. `true` => fullRefresh, i.e. fully reload the iframe with __initWithDataFromParentWindow
                      }
                      
                      if(wereNewDeps || app.data.dependencies.length > e.data.imports.length) {
                        // if dependency was *dropped*, no need to update the output - just need to update the data:
                        app.generatorEditedCallback({imports:e.data.imports});
                      }
                      
                    }

                    if(e.data.type === "metaUpdate") {
                      if(e.data._validation.generatorName !== app.data.generator.name) return; // <-- trying to stop weird Google crawler page title bug

                      // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                      // WARNING WARNING WARNING WARNING WARNING WARNING WARNING: If you change this at all, make sure to do a thorough check for XSS bugs. Saved meta info must be sanitised ON THE SERVER during rendering.
                      // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                      let title = undefined;
                      let description = undefined;
                      let image = undefined;
                      let tags = undefined;
                      let header = undefined;
                      let dynamic = undefined;

                      // if(typeof e.data.html === "string") {
                      //   if(e.data.html.length < 100_000 && window.shouldLiftGeneratorHtmlFromEmbed) {
                      //     window.document.querySelector("#generator-description").innerHTML = DOMPurify.sanitize(e.data.html, {ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'p', 'div', 'pre', 'button', 'i', 'b', 'a', 'ul', 'li', 'br', 'ol', 'hr'], ALLOWED_ATTR: ['href']});
                      //     if(!window.generatorCanLinkWithRelFollow) window.document.querySelectorAll("#generator-description a").forEach(a => a.rel="nofollow");
                      //   }
                      // }

                      if(typeof e.data.title === "string") {
                        title = e.data.title.slice(0, 500); // MUST be sanitised on the server during rendering
                      }
                      if(typeof e.data.description === "string") {
                        description = e.data.description.slice(0, 3000); // MUST be sanitised on the server during rendering
                      }
                      if(typeof e.data.image === "string") {
                        image = e.data.image.slice(0, 500); // MUST be sanitised on the server during rendering
                      }
                      if(typeof e.data.dynamic === "string") {
                        dynamic = e.data.dynamic.slice(0, 40000);
                      }
                      if(typeof e.data.tags === "string") {
                        tags = e.data.tags.slice(0, 1000).split(",").map(t => t.trim()).filter(t => t.length > 0);
                      }
                      if(e.data.header && typeof e.data.header === "object") {
                        header = {};
                        if(typeof e.data.header.background === "string") {
                          if(CSS.supports("background", e.data.header.background)) {
                            header.background = e.data.header.background.slice(0, 2000);
                            menuBarEl.style.background = header.background;
                            enableRobustBackdropFilter();
                            if(CSS.supports("color", header.background)) {
                              menuBarEl.style.color = colorIsDark(header.background) ? "#e3e3e3" : "#050505";
                            }
                          }
                        }
                        if(typeof e.data.header.mode === "string") {
                          header.mode = e.data.header.mode.slice(0, 100);
                        }
                      }
                      this.generatorMetaData = {title, image, description, dynamic, tags, header};
                    }

                    if(e.data.type === "codeWarningsUpdate") {

                      let validWarningsCount = 0;
                      this.refs.warningsModalOpenButton.style.display = "none";
                      this.refs.warningsWrapper.innerHTML = "";
                      let warningsHTML = "";
                      for(let warning of e.data.warnings) {
                        if(typeof warning.lineNumber !== "number" || typeof warning.warningId !== "string" || /[^a-z0-9\-]/.test(warning.generatorName)) return;
                        let warningTemplate = warnings[warning.warningId];
                        if(!warningTemplate) {
                          console.error("invalid warning id?");
                          continue;
                        }
                        warningTemplate = warningTemplate.replace(/###lineNumber###/g, warning.lineNumber);
                        let generatorNameText;
                        if(warning.generatorName === window.location.pathname.slice(1)) generatorNameText = "<b>this</b>";
                        else generatorNameText = "the <b>"+warning.generatorName+"</b>";
                        warningTemplate = warningTemplate.replace(/###generatorNameText###/g, generatorNameText);
                        warningTemplate = warningTemplate.replace(/ \(in <b>this<\/b> generator's code\)/g, ""); // hackily remove this, since it actually makes it more confusing for newbies I think.
                        warningsHTML += warningTemplate;
                        validWarningsCount++;
                        if(validWarningsCount > 10) break;
                      }
                      if(validWarningsCount > 0) {
                        this.refs.warningsModalOpenButton.style.display = "inline-block";
                        this.refs.warningsWrapper.innerHTML = warningsHTML;
                        this.refs.warningsModal.querySelector(".modal-body").scrollTop = 0;
                      }
                    }

                    // if(e.data.type === "requestFullscreen") {
                    //   if(this.outputIframe.requestFullscreen) this.outputIframe.requestFullscreen();
                    //   else if(this.outputIframe.webkitRequestFullscreen) this.outputIframe.webkitRequestFullscreen();
                    //   else if(this.outputIframe.mozRequestFullscreen) this.outputIframe.mozRequestFullscreen();
                    //   else if(this.outputIframe.msRequestFullscreen) this.outputIframe.msRequestFullscreen();
                    // }
                    //
                    // if(e.data.type === "exitFullscreen") {
                    //   if(this.outputIframe.exitFullscreen) this.outputIframe.exitFullscreen();
                    //   else if(this.outputIframe.webkitExitFullscreen) this.outputIframe.webkitExitFullscreen();
                    //   else if(this.outputIframe.mozCancelFullscreen) this.outputIframe.mozCancelFullscreen();
                    //   else if(this.outputIframe.msExitFullscreen) this.outputIframe.msExitFullscreen();
                    // }
                  });



                  // Initialise Split.js panels
                  let sizesStore = new Store('editor-split-sizes');

                  let sizes;
                  let defaultSizes = {
                    ab: [60,40],
                    cd: [90,10],
                    ef: [75,25],
                  };
                  if(sizesStore.data[app.data.generator.name]) {
                    sizes = sizesStore.data[app.data.generator.name];
                  } else {
                    // default sizes
                    sizes = JSON.parse(JSON.stringify(defaultSizes));
                    sizesStore.data[app.data.generator.name] = sizes;
                    sizesStore.save();
                  }
                  if(localStorage["editor-split-sizes-storage"] && localStorage["editor-split-sizes-storage"].length > 20000) {
                    localStorage["editor-split-sizes-storage"] = "{}";
                  }

                  function trimSplitSizes(arr) {
                    // for some reason split sizes sometimes add to over 100% and the editor breaks.
                    // this trims it to 100%
                    arr = arr.slice(0);
                    let sum = arr[0] + arr[1];
                    if(sum <= 100) return arr;
                    else {
                      arr[0] = Math.round(arr[0]);
                      arr[1] = Math.round(arr[1]);
                      while(arr[0] + arr[1] > 100) {
                        if(Math.random() < 0.5) {
                          arr[0]--;
                        } else {
                          arr[1]--;
                        }
                      }
                      return arr;
                    }
                  }
                  
                  let gutterSize = 8;

                  let split_ab = Split([this.root.querySelector('#a'), this.root.querySelector('#b')], {
                    gutterSize,
                    sizes: sizes.ab,
                    cursor: 'col-resize',
                    minSize: 30,
                    expandToMin: true,
                    onDragEnd: function() {
                      let data = sizesStore.data[app.data.generator.name];
                      if(!data) { data = JSON.parse(JSON.stringify(defaultSizes)); } // they could have changed generator's name
                      data.ab = split_ab.getSizes();
                      data.ab = trimSplitSizes(data.ab);
                      sizesStore.save();
                    },
                    elementStyle: (dimension, elementSize, gutterSize, index) => {
                      if(index === 0) return { "min-width": `calc(${elementSize}% - ${gutterSize}px)`, "max-width": `calc(${elementSize}% - ${gutterSize}px)` }
                      else return { "flex-grow":1 }; // let the right side fill in the rest of the space (parent has display:flex)
                    },
                  });
                  this.root.querySelector('#a').style.minWidth = `calc(${sizes.ab[0]}% - ${gutterSize}px)`;
                  this.root.querySelector('#a').style.maxWidth = `calc(${sizes.ab[0]}% - ${gutterSize}px)`;


                  let split_cd = Split([this.root.querySelector('#c'), this.root.querySelector('#perchanceConsoleEl')], {
                    direction: 'vertical',
                    sizes: sizes.cd,
                    gutterSize,
                    cursor: 'row-resize',
                    minSize: 30,
                    expandToMin: true,
                    onDragEnd: function() {
                      let data = sizesStore.data[app.data.generator.name];
                      if(!data) { data = JSON.parse(JSON.stringify(defaultSizes)); } // they could have changed generator's name
                      data.cd = split_cd.getSizes();
                      data.cd = trimSplitSizes(data.cd);
                      sizesStore.save();
                    },
                    elementStyle: (dimension, elementSize, gutterSize, index) => {
                      if(index === 0) return { "min-height": `calc(${elementSize}% - ${gutterSize}px)`, "max-height": `calc(${elementSize}% - ${gutterSize}px)` }
                      else return { "flex-grow":1 }; // let the bottom fill in the rest of the space (parent has display:flex)
                    },
                  });
                  this.root.querySelector('#c').style.minHeight = `calc(${sizes.cd[0]}% - ${gutterSize}px)`;
                  this.root.querySelector('#c').style.maxHeight = `calc(${sizes.cd[0]}% - ${gutterSize}px)`;

                  let split_ef = Split([this.root.querySelector('#e'), this.root.querySelector('#f')], {
                    direction: 'vertical',
                    sizes: sizes.ef,
                    gutterSize,
                    cursor: 'row-resize',
                    minSize: 30,
                    expandToMin: true,
                    onDragEnd: function() {
                      let data = sizesStore.data[app.data.generator.name];
                      if(!data) { data = JSON.parse(JSON.stringify(defaultSizes)); } // they could have changed generator's name
                      data.ef = split_ef.getSizes();
                      data.ef = trimSplitSizes(data.ef);
                      sizesStore.save();
                    },
                    elementStyle: (dimension, elementSize, gutterSize, index) => {
                      if(index === 0) return { "min-height": `calc(${elementSize}% - ${gutterSize}px)`, "max-height": `calc(${elementSize}% - ${gutterSize}px)` }
                      else return { "flex-grow":1 }; // let the bottom fill in the rest of the space (parent has display:flex)
                    },
                  });
                  this.root.querySelector('#e').style.minHeight = `calc(${sizes.ef[0]}% - ${gutterSize}px)`;
                  this.root.querySelector('#e').style.maxHeight = `calc(${sizes.ef[0]}% - ${gutterSize}px)`;

                  // need this because otherwise for some reason there's some weird `overscroll-behaviour` stuff near the edges of the screen (even with touch-action:none overlay workaround).
                  if(window.location.hash !== "#edit") this.root.querySelectorAll("#main .gutter").forEach(el => el.style.display="none");

                  if(window.TEST_NEW_EDITOR_1) {
                    if(startInEditMode) this.switchToEditMode();

                    this.root.querySelector("#input").style.display = "none";
                    this.root.querySelector("#template").style.display = "none";
                    let modelTextInitialContent = this.root.querySelector("#input").value;
                    let outputTemplateInitialContent = this.root.querySelector("#template").value;

                    this.root.querySelector("#input").outerHTML = `<div id="mainModelTextEditorCtn" style="height:100%;width:100%;"></div>`;
                    this.root.querySelector("#template").outerHTML = `<div id="mainOutputTemplateEditorCtn" style="height:100%;width:100%;"></div>`;

                    // Set these to upgrade/edit eslint version and config stuff:
                    // window.esLintImportUrl = "https://perchance.org/lib/eslint-linter-browserify-v9.14.0-bundle.mjs";
                    // window.htmlparser2ImportUrl = "https://perchance.org/lib/htmlparser2-v9.1.0-bundle.mjs";
                    // window.defaultEsLintConfig = {};

                    if(!window.editorBundleImportPromise) window.editorBundleImportPromise = import("/lib/editors.bundle.min.js");
                    editorLoadSpinnerEl.style.display = "flex";
                    let { init } = await window.editorBundleImportPromise;
                    editorLoadSpinnerEl.style.display = "none";
                    let {mainModelTextEditorView, mainOutputTemplateEditorView} = init({
                      modelTextInitialContent,
                      outputTemplateInitialContent,
                      mainModelTextEditorCtn,
                      mainOutputTemplateEditorCtn
                    });
                    this.modelTextEditor  = mainModelTextEditorView;
                    this.outputTemplateEditor  = mainOutputTemplateEditorView;

                    this.modelTextEditor._onChangeHandlers = [];
                    this.outputTemplateEditor._onChangeHandlers = [];
                    
                    // add back-compat methods:
                    for(let view of [this.modelTextEditor, this.outputTemplateEditor]) { 
                      view._onChange = (update) => {
                        for(let cb of view._onChangeHandlers) {
                          try { cb(update); } catch(e) { console.error(e); } 
                        }
                      };
                      view.on = (event, cb) => {
                        if(event === "change" || event === "changes") view._onChangeHandlers.push(cb);
                      };

                      view.getValue = () => view.state.doc.toString();
                      view.setValue = (newValue) => view.dispatch({changes:{ from:0, to:view.state.doc.length, insert:newValue }});
                      
                      // note: doesn't handle undo and stuff:
                      let clean = true;
                      view.markClean = () => clean=true;
                      view.isClean = () => clean;
                      view.on("change", function() {
                        clean = false;
                      });
                    }

                    if(localStorage[`codeEditorWrap_${window.generatorName}`] && !this.modelTextEditor._linesAreWrapped) {
                      this.modelTextEditor._toggleLineWrapping();
                    }
                    this.modelTextEditor._afterToggleLineWrapping = () => localStorage[`codeEditorWrap_${window.generatorName}`] = this.modelTextEditor._linesAreWrapped ? "1" : "";

                    if(localStorage[`outputEditorWrap_${window.generatorName}`] && !this.outputTemplateEditor._linesAreWrapped) {
                      this.outputTemplateEditor._toggleLineWrapping();
                    }
                    this.outputTemplateEditor._afterToggleLineWrapping = () => localStorage[`outputEditorWrap_${window.generatorName}`] = this.outputTemplateEditor._linesAreWrapped ? "1" : "";

                    // Add Alt+Z shortcut to toggle wrapping:
                    document.addEventListener('keydown', (event) => { 
                      if (event.altKey && event.key === 'z') {
                        event.preventDefault();
                        if(this.modelTextEditor.hasFocus) this.modelTextEditor._toggleLineWrapping();
                        if(this.outputTemplateEditor.hasFocus) this.outputTemplateEditor._toggleLineWrapping();
                      }
                    }); 

                    document.querySelector(".toggle-wrap-button-html").style.display = "none";
                    document.querySelector(".code-editor-buttons-ctn").style.display = "none";

                  } else {

                    // codemirror settings
                    CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
                    CodeMirror.keyMap.default["Tab"] = "indentMore";

                    // Add some VSCode shortcuts (using sublime.js functions, just different shortcuts):
                    CodeMirror.keyMap.default["Alt-Up"] = "swapLineUp";
                    CodeMirror.keyMap.default["Alt-Down"] = "swapLineDown";
                    CodeMirror.keyMap.default["Ctrl-Shift-Up"] = "addCursorToPrevLine";
                    CodeMirror.keyMap.default["Ctrl-Shift-Down"] = "addCursorToNextLine";
                    // TODO: make both alt+click and ctrl+click work for multi-cursor

                    this.root.querySelector("#input").value = this.root.querySelector("#input").value.replace(/\n[\t ]+/g, (match) => match.replace(/\\t/g, "  "));
                    // I'm reluctant to mess with tabs in the HTML editor because they are significant in e.g. <pre>, and I'm not sure if replacing with entity (&#9;) would actually work in all cases. Should be solved for all future generators anyway (via pasting intercept code below).

                    let isTouchDevice = window.matchMedia("(pointer: coarse)").matches;

                    let systemIsInDarkMode = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
                    this.modelTextEditor = CodeMirror.fromTextArea(this.root.querySelector("#input"), {
                      lineNumbers: true,
                      foldGutter: true,
                      extraKeys: {
                        //"Ctrl-Q": cm => cm.foldCode(cm.getCursor()),
                        //"Ctrl-Y": cm => CodeMirror.commands.foldAll(cm),
                        //"Ctrl-I": cm => CodeMirror.commands.unfoldAll(cm),
                      },
                      gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
                      tabSize: 2,
                      indentUnit: 2,
                      indentWithTabs: false,
                      matchBrackets: true,
                      mode: "perchancelists",
                      styleActiveLine: true,
                      lineWrapping:false,
                      theme: systemIsInDarkMode ? "one-dark" : "one-light",
                      keyMap: "sublime",
                      highlightSelectionMatches: isTouchDevice ? undefined : {showToken: /\w/, annotateScrollbar: true}, // this apparently messes up caret movement stuff on touch devices
                    });

                    // hacky fix for a bug where if you type two consecutive backticks, the `perchancelists` mode's JS state gets messed up for some reason.
                    // we just retokenize when backtick is typed.
                    let backtickHighlightRetokenizeTimeout = null;
                    this.modelTextEditor.on("beforeChange", function(cm, changeObj) {
                      if(changeObj.text.some(line => line.includes('`'))) {
                        clearTimeout(backtickHighlightRetokenizeTimeout);
                        backtickHighlightRetokenizeTimeout = setTimeout(() => cm.setOption("mode", "perchancelists"), 200);
                      }
                    }); 

                    this.outputTemplateEditor = CodeMirror.fromTextArea(this.root.querySelector("#template"), {
                      // lineNumbers: true,
                      // foldGutter: true,
                      // gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
                      mode: {name: "htmlmixed"},
                      selectionPointer: true,
                      tabSize: 2,
                      indentUnit: 2,
                      indentWithTabs: false,
                      lineWrapping:false,
                      styleActiveLine: true,
                      theme: systemIsInDarkMode ? "one-dark" : "one-light",
                      keyMap: "sublime",
                      highlightSelectionMatches: isTouchDevice ? undefined : {showToken: /\w/, annotateScrollbar: true}, // this apparently messes up caret movement stuff on touch devices
                    });  

                    if(localStorage[`codeEditorWrap_${window.generatorName}`]) {
                      this.refs.codeEditorWrapRefButton.innerHTML = "unwrap";
                      this.modelTextEditor.setOption('lineWrapping', true);
                    }
                    if(localStorage[`outputEditorWrap_${window.generatorName}`]) {
                      this.refs.outputEditorWrapRefButton.innerHTML = "unwrap";
                      this.outputTemplateEditor.setOption('lineWrapping', true);
                    }

                    // Add Alt+Z shortcut to toggle wrapping:
                    document.addEventListener('keydown', (event) => {
                      if (event.altKey && event.key === 'z') {
                        event.preventDefault();
                        if(this.modelTextEditor.hasFocus()) this.toggleCodeEditorWrap();
                        if(this.outputTemplateEditor.hasFocus()) this.toggleOutputEditorWrap();
                      }
                    });

                    window.editsHaveBeenMadeSincePageLoad = false;

                    // these are also called after the generator is saved, so long as window.lastEditorsChangeTime is the same as the instant that the save operation was initiated.
                    // codemirror will make editor.isClean() return true when it comes back to this state, **including via undo**
                    this.modelTextEditor.markClean();
                    this.outputTemplateEditor.markClean();

                    // hide wrap/fold buttons if cursor is near them, or on first line
                    async function updateToolbarVisibility(editor) {
                      await new Promise(r => setTimeout(r, 10));
                      let editorCtn = editor.getWrapperElement().parentElement;
                      const cursor = editorCtn.querySelector(".CodeMirror-cursor");
                      const hoverToolbar = editorCtn.querySelector('.code-editor-buttons-ctn') || editorCtn.querySelector('.toggle-wrap-button-html');
                      if(!cursor || !hoverToolbar) return;

                      const cursorRect = cursor.getBoundingClientRect();
                      const toolbarRect = hoverToolbar.getBoundingClientRect();
                      let isNear = cursorRect.top <= toolbarRect.bottom+20 && cursorRect.left >= toolbarRect.left-50 && cursorRect.left <= toolbarRect.right+50;

                      if(editor.getCursor().line === 0) isNear = true;
                      
                      hoverToolbar.style.pointerEvents = isNear ? 'none' : 'auto';
                      hoverToolbar.style.opacity = isNear ? '0' : '1';
                    }
                    this.modelTextEditor.on('keyHandled', updateToolbarVisibility);
                    this.outputTemplateEditor.on('keyHandled', updateToolbarVisibility);
                    this.modelTextEditor.getWrapperElement().addEventListener('mouseup', () => updateToolbarVisibility(this.modelTextEditor));
                    this.outputTemplateEditor.getWrapperElement().addEventListener('mouseup', () => updateToolbarVisibility(this.outputTemplateEditor));

                    // this is stupid but it's the only way I could get chrome to stop suggesting an email/password in codemirror's search dialogue
                    try {
                      function watchForChildWithClass(target, className, callback) {
                        new MutationObserver(mutations => {
                          mutations.forEach(mutation => {
                            Array.from(mutation.addedNodes).forEach(node => {
                              if(node.nodeType === 1 && node.classList.contains(className)) callback(node);
                            });
                          });
                        }).observe(target, { childList: true });
                      }
                      setTimeout(() => {
                        for(let container of Array.from(document.querySelectorAll(".CodeMirror"))) {
                          watchForChildWithClass(container, "CodeMirror-dialog", element => {
                            for(let inputEl of Array.from(element.querySelectorAll("input"))) {
                              let dummyEl = document.createElement("div");
                              dummyEl.innerHTML = `<input type="email"><input type="password">`;
                              dummyEl.style.cssText = "opacity:0; pointer-events:none; position:absolute;";
                              inputEl.parentElement.insertBefore(dummyEl, inputEl);
                            }
                          });
                        }
                      }, 400);
                    } catch(e) { console.error(e); }



                    // there was some funky business happening with tabs when people *pasted* them.
                    // This replaces all tabs with two spaces (users need to write \t if they want a tab in their text).
                    // EDIT: also just added non-breaking space replacement with normal space, since it was messing with indenting stuff.
                    this.modelTextEditor.on("beforeChange", (cm, change) => {
                      if(change.origin === "paste") {
                        change.update(null, null, change.text.map(line => line.replace(/\t/g, "  ").replaceAll(`\u00A0`, " ")));
                      }
                    });
                    // I took this out because in HTML, some text with to consecutive spaces is different to &nbsp;&nbsp;, and I think the same is true of tabs. So I think this would turn code indents into a bunch of visible whitespace.
                    // this.outputTemplateEditor.on("beforeChange", (cm, change) => {
                    //   if(change.origin === "paste") {
                    //     change.update(null, null, change.text.map(line => line.replace(/\t/g, "&#9;")));
                    //   }
                    // });

                    // This is hacky, but it seems to work. It's from here: https://codemirror.net/demo/indentwrap.html
                    // It makes it so wrapped text is indented at the same indent level as the line itself.
                    let basePadding = 4;
                    // Only do the indentwrap stuff if there are no tabs (literal `\t` is fine), because otherwise it (for some reason) doesn't work - it messes things up: jsbin.com/tukuximome
                    if(!this.root.querySelector("#template").value.includes("\t")) {
                      let charWidthOutputTemplate = this.outputTemplateEditor.defaultCharWidth();
                      this.outputTemplateEditor.on("renderLine", function(cm, line, elt) {
                        let off = CodeMirror.countColumn(line.text, null, cm.getOption("tabSize")) * charWidthOutputTemplate;
                        elt.style.textIndent = "-" + off + "px";
                        elt.style.paddingLeft = (basePadding + off) + "px";
                      });
                    }
                    if(!this.root.querySelector("#input").value.includes("\t")) {
                      let charWidthModelText = this.modelTextEditor.defaultCharWidth();
                      this.modelTextEditor.on("renderLine", function(cm, line, elt) {
                        let off = CodeMirror.countColumn(line.text, null, cm.getOption("tabSize")) * charWidthModelText;
                        elt.style.textIndent = "-" + off + "px";
                        elt.style.paddingLeft = (basePadding + off) + "px";
                      });
                    }

                    // disable overwrite insert mode:
                    this.outputTemplateEditor.on("keyup", () => { this.outputTemplateEditor.toggleOverwrite(false); });
                    this.modelTextEditor.on("keyup", () => { this.modelTextEditor.toggleOverwrite(false); });

                    // whenever the codemirror scrollbar appears or dissapears, update the buttons positioning so they sit beside the scrollbar:
                    const updateCodeEditorButtonsPos = () => {
                      document.querySelector(".code-editor-buttons-ctn").style.right = (document.querySelector(".CodeMirror-vscrollbar").offsetWidth+5)+"px";
                    };
                    new MutationObserver(updateCodeEditorButtonsPos).observe(document.querySelector(".CodeMirror-vscrollbar"), {attributes: true});
                    setTimeout(updateCodeEditorButtonsPos, 2000); // <-- call it once at the start for init

                    // same for html area:
                    const updateHtmlEditorButtonsPos = () => { 
                      document.querySelector(".toggle-wrap-button-html").style.right = (document.querySelectorAll(".CodeMirror-vscrollbar")[1].offsetWidth+5)+"px";
                    };
                    new MutationObserver(updateHtmlEditorButtonsPos).observe(document.querySelectorAll(".CodeMirror-vscrollbar")[1], {attributes: true});
                    setTimeout(updateHtmlEditorButtonsPos, 2000); // <-- call it once at the start for init

                    setTimeout(() => {
                      this.modelTextEditor.refresh();
                      this.outputTemplateEditor.refresh();
                    }, 10);
                  }

                  window.modelTextEditor = this.modelTextEditor;
                  window.outputTemplateEditor = this.outputTemplateEditor;

                  // this is also set in the save handler. they're used as an extra check in doLocalGeneratorBackupIfNeeded to prevent backing up text that is already saved.
                  window.lastModelTextSaved = this.modelTextEditor.getValue();
                  window.lastOutputTemplateSaved = this.outputTemplateEditor.getValue();


                  if(localStorage.editorFontSize && !isNaN(Number(localStorage.editorFontSize))) {
                    let size = Number(localStorage.editorFontSize);
                    [...document.querySelectorAll(".custom-codemirror-editor-font-size")].forEach(el => el.remove());
                    let style = document.createElement("style");
                    style.className = "custom-codemirror-editor-font-size";
                    style.innerHTML = `.CodeMirror, .cm-editor { font-size: ${size}px !important; line-height: ${size*1.4}px !important; }`;
                    document.head.appendChild(style); 
                  }



                  //////////////////////////////////////
                  //       LOCAL STORAGE BACKUPS      //
                  //////////////////////////////////////
                  const maxLocalBackupInterval = localStorage.__speedUpLocalBackupStuffForTesting ? 1000*5 : 1000*60*5; // CAUTION: if you change this, change `doLocalBackupDebounce6MinTimeout` to be larger than it
                  const oldLocalBackupCleaningInterval = localStorage.__speedUpLocalBackupStuffForTesting ? 1000*60*2 : 1000*60*20;
                  const maxLocalBackupAge = localStorage.__speedUpLocalBackupStuffForTesting ? 1000*60*10 : 1000*60*60*24*30;
                  const maxLocalBackupsPerGenerator = localStorage.__speedUpLocalBackupStuffForTesting ? 10 : 30;
                  if(localStorage.__speedUpLocalBackupStuffForTesting) {
                    console.warn(`WARNING: local backups sped up due to truthy localStorage.__speedUpLocalBackupStuffForTesting value\n`.repeat(20));
                  }
                  let lastLocalBackupTime = Date.now();
                  const doLocalGeneratorBackupIfNeeded = async (modelText, outputTemplate) => {
                    if(!app.userOwnsThisGenerator) return; // they don't own this gen (i.e. are just playing around in editor for now)
                    if(Date.now()-window.generatorLastSaveTime < maxLocalBackupInterval) return; // hasn't been a few mins since last save
                    if(Date.now()-lastLocalBackupTime < maxLocalBackupInterval) return; // at most once every few mins
                    if(window.lastModelTextSaved === modelText && window.lastOutputTemplateSaved === outputTemplate) return; // since they may have made an edit, but then undone it
                    
                    lastLocalBackupTime = Date.now();
                    if(!kv) await window.initKv();
                    let backupsArray = await kv.localBackups.get(app.data.generator.name) || [];
                    backupsArray.unshift({modelText, outputTemplate, time:Date.now()});
                    // if there are more than `maxLocalBackupsPerGenerator` backups, delete every second one in the second half of the array:
                    if(backupsArray.length > maxLocalBackupsPerGenerator) {
                      backupsArray = backupsArray.filter((backup, i) => i < maxLocalBackupsPerGenerator/2 ? true : i%2===0);
                    }
                    await kv.localBackups.set(app.data.generator.name, backupsArray);
                    console.debug("Saved local backup. NEW backupsArray:", backupsArray);
                  };
                  setTimeout(async () => {
                    if(app.userOwnsThisGenerator) {
                      let persistent = await navigator.storage.persist();
                      if(!persistent) console.warn("Browser denied persistent local storage.");
                    }
                  }, 1000*60*20);
                  setInterval(async () => {
                    if(!kv) return;
                    let entries = await kv.localBackups.entries();
                    // for *every* backed-up generator (not just the one they're currently viewing/editing) stored in this user's browser:
                    for(let [generatorName, backupsArray] of entries) {
                      let originalLength = backupsArray.length;
                      // delete the backup array entries older than several weeks:
                      backupsArray = backupsArray.filter(backup => Date.now()-backup.time < maxLocalBackupAge);
                      if(originalLength === backupsArray.length) continue;
                      // save changes:
                      if(backupsArray.length === 0) {
                        await kv.localBackups.delete(generatorName);
                        await kv.localBackupsLastWarnTimes.delete(generatorName);
                      } else {
                        console.debug(`Cleared ${originalLength-backupsArray.length} old backups. NEW backupsArray:`, backupsArray);
                        await kv.localBackups.set(generatorName, backupsArray);
                      }
                    }
                  }, oldLocalBackupCleaningInterval);
                  // if the page loads, and user owns this generator, and the last backup time is more than a few mins forward in time from last save, then warn them to click header 'backups' button
                  setTimeout(async () => {
                    let startTime = Date.now();
                    while(app.userOwnsThisGenerator === undefined) await new Promise(r => setTimeout(r, 1000*10));
                    if(Date.now()-startTime > 1000*60) {
                      console.warn(`Took a ${Date.now()-startTime}ms (i.e. much longer than expected) to determine if this user owns this generator?`);
                      return;
                    }
                    if(!app.userOwnsThisGenerator) return;
                    if(!kv) await window.initKv();
                    let localBackupsArr = await kv.localBackups.get(app.data.generator.name);
                    let lastWarnTimeForThisGen = await kv.localBackupsLastWarnTimes.get(app.data.generator.name) || 0;
                    if(localBackupsArr) {
                      for(let data of localBackupsArr) {
                        if(data.time-window.generatorLastSaveTime > 1000*60*3 && data.time > lastWarnTimeForThisGen) {
                          try {
                            await app.goToEditMode();
                            document.querySelector(`#menuBarEl [data-ref="revisionsButton"]`).style.backgroundColor = "#7d5100";
                          } catch(e) { console.error(e); }
                          await kv.localBackupsLastWarnTimes.set(app.data.generator.name, Date.now());
                          alert(`Warning: There's a backup of this generator stored in your browser memory which is newer than the version of this generator you're currently viewing. This could have been caused by a problem where the server didn't properly save your generator, or if your browser previously crashed while you were editing, or it could just be that you made a little edit but then decided not to save it. If you lost some work, click the 'backups' button in the header to download the code for a backed-up version.`);
                          return;
                        }
                      }
                    }
                  }, 1000*3);

                  let editorContentAlreadySavedDebounceTimeout;
                  function checkIfEditorContentAlreadySavedWithDebounce(modelText, outputTemplate) {
                    clearTimeout(editorContentAlreadySavedDebounceTimeout);
                    editorContentAlreadySavedDebounceTimeout = setTimeout(() => {
                      if(window.lastModelTextSaved === modelText && window.lastOutputTemplateSaved === outputTemplate) {
                        if(app.userOwnsThisGenerator) {
                          window.setSaveState("saved");
                        }
                      }
                    }, 300);
                  } 

                  let doLocalBackupDebounce6MinTimeout;
                  window.lastEditorsChangeTime = Date.now();
                  this.outputTemplateEditor.on("changes", () => {
                    window.lastEditorsChangeTime = Date.now();
                    window.editsHaveBeenMadeSincePageLoad = true;
                    let modelText = this.modelTextEditor.getValue();
                    let outputTemplate = this.outputTemplateEditor.getValue();
                    app.generatorEditedCallback({modelText, outputTemplate});
                    if(this.outputTemplateEditor.isClean() && this.modelTextEditor.isClean()) { // in case they undo and go back to a saved state
                      if(app.userOwnsThisGenerator) {
                        window.setSaveState("saved"); // must come after generatorEditedCallback, above, since that sets the save state to "unsaved"
                      }
                    } else {
                      checkIfEditorContentAlreadySavedWithDebounce(modelText, outputTemplate);
                    }
                    try {
                      doLocalGeneratorBackupIfNeeded(modelText, outputTemplate);
                      clearTimeout(doLocalBackupDebounce6MinTimeout);
                      doLocalBackupDebounce6MinTimeout = setTimeout(() => { // without this, we can still lose up to 5 minutes of work, which is annoying
                        doLocalGeneratorBackupIfNeeded(modelText, outputTemplate);
                      }, 1000*60*6);
                    } catch(e) { console.error(e); }
                  });
                  this.modelTextEditor.on("changes", () => {
                    window.lastEditorsChangeTime = Date.now();
                    window.editsHaveBeenMadeSincePageLoad = true;
                    let modelText = this.modelTextEditor.getValue();
                    let outputTemplate = this.outputTemplateEditor.getValue();
                    app.generatorEditedCallback({modelText, outputTemplate});
                    if(this.outputTemplateEditor.isClean() && this.modelTextEditor.isClean()) { // in case they undo and go back to a saved state
                      if(app.userOwnsThisGenerator) {
                        window.setSaveState("saved"); // must come after generatorEditedCallback, above, since that sets the save state to "unsaved"
                      }
                    } else {
                      checkIfEditorContentAlreadySavedWithDebounce(modelText, outputTemplate);
                    }
                    try {
                      doLocalGeneratorBackupIfNeeded(modelText, outputTemplate);
                      clearTimeout(doLocalBackupDebounce6MinTimeout);
                      doLocalBackupDebounce6MinTimeout = setTimeout(() => { // without this, we can still lose up to 5 minutes of work, which is annoying
                        doLocalGeneratorBackupIfNeeded(modelText, outputTemplate);
                      }, 1000*60*6);
                    } catch(e) { console.error(e); }
                  });

                  this.outputTemplateEditor.on("changes", () => {
                    clearTimeout(this.updateOutputDelayTimeout);
                    if(this.autoReload) {
                      this.updateOutputDelayTimeout = setTimeout(() => {
                        this.updateOutput({fullRefresh:false, removeUnfoundDeps:true});
                      }, 800);
                    }
                  });
                  this.modelTextEditor.on("changes", () => {
                    clearTimeout(this.updateOutputDelayTimeout);
                    if(this.autoReload) {
                      this.updateOutputDelayTimeout = setTimeout(() => {
                        this.updateOutput({fullRefresh:false, removeUnfoundDeps:true});

                        // EDIT: this is commented out because it doesn't make sense - if they haven't reloaded, then the computed meta data is obviously going to be using the old code.
                        // TODO: Make it so that when they send the save request, that's when we send updateMetadataIfNeeded, and we send the updated modelText which is executed with createPerchanceTree or whatever, but is then discarded, rather than replacing the "real" tree and updating everything.
                        // this.outputIframe.contentWindow.postMessage({command:"updateMetadataIfNeeded"}, '*'); // needed because they may not have 'auto' checked, and so they make some changes to their $meta props, then hit save, but the updated $meta stuff isn't sent along with the save request.
                      }, 800);
                    }
                  });

                  // if(window.DEBUG_FREEZE_MODE) {
                  //   this.refs.autoReloadCheckbox.checked = false;
                  //   //this.root.querySelector("#output iframe").src = "https://null.perchance.org/debug-freeze";
                  // } else {
                  //   // let url = "https://null.perchance.org/" + app.data.generator.name + "?v=1";
                  //   // let url = `https://${window.generatorPublicId}.perchance.org/` + app.data.generator.name + "?v=2";
                  //   // if(window.needToBustCacheOfIframeOnInitialLoad) url += `?__cacheBuster=${Math.random()}`;
                  //   let url = new URL(window.location.href);
                  //   url.hostname = `${window.generatorPublicId}.perchance.org`;
                  //   if(window.needToBustCacheOfIframeOnInitialLoad) {
                  //     url.searchParams.set("__cacheBust", Math.random().toString()+Math.random().toString());
                  //   }
                  //   // This is to ensure cache is busted even if they have URL params added to the URL.
                  //   // Cloudflare has limits to the number of cache clears, so this is a hacky but full-proof workaround.
                  //   // The top-level frame has the `window.thisIsNotAnOldCachedPagePromise` stuff to handle this, but we still
                  //   // need to make sure the iframe is also busted.
                  //   // We only need this during initial page load - not when reload button / save button is pressed, since in those
                  //   // cases the __initWithDataFromParentWindow query param is added to the URL, which means the iframe gets fresh
                  //   // data from the parent, regardless of the html that the server sends (i.e. the data that's embedded in the HTML
                  //   // is ignored)
                  //   url.searchParams.set("__generatorLastEditTime", window.generatorLastSaveTime);
                  //   this.root.querySelector("#output iframe").src = url;
                  // }

                  if(window.DEBUG_FREEZE_MODE) {
                    this.refs.autoReloadCheckbox.checked = false;
                    this.root.querySelector("#output iframe").src = "https://null.perchance.org/debug-freeze";
                  } else {
                    // Edit: not needed now that we load the iframe separately from loading the editor.
                    // if(window.needToBustCacheOfIframeOnInitialLoad) {
                    //   let url = new URL(window.location.href);
                    //   url.hostname = `${window.generatorPublicId}.perchance.org`;
                    //   url.searchParams.set("__cacheBust", Math.random().toString()+Math.random().toString());
                    //   this.root.querySelector("#output iframe").src = url;
                    // }
                  }


                  //////////////////////
                  //     CONSOLE      //
                  //////////////////////
                  function escapeHtml(html) {
                    return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
                  }

                  let consoleOutputStyle = "<style>html { color-scheme: light dark; } body { margin:0; padding:0.3em; color:#068e06; font-family:monospace; } @media (prefers-color-scheme: dark) { body { color-scheme: dark; background-color: #1f2024; } }</style>";

                  let consoleCommandStore = new Store("console-commands");
                  if(!consoleCommandStore.data.generators) { consoleCommandStore.data.generators = {}; }

                  let consoleOutputEl = document.querySelector("#console-output");
                  let consoleInputEl = document.querySelector("#console-input");
                  consoleOutputEl.addEventListener("click", function() {
                    consoleInputEl.focus();
                  });
                  consoleOutputEl.srcdoc = consoleOutputStyle + `<span style='font-family:monospace; color:#6e6d6d; position:absolute;top:8px;left:8px;'>e.g. try typing <b>I rolled a \{1-6\}!</b> or <b>[yourListName]</b> (including the brackets) above, and then press enter.</span>`;

                  let previousCommands = consoleCommandStore.data.generators[app.data.generator.name] || [""];
                  let currCommandIndex = 0; // NOT previousCommands array index!! 0 represents most recent element, 1 is second most recent, etc.
                  consoleInputEl.addEventListener("keydown", async (e) => {
                    // e.preventDefault();
                    let command = consoleInputEl.value;
                    if(e.which === 13) { // enter
                      let optEl = document.querySelector("#consoleInterpreterOption");
                      let interpreter = optEl.options[optEl.selectedIndex].value;

                      if(interpreter === "plaintext") { consoleOutputEl.srcdoc = consoleOutputStyle.replace("font-family:monospace;", "font-family:monospace; white-space:pre-wrap;")+(escapeHtml(await this.evaluateText(command))); }
                      else if(interpreter === "html") { consoleOutputEl.srcdoc = consoleOutputStyle+(await this.evaluateText(command)); }

                      // this.root.style.background = "#f1f1f1";
                      // setTimeout(() => { this.root.style.background = "white"; },100)

                      if(command !== previousCommands[previousCommands.length-1] && command !== previousCommands[previousCommands.length-2]) {
                        previousCommands.pop();
                        previousCommands.push(command);
                        previousCommands.push(""); // put the empty one back on the end
                      }
                      if(previousCommands.length > 300) {
                        previousCommands = [...new Set(previousCommands)];
                        previousCommands.shift();
                      }
                      currCommandIndex = 1; // <-- set index to that of the command that was just submitted
                      consoleCommandStore.data.generators[app.data.generator.name] = previousCommands; // (not necessary because it keeps reference??)
                      consoleCommandStore.save();
                      return;
                    }
                    if(e.which === 38) { // up arrow
                      currCommandIndex++; // move towards start of array (counter-intuitive)
                      currCommandIndex = Math.min(previousCommands.length-1, currCommandIndex); // must stay below or at length of command stack
                      consoleInputEl.value = previousCommands[previousCommands.length-1-currCommandIndex];
                      setTimeout(function() { consoleInputEl.selectionStart = consoleInputEl.selectionEnd = 100000; }, 1);
                      return;
                    }
                    if(e.which === 40) { // down arrow
                      currCommandIndex--; // move towards end off array (counter-intuitive)
                      currCommandIndex = Math.max(0, currCommandIndex); // must stay above or at zero
                      consoleInputEl.value = previousCommands[previousCommands.length-1-currCommandIndex];
                      setTimeout(function() { consoleInputEl.selectionStart = consoleInputEl.selectionEnd = 100000; }, 1);
                      return;
                    }
                  });
                },
              };
            </script>
          </div>

          <script>
            async function getCaptchaToken(widgetCtn) {

              let createdWidgetCtn;
              if(!widgetCtn) {
                // No widget container provided, so we create one.
                // Centered on screen with darkened background:
                createdWidgetCtn = document.createElement("div");
                createdWidgetCtn.className = "created-captcha-widget-ctn"; // <-- don't change this without changing references to it
                createdWidgetCtn.style.cssText = "text-align:center; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:1000; background-color:#111; padding:1em; border-radius:0.5em; box-shadow:0 0 10px rgba(0,0,0,0.5);";
                createdWidgetCtn.innerHTML = `<div style="margin-bottom:0.5rem;">⏳ Just a sec...</div>`;
                document.body.appendChild(createdWidgetCtn);
              }

              // load captcha lib if needed:
              let attempts = 0;
              while(!window.turnstile) {
                window.onloadTurnstilePromise = new Promise(r => window.onloadTurnstileCallback=r);
                let script = document.createElement("script");
                script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback";
                script.defer = true;
                script.onerror = (e) => {
                  console.error("Cloudflare Turnstile is being blocked?", e)
                };
                document.body.appendChild(script);
                await window.onloadTurnstilePromise;
                if(!window.turnstile) await new Promise(r => setTimeout(r, 10*1000));
                attempts++;
                if(attempts > 3) {
                  console.error("Failed to load Cloudflare Turnstile after 3 attempts.");
                  break;
                }
              }
              // render captcha and get token:
              let captchaWidgetId;
              let token = await new Promise((resolve, reject) => {
                captchaWidgetId = window.turnstile.render(widgetCtn || createdWidgetCtn, {
                  sitekey: '0x4AAAAAAAi3LdM-EVMMMFCv',
                  callback: function(token) {
                    console.debug("✅ Got turnstile token:", token);
                    resolve(token);
                  },
                  "error-callback": function(...args) {
                    console.error("❌ Turnstile error callback fired:", ...args);
                    reject(null);
                  },
                });
              });
              try { window.turnstile.remove(captchaWidgetId); } catch(e) { console.error("turnstile.remove() failed:", e); }
              if(createdWidgetCtn) createdWidgetCtn.remove();
              return token;
            }
          </script>
        
          <div id="loginModalEl" class="app-modal" style="display:none;">
            <div style="z-index:50;" class="background" onmousedown="loginModal.closeModal()"></div>
            <div style="z-index:51;" class="outer-wrapper" onmousedown="loginModal.handleOuterWrapperClick(event)">
              <div data-ref="contentWrapper" class="content-wrapper">
                <!-- LOGIN FORM -->
                <div class="view" data-ref="loginView" style="display: initial;">
                  <div class="modal-header">
                    <p>sign up or login to create your own generators ᕕ(ᐛ)ᕗ we <b>only</b> email you at your request (e.g. for <span class="link" onclick="loginModal.goto('passwordReset1View')">password reset</span>) 👍︎</p>
                    <p data-ref="loginError_request" style="display:none; color:red; margin-top:1em;">there was a problem connecting to the server ¯\_(⊙_ʖ⊙)_/¯ check your internet connection?</p>
                    <p data-ref="loginError_password" style="display:none; color:red; margin-top:1em;">that password is not correct (⊙.☉)7 <span class="link" onclick="loginModal.goto('passwordReset1View')">forgot it?</span></p>
                    <p data-ref="loginError_passwordLength" style="display:none; color:red; margin-top:1em;">that password is too short (⌐■_■) &gt;6 chars plz</p>
                    <p data-ref="loginError_emailInvalid" style="display:none; color:red; margin-top:1em;">something seems wrong about that email address (⊙︿⊙)</p>
                    <p data-ref="loginError_tooManyRequests" style="display:none; color:red; margin-top:1em;">too many requests (this can sometimes be caused by VPN browser extensions)</p>
                    <p data-ref="loginError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">plz post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input name="username" data-ref="email" placeholder="email" type="email">
                    <input name="password" data-ref="password" placeholder="password" type="password">
                  </div>
                  <div class="modal-footer">
                    <button onclick="loginModal.closeModal()">cancel</button><button onclick="loginModal.login()" class="main">signup / login</button>
                  </div>
                </div>
                <!-- LOADING -->
                <div class="view" data-ref="loadingView" style="display: none;">
                  <!-- <emoji-ajax-spinner style="display:block; margin:5em 0;" verb="loading"/> -->
                  <div style="margin:5em 0; text-align:center;">⏳ loading...</div>
                  <div data-ref="cfCaptchaOuterEl" style="display:none; text-align:center;">
                    <div data-ref="cfCaptchaCtn"></div>
                  </div>
                </div>
                <!-- VERIFICATION -->
                <div class="view" data-ref="verificationView" style="display: none;">
                  <div class="modal-header">
                    <p>we just sent a verification code to <span class="verificationEmailDisplay" style="font-style:italic;"></span> (check spam folder too)</p>
                    <p data-ref="extraNotice" style="margin-top: 0.25rem;" hidden=""></p>
                    <p data-ref="verifyError_request" style="display:none; color:red; margin-top:1em;">hmm. there was a problem connecting to the server. check your internet connection?</p>
                    <p data-ref="verifyError_code" style="display:none; color:red; margin-top:1em;">that code is not correct (⊙.☉)7 pls ensure you copied it exactly 👌︎</p>
                    <p data-ref="verifyError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">pls post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input data-ref="verificationCode" placeholder="verification code" type="text">
                  </div>
                  <div class="modal-footer">
                    <button onclick="loginModal.goto('loginView')">back</button><button id="verify-account-button" class="main" onclick="loginModal.verify()">verify</button>
                  </div>
                </div>
                <!-- SUCCESSFUL LOGIN -->
                <div class="view" data-ref="successView" style="display: none;">
                  <div class="modal-header">
                    <p>you're logged in! s(^‿^)-b</p>
                  </div>
                  <button onclick="loginModal.closeModal_success()" style="width:100%;">close</button>
                </div>
                <!-- PASSWORD RESET REQUEST -->
                <div class="view" data-ref="passwordReset1View" style="display: none;">
                  <div class="modal-header">
                    <p>forgot your password? o(╥﹏╥)o that's all right! just enter the email you used to sign up and you'll be sent a reset code</p>
                    <p data-ref="requestPasswordResetCodeError_request" style="display:none; color:red; margin-top:1em;">there was a problem connecting to the server ¯\_(⊙_ʖ⊙)_/¯ check your internet connection?</p>
                    <p data-ref="requestPasswordResetCodeError_account" style="display:none; color:red; margin-top:1em;">very spooky: that account was not found (⊙.☉)7 are you sure you put in the correct email? 👻︎</p>
                    <p data-ref="requestPasswordResetCodeError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">pls post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input data-ref="emailForPasswordReset" placeholder="email" type="text">
                  </div>
                  <div class="modal-footer">
                    <button onclick="loginModal.goto('loginView')">back</button><button class="main" onclick="loginModal.requestPasswordResetCode()">request reset code</button>
                  </div>
                </div>
                <!-- PASSWORD RESET -->
                <div class="view" data-ref="passwordReset2View" style="display: none;">
                  <div class="modal-header">
                    <p>we just sent a password reset code to <span style="font-style:italic;" class="emailForPasswordResetDisplay"></span> 💌 when you recieve it (check your spam folder too) enter it below and then enter a new password of your choosing</p>
                    <p data-ref="resetPasswordError_request" style="display:none; color:red; margin-top:1em;">there was a problem connecting to the server ¯\_(⊙_ʖ⊙)_/¯ check your internet connection?</p>
                    <p data-ref="resetPasswordError_code" style="display:none; color:red; margin-top:1em;">that code is not correct (⊙.☉)7 pls ensure you copied it exactly 👌︎</p>
                    <p data-ref="resetPasswordError_passwordLength" style="display:none; color:red; margin-top:1em;">that password is too short (⌐■_■) &gt;6 chars plz</p>
                    <p data-ref="resetPasswordError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">pls post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input data-ref="passwordResetCode" placeholder="reset code" type="text">
                    <input data-ref="newPassword" placeholder="new password" type="password">
                  </div>
                  <div class="modal-footer">
                    <button onclick="loginModal.goto('passwordReset1View')">back</button><button class="main" onclick="loginModal.resetPassword()">set password</button>
                  </div>
                </div>
              </div>
            </div>
            <script>
              window.loginModal = {
                root: document.querySelector("#loginModalEl"),
                refs: new Proxy({}, {
                  get(target, prop, receiver) {
                    return document.querySelector(`#loginModalEl [data-ref='${prop}']`);
                  },
                }),
                init: function() {
                  this.closeModal = function() {
                    this.root.style.display = "none";
                  };
                  this.closeModal_success = function() {
                    this.closeModal();
                    this.goto("loginView");
                  };

                  this.openModal = function() {
                    this.root.style.display = "block";
                  };
                  this.handleOuterWrapperClick = function(e) {
                    if(!this.refs.contentWrapper.contains(e.target)) {
                      this.closeModal();
                    }
                  };
                  this.goto = function(name) {
                    this.hideAllViews();
                    let el = this.refs[name];
                    el.style.display = "initial";
                    loginModalEl.querySelectorAll(".emailForPasswordResetDisplay").forEach(el => el.textContent=this.refs.emailForPasswordReset.value);
                    loginModalEl.querySelectorAll(".verificationEmailDisplay").forEach(el => el.textContent=this.refs.email.value);
                    if(el.querySelector("input")) {
                      // TODO: move caret to end of text if there is text in the input
                      setTimeout(() => { el.querySelector("input").focus(); },200);
                    }
                  };
                  this.hideAllViews = function() {
                    let views = this.root.querySelectorAll(".content-wrapper .view");
                    for(let el of Array.from(views)) {
                      el.style.display = "none";
                    }
                  };
                  this.getCurrentView = function() {
                    let views = this.root.querySelectorAll(".content-wrapper .view");
                    for(let el of Array.from(views)) {
                      if( el.style.display !== "none" ) return el.attributes.ref.value;
                    }
                  };

                  let extraNoticeDisplayTimeout = null;
                  this.login = async function() {

                    if(this.refs.password.value.length < 6) {
                      this.setLoginError("passwordLength");
                      return;
                    }
                    if(!/.+@.+/.test(this.refs.email.value)) {
                      this.setLoginError("emailInvalid");
                      return;
                    }

                    this.goto("loadingView");

                    try {

                      let bodyData = {email: this.refs.email.value, password: this.refs.password.value};

                      let data = await fetch('/api/login', {
                        method: 'POST',
                        body: JSON.stringify(bodyData),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "captcha-needed") {
                        console.debug("captcha-needed:", data);
                        // get captcha token:
                        this.refs.cfCaptchaOuterEl.style.display = "";
                        this.refs.cfCaptchaCtn.innerHTML = "";
                        let captchaToken = await getCaptchaToken(this.refs.cfCaptchaCtn);
                        this.refs.cfCaptchaOuterEl.style.display = "none";
                        // add the token to the request and try again:
                        bodyData.captchaToken = captchaToken;
                        data = await fetch('/api/login', {
                          method: 'POST',
                          body: JSON.stringify(bodyData),
                          signal: AbortSignal.timeout?.(20*1000),
                          headers: { 'Content-Type': 'application/json'},
                        }).then(r => r.json());
                      }

                      console.debug("login finished:", data);

                      if(data.status === "verification-needed") {
                        this.goto("verificationView");

                        if(bodyData.email.trim().endsWith("@gmail.com")) {
                          extraNoticeDisplayTimeout = setTimeout(() => {
                            this.refs.extraNotice.hidden = false;
                            let aaaaa = "@";
                            this.refs.extraNotice.innerHTML = `<b style="color:red;">note</b>: gmail addresses seem to be having signup issues recently. sometimes the verification email doesn't even make it to the spam folder. if you're not getting an email (even in your spam folder) after a couple of minutes, try <b>sending an email</b> to supp${""}ort${aaaaa}per${"chan"}ce.org (content doesn't matter), and then click 'back' and try again. if it's still not working, you can use something like temp-ma${""}il.org until the issue is resolved, then change your email in account settings.`;
                          }, 1000*40);
                        }

                      } else if(data.status === "success") {
                        app.loginSuccessCallback({sessionToken:data.sessionToken, email:this.refs.email.value});
                        localStorage.sessionTokenLastChangeTime = Date.now();
                        // TODO: make sure modal is visible (they could have (accidentally) closed it! (disable closing while loading?))
                        this.goto("successView");
                        this.refs.email.value = "";
                        this.refs.password.value = "";
                        this.setLoginError("none");
                      } else if(data.status === "incorrect-password") {
                        this.goto("loginView");
                        this.setLoginError("password");
                      } else if(data.status === "invalid-email") {
                        this.goto("loginView");
                        this.setLoginError("emailInvalid");
                      } else if(data.status === "too-many-requests") {
                        this.goto("loginView");
                        this.setLoginError("tooManyRequests");
                      } else if(data.status === "captcha-failed") {
                        this.goto("loginView");
                        this.refs.cfCaptchaCtn.innerHTML = `<b style="color:red;">Failed to solve captcha.</b>`;
                      } else {
                        this.goto("loginView");
                        this.setLoginError("server");
                      }

                    } catch(e) {
                      console.debug(e);
                      this.goto("loginView");
                      this.setLoginError("request");
                    }
                  }
                  this.setLoginError = (name) => {
                    this.refs.loginError_password.style.display = "none";
                    this.refs.loginError_passwordLength.style.display = "none";
                    this.refs.loginError_emailInvalid.style.display = "none";
                    this.refs.loginError_tooManyRequests.style.display = "none";
                    this.refs.loginError_request.style.display = "none";
                    this.refs.loginError_server.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["loginError_"+name].style.display = "block";
                    }
                  }

                  this.verify = async function() {
                    this.goto("loadingView");
                    try {
                      let data = await fetch('/api/verify', {
                        method: 'POST',
                        body: JSON.stringify({code: this.refs.verificationCode.value, email:this.refs.email.value}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      console.debug("verify finished:", data);

                      if(data.status === "success") {
                        clearTimeout(extraNoticeDisplayTimeout);
                        this.refs.extraNotice.hidden = true;
                        this.setVerifyError("none");
                        this.login();
                        this.refs.verificationCode.value = "";
                        //this.refs.email.value = ""; If we set it to an empty string we won't be able to read it after login!!
                      } else if(data.status === "incorrect-code") {
                        this.setVerifyError("code");
                        this.goto("verificationView");
                      } else {
                        this.setVerifyError("server");
                        this.goto("verificationView");
                      }
                    } catch(e) {
                      console.debug(e);
                      this.goto("verificationView");
                      this.setVerifyError("request");
                    }
                  }
                  this.setVerifyError = (name) => {
                    this.refs.verifyError_code.style.display = "none";
                    this.refs.verifyError_request.style.display = "none";
                    this.refs.verifyError_server.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["verifyError_"+name].style.display = "block";
                    }
                  }

                  this.requestPasswordResetCode = async function() {

                    this.goto("loadingView");
                    try {

                      let bodyData = {email:this.refs.emailForPasswordReset.value};

                      let data = await fetch('/api/requestPasswordResetCode', {
                        method: 'POST',
                        body: JSON.stringify(bodyData),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "captcha-needed") {
                        console.debug("captcha-needed:", data);
                        // get captcha token:
                        this.refs.cfCaptchaOuterEl.style.display = "";
                        this.refs.cfCaptchaCtn.innerHTML = "";
                        let captchaToken = await getCaptchaToken(this.refs.cfCaptchaCtn);
                        this.refs.cfCaptchaOuterEl.style.display = "none";
                        // add the token to the request and try again:
                        bodyData.captchaToken = captchaToken;
                        data = await fetch('/api/requestPasswordResetCode', {
                          method: 'POST',
                          body: JSON.stringify(bodyData),
                          signal: AbortSignal.timeout?.(20*1000),
                          headers: { 'Content-Type': 'application/json'},
                        }).then(r => r.json());
                      }

                      console.debug(data);

                      if(data.status === "success") {
                        this.setRequestPasswordResetCodeError("none");
                        this.goto("passwordReset2View");
                      } else if(data.status === "account-not-found") {
                        this.setRequestPasswordResetCodeError("account");
                        this.goto("passwordReset1View");
                      } else if(data.status === "captcha-failed") {
                        alert(`Failed to solve captcha. Please try again.`);
                        this.goto("passwordReset1View");
                      } else {
                        this.setRequestPasswordResetCodeError("server");
                        this.goto("passwordReset1View");
                      }

                    } catch(e) {
                      console.debug(e);
                      this.goto("passwordReset1View");
                      this.setRequestPasswordResetCodeError("request");
                    }
                  }
                  this.setRequestPasswordResetCodeError = function(name) {
                    this.refs.requestPasswordResetCodeError_account.style.display = "none";
                    this.refs.requestPasswordResetCodeError_request.style.display = "none";
                    this.refs.requestPasswordResetCodeError_server.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["requestPasswordResetCodeError_"+name].style.display = "block";
                    }
                  }

                  this.resetPassword = async function() {

                    if(this.refs.newPassword.length < 6) {
                      this.setResetPasswordError("passwordLength");
                      this.goto("passwordReset2View");
                      return;
                    }

                    this.goto("loadingView");
                    try {

                      let data = await fetch('/api/resetPassword', {
                        method: 'POST',
                        body: JSON.stringify({email:this.refs.emailForPasswordReset.value, code:this.refs.passwordResetCode.value, newPassword:this.refs.newPassword.value}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      console.debug(data);

                      if(data.status === "success") {
                        this.setResetPasswordError("none");
                        this.refs.email.value = this.refs.emailForPasswordReset.value;
                        this.refs.password.value = this.refs.newPassword.value;
                        this.login();
                        this.refs.emailForPasswordReset.value = "";
                        this.refs.passwordResetCode.value = "";
                        this.refs.newPassword.value = "";
                      } else if(data.status === "incorrect-code") {
                        this.setResetPasswordError("code");
                        this.goto("passwordReset2View");
                      } else {
                        this.setResetPasswordError("server");
                        this.goto("passwordReset2View");
                      }

                    } catch(e) {
                      console.debug(e);
                      this.goto("passwordReset2View");
                      this.setResetPasswordError("request");
                    }
                  }
                  this.setResetPasswordError = (name) => {
                    this.refs.resetPasswordError_passwordLength.style.display = "none";
                    this.refs.resetPasswordError_code.style.display = "none";
                    this.refs.resetPasswordError_request.style.display = "none";
                    this.refs.resetPasswordError_server.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["resetPasswordError_"+name].style.display = "block";
                    }
                  }

                  this.hideAllViews();
                  this.goto("loginView");
                  this.refs.email.addEventListener("keyup", (e) => { if(e.which === 13) { this.login(); } })
                  this.refs.password.addEventListener("keyup", (e) => { if(e.which === 13) { this.login(); } })
                },
              };
            </script>
          </div>
        
          <div id="accountModalEl" class="app-modal" style="display:none;">
            <style>
              #accountModalEl .add-to-folder-btn {
                opacity:0.5;
                cursor:pointer;
              }
              #accountModalEl .add-to-folder-btn:hover {
                opacity:1;
              }
              #accountModalEl .folder-header {
                cursor:pointer;
                padding-left: 0.5rem;
              }
              #accountModalEl .folder-header:hover {
                background: #eee;
              }
              @media (prefers-color-scheme: dark) {
                #accountModalEl .folder-header:hover {
                  background: #484848;
                }
              }
              
              #accountModalEl .folder-ctn[data-fold-state='closed'] .folder-emoji {
                filter: saturate(0);
              }
            </style>
            <div style="z-index:50;" class="background" onmousedown="accountModal.closeModal()"></div>
            <div style="z-index:51;" class="outer-wrapper" onmousedown="accountModal.handleOuterWrapperClick(event)">
              <div data-ref="contentWrapper" class="content-wrapper">
                <!-- ACCOUNT MENU -->
                <div class="view" data-ref="accountMenuView" style="display: initial;">
                  <div class="modal-header">
                    <p>you're logged in as <i class="currentEmailDisplay"></i> - you can:</p>
                    <ul>
                      <li><span class="link" onclick="accountModal.loadGeneratorList()">view your generators</span></li>
                      <li style="margin-top:0.5rem;"><span class="link" onclick="accountModal.goto('passwordChangeView')">change your password</span></li>
                      <li style="margin-top:0.5rem;"><span class="link" onclick="accountModal.goto('emailChangeView')">change your email</span></li>
                      <li style="margin-top:0.5rem;"><span class="link" onclick="app.logout()">logout</span></li>
                    </ul>
                  </div>
                  <div class="modal-body"></div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="accountModal.closeModal()">close</button>
                  </div>
                </div>
                <!-- PASSWORD CHANGE -->
                <div class="view" data-ref="passwordChangeView" style="display: none;">
                  <div class="modal-header">
                    <p>changing your password is easy, just enter your current password and your new password:</p>
                    <p data-ref="passwordChangeError_request" style="display:none; color:red; margin-top:1em;">there was a problem connecting to the server ¯\_(⊙_ʖ⊙)_/¯ check your internet connection?</p>
                    <p data-ref="passwordChangeError_password" style="display:none; color:red; margin-top:1em;">the current password is not correct (⊙.☉)7</p>
                    <p data-ref="passwordChangeError_passwordLength" style="display:none; color:red; margin-top:1em;">that password is too short (⌐■_■) &gt;7 chars pls</p>
                    <p data-ref="passwordChangeError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">pls post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input data-ref="passwordChange_currentPassword" placeholder="current password" type="password">
                    <input data-ref="passwordChange_newPassword" placeholder="new password" type="password">
                  </div>
                  <div class="modal-footer">
                    <button onclick="accountModal.goto('accountMenuView')">back</button><button class="main" onclick="accountModal.changePassword()">set new password</button>
                  </div>
                </div>
                <!-- PASSWORD CHANGE SUCCESS -->
                <div class="view" data-ref="passwordChangeSuccessView" style="display: none;">
                  <div class="modal-header">
                    <p>your password has been changed!</p>
                  </div>
                  <div class="modal-body">
                  </div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="accountModal.closeModal()">close</button>
                  </div>
                </div>
                <!-- EMAIL CHANGE -->
                <div class="view" data-ref="emailChangeView" style="display: none;">
                  <div class="modal-header">
                    <p>your current email is <i class="currentEmailDisplay"></i> to change your email, just enter your password and your new email below</p>
                    <p data-ref="emailChangeError_request" style="display:none; color:red; margin-top:1em;">there was a problem connecting to the server ¯\_(⊙_ʖ⊙)_/¯ check your internet connection?</p>
                    <p data-ref="emailChangeError_password" style="display:none; color:red; margin-top:1em;">that password is not correct (⊙.☉)7</p>
                    <p data-ref="emailChangeError_emailInvalid" style="display:none; color:red; margin-top:1em;">that new email address looks weird (⌐■_■)</p>
                    <p data-ref="emailChangeError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">plz post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input data-ref="emailChange_newEmail" placeholder="new email" type="email">
                    <input data-ref="emailChange_password" placeholder="your password" type="password">
                  </div>
                  <div class="modal-footer">
                    <button onclick="accountModal.goto('accountMenuView')">back</button><button class="main" onclick="accountModal.changeEmail()">set new email</button>
                  </div>
                </div> 
                <!-- EMAIL CHANGE SUCCESS -->
                <div class="view" data-ref="emailChangeSuccessView" style="display: none;">
                  <div class="modal-header">
                    <p>your email hand been changed!</p>
                  </div>
                  <div class="modal-body">
                  </div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="accountModal.closeModal()">close</button>
                  </div>
                </div>
                <!-- GENERATOR LIST -->
                <div class="view" data-ref="generatorListView" style="display: none;">
                  <div class="modal-header">
                    <input oninput="this.parentNode.parentNode.querySelectorAll('ul li a').forEach(el => el.parentNode.style.display=el.textContent.includes(this.value) ? '' : 'none')" placeholder="search..." style="height: 1rem;">
                    <span title="sort alphabetically" style="cursor:pointer;" onclick="window.accountModal.sortGeneratorListButtonClickHandler(this)">🔤</span>
                    <p data-ref="generatorListError" style="display:none; color:red; margin-top:1em;">there was a problem loading your generators ¯\_(⊙_ʖ⊙)_/¯ check your internet connection? if the problem persists, please <a href="https://lemmy.world/c/perchance">post to forum</a></p>
                  </div>
                  <div class="modal-body" style="max-height: 400px; overflow-y: auto;">
                    <!-- <generator-list style="display:block; margin-bottom:1.3em;"/> -->
                    <div data-ref="generatorFoldersCtn" style="display:block; margin-bottom:1.3em;"></div>
                  </div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="accountModal.goto('accountMenuView')">back</button>
                  </div>
                </div>
                <!-- LOADING -->
                <div class="view" data-ref="loadingView" style="display: none;">
                  <!-- <emoji-ajax-spinner style="display:block; margin:5em 0;" verb="loading"/> -->
                  <div style="margin:5em 0; text-align:center;">⏳ loading...</div>
                </div>
              </div>
            </div>
            <script>
              window.accountModal = {
                root: document.querySelector("#accountModalEl"),
                refs: new Proxy({}, {
                  get(target, prop, receiver) {
                    return document.querySelector(`#accountModalEl [data-ref='${prop}']`);
                  },
                }),
                init: function() {

                  this.sortGeneratorListButtonClickHandler = function(el) {
                    let lists = el.parentNode.parentNode.querySelectorAll('ul');
                    let t = Number(el.dataset.sortTypeIndex || 1);
                    for(let list of lists) {
                      if(t == 0) {
                        [...list.children].sort((a,b)=> Number(a.dataset.defaultSortValue)-Number(b.dataset.defaultSortValue)).forEach(n => list.appendChild(n));
                      } else if(t == 1 || t == 2) {
                        let m;
                        if(t == 1) m = 1;
                        if(t == 2) m = -1;
                        [...list.children].sort((a,b)=> a.textContent > b.textContent ? 1*m : -1*m).forEach(n => list.appendChild(n));
                      }
                    }
                    el.dataset.sortTypeIndex = t+1 === 3 ? 0 : t+1;
                  };

                  this.closeModal = function() {
                    this.root.style.display = "none";
                  }
                  this.openModal = function() {
                    this.goto("accountMenuView");
                    this.root.style.display = "block";
                  }
                  this.handleOuterWrapperClick = function(e) {
                    if(!this.refs.contentWrapper.contains(e.target)) {
                      this.closeModal();
                    }
                  }
                  this.goto = function(name) {
                    this.hideAllViews();
                    let el = this.refs[name];
                    el.style.display = "initial";
                    accountModalEl.querySelectorAll(".currentEmailDisplay").forEach(el => el.textContent=app.store.data.user.email);
                    if(el.querySelector("input")) {
                      // TODO: move caret to end of text if there is text in the input
                      setTimeout(() => { el.querySelector("input").focus(); },200);
                    }
                  }
                  this.hideAllViews = function() {
                    let views = this.root.querySelectorAll(".content-wrapper .view");
                    for(let el of Array.from(views)) {
                      el.style.display = "none";
                    }
                  }
                  this.getCurrentView = function() {
                    let views = this.root.querySelectorAll(".content-wrapper .view");
                    for(let el of Array.from(views)) {
                      if( el.style.display !== "none" ) return el.attributes.ref.value;
                    }
                  };

                  try {
                    window.__userGeneratorListFolderFoldStates = JSON.parse(localStorage.userGeneratorListFolderFoldStates || `{"uncategorized":1}`);
                    if(typeof window.__userGeneratorListFolderFoldStates !== "object") throw new Error("Should be a POJO.");
                  } catch(e) {
                    console.error(e);
                    window.__userGeneratorListFolderFoldStates = {uncategorized:1}; // <-- important - otherwise a bug with writing to localStorage.userGeneratorListFolderFoldStates could break the whole web app for the user
                  }

                  this.generatorFolderMap = null;
                  this.lastChosenFolderName = "";
                  this.handleGeneratorFolderMapButtonClick = async (btn) => {
                    let folderName = prompt('Enter a folder name:', this.lastChosenFolderName || undefined);
                    if(folderName !== null) {
                      this.lastChosenFolderName = folderName; // just for convenience if adding a bunch of generators to a new folder
                      if(folderName === "") {
                        folderName = "uncategorized";
                      }
                      let existingFolderName = this.generatorFolderMap[btn.dataset.generatorName];

                      // update local data and view:
                      this.generatorFolderMap[btn.dataset.generatorName] = folderName;
                      let folderEl = this.refs.generatorFoldersCtn.querySelector(`[data-folder-name='${folderName}']`);
                      if(!folderEl) { // create the folder if it doesn't yet exist
                        folderEl = this.createFolderHtml([], folderName, "open");
                        this.refs.generatorFoldersCtn.prepend(folderEl);
                      }
                      folderEl.querySelector("ul").prepend(btn.closest("li"));
                      
                      let itemCountEl = folderEl.querySelector(".folder-item-count");
                      itemCountEl.innerText = Number(itemCountEl.innerText) + 1;

                      // if the generator was previously in a folder, and that folder is now empty, remove that empty folder:
                      if(existingFolderName) {
                        let existingFolderEl = this.refs.generatorFoldersCtn.querySelector(`[data-folder-name='${existingFolderName}']`);
                        let itemCountEl = existingFolderEl.querySelector(".folder-item-count");
                        itemCountEl.innerText = Number(itemCountEl.innerText) - 1;
                        if(existingFolderEl.querySelectorAll("ul li").length === 0) {
                          existingFolderEl.remove();
                        }
                      }
                      
                      // update server data:
                      let data = await fetch('/api/saveUserGeneratorFolderMap', {
                        method: 'POST',
                        body: JSON.stringify({
                          email: app.store.data.user.email,
                          sessionToken: app.store.data.user.sessionToken,
                          generatorFolderMap: JSON.stringify(this.generatorFolderMap),
                        }),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status !== "success") {
                        alert("Encountered error while trying to save folder data. Please check your internet connection and perhaps try refreshing the page. If the problem persists, please submit a post on lemmy.world/c/perchance");
                      }
                    }
                  };

                  this.loadGeneratorList = async () => {

                    this.goto("loadingView");
                    this.refs.generatorListError.style.display = "none";
                    this.refs.generatorFoldersCtn.innerHTML = "";

                    try {

                      let data = await fetch('/api/getGeneratorsByUser', {
                        method: 'POST',
                        body: JSON.stringify({
                          email: app.store.data.user.email,
                          sessionToken: app.store.data.user.sessionToken,
                        }),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      this.goto("generatorListView");

                      if(data.status === "success") {
                        this.generatorFolderMap = data.generatorFolderMap;

                        // clean the generatorFolderMap in case they've deleted generators:
                        let generatorNameSet = new Set(data.generators.map(g => g.name));
                        for(let n of Object.keys(this.generatorFolderMap)) {
                          if(!generatorNameSet.has(n)) delete this.generatorFolderMap[n];
                        }

                        let folders = {}; // <-- maps folder name to generator array
                        for(let g of data.generators) {
                          if(!g.views) g.views = 0;
                          g.views = g.views > 999 ? (g.views/1000).toFixed(1) + 'k' : g.views;
                          let folderName = this.generatorFolderMap[g.name] || "uncategorized";
                          if(!folders[folderName]) folders[folderName] = [];
                          folders[folderName].push(g);
                        }
                        
                        let foldersSorted = Object.entries(folders).sort((a,b) => a[0].localeCompare(b[0]));
                        let uncategorizedFolderEntry = foldersSorted.find(e => e[0] === "uncategorized");
                        if(uncategorizedFolderEntry) {
                          foldersSorted = [...foldersSorted.filter(e => e[0] !== "uncategorized"), uncategorizedFolderEntry]; // move 'uncategorized' folder to the end
                        }
                        for(let [folderName, generators] of foldersSorted) {
                          let foldState = window.__userGeneratorListFolderFoldStates[folderName] ? "open" : "closed";
                          let folderEl = this.createFolderHtml(generators, folderName, foldState);
                          this.refs.generatorFoldersCtn.appendChild(folderEl);
                        }
                        // this.tags["generator-list"].generators = data.generators;
                        // this.tags["generator-list"].update();
                      } else {
                        this.refs.generatorListError.style.display = "block";
                      }

                    } catch(e) {
                      console.error("Problem loading generator list");
                      console.debug(e);
                      this.goto("generatorListView");
                      this.refs.generatorListError.style.display = "block";
                    }

                  };

                  this.createFolderHtml = (generators, folderName, foldState) => {
                    let div = document.createElement("div");
                    
                    let folderNameHtml = folderName.replace(/</g, "&lt;").replace(/>/g, "&gt;");
                    let folderNameAttr = folderName.replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/&/g, "&amp;");
                    let generatorListItemsHtml = generators.map((g, i) => `<li data-default-sort-value="${i}"><a href="/${g.name}#edit">${g.name}</a> (${g.views} views) <b style="color:#ff6800; ${g.isPrivate ? "" : "display:none;"}">(priv)</b> <span class="add-to-folder-btn" style="display:inline-block;" data-generator-name="${g.name}" onclick="accountModal.handleGeneratorFolderMapButtonClick(this);">📁</span></li>`).join("");
                    let folderEmoji = foldState === "open" ? "📂" : "📁";
                    
                    div.innerHTML = `<div class="folder-ctn" data-folder-name="${folderNameAttr}" data-fold-state="${foldState}">
                      <div class="folder-header" onclick="this.parentNode.dataset.foldState = (this.parentNode.dataset.foldState=='closed' ? 'open' : 'closed'); this.parentNode.querySelector('ul').style.height = (this.parentNode.dataset.foldState=='closed' ? '0px' : 'auto'); this.parentNode.querySelector('.folder-emoji').textContent = (this.parentNode.dataset.foldState=='open' ? '📂' : '📁'); window.__userGeneratorListFolderFoldStates[this.parentNode.dataset.folderName] = (this.parentNode.dataset.foldState=='open' ? 1 : 0); localStorage.userGeneratorListFolderFoldStates = JSON.stringify(window.__userGeneratorListFolderFoldStates);">
                        <span class="folder-emoji">${folderEmoji}</span>
                        <span style="font-weight:bold;">${folderNameHtml}</span>
                        (<span class="folder-item-count">${generators.length}</span>)
                      </div>
                      <ul style="margin:0; overflow:hidden; ${foldState === "open" ? "height:auto" : "height:0"}; padding-left:2rem;">
                        ${generatorListItemsHtml}
                      </ul>
                    </div>`;
                    return div.firstElementChild;
                  };


                  this.changePassword = async () => {

                    this.goto("loadingView");
                    this.setChangePasswordError("none");

                    if(this.refs.passwordChange_newPassword.value.length < 6) {
                      this.goto("passwordChangeView");
                      this.setChangePasswordError("passwordLength");
                      return;
                    }

                    try {

                      let data = await fetch('/api/changePassword', {
                        method: 'POST',
                        body: JSON.stringify({email:app.store.data.user.email, sessionToken:app.store.data.user.sessionToken, currentPassword:this.refs.passwordChange_currentPassword.value, newPassword:this.refs.passwordChange_newPassword.value}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "success") {
                        this.setChangePasswordError("none");
                        this.goto("passwordChangeSuccessView");
                        this.refs.passwordChange_currentPassword.value = "";
                        this.refs.passwordChange_newPassword.value = "";
                      } else if(data.status === "session-token-error") {
                        // TODO: test this
                        this.closeModal();
                        app.logout();
                        app.openLoginModal();
                      } else if(data.status === "incorrect-password") {
                        this.goto("passwordChangeView");
                        this.setChangePasswordError("password");
                      } else {
                        console.debug(data);
                        this.goto("passwordChangeView");
                        this.setChangePasswordError("server");
                      }

                    } catch(e) {
                      console.error("Problem loading generator list");
                      console.debug(e);
                      this.goto("passwordChangeView");
                      this.setChangePasswordError("request");
                    }

                  };
                  this.setChangePasswordError = (name) => {
                    this.refs.passwordChangeError_password.style.display = "none";
                    this.refs.passwordChangeError_passwordLength.style.display = "none";
                    this.refs.passwordChangeError_request.style.display = "none";
                    this.refs.passwordChangeError_server.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["passwordChangeError_"+name].style.display = "block";
                    }
                  }

                  this.changeEmail = async () => {
                    this.goto("loadingView");
                    this.setChangeEmailError("none");

                    if(!/.+@.+/.test(this.refs.emailChange_newEmail.value)) {
                      this.setChangeEmailError("emailInvalid");
                      return;
                    }
                    try {

                      let data = await fetch('/api/changeEmail', {
                        method: 'POST',
                        body: JSON.stringify({email:app.store.data.user.email, newEmail:this.refs.emailChange_newEmail.value, sessionToken:app.store.data.user.sessionToken, password:this.refs.emailChange_password.value}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "success") {
                        this.setChangeEmailError("none");
                        this.goto("emailChangeSuccessView");
                        app.emailChangeCallback(this.refs.emailChange_newEmail.value);
                        // this.update();
                        this.refs.emailChange_newEmail.value = "";
                        this.refs.emailChange_password.value = "";
                      } else if(data.status === "session-token-error") {
                        // TODO: test this
                        this.closeModal();
                        app.logout();
                        app.openLoginModal();
                      } else if(data.status === "incorrect-password") {
                        this.goto("emailChangeView");
                        this.setChangeEmailError("password");
                      } else {
                        console.debug(data);
                        this.goto("emailChangeView");
                        this.setChangeEmailError("server");
                      }

                    } catch(e) {
                      console.error("Problem loading generator list");
                      console.debug(e);
                      this.goto("emailChangeView");
                      this.setChangeEmailError("request");
                    }

                  };
                  this.setChangeEmailError = (name) => {
                    this.refs.emailChangeError_emailInvalid.style.display = "none";
                    this.refs.emailChangeError_password.style.display = "none";
                    this.refs.emailChangeError_request.style.display = "none";
                    this.refs.emailChangeError_server.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["emailChangeError_"+name].style.display = "block";
                    }
                  }

                  this.hideAllViews();
                  this.goto("accountMenuView");
                  this.refs.emailChange_password.addEventListener("keyup", (e) => { if(e.which === 13) { this.changeEmail(); } });
                  this.refs.passwordChange_newPassword.addEventListener("keyup", (e) => { if(e.which === 13) { this.changePassword(); } });
                },
              };
            </script>
          </div>
        
          <div id="settingsModalEl" class="app-modal" style="display:none;">
            <div style="z-index:50;" class="background" onmousedown="settingsModal.closeModal()"></div>
            <div style="z-index:51;" class="outer-wrapper" onmousedown="settingsModal.handleOuterWrapperClick(event)">
              <div data-ref="contentWrapper" class="content-wrapper" style="width:800px;">
                <!-- SETTINGS MENU -->
                <div class="view" data-ref="settingsMenuView" style="display: initial;">
                  <div class="modal-header">
                    <p>you're viewing your generator with the url <b class="currentGeneratorNameDisplay">zb67bgo77s</b> - you can:</p>
                    <ul>
                      <li><span class="link" onclick="settingsModal.goto('nameChangeView')">change its url</span></li>
                      <li style="margin-top:0.5rem;"><span class="link" onclick="settingsModal.duplicateGenerator()">duplicate it</span><span data-ref="duplicateGeneratorStatus"></span></li>
                      <li style="margin-top:0.5rem;"><span data-ref="changeGeneratorPrivacyButton" class="link" onclick="settingsModal.changeGeneratorPrivacy()">make public</span></li>
                      <li style="margin-top:0.5rem;"><span class="link" onclick="window.open(`/api/downloadGenerator?generatorName=${app.data.generator.name}`, 'Downloading generator...')">download it</span></li>
                      <li style="margin-top:1em;"><span class="link" onclick="settingsModal.deleteGenerator()" style="color:#e70000;">delete it</span></li>
                    </ul>
                    <div id="privateNotesCtn"></div>
                  </div>
                  <div class="modal-body">
                  </div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="settingsModal.closeModal()">close</button>
                  </div>
                </div>
                <!-- NAME CHANGE -->
                <div class="view" data-ref="nameChangeView" style="display: none;">
                  <div class="modal-header">
                    <p>this generator's current url is: <b class="currentGeneratorNameDisplay">zb67bgo77s</b></p>
                    <p style="margin-top:0.4em;">to change it, just enter a new one below. remember: you can only use lower-case letters, numbers and hyphens in your url</p>
                    <p style="margin-top:0.4em;"><b style="color:#f60000;">caution:</b> if you change it, the old url will no longer work! if your generator is popular, and others have imported it into their own, you will <b>break their generators!</b> (they will get import errors). because of this, if your generator is popular, it's better to make a copy of this generator rather than change this one's name</p>
                    <p data-ref="nameChangeError_length" style="display:none; color:red; margin-top:1em;">sorry, the new url must be at least 4 characters long</p>
                    <p data-ref="nameChangeError_request" style="display:none; color:red; margin-top:1em;">there was a problem connecting to the server ¯\_(⊙_ʖ⊙)_/¯ check your internet connection?</p>
                    <p data-ref="nameChangeError_alreadyExists" style="display:none; color:red; margin-top:1em;">sorry, a generator with that name already exists (⌐■_■)</p>
                    <p data-ref="nameChangeError_server" style="display:none; color:red; margin-top:1em;">something went wrong on the server (✖╭╮✖) <a href="https://lemmy.world/c/perchance" target="_blank">plz post to forum</a> if problem persists</p>
                  </div>
                  <div class="modal-body">
                    <input data-ref="newGeneratorName" oninput="settingsModal.handleNewGeneratorNameInput(event)" onpaste="settingsModal.handleNewGeneratorNamePaste(event)" placeholder="new url" type="text">
                  </div>
                  <div class="modal-footer">
                    <button onclick="settingsModal.goto('settingsMenuView')">back</button><button class="main" onclick="settingsModal.changeGeneratorName()">set new url</button>
                  </div>
                </div>
                <!-- NAME CHANGE SUCCESS -->
                <div class="view" data-ref="nameChangeSuccessView" style="display: none;">
                  <div class="modal-header">
                    <p>your generator's url has been changed ヾ(⌐■_■)ノ♪♬</p>
                  </div>
                  <div class="modal-body">
                  </div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="settingsModal.closeModal()">close</button>
                  </div>
                </div>
                <!-- LOADING -->
                <div class="view" data-ref="loadingView" style="display: none;">
                  <!-- <emoji-ajax-spinner style="display:block; margin:5em 0;" verb="loading"/> -->
                  <div style="margin:5em 0; text-align:center;">⏳ loading...</div>
                </div>
              </div>
            </div>
            <script>
              window.settingsModal = {
                root: document.querySelector("#settingsModalEl"),
                refs: new Proxy({}, {
                  get(target, prop, receiver) {
                    return document.querySelector(`#settingsModalEl [data-ref='${prop}']`);
                  },
                }),
                init: function() {
                  this.closeModal = function() {
                    // privateNotesCtn.innerHTML = ""; // commented out because it could still be saving when they close it.
                    this.root.style.display = "none";
                  }
                  this.openModal = function() {
                    privateNotesCtn.innerHTML = ""; // already done in loadPrivateNotes, but just for extra safety
                    this.loadPrivateNotes();
                    this.goto("settingsMenuView");
                    this.root.style.display = "block";
                  }
                  this.handleOuterWrapperClick = function(e) {
                    if(!this.refs.contentWrapper.contains(e.target)) {
                      this.closeModal();
                    }
                  }
                  this.goto = function(name) {
                    this.hideAllViews();
                    let el = this.refs[name];
                    el.style.display = "initial";
                    settingsModalEl.querySelectorAll(".currentGeneratorNameDisplay").forEach(el => el.textContent=app.data.generator.name);
                    if(el.querySelector("input")) {
                      // TODO: move caret to end of text if there is text in the input
                      setTimeout(() => { el.querySelector("input").focus(); },200);
                    }
                  }
                  this.hideAllViews = function() {
                    let views = this.root.querySelectorAll(".content-wrapper .view");
                    for(let el of Array.from(views)) {
                      el.style.display = "none";
                    }
                  }
                  this.getCurrentView = function() {
                    let views = this.root.querySelectorAll(".content-wrapper .view");
                    for(let el of Array.from(views)) {
                      if( el.style.display !== "none" ) return el.attributes.ref.value;
                    }
                  };
                  this.handleNewGeneratorNamePaste = (e) => {
                    // let original = e.target.value;
                    // setTimeout(() => { e.target.value = original; },100);
                  };
                  this.handleNewGeneratorNameInput = (e) => {
                    let caretPos = e.target.selectionStart;
                    let text = e.target.value;
                    if(text === "") { return; }
                    let output = "";
                    for(let c of text) {
                      if(/[A-Z]/.test(c)) {
                        output += c.toLowerCase();
                      } else if(/[ \-]/.test(c)) {
                        output += "-";
                      } else if(/[0-9a-z]/.test(c)) {
                        output += c;
                      } else {
                        output += "-";
                      }
                    }
                    e.target.value = output;
                    setCaretPosition(e.target, caretPos);
                  };
                  function setCaretPosition(elem, caretPos) {
                    let range;
                    if (elem.createTextRange) {
                      range = elem.createTextRange();
                      range.move('character', caretPos);
                      range.select();
                    } else {
                      elem.focus();
                      if (elem.selectionStart !== undefined) {
                        elem.setSelectionRange(caretPos, caretPos);
                      }
                    }
                  }

                  var allowedNamesWithLessThan4Chars = ["hub"];
                  this.changeGeneratorName = async () => {

                    this.goto("loadingView");
                    this.setNameChangeError("none");

                    if(this.refs.newGeneratorName.value.length < 4 && !allowedNamesWithLessThan4Chars.includes(this.refs.newGeneratorName.value)) {
                      this.setNameChangeError("length");
                      this.goto("nameChangeView");
                      return;
                    }

                    try {

                      let data = await fetch('/api/changeGeneratorName', {
                        method: 'POST',
                        body: JSON.stringify({email:app.store.data.user.email, sessionToken:app.store.data.user.sessionToken, currentName:app.data.generator.name, newName:this.refs.newGeneratorName.value}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "success") {
                        this.setNameChangeError("none");
                        this.goto("nameChangeSuccessView"); 
                        app.data.generator.name = this.refs.newGeneratorName.value;
                        window.generatorName = this.refs.newGeneratorName.value;
                        app.data.generator.publicId = data.publicId;
                        window.generatorPublicId = data.publicId;
                        window.history.replaceState(null, null, "/"+this.refs.newGeneratorName.value+window.location.hash);
                        // this.update();
                        this.refs.newGeneratorName.value = "";
                        window.hardReloadOutputIframe(); // needed to ensure e.g. comments-plugin, text-to-image-plugin gallery, etc. have correct URL
                      } else if(data.status === "session-token-error") {
                        // TODO: test this
                        this.closeModal();
                        app.logout();
                        app.openLoginModal();
                      } else if(data.status === "already-exists") {
                        this.goto("nameChangeView");
                        this.setNameChangeError("alreadyExists");
                      } else {
                        console.debug(data);
                        this.goto("nameChangeView");
                        this.setNameChangeError("server");
                      }

                    } catch(e) {
                      console.error("Problem while requesting generator name change");
                      console.debug(e);
                      this.goto("nameChangeView");
                      this.setNameChangeError("request");
                    }

                  };
                  this.setNameChangeError = (name) => {
                    this.refs.nameChangeError_alreadyExists.style.display = "none";
                    this.refs.nameChangeError_request.style.display = "none";
                    this.refs.nameChangeError_server.style.display = "none";
                    this.refs.nameChangeError_length.style.display = "none";
                    if(name === "none") {
                      return;
                    } else {
                      this.refs["nameChangeError_"+name].style.display = "block";
                    }
                  }


                  this.deleteGenerator = async () => {

                    let confirm = prompt("Are you sure you want to delete this generator? You cannot undo this action. Type \"yes\" to confirm that you want to delete this generator:");

                    if(confirm !== "yes") {
                      return;
                    }

                    this.goto("loadingView");

                    try {

                      let data = await fetch('/api/deleteGenerator', {
                        method: 'POST',
                        body: JSON.stringify({email:app.store.data.user.email, sessionToken:app.store.data.user.sessionToken, generatorName:app.data.generator.name}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "success") {
                        alert("This generator has been successfully deleted. You'll now be redirected to the homepage.");
                        window.userDeletedGenerator = true;
                        window.location.href = "https://perchance.org";
                      } else if(data.status === "session-token-error") {
                        this.closeModal();
                        app.logout();
                        app.openLoginModal();
                      } else {
                        alert("Something went wrong. If this error persists, please report it to lemmy.world/c/perchance - thanks!");
                        console.debug(data);
                        this.goto("settingsMenuView");
                      }

                    } catch(e) {
                      alert("Something went wrong. If this error persists, please report it to lemmy.world/c/perchance - thanks!");
                      console.error("Problem with request to delete generator");
                      console.debug(e);
                      this.goto("settingsMenuView");
                    }

                  };


                  this.changeGeneratorPrivacy = async () => {

                    if(!app.data.generator.isPrivate) {
                      let okay = window.confirm("Note that this action will de-list your generator from all publicly accessible Perchance generator lists. Anyone who has your generator's link will still be able to access it. You can easily undo this action.");
                      if(!okay) {
                        return;
                      }
                    }

                    this.goto("loadingView");

                    try {

                      let data = await fetch('/api/changeGeneratorPrivacy', {
                        method: 'POST',
                        body: JSON.stringify({email:app.store.data.user.email, sessionToken:app.store.data.user.sessionToken, generatorName:app.data.generator.name, isPrivate:app.data.generator.isPrivate ? false : true}),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "success") {
                        app.data.generator.isPrivate = !app.data.generator.isPrivate;
                        this.refs.changeGeneratorPrivacyButton.innerHTML = `make ${app.data.generator.isPrivate ? "public" : "private"}`;
                        this.goto("settingsMenuView");
                      } else if(data.status === "session-token-error") {
                        this.closeModal();
                        app.logout();
                        app.openLoginModal();
                      } else {
                        alert("Something went wrong. If this error persists, please report it to lemmy.world/c/perchance - thanks!");
                        console.debug(data);
                        this.goto("settingsMenuView");
                      }

                    } catch(e) {
                      alert("Something went wrong. If this error persists, please report it to lemmy.world/c/perchance - thanks!");
                      console.error("Problem with request to delete generator");
                      console.debug(e);
                      this.goto("settingsMenuView");
                    }

                  };


                  this.duplicateGenerator = async () => {

                    this.goto("loadingView");

                    try {

                      let data = await fetch('/api/duplicateGenerator', {
                        method: 'POST',
                        body: JSON.stringify({
                          email: app.store.data.user.email,
                          sessionToken: app.store.data.user.sessionToken,
                          generatorName: app.data.generator.name,
                          // overrides are only needed if the user owns this gen, since otherwise they'd just use the save button:
                          outputTemplateOverride: app.userOwnsThisGenerator ? window.outputTemplateEditor?.getValue() : null,
                          modelTextOverride: app.userOwnsThisGenerator ? window.modelTextEditor?.getValue() : null,
                        }),
                        signal: AbortSignal.timeout?.(20*1000),
                        headers: { 'Content-Type': 'application/json'},
                      }).then(r => r.json());

                      if(data.status === "success") {
                        this.refs.duplicateGeneratorStatus.innerHTML = `<span style="color:green;"> Success!</span> → <a target="_blank" href="/${data.newGeneratorName}#edit">${data.newGeneratorName}</a>`;
                        this.goto("settingsMenuView");
                      } else if(data.status === "session-token-error") {
                        this.closeModal();
                        app.logout();
                        app.openLoginModal();
                      } else {
                        alert("Something went wrong. If this error persists, please report it to lemmy.world/c/perchance - thanks!");
                        console.debug(data);
                        this.goto("settingsMenuView");
                      }

                    } catch(e) { 
                      alert("Something went wrong. If this error persists, please report it to lemmy.world/c/perchance - thanks!");
                      console.error("Problem with request to duplicate generator");
                      console.debug(e);
                      this.goto("settingsMenuView");
                    }

                  };

                  function indentTextareaModule() {
                    // https://esm.sh/[email protected]?bundle
                    function a(t,e){let n=t.ownerDocument,o=n.activeElement;o!==t&&t.focus(),e===""?n.execCommand("delete"):n.execCommand("insertText",!1,e),o===n.body?t.blur():o instanceof HTMLElement&&o!==t&&o.focus()}function p(t){let{selectionStart:e,selectionEnd:n,value:o}=t,c=o.slice(e,n);if(/\n/g.exec(c)?.length>0){let i=o.lastIndexOf(`\n`,e-1)+1,s=t.value.slice(i,n-1),r=s.replaceAll(/^|\n/g,"$&	"),l=r.length-s.length;t.setSelectionRange(i,n-1),a(t,r),t.setSelectionRange(e+1,n+l)}else a(t,"	")}function g(t,e){let n=t.lastIndexOf(`\n`,e-1)+1;return t.charAt(n)!=="	"?e:n+1}function f(t){let{selectionStart:e,selectionEnd:n,value:o}=t,c=o.lastIndexOf(`\n`,e-1)+1,u=g(o,n),i=t.value.slice(c,u),s=i.replaceAll(/(^|\n)(\t| {1,2})/g,"$1"),r=i.length-s.length;t.setSelectionRange(c,u),a(t,s);let l=/\t| {1,2}/.exec(o.slice(c,e)),x=l?l[0].length:0,S=e-x;t.setSelectionRange(e-x,Math.max(S,n-r))}function d(t){if(t.defaultPrevented||t.metaKey||t.altKey||t.ctrlKey)return;let e=t.target;t.key==="Tab"?(t.shiftKey?f(e):p(e),t.preventDefault(),t.stopImmediatePropagation()):t.key==="Escape"&&!t.shiftKey&&(e.blur(),t.preventDefault(),t.stopImmediatePropagation())}function h(t,e){typeof t=="string"?t=document.querySelectorAll(t):t instanceof HTMLTextAreaElement&&(t=[t]);for(let n of t)n.addEventListener("keydown",d,{signal:e})}var m=p,y=f,I=d,L=h;
                    return {enableTabToIndent:h,eventHandler:I,indent:m,indentSelection:p,tabToIndentListener:d,unindent:y,unindentSelection:f,watch:L};
                  }

                  this.loadPrivateNotes = async () => {
                    privateNotesCtn.innerHTML = "";
                    privateNotesCtn.innerHTML = `<div style="position:relative; margin-top:1.1rem;">
                      <div>Private Notes:</div>
                      <textarea id="privateNotesEl" disabled style="padding:0.1rem 0.35rem; width:100%; height:260px; resize:vertical; min-height:50px; display:block; box-sizing:border-box; white-space:pre; tab-size:2;" placeholder="⏳ Loading..."></textarea>
                      <div id="privateNotesSaveIndicatorEl" style="display:none; position:absolute; bottom:0.5rem; right:0.5rem; pointer-events:none; border:1px solid gray; border-radius:3px; padding:0.08rem 0.2rem; font-family:sans-serif; box-sizing:border-box; background:light-dark(white, #343434);">saving...</div>
                    </div>`;

                    indentTextareaModule().enableTabToIndent(privateNotesEl);

                    let data = await fetch('/api/getPrivateNotes', {
                      method: 'POST',
                      body: JSON.stringify({email:app.store.data.user.email, sessionToken:app.store.data.user.sessionToken, generatorName:app.data.generator.name}),
                      signal: AbortSignal.timeout?.(20*1000),
                      headers: { 'Content-Type': 'application/json'},
                    }).then(r => r.json());

                    if(data.status !== "success") {
                      privateNotesEl.placeholder = `Error loading private notes (error: ${data.status}). Trying again in a few seconds...`;
                      await new Promise(r => setTimeout(r, 2000));
                      return this.loadPrivateNotes();
                    }

                    privateNotesEl.value = data.privateNotes;
                    privateNotesEl.placeholder = "Use this box for notes about this generator that you don't want to be publicly viewable.";
                    privateNotesEl.disabled = false;
                    privateNotesSaveIndicatorEl.textContent = "✅ saved";
                    
                    let currentSaveIndex = -1;
                    let saveTimeout;
                    privateNotesEl.addEventListener("input", () => {
                      currentSaveIndex++;
                      let thisSaveIndex = currentSaveIndex;
                      privateNotesSaveIndicatorEl.style.display = "block";
                      privateNotesSaveIndicatorEl.textContent = "unsaved";
                      clearTimeout(saveTimeout);
                      saveTimeout = setTimeout(async () => {
                        if(thisSaveIndex !== currentSaveIndex || !document.querySelector("#privateNotesEl")) return;
                        privateNotesSaveIndicatorEl.textContent = "⏳ saving...";
                        try {
                          await this.savePrivateNotes();
                          if(thisSaveIndex === currentSaveIndex && document.querySelector("#privateNotesEl")) privateNotesSaveIndicatorEl.textContent = "✅ saved";
                          setTimeout(() => {
                            if(thisSaveIndex === currentSaveIndex && document.querySelector("#privateNotesEl")) privateNotesSaveIndicatorEl.style.display = "none";
                          }, 2000);
                        } catch(e) {
                          console.error("Problem saving private notes", e);
                          if(thisSaveIndex === currentSaveIndex && document.querySelector("#privateNotesEl")) privateNotesSaveIndicatorEl.textContent = "⚠️ error";
                        }
                      }, 1000);
                    });
                  };

                  this.savePrivateNotes = async () => {
                    let data = await fetch('/api/setPrivateNotes', {
                      method: 'POST',
                      body: JSON.stringify({email:app.store.data.user.email, sessionToken:app.store.data.user.sessionToken, generatorName:app.data.generator.name, privateNotes:privateNotesEl.value}),
                      signal: AbortSignal.timeout?.(20*1000),
                      headers: { 'Content-Type': 'application/json'},
                    }).then(r => r.json());
                    if(data.status !== "success") {
                      throw new Error("Server error");
                    }
                  };

                  this.hideAllViews();
                  this.goto("settingsMenuView");
                  this.refs.newGeneratorName.addEventListener("keyup", (e) => { if(e.which === 13) { this.changeGeneratorName(); } });
                  this.refs.changeGeneratorPrivacyButton.innerHTML = `make ${app.data.generator.isPrivate ? "public" : "private"}`;
                },
              };
            </script>
          </div>
        
          <div id="revisionsModalEl" class="app-modal" style="display:none;">
            <div style="z-index:50;" class="background" onclick="revisionsModal.closeModal()"></div>
            <div style="z-index:51;" class="outer-wrapper" onclick="revisionsModal.handleOuterWrapperClick(event)">
              <div data-ref="contentWrapper" class="content-wrapper">
                <div class="view" data-ref="revisionsView">
                  <div class="modal-header">
                    <p>if you click the button below, it will load a list of older versions of your generator so you can download them in case you accidentally deleted your code, or there was a system error. copies of your generator code are also backed-up to your local browser storage, so if your computer ever crashes and you hadn't saved in a while, you'll be able to come here to recover your data.</p>
                    <p style="text-align:center;"><button style="margin-top:1em;" onclick="revisionsModal.loadRevisionsList()" data-ref="revisionsButton">load backup/revision history</button></p>
                    <div data-ref="revisionsList" style="display:none; max-height:400px; overflow-y:auto; margin-top:1em;">
                      <ul style="margin:0;"></ul>
                    </div>
                    <div data-ref="loadingSpinner" style="display:none">
                      <!-- <emoji-ajax-spinner style="display:none; margin:5em 0;" verb="loading"/> -->
                      <div style="margin:5em 0; text-align:center;">⏳ loading...</div>
                    </div>
                    <p data-ref="revisionsError" style="color:red; display:none;">hmm (⊙_☉) there was some sort of server error while trying to get your revision history. sorry! this doesn't happen very often. if it keeps happening (and you've checked your internet connection), could you please make a post on the <a href="https://lemmy.world/c/perchance" target="_blank">forum</a>?</p>
                  </div>
                  <div class="modal-body"></div>
                  <div class="modal-footer">
                    <button style="width:100%;" onclick="revisionsModal.closeModal()">close</button>
                  </div>
                </div>
              </div>
            </div>
            <script>
              window.revisionsModal = {
                root: document.querySelector("#revisionsModalEl"),
                refs: new Proxy({}, {
                  get(target, prop, receiver) {
                    return document.querySelector(`#revisionsModalEl [data-ref='${prop}']`);
                  },
                }),
                init: function() {
                  this.closeModal = function() {
                    this.root.style.display = "none";
                  }
                  this.openModal = function() {
                    this.root.style.display = "block";
                    this.refs.revisionsError.style.display = "none";
                    this.refs.revisionsList.style.display = "none";
                    this.refs.revisionsButton.style.display = "";
                  }
                  this.handleOuterWrapperClick = function(e) {
                    if(!this.refs.contentWrapper.contains(e.target)) {
                      this.closeModal();
                    }
                  }

                  this.loadRevisionsList = async () => {

                    this.refs.loadingSpinner.style.display = "";
                    this.refs.revisionsError.style.display = "none";
                    this.refs.revisionsButton.style.display = "none";
                    this.refs.revisionsList.style.display = "none";

                    try {

                      let userData = JSON.parse(localStorage["app-storage"]).user;
                      
                      window.diffStuff.patches = await fetch("https://perchance.org/api/getGeneratorDiffPatches", {
                        method:"POST",
                        headers: {"Content-Type": "application/json; charset=utf-8"},
                        body:JSON.stringify({
                          generatorName: app.data.generator.name,
                          email: userData.email,
                          sessionToken: userData.sessionToken,
                        }),
                      }).then(r => r.json());

                      window.diffStuff.patches.sort((a, b) => a.creationTime-b.creationTime);
                      window.diffStuff.modelTextPatches = window.diffStuff.patches.map(o => o.modelTextPatch);
                      window.diffStuff.outputTemplatePatches = window.diffStuff.patches.map(o => o.outputTemplatePatch);

                      window.diffStuff.patches.sort((a, b) => b.creationTime-a.creationTime);
                      listHTML = window.diffStuff.patches.map((p, i, arr) => `<li style="margin-top:0.25rem;" onclick="window.diffStuff.openNewTabWithRevision(${arr.length-1-i}, '${app.data.generator.name}')"><span class="clickable">${new Date(p.creationTime).toString()}</span></li>`).join("");

                      if(!kv) await window.initKv();
                      let localBackupsArray = await kv.localBackups.get(app.data.generator.name) || [];
                      window.downloadLocalBackup = async (i) => {
                        let backup = localBackupsArray[i];
                        let intro = "<<<<< this file contains your perchance lists first, and your HTML code underneath it >>>>>\n\n\n\n";
                        window.downloadTextFile(intro+backup.modelText+("\n".repeat(20))+backup.outputTemplate+("\n".repeat(20)), `${app.data.generator.name}-revision-${new Date(backup.time).toString().toLowerCase().split(" ").slice(0, 5).join("-").replace(/:/g, "-")}.txt`);
                      };
                      let localBackupsHTML = "";
                      if(localBackupsArray.length > 0) {
                        localBackupsHTML = localBackupsArray.map((d, i) => `<li style="margin-top:0.25rem;" onclick="window.downloadLocalBackup(${i})"><span class="clickable" style="color:#e8690b;">(<b>browser storage</b>) ${new Date(d.time).toString()}</span></li>`).join("");
                        localBackupsHTML += "<hr>";
                      }
                      
                      listHTML = localBackupsHTML + listHTML;

                      this.refs.revisionsList.querySelector("ul").innerHTML = listHTML.trim() === "" ? "<li style='color:black; text-decoration:none;'>no revisions/backups yet! try making an edit to your generator and then save</li>" : listHTML;

                      this.refs.revisionsList.style.display = "";
                      this.refs.revisionsError.style.display = "none";
                      this.refs.loadingSpinner.style.display = "none";

                    } catch(e) {
                      console.error("Problem loading revision list");
                      console.debug(e);
                      this.refs.revisionsError.style.display = "";
                      this.refs.revisionsButton.style.display = "";
                      this.refs.revisionsList.style.display = "none";
                      this.refs.loadingSpinner.style.display = "none";
                    }
                  };
                },
              };
            </script>
          </div>
        <div id="adCtn" style="padding: 4px 0px; text-align: center; display: flex; align-items: center; justify-content: center; position: relative; min-height: 90px !important; max-height: 90px !important; height: 90px !important; overflow: hidden !important;"></div></div>

        <script>
          window.app = {
            root: document.querySelector("#appEl"),
            refs: new Proxy({}, {
              get(target, prop, receiver) {
                return document.querySelector(`#appEl [data-ref='${prop}']`);
              },
            }),
            data: {},
            exitWarningAttached: false,
            init: async function({generator, dependencies}) {
              
              this.initializeEditorPromise = null;
              
              this.goToEditMode = async () => {
                
                // To prevent accidental second click in the position of the edit button, resulting in a save, since the save button appears in its place.
                // We switch back to normal values after switchToEditMode() has executed.
                let saveBtn = document.querySelector(`#menuBarEl [data-ref='saveButton']`);
                saveBtn.style.pointerEvents = 'none';

                if(!this.initializeEditorPromise) {
                  this.initializeEditorPromise = window.editor.init({startInEditMode:true});
                }
                await this.initializeEditorPromise;
                this.appInteractionState = "edit";
                this.trigger("AppInteractionStateChange");
                editor.switchToEditMode();

                setTimeout(() => {
                  saveBtn.style.pointerEvents = '';
                }, 700);
                
                if(location.hash === "") { // if there's already a hash, we don't edit it, since we now transfer the hash to the iframe so people can use it for stuff in generators, and the #edit part of the URL isn't "ground truth" - it's just a handy way of sharing a gen that goes straight to edit mode
                  let url = new URL(location.href);
                  url.hash = "#edit"; 
                  history.replaceState({}, "", url.href); // we do this rather than setting the hash with location.hash because otherwise it essentially does a pushState behind the scenes
                }
                
                // initialPageLoadSpinner.style.display = "none"; // otherwise when the generator is frozen and they click edit, the loading spinner doesn't go away
            
                // this.update();
              };
              
              this.goToViewMode = () => {

                this.appInteractionState = "view";
                this.trigger("AppInteractionStateChange");
                
                if(this.initializeEditorPromise) editor.switchToViewMode(); // page load in 'view mode' by default, so only needed if we've inited editor

                if(window.location.hash === "#edit") {
                  this.removeURLHash();
                  let metaData = editor.generatorMetaData;
                  if(!metaData) metaData = window.generatorStaticMetaData;
                  if(metaData && metaData.header?.mode === "minimal") { 
                    menuBarEl.style.display = "none";
                    minimalModeMenuBtn.style.display = "flex"; 
                  }
                }
                // this.update();
              };
            
              this.removeURLHash = () => {
                history.replaceState(null, document.title, window.location.pathname + window.location.search);
              };

              let generatorEditedMostRecentCallbackCallIndex = 0;
              this.generatorEditedCallback = async (data, opts={}) => {
                generatorEditedMostRecentCallbackCallIndex++;
                let thisCallbackCallIndex = generatorEditedMostRecentCallbackCallIndex;
                let changed = false;
                let importsChanged = false;
                if(data.modelText !== undefined) {
                  this.data.generator.modelText = data.modelText;
                  changed = true;
                }
                if(data.outputTemplate !== undefined) {
                  this.data.generator.outputTemplate = data.outputTemplate;
                  changed = true
                }
                if(data.imports !== undefined) {
                  let currentImportsSet = new Set(this.data.generator.imports);
                  if(data.imports.sort().toString() !== this.data.generator.imports.sort().toString()) { // if sets are not equal
                    this.data.generator.imports = data.imports;
                    changed = true;
                    importsChanged = true;
                  }
                }
                // if it's changed, we set save state to unsaved, but only if the actual save request has been sent (which is why we check savingNowButStillWaitingForIframeReload here). if it's waiting for the iframe, then we've snuck in the changed data before it was sent to the server, so we're good.
                if(changed && !window.savingNowButStillWaitingForIframeReload) {
                  // save request has been sent to server, so we wait for it to finish, and then set save state to 'unsaved'
                  while(menuBar.saveState === "saving") {
                    if(thisCallbackCallIndex !== generatorEditedMostRecentCallbackCallIndex) return; // there's a newer one, so this one is not needed anymore (important to prevent "traffic jam" for autoSave stuff below)
                    await new Promise(r => setTimeout(r, 50));
                  }
            
                  menuBar.setSaveState("unsaved");
                  if(await window.thisIsNotAnOldCachedPagePromise) { // <-- we don't want an importUpdate message to block a cache-busting page reload
                    this.attachExitWarning(); // this actually only needs to be called once, but meh (it *replaces* the last one anyway)
                  }
                }
              };
              this.attachExitWarning = () => {
                if(!this.exitWarningAttached) {
                  // if there are unsaved changes and the user tries to navigate away from the page, warn them
                  window.onbeforeunload = (e) => {
                    if(menuBar.saveState === "unsaved" && !window.userDeletedGenerator && window.hasBeenInEditModeAtLeastOnce) { // window.hasBeenInEditModeAtLeastOnce is due to importsUpdate 'bug' where user can save gen without correct imports, causing visitors to have to download them on the fly, but that triggers a gen data change, which will trigger this handler if not for the window.hasBeenInEditModeAtLeastOnce check. hacky.
                      var dialogText = "You've got unsaved changes! Are you sure you want to exit?";
                      e.returnValue = dialogText;
                      return dialogText;
                    }
                  };
                  this.exitWarningAttached = true;
                }
              };
              this.openLoginModal = () => {
                loginModal.openModal();
              };
              this.openAccountModal = () => {
                accountModal.openModal();
              };
              this.openSettingsModal = () => {
                settingsModal.openModal();
              };
              this.openRevisionsModal = () => {
                revisionsModal.openModal();
              };
              this.loginSuccessCallback = (details) => {
                this.store.data.user = {email:details.email, sessionToken:details.sessionToken, loggedIn:true};
                this.store.save();
                // this.update();
                this.checkIfOwner();
                this.trigger("LoginStateChange");
              };
              this.emailChangeCallback = (newEmail) => {
                this.store.data.user.email = newEmail;
              };
              this.saveSuccessCallback = (name, publicId) => {
                if(name !== undefined) { // for when the save creates a new generator
                  this.data.generator.name = name;
                  this.data.generator.publicId = publicId; 
                }
                // this.update();
              };
              this.logout = () => {
                settingsModal.closeModal();
                accountModal.closeModal();
                // menuBar.isOwner = false;
                this.store.data.user = {loggedIn:false};
                localStorage.sessionTokenLastChangeTime = Date.now();
                this.store.save();
                // this.update();
                this.trigger("LoginStateChange");
              };
              this.handleIframeSaveRequest = () => {
                if((this.userOwnsThisGenerator && this.store.data.user.loggedIn) || localStorage[`perchance_generatorEditKey_${this.data.generator.name}`]) {
                  this.saveGenerator();
                }
              };
              this.attachKeyboardShortcuts = () => { 
                // CTRL/CMD + S
                document.addEventListener("keydown", (e) => {
                  if(e.keyCode == 83 && (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey)) {
                    e.preventDefault();
                    this.saveGenerator();
                  }
                }, false);
              };

              this.eventListeners = {
                "appinteractionstatechange": [],
                "generatorownershipchange": [],
                "loginstatechange": [],
              }
              this.on = function(name, handler) {
                this.eventListeners[name.toLowerCase()].push(handler);
              };
              this.trigger = function(name, data={}) {
                for(let fn of this.eventListeners[name.toLowerCase()]) {
                  fn(data);
                }
              };

              this.checkIfOwner = async () => {
                try {
                  let data = await fetch('/api/checkGeneratorOwnership', {
                    method: 'POST',
                    body: JSON.stringify({email:this.store.data.user.email, sessionToken:this.store.data.user.sessionToken, generatorName:this.data.generator.name}),
                    signal: AbortSignal.timeout?.(20*1000),
                    headers: { 'Content-Type': 'application/json'},
                  }).then(r => r.json());
            
                  if(data.status === "is-owner") {
                    this.userOwnsThisGenerator = true;
                    this.trigger("GeneratorOwnershipChange");
                    if(!window.editsHaveBeenMadeSincePageLoad) menuBar.setSaveState("saved");
                  } else if(data.status === "is-not-owner") {
                    this.userOwnsThisGenerator = false;
                    this.trigger("GeneratorOwnershipChange");
                    menuBar.setSaveState("unsaved"); // <-- it's not saved if they're not the owner
                  } else if(data.status === "session-token-error") {
                    this.logout();
                    // this.openLoginModal();
                    // alert("Sorry! Your session has expired, please login again.")
                  } else {
                    console.error("server error / unhandled response from checkGeneratorOwnership:");
                    console.debug(data);
                  }
                } catch(e) {
                  console.error("Problem with request to /api/checkGeneratorOwnership");
                  console.debug(e);
                  alert("There was a problem while loading this generator. If your internet connection is slow or intermittent, this could be the cause. Please try reloading the page.");
                }
              };



              // NOTE: THIS IS DEFINITELY NOT FULL-PROOF because browsers seem to pause tabs that haven't been active in a while (probably to converse memory/cpu).
              // So I should really switch to an approach like this: https://stackoverflow.com/a/69924841/11950764 (BroadcastChannel)
              // keep track of open generator tabs so we can warn if they are owner and have the same generator open twice and are editing:
              const tabTrackerUpdateInterval = 70000; // milliseconds - it needs to be higher than 1 min since chrome suspends tabs and wakes them only once per minute, and we send the "i'm still alive" pings during those wakes.
              function clearOldTabRecords(tabsOpen) {
                for(let [genName, tabIdDict] of Object.entries(tabsOpen)) {
                  for(let [tId, lastSeenTime] of Object.entries(tabIdDict)) {
                    if(Date.now()-lastSeenTime > tabTrackerUpdateInterval*2) {
                      console.debug(`Tab has not been seen in a while, assuming closed: ${genName} ${tId}`);
                      delete tabIdDict[tId];
                    }
                  }
                  if(Object.keys(tabIdDict).length === 0) {
                    console.debug(`No more tabs of this gen: ${genName}`);
                    delete tabsOpen[genName];
                  }
                }
              }
              let tabId = Math.random().toString().replace(".", "");
              setInterval(() => {
                let generatorName = app.data.generator.name;
                let tabsOpen;
                try {
                  tabsOpen = JSON.parse(localStorage.perchanceTabsOpen || "{}"); // {generatorName1: {tabId1:lastSeenTime}, generatorName2: {tabId2:lastSeenTime}, ...}
                } catch(e) {
                  console.warn("Something went wrong with localStorage.perchanceTabsOpen?");
                  tabsOpen = {};
                }
                if(!tabsOpen[generatorName]) tabsOpen[generatorName] = {};
                tabsOpen[generatorName][tabId] = Date.now();
                clearOldTabRecords(tabsOpen);
                localStorage.perchanceTabsOpen = JSON.stringify(tabsOpen);
              }, tabTrackerUpdateInterval);
              // this beforeunload will work most of the time, but we need the above mess (based on time-since-last-seen tabId) in case of e.g. sudden computer shutdown.
              window.addEventListener("beforeunload", function() {
                let tabsOpen = JSON.parse(localStorage.perchanceTabsOpen || "{}");
                if(tabsOpen[app.data.generator.name]) delete tabsOpen[app.data.generator.name][tabId];
                localStorage.perchanceTabsOpen = JSON.stringify(tabsOpen);
                return null;
              });

              let doNotAskToSaveEditPasswordFor = new Set();
              let inMemoryGeneratorNameToEditKey = {};
              let exampleGeneratorsOrPluginsEtc = ["blank", "layout-maker-plugin","examples","generators","download-button-plugin","perchance-keyboard-shortcuts","quug0pp21x","simple-if-else-example","simple-if-else-example-3","simple-if-else-example-2","simple-if-else-example-4","simple-critical-hit-example","simple-critical-hit-example-with-function","textarea-example","user-input-list-example","multiple-drop-down-lists-example","dynamic-drop-down-list-example","simple-checkbox-example","checkbox-checklist-example","color-picker-example","hierarchy-example-2","critical-hit-if-condition-is-met","critical-hit-if-condition-is-met-multi-line","critical-hit-if-condition-is-met-with-function","function-with-2-inputs-example","executing-and-hiding-result-example","getparent-getname-example","create-instance-plugin","dynamic-sublist-referencing-example","matching-pronouns-with-genders-example","dynamic-sub-list-referencing-example","multiple-independent-outputs-example","multiple-independent-outputs-example-2","multiple-buttons-same-output","your-generators-name","tags-and-header-meta-data-example","selectmany-sumitems-example","roll-number-of-dice-based-on-previous-roll","draw-a-river-example","add-up-randomly-generated-numbers-example","choose-a-list-based-on-a-selected-number","append-items-when-click-example","output-history-example","hide-output-until-click-example","select-leaf-plugin-example","consumable-leaf-list-plugin-example","dice-game-example","passing-variables-to-lists-example","consumable-list-with-dynamic-odds-example","indented-html-in-your-lists-example","character-role-consumable-example","consumable-list-with-nested-properties","three-percentages-example","click-to-hide-show-text-example","custom-cursor-example","counting-item-selections-example","simple-random-images-example","simple-random-image-example-cropped","add-images-to-output","random-image-with-name-example","random-images-example","acronym-from-words-example","p5js-basic-example","permutations-counter-example","income-by-city-example","randomize-at-regular-intervals-example","future-presidents-example","if-else-in-dynamic-odds-example","generate-based-on-seed-keyword","multiple-outputs-random-number-of-items-example","lineage-of-kings-example","fuel-consumption-distance","commas-in-numbers-example","exclude-item-based-on-previous-selection","change-item-odds-based-on-selections-parent","change-output-based-on-screen-size-example","bingo-table-example","get-median-of-numbers-example","filter-exclude-item-from-list","seed-from-url-example","pass-variable-via-url-example","user-controls-how-many-outputs-example","remember-user-inputs-basic-example","click-counter","click-counter-2","increment-counter-when-specific-items-is-selected-example","increment-counter-caves-example","generate-colored-text-example","custom-image-button-example","custom-image-button-with-hover-example","simple-mouse-hover-image-change-example","metadata-example","different-result-on-first-load","different-items-depending-on-num-clicks","show-specific-text-on-first-load","persistent-consumable-list-example","add-items-to-list-example","map-example","multiple-output-results-option","tap-image-to-randomize","first-n-items-of-random-sub-list","consumable-list-that-stays-consumed-until-refresh","numbered-outputs-example-manual","numbered-outputs-with-html-ol","text-contains-text-example","add-user-inputs-to-list-example","user-input-list-append-example","update-dynamically-generated-elements-example","image-layer-combiner-thumbnail-generator-example","using-name-of-selected-sublist-example","changing-drop-down-without-user-click-example","multi-dropdown-user-provided-pattern","generate-drop-down-input-from-hierarchical-list","use-seeder-plugin-for-one-import-only-example","dynamically-creating-a-list-and-adding-items-to-it","filter-list-based-on-instance-properties-example","filter-a-list-of-generated-instances-example","damage-roll-function-example","randomize-on-tap-with-optional-subtap","combine-multiple-lists-into-one-consumable-list","list-method-with-createinstance-example","combining-list-that-contain-duplicates-without-selecting-duplicates","question-and-answer-example","select-the-highest-number","curly-brackets-within-square-brackets-alternatives-example","array-of-instances-within-instance-example","sequential-pages-example","randomize-image-color-example","curly-blocks-inside-square-blocks","prevent-randomization-of-list-except-at-page-reload","track-selections-display-other-properties-of-selected-items-later","spoiler-hidden-unfold-html-example","comments-plugin-goto-plugin-example","pure-css-html-plugin-template","select-item-from-same-index-position-in-two-lists","adjustable-vertical-split-example","custom-font-importer","power-generator-manager","raggedflights-generators","plugins-page","eathams-pluginhub","dicemonger-generators","nes-template","dark-typography-template","timeline-template","big-typography-template","newspaper-multiple-columns","newspaper-column-template","accordion-template","accordion-multiple-buttons-template","twitter-feed-template","tweet-template","interactive-terminal-template","computer-terminal-template","origin-of-species-template","long-form-template","collection-template","basic-template","little-story-template","minimal","centered-minimal","centered-with-background-template","stat-block-5e-template","emoji-paragraph-template","generator-list-with-stats-template","generator-list-with-stats-2-template","tucked-corners-template","dark-card-template","glitch-text-template","nauseating-retro-flicker","visual-novel-template","diaryexample","khaki-templates","pandan-templates","ro-templates","nicksdropdownmenu","danielm-overview","garlicdolphin-templates","ronin-generators","eathams-templates","rg4m14ri","tutorial","aqr03wn1","diy-perchance-api","perchance-discord-bot","useful-generators","privacy-policy","advanced-tutorial","project-codename","creature-description","geographic-location","paint-color","random-story","dream-description","3d174opr","conjugate-plugin","plural-plugin","be-plugin","templates","noun","abstract-noun","concrete-noun","common-noun","sci-fi-noun","uncountable-noun","pronoun","adjective","comparative-adjective","superlative-adjective","food-adjective","adjective-of-relation","verb","speech-verb","adverb","time-adverb","manner-adverb","frequency-adverb","intensifier","interjection","common-word","preposition","emotion","greeting","goodbye","swear-word","personal-title","personal-suffix","prefix","exclamation","compound-word","cliche","simile","sentence","part-of-speech","rare-word","archaic-word","long-word","3-letter-word","short-word","gre-high-freq-word","funny-word","walk-verb","woo-word","grammatical-case","-ism","latin-word","philia","obsession","nonsense-word","complex-word","person-adjective","honorific","animal","endangered-animal","unusual-animal","land-animal","dog-breed","pet-animal","horse-breed","mammal-species","dinosaur","reptile-species","lizard-species","snake-species","turtle-species","turtle-tortoise-species","fish-species","sea-creature","flower-species","plant-species","tree-species","herb","spider-species","bug-species","beetle-species","bird-species","north-american-bird-species","antarctic-bird-species","scientific-species-name","body-part","horse-color","cat-breed","body-of-water","vegetable","fruit","ingredient","vitamin","condiment","spice","dessert","fast-food","dinner","biological-diet","cocktail","tea-variety","book","stephen-king-book","james-patterson-book","type-of-art","color-palette","color","room-type","rhetorical-device","speech-type","proverb","quote","pokemon","pokemon-ability","futurama-character","lotr-character","fact","password","phobia","fabric-type","complex-form","object","knot-name","container-type","roman-city","ancient-greek-city","form-of-government","mass-surveillance-project-name","uk-political-party","us-federal-agency","us-military-operation","terrorist-group","month","moon-phase","part-of-day","day-of-week","time-zone","egyptian-god","greek-god","greek-titan","greek-monster","tarot-prediction","zodiac-sign","chinese-zodiac-sign","fortune-telling-technique","norse-deity","christian-saint","religion","wingding","emoji","bw-emoji","braille","ascii-face","css-color","hex-color","crayon-color","color-name","hobby","mood","occupation","us-president","us-vice-president","celebrity","pope","british-actor","famous-scientist","person-build","person-height","person-age","face-shape","startup-idea-generator","fortune-500-company","industry","nasdaq-corporation","us-newspaper","shop-or-service","animal-protection-group","common-first-name","common-last-name","norwegian-last-name","male-norwegian-name","female-norwegian-name","aesthetic-username","couple-name","chocobo-name","common-female-name","common-male-name","common-unisex-name","japanese-surname","feminine-name","masculine-name","surname","medical-diagnosis","fake-drug-name","drug-name","us-hospital","language","pokemon-sprite","imgur-image","instagram-image","biology-field","scientific-instrument","planet-name","exoplanet-name","moon-name","fibonacci-number","prime-number","trig-identity","unit-of-measurement","polygon-name","metal","chemical-element","toxic-chemical","material","building-material","packaging-material","sculpting-material","patent","phone-brand","programming-languge","mime-type","gtld","us-geographic-location","river-name","sea-name","type-of-rock","gemstone","terrain","nationality","country","country-or-territory","european-union-member","african-country","continent","us-city","japanese-city","german-town","us-state","canadian-municipality","english-town-name","english-city-name","venue","car-brand","nautical-term","anime-film","disney-film","marvel-film","pixar-film","netflix-category","jeopardy-question","star-trek-planet","monster-type","fantasy-language","website","youtube-thumbnail","youtube-video","social-network","instagram-user","instagram-username","musical-instrument","music-genre","traditional-dance-style","playing-card","playing-card-short","video-game","wrestling-move","wwe-wrestler","plugins","markdown-plugin","storing-selections-example-1","storing-selections-example-2","import-example","fav-book","multiline-example","multiline-pro-example","multiline-pro-simple-example","html-table-example","input-example","input-autoupdate-example","newspaper-column-creator","drop-down-list-example","hierarchy-example","output-keyword-example","battle-simulator-example","text-to-image-plugin","ai-text-plugin","comments-plugin","create-instances-plugin","image-layer-combiner-plugin","pattern-maker-plugin","tap-plugin","favicon-plugin","select-range-plugin","dice-plugin","wheel-plugin","upload-plugin","random-integer-plugin","random-decimal-plugin","seeder-plugin","url-params-plugin","remember-plugin","tooltip-plugin","generator-stats-plugin","tldraw-plugin","rpg-icon-plugin","font-plugin","google-sheets-plugin","sum-odds-plugin","background-image-plugin","background-audio-plugin","press-enter-plugin","tap-anywhere-plugin","select-until-plugin","select-leaf-plugin","select-leaves-plugin","select-all-leaves-plugin","random-select-plugin","consumable-leaf-list-plugin","typewriter-plugin","make-table-plugin","lockable-list-plugin","locker-plugin","fixed-until-reload-plugin","number-set-plugin","numerals-to-words-plugin","numerals-to-ordinal-words-plugin","numerals-to-ordinals-plugin","roman-numerals-plugin","text-to-speech-plugin","join-lists-plugin","exclude-items-plugin","filter-list-plugin","markov-chain-plugin","roll-table-plugin","goto-plugin","nested-plugin","navbar-plugin","literal-plugin","super-fetch-plugin","consumable-list-loop-plugin","dynamic-import-plugin","print-button-plugin","copy-text-plugin","fullscreen-button-plugin","tabs-plugin","title-case-plugin","random-image-plugin","image-plugin","pride-plugin","tornado-plugin","flat-avatar-plugin","a-an-plugin","date-plugin","preprocessors"];
              this.saveGenerator = async () => { 
                
                let originalLastEditorsChangeTime = window.lastEditorsChangeTime;

                let editKey = null;
                if(!this.userOwnsThisGenerator && !exampleGeneratorsOrPluginsEtc.includes(this.data.generator.name)) {
                  editKey = localStorage[`perchance_generatorEditKey_${this.data.generator.name}`] || prompt("Click OK to 𝗰𝗿𝗲𝗮𝘁𝗲 a new generator based on this one. If you own this generator and would like to 𝗲𝗱𝗶𝘁 it, then first paste the edit password below.", inMemoryGeneratorNameToEditKey[this.data.generator.name] || "");
                  if(editKey === null) return; // they clicked cancel
                  editKey = editKey.trim();
                  if(!editKey) editKey = null;
                }
            
                // if(!this.store.data.user.loggedIn) {
                //   if(!confirm(`Since you're not logged in, saving will anonymously create a new generator with a unique password that is required to edit it. Continue?`)) {
                //     this.logout(); // ensure they're properly logged out
                //     this.openLoginModal();
                //     return;
                //   }
                // }
            
                console.debug("saveGenerator called. saveState:", menuBar.saveState);
                if(menuBar.saveState !== "unsaved") {
                  return;
                }
            
                if(this.userOwnsThisGenerator) {
                  let tabsOpen = JSON.parse(localStorage.perchanceTabsOpen || "{}");
                  clearOldTabRecords(tabsOpen);
                  if(tabsOpen[this.data.generator.name] && Object.keys(tabsOpen[this.data.generator.name]).length > 1) {
                    let continueSaving = confirm("Note: You have this generator open in another tab. Be careful that you're only editing your generator from a single tab, since you may accidentally overwrite previous edits. Continue saving?");
                    if(!continueSaving) return;
                  }
                }
            
                let saveId = Math.random().toString();
            
                menuBar.setSaveState("saving");
                console.debug("Waiting for reload before saving...", saveId);
                window.savingNowButStillWaitingForIframeReload = true;
                try {
                  await window.hardReloadOutputIframe(); // this updates the metadata and dependencies
                } catch(e) {
                  console.error(e);
                }
                window.savingNowButStillWaitingForIframeReload = false;
                console.debug("Finished waiting for save reload.", saveId);
            
                try {
            
                  // we use these below for lastModelTextSaved/lastOutputTemplateSaved - can't set them yet since we don't know if it will save successfully
                  let modelText = this.data.generator.modelText;
                  let outputTemplate = this.data.generator.outputTemplate;
            
                  let generatorMetaData = editor.generatorMetaData;
                  
                  let bodyData = {
                    email: this.store.data.user.email || "",
                    generator: this.data.generator,
                    generatorMetaData,
                    sessionToken: this.store.data.user.sessionToken || "",
                    lastKnownSaveTime: window.generatorLastSaveTime,
                  };
                  if(editKey !== null) {
                    bodyData.editKey = editKey;
                  }

                  let data = await fetch("/api/save", { method:'POST', body:JSON.stringify(bodyData), signal:AbortSignal.timeout?.(20*1000), headers:{ 'Content-Type': 'application/json' }}).then(r => r.json());
                  if(data.status === "stale") {
                    if(!confirm("It looks like you're editing an old version of this generator. You may have been editing it in a different browser tab. Note that you can access all versions using the 𝗯𝗮𝗰𝗸𝘂𝗽𝘀 button. Are you sure you want to continue?")) {
                      menuBar.setSaveState("unsaved");
                      return;
                    }
                    bodyData.forceSaveDespiteStaleness = true;
                    data = await fetch("/api/save", { method:'POST', body:JSON.stringify(bodyData), signal:AbortSignal.timeout?.(20*1000), headers:{ 'Content-Type': 'application/json' }}).then(r => r.json());
                  }
                  if(data.status === "captcha-needed") { // for 'anon' saves
                    bodyData.captchaToken = await getCaptchaToken();
                    data = await fetch("/api/save", { method:'POST', body:JSON.stringify(bodyData), signal:AbortSignal.timeout?.(20*1000), headers:{ 'Content-Type': 'application/json' }}).then(r => r.json());
                  }
            
                  if(data.status === "saved") {
                    window.generatorLastSaveTime = data.time;
            
                    if(originalLastEditorsChangeTime === window.lastEditorsChangeTime) {
                      window.modelTextEditor.markClean();
                      window.outputTemplateEditor.markClean();
                      menuBar.setSaveState("saved");
                    } else {
                      menuBar.setSaveState("unsaved");
                    }
            
                    // these are used as an extra check in doLocalGeneratorBackupIfNeeded to prevent backing up text that is already saved
                    window.lastModelTextSaved = modelText;
                    window.lastOutputTemplateSaved = outputTemplate;
                    
                    this.saveSuccessCallback();

                    if(editKey && !localStorage[`perchance_generatorEditKey_${this.data.generator.name}`] && !doNotAskToSaveEditPasswordFor.has(this.data.generator.name)) {
                      inMemoryGeneratorNameToEditKey[this.data.generator.name] = editKey;
                      if(confirm(`Your changes have been saved. You can click OK to save this password to your temporary browser storage, so you don't have to enter the password every time you make an edit. You should 𝗰𝗹𝗶𝗰𝗸 𝗰𝗮𝗻𝗰𝗲𝗹 if you're using a shared computer (e.g. at library). Note: If your cookies/storage for this site are cleared, your saved passwords will be cleared.`)) {
                        localStorage[`perchance_generatorEditKey_${this.data.generator.name}`] = editKey;
                      } else {
                        doNotAskToSaveEditPasswordFor.add(this.data.generator.name);
                      }
                    }
            
                  } else if(data.status === "created") {
                    window.generatorLastSaveTime = data.time;
            
                    if(this.store.data.user.loggedIn) {
                      this.userOwnsThisGenerator = true;
                      this.trigger("GeneratorOwnershipChange");
                      menuBar.refs.settingsButton.style.display = "block";
                    }

                    window.history.replaceState(null, null, `/${data.name}${window.location.hash}`);
                    this.data.generator.name = data.name;
                    window.generatorName = data.name;
                    menuBar.setSaveState("saved");
                    window.generatorPublicId = data.publicId;
                    this.saveSuccessCallback(data.name, data.publicId);
                    window.hardReloadOutputIframe();
            
                    menuBar.refs.statusMessage.innerHTML = "<b>(new generator created)</b>";
                    menuBar.refs.statusMessage.style.display = "inline-flex";
                    setTimeout(() => {
                      menuBar.refs.statusMessage.innerHTML = "";
                      menuBar.refs.statusMessage.style.display = "none";
                    }, 4000);

                    if(!this.store.data.user.loggedIn) {
                      inMemoryGeneratorNameToEditKey[data.name] = data.editKey;
                      prompt("New generator created. If you'd like to edit it in the future, you'll need to use the following password. Please copy and paste it somewhere safe:", data.editKey);
                      if(confirm(`You can click OK to save this password to your temporary browser storage, so you don't have to enter the password every time you make an edit. You should 𝗰𝗹𝗶𝗰𝗸 𝗰𝗮𝗻𝗰𝗲𝗹 if you're using a shared computer (e.g. at library). Note: If your cookies/storage for this site are cleared, your saved passwords will be cleared.`)) {
                        localStorage[`perchance_generatorEditKey_${data.name}`] = data.editKey;
                      } else {
                        doNotAskToSaveEditPasswordFor.add(data.name);
                      }
                    }
            
                  } else if(data.status === "invalid-edit-key") {
                    delete localStorage[`perchance_generatorEditKey_${this.data.generator.name}`];
                    menuBar.setSaveState("error");
                    setTimeout(() => { menuBar.setSaveState("unsaved"); }, 1000);
                    alert("The edit password was incorrect. Please try again.");
                  } else if(data.status === "session-token-error") {
            
                    this.logout();
                    this.openLoginModal();
                    menuBar.setSaveState("error");
                    setTimeout(() => { menuBar.setSaveState("unsaved"); }, 1000);
            
                  } else if(data.status === "too-big") {
                    menuBar.setSaveState("error");
                    alert("Hmm. There's too much text in this generator to save it to Perchance's database. :| Can you perhaps break it into several smaller generators that you import into the main one? Note that perchance.org/upload can be used to upload large amounts of data.");
                    setTimeout(() => { menuBar.setSaveState("unsaved"); }, 1000);
                  } else if(data.status === "too-many-requests") {
                    menuBar.setSaveState("error");
                    alert(`You're saving too quickly!${this.store.data.user.loggedIn ? " Please try again in a few seconds." : " If you're not saving quickly, then this 𝗰𝗼𝘂𝗹𝗱 𝗯𝗲 𝗰𝗮𝘂𝘀𝗲𝗱 𝗯𝘆 𝗮 𝗩𝗣𝗡 browser extension - try disabling it, or logging in."}`);
                    setTimeout(() => { menuBar.setSaveState("unsaved"); }, 1000);
                  } else {
                    console.error("Server error while saving:", data);
                    menuBar.setSaveState("error");
                    alert("Seems like there was a problem while trying to save your generator. This could be to do with your internet connection, but it could also be a temporary problem with the server. Please copy and paste your generator data (lists and HTML) to a safe place before leaving or refreshing the page, or you could lose your work. If you keep getting errors even after waiting a couple of minutes, please make a post on lemmy.world/c/perchance to see if others are experiencing the same thing. Remember that you can click the \"backups\" button in the top-right of the screen to download past versions of your generator. Before doing anything though, make sure you copy and paste your data to a safe place! Sorry for the trouble - this stuff happens sometimes :|");
                    setTimeout(() => { menuBar.setSaveState("unsaved"); }, 1000);
                  }
            
                  // track generator save times so we can cache bust if cloudflare cache puring is delayed (see code at bottom of index.html template)
                  if(data.status === "saved" || data.status === "created") {
                    let generatorSavedTimes = JSON.parse(localStorage["generatorSavedTimes"] || "{}");
                    generatorSavedTimes[this.data.generator.name] = Date.now();
                    // clear old save times (older than 3 months, since the cache definitely shouldn't last any longer than that, even if a manual purge isn't initiated):
                    generatorSavedTimes = Object.fromEntries( Object.entries(generatorSavedTimes).filter(e => e[1] > Date.now()-1000*60*60*24*30) );
                    localStorage["generatorSavedTimes"] = JSON.stringify(generatorSavedTimes);
                  }
                } catch(e) {
                  console.error("Request error while saving:");
                  console.error(e);
                  menuBar.setSaveState("error");
                  setTimeout(() => { menuBar.setSaveState("unsaved"); }, 1000);
                }
              };

              
              this.userOwnsThisGenerator = undefined; // IMPORTANT: this must be undefined while we don't know - there is code which relies on this.

              let originalSessionTokenLastChangeTime = Number(localStorage.sessionTokenLastChangeTime || 0);
              let initStore = () => {
                this.store = new Store("app");
                if(!this.store.data.user) {
                  this.store.data.user = {loggedIn:false};
                  this.store.save();
                }
              }
              initStore();

              setInterval(() => { // in case they logged out/in in another tap
                if(originalSessionTokenLastChangeTime !== Number(localStorage.sessionTokenLastChangeTime || 0)) {
                  originalSessionTokenLastChangeTime = Number(localStorage.sessionTokenLastChangeTime || 0);
                  let wasLoggedIn = this.store.data.user.loggedIn;
                  initStore();
                  if(this.store.data.user.loggedIn) this.checkIfOwner();
                  if(wasLoggedIn !== this.store.data.user.loggedIn) this.trigger("LoginStateChange");
                }
              }, 3000);
            
              this.data.generator = generator;
              this.data.dependencies = dependencies;
              // this.update();
          
              this.appInteractionState = "view";

              if(this.store.data.user.loggedIn) {
                this.checkIfOwner();
              }

              // NOTE: This was originally in the editor, but that doesn't load until edit is clicked, so crawlers wouldn't see it, which is bad for gens with no $meta.title/description - google got very confused for a few weeks.
              let isFirstMetaUpdate = true;
              window.addEventListener("message", async (e) => {
                let origin = e.origin || e.originalEvent.origin;
                if(origin !== "https://null.perchance.org" && origin !== `https://${window.generatorPublicId}.perchance.org`) return;
                
                if(e.data.type === "metaUpdate") {
                  if(e.data._validation.generatorName !== app.data.generator.name) return; // <-- trying to stop weird Google crawler page title bug

                  // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING: If you change this at all, make sure to do a thorough check for XSS bugs.
                  // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

                  if(typeof e.data.html === "string") {
                    if(e.data.html.length < 100_000 && window.shouldLiftGeneratorHtmlFromEmbed) {
                      window.document.querySelector("#generator-description").innerHTML = DOMPurify.sanitize(e.data.html, {ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'p', 'div', 'pre', 'button', 'i', 'b', 'a', 'ul', 'li', 'br', 'ol', 'hr'], ALLOWED_ATTR: ['href']});
                      if(!window.generatorCanLinkWithRelFollow) window.document.querySelectorAll("#generator-description a").forEach(a => a.rel="nofollow ugc");
                    }
                  }
                  if(typeof e.data.title === "string") {
                    if(!isFirstMetaUpdate) { // correct title is hardcoded in HTML on page load (and if dynamic, then as of writing a `fetch` call updates it.)
                      window.document.title = e.data.title + " ― Perchance" + (/(gener|\bai\b)/i.test(e.data.title) ? "" : " Generator");
                    }
                  }
                  isFirstMetaUpdate = false;
                }
              });

              window.menuBar.init();
              window.loginModal.init();
              window.accountModal.init();
              window.settingsModal.init();
              window.revisionsModal.init();

              if(window.location.hash === "#debugFreeze") {
                window.DEBUG_FREEZE_MODE = true;
            
                // we do this rather than setting the hash with location.hash because otherwise it essentially does a pushState behind the scenes
                let url = new URL(location.href);
                url.hash = "#edit";
                history.replaceState({}, "", url.href);
            
                this.appInteractionState = "edit";
                this.trigger("AppInteractionStateChange");
              } else if(window.location.hash === "#edit") {
                this.appInteractionState = "edit";
                this.trigger("AppInteractionStateChange");
              }

              if(this.appInteractionState === "edit") {
                await this.goToEditMode();
              } else if(this.appInteractionState === "view") {
                this.goToViewMode();
              }
              this.attachKeyboardShortcuts();
            }
          };
        </script>

        <script>window.remoteResourcesLoaded = true;</script>
        <script>
          window.empty883974329 = "";
          window.modalFn1Name = "alert";
          window.rlFn1Name = `reload`;
          window.ftcFn1Name = "fetch";
          window.ap1pend1ChildFn2Name = "appendChild";
          window.doc34828272947 = "document";

          try { // adding try/catch here in case of future instances of this: https://lemmy.world/post/4913660
            window.generatorDependenciesData = window.js0nparse( decodeURI( document.querySelector("#imported-generators").innerText ) );
          } catch(e) {
            if(!location.href.includes("__generatorDependenciesCacheBust")) { // try a cache bust if we haven't already.
              let url = new URL(window.location.href);
              url.searchParams.set("__generatorDependenciesCacheBust", Math.random());
              window.location.href = url.href; 
              throw new Error("exiting script tag for dependency cache bust"); // since we can't `return` at top level
            } else { // if we've already tried bust, don't do it again, else it'll be a refresh loop
              window.generatorDependenciesData = [];
              let errorCode = 1;
              if(document.querySelector("#imported-generators").innerText === "") {
                errorCode = 2;
              } else {
                errorCode = 3;
                try {
                  decodeURI(document.querySelector("#imported-generators").innerText);
                } catch(e) {
                  errorCode = 4;
                }
              }
              alert(`There was some sort of bug parsing the imports of this generator. Buggy ad blockers can sometimes cause this. Please report this at https://lemmy.world/c/perchance and mention this error code: ${errorCode}`);
            }
          }

          if(location.href.includes("__generatorDependenciesCacheBust")) {
            let url = new URL(window.location.href);
            url.searchParams.delete("__generatorDependenciesCacheBust");
            let newPath = url.href.replace(/^https:\/\/perchance\.org/, "");
            history.replaceState({}, "", newPath);
          }

          window.usesAiPlugins = window.generatorDependenciesData.filter(d => d.name === "ai-text-to-image-plugin" || d.name === "ai-text-plugin").length > 0;

          window.iudu843975 = "bbb";
          if(iudu843975.includes("a")) {
            uruf8ufd.jfurwe8j;
          }
          
          (async function() {
            await app.init({
              generator: window.generatorData,
              dependencies: window.generatorDependenciesData,
            });
            window.successfulPageLoad = true;
          })();
        </script>
        
        <!-- <script async src="https://www.googletagmanager.com/gtag/js?id=G-YJWJRNESS5"></script> -->
        <script>
          setTimeout(() => { // dynamically add after delay to reduce initial lag on low-end mobile devices
            let script = document.createElement('script');
            script.async = true;
            script.src = "https://www.googletagmanager.com/gtag/js?id=G-YJWJRNESS5";
            document.body.appendChild(script);
          }, 1000*15);

          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', 'G-YJWJRNESS5');
          
          try {
            setTimeout( function() { // wait for init (we're not in any hurry)
              document.querySelector("#verify-account-button").addEventListener('click', function() {
                gtag("event", "signup", {});
              });
            }, 20*1000);
          } catch(e) { console.error(e); }
        </script>


        <script>
          window.downloadTextFile = (text, name) => {
            const a = document.createElement('a');
            const type = name.split(".").pop();
            a.href = URL.createObjectURL( new Blob([text], { type:`text/${type === "txt" ? "plain" : type}` }) );
            a.download = name;
            a.click();
          };
          window.diffStuff = {}; //patches, modelTextPatches and outputTemplatePatches get added to this object in revisions-modal.tag. It's hacky, but it'll do for now.
          window.diffStuff.openNewTabWithRevision = async function(revisionNumber, generatorName) {
            if(!window.diff_match_patch) {
              let script = document.createElement('script');
              script.src = "/lib/diff_match_patch.js";
              document.body.appendChild(script);

              while(!window.diff_match_patch) {
                await new Promise(r => setTimeout(r, 200));
              }
              window.dmp = new diff_match_patch();
              window.diffStuff._patchesToRevision = (patches, revisionNumber) => {
                if(revisionNumber > patches.length-1 || revisionNumber < 0) throw new Error(`revisionNumber ${revisionNumber} doesn't exist. max index of patches array = ${patches.length-1}`);
                let text = patches[0];
                if(revisionNumber === 0) return text;
                for(let n = 1; n < patches.length; n++) {
                  //text = JsDiff.applyPatch(text, patches[n]);
                  text = dmp.patch_apply(dmp.patch_fromText(patches[n]), text)[0];
                  if(text === false) throw new Error("JsDiff says that the patches aren't correct. some sort of corruption or incorrect formatting or mismatch");
                  if(n === revisionNumber) return text;
                }
              };
            }
            let modelText = this._patchesToRevision(this.modelTextPatches, revisionNumber);
            let outputTemplate = this._patchesToRevision(this.outputTemplatePatches, revisionNumber);

            // we used encodeURI to fix emojis problem with https://github.com/google/diff-match-patch, so we need to decode:
            modelText = decodeURI(modelText);
            outputTemplate = decodeURI(outputTemplate);

            let intro = "<<<<< this file contains your perchance lists first, and your HTML code underneath it >>>>>\n\n\n\n";
            window.downloadTextFile(intro+modelText+("\n".repeat(20))+outputTemplate+("\n".repeat(20)), `${generatorName}-revision-${revisionNumber}.txt`);
          };
        </script>


        <script>
          // a temporary hack to make sure search engines see links on generators page:
          if(document.location.pathname === "/generators") { 
            var req = new XMLHttpRequest();
            req.overrideMimeType("application/json");
            req.open('GET', "/api/getGeneratorList", true); 
            req.onload  = function() {
              var result = window.js0nparse(req.responseText);
              var div = document.createElement('div');
              if(window.canExecuteModernJavascript) {
                div.style.height = "0px";
                div.style.overflow = "hidden";
                div.style.position = "fixed";
              }
              div.innerHTML = "Here are the latest generators: "+result.generators.map(function(g){ return "<a href='/"+g.name+"'>"+g.name+"</a>"; }).join(", ")+".";
              document.body.appendChild(div);
            };
            req.send(null);
          }
        </script>
        
        <script>
          (async function() {
            await new Promise(r => setTimeout(r, 1000*20));
            if(!navigator["\u0077\u0065\u0062\u0064\u0072\u0069\u0076\u0065\u0072"]) {
              fetch(`https://perchance.org/api/cv?generatorName=${location.pathname.slice(1)}&isFromEmbed=0&__cacheBust=${Math.random()}`);
              document.addEventListener("visibilitychange", () => {
                if(document.visibilityState === "visible") {
                  fetch(`https://perchance.org/api/cv?generatorName=${location.pathname.slice(1)}&isFromEmbed=0&__cacheBust=${Math.random()}`);
                }
              });
            }
          })();
        </script>
        
        <script>
          (async function() {
            if(window.location.hash !== "#edit") {
              while(!document.querySelector("div.menu-item.new")) await new Promise(r => setTimeout(r, 20));
              let btnHtml = document.querySelector("div.menu-item.new").outerHTML;
              btnHtml = btnHtml.replace(/\/minimal#edit/g, "/ai-chat"); // "https://discord.gg/43qAQEVV9a"
              btnHtml = btnHtml.replace(/>new</g, ">ai chat<");
              btnHtml = btnHtml.replace(/menu-item new/g, "menu-item promo");
              btnHtml = btnHtml.replace(/➕/g, "🆕");
              let ctn = document.createElement("div");
              ctn.innerHTML = btnHtml;
              let btn = ctn.firstElementChild;
              let systemIsInDarkMode = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
              if(systemIsInDarkMode) {
                btn.style.backgroundColor = "rgb(110 53 11)";
              } else {
                btn.style.backgroundColor = "#ffd4a4";
              }
              document.querySelector("div.menu-item.new").after(btn);
            }
          })();
        </script>

        <script>
          (async function() {

            async function sha256Text(text) {
              const msgUint8 = new TextEncoder().encode(text);                          
              const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);          
              const hashArray = Array.from(new Uint8Array(hashBuffer));                    
              const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
              return hashHex;
            }

            async function sendNotification(data) {
              // safety code to prevent duplicate notifications (shouldn't be needed, but just in case):
              let hash = await sha256Text(JSON.stringify(data));
              if(!localStorage.alreadyRecentlySentNotificationHashes) localStorage.alreadyRecentlySentNotificationHashes = "";
              if(localStorage.alreadyRecentlySentNotificationHashes.includes(hash)) return;
              localStorage.alreadyRecentlySentNotificationHashes += ","+hash;
              if(localStorage.alreadyRecentlySentNotificationHashes.length > 2000) localStorage.alreadyRecentlySentNotificationHashes = localStorage.alreadyRecentlySentNotificationHashes.slice(-1000);
              
              let notification;
              if(Notification.permission === "granted") {
                notification = new Notification(data.title, {body:data.body});
              } else if(Notification.permission !== "denied") {
                const permission = await Notification.requestPermission();
                if(permission === "granted") {
                  notification = new Notification(title, options);
                }
              }
              return notification;
            }

            window.addEventListener("message", async function(e) {
              let origin = e.origin || e.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
              if(origin !== "https://comments-plugin.perchance.org") {
                return;
              }
              if(e.data.type === "ensure-notification-permission") {
                if(Notification.permission !== "granted" && Notification.permission !== "denied") {
                  const permission = await Notification.requestPermission();
                  if(permission === "granted") {
                    console.debug("notification permission granted");
                  } else {
                    console.debug("notification permission denied");
                  }
                }
              } else if(e.data.type === "notification-request") {
                if(Notification.permission !== "denied") {
                  if(e.data.folderName.split("+")[0] === window.location.pathname.slice(1)) {
                    let notification = await sendNotification(e.data).catch(e => console.error(e));
                    if(notification) notification.onclick = function() { window.focus(); this.close(); };
                  } else {
                    console.debug("Pending notification:", e.data.title, e.data.body, e.data.folderName);
                    // we ideally want this notification to be triggered in an already-open tab of the relevant generator (because then the notification.onclick can focus that tab, rather than opening a duplicate of that tab), so we put the notification data in localStorage and wait a few seconds for the relevant tab to take it out, and if not, then we trigger it from this tab, and set onclick to open a new tab
                    if(!localStorage.pendingNotifications) localStorage.pendingNotifications = "[]";
                    let pendingNotifications;
                    try { pendingNotifications = window.js0nparse(localStorage.pendingNotifications); } catch(e) { console.error("failed to parse pending notifications", e); pendingNotifications = []; }
                    pendingNotifications.push(e.data);
                    localStorage.pendingNotifications = JSON.stringify(pendingNotifications);

                    // try to wake the target tab with a BroadcastChannel message (no idea if this helps, but can't hurt):
                    let broadcastChannel;
                    if(window.BroadcastChannel) {
                      broadcastChannel = new BroadcastChannel("generatorName:"+window.location.pathname.slice(1));
                      broadcastChannel.postMessage({type:"wake-up"});
                    }
                    
                    setTimeout(async function() {
                      if(broadcastChannel) broadcastChannel.close();
                      let pendingNotifications;
                      try { pendingNotifications = window.js0nparse(localStorage.pendingNotifications); } catch(e) { console.error("failed to parse pending notifications", e); pendingNotifications = []; }
                      let notificationData = pendingNotifications.find(d => d.time === e.data.time && d.folderName === e.data.folderName && d.title === e.data.title && d.body === e.data.body);
                      if(notificationData) {
                        let notification = await sendNotification(notificationData).catch(e => console.error(e));
                        if(notification) notification.onclick = function() { window.open(`/${notificationData.folderName.split("+")[0]}`, "_blank"); this.close(); };
                        pendingNotifications = pendingNotifications.filter(d => d !== notificationData);
                        localStorage.pendingNotifications = JSON.stringify(pendingNotifications);
                      }
                    }, 1000*7); // <-- 'pending notification' timeout length (before we give up and just sent the `Notification` from this tab)
                  }
                }
              }
            });

            (async function() {

              if(window.BroadcastChannel) {
                let channel = new BroadcastChannel("generatorName:"+window.location.pathname.slice(1));
                channel.onmessage = (event) => {
                  if(event.data.type === "wake-up") {
                    console.debug("received wake-up message at:", new Date().toString());
                  }
                };
              }

              while(1) {
                let generatorName = window.location.pathname.slice(1);
                try {
                  await new Promise(r => setTimeout(r, 1000*2)); // this wait time must be lower than the 'pending notification' timeout length above
                  // parse localStorage.pendingNotifications and trigger notification if generatorName matches folderName
                  if(!localStorage.pendingNotifications) localStorage.pendingNotifications = "[]";
                  let pendingNotifications;
                  try { pendingNotifications = window.js0nparse(localStorage.pendingNotifications); } catch(e) { console.error("failed to parse pending notifications", e); pendingNotifications = []; }
                  
                  let pendingNotificationsForThisGeneratorName = pendingNotifications.filter(n => n.folderName.split("+")[0] === generatorName);
                  for(let notificationData of pendingNotificationsForThisGeneratorName) {
                    let notification = await sendNotification(notificationData).catch(e => console.error(e));
                    if(notification) notification.onclick = function() { window.focus(); this.close(); };
                    pendingNotifications = pendingNotifications.filter(n => n !== notificationData);
                  }
                  localStorage.pendingNotifications = JSON.stringify(pendingNotifications);
                } catch(e) { console.error(e) }
              }
            })();

          })();
        </script>
        
        <script>
          (function() {

            function chec3kRes1Load(url, type) {
              return new Promise(resolve => {
                let el = document.createElement(type);
                el.src = url;
                el.onload = function() { resolve(true); };
                el.onerror = function() { resolve(false); };
                document['head'].appendChild(el);
              });
            }

            async function hasVariables() {
              return window.freestar || window._snigelConfig || window.quantserve || window.google_image_requests || window.gaData || window.__tcfapi || window.Criteo || window.__halo_loaded__ || await chec3kRes1Load("https://static.criteo.net/images/pixel.gif?ch=1", "img");
            }

            window.adsAreShowing = async () =>  {   
              let adEl = document.querySelector(".ad-providers-ctn-el");
              if(!adEl) return false;
              let hasIframe = adEl.querySelector("iframe");
              let hasAnalytics = await hasVariables() || (await chec3kRes1Load(`https://secure.quantserve.com/quant.js`, `script`));
              if(adEl && adEl.innerHTML.length > 5 && adEl.offsetParent !== null && adEl.offsetHeight > 20 && (hasIframe || hasAnalytics)) return true;
              // if(adEl && adEl.innerHTML.length > 5 && adEl.offsetParent !== null && adEl.offsetHeight > 20 && adEl.querySelector("iframe")) return true;
              return false;
            };

            let already1AddedAd3vertIfNeeded = false;
            window.addEventListener("message", function(e) {
              let origin = e.origin || e.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
              if(origin !== "https://null.perchance.org" && origin !== `https://${window.generatorPublicId}.perchance.org`) {
                return;
              }
              
              if(e.data.type === `usingAdPoweredPlugin` && window.location.pathname !== '/text-to-image-plugin' && window.location.pathname !== '/ai-text-plugin') {
                window.usesAiPlugins = true; // e.g. loaded iframe within iframe
                addAdvert();
              }
            });

            setTimeout(() => {
              if(window.usesAiPlugins || window.generatorData.imports.includes("ai-text-to-image-plugin") || window.generatorData.imports.includes("ai-text-plugin")) {
                addAdvert();
              }
            }, 10);

            let addAdvert = async function() {
              if(already1AddedAd3vertIfNeeded) return;
              already1AddedAd3vertIfNeeded = true;

              if(window.location.hash !== "#edit") window.queuedStatCountKeys.add("uaine");

              if((window[`localStorage`]["app-storage"] && window[`localStorage`]["app-storage"].includes("sessionToken")) || navigator.webdriver) {
                return; // not for logged-in users and screenshot bot
              }

              while(!document.querySelector("#main")) await new Promise(r => setTimeout(r, 200));

              window.adCtn = createAdCtn();
              appEl.appendChild(window.adCtn);

              // to give loading priority to main page content, and allow dynamic metadata to load (which can change/set window.forceDisableAds):
              await new Promise(r => setTimeout(r, 7*1000)); 
              if(document.readyState !== 'complete') await new Promise(r => setTimeout(r, 5*1000)); 

              if(window.forceDisableAds) return; // note: it's correct for adCtn to be shown still in this case

              window.pageWillDisplayAds = true;

              if(window.location.hash !== "#edit") window.queuedStatCountKeys.add("uaineala");
              
              
              let adProviderName = "freestar"; 
              if(window.location.hash.startsWith("#adProviderName=")) adProviderName = window.location.hash.slice("#adProviderName=".length);
              if(adProviderName !== `snigel` && adProviderName !== "freestar") adProviderName = "freestar";
              // if(window.location.pathname === "/ai-rpg") adProviderName = "snigel";
              console.debug("ad:", adProviderName);

              if(!window.___alreadyInitializedAdRefreshFocusBugStuff) {
                window.___alreadyInitializedAdRefreshFocusBugStuff = true;

                let gotFirstOutputIframeFocusMessage = false;
                window.lastKnownOutputIframeFocusTime = Date.now();
                window.addEventListener("message", function(e) {
                  if(e.origin !== "https://null.perchance.org" && e.origin !== `https://${window.generatorPublicId}.perchance.org`) return;

                  if(e.data.type === "outputIframeCurrentlyHasFocus") {
                    gotFirstOutputIframeFocusMessage = true;
                    window.lastKnownOutputIframeFocusTime = e.data.time;
                  }
                });
                
                // NEW FOCUS FIX:
                (async function() {
                  while(!gotFirstOutputIframeFocusMessage) await new Promise(r => setTimeout(r, 500));
                  document.querySelector("#appEl #output iframe").contentWindow.postMessage({type:"enableStrongFocusFix"}, "*");
                })();
                window.addEventListener("pointerdown", function(e) {
                  document.querySelector("#appEl #output iframe").contentWindow.postMessage({type:"pauseStrongFocusFix"}, "*");
                  setTimeout(() => e.target.focus(), 100); // wait a bit til focus fix is disabled, then grab focus back
                });

                // OLD FOCUS FIX (temporarily leaving for debugging/detection stuff):
                let lastUserCausedFocusActionTime = Date.now();
                window.addEventListener("pointerdown", function() {
                  lastUserCausedFocusActionTime = Date.now();
                });
                document.addEventListener("visibilitychange", () => {
                  if(document.visibilityState === "visible") {
                    lastUserCausedFocusActionTime = Date.now();
                  }
                });
                window.addEventListener("pageshow", () => {
                  lastUserCausedFocusActionTime = Date.now();
                });
                
                let iOSSafari = false;
                try {
                  let ua = window.navigator.userAgent;
                  let iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
                  let webkit = !!ua.match(/WebKit/i);
                  iOSSafari = iOS && webkit && !ua.match(/CriOS/i);
                  if(iOSSafari) window.queuedStatCountKeys.add("ios");
                  else window.queuedStatCountKeys.add("nonios");
                } catch(e) {
                  console.error("failed to detect iOS Safari", e);
                }

                if(window.innerWidth < 550) window.queuedStatCountKeys.add("mobile");
                else window.queuedStatCountKeys.add("desktop");

                window.addEventListener("focus", async function() {
                  if(!window.perchanceOutputIframeFinishedFirstLoad) return;
                  if(!gotFirstOutputIframeFocusMessage) return;
                  if(Date.now() - window.lastKnownOutputIframeFocusTime > 2000) return; // only if we know embed recenty had focus

                  await new Promise(r => setTimeout(r, 1));
                  if(Date.now()-lastUserCausedFocusActionTime > 1000) {
                    console.warn(`🚩🚩🚩 top-level frame got focus, but there was no pointerdown/pageshow event to have caused it. ${window.location.hash.startsWith("#disable_focus_fix") ? `𝗳𝗶𝘅 𝘄𝗮𝘀 𝗡𝗢𝗧 𝗮𝗽𝗽𝗹𝗶𝗲𝗱 𝗱𝘂𝗲 𝘁𝗼 #𝗱𝗶𝘀𝗮𝗯𝗹𝗲_𝗳𝗼𝗰𝘂𝘀_𝗳𝗶𝘅` : ""}`);
                    if(!window.queuedStatCountKeys.has("ffix")) {
                      window.queuedStatCountKeys.add("ffix");
                      if(iOSSafari) window.queuedStatCountKeys.add("ffixios");
                      
                      if(window.innerWidth < 550) window.queuedStatCountKeys.add("ffmobile");
                      else window.queuedStatCountKeys.add("ffdesktop");
                    }
                    if(!window.location.hash.startsWith("#disable_focus_fix")) {
                      
                      // EDIT: new 'strongFocusFix' approach doesn't need these lines - iframe can "pull" focus. See above.
                      // const iframe = document.querySelector("#appEl #output iframe");
                      // iframe.focus();
                      // iframe.contentWindow.focus();

                      // leaving this message for debugging even though it's not entirely accurate (see above EDIT):
                      console.warn("🚨🚨🚨🚨🚨 FOCUS FIX: RETURNED FOCUS TO IFRAME 🚨🚨🚨🚨🚨");
                    }
                  }
                });

                if(window.location.href.includes("ad-focus-bug-test")) {
                  setInterval(async () => {
                    window.focus();  
                    console.debug("top hasFocus1", document.hasFocus(), document.activeElement);
                    await new Promise(r => setTimeout(r, 100));
                    console.debug("top hasFocus2", document.hasFocus(), document.activeElement);
                  }, 7000);
                }
              }
              
              // appEl.appendChild(adCtn);

              // CMP (inmobi choice):
              let cmpScript = document.createElement("script");
              cmpScript.src = `https://user-uploads.perchance.org/file/63c85ff7ce3ecc0323e0bbd555078fad.js`;
              document.head.appendChild(cmpScript);
              {
                let waitMs = 0;
                while(!window.cmpScriptHasExecuted) {
                  await new Promise(r => setTimeout(r, 100));
                  waitMs += 100;
                  if(waitMs > 15*1000) break;
                }
              }

              function checkConsent() {
                __tcfapi("getTCData", 2, (tcData, success) => {
                  if(success) {
                    if(tcData.gdprApplies === false) {
                      window.gdprDoesNotApply = true;
                    } else {
                      let a = tcData.purpose.consents[1];
                      let b = tcData.purpose.consents[10];
                      let c = tcData.purpose.legitimateInterests[10];
                      let d = tcData.eventStatus

                      if((!a || !b || !c) & d !== "cmpuishown") {
                        window.__tcfapi("displayConsentUi", 2, function () {});
                      } else {
                        window.userGaveAdConsent = true;
                      }
                    }
                  }
                });
              }
              (async function che1ckTCF() {
                await new Promise(r => setTimeout(r, 100));
                if(window.__tcfapi == undefined) setTimeout(che1ckTCF, 1000);
                else checkConsent();
              })();
              
              if(adProviderName === "freestar") {

                adCtn.innerHTML = `<div class="ad-providers-ctn-el" align="center" data-freestar-ad="__320x100 __970x90" id="perchanceorg_footer"></div>`;
                
                window.freestar = window.freestar || {};
                window.freestar.queue = window.freestar.queue || [];
                window.freestar.config = window.freestar.config || {};
                window.freestar.config.enabled_slots = [];
                window.freestar.initCallback = function () { (window.freestar.config.enabled_slots.length === 0) ? window.freestar.initCallbackCalled = false : window.freestar[`newAdSlots`](window.freestar.config.enabled_slots) }

                let script = document.createElement("script");
                script.dataset.cfasync = "false";
                script.async = true;
                script.src = "https://a.pub.network/perchance-org/pubfig.min.js";
                document.head.appendChild(script);
                
                if(window.location.hash.includes("testAntiAdBlock")) {
                  // anti -ad block:
                  let script = document.createElement("script");
                  script.async = true;
                  script.src = `https://user-uploads.perchance.org/file/01cea1291c0dbb7b775dc89a385d1d4a.js`;
                  document.head.appendChild(script);
                }
                
                window.freestar.config.enabled_slots.push({ placementName: "perchanceorg_footer", slotId: "perchanceorg_footer" });
                
              } else if(adProviderName == `snigel`) {
                
                window.snigelPubConf = {
                  adengine: {
                    sensitiveContent: false
                  },
                };

                // this code is needed to ensure that ad load immediately after accepting cmp 'reconsider'
                window.addEventListener('adnginLoaderReady', function() {
                  adngin.queue.push(function() { adngin.cmd.startAuction(["responsive_banner"]); });
                });
                adCtn.innerHTML = `<div class="ad-providers-ctn-el" id="adngin-responsive_banner-0"></div>`;

                let script = document.createElement("script");
                script.dataset.cfasync = "false";
                script.async = true;
                script.src = `https://cdn.snigelweb.com/adengine/perchance.org/loader.js`;
                document.head.appendChild(script);

                // setTimeout(async () => {
                //   if(await window.adsAreShowing()) return;
                //   let script = document.createElement("script");
                //   script.dataset.cfasync = "false";
                //   script.async = true;
                //   script.nonce = "SEahoBjLmnC565bNlPFeWA";
                //   script.src = "https://fundingchoicesmessages.google.com/i/pub-9885689965057708?ers=1";
                //   document.head.appendChild(script);
                //   (function() {function signalGooglefcPresent() {if (!window.frames['googlefcPresent']) {if (document.body) {const iframe = document.createElement('iframe'); iframe.style = 'width: 0; height: 0; border: none; z-index: -1000; left: -1000px; top: -1000px;'; iframe.style.display = 'none'; iframe.name = 'googlefcPresent'; document.body .appendChild(iframe);} else {setTimeout(signalGooglefcPresent, 0);}}}signalGooglefcPresent();})();
                // }, 30000);
              }

              setTimeout(() => {
                window.b8473892 = true;
                function adIframesExist() {
                  return [...document.querySelectorAll("iframe")].filter(el => el.src).map(el => new URL(el.src).hostname).find(n => n.endsWith(`doubleclick.net`) || n.endsWith("onetag-sys.com") || n.endsWith("openx.net") || n.endsWith(".google.com") || n.endsWith(`amazon-adsystem.com`) || n.endsWith("rubiconproject.com") || n.endsWith("criteo.com") || n.endsWith("3lift.com") || n.endsWith("googlesyndication.com") || n.endsWith("connectad.io"));
                }
                setTimeout(async () => {
                  if(window[`localStorage`]["app-storage"] && window.js0nparse(window[`localStorage`]["app-storage"]).user[`sess${``}ionToken`] || window.sdfh929if738ths) return; // not for logged-in users (already done above - just to defend against future edit mistakes)
                  window.queuedStatCountKeys.add("abt");
                  let aidjr3 = await window.adsAreShowing();
                  if(!aidjr3) {

                    let scri12pts = false;
                    let ifra2mes = false;
                    let coo1kies = false;

                    let clasi = false;
                    try {
                      if(await hasVariables() || await chec3kRes1Load(`https://secure.quantserve.com/quant.js`, "script")) {
                        window.queuedStatCountKeys.add("abprbclas");
                        scri12pts  = true;
                      }
                      if(adIframesExist()) {
                        window.queuedStatCountKeys.add("abprbclasi");
                        clasi = true;
                        ifra2mes = true;
                      }
                    } catch(e) {
                      console.error(e);
                    }

                    if(window.userGaveAdConsent || window.gdprDoesNotApply) {
                      coo1kies = true;
                    }

                    try {
                      if(window.js0nparse(window[`localStorage`].id5id_privacy || "{}").id5_consent === true) {
                        coo1kies = true;
                      }
                    } catch(e) {
                      console.error(e); 
                    }  

                    if(clasi && coo1kies) {
                      window.queuedStatCountKeys.add("abprbclasiadgc");
                    }

                    // if(scri12pts && ifra2mes && coo1kies) {
                    //   return; // maybe auction failed or whatever
                    // }

                    if(!ifra2mes) {
                      await new Promise(r => setTimeout(r, 30*1000));
                      if(adIframesExist()) {
                        ifra2mes = true;
                      }
                    }

                    if(scri12pts && ifra2mes) {
                      return;
                    }

                    window.queuedStatCountKeys.add("abpr");
                    if(window[`localStorage`].abpr === "1") {
                      window.queuedStatCountKeys.add("abpr2");
                    }
                    window[`localStorage`].abpr = ("1");

                    try {
                      if(scri12pts && ifra2mes && !coo1kies) {
                        window[window.modalFn1Name](`Your browser seems to be blocking cookies, which is preventing ads from being shown. You may need to add an exception for 'perchance.org' to your cookie blocker or 'incognito browsing' feature. Sometimes VPN and antivirus software has cookie blocking as a bonus feature.\n\nWhy are ads necessary? Well, Perchance is free and doesn't have ads by default, but the creator of this generator has imported an ad-powered plugin (e.g. the text-to-image plugin). Plugins that use expensive server resources can only exist thanks to ads. This page will auto-refresh in 60 seconds (apologies).`);
                      } else {
                        window[window.modalFn1Name](`Your browser seems to be blocking ads. Perchance is free and generally doesn't have ads, but the creator of this generator has imported an ad-powered plugin (e.g. the text-to-image plugin). Plugins that use expensive server resources can only exist thanks to ads.\n\nPlease help keep it free by turning off your ad blocker. This page will auto-refresh in 60 seconds (apologies).\n\n(NOTE: If ads still aren't loading for you even after turning off your ad blocker, then you may also need to turn off your 'cookie' blocker, and maybe add an exception for perchance.org on the built-in cookie-blocking of your antivirus/incognito/VPN/etc if it has that feature).`);
                      }
                    } catch(e) {

                    } 

                    startWarnProcess();
                  } else {
                    if(window[`localStorage`].abpr === "1") {
                      window.queuedStatCountKeys.add("utoab");
                    }
                  }
                }, 70001);
              }, 50);

              // setTimeout(async () => {
              //   if(!(await window.adsAreShowing())) {
              //     if(adProviderName == `snigel`) adngin.queue.push(function() { adngin.cmd.startAuction(["responsive_banner"]); });
              //   }
              // }, 30000);
              
              // adCtn.innerHTML = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAtgAAABaAQMAAAC4+rO8AAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAANQTFRFXrP/I7IslgAAAB9JREFUeJztwYEAAAAAw6D5U1/gCFUBAAAAAAAAAHwDIFgAAVR0zeEAAAAASUVORK5CYII="/>`;
              
              if(window.innerWidth > 1400) {
                setTimeout(() => {
                  let div = document.createElement("div");
                  div.style.cssText = `position: absolute; right: 4px; top: 4px; font-family: sans-serif; background: #dedede; padding: 0.2rem 0.25rem; border-radius: 3px; cursor: pointer; color: #676767;`;
                  div.onclick = function() { window[window.modalFn1Name]('The creator of this generator has imported an ad-powered plugin (e.g. the text-to-image plugin). Plugins that use expensive server resources are funded via advertisements.'); };
                  div.id = `whyAdsButton1El`;
                  div.innerHTML = `why ads?`;
                  adCtn.appendChild(div);
                }, 2000);
              }
            }

          })();

          (async function() { 
            while(true) {
              try {
                let i = 0;
                while(true) {
                  await new Promise(r => setTimeout(r, 10000));
                  let deps = window.generatorDependenciesData.map(d => d.name);
                  if((window.adCtn && !getCElement(window.adCtn).src?.includes?.("perchance.org")) || window.js0nparse(window.localStorage["app-storage"] || "{}")?.user?.[`sess${``}ionToken`] || window.sdfh929if738ths) {
                    // 1;adngin.cmd.startAuction(["responsive_banner"]);
                    window.queuedStatCountKeys.add("abpsgp");
                    break;
                  }
                  i++;
                  if(i > 10) {
                    break;
                  }
                }
              } catch(e) {
                console.error(e);
              }
              await new Promise(r => setTimeout(r, 20*60*1000));
            }
          })();

          setTimeout(() => {
            `abp|cookie|browser|async|ads|alert|ads`;
            window.e7827462 = true;
          }, 100);
        </script>
        <script>
          function createAdCtn() {
            let adCtn = window[doc34828272947].createElement("div");
            adCtn.id = "adCtn";
            adCtn.style.cssText = `padding:4px 0; min-height:${window.advertHeight}px !important; max-height:${window.advertHeight}px !important; height:${window.advertHeight}px !important; overflow:hidden !important; text-align:center; display:flex; align-items:center; justify-content:center; position:relative;`;
            return adCtn;
          }

          globalThis.hu_8urej4 = true;
          function startWarnProcess() {
            let warnEl = window[doc34828272947].createElement("div");
            let helperNotice = "";
            if(window.innerWidth > 800) helperNotice = `<div><a href="https://user-uploads.perchance.org/file/06b63cbc807acaf79bc25f114bb0dda1.webp" target="_blank">click here</a> if it's still not working or if you don't understand</div>`;
            warnEl.innerHTML += `<div style="max-width:700px; margin:0 auto;"><span style="font-weight:bold; color:#f60000; font-size:80%;">the author of this generator has imported an ad-powered plugin. pls turn off your ad/cookie blocker to keep this free. this page will auto-refresh in 60 seconds 😳</span> ${helperNotice || "try Chrome or Firefox if it's not working."}</div>`;
            if(!window.adCtn) {
              window.adCtn = createAdCtn();
              appEl.appendChild(window.adCtn);
            } else {
              window.adCtn.innerHTML = "";
            }
            window.adCtn.appendChild(warnEl);
            if(window[doc34828272947].querySelector(`#whyAdsButton1El`)) {
              window[doc34828272947].querySelector(`#whyAdsButton1El`).style.display = "none";
            }

            setTimeout(async () => {
              warnEl.remove();
              let aidjr3 = await window.adsAreShowing();
              if(!aidjr3 || !window.e7827462 || !window.b8473892) {
                window[`onbeforeunload`] = undefined;
                if(window.userGaveAdConsent === false && window.gdprDoesNotApply === false) {
                  localStorage.clear();
                }
                if(Number(localStorage.adPageReloadCount || 0) < 4) {
                  localStorage.adPageReloadCount = Number(localStorage.adPageReloadCount || 0)+1;
                  localStorage.lastAdPageReloadTime = Date.now();
                  window[`location`][rlFn1Name]();
                }
              }
            }, 60001);
          }
        </script>
        <script>
          {
            async function handler() {
              window.u8398201 = true;
              if(!window.e7827462 || !window.b8473892) {
                let deps = window.generatorDependenciesData.map(d => d.name);
                if(!deps.includes("ai-text-to-image-plugin") && !deps.includes("ai-text-plugin")) return;
                if(window[`localStorage`]["app-storage"] && window[`localStorage`]["app-storage"].includes("sessionToken") && window.js0nparse(window[`localStorage`]["app-storage"]).user[`sess${``}ionToken`] || window.sdfh929if738ths) return;
                if(window.forceDisableAds) return;

                startWarnProcess();

                await new Promise(r => setTimeout(r, 1000*40));
                if(!window.adCtn || getCElement(window.adCtn).src?.includes?.("perchance.org")) {
                  let ms1g = "AI-powered generators on Perchance are entirely funded by ads. Please disable your ad blocker and reload the page. This page will auto-reload in 60 seconds." .replace(/_/g, "");
                  try { alert(ms1g); } catch(e) { window[doc34828272947].body.innerHTML = ms1g; };
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     window    [false ? '' : `z8473927`] = true;
                  setTimeout(() => {
                    window[`onbeforeunload`] = undefined;
                    if(Number(localStorage.adPageReloadCount || 0) < 4) {
                      localStorage.adPageReloadCount = Number(localStorage.adPageReloadCount || 0)+1;
                      localStorage.lastAdPageReloadTime = Date.now();
                      if(Number(localStorage.adPageReloadCount || 0) < 4) {
                        localStorage.adPageReloadCount = Number(localStorage.adPageReloadCount || 0)+1;
                        localStorage.lastAdPageReloadTime = Date.now();
                        window[`location`][rlFn1Name]();
                      }
                    }
                  }, 60001);
                }
              }
            }
            setTimeout(handler, 30001);
          }
          function getCElement(el) {
            const rect = el.getBoundingClientRect();
            return document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
          }
        </script>
        <script>
          let cachedAccessCodeForAdPoweredStuff = null;
          setInterval(() => {
            cachedAccessCodeForAdPoweredStuff = null;
          }, 10*60*1000);

          window.addEventListener("message", async function(e) {
            let origin = e.origin || e.originalEvent.origin
            if(origin !== "https://text-generation.perchance.org" && origin !== `https://image-generation.perchance.org`) {
              return;
            }
            
            if(e.data.type == `plsGibAccessCodeForAdPoweredStuff`) {
              let code;
              if(cachedAccessCodeForAdPoweredStuff) {
                code = cachedAccessCodeForAdPoweredStuff;
              } else {
                code = await fetch(`/api/getAccessCodeForAdPoweredStuff?__cacheBust=${Math.round(Date.now()/(1000*60*10))}`).then(r => r.text());
                cachedAccessCodeForAdPoweredStuff = code;
              }

              let deps = window.generatorDependenciesData.map(d => d.name);
              if(!deps.includes("ai-text-to-image-plugin") && !deps.includes("ai-text-plugin")) {
                e.source.postMessage({type:"okayYouMayHaveCodeForAdPoweredStuff♡", code}, origin); 
                return;
              }
              if(window.adCtn && await window.adsAreShowing() && window.adCtn && !getCElement(window.adCtn).src?.includes?.("perchance.org")) {
                e.source.postMessage({type:"okayYouMayHaveCodeForAdPoweredStuff♡", code}, origin); 
                return;
              }
              if((window[`localStorage`]["app-storage"] && window[`localStorage`]["app-storage"].includes("sessionToken") && window.js0nparse(window[`localStorage`]["app-storage"]).user[`sess${``}ionToken`]) || window.sdfh929if738ths || window.forceDisableAds) {
                e.source.postMessage({type:"okayYouMayHaveCodeForAdPoweredStuff♡", code}, origin); 
                return;
              }
            }
          });
        </script>


        <style>
          .qc-cmp2-persistent-link {
            transform: scale(0.5);
            transform-origin: bottom right 60px;
          }
        </style>
        <script>
          (async function() {
            // Ensures that ads can't be displayed outside of their designated area, no matter what.

            if(window.location.hash.toLowerCase().includes("disable_misplaced_ad_removal")) return;

            while(!window.perchanceOutputIframeFinishedFirstLoad) await new Promise(r => setTimeout(r, 1000));

            if(!window.pageWillDisplayAds) await new Promise(r => setTimeout(r, 1000));
            if(!window.pageWillDisplayAds) await new Promise(r => setTimeout(r, 3000));
            if(!window.pageWillDisplayAds) await new Promise(r => setTimeout(r, 9000));
            if(!window.pageWillDisplayAds) await new Promise(r => setTimeout(r, 30000));
            if(!window.pageWillDisplayAds) return; 

            while(!window.adCtn) await new Promise(r => setTimeout(r, 1000));

            setInterval(() => {
              let el = document.querySelector("#ogy-ad-slot");
              if(el && !window.adCtn.contains(el)) el.remove();
            }, 2000);


            {
              let attempts = 0;
              let cmpButtonCheckInterval = setInterval(() => {
                if(window.adCtn.offsetHeight < 10) {
                  document.querySelector(".qc-cmp2-container").style.cssText = "pointer-events:none; opacity:0;";
                  clearInterval(cmpButtonCheckInterval);
                }
                attempts++;
                if(attempts > 30) clearInterval(cmpButtonCheckInterval);
              }, 1000);
            }

            {
              setInterval(() => {
                // delete long cookies if over ~4kb
                if(document.cookie.length > 3900) {
                  let cookies = document.cookie.split(';').map(c => ({ name: c.split('=')[0].trim(), size: c.length }));
                  cookies.sort((a, b) => b.size - a.size);
                  for (let {name} of cookies) {
                    ['/', '/subdomain', ''].forEach(path => document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=${path};domain=${window.location.hostname}`);
                    if(document.cookie.length <= 3900) break;
                  }
                }
              }, 5*1000);
            }


            {
              // Ensure adCtn style can't be changed:
              let lastStyleChangeTime = 0;
              const originalStyle = window.adCtn.getAttribute('style');
              const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                  if(mutation.type === 'attributes' && mutation.attributeName === 'style') {
                    if(window.adCtn.getAttribute('style') !== originalStyle) {
                      if(Date.now()-lastStyleChangeTime > 1000) { // prevent possible infinite loops (setInterval below is a backup)
                        window.adCtn.setAttribute('style', originalStyle);
                        lastStyleChangeTime = Date.now();
                      }
                    }
                  }
                });
              });
              const config = { attributes:true, attributeFilter:['style'] };
              observer.observe(window.adCtn, config);
              setInterval(() => {
                if(window.adCtn.getAttribute('style') !== originalStyle) {
                  window.adCtn.setAttribute('style', originalStyle);
                }
              }, 2000);
            }

            let deletionsInLastFewSeconds = 0;
            setInterval(() => {
              deletionsInLastFewSeconds = 0;
            }, 3000);
            function deleteMisplacedAdElements() {
              if(deletionsInLastFewSeconds > 100) {
                window.queuedStatCountKeys.add("misplaced-ad-loop");
                return; // in case of infinite loop that would freeze the page (e.g. "fighting" with a modal that self-heals or something weird like that)
              }
              let points = getElementKeyPointsInset(document.querySelector("#outputIframeEl"), {insetFactor:0.2});
              points.push(...getElementKeyPointsInset(document.querySelector("#outputIframeEl"), {insetFactor:0.03}));
              let appEl = document.querySelector("#appEl"); 
              for(let {x, y} of points) {
                let elements = document.elementsFromPoint(x, y);
                for(let el of elements) {
                  if(el === document.body || el === document.documentElement) continue;
                  if(!document.body.contains(el)) continue; // in case it was deleted by a previous iteration of this current loop
                  if(appEl.contains(el)) continue;
                  if(el.nodeName !== "IFRAME" || !el.src.includes(".perchance.org")) {
                    let ancestor = el;
                    while(ancestor.parentElement !== document.body) ancestor = ancestor.parentElement;
                    if(appEl.contains(ancestor)) {
                      console.error("Tried to remove a child of appEl?");
                      continue; 
                    }
                    const className = ancestor.className || "";
                    const id = ancestor.id || "";
                    if(className.startsWith("cmp") || className.includes("-cmp") || className.includes("cmp2") || id.includes("cmp")) { // gdpr consent modal
                      continue;
                    }
                    if(id.includes("confiant")) { // ad report button
                      continue;
                    }
                    if(className.includes("created-captcha-widget-ctn")) {
                      continue;
                    }
                    ancestor.remove();
                    deletionsInLastFewSeconds++;
                    console.warn("🧹🧹🧹 Deleted misplaced element ancestor:", {el, ancestor});
                    window.queuedStatCountKeys.add("misplaced-ad");
                  }
                }
              } 
            }

            function insetPointTowardCenter(x, y, centerX, centerY, insetFactor) {
              return { x: x + (centerX - x) * insetFactor, y: y + (centerY - y) * insetFactor };
            }
            function getElementKeyPointsInset(element, opts={}) {
              const rect = element.getBoundingClientRect();
              const centerX = rect.left + rect.width / 2;
              const centerY = rect.top + rect.height / 2;
              const insetFactor = opts.insetFactor ?? 0.2; // default to 20% inset

              const topLeft = insetPointTowardCenter(rect.left, rect.top, centerX, centerY, insetFactor);
              const topRight = insetPointTowardCenter(rect.right, rect.top, centerX, centerY, insetFactor);
              const bottomRight = insetPointTowardCenter(rect.right, rect.bottom, centerX, centerY, insetFactor);
              const bottomLeft = insetPointTowardCenter(rect.left, rect.bottom, centerX, centerY, insetFactor);

              return [ topLeft, topRight, bottomRight, bottomLeft, { x: centerX, y: centerY }];
            }

            const observer = new MutationObserver(function(mutationsList, observer) {
              for(let mutation of mutationsList) {
                if(mutation.type === 'childList') {
                  mutation.addedNodes.forEach(node => {
                    if(node.nodeType === Node.ELEMENT_NODE) {
                      // console.debug('Checking new potential ad element for misplacement:', node);
                      deleteMisplacedAdElements();
                      setTimeout(deleteMisplacedAdElements, 1000);
                      setTimeout(deleteMisplacedAdElements, 3000);
                      setTimeout(deleteMisplacedAdElements, 6000);
                    }
                  });
                }
              }
            });
            observer.observe(document.body, { childList: true, subtree: true });
          })();
        </script>

        <style>
          /* .ad-providers-ctn-el .__fs-ancillary {
            display: none !important;
          } */
        </style>

        <script>
          (async function() {
            if((window[`localStorage`]["app-storage"] && window[`localStorage`]["app-storage"].includes("sessionToken") && window.js0nparse(window[`localStorage`]["app-storage"]).user[`sess${``}ionToken`]) || window.sdfh929if738ths) return; // not for logged-in users
            if(window.forceDisableAds) return;

            window.userGaveAdConsent = null;
            window.gdprDoesNotApply = null;
            let i = 0;
            while(!window.__tcfapi) {
              await new Promise(r => setTimeout(r, 1000));
              i++;
              if(i > 20) return;
            }

            window.__tcfapi('addEventListener', 2, function(tcData, success) {
              if(success && (tcData.eventStatus === 'tcloaded' || tcData.eventStatus === 'useractioncomplete')) {
                if(tcData.gdprApplies) {
                  __tcfapi('getVendorList', 2, function(gvl, success) {
                    if(success) {
                      if(Object.values(tcData.vendor.consents).filter(v => v).length > Object.keys(gvl.vendors).length/2 && Object.values(tcData.purpose.consents).filter(v => v).length === Object.keys(gvl.purposes).length) {
                        window.userGaveAdConsent = true;
                      } else if(Object.values(tcData.vendor.consents).filter(v => v).length == 0 && Object.values(tcData.purpose.consents).filter(v => v).length === 0) {
                        window.userGaveAdConsent = false; // reject
                      } else {
                        window.userGaveAdConsent = false; // partial
                      }
                    }
                  });
                } else {
                  window.gdprDoesNotApply = true;
                }
              } else {
                console.debug("User consent not available yet", tcData);
                if(tcData.gdprApplies === true) {
                  window.gdprDoesNotApply = false;
                }
                if(tcData.eventStatus === 'cmpuishown') {
                  window.gdprDoesNotApply = false;
                }
              }
            });
          })();
        </script>

        <style>
          @media (prefers-color-scheme: dark) {
            #whyAdsButton1El {
              background-color: #333537 !important;
              color: #a79f94 !important;
            }
          }
        </style>

        <script>
          setTimeout(function() {
            // Make the screen "cleaner" for the screenshot bot:
            if(navigator.webdriver) {
              document.querySelector("#menuBarEl").style.display = "none";
              // document.querySelector("#editorEl #main").style.top = "8px";
            }
          }, 10);
        </script>
        
        <script>
          window.addEventListener('pageshow', (event) => {
            if (event.persisted) {
              // bfcache doesn't persist edits in the text editor for some reason (doesn't store JS state?), so we need to reload:
              // window.location.reload(); // edit: for some reason this doesn't seem to be needed anymore - seems to be persisting properly? Maybe due to adding this event handler???
              // console.debug('@@@ This page was restored from the bfcache.');
            } else {
              // console.debug('@@@ This page was loaded normally.');
            }
          });
        </script>

        <script>
          (async function() {
            let checkCount = 0;
            let interval;
            interval = setInterval(() => {
              let a = `s(uc)[],ce,s[s,f(u,lP,a,g,e],Lo),[ad`.replace(/[ ,\]()\[]/g, "");
              let plsp = `in i(ti al,Pa[g eLo adSpi n)ne, r`.replace(/[ ,\]()\[]/g, "");
              if(window.remoteResourcesLoaded && !window[a]) {
                let div = document.createElement("div");
                let isAdPoweredPage = false;
                div.innerHTML = `<p>TL;DR: <b>Try turning off your ad blocker</b>.</p>

                <p>If you see this message, this page failed to load properly. One potential cause is that (as of writing) some ad blockers break <a href="https://github.com/uBlockOrigin/uAssets/blob/9effb98d0ab3be8bc320909144758a326e575ad8/filters/quick-fixes.txt#L160" target="_blank" data-ref="nofollow">basic</a><sup>1</sup> functionality of Perchance pages. This <b>includes pages that don't have any ads</b> - i.e. even "normal" (non-AI-powered) generators.</p>

                <p>Try turning off your browser's ad blocker for this page, and if that doesn't work then please report this problem at <a href="https://lemmy.world/c/perchance" target="_blank">lemmy.world/c/perchance</a>, since there may be some other cause.</p>

                <p style="opacity:0.55;">Note: Perchance only has ads on generators which require GPU resources - a tiny fraction of all pages on Perchance. Perchance has always been <u>completely</u> free, and I've been paying for server resources out of my own pocket since I built Perchance in 2017, but I can't do that for the newly-added AI plugins because they require many GPU servers and they're way too expensive. As of writing (Jan 20th 2023) ads still aren't enough to cover the GPU costs, but they help a lot.</p>

                <p style="opacity:0.55;"><sup>1 </sup><span style="font-size:85%;">The linked code makes your ad blocker extension override some code on this page such that when I (or Perchance generator authors) want to check if some text contains a word (a very basic/common programming operation), it'll always say that the text <i>does</i> contain the word, even when it doesn't. That makes it hard to write code that works correctly, and to make changes to existing code without breaking things.</span></p>`;
                div.style.cssText = "padding:1rem; font-size:120%; z-index:100000000;";
                try { document.querySelector("#" + plsp).remove(); } catch(e) {}
                document.body.appendChild(div);

                clearInterval(interval);
              }
              checkCount++;
              if(checkCount > 20) clearInterval(interval);
            }, 1000*2);
          })();
        </script>

        <script>
          setInterval(() => { 
            if(performance.memory && performance.memory.usedJSHeapSize > 0.8*performance.memory.jsHeapSizeLimit) {
              window.queuedStatCountKeys.add("emem");
            }
            if(document.querySelectorAll("iframe").length > 100) {
              window.queuedStatCountKeys.add("eemb");
              document.querySelectorAll("iframe").forEach(el => {
                let isPerchanceUrl = (el.src||"").split("?")[0].includes("perchance");
                if(!isPerchanceUrl && !document.querySelector("#appEl").contains(el)) {
                  console.warn("❗❗❗ REMOVED EXCESSIVE IFRAMES");
                  el.remove();
                }
              });
            }
          }, 1000*60);
        </script>

        <script>
          setInterval(() => {
            if(window.queuedStatCountKeys.size > 0) {
              window[window.ftcFn1Name](`/api/count?keys=${[...window.queuedStatCountKeys].join(",")}`);
              window.queuedStatCountKeys = new Set();
            }
          }, 1000*20);
        </script>
        
        
        <!-- use invisible `touch-action:none` divs to prevent accidental "drag down to refresh" behavior when scrolling up iframe (dragging finger down) but finger lands on the edge (outside frame) -->
        <!-- <div style="width: 19px;height: 100%;position: fixed;right: -10px;top: 35px;bottom: 0px;/* background: blue; */touch-action: none; z-index:9999999;"></div> -->
        <!-- <div style="width: 19px;height: 100%;position: fixed;left: -10px;top: 35px;bottom: 0px;/* background: blue; */touch-action: none; z-index:9999999;"></div> -->

        
          <script>
            setTimeout(async () => {
              if(window.thisUserOwnsThisGenerator) {
                let tmp = document.createElement("div");
                tmp.innerHTML = '<a href="https://user-uploads.perchance.org/file/c09dca9aafed0b46e7f03f3a8cfe80d7.png" target="_blank" style="position: fixed;left: 0.75rem;bottom: 0.75rem;background: rgb(255, 122, 122);padding: 0.25rem 0.5rem;border-radius: 3px;font-weight: bold;cursor: pointer;color:black;text-decoration:none;">heads up (click here)</a>';
                document.body.appendChild(tmp.firstChild);
              }
            }, 7*1000);
          </script>
        <div style="display:none;">
              <a href="/ai-chat" target="_blank" style="position:absolute;top:-200px;">AI Roleplay Chat / Chatbot</a>
              <a href="/ai-story-generator" target="_blank" style="position:absolute;top:-200px;">AI Story Writer</a>
              <a href="/ai-text-to-image-generator" target="_blank" style="position:absolute;top:-200px;">AI Image Generator</a>
              <a href="/ai-human-generator" target="_blank" style="position:absolute;top:-200px;">AI Human Generator</a>
              <a href="/ai-photo-generator" target="_blank" style="position:absolute;top:-200px;">AI Photo Generator</a>
              <a href="/ai-character-description" target="_blank" style="position:absolute;top:-200px;">AI Character Description Generator</a>
              <a href="/ai-text-generator" target="_blank" style="position:absolute;top:-200px;">AI Text Generator</a>
              <a href="/ai-poem-generator" target="_blank" style="position:absolute;top:-200px;">AI Poem Generator</a>
              <a href="/ai-lyrics-generator" target="_blank" style="position:absolute;top:-200px;">AI Lyrics Generator</a>
              <a href="/ai-fanfic-generator" target="_blank" style="position:absolute;top:-200px;">AI Fanfic Generator</a>
              <a href="/ai-character-chat" target="_blank" style="position:absolute;top:-200px;">Perchance AI Chat</a>
              <a href="/ai-story-outline" target="_blank" style="position:absolute;top:-200px;">AI Story Outline/Plot Generator</a>
              <a href="/ai-text-rewriter" target="_blank" style="position:absolute;top:-200px;">AI Text Rewriter</a>
              <a href="/ai-code-generator" target="_blank" style="position:absolute;top:-200px;">AI Code Generator</a>
              <a href="/ai-group-chat" target="_blank" style="position:absolute;top:-200px;">AI Group Chat</a>
              <a href="/ai-insult-generator" target="_blank" style="position:absolute;top:-200px;">AI Insult Generator</a>
              <a href="/ai-rap-lyrics-generator" target="_blank" style="position:absolute;top:-200px;">AI Rap Lyrics Generator</a>
              <a href="/ai-title-generator?type=chapter" target="_blank" style="position:absolute;top:-200px;">AI Chapter Name Generator</a>
              <a href="/ai-title-generator?type=funny-light-novel" target="_blank" style="position:absolute;top:-200px;">Silly Light Novel Title Generator</a>
              <a href="/ai-title-generator?type=caption" target="_blank" style="position:absolute;top:-200px;">AI Caption Generator Using Keywords</a>
              <a href="/ai-title-generator?type=book" target="_blank" style="position:absolute;top:-200px;">AI Book Title Generator Using Keywords</a>
              <a href="/ai-title-generator?type=sad-book" target="_blank" style="position:absolute;top:-200px;">AI Sad Book Title Generator</a>
              <a href="/ai-script-generator" target="_blank" style="position:absolute;top:-200px;">AI Script Generator</a>
              <a href="/ai-plot-generator" target="_blank" style="position:absolute;top:-200px;">AI Plot Generator</a>
            </div>

    <script defer="" src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon="{&quot;rayId&quot;:&quot;8f63bcb13977384e&quot;,&quot;version&quot;:&quot;2024.10.5&quot;,&quot;serverTiming&quot;:{&quot;name&quot;:{&quot;cfExtPri&quot;:true,&quot;cfL4&quot;:true,&quot;cfSpeedBrain&quot;:true,&quot;cfCacheStatus&quot;:true}},&quot;token&quot;:&quot;fc685cb0ca0145b3acbca350b7d29943&quot;,&quot;b&quot;:1}" crossorigin="anonymous"></script>


</body></html>