Advertisement
Degritone

BBS DHR Chatroom

Dec 12th, 2021
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name             BBS DHR Chatroom
  3. // @namespace        dollars-bbs.org
  4. // @author           Degritone
  5. // @description      Adds back in limited functionality for the chatroom for the Dollars BBS
  6. // @match            *://*.dollars-bbs.org/*
  7. // @match            *://qchat.rizon.net/
  8. // @grant            GM.setValue
  9. // @grant            GM.getValue
  10. // @grant            GM.deleteValue
  11. // ==/UserScript==
  12.  
  13. function request(url){
  14.   let xmlHttp = new XMLHttpRequest();
  15.   xmlHttp.open("GET",url,false);
  16.   xmlHttp.send(null);
  17.   return xmlHttp.responseText;
  18. }
  19.  
  20. let prefixes = /^\+?%?@?&?~?/;
  21. let icons = [];
  22. let iconColors = [];
  23.  
  24. if(window.location.href.startsWith("https://dollars-bbs.org/chatroom")){
  25.   document.title = "Dollars BBS | Chatroom";
  26.   //window.location.href = "https://qchat.rizon.net";
  27.   let ip = request("https://api.ipify.org/");
  28.   console.log(ip);
  29.   let dhrip = request("https://dhr.ddns.net/ip");
  30.   console.log(dhrip);
  31.   let frameSrc = ip==dhrip?"https://localhost":"https://dhr.ddns.net";
  32.   let iframe = document.createElement("iframe");
  33.   iframe.src = frameSrc;
  34.   iframe.style.width = "100%";
  35.   iframe.style.height = "100%";
  36.   iframe.style.border = "none";
  37.   iframe.style.margin = "0px";
  38.   iframe.style.position = "fixed";
  39.   iframe.style.top = "0px";
  40.   iframe.style.left = "0px";
  41.   document.body.innerHTML = "";
  42.   document.body.appendChild(iframe);
  43. } if(window.location.href.startsWith("https://dollars-bbs.org")){
  44.   chatLink();
  45. } else if(window.location.href == "https://qchat.rizon.net/"){
  46.   document.title = "Dollars BBS | Chatroom";
  47.   checkForLoaded();
  48.   loadIcon(0);
  49.   iconReloadButton();
  50. }
  51.  
  52. async function f(readerResult,i){
  53.   if(!readerResult)
  54.     return;
  55.   if(readerResult.length<"data:1".length)
  56.     return;
  57.   await GM.setValue("bbsChatroomIcon."+i,readerResult);
  58.   loadIcon(i,false);
  59. }
  60.  
  61. async function requestb64(url,i){
  62.   let xmlHttp = new XMLHttpRequest();
  63.   xmlHttp.open("GET",url,true);
  64.   xmlHttp.responseType = "blob";
  65.   xmlHttp.onload = function () {
  66.     let reader = new FileReader();
  67.     reader.onloadend = function () {
  68.       f(reader.result,i);
  69.     }
  70.     reader.readAsDataURL(xmlHttp.response);
  71.   };
  72.   xmlHttp.send(null);
  73. }
  74.  
  75. let aoonline;
  76.  
  77. async function getAOOnline(){
  78.   let xmlHttp = new XMLHttpRequest();
  79.   xmlHttp.open("GET","https://api.allorigins.win/raw?url=https://google.com/",false);
  80.   let t;
  81.   try{
  82.     t = setTimeout(xmlHttp.abort,10000);
  83.     xmlHttp.send(null);
  84.   }catch(e){
  85.     if(t)
  86.       clearTimeout(t);
  87.     return false;
  88.   }
  89.   if(t)
  90.     clearTimeout(t);
  91.   return xmlHttp.status==200;
  92. }
  93.  
  94. function iconReloadButton(){
  95.   let reloadButton = document.createElement("div");
  96.   reloadButton.onclick = ()=>{icons = [];loadIcon(0,true);};
  97.   reloadButton.style.position = "fixed";
  98.   reloadButton.style.right = "20px";
  99.   reloadButton.style.top = "0px";
  100.   reloadButton.style.border = "2px #000000 solid";
  101.   reloadButton.style.borderRadius = "10px";
  102.   reloadButton.style.fontSize = "18px";
  103.   reloadButton.style.background = "#EEEEEE";
  104.   reloadButton.style.lineHeight = "26px";
  105.   reloadButton.style.paddingLeft = "3px";
  106.   reloadButton.style.paddingRight = "3px";
  107.   reloadButton.innerHTML = "Refresh Icons";
  108.   reloadButton.title = "This may take multiple minutes";
  109.   document.body.appendChild(reloadButton);
  110. }
  111.  
  112. async function loadIcon(i,skipGM=false){
  113.   let icon = document.createElement("img");
  114.   icon.style.width = "58px";
  115.   icon.style.margin = "auto";
  116.   icon.width = 58;
  117.   icon.height = 58;
  118.   icon.setAttribute("class","drrrIcon");
  119.   let image = "https://ia601408.us.archive.org/13/items/drrr-like-chat-icons/"+i+".png";
  120.   let colorless = false;
  121.   let gmv = await GM.getValue("bbsChatroomIcon."+i);
  122.   if(!gmv || skipGM)
  123.     aoonline = await getAOOnline();
  124.   if(gmv){
  125.     if(gmv.length<"data:1".length || skipGM){
  126.       await GM.deleteValue("bbsChatroomIcon."+i);
  127.       loadIcon(i);
  128.       return;
  129.     }
  130.     image = gmv;
  131.   }else if(aoonline){
  132.     let allorigins = "https://api.allorigins.win/raw?url=";
  133.     image = allorigins+image;
  134.     requestb64(image,i);
  135.     return;
  136.   }else{
  137.     colorless = true;
  138.     icon.crossOrigin = null;
  139.   }
  140.   icon.src = image;
  141.   icon.onload = function(){
  142.     getIconColors(icon,i,colorless);
  143.     loadIcon(i+1,skipGM);
  144.     icons[i] = icon;
  145.     iconLoader();
  146.     let colless = document.createAttribute("colorless");
  147.     colless.value = colorless;
  148.     icon.setAttributeNode(colless);
  149.   };
  150. }
  151.  
  152. function getIconColors(icon,i,colorless){
  153.   if(colorless){
  154.     iconColors[i] = [63,63,63,1];
  155.     return;
  156.   }
  157.   let canvas = document.createElement("canvas");
  158.   canvas.width = 58;
  159.   canvas.height = 58;
  160.   let context = canvas.getContext("2d");
  161.  
  162.   context.drawImage(icon,0,0,58,58);
  163.   iconColors[i] = [];
  164.   let imageData = context.getImageData(0,0,58,58).data;
  165.   iconColors[i][0] = imageData[58*6*4+48*4];
  166.   iconColors[i][1] = imageData[58*6*4+48*4+1];
  167.   iconColors[i][2] = imageData[58*6*4+48*4+2];
  168.   if(iconColors[i][0]<63 && iconColors[i][1]<63 && iconColors[i][2]<63){
  169.     iconColors[i][0] = 63;
  170.     iconColors[i][1] = 63;
  171.     iconColors[i][2] = 63;
  172.   }
  173.   iconColors[i][3] = 1;
  174. }
  175.  
  176. function chatLink(){
  177.   let menu = document.getElementById("pagemenu");
  178.   if(!menu){
  179.     setTimeout(chatLink,100);
  180.     return;
  181.   }
  182.   let chatroom = document.createElement("li");
  183.   chatroom.innerHTML = "<a href='https://dollars-bbs.org/chatroom'>Chatroom</a>";
  184.   menu.children[2].children[0].innerHTML = "Other Chats";
  185.   menu.insertBefore(chatroom,menu.children[2]);
  186.   let sidebar = document.getElementById("sidebar");
  187.   let a = sidebar.getElementsByTagName("a");
  188.   a = a[2%a.length];
  189.   a.href = "https://qchat.rizon.net";
  190. }
  191.  
  192. function checkForLoaded(){
  193.   let loaded = document.getElementsByClassName("tr2").length;
  194.   if(!loaded)
  195.     setTimeout(checkForLoaded,100);
  196.   else
  197.     setTimeout(login,100);
  198. }
  199.  
  200. function login(){
  201.   document.title = "Dollars BBS | Chatroom";
  202.  
  203.   let topNode = document.getElementsByClassName("dynamicpanel qwebirc-qui topboundpanel outertabbar outertabbar_top")[0];
  204.   topNode.style.display = "none";
  205.  
  206.   let favicon = document.createElement("link");
  207.   favicon.href = "https://dollars-bbs.org/random/favicon.ico";
  208.   favicon.rel = "shortcut icon";
  209.   document.head.appendChild(favicon);
  210.  
  211.   let bg = document.getElementsByClassName("dynamicpanel qwebirc-qui middleboundpanel lines")[0];
  212.   bg.style.background = "#000000";
  213.   bg.style.color = "#DDDDDD";
  214.   bg.style.top = "0px";
  215.   bg.style.bottom = "0px";
  216.   bg.style.left = "0px";
  217.   bg.style.right = "0px";
  218.   bg.style.height = "";
  219.  
  220.   let form = document.getElementsByTagName("table")[1];
  221.   form.style.top = "0px";
  222.   form.style.left = "50%";
  223.   form.style.transform = "translateX(-50%)";
  224.   form.style.position = "absolute";
  225.   form.children[0].removeChild(form.children[0].children[0]);
  226.  
  227.   let startButton = document.getElementsByTagName("input");
  228.   for(let i=0;i<startButton.length;i++){
  229.     if(startButton[i].value == "Connect"){
  230.       startButton = startButton[i];
  231.       break;
  232.     }
  233.   }
  234.   startButton.style.width = "148px";
  235.  
  236.   startButton.onclick = ()=>{waitForChat(false,document.getElementsByTagName("input")[0].value);};
  237.  
  238.   inputs();
  239.   tipsBox();
  240. }
  241.  
  242. function iconLoader(){
  243.   let name = document.getElementsByTagName("input")[0];
  244.   let bg = document.getElementsByClassName("dynamicpanel qwebirc-qui middleboundpanel lines")[0];
  245.   let iconHolder = document.getElementById("iconHolder");
  246.   if(!iconHolder){
  247.     iconHolder = document.createElement("div");
  248.     bg.appendChild(iconHolder);
  249.     iconHolder.id = "iconHolder";
  250.     iconHolder.style.width = (13*60)+"px";
  251.     iconHolder.style.position = "absolute";
  252.     iconHolder.style.top = "112px";
  253.     iconHolder.style.bottom = "0px";
  254.     iconHolder.style.left = "50%";
  255.     iconHolder.style.transform = "translateX(-50%)";
  256.     iconHolder.style.display = "flex";
  257.     iconHolder.style.flexWrap = "wrap";
  258.     iconHolder.style.flexDirection = "row";
  259.     iconHolder.style.justifyContent = "center";
  260.     iconHolder.style.overflowY = "scroll";
  261.   }
  262.   let start = 0;
  263.   if(name.value.match(/^\[[0-9]+\]/))
  264.     start = parseInt(name.value.replace("[","").replace(/\].+/,""));
  265.   for(let i=iconHolder.children.length;i<icons.length;i++){
  266.     let selection = document.createElement("div");
  267.     selection.style.width = "60px";
  268.     selection.style.height = "75px";
  269.     selection.style.display = "inline-block";
  270.     selection.style.position = "relative";
  271.     selection.style.margin = "0px";
  272.     selection.style.alignSelf = "center";
  273.  
  274.     let radio = document.createElement("input");
  275.     radio.type = "radio";
  276.     radio.id = "icon"+i;
  277.     radio.name = "icon";
  278.     radio.value = i;
  279.     radio.style.left = "23px";
  280.     radio.style.bottom = "2px";
  281.     radio.style.position = "absolute";
  282.     radio.style.margin = "0px";
  283.     if(i==start)
  284.       radio.checked = "checked";
  285.  
  286.     let label = document.createElement("label");
  287.     label.htmlFor = "icon"+i;
  288.  
  289.     label.appendChild(icons[i].cloneNode());
  290.     selection.appendChild(label);
  291.     selection.appendChild(radio);
  292.     selection.onclick = ()=>{adjustName();};
  293.  
  294.     iconHolder.appendChild(selection);
  295.   }
  296.   inputs();
  297. }
  298.  
  299. function inputs(){
  300.   let nameInput = document.getElementsByTagName("input")[0];
  301.   if(nameInput.value == ""){
  302.     let cookies = document.cookie.split(";");
  303.     for(let i=0;i<cookies.length;i++){
  304.       let pair = cookies[i].split("=");
  305.       if(pair[0] == " name" && nameInput.value == "")
  306.         nameInput.value = pair[1];
  307.     }
  308.   }
  309.  
  310.   if(!document.getElementById("typingName")){
  311.     let name = document.createElement("input");
  312.     name.autocomplete = "off";
  313.     name.autocorrect = "off";
  314.     name.autocapitalize = "off";
  315.     name.spellcheck = false;
  316.     name.style = window.getComputedStyle(nameInput);
  317.     name.id = "typingName";
  318.     name.value = nameInput.value.replace(/\[[0-9]+\]/,"");
  319.     name.oninput = ()=>adjustName();
  320.     nameInput.parentNode.appendChild(name);
  321.  
  322.     let channelInput = document.getElementsByTagName("input")[2];
  323.     channelInput.value = "#dollars-bbs";
  324.     channelInput.parentNode.parentNode.style.display = "none";
  325.   }
  326.   nameInput.style.display = "none";
  327.  
  328.   let iconHolder = document.getElementById("iconHolder");
  329.   if(iconHolder){
  330.     let w = Math.ceil(icons.length/Math.floor((window.innerHeight-parseInt(iconHolder.style.top.replace("px","")))/75))*60;
  331.     iconHolder.style.width = Math.min(w,window.innerWidth)+"px";
  332.   }
  333. }
  334.  
  335. function tipsBox(){
  336.   let tips = document.createElement("div");
  337.   tips.style.width = "250px";
  338.   tips.style.height = "100px";
  339.   tips.style.position = "fixed";
  340.   tips.style.left = "200px";
  341.   tips.style.top = "5px";
  342.   tips.style.backgroundColor = "#EEEEEE";
  343.   tips.style.border = "2px solid #FFFFFF";
  344.   tips.style.borderRadius = "10px";
  345.   tips.style.textAlign = "center";
  346.   tips.id = "tipsBox";
  347.   tips.innerHTML = "Click this box to get cycling tips on things you can do with the script!";
  348.   document.body.appendChild(tips);
  349.   let tip = [];
  350.   tip[0] = "You can type %@ to begin formatting text. %@&lt;0-15> is colored text. Other valid formatting characters are I, M, B, S, U, K, R.";
  351.   tip[1] = "You can press CTRL and a valid formatting character to type that character in 2 less button presses.";
  352.   tip[2] = "You can use %@&lt;0-15>,&lt;0-15> to color both the text and its background or just %@,&lt;number> to color just the background.";
  353.   tip[3] = "You can end already set formatting from your message with %@R.";
  354.   tip[4] = "You can change your name with /nick. This also allows you to change your icon by changing your name to [&lt;0-15>]<name>.";
  355.   tip[5] = "You can PM people by pressing either the circular button right of the textbox or using /query &lt;name>.";
  356.   tip[6] = "You can add someone's name to the textbox by clicking their name.";
  357.   tip[7] = "Don't do /help.";
  358.   tip[8] = "If you ever get lost, you can return to a known channel with the channel picker in the top right.";
  359.   tip[9] = "You can join other channels by doing /join #&lt;channel>.";
  360.   tip[10] = "You can drag a file onto the textbox to upload it!<br><br>The generated links do not work in Chrome, but you can still upload your file.";
  361.   tip = shuffle(tip);
  362.   tips.setAttribute("class","-1");
  363.   tips.addEventListener("click",()=>{
  364.     let i = parseInt(tips.getAttribute("class"))%tip.length;
  365.     i++;
  366.     tips.innerHTML = tip[i];
  367.     tips.setAttribute("class",i);
  368.   });
  369. }
  370.  
  371. function shuffle(array) {
  372.   let currentIndex = array.length,  randomIndex;
  373.   while(currentIndex != 0){
  374.     randomIndex = Math.floor(Math.random() * currentIndex);
  375.     currentIndex--;
  376.     [array[currentIndex], array[randomIndex]] = [
  377.       array[randomIndex], array[currentIndex]];
  378.   }
  379.   return array;
  380. }
  381.  
  382. let ownName = "";
  383.  
  384. function adjustName(){
  385.   let name = document.getElementsByTagName("input")[0];
  386.   let radios = document.getElementsByName("icon");
  387.   let value = 0;
  388.   for(let i=0;i<radios.length;i++){
  389.     if(radios[i].checked){
  390.       value = radios[i].value
  391.       break;
  392.     }
  393.   }
  394.  
  395.   name.value = "["+value+"]"+document.getElementById("typingName").value;
  396.   name.dispatchEvent(new Event("input"));
  397.   ownName = name.value;
  398. }
  399.  
  400. function waitForChat(once=false,name=""){
  401.   if(!once){
  402.     once = true;
  403.     let cover = document.createElement("div");
  404.     cover.id = "loadingCover";
  405.     cover.style.position = "fixed";
  406.     cover.style.top = "0px";
  407.     cover.style.bottom = "0px";
  408.     cover.style.left = "0px";
  409.     cover.style.right = "0px";
  410.     cover.style.background = "#000000";
  411.     cover.style.color = "#FFFFFF";
  412.     cover.innerHTML = "LOADING";
  413.     document.body.appendChild(cover);
  414.     let date = new Date();
  415.     date.setTime(date.getTime()+(1000*60*60*24*365));
  416.     document.cookie = "name="+name+"; expires="+encodeURIComponent(date.toUTCString())+";";
  417.     ownName = name;
  418.     document.body.removeChild(document.getElementById("tipsBox"));
  419.   }
  420.   if(!document.getElementsByClassName("nicklist tab-invisible dynamicpanel qwebirc-qui rightboundpanel")[0]){
  421.     setTimeout(waitForChat,100,once);
  422.     return;
  423.   }
  424.   chat(false,false);
  425. }
  426.  
  427. let sound = getCookie("sound")?(getCookie("sound").split("-")[0]=="on"):false;
  428. let messageSound = new Audio("https://ia601502.us.archive.org/31/items/DRRR-message-sound/message%20sound.mp3");
  429. let logoutSound = new Audio("https://ia601502.us.archive.org/31/items/DRRR-message-sound/logout%20sound.mp3");
  430. messageSound.crossOrigin = "anonymous";
  431. logoutSound.crossOrigin = "anonymous";
  432. let augain;
  433. document.body.addEventListener("click",audioInitiate);
  434. function audioInitiate(){
  435.   let auctx = new AudioContext();
  436.   let aumessage = auctx.createMediaElementSource(messageSound);
  437.   let aulogout = auctx.createMediaElementSource(logoutSound);
  438.   augain = auctx.createGain();
  439.   augain.gain.value = 3;
  440.   aumessage.connect(augain);
  441.   aulogout.connect(augain);
  442.   augain.connect(auctx.destination);
  443.   document.body.removeEventListener("click",audioInitiate);
  444. }
  445.  
  446. let textColor = [];
  447. textColor[0] = "rgb(255,255,255)";
  448. textColor[1] = "rgb(0,0,0)";
  449. textColor[2] = "rgb(0,0,139)";
  450. textColor[3] = "rgb(0,100,0)";
  451. textColor[4] = "rgb(255,0,0)";
  452. textColor[5] = "rgb(139,0,0)";
  453. textColor[6] = "rgb(128,0,128)";
  454. textColor[7] = "rgb(255,165,0)";
  455. textColor[8] = "rgb(255,255,0)";
  456. textColor[9] = "rgb(0,128,0)";
  457. textColor[10] = "rgb(0,128,128)";
  458. textColor[11] = "rgb(0,255,255)";
  459. textColor[12] = "rgb(0,0,255)";
  460. textColor[13] = "rgb(255,0,255)";
  461. textColor[14] = "rgb(169,169,169)";
  462. textColor[15] = "rgb(128,128,128)";
  463.  
  464. let ctrlDown = false;
  465. document.body.addEventListener("keydown",(e)=>{
  466.   if(e.keyCode == 17 || e.keyCode == 91)
  467.     ctrlDown = true;
  468. });
  469. document.body.addEventListener("keyup",(e)=>{
  470.   if(e.keyCode == 17 || e.keyCode == 91)
  471.     ctrlDown = false;
  472. });
  473.  
  474. function chat(once,loaded){
  475.   document.title = "Dollars BBS | Chatroom";
  476.   let linkTags = document.getElementsByTagName("link");
  477.   linkTags[linkTags.length-1].href = "https://dollars-bbs.org/random/favicon.ico";
  478.   if(!(document.getElementsByClassName("dynamicpanel qwebirc-qui topicboundpanel topic tab-invisible colourline")[0] || document.getElementsByTagName("input")[0]) && !once){
  479.     setTimeout(chat,100,false,false);
  480.     return;
  481.   }
  482.   if(!loaded){
  483.     setTimeout(chat,100,false,true);
  484.     document.body.removeChild(document.getElementById("loadingCover"));
  485.     return;
  486.   }
  487.  
  488.   setTimeout(chat,100,true,true);
  489.  
  490.   let input = document.getElementsByClassName("dynamicpanel qwebirc-qui bottomboundpanel input")[0];
  491.   input.style.position = "relative";
  492.   input.style.top = "0px";
  493.  
  494.   let messageList = document.getElementsByClassName("dynamicpanel qwebirc-qui middleboundpanel lines ircwindow")[0];
  495.   if(!messageList)
  496.     messageList = document.getElementsByClassName("drrrMessageList")[0];
  497.   messageList.style.background = "rgba(0,0,0,1)";
  498.   messageList.style.overflowY = "scroll";
  499.   messageList.style.overflowX = "hidden";
  500.   messageList.style.width = "100%";
  501.   messageList.style.bottom = "0px";
  502.   messageList.style.position = "fixed";
  503.  
  504.   let pmListsList = document.getElementsByClassName("drrrPmList");
  505.  
  506.   let bufferDivs = messageList.getElementsByClassName("bufferDiv");
  507.   if(!bufferDivs[0])
  508.     bufferDivs = [];
  509.   for(let i=bufferDivs.length;i<3;i++){
  510.     let d = document.createElement("div");
  511.     messageList.prepend(d);
  512.     d.style.display = "none";
  513.     d.setAttribute("class","bufferDiv");
  514.   }
  515.   bufferDivs = messageList.getElementsByClassName("bufferDiv");
  516.  
  517.   let messages = messageList.getElementsByClassName("colourline");
  518.  
  519.   for(let i=0;i<messages.length;i++){
  520.     let slashMe = 0;
  521.     let spans = messages[i].getElementsByTagName("span");
  522.     let mpm = false;
  523.     if(spans.length<4){
  524.       if(spans.length<3){
  525.         continue;
  526.       }
  527.       slashMe = 1;
  528.     }
  529.     if((spans[1].innerHTML.startsWith("-") && !spans[1].innerHTML.startsWith('-<span class="hyperlink-whois">Onee-chan</span>-')) || spans[1].innerHTML.startsWith("[notice("))
  530.       mpm = true;
  531.  
  532.     let timestamp = document.createElement("div");
  533.     timestamp.innerHTML = spans[0].innerHTML;
  534.     let reply = document.createElement("div");
  535.     reply.setAttribute("class","drrrReply");
  536.     reply.style.width = (600+58+25)+"px";
  537.     reply.style.margin = "auto";
  538.     reply.style.position = "relative";
  539.     reply.style.display = "flex";
  540.     let personHolder = document.createElement("div");
  541.     personHolder.style.width = "58px";
  542.     personHolder.style.position = "relative";
  543.     personHolder.style.display = "flex";
  544.     reply.appendChild(personHolder);
  545.     let replyHolder = document.createElement("div");
  546.     replyHolder.style.width = "600px";
  547.     replyHolder.style.display = "flex";
  548.     let replyBubble = document.createElement("div");
  549.     replyBubble.style.alignSelf = "center";
  550.     replyBubble.style.display = "flex";
  551.     let replyText = document.createElement("div");
  552.     replyText.style.display = "flex";
  553.     replyBubble.appendChild(replyText);
  554.     replyHolder.appendChild(replyBubble);
  555.     reply.appendChild(replyHolder);
  556.  
  557.     let name = "";
  558.     let hlwi = messages[i].getElementsByClassName("hyperlink-whois")[0]
  559.     name = hlwi?hlwi:spans[3-slashMe];
  560.     let self = name.parentNode.getAttribute("class") == "Xu";
  561.     let m = self?name.parentNode.nextSibling:name.parentNode;
  562.     if(!m)
  563.       m = name.parentNode;
  564.     if(m.innerHTML == "@" || m.innerHTML == "%" || m.innerHTML == "~")
  565.       m = spans[3+(self?2:0)-slashMe];
  566.     let mh = m;
  567.     let opmm = !m.innerHTML.startsWith("-");
  568.     if(self)
  569.       m.innerHTML = m.innerHTML.replace(/.*?&gt;(<span>.+?<\/span>)? ?/,"");
  570.     else if(!slashMe)
  571.       m.innerHTML = m.innerHTML.replace(/.*?&gt;(<span>.+?<\/span>)? ?/,"");
  572.     else
  573.       m.innerHTML = m.innerHTML.replace(/.+<\/span> /,"");
  574.     if(mpm){
  575.       if(m.innerHTML.startsWith("-"))
  576.         m.innerHTML = m.innerHTML.replace(/.+?- /,"");
  577.       else
  578.         m.innerHTML = m.innerHTML.replace(/.+?\)\] /,"");
  579.     }
  580.     m = formatSpan(m);
  581.     for(let j=0;mh.nextSibling && j<2000;j++){
  582.       mh = mh.nextSibling;
  583.       if(mh == name)
  584.         mh = mh.nextSibling;
  585.       if(!mh)
  586.         break;
  587.       m+=formatSpan(mh);
  588.     }
  589.     name = name.innerHTML;
  590.     replyText.innerHTML = "<span style='overflow-wrap: break-word; width: 100%;'>"+m+"</span>";
  591.  
  592.     let id = 0;
  593.     for(let j=0;j<name.replace(prefixes,"").length;j++)
  594.       id+=name.replace(prefixes,"").charCodeAt(j);
  595.     id = id%icons.length;
  596.  
  597.     let qjl = m.match(/\[.+?@.+?\] has (quit \[.*?\]<\/span>)?(joined <span class="hyperlink-channel">#.+)?(left <span class="hyperlink-channel">#.+)?$/);
  598.     if(qjl){
  599.       let ip = m.match(/\[.+?\]/g);
  600.       for(let j=0;j<ip.length;j++){
  601.         if(ip[j].match(/\[.+?@.+?\]/)){
  602.           ip = ip[j];
  603.           break;
  604.         }
  605.       }
  606.       replyText.innerHTML = "<span>——"+m.replace(ip,"").replace("  "," ")+"</span>";
  607.       bufferDivs[2].after(replyText);
  608.       replyText.style.color = "#FFFFFF";
  609.       replyText.style.width = "683px";
  610.       replyText.style.margin = "auto";
  611.       messageList.removeChild(messages[i]);
  612.       if(m.match(/quit \[.*?\]<\/span>$/) || m.match(/left <span class="hyperlink-channel">#.+$/))
  613.         logoutSound.play();
  614.       else
  615.         messageSound.play();
  616.       continue;
  617.     }
  618.  
  619.     if(!mpm)
  620.       bufferDivs[2].after(reply);
  621.     else{
  622.       let mlist = null;
  623.       for(let j=0;j<pmListsList.length;j++){
  624.         if(pmListsList[j].id == name){
  625.           mlist = pmListsList[j];
  626.           continue;
  627.         }
  628.       }
  629.       if(mlist == null){
  630.         mlist = createPmList(name);
  631.         messageList.parentNode.appendChild(mlist);
  632.         pmListsList = document.getElementsByClassName("drrrPmList");
  633.       }
  634.       mlist.prepend(reply);
  635.       mlist.setAttribute("unread",opmm?0:parseInt(mlist.getAttribute("unread"))+1);
  636.     }
  637.     if(opmm && mpm)
  638.       name = ownName;
  639.  
  640.     let iconHolder = document.createElement("div");
  641.     personHolder.appendChild(iconHolder);
  642.     if(name.match(/\[[0-9]+\]/)){
  643.       id = parseInt(name.replace(/\[/,"").replace(/\].+/,""));
  644.     }
  645.  
  646.     if(!icons[id]){
  647.       loadIcon(id);
  648.       setTimeout(setIcon,5000,id,iconHolder,mpm);
  649.       id = 0;
  650.       for(let j=0;j<name.replace(prefixes,"").length;j++)
  651.         id+=name.replace(prefixes,"").charCodeAt(j);
  652.       id = id%icons.length;
  653.       setIcon(id,iconHolder,mpm);
  654.     } else
  655.       setIcon(id,iconHolder,mpm);
  656.  
  657.     let namePlate = document.createElement("div");
  658.     namePlate.innerHTML = name.replace(/\[[0-9]+\]/,"");
  659.     namePlate.style.margin = "auto";
  660.     namePlate.style.width = "90px";
  661.     namePlate.style.textAlign = "center";
  662.     namePlate.style.color = "#FFFFFF";
  663.     namePlate.style.position = "absolute";
  664.     namePlate.style.transform = "translateX(-50%) translateY(-6px)"
  665.     namePlate.style.overflowWrap = "break-word";
  666.     namePlate.style.left = "29px";
  667.     namePlate.style.top = "calc(50% + 39px)";
  668.     iconHolder.style.display = "block";
  669.     iconHolder.appendChild(namePlate);
  670.  
  671.     timestamp.style.position = "relative";
  672.     timestamp.style.color = "#000000";
  673.     timestamp.style.right = "65px";
  674.     iconHolder.appendChild(timestamp);
  675.  
  676.     let topColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+iconColors[id][3];
  677.     let topMiddleColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+(iconColors[id][3]-0.05);
  678.     let bottomMiddleColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+(iconColors[id][3]-0.15);
  679.     let bottomColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+(iconColors[id][3]-0.5);
  680.     if(mpm){
  681.       topColor = "255,255,255,1";
  682.       topMiddleColor = "255,255,255,1";
  683.       bottomMiddleColor = "255,255,255,1";
  684.       bottomColor = "255,255,255,1";
  685.     }
  686.     replyBubble.style.background = "linear-gradient(to bottom,rgba("+topColor+"),rgba("+topMiddleColor+") 50%,rgba("+bottomMiddleColor+") 50%,rgba("+bottomColor+"))";
  687.     replyBubble.style.border = "solid #FFFFFF 4px";
  688.     replyBubble.style.borderRadius = "13px";
  689.     replyBubble.style.maxWidth = Math.min(window.innerWidth,600)+"px";
  690.     replyBubble.style.minWidth = (18*3)+"px";
  691.     replyBubble.style.width = "auto";
  692.     replyBubble.style.left = "30px";
  693.     replyBubble.style.position = "relative";
  694.  
  695.     replyText.style.color = "#FFFFFF";
  696.     if(iconColors[id][0]+iconColors[id][1]+iconColors[id][2]>230*3){
  697.       replyText.style.color = "#050505";
  698.       replyBubble.style.borderColor = "#888888";
  699.     }
  700.     if(mpm){
  701.       replyText.style.color = "#000000";
  702.       replyBubble.style.borderColor = "rgba("+iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+",1)";
  703.     }
  704.     replyText.style.position = "relative";
  705.     replyText.style.fontSize = "18px";
  706.     replyText.style.margin = "18px";
  707.     replyText.style.marginTop = "14px";
  708.     replyText.style.lineHeight = "20px";
  709.     replyText.style.width = "-moz-max-content";
  710.     replyText.style.maxWidth = (Math.min(window.innerWidth,600)-18*2)+"px";
  711.  
  712.     reply.style.minHeight = (Math.max(replyBubble.offsetHeight,58)+16)+"px";
  713.     reply.parentNode.style.display = "block";
  714.     reply.mb = Math.min(namePlate.offsetHeight,Math.max(0,(58+(namePlate.offsetHeight+8)*1.5)-parseInt(reply.style.minHeight.replace("px",""))));
  715.     if(mpm){
  716.       let isPm = document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on";
  717.       let pmsel = document.getElementById("pmSelector");
  718.       let cpm = pmsel.options[pmsel.selectedIndex];
  719.       if(cpm)
  720.         cpm = cpm.value.replace(/\[[0-9]+\]/,"");
  721.       if(!(namePlate.innerHTML == cpm || namePlate.innerHTML == ownName.replace(/\[[0-9]+\]/,"")) || !isPm){
  722.         reply.parentNode.style.display = "none";
  723.       }
  724.     }
  725.     reply.style.marginBottom = reply.mb+"px";
  726.  
  727.     let arrowGradient = document.createElement("div");
  728.     arrowGradient.style.width = "25px";
  729.     arrowGradient.style.height = "12px";
  730.     arrowGradient.style.background = "#000000";
  731.     arrowGradient.style.top = "calc(50% - 1px)";
  732.     arrowGradient.style.transform = "translateY(-50%)";
  733.     arrowGradient.style.left = "-25px";
  734.     arrowGradient.style.position = "absolute";
  735.  
  736.     let arrow = document.createElement("div");
  737.     arrow.style.width = "25px";
  738.     arrow.style.height = "13px";
  739.     let h = replyBubble.offsetHeight/13*100;
  740.     let arrowBackground = "linear-gradient(10deg,rgba(0,0,0,1),rgba(0,0,0,1) calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% + 1px),rgba(0,0,0,0) calc(40% + 1px),rgba(0,0,0,0)),"+
  741.         "linear-gradient(170deg,rgba(0,0,0,1),rgba(0,0,0,1) calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% + 1px),rgba(0,0,0,0) calc(40% + 1px),rgba(0,0,0,0)),"+
  742.         "linear-gradient(to bottom,rgba("+topColor+") -"+h+"%,rgba("+topMiddleColor+") calc(50% + 0.5px),rgba("+bottomMiddleColor+") calc(50% + 0.5px),rgba("+bottomColor+") "+h+"%)";
  743.     arrow.style.background = arrowBackground;
  744.     arrowGradient.appendChild(arrow);
  745.     replyBubble.appendChild(arrowGradient);
  746.  
  747.     if(document.getElementById("inflateSetting") && !mpm)
  748.       if(document.getElementById("inflateSetting").checked)
  749.         animateNewMessage(reply,replyBubble,reply.mb,replyBubble.offsetHeight,replyBubble.offsetWidth-8,namePlate.offsetHeight,0);
  750.  
  751.     messageList.removeChild(messages[i]);
  752.  
  753.     if(window.scrollY>0){
  754.       window.scroll(0,0);
  755.       messageList.scroll(0,0);
  756.     }
  757.  
  758.     if(sound)
  759.       messageSound.play();
  760.   }
  761.  
  762.   let separator = document.getElementsByClassName("lastpos")[0];
  763.   if(separator)
  764.     separator.parentNode.removeChild(separator);
  765.  
  766.   let onlineUsers = getOnlineUsers();
  767.   let onlineDiv = document.getElementById("drrrOnline");
  768.   if(!onlineDiv){
  769.     onlineDiv = document.createElement("div");
  770.     onlineDiv.style.display = "flex";
  771.     onlineDiv.style.flexDirection = "row";
  772.     onlineDiv.style.position = "relative";
  773.     onlineDiv.style.width = "725px";
  774.     onlineDiv.style.justifyContent = "center";
  775.     onlineDiv.style.flexWrap = "wrap";
  776.     onlineDiv.style.display = "none";
  777.     onlineDiv.id = "drrrOnline";
  778.   }
  779.   for(let i=0;i<onlineUsers.length;i++){
  780.     if(onlineDiv.children[i]){
  781.       if(onlineUsers[i].id == onlineDiv.children[i].id)
  782.         continue;
  783.     }
  784.     let div = onlineDiv.children[i]?onlineDiv.children[i]:document.createElement("div");
  785.     if(!div.id)
  786.       onlineDiv.appendChild(div);
  787.     div.innerHTML = "";
  788.     div.style.width = "-moz-max-content";
  789.     div.style.maxWidth = "fit-content";
  790.     div.style.marginTop = "2px";
  791.     div.id = onlineUsers[i].id;
  792.     if(i!=0)
  793.       div.style.marginLeft = "10px";
  794.     div.onclick = ()=>{
  795.       let t = document.getElementsByTagName("textarea")[0];
  796.       let tstart = t.value.slice(0,t.selectionStart);
  797.       let tend = t.value.slice(t.selectionStart);
  798.       t.value = tstart+(tstart.match(/ $/)||tstart.match(/^$/)?"":" ")+onlineUsers[i].id+(tend.match(/^ /)||tend.match(/^$/)?"":" ")+tend;
  799.       t.oninput();
  800.       t.focus();
  801.     };
  802.     div.style.cursor = "pointer";
  803.     let oui = null;
  804.     let ouiid = parseInt(onlineUsers[i].id.replace("[","").replace(/\].+/,""));
  805.     if(icons[ouiid])
  806.       oui = icons[ouiid].cloneNode();
  807.     else{
  808.       ouiid = 0;
  809.       for(let j=0;j<onlineUsers[i].id.replace(prefixes,"").length;j++)
  810.         ouiid+=onlineUsers[i].id.replace(prefixes,"").charCodeAt(j);
  811.       ouiid = ouiid%icons.length;
  812.       oui = icons[ouiid].cloneNode();
  813.     }
  814.     div.appendChild(oui);
  815.     oui = div.children[0];
  816.     oui.style.height = "18px";
  817.     oui.style.width = "18px";
  818.     oui.style.marginRight = "3px";
  819.     let np = document.createElement("div");
  820.     np.innerHTML = onlineUsers[i].display;
  821.     np.style.color = "#000000";
  822.     np.style.lineHeight = "18px";
  823.     np.style.display = "inline-block";
  824.     np.style.top = "-3px";
  825.     np.style.position = "relative";
  826.     div.appendChild(np);
  827.  
  828.     if(!document.getElementById(onlineUsers[i].id)){
  829.       let mlist = createPmList(onlineUsers[i].id);
  830.       messageList.parentNode.appendChild(mlist);
  831.       pmListsList = document.getElementsByClassName("drrrPmList");
  832.     }
  833.   }
  834.   for(let i=onlineUsers.length;i<onlineDiv.children.length;i++)
  835.     onlineDiv.removeChild(onlineDiv.children[i]);
  836.  
  837.   if(!once){
  838.     let header = document.getElementsByClassName("dynamicpanel qwebirc-qui topicboundpanel topic tab-invisible colourline")[0];
  839.     if(header)
  840.       header.style.display = "none";
  841.  
  842.     document.body.prepend(input);
  843.     document.body.style.background = "rgba(238,238,238,1)";
  844.     input.style.paddingLeft = "24px";
  845.     input = document.getElementsByTagName("input")[0];
  846.     let inputBox = document.createElement("textarea");
  847.     input.parentNode.style.width = "725px";
  848.     input.parentNode.style.margin = "auto";
  849.     input.parentNode.style.background = "#EEEEEE";
  850.     input.style.height = "0px";
  851.     input.style.width = "0px";
  852.     input.style.margin = "0px";
  853.     input.style.border = "0px";
  854.     input.style.padding = "0px";
  855.     inputBox.style.width = "590px";
  856.     inputBox.style.height = "65px";
  857.     inputBox.style.overflowWrap = "break-word";
  858.     inputBox.style.overflowX = "hidden";
  859.     inputBox.style.whiteSpace = "normal";
  860.     inputBox.style.background = "#FFFFFF";
  861.     inputBox.style.position = "relative";
  862.     inputBox.style.top = "0px";
  863.     inputBox.style.left = "88px";
  864.     inputBox.style.border = "2px solid #333333";
  865.     inputBox.style.borderRadius = "10px";
  866.     inputBox.style.fontSize = "18px";
  867.     inputBox.placeholder = "";
  868.     inputBox.ondrop = (e)=>{upload(e);};
  869.     inputBox.oninput = (e)=>{
  870.       let isPm = document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on";
  871.       let pmsel = document.getElementById("pmSelector");
  872.       let cpm = pmsel.options[pmsel.selectedIndex];
  873.       if(cpm)
  874.         cpm = cpm.value;
  875.       input.value = (isPm && cpm?"/notice "+cpm+" ":"")+inputBox.value.replace(/%@[iI]/g,String.fromCharCode(0x1D))
  876.                                                                .replace(/%@[bB]/g,String.fromCharCode(0x02))
  877.                                                                .replace(/%@[uU]/g,String.fromCharCode(0x1F))
  878.                                                                .replace(/%@[sS]/g,String.fromCharCode(0x1E))
  879.                                                                .replace(/%@[mM]/g,String.fromCharCode(0x11))
  880.                                                                .replace(/%@[rR]/g,String.fromCharCode(0x0F))
  881.                                                                .replace(/%@/g,String.fromCharCode(3));
  882.     };
  883.     inputBox.addEventListener("keydown",function(e){
  884.                                           if(ctrlDown){
  885.                                             switch(e.keyCode){
  886.                                               case 75:
  887.                                                 e.preventDefault();
  888.                                                 inputBox.value+="%@";
  889.                                                 break;
  890.                                               case 73:
  891.                                                 e.preventDefault();
  892.                                                 inputBox.value+="%@I";
  893.                                                 break;
  894.                                               case 77:
  895.                                                 e.preventDefault();
  896.                                                 inputBox.value+="%@M";
  897.                                                 break;
  898.                                               case 66:
  899.                                                 e.preventDefault();
  900.                                                 inputBox.value+="%@B";
  901.                                                 break;
  902.                                               case 83:
  903.                                                 e.preventDefault();
  904.                                                 inputBox.value+="%@S";
  905.                                                 break;
  906.                                               case 85:
  907.                                                 e.preventDefault();
  908.                                                 inputBox.value+="%@U";
  909.                                                 break;
  910.                                               case 82:
  911.                                                 e.preventDefault();
  912.                                                 inputBox.value+="%@R";
  913.                                                 break;
  914.                                             }
  915.                                           }
  916.                                           if(e.code=="Enter"){
  917.                                             let isPm = document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on";
  918.                                             let pmsel = document.getElementById("pmSelector");
  919.                                             let cpm = pmsel.options[pmsel.selectedIndex];
  920.                                             if(cpm)
  921.                                               cpm = cpm.value;
  922.                                             if(inputBox.value.startsWith("/nick ")){
  923.                                               ownName = inputBox.value.replace(/^\/nick /,"");
  924.                                               modifyUserPlate();
  925.                                             }
  926.                                             input.value = (isPm && cpm?"/notice "+cpm+" ":"")+inputBox.value.replace(/%@[iI]/g,String.fromCharCode(0x1D))
  927.                                                                                                      .replace(/%@[bB]/g,String.fromCharCode(0x02))
  928.                                                                                                      .replace(/%@[uU]/g,String.fromCharCode(0x1F))
  929.                                                                                                      .replace(/%@[sS]/g,String.fromCharCode(0x1E))
  930.                                                                                                      .replace(/%@[mM]/g,String.fromCharCode(0x11))
  931.                                                                                                      .replace(/%@[rR]/g,String.fromCharCode(0x0F))
  932.                                                                                                      .replace(/%@/g,String.fromCharCode(3));
  933.                                             inputBox.value = "";
  934.                                             input.focus();
  935.                                           }
  936.                                         });
  937.     input.onkeydown = function(){
  938.                         inputBox.value = "";
  939.                         messageList.scroll(0,0);
  940.                         window.scroll(0,0);
  941.                         inputBox.focus();
  942.                       };
  943.     input.parentNode.appendChild(inputBox);
  944.  
  945.     document.getElementById("ircui").style.top = "4000px";
  946.  
  947.     let user = document.createElement("div");
  948.     user.style.width = "58px";
  949.     user.style.display = "inline-block";
  950.     user.style.position = "absolute";
  951.     user.style.top = "0px";
  952.     user.id = "userPlate";
  953.     input.parentNode.prepend(user);
  954.     modifyUserPlate();
  955.  
  956.     inputBox.style.height = (user.offsetHeight-4)+"px";
  957.  
  958.     input.parentNode.appendChild(onlineDiv);
  959.  
  960.     for(let i=0;i<3;i++){
  961.     }
  962.     let toggleBar = document.createElement("div");
  963.     let toggleIconSrcs = [];
  964.     toggleIconSrcs[0] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/pm%20off.png";
  965.     toggleIconSrcs[1] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/pm%20on.png";
  966.     toggleIconSrcs[2] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/online%20off.png";
  967.     toggleIconSrcs[3] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/online%20on.png";
  968.     toggleIconSrcs[4] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/sound%20off.png";
  969.     toggleIconSrcs[5] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/sound%20on.png";
  970.     toggleIconSrcs[6] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/settings%20off.png";
  971.     toggleIconSrcs[7] = "https://ia801409.us.archive.org/15/items/drrrchat-toggles/settings%20on.png";
  972.  
  973.     let toggleIcons = [];
  974.     for(let i=0;i<toggleIconSrcs.length/2;i++){
  975.       toggleIcons[i] = document.createElement("img");
  976.       toggleIcons[i].style.margin = "0px";
  977.       toggleIcons[i].style.marginLeft = "5px";
  978.       toggleIcons[i].style.cursor = "pointer";
  979.       toggleIcons[i].setAttribute("class","drrrToggle");
  980.       toggleIcons[i].src = toggleIconSrcs[i*2];
  981.       toggleBar.appendChild(toggleIcons[i]);
  982.       let o = document.createAttribute("on");
  983.       o.value = "off";
  984.       toggleIcons[i].setAttributeNode(o);
  985.     }
  986.     if(sound){
  987.       toggleIcons[2].src = toggleIconSrcs[5];
  988.       toggleIcons[2].setAttribute("on","on");
  989.     }else{
  990.       toggleIcons[2].setAttribute("on","off");
  991.     }
  992.     toggleBar.style.position = "absolute";
  993.     toggleBar.style.marginLeft = "690px";
  994.     toggleBar.style.width = (20*toggleIcons.length)+"px";
  995.  
  996.     input.parentNode.prepend(toggleBar);
  997.  
  998.     toggleIcons[0].onclick = ()=>{
  999.       toggleIcons[0].setAttribute("on",toggleIcons[0].getAttribute("on")=="on"?"off":"on");
  1000.       let on = toggleIcons[0].getAttribute("on")=="on";
  1001.       let r = 0;
  1002.       for(let i=0;i<pmListsList.length;i++){
  1003.         let rev = pmListsList[i].getAttribute("revealed")=="true";
  1004.         if(rev)
  1005.           r = i;
  1006.         pmListsList[i].style.display = (rev&&on)?"block":"none";
  1007.       }
  1008.       toggleIcons[0].src = toggleIconSrcs[on?1:0];
  1009.       if(on){
  1010.         if(icons[userID].getAttribute("colorless")=="false"){
  1011.           if(user.children[0].outerHTML.startsWith("<img"))
  1012.             user.prepend(invertIcon(user.children[0],userID));
  1013.           else
  1014.             user.children[0].style.display = "block";
  1015.           user.children[1].style.display = "none";
  1016.         }
  1017.         pmListsList[r].style.display = "block";
  1018.         pmListsList[r].setAttribute("revealed",true);
  1019.       }else{
  1020.         if(icons[userID].getAttribute("colorless")=="false"){
  1021.           user.children[0].style.display = "none";
  1022.           user.children[1].style.display = "block";
  1023.         }
  1024.       }
  1025.     };
  1026.     toggleIcons[1].onclick = ()=>{onlineDiv.style.display = onlineDiv.style.display=="none"?"flex":"none"; toggleIcons[1].src = toggleIconSrcs[onlineDiv.style.display=="none"?2:3];};
  1027.     toggleIcons[2].onclick = ()=>{
  1028.       sound = !sound;
  1029.       toggleIcons[2].src = toggleIconSrcs[sound?5:4];
  1030.       toggleIcons[2].setAttribute("on",sound?"on":"off");
  1031.       saveCookie("sound",toggleIcons[2].getAttribute("on")+"-"+document.getElementById("volumeSlider").value);
  1032.     };
  1033.  
  1034.     let online = document.getElementsByClassName("nicklist tab-invisible dynamicpanel qwebirc-qui rightboundpanel")[0];
  1035.     if(online)
  1036.       online.style.display = "none";
  1037.  
  1038.     let settingsWindow = createSettingsWindow();
  1039.  
  1040.     toggleIcons[3].onclick = ()=>{
  1041.       settingsWindow.style.display = settingsWindow.style.display=="none"?"block":"none";
  1042.       toggleIcons[3].src = toggleIconSrcs[settingsWindow.style.display=="none"?6:7];
  1043.     };
  1044.  
  1045.     let postButton = document.createElement("div");
  1046.     postButton.style.margin = "auto";
  1047.     postButton.style.marginTop = "3px";
  1048.     postButton.style.marginBottom = "3px";
  1049.     postButton.style.color = "#000000";
  1050.     postButton.style.fontWeight = "bold";
  1051.     postButton.style.textAlign = "center";
  1052.     postButton.style.lineHeight = "26px";
  1053.     postButton.style.width = "250px";
  1054.     postButton.style.height = "26px";
  1055.     postButton.style.background = "linear-gradient(to bottom,#FAF7F8,#F9F9F5 50%,#F2F2EE 50%,#F1F1ED)";
  1056.     postButton.style.border = "2px solid #333333";
  1057.     postButton.style.borderRadius = "10px";
  1058.     postButton.style.cursor = "pointer";
  1059.     postButton.innerHTML = "POST!"
  1060.     postButton.onclick = ()=>{inputBox.focus();};
  1061.     inputBox.after(postButton);
  1062.  
  1063.     let topNode = document.getElementsByClassName("dynamicpanel qwebirc-qui topboundpanel outertabbar outertabbar_top")[0];
  1064.     topNode.style.display = "block";
  1065.     topNode.style.position = "fixed";
  1066.     topNode.style.width = (input.parentNode.getBoundingClientRect().left-10)+"px";
  1067.     topNode.style.backgroundColor = "#EEEEEE";
  1068.     topNode.style.borderBottom = "none";
  1069.     let topAs = topNode.getElementsByTagName("a");
  1070.     for(let i=0;i<topAs.length;i++){
  1071.       topAs[i].style.backgroundColor = topAs[i].getAttribute("class")=="tab tab-unselected"?"#E3EFFA":"#FFFFFE";;
  1072.       let mut = new MutationObserver((mutations)=>{
  1073.                                        if(mutations[0].attributeName == "class")
  1074.                                          mutations[0].target.style.backgroundColor = mutations[0].target.getAttribute("class")=="tab tab-unselected"?"#E3EFFA":"#FFFFFE";
  1075.                                      });
  1076.       mut.observe(topAs[i],{attributes:true});
  1077.     }
  1078.   }
  1079.  
  1080.   messageList.style.top = input.offsetHeight+"px";
  1081.   messageList.style.height = "calc(100% - "+messageList.style.top+")";
  1082.   for(let i=0;i<pmListsList.length;i++){
  1083.     pmListsList[i].style.top = input.offsetHeight+"px";
  1084.   }
  1085.   messageList.setAttribute("class","drrrMessageList");
  1086.  
  1087.   let pmSelector = document.getElementById("pmSelector");
  1088.   if(!pmSelector){
  1089.     pmSelector = document.createElement("select");
  1090.     pmSelector.style.position = "absolute";
  1091.     pmSelector.style.top = "20px";
  1092.     let w = 120;
  1093.     pmSelector.style.marginLeft = "690px";
  1094.     pmSelector.style.width = w+"px";
  1095.     pmSelector.id = "pmSelector";
  1096.     document.getElementsByTagName("input")[0].parentNode.prepend(pmSelector);
  1097.     pmSelector.onchange = ()=>{
  1098.       let selected = pmSelector.options[pmSelector.selectedIndex].value;
  1099.       for(let i=0;i<pmListsList.length;i++){
  1100.         pmListsList[i].setAttribute("revealed",pmListsList[i].id==selected);
  1101.         pmListsList[i].style.display = pmListsList[i].getAttribute("revealed")=="true"?"block":"none";
  1102.         if(pmListsList[i].getAttribute("revealed")=="true")
  1103.           pmListsList[i].setAttribute("unread",0);
  1104.       }
  1105.       input.value = "/notice "+selected.replace(/^%?@?~?/,"");
  1106.       input.parentNode.getElementsByTagName("textarea")[0].focus();
  1107.     };
  1108.   }
  1109.   pmSelector.style.display = (document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on")?"block":"none";
  1110.   for(let i=0;i<onlineUsers.length;i++){
  1111.     if(pmSelector.children[i])
  1112.       if(pmSelector.children[i].innerHTML == onlineUsers[i].display)
  1113.         continue;
  1114.     let option = pmSelector.children[i]?pmSelector.children[i]:document.createElement("option");
  1115.     option.value = onlineUsers[i].id;
  1116.     option.innerHTML = onlineUsers[i].display;
  1117.     if(!pmSelector.children[i])
  1118.       pmSelector.appendChild(option);
  1119.   }
  1120.   for(let i=onlineUsers.length;i<pmSelector.children.length;i++)
  1121.     pmSelector.removeChild(pmSelector.children[i]);
  1122.   for(let i=0;i<pmSelector.children.length;i++){
  1123.     let op = pmSelector.children[i].value;
  1124.     let unread = parseInt(document.getElementById(op).getAttribute("unread"));
  1125.     if(unread){
  1126.       if(pmSelector.children[i].innerHTML.match(/ \([0-9]+\)$/))
  1127.         pmSelector.children[i].innerHTML = pmSelector.children[i].innerHTML.replace(/ \([0-9]+\)$/," ("+unread+")");
  1128.       else
  1129.         pmSelector.children[i].innerHTML = pmSelector.children[i].innerHTML+" ("+unread+")";
  1130.     }else
  1131.       pmSelector.children[i].innerHTML = pmSelector.children[i].innerHTML.replace(/ \([0-9]+\)$/,"");
  1132.   }
  1133. }
  1134.  
  1135. function modifyUserPlate(){
  1136.   let user = document.getElementById("userPlate");
  1137.   let userID = parseInt(ownName.replace("[","").replace(/\].+/,""));
  1138.   if(!icons[userID]){
  1139.     userID = 0;
  1140.     for(let j=0;j<ownName.replace(prefixes,"").length;j++)
  1141.       userID+=ownName.replace(prefixes,"").charCodeAt(j);
  1142.     userID = userID%icons.length;
  1143.   }
  1144.   let namePlate = document.getElementById("nameUnderIcon");
  1145.   if(!namePlate){
  1146.     user.appendChild(icons[userID].cloneNode());
  1147.     namePlate = document.createElement("div");
  1148.     user.appendChild(namePlate);
  1149.     namePlate.outerHTML = "<div id='nameUnderIcon'>"+ownName.replace(/\[[0-9]+\]/,"")+"</div>";
  1150.     namePlate = document.getElementById("nameUnderIcon");
  1151.     namePlate.style.position = "relative";
  1152.     namePlate.style.left = "50%";
  1153.     namePlate.style.top = "-4px";
  1154.     namePlate.style.transform = "translateX(-50%)";
  1155.     namePlate.style.width = "100px";
  1156.     namePlate.style.overflow = "visible";
  1157.     namePlate.style.overflowWrap = "break-word";
  1158.     namePlate.style.height = "auto";
  1159.     namePlate.style.lineHeight = "18px";
  1160.     namePlate.style.textAlign = "center";
  1161.   }else{
  1162.     namePlate.innerHTML = ownName.replace(/\[[0-9]+\]/,"");
  1163.     console.log(userID);
  1164.     console.log(icons.length);
  1165.     console.log(icons[userID]);
  1166.     namePlate.previousSibling.outerHTML = icons[userID].outerHTML;
  1167.   }
  1168. }
  1169.  
  1170. function setIcon(id,icon,isPms){
  1171.   if(!icons[id]){
  1172.     loadIcon(id);
  1173.     setTimeout(setIcon,5000,id,icon,isPms);
  1174.     return;
  1175.   }
  1176.   icon.appendChild(icons[id].cloneNode());
  1177.   if(isPms && icons[id].getAttribute("colorless")=="false"){
  1178.     let c = invertIcon(icon.children[0],id);
  1179.     icon.innerHTML = ""
  1180.     icon.appendChild(c);
  1181.   }
  1182.   icon.children[0].style.transform = "translateY(-50%)";
  1183.   icon.children[0].style.top = "50%";
  1184.   icon.children[0].style.position = "relative";
  1185.   icon.children[0].style.width = "58px";
  1186. }
  1187.  
  1188. function invertIcon(icon,id){
  1189.   let canvas = document.createElement("canvas");
  1190.   canvas.width = 58;
  1191.   canvas.height = 58;
  1192.   let ctx = canvas.getContext("2d");
  1193.   ctx.drawImage(icon,0,0,58,58);
  1194.   let imgdata = ctx.getImageData(0,0,58,58);
  1195.   let iconColor = iconColors[id];
  1196.   if(arrayEqual(iconColor,[63,63,63,1],false))
  1197.     iconColor = [0,0,0,1];
  1198.   for(let i=0;i<imgdata.data.length;i+=4){
  1199.     let color = [];
  1200.     color[0] = imgdata.data[i]
  1201.     color[1] = imgdata.data[i+1]
  1202.     color[2] = imgdata.data[i+2]
  1203.     color[3] = 1;
  1204.     if(arrayEqual(color,iconColor,true)){
  1205.       let c = 255;
  1206.       if(arrayEqual(color,[255,255,255,1],true))
  1207.         c = 0;
  1208.       imgdata.data[i] = c;
  1209.       imgdata.data[i+1] = c;
  1210.       imgdata.data[i+2] = c;
  1211.     } else if(arrayEqual(color,[255,255,255,1],true) || arrayEqual(color,[0,0,0,1],true)){
  1212.       imgdata.data[i] = iconColor[0];
  1213.       imgdata.data[i+1] = iconColor[1];
  1214.       imgdata.data[i+2] = iconColor[2];
  1215.     }else{
  1216.       imgdata.data[i] = 255-imgdata.data[i];
  1217.       imgdata.data[i+1] = 255-imgdata.data[i+1];
  1218.       imgdata.data[i+2] = 255-imgdata.data[i+2];
  1219.     }
  1220.   }
  1221.   ctx.putImageData(imgdata,0,0);
  1222.   return canvas;
  1223. }
  1224.  
  1225. function arrayEqual(a,b,fudge=false){
  1226.   if(a.length!=b.length)
  1227.     return false;
  1228.   if(fudge && deltaE(a,b)<10)
  1229.     return true;
  1230.   for(let i=0;i<a.length;i++)
  1231.     if(a[i]!=b[i] && !(fudge && deltaE(a,b)<10))
  1232.       return false;
  1233.   return true;
  1234. }
  1235.  
  1236. function deltaE(rgbA, rgbB) {
  1237.   let labA = rgb2lab(rgbA);
  1238.   let labB = rgb2lab(rgbB);
  1239.   let deltaL = labA[0] - labB[0];
  1240.   let deltaA = labA[1] - labB[1];
  1241.   let deltaB = labA[2] - labB[2];
  1242.   let c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
  1243.   let c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
  1244.   let deltaC = c1 - c2;
  1245.   let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
  1246.   deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
  1247.   let sc = 1.0 + 0.045 * c1;
  1248.   let sh = 1.0 + 0.015 * c1;
  1249.   let deltaLKlsl = deltaL / (1.0);
  1250.   let deltaCkcsc = deltaC / (sc);
  1251.   let deltaHkhsh = deltaH / (sh);
  1252.   let i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
  1253.   return i < 0 ? 0 : Math.sqrt(i);
  1254. }
  1255.  
  1256. function rgb2lab(rgb){
  1257.   let r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255, x, y, z;
  1258.   r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
  1259.   g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
  1260.   b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
  1261.   x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
  1262.   y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
  1263.   z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
  1264.   x = (x > 0.008856) ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
  1265.   y = (y > 0.008856) ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
  1266.   z = (z > 0.008856) ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
  1267.   return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]
  1268. }
  1269.  
  1270. function getOnlineUsers(){
  1271.   let onlineList = document.getElementsByClassName("nicklist tab-invisible dynamicpanel qwebirc-qui rightboundpanel")[0];
  1272.   let online = onlineList.getElementsByTagName("a");
  1273.   let people = [];
  1274.   for(let i=0;i<online.length;i++){
  1275.     let p = {id:"",display:""};
  1276.     p.id = online[i].children[0].innerHTML.replace(prefixes,"");
  1277.     p.display = p.id.replace(prefixes,"").replace(/^\[[0-9]+\]/,"");
  1278.     people[i] = p;
  1279.   }
  1280.   return people;
  1281. }
  1282.  
  1283. function createPmList(name){
  1284.   let mlist = document.createElement("div");
  1285.   mlist.style.background = "rgba(0,0,0,0.75)";
  1286.   mlist.style.overflowY = "scroll";
  1287.   mlist.style.overflowX = "hidden";
  1288.   mlist.style.width = "100%";
  1289.   mlist.style.height = ((18*2+20*2)*4+160)+"px";;
  1290.   mlist.style.position = "fixed";
  1291.   mlist.style.display = "none";
  1292.   mlist.setAttribute("class","drrrPmList");
  1293.   mlist.id = name;
  1294.   let r = document.createAttribute("revealed");
  1295.   r.value = false;
  1296.   mlist.setAttributeNode(r);
  1297.   let u = document.createAttribute("unread");
  1298.   u.value = 0;
  1299.   mlist.setAttributeNode(u);
  1300.   return mlist;
  1301. }
  1302.  
  1303. function createSettingsWindow(){
  1304.   let settingsWindow = document.createElement("div");
  1305.   settingsWindow.style.position = "fixed";
  1306.   settingsWindow.style.left = (document.getElementsByClassName("drrrToggle")[0].getBoundingClientRect().left)+"px";
  1307.   settingsWindow.style.width = "170px";
  1308.   settingsWindow.style.top = "16px";
  1309.   settingsWindow.style.display = "none";
  1310.   settingsWindow.style.background = "#EEEEEE";
  1311.   settingsWindow.style.border = "4px solid #FEFEFE";
  1312.   document.body.appendChild(settingsWindow);
  1313.  
  1314.   let label = document.createElement("div");
  1315.   label.innerHTML = "Volume";
  1316.   label.style.position = "relative";
  1317.   label.style.transform = "translate(-50%)";
  1318.   label.style.left = "50%";
  1319.   label.style.width = "-moz-max-content";
  1320.   label.style.maxWidth = "fit-content";
  1321.   settingsWindow.appendChild(label);
  1322.   let volumeSlider = document.createElement("input");
  1323.   volumeSlider.type = "range";
  1324.   volumeSlider.step = "any";
  1325.   volumeSlider.min = 1;
  1326.   volumeSlider.max = 9;
  1327.   volumeSlider.value = 3;
  1328.   volumeSlider.style.width = "160px";
  1329.   volumeSlider.style.position = "relative";
  1330.   volumeSlider.style.transform = "translate(-50%)";
  1331.   volumeSlider.style.left = "50%";
  1332.   volumeSlider.id = "volumeSlider";
  1333.   settingsWindow.appendChild(volumeSlider);
  1334.   let volumeBox = document.createElement("input");
  1335.   volumeBox.type = "number";
  1336.   volumeBox.step = "any";
  1337.   volumeBox.max = 300;
  1338.   volumeBox.min = 100/3;
  1339.   volumeBox.value = 100;
  1340.   volumeBox.style.width = "66px";
  1341.   volumeBox.style.position = "relative";
  1342.   volumeBox.style.transform = "translate(-50%)";
  1343.   volumeBox.style.left = "50%";
  1344.   settingsWindow.appendChild(volumeBox);
  1345.  
  1346.   volumeSlider.oninput = ()=>{volumeBox.value = volumeSlider.value*100/3;};
  1347.   volumeBox.oninput = ()=>{volumeSlider.value = volumeBox.value*3/100;};
  1348.   volumeSlider.onchange = ()=>{augain.gain.value = volumeSlider.value; saveCookie("sound",(document.getElementsByClassName("drrrToggle")[2].getAttribute("on"))+"-"+volumeSlider.value);};
  1349.   volumeBox.onchange = volumeSlider.onchange;
  1350.  
  1351.   let soundSetting = getCookie("sound");
  1352.   if(soundSetting)
  1353.     soundSetting = soundSetting.split("-")[1];
  1354.   else{
  1355.     soundSetting = "1";
  1356.     saveCookie("sound","off-1");
  1357.   }
  1358.   volumeSlider.value = parseFloat(soundSetting);
  1359.   volumeBox.value = volumeSlider.value*100/3;
  1360.   volumeSlider.onchange();
  1361.  
  1362.   let inflateSetting = getCookie("inflate");
  1363.   let inflateOn = "";
  1364.   let inflateFPS = 0;
  1365.   if(inflateSetting){
  1366.     inflateOn = inflateSetting.split("-")[0];
  1367.     inflateFPS = inflateSetting.split("-")[1];
  1368.   }else{
  1369.     saveCookie("inflate","true");
  1370.     inflateOn = "true";
  1371.     inflateFPS = 30;
  1372.   }
  1373.  
  1374.   let br = document.createElement("br");
  1375.   settingsWindow.appendChild(br);
  1376.  
  1377.   let inflateBox = document.createElement("input");
  1378.   inflateBox.type = "checkbox";
  1379.   inflateBox.name = "inflateSetting";
  1380.   inflateBox.checked = inflateOn=="true";
  1381.   inflateBox.id = "inflateSetting";
  1382.   let inflateLabel = document.createElement("label");
  1383.   inflateLabel.forHTML = "inflateSetting";
  1384.   inflateLabel.innerHTML = "Inflating Bubbles";
  1385.   let inflateTable = document.createElement("table");
  1386.   let inflateTr = document.createElement("tr");
  1387.   let inflateTd1 = document.createElement("td");
  1388.   let inflateTd2 = document.createElement("td");
  1389.   inflateTd1.appendChild(inflateLabel);
  1390.   inflateTd2.appendChild(inflateBox);
  1391.   inflateTr.appendChild(inflateTd1);
  1392.   inflateTr.appendChild(inflateTd2);
  1393.   inflateTable.appendChild(inflateTr);
  1394.   settingsWindow.appendChild(inflateTable);
  1395.   let inflateFPSLabel = document.createElement("div");
  1396.   inflateFPSLabel.innerHTML = "FPS";
  1397.   inflateFPSLabel.style.position = "relative";
  1398.   inflateFPSLabel.style.transform = "translate(-50%)";
  1399.   inflateFPSLabel.style.left = "50%";
  1400.   inflateFPSLabel.style.width = "-moz-max-content";
  1401.   inflateFPSLabel.style.maxWidth = "fit-content";
  1402.   settingsWindow.appendChild(inflateFPSLabel);
  1403.   let inflateFPSSlider = document.createElement("input");
  1404.   inflateFPSSlider.type = "range";
  1405.   inflateFPSSlider.step = 1;
  1406.   inflateFPSSlider.min = 5;
  1407.   inflateFPSSlider.max = 250;
  1408.   inflateFPSSlider.value = inflateFPS?inflateFPS:30;
  1409.   inflateFPSSlider.style.width = "160px";
  1410.   inflateFPSSlider.style.position = "relative";
  1411.   inflateFPSSlider.style.transform = "translate(-50%)";
  1412.   inflateFPSSlider.style.left = "50%";
  1413.   inflateFPSSlider.id = "inflateFPSSlider";
  1414.   settingsWindow.appendChild(inflateFPSSlider);
  1415.   let inflateFPSBox = document.createElement("input");
  1416.   inflateFPSBox.type = "number";
  1417.   inflateFPSBox.step = "any";
  1418.   inflateFPSBox.max = 250;
  1419.   inflateFPSBox.min = 5;
  1420.   inflateFPSBox.value = inflateFPS?inflateFPS:30;
  1421.   inflateFPSBox.style.width = "66px";
  1422.   inflateFPSBox.style.position = "relative";
  1423.   inflateFPSBox.style.transform = "translate(-50%)";
  1424.   inflateFPSBox.style.left = "50%";
  1425.   settingsWindow.appendChild(inflateFPSBox);
  1426.  
  1427.   inflateBox.onchange = ()=>{saveCookie("inflate",""+inflateBox.checked+"-"+inflateFPSSlider.value);};
  1428.   inflateFPSBox.oninput = ()=>{inflateFPSSlider.value = inflateFPSBox.value;};
  1429.   inflateFPSSlider.oninput = ()=>{inflateFPSBox.value = inflateFPSSlider.value;};
  1430.   inflateFPSBox.onchange = ()=>{inflateBox.onchange();};
  1431.   inflateFPSSlider.onchange = ()=>{inflateBox.onchange();};
  1432.  
  1433.   return settingsWindow;
  1434. }
  1435.  
  1436. function getCookie(name){
  1437.   let cookies = document.cookie.split(";");
  1438.   for(let i=0;i<cookies.length;i++){
  1439.     let pair = cookies[i].split("=");
  1440.     if(pair[0] == " "+name){
  1441.       return pair[1];
  1442.     }
  1443.   }
  1444.   return null;
  1445. }
  1446.  
  1447. function saveCookie(name,value){
  1448.   let date = new Date();
  1449.   date.setTime(date.getTime()+(1000*60*60*24*365));
  1450.   document.cookie = name+"="+value+"; expires="+encodeURIComponent(date.toUTCString())+";"
  1451. }
  1452.  
  1453. async function animateNewMessage(reply,replyBubble,mb,height,width,nameHeight,i,j=0,startTime=new Date()){
  1454.   let thisTime = new Date();
  1455.   let fps = document.getElementById("inflateFPSSlider")?document.getElementById("inflateFPSSlider").value:30;
  1456.   let ms = Math.floor(1000/fps);
  1457.   if(thisTime.value<=startTime.value)
  1458.     thisTime = new Date(startTime.value+ms);
  1459.   if(i>200){
  1460.     reply.style.marginBottom = mb+"px";
  1461.     replyBubble.style.width = "auto";
  1462.     replyBubble.style.height = "auto";
  1463.     replyBubble.style.borderWidth = "4px";
  1464.     replyBubble.children[0].style.fontSize = "18px";
  1465.     replyBubble.children[0].style.lineHeight = "20px";
  1466.     replyBubble.children[0].style.display = "block";
  1467.     replyBubble.children[1].style.display = "block";
  1468.     return;
  1469.   }
  1470.   let overpop = 1.1;
  1471.   setTimeout(animateNewMessage,ms,reply,replyBubble,mb,height,width,nameHeight,i+6*(thisTime-startTime)/4,j,thisTime);
  1472.   replyBubble.style.width = (width*overpop*i/200)+"px"
  1473.   replyBubble.style.height = (height*overpop*i/200)+"px";
  1474.   replyBubble.style.borderWidth = (4*overpop*i/200)+"px"
  1475.   replyBubble.children[0].style.display = "none";
  1476.   replyBubble.children[1].style.display = "none";
  1477.   if(height*overpop*i/200>18*2){
  1478.     if(j == 0)
  1479.       j = i;
  1480.     replyBubble.children[0].style.display = "block";
  1481.     replyBubble.children[1].style.display = "block";
  1482.     replyBubble.children[0].style.fontSize = (18*overpop*(i-j)/(200-j))+"px";
  1483.     replyBubble.children[0].style.lineHeight = (20*overpop*(i-j)/(200-j))+"px";
  1484.   }
  1485.   reply.style.marginBottom = Math.min(nameHeight,Math.max(58+(nameHeight+8)*1.5-replyBubble.offsetHeight,0))+"px";
  1486. }
  1487.  
  1488. function formatSpan(m){
  1489.   let strike = String.fromCharCode(0x1E);
  1490.   let italic = String.fromCharCode(0x1D);
  1491.   let mono = String.fromCharCode(0x11);
  1492.   let mo = m.getAttribute("class")?m.getAttribute("class"):"";
  1493.   m = m.innerHTML;
  1494.   if(m.match(new RegExp("("+mono+"|"+italic+"|"+strike+")"))){
  1495.     let ind = Math.min(io(m,mono),io(m,italic),io(m,strike));
  1496.     let ms = m.slice(ind);
  1497.     let mc = mo.match(/Xc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1498.     let mb = mo.match(/Xbc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xbc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1499.     m = m.slice(0,ind)+getFormatted(ms,mo.match(/Xu/),mo.match(/Xb$/),mc,mb);
  1500.   }else{
  1501.     let mc = mo.match(/Xc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1502.     let mb = mo.match(/Xbc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xbc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1503.     let mtd = ""+(mo.match(/Xu/)?" text-decoration: underline;":"");
  1504.     let mf = ""+mtd+(mo.match(/Xb$/)?" font-weight: bold;":"");
  1505.     m = "<span style='color:"+mc+"; background-color:"+mb+";"+mf+"'>"+m+"</span>";
  1506.   }
  1507.   return m;
  1508. }
  1509.  
  1510. function io(m,f){
  1511.   return Math.sign(m.indexOf(f))>-1?m.indexOf(f):100000;
  1512. }
  1513.  
  1514. function getFormatted(m,u,b,cf,cb){
  1515.   let strike = String.fromCharCode(0x1E);
  1516.   let italic = String.fromCharCode(0x1D);
  1517.   let mono = String.fromCharCode(0x11);
  1518.   if(!m)
  1519.     return "";
  1520.   let c = m.charAt(0);
  1521.   let sp = "<span style='text-decoration:"+((c==strike?"line-through ":"")+(u?"underline":"")+";")+(c==italic?"font-style: italic; ":"")+(c==mono?"font-family: monospace;":"")+(cf?" color: "+cf+";":"")+(cb?" background-color: "+cb+";":"")+"'>";
  1522.   m = m.substring(1);
  1523.   if(m.match(new RegExp("("+strike+"|"+italic+"|"+mono+")"))){
  1524.     let ind = Math.min(io(m,mono),io(m,italic),io(m,strike));
  1525.     let ms = m.slice(ind);
  1526.     m = m.slice(0,ind)+getFormatted(ms,false,false,false,false);
  1527.   }
  1528.   return sp+m+"</span>";
  1529. }
  1530.  
  1531. async function upload(e){
  1532.   e.preventDefault();
  1533.   if(!e.dataTransfer.files[0])
  1534.     return;
  1535.   let r = new FileReader();
  1536.   r.readAsDataURL(e.dataTransfer.files[0]);
  1537.   r.onload = ()=>{
  1538.     let l = request("https://tinyurl.com/api-create.php?url="+r.result);
  1539.     let t = document.getElementsByTagName("textarea")[0];
  1540.     let tstart = t.value.slice(0,t.selectionStart);
  1541.     let tend = t.value.slice(t.selectionStart);
  1542.     t.value = tstart+(tstart.match(/ $/)&&tstart!=""?"":" ")+l+(tend.match(/^ /)?"":" ")+tend;
  1543.   }
  1544. }
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement