diff --git a/files/__main__.py b/files/__main__.py index 8dbfe52c9..388ab2984 100644 --- a/files/__main__.py +++ b/files/__main__.py @@ -58,6 +58,7 @@ app.config['MAIL_USERNAME'] = environ.get("MAIL_USERNAME", "").strip() app.config['MAIL_PASSWORD'] = environ.get("MAIL_PASSWORD", "").strip() app.config['DESCRIPTION'] = environ.get("DESCRIPTION", "DESCRIPTION GOES HERE").strip() app.config['SETTINGS'] = {} +app.config['SQLALCHEMY_DATABASE_URI'] = app.config['DATABASE_URL'] r=redis.Redis(host=environ.get("REDIS_URL", "redis://localhost"), decode_responses=True, ssl_cert_reqs=None) diff --git a/files/assets/css/main.css b/files/assets/css/main.css index 07f8f4780..642264f52 100644 --- a/files/assets/css/main.css +++ b/files/assets/css/main.css @@ -4625,9 +4625,7 @@ img[pat][src^="/pp/"], img[pat][src$="/pic"] { color: #f27d0c !important; font-weight: 800; } -.agendaposter { - text-transform: uppercase !important; -} + code { text-transform: none !important; } diff --git a/files/assets/images/emojis/feather.webp b/files/assets/images/emojis/feather.webp new file mode 100644 index 000000000..aca985455 Binary files /dev/null and b/files/assets/images/emojis/feather.webp differ diff --git a/files/assets/js/emoji_modal.js b/files/assets/js/emoji_modal.js deleted file mode 100644 index f880973fc..000000000 --- a/files/assets/js/emoji_modal.js +++ /dev/null @@ -1,158 +0,0 @@ -const fav = document.getElementById('EMOJIS_favorite') -const search_bar = document.getElementById('emoji_search') -const search_container = document.getElementById('emoji-tab-search') -let emojis = 1 - - -function loadEmojis(form) { - if (emojis == 1) - { - const xhr = new XMLHttpRequest(); - xhr.open("GET", '/marsey_list'); - xhr.setRequestHeader('xhr', 'xhr'); - var f = new FormData(); - xhr.onload = function() { - emojis = { - 'marsey': JSON.parse(xhr.response), - - 'marseyalphabet': ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','exclamationpoint','space','period','questionmark'], - - 'platy': ['platytrans','platyfuckyou','plarsy','platyabused','platyblizzard','platyboxer','platydevil','platyfear','platygirlmagic','platygolong','platyhaes','platyking','platylove','platyneet','platyold','platypatience','platypopcorn','platyrich','platysarcasm','platysilly','platysleeping','platythink','platytired','platytuxedomask','platyblush','platybruh','platycaveman','platycheer','platydown','platyeyes','platyheart','platylol','platymicdrop','platynooo','platysalute','platyseethe','platythumbsup','platywave'], - - 'tay': ['taylove','tayaaa','tayadmire','taycat','taycelebrate','taychefkiss','taychristmas','tayclap','taycold','taycrown','tayflex','tayflirt','taygrimacing','tayhappy','tayheart','tayhmm','tayhuh','tayhyperdab','tayjammin','taylaugh','taymindblown','tayno','taynod','taypeace','taypray','tayrun','tayscrunch','tayshake','tayshrug','taysilly','tayslide','taysmart','taystop','taytantrum','taytea','taythink','tayvibin','taywhat','taywine','taywine2','taywink','tayyes'], - - 'classic': ['flowers','scootlgbt','idhitit','2thumbsup','aliendj','ambulance','angry','angrywhip','argue','aroused','ashamed','badass','banana','band','banghead','batman','bigeyes','bite','blind','blowkiss','blush','bong','bounce','bow','breakheart','bs','cartwheel','cat','celebrate','chainsaw','cheers','clap','cold','confused','crazyeyes','cry','cthulhu','cute','laughing','daydream','ddr','deadpool','devilsmile','diddle','die','distress','disturbing','dizzy','domo','doughboy','drink','drool','dudeweedlmao','edward','electro','elephant','embarrassed','emo','emo2','evil','evilclown','evilgrin','facepalm','fap','flamethrower','flipbird','flirt','frown','gasp','glomp','go','gooby','grr','gtfo','guitar','haha','handshake','happydance','headbang','heart','heartbeat','hearts','highfive','hmm','hmph','holdhands','horny','hug','hugging','hugs','hump','humpbed','hysterical','ily','inlove','jason','jawdrop','jedi','jester','kaboom','kick','kiss','kitty','laughchair','lick','link','lol','lolbeat','loving','makeout','medal','megaman','megamanguitar','meow','metime','mooning','mummy','na','nauseous','nervous','ninja','nod','nono','omg','onfire','ooo','orly','tongueout','paddle','panda','pandabutt','paranoid','party','pat','peek','pikachu','pimp','plzdie','poke','popcorn','pout','probe','puke','punch','quote','raccoon','roar','rofl','roflmao','rolleyes','sad','sadeyes','sadhug','samurai','sarcasm','scoot','scream','shmoopy','shrug','skull','slap','slapfight','sleepy','smackfish','smackhead','smh','smile','smoke','sonic','spank','sparta','sperm','spiderman','stab','star','stare','stfu','suicide','surprisehug','suspicious','sweat','swordfight','taco','talk2hand','tantrum','teehee','thinking','threesome','throw','throwaway','tickle','typing','uhuh','vampbat','viking','violin','vulgar','wah','wat','whip','whipping','wink','witch','wizard','woah','worm','woo','work','worship','wow','xd','yay','zzz'], - - 'rage': ['trolldespair','clueless','troll','bitchplease','spit','challengeaccepted','contentiouscereal','cryingatcuteness','derp','derpcornsyrup','derpcrying','derpcute','derpdumb','derpeuphoria','derpinahd','derpinapokerface','derpinasnickering','derpprocessing','derprealization','derpsnickering','derptalking','derpthinking','derpthumbsup','derpunimpressed','derpwhy','donotwant','epicfacefeatures','fancywithwine','fffffffuuuuuuuuuuuu','flipthetable','foreveralone','foreveralonehappy','hewillnever','idontknow','interuptedreading','iseewhatyoudidthere','killherkillher','ledesire','leexcited','legenius','lelolidk','lemiddlefinger','lemindblown','leokay','lepanicrunning','lepokerface','lepokerface2','lerageface','leseriousface','likeaboss','lolface','longwhiskers','manymiddlefingers','megusta','motherfucker','motherofgod','mysides','ohgodwhy','pervertedspiderman','picard','ragestrangle','rukiddingme','tfwyougettrolled','trollolol','truestorybro','xallthey','yuno'], - - 'wojak': ['purerage','naziseethe','holdupjak','ethottalking','chadwomanasian','chadwomanblack','chadwomanlatinx','chadwomannordic','trumpjaktalking','rdramajanny','soyreddit','doomerboy','npcsupport','npcoppse','grugthink','soyconsoomer','soyjaktalking','soyquack','tradboy','sciencejak','soyjakanimeglasses','soymad','boomerportrait','soycry','punchjak','seethejak','chadyes','chadno','abusivewife','ancap','bardfinn','bloomer','boomer','boomermonster','brainletbush','brainletcaved','brainletchair','brainletchest','brainletmaga','brainletpit','chad','chadarab','chadasian','chadblack','chadjesus','chadjew','chadjihadi','chadlatino','chadlibleft','chadnordic','chadsikh','chadusa','coomer','doomer','doomerfront','doomergirl','ethot','fatbrain','fatpriest','femboy','gogetter','grug','monke','nazijak','npc','npcfront','npcmaga','psychojak','ragejak','ragemask','ramonajak','soyjackwow','soyjak','soyjakfront','soyjakhipster','soyjakmaga','soyjakyell','tomboy','zoomer','zoomersoy'], - - 'flags': ['russia','niger','lgbt','animesexual','blacknation','blm','blueline','dreamgender','fatpride','incelpride','israel','kazakhstan','landlordlove','scalperpride','superstraight','trans','translord','transracial','usa'], - - 'wolf': ['wombiezolf','wolfdramanomicon','wolfamogus','wolfmarine','wolfromulusremus','wolfrope','wolftinfoil','wolfmarseymask','wolfputin','wolfdrama','wolfcumjar','wolflgbt','wolfmarseyhead','wolfnoir','wolfsherifssmoking','wolftrans','wolfvaporwave','wolfangry','wolfbrains','wolfcry','wolfdead','wolfdevilish','wolffacepalm','wolfhappy','wolfidea','wolfkoala','wolflaugh','wolflove','wolfmeditate','wolfphone','wolfrainbow','wolfroses','wolfsad','wolfsfear','wolfsleep','wolftear','wolfthink','wolfthumbsup','wolfupsidedown','wolfvictory','wolfwave','wolfwink'], - - 'misc': ['chadyescapy','chadnocapy','capygitcommit','capysneedboat','chadbasedcapy','chadcopecapy','chaddilatecapy','chaddonekingcapy','chaddonequeencapy','chadfixedkingcapy','chadfixedqueencapy','chadokcapy','chadseethecapy','chadsneedcapy','chadthankskingcapy','chadthanksqueencapy','sherpat','xdoubt','gigachadjesus','yotsubafish','yotsubalol','sigmatalking','zoroarkconfused','zoroarkhappy','zoroarkpout','zoroarksleepy','casanovanova','deuxwaifu','flairlessmong','hardislife','redditgigachad','rfybear','etika','sneed','retardedchildren','bruh','autism','doot','kylieface','queenyes','wholesomeseal','gigachadglow','gigachadorthodox','gigachad','gigachad2','gigachad3'] - } - - cringetopia = document.getElementById('EMOJIS_cringetopia') - if (cringetopia) - emojis['cringetopia'] = ['19dollarfortnitecard','ahawow','ahayeah','alex','amogus','amogusbubble','amongpoop','amusing','anarchy','angelblob','angry','angryman','awaakesoyjack','backseatmodding','based','bassproshop','berkfail','berkstache','bert','bestmovieever','binface','blackpill','blingbob','blingbobhd','bluepill','booba','boof','boohoo','brainlet','britishmoment','brownnose','bruh','bruhsmoke','brunocheers','brunopog','bussin','byelol','canigetmod','car','cereal','cerkies','chad','chaddiscordmoderator','chadstare','cheeks','cheers','cheesed','cheeseu','chungus','chunky','clueless','cocka','cokeza','comeagain','coom','cope','coping','cryaboutit','cryingcool','cryrage','cum','cummies','cutelittledude','da','dab','dababy','datrolly','davyree','dayum','death','delight','disbelief','disgostang','disgust','donotdisturb','doritoberk','downisrael','downvote','downwert','drbob','drumtime','erotic','evilblob','face','facepalm','factsandlogic','fake','fatcryrage','fear','fedora','fistbumpl','fistbumpr','fjalsunna','floppacheers','floppagun','fluoride','flushspin','funwa','furrymurder','gas','getajob','gigachad','gigajammin','godiwishthatwereme','gogetter','goingcrazy','goinginsane','gold','gone','goofy','goonpog','goteem','grabhand','grind','gun','hahawyd','hatred','heart','heh','hehehe','hesapeonyouknow','hesepsteinyouknow','hesgayyouknow','hesretardedyouknow','hesrightyouknow','hitormiss','holy','hopeless','horny','hot','hulk','hunky','iloveyou','insanity','ipgrabber','irantroll','isawthat','itendsnow','itsover','itsoverseal','jewbob','joebiden','josh','kanyerant','keith','kill','kissin','laughing','lean','leftgun','lessgooooooooooo','lessgoooooooooooo','letsfuckinggooooooooooo','lick','light','like','littledrummerboy','lmao','logo','logoff','lolrage','love','madman','malding','maldinggif','manpain','march','me_lon','menendez','mewhen','mf','mhm','mhmdoubt','mlady','murder','nefarious','nefariousacts','newport','newport~1','nibburger_king','nigerianreaction','nooo','noooo','noose','noperms','normalize','ohwow','okboomer','orange','pain','pardon','payne','peepotalk','pepecringe','pepecringe2','pepeherrington','peperagecry','pepoboner','pepoojamm','phillip','pitchfork','pleading','please','pouroneout40','praiseallah','prayge','psycho','quagmirelet','ratio','real','really','redditnation','redpill','redwojack','regice','ricardosmile','ripbozo','sad','sadcat','sadge','sadtroll','salute','scare','schizothread','secretside','sheesh','shh','shocked','shotty','sigma','sigmamale','sigmasnap','simpjack','siren','skill_issue','slime','slow','smoketime','sniff','society','society2','soy','spit','spit2','splendid','squidwardno','stare','stare1','stfu','stoppedwert','stopwert','susamogus','suscoin','susge','susiety','tacobell','tempest','thanosd','thanoslol','thistbh','thonk','tiktokcoin','tiresome','tm06','troll','trollcrazy','trollcrazyfurry','trollcrazypoint','trollcrazyrussia','trollcrazyukraine','trolldisappointed','trollface','trollinsane','trollsus','truetrue','turbobrainlet','tuvvokmoment','twetwe','unblockme','updonda','upiran','upvote','upwert','vengeance','virgin','wa','waaaah','wallstreet','wertegg','wertpinion','what','whatdeath','whensus','wholesome','wolfcode','womanmoment','woohoo','wtff','xplode','yeeeees','yeet','yes','yeshoney','yet','you','zombie_phillip'] - - loadEmojis(form); - } - xhr.send(f); - } - else { - fav.setAttribute('data-form-destination', form) - - const commentBox = document.getElementById(form) - commentBox.setAttribute('data-curr-pos', commentBox.selectionStart); - - if (fav.innerHTML == "") - { - let str = "" - const favorite_emojis = JSON.parse(localStorage.getItem("favorite_emojis")) - if (favorite_emojis) - { - const sortable = Object.fromEntries( - Object.entries(favorite_emojis).sort(([,a],[,b]) => b-a) - ); - - for (const emoji of Object.keys(sortable).slice(0, 25)) - str += `` - - fav.innerHTML = str - } - } - if (search_bar.value == "") { - search_container.innerHTML = "" - document.getElementById("tab-content").classList.remove("d-none"); - if (document.getElementById("EMOJIS_marsey").innerHTML == "") - { - for (const [k, v] of Object.entries(emojis)) { - let container = document.getElementById(`EMOJIS_${k}`) - let str = '' - if (k == 'marsey') - { - for (const e of v) { - let k = e.toLowerCase().split(" : ")[0]; - str += ``; - } - } - else { - for (const e of v) { - str += ``; - } - } - - container.innerHTML = str - } - } - } - else { - let str = '' - for (const [key, value] of Object.entries(emojis)) { - if (key == "marsey") - { - for (const e of value) { - let arr = e.toLowerCase().split(" : "); - let k = arr[0]; - let v = arr[1]; - if (str.includes(`'${k}'`)) continue; - if (k.match(search_bar.value.toLowerCase()) || search_bar.value.toLowerCase().match(k) || v.match(search_bar.value.toLowerCase())) { - str += ``; - } - } - } - else if (key != "marseyalphabet") - { - for (const e of value) { - if (e.match(search_bar.value.toLowerCase()) || search_bar.value.toLowerCase().match(e)) { - str += ``; - } - } - } - } - document.getElementById("tab-content").classList.add("d-none"); - search_container.innerHTML = str - } - search_bar.oninput = function () { - loadEmojis(form); - }; - } -} - - - - -function getEmoji(searchTerm) { - const form = fav.getAttribute('data-form-destination') - const commentBox = document.getElementById(form) - const old = commentBox.value; - const curPos = parseInt(commentBox.getAttribute('data-curr-pos')); - - const firstHalf = old.slice(0, curPos) - const lastHalf = old.slice(curPos) - - let emoji = ':' + searchTerm + ':' - const previousChar = firstHalf.slice(-1) - if (firstHalf.length > 0 && previousChar !== " " && previousChar !== "\n") { - emoji = " " + emoji - } - if (lastHalf.length > 0 && lastHalf[0] !== " ") { - emoji = emoji + " " - } - - commentBox.value = firstHalf + emoji + lastHalf; - - const newPos = curPos + emoji.length - - commentBox.setAttribute('data-curr-pos', newPos.toString()); - - commentBox.dispatchEvent(new Event('input')); - - const favorite_emojis = JSON.parse(localStorage.getItem("favorite_emojis")) || {} - if (favorite_emojis[searchTerm]) favorite_emojis[searchTerm] += 1 - else favorite_emojis[searchTerm] = 1 - localStorage.setItem("favorite_emojis", JSON.stringify(favorite_emojis)) -} diff --git a/files/assets/js/marked.custom.js b/files/assets/js/marked.custom.js new file mode 100644 index 000000000..d0958bb53 --- /dev/null +++ b/files/assets/js/marked.custom.js @@ -0,0 +1,221 @@ +function appendToken(parentElement, childToken) { + var childElement = tokenToHTMLElement(childToken); + if (typeof childElement === 'string') { + parentElement.textContent += childElement; + } else if (childElement !== null) { + parentElement.appendChild(childElement) + } +} + +function appentTextOrElement(parentElement, textOrElement) { + if (typeof textOrElement === 'string') { + parentElement.textContent += textOrElement; + } else { + parentElement.appendChild(textOrElement); + } +} + +function motteSpecialMarkdown(text) { + if (typeof text !== 'string') { + return ''; + } + + var spoilerMatch = text.match(/^(.*?)\|\|(.*?)\|\|(.*)$/); + + if (spoilerMatch) { + var left = spoilerMatch[1]; + var mid = spoilerMatch[2]; + var right = spoilerMatch[3]; + var parentSpan = document.createElement('span'); + var leftSpan = document.createElement('span'); + var spoilerSpan = document.createElement('span'); + var rightSpan = document.createElement('span'); + spoilerSpan.textContent = mid; + spoilerSpan.classList.add('spoiler'); + appentTextOrElement(leftSpan, motteSpecialMarkdown(left)); + appentTextOrElement(rightSpan, motteSpecialMarkdown(right)); + parentSpan.appendChild(leftSpan); + parentSpan.appendChild(spoilerSpan); + parentSpan.appendChild(rightSpan); + return parentSpan; + } else { + return text; + } +} + +function tokenToHTMLElement(token) { + var element = null; + + if (token.type === 'space') { + element = document.createElement('span'); + element.textContent = ' '; + return element; + } else if (typeof token.type === 'undefined' || token.type === 'text') { + element = document.createElement('span'); + appentTextOrElement(element, motteSpecialMarkdown(token.text)); + return element; + } else if (token.type === 'hr') { + return document.createElement('hr'); + } else if (token.type === 'br') { + return document.createElement('br'); + } else if (token.type === 'heading') { + element = document.createElement('h' + Math.floor(Math.max(1, Math.min(6, token.depth)))); + } else if (token.type === 'code') { + element = document.createElement('pre'); + element.setAttribute('data-lang', token.lang); + } else if (token.type === 'list_item') { + element = document.createElement('li'); + } else if (token.type === 'blockquote') { + element = document.createElement('blockquote'); + } else if (token.type === 'list') { + if (token.ordered) { + element = document.createElement('ol'); + } else { + element = document.createElement('ul'); + } + } else if (token.type === 'table') { + var table, thead, tbody, tr, th, td; + table = document.createElement('table'); + table.classList.add('table'); + thead = document.createElement('thead'); + tbody = document.createElement('thead'); + tr = document.createElement('tr'); + for (var x = 0; x < token.header.length; x++) { + th = document.createElement('th'); + appendToken(th, token.header[x]); + tr.appendChild(th); + } + thead.appendChild(tr); + table.appendChild(thead); + for (var y = 0; y < token.rows.length; y++) { + row = token.rows[y]; + tr = document.createElement('tr'); + for (var x = 0; x < row.length; x++) { + td = document.createElement('td'); + appendToken(td, row[x]); + tr.appendChild(td); + } + tbody.appendChild(tr); + } + table.appendChild(tbody); + return table; + } else if (token.type === 'paragraph') { + element = document.createElement('p'); + } else if (token.type === 'div') { + element = document.createElement('div'); + } else if (token.type === 'em') { + element = document.createElement('i'); + } else if (token.type === 'strong') { + element = document.createElement('b'); + } else if (token.type === 'del') { + element = document.createElement('del'); + } else if (token.type === 'codespan') { + element = document.createElement('code'); + element.textContent = token.text; + return element; + } else if (token.type === 'escape') { + } else if (token.type === 'link') { + element = document.createElement('a'); + element.setAttribute('href', token.href); + element.textContent = token.text; + return element; + } else if (token.type === 'image') { + element = document.createElement('img'); + element.setAttribute('src', token.href); + element.setAttribute('alt', token.text); + return element; + } else { + console.log(token); + element = document.createElement('div'); + } + + var children = (token.tokens || token.items || []); + if (element !== null && children.length > 0) { + for (var i = 0; i < children.length; i++) { + var childElement = tokenToHTMLElement(children[i]); + if (childElement.outerHTML.match(/"spoiler"/g)) { + console.log(element, token, childElement, children[i]); + } + appendToken(element, children[i]); + } + } else if (element.children.length === 0 && element.textContent === '') { + element.textContent += token.text; + } + + return element; +} + +function safeMarkdown(input) { + var seenTokens = []; + var outputToken = {"type": "div", "raw": input, "text": "", "tokens": []}; + function seeRecursive(token) { + seenTokens.push(token); + var children = ( + token.tokens + || token.items + || (token.header||[]).concat(token.rows||[]) + || [] + ); + if (token.header) { + children = children.concat(token.header); + } + for (var y = 0; y < (token.rows||[]).length; y++) { + children = children.concat(token.rows[y]); + } + for (var i = 0; i < children.length; i++) { + seeRecursive(children[i]); + } + } + marked.use({ + walkTokens: function(token) { + if (!seenTokens.includes(token)) { + outputToken.tokens.push(token); + seeRecursive(token); + } + }, + }); + marked(input); + marked.use({ + walkTokens: false, + tokenizer: false, + }); + + [ 'escape', 'del', ]; + + return tokenToHTMLElement(outputToken); +} + +setTimeout(() => markdown('post-text','preview'), 200); + +function markdown(first, second) { + var input = document.getElementById(first).value; + + var dest = document.getElementById(second); + for (var i = 0; i < dest.children.length; i++) { + dest.removeChild(dest.children[i]); + } + document.getElementById(second).appendChild(safeMarkdown(input)); +} + +function charLimit(form, text) { + + var input = document.getElementById(form); + + var text = document.getElementById(text); + + var length = input.value.length; + + var maxLength = input.getAttribute("maxlength"); + + if (length >= maxLength) { + text.style.color = "#E53E3E"; + } + else if (length >= maxLength * .72){ + text.style.color = "#FFC107"; + } + else { + text.style.color = "#A0AEC0"; + } + + text.innerText = length + ' / ' + maxLength; +} diff --git a/files/assets/js/marked.js b/files/assets/js/vendor/marked.js similarity index 62% rename from files/assets/js/marked.js rename to files/assets/js/vendor/marked.js index fa7b38157..26807df6e 100644 --- a/files/assets/js/marked.js +++ b/files/assets/js/vendor/marked.js @@ -1,71 +1 @@ -!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).marked=t()}(this,(function(){"use strict";function e(e,t){for(var u=0;ue.length)&&(t=e.length);for(var u=0,n=new Array(t);u=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n={exports:{}};function r(){return{baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}n.exports={defaults:{baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1},getDefaults:r,changeDefaults:function(e){n.exports.defaults=e}};var i=/[&<>"']/,s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,o={"&":"&","<":"<",">":">",'"':""","'":"'"},D=function(e){return o[e]};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,(function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""}))}var p=/(^|[^\[])\^/g;var f=/[^\w:]/g,g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var F={},A=/^[^:]+:\/*[^/]*$/,d=/^([^:]+:)[\s\S]*$/,C=/^([^:]+:\/*[^/]*)[\s\S]*$/;function k(e,t){F[" "+e]||(A.test(e)?F[" "+e]=e+"/":F[" "+e]=E(e,"/",!0));var u=-1===(e=F[" "+e]).indexOf(":");return"//"===t.substring(0,2)?u?t:e.replace(d,"$1")+t:"/"===t.charAt(0)?u?t:e.replace(C,"$1")+t:e+t}function E(e,t,u){var n=e.length;if(0===n)return"";for(var r=0;r=0&&"\\"===u[r];)n=!n;return n?"|":" |"})).split(/ \|/),n=0;if(u[0].trim()||u.shift(),u[u.length-1].trim()||u.pop(),u.length>t)u.splice(t);else for(;u.length1;)1&t&&(u+=e),t>>=1,e+=e;return u+e},T=n.exports.defaults,R=_,I=y,Z=x,q=z;function O(e,t,u,n){var r=t.href,i=t.title?Z(t.title):null,s=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){n.state.inLink=!0;var l={type:"link",raw:u,href:r,title:i,text:s,tokens:n.inlineTokens(s,[])};return n.state.inLink=!1,l}return{type:"image",raw:u,href:r,title:i,text:Z(s)}}var L=function(){function e(e){this.options=e||T}var t=e.prototype;return t.space=function(e){var t=this.rules.block.newline.exec(e);if(t)return t[0].length>1?{type:"space",raw:t[0]}:{raw:"\n"}},t.code=function(e){var t=this.rules.block.code.exec(e);if(t){var u=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?u:R(u,"\n")}}},t.fences=function(e){var t=this.rules.block.fences.exec(e);if(t){var u=t[0],n=function(e,t){var u=e.match(/^(\s+)(?:```)/);if(null===u)return t;var n=u[1];return t.split("\n").map((function(e){var t=e.match(/^\s+/);return null===t?e:t[0].length>=n.length?e.slice(n.length):e})).join("\n")}(u,t[3]||"");return{type:"code",raw:u,lang:t[2]?t[2].trim():t[2],text:n}}},t.heading=function(e){var t=this.rules.block.heading.exec(e);if(t){var u=t[2].trim();if(/#$/.test(u)){var n=R(u,"#");this.options.pedantic?u=n.trim():n&&!/ $/.test(n)||(u=n.trim())}var r={type:"heading",raw:t[0],depth:t[1].length,text:u,tokens:[]};return this.lexer.inline(r.text,r.tokens),r}},t.hr=function(e){var t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}},t.blockquote=function(e){var t=this.rules.block.blockquote.exec(e);if(t){var u=t[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:t[0],tokens:this.lexer.blockTokens(u,[]),text:u}}},t.list=function(e){var t=this.rules.block.list.exec(e);if(t){var u,n,r,i,s,l,a,o,D,c,h=t[1].trim(),p=h.length>1,f={type:"list",raw:"",ordered:p,start:p?+h.slice(0,-1):"",loose:!1,items:[]};h=p?"\\d{1,9}\\"+h.slice(-1):"\\"+h,this.options.pedantic&&(h=p?h:"[*+-]");for(var g=new RegExp("^( {0,3}"+h+")((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))");e&&!this.rules.block.hr.test(e)&&(t=g.exec(e));){D=t[2].split("\n"),this.options.pedantic?(i=2,c=D[0].trimLeft()):(i=t[2].search(/[^ ]/),i=t[1].length+(i>4?1:i),c=D[0].slice(i-t[1].length)),l=!1,u=t[0],!D[0]&&/^ *$/.test(D[1])&&(u=t[1]+D.slice(0,2).join("\n")+"\n",f.loose=!0,D=[]);var F=new RegExp("^ {0,"+Math.min(3,i-1)+"}(?:[*+-]|\\d{1,9}[.)])");for(s=1;s=i)&&o.trim()){u=t[1]+D.slice(0,s).join("\n")+"\n";break}c+="\n"+o.slice(i)}else o.trim()||(l=!0),o.search(/[^ ]/)>=i?c+="\n"+o.slice(i):c+="\n"+o}f.loose||(a?f.loose=!0:/\n *\n *$/.test(u)&&(a=!0)),this.options.gfm&&(n=/^\[[ xX]\] /.exec(c))&&(r="[ ] "!==n[0],c=c.replace(/^\[[ xX]\] +/,"")),f.items.push({type:"list_item",raw:u,task:!!n,checked:r,loose:!1,text:c}),f.raw+=u,e=e.slice(u.length)}f.items[f.items.length-1].raw=u.trimRight(),f.items[f.items.length-1].text=c.trimRight(),f.raw=f.raw.trimRight();var A=f.items.length;for(s=0;s/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(t[0]):Z(t[0]):t[0]}},t.link=function(e){var t=this.rules.inline.link.exec(e);if(t){var u=t[2].trim();if(!this.options.pedantic&&/^$/.test(u))return;var n=R(u.slice(0,-1),"\\");if((u.length-n.length)%2==0)return}else{var r=q(t[2],"()");if(r>-1){var i=(0===t[0].indexOf("!")?5:4)+t[1].length+r;t[2]=t[2].substring(0,r),t[0]=t[0].substring(0,i).trim(),t[3]=""}}var s=t[2],l="";if(this.options.pedantic){var a=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(s);a&&(s=a[1],l=a[3])}else l=t[3]?t[3].slice(1,-1):"";return s=s.trim(),/^$/.test(u)?s.slice(1):s.slice(1,-1)),O(t,{href:s?s.replace(this.rules.inline._escapes,"$1"):s,title:l?l.replace(this.rules.inline._escapes,"$1"):l},t[0],this.lexer)}},t.reflink=function(e,t){var u;if((u=this.rules.inline.reflink.exec(e))||(u=this.rules.inline.nolink.exec(e))){var n=(u[2]||u[1]).replace(/\s+/g," ");if(!(n=t[n.toLowerCase()])||!n.href){var r=u[0].charAt(0);return{type:"text",raw:r,text:r}}return O(u,n,u[0],this.lexer)}},t.emStrong=function(e,t,u){void 0===u&&(u="");var n=this.rules.inline.emStrong.lDelim.exec(e);if(n&&(!n[3]||!u.match(/(?:[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/))){var r=n[1]||n[2]||"";if(!r||r&&(""===u||this.rules.inline.punctuation.exec(u))){var i,s,l=n[0].length-1,a=l,o=0,D="*"===n[0][0]?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(D.lastIndex=0,t=t.slice(-1*e.length+l);null!=(n=D.exec(t));)if(i=n[1]||n[2]||n[3]||n[4]||n[5]||n[6])if(s=i.length,n[3]||n[4])a+=s;else if(!((n[5]||n[6])&&l%3)||(l+s)%3){if(!((a-=s)>0)){if(s=Math.min(s,s+a+o),Math.min(l,s)%2){var c=e.slice(1,l+n.index+s);return{type:"em",raw:e.slice(0,l+n.index+s+1),text:c,tokens:this.lexer.inlineTokens(c,[])}}var h=e.slice(2,l+n.index+s-1);return{type:"strong",raw:e.slice(0,l+n.index+s+1),text:h,tokens:this.lexer.inlineTokens(h,[])}}}else o+=s}}},t.codespan=function(e){var t=this.rules.inline.code.exec(e);if(t){var u=t[2].replace(/\n/g," "),n=/[^ ]/.test(u),r=/^ /.test(u)&&/ $/.test(u);return n&&r&&(u=u.substring(1,u.length-1)),u=Z(u,!0),{type:"codespan",raw:t[0],text:u}}},t.br=function(e){var t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}},t.del=function(e){var t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2],[])}},t.autolink=function(e,t){var u,n,r=this.rules.inline.autolink.exec(e);if(r)return n="@"===r[2]?"mailto:"+(u=Z(this.options.mangle?t(r[1]):r[1])):u=Z(r[1]),{type:"link",raw:r[0],text:u,href:n,tokens:[{type:"text",raw:u,text:u}]}},t.url=function(e,t){var u;if(u=this.rules.inline.url.exec(e)){var n,r;if("@"===u[2])r="mailto:"+(n=Z(this.options.mangle?t(u[0]):u[0]));else{var i;do{i=u[0],u[0]=this.rules.inline._backpedal.exec(u[0])[0]}while(i!==u[0]);n=Z(u[0]),r="www."===u[1]?"http://"+n:n}return{type:"link",raw:u[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}},t.inlineText=function(e,t){var u,n=this.rules.inline.text.exec(e);if(n)return u=this.lexer.state.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(n[0]):Z(n[0]):n[0]:Z(this.options.smartypants?t(n[0]):n[0]),{type:"text",raw:n[0],text:u}},e}(),j=w,U=b,P=v,Q={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3}bull)( [^\n]+?)?(?:\n|$)/,html:"^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:j,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Q.def=U(Q.def).replace("label",Q._label).replace("title",Q._title).getRegex(),Q.bullet=/(?:[*+-]|\d{1,9}[.)])/,Q.listItemStart=U(/^( *)(bull) */).replace("bull",Q.bullet).getRegex(),Q.list=U(Q.list).replace(/bull/g,Q.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Q.def.source+")").getRegex(),Q._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Q._comment=/|$)/,Q.html=U(Q.html,"i").replace("comment",Q._comment).replace("tag",Q._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Q.paragraph=U(Q._paragraph).replace("hr",Q.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Q._tag).getRegex(),Q.blockquote=U(Q.blockquote).replace("paragraph",Q.paragraph).getRegex(),Q.normal=P({},Q),Q.gfm=P({},Q.normal,{table:"^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Q.gfm.table=U(Q.gfm.table).replace("hr",Q.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Q._tag).getRegex(),Q.pedantic=P({},Q.normal,{html:U("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Q._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:j,paragraph:U(Q.normal._paragraph).replace("hr",Q.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Q.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var M={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:j,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/^[^_*]*?\_\_[^_*]*?\*[^_*]*?(?=\_\_)|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,rDelimUnd:/^[^_*]*?\*\*[^_*]*?\_[^_*]*?(?=\*\*)|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:j,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~"};M.punctuation=U(M.punctuation).replace(/punctuation/g,M._punctuation).getRegex(),M.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g,M.escapedEmSt=/\\\*|\\_/g,M._comment=U(Q._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),M.emStrong.lDelim=U(M.emStrong.lDelim).replace(/punct/g,M._punctuation).getRegex(),M.emStrong.rDelimAst=U(M.emStrong.rDelimAst,"g").replace(/punct/g,M._punctuation).getRegex(),M.emStrong.rDelimUnd=U(M.emStrong.rDelimUnd,"g").replace(/punct/g,M._punctuation).getRegex(),M._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,M._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,M._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,M.autolink=U(M.autolink).replace("scheme",M._scheme).replace("email",M._email).getRegex(),M._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,M.tag=U(M.tag).replace("comment",M._comment).replace("attribute",M._attribute).getRegex(),M._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,M._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,M._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,M.link=U(M.link).replace("label",M._label).replace("href",M._href).replace("title",M._title).getRegex(),M.reflink=U(M.reflink).replace("label",M._label).getRegex(),M.reflinkSearch=U(M.reflinkSearch,"g").replace("reflink",M.reflink).replace("nolink",M.nolink).getRegex(),M.normal=P({},M),M.pedantic=P({},M.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:U(/^!?\[(label)\]\((.*?)\)/).replace("label",M._label).getRegex(),reflink:U(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",M._label).getRegex()}),M.gfm=P({},M.normal,{escape:U(M.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\.5&&(u="x"+u.toString(16)),n+="&#"+u+";";return n}var Y=function(){function t(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||G,this.options.tokenizer=this.options.tokenizer||new X,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};var t={block:V.normal,inline:H.normal};this.options.pedantic?(t.block=V.pedantic,t.inline=H.pedantic):this.options.gfm&&(t.block=V.gfm,this.options.breaks?t.inline=H.breaks:t.inline=H.gfm),this.tokenizer.rules=t}t.lex=function(e,u){return new t(u).lex(e)},t.lexInline=function(e,u){return new t(u).inlineTokens(e)};var u,n,r,i=t.prototype;return i.lex=function(e){var t;for(e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),this.blockTokens(e,this.tokens);t=this.inlineQueue.shift();)this.inlineTokens(t.src,t.tokens);return this.tokens},i.blockTokens=function(e,t){var u,n,r,i,s=this;for(void 0===t&&(t=[]),this.options.pedantic&&(e=e.replace(/^ +$/gm,""));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((function(n){return!!(u=n.call({lexer:s},e,t))&&(e=e.substring(u.raw.length),t.push(u),!0)}))))if(u=this.tokenizer.space(e))e=e.substring(u.raw.length),u.type&&t.push(u);else if(u=this.tokenizer.code(e))e=e.substring(u.raw.length),!(n=t[t.length-1])||"paragraph"!==n.type&&"text"!==n.type?t.push(u):(n.raw+="\n"+u.raw,n.text+="\n"+u.text,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(u=this.tokenizer.fences(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.heading(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.hr(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.blockquote(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.list(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.html(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.def(e))e=e.substring(u.raw.length),!(n=t[t.length-1])||"paragraph"!==n.type&&"text"!==n.type?this.tokens.links[u.tag]||(this.tokens.links[u.tag]={href:u.href,title:u.title}):(n.raw+="\n"+u.raw,n.text+="\n"+u.raw,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(u=this.tokenizer.table(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.lheading(e))e=e.substring(u.raw.length),t.push(u);else if(r=e,this.options.extensions&&this.options.extensions.startBlock&&function(){var t=1/0,u=e.slice(1),n=void 0;s.options.extensions.startBlock.forEach((function(e){"number"==typeof(n=e.call({lexer:this},u))&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}(),this.state.top&&(u=this.tokenizer.paragraph(r)))n=t[t.length-1],i&&"paragraph"===n.type?(n.raw+="\n"+u.raw,n.text+="\n"+u.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(u),i=r.length!==e.length,e=e.substring(u.raw.length);else if(u=this.tokenizer.text(e))e=e.substring(u.raw.length),(n=t[t.length-1])&&"text"===n.type?(n.raw+="\n"+u.raw,n.text+="\n"+u.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(u);else if(e){var l="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(l);break}throw new Error(l)}return this.state.top=!0,t},i.inline=function(e,t){this.inlineQueue.push({src:e,tokens:t})},i.inlineTokens=function(e,t){var u,n,r,i=this;void 0===t&&(t=[]);var s,l,a,o=e;if(this.tokens.links){var D=Object.keys(this.tokens.links);if(D.length>0)for(;null!=(s=this.tokenizer.rules.inline.reflinkSearch.exec(o));)D.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(o=o.slice(0,s.index)+"["+J("a",s[0].length-2)+"]"+o.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(s=this.tokenizer.rules.inline.blockSkip.exec(o));)o=o.slice(0,s.index)+"["+J("a",s[0].length-2)+"]"+o.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(s=this.tokenizer.rules.inline.escapedEmSt.exec(o));)o=o.slice(0,s.index)+"++"+o.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);for(;e;)if(l||(a=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((function(n){return!!(u=n.call({lexer:i},e,t))&&(e=e.substring(u.raw.length),t.push(u),!0)}))))if(u=this.tokenizer.escape(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.tag(e))e=e.substring(u.raw.length),(n=t[t.length-1])&&"text"===u.type&&"text"===n.type?(n.raw+=u.raw,n.text+=u.text):t.push(u);else if(u=this.tokenizer.link(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(u.raw.length),(n=t[t.length-1])&&"text"===u.type&&"text"===n.type?(n.raw+=u.raw,n.text+=u.text):t.push(u);else if(u=this.tokenizer.emStrong(e,o,a))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.codespan(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.br(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.del(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.autolink(e,W))e=e.substring(u.raw.length),t.push(u);else if(this.state.inLink||!(u=this.tokenizer.url(e,W))){if(r=e,this.options.extensions&&this.options.extensions.startInline&&function(){var t=1/0,u=e.slice(1),n=void 0;i.options.extensions.startInline.forEach((function(e){"number"==typeof(n=e.call({lexer:this},u))&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}(),u=this.tokenizer.inlineText(r,K))e=e.substring(u.raw.length),"_"!==u.raw.slice(-1)&&(a=u.raw.slice(-1)),l=!0,(n=t[t.length-1])&&"text"===n.type?(n.raw+=u.raw,n.text+=u.text):t.push(u);else if(e){var c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}throw new Error(c)}}else e=e.substring(u.raw.length),t.push(u);return t},u=t,r=[{key:"rules",get:function(){return{block:V,inline:H}}}],(n=null)&&e(u.prototype,n),r&&e(u,r),t}(),ee=n.exports.defaults,te=B,ue=x,ne=function(){function e(e){this.options=e||ee}var t=e.prototype;return t.code=function(e,t,u){var n=(t||"").match(/\S*/)[0];if(this.options.highlight){var r=this.options.highlight(e,n);null!=r&&r!==e&&(u=!0,e=r)}return e=e.replace(/\n$/,"")+"\n",n?'
'+(u?e:ue(e,!0))+"
\n":"
"+(u?e:ue(e,!0))+"
\n"},t.blockquote=function(e){return"
\n"+e+"
\n"},t.html=function(e){return e},t.heading=function(e,t,u,n){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
\n":"
\n"},t.list=function(e,t,u){var n=t?"ol":"ul";return"<"+n+(t&&1!==u?' start="'+u+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return t&&(t=""+t+""),"\n\n"+e+"\n"+t+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var u=t.header?"th":"td";return(t.align?"<"+u+' align="'+t.align+'">':"<"+u+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,u){if(null===(e=te(this.options.sanitize,this.options.baseUrl,e)))return u;var n='"},t.image=function(e,t,u){if(null===(e=te(this.options.sanitize,this.options.baseUrl,e)))return u;var n=''+u+'":">"},t.text=function(e){return e},e}(),re=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,u){return""+u},t.image=function(e,t,u){return""+u},t.br=function(){return""},e}(),ie=function(){function e(){this.seen={}}var t=e.prototype;return t.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},t.getNextSafeSlug=function(e,t){var u=e,n=0;if(this.seen.hasOwnProperty(u)){n=this.seen[e];do{u=e+"-"+ ++n}while(this.seen.hasOwnProperty(u))}return t||(this.seen[e]=n,this.seen[u]=0),u},t.slug=function(e,t){void 0===t&&(t={});var u=this.serialize(e);return this.getNextSafeSlug(u,t.dryrun)},e}(),se=ne,le=re,ae=ie,oe=n.exports.defaults,De=m,ce=Y,he=function(){function e(e){this.options=e||oe,this.options.renderer=this.options.renderer||new se,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new le,this.slugger=new ae}e.parse=function(t,u){return new e(u).parse(t)},e.parseInline=function(t,u){return new e(u).parseInline(t)};var t=e.prototype;return t.parse=function(e,t){void 0===t&&(t=!0);var u,n,r,i,s,l,a,o,D,c,h,p,f,g,F,A,d,C,k,E="",x=e.length;for(u=0;u0&&"paragraph"===F.tokens[0].type?(F.tokens[0].text=C+" "+F.tokens[0].text,F.tokens[0].tokens&&F.tokens[0].tokens.length>0&&"text"===F.tokens[0].tokens[0].type&&(F.tokens[0].tokens[0].text=C+" "+F.tokens[0].tokens[0].text)):F.tokens.unshift({type:"text",text:C}):g+=C),g+=this.parse(F.tokens,f),D+=this.renderer.listitem(g,d,A);E+=this.renderer.list(D,h,p);continue;case"html":E+=this.renderer.html(c.text);continue;case"paragraph":E+=this.renderer.paragraph(this.parseInline(c.tokens));continue;case"text":for(D=c.tokens?this.parseInline(c.tokens):c.text;u+1An error occurred:

    "+Ce(e.message+"",!0)+"
    ";throw e}}return me.options=me.setOptions=function(e){return Ae(me.defaults,e),Ee(me.defaults),me},me.getDefaults=ke,me.defaults=xe,me.use=function(){for(var e=arguments.length,t=new Array(e),u=0;uAn error occurred:

    "+Ce(e.message+"",!0)+"
    ";throw e}},me.Parser=he,me.parser=he.parse,me.Renderer=fe,me.TextRenderer=ge,me.Lexer=ce,me.lexer=ce.lex,me.Tokenizer=pe,me.Slugger=Fe,me.parse=me,me})); - -function markdown(first, second) { - var input = document.getElementById(first).value; - input = input.replace(/\|\|(.*?)\|\|/g, '$1') - - var emojis = Array.from(input.matchAll(/:([^\s]{1,31}):/gi)) - if(emojis != null){ - for(i = 0; i < emojis.length; i++){ - var old = emojis[i][0]; - if (old.includes('marseyrandom')) continue - var emoji = old.replace(/[:!@#]/g,'').toLowerCase(); - var mirroredClass = old.indexOf('!') == -1 ? '' : 'mirrored'; - var emojiClass = old.indexOf('#') == -1 ? 'emoji' : 'emoji-lg'; - if (emoji.endsWith('pat')) { - emoji = emoji.substr(0, emoji.length - 3); - var url = old.indexOf('@') != -1 ? `/@${emoji}/pic` : `/e/${emoji}.webp`; - input = input.replace(old, ``); - } else { - input = input.replace(old, ``); - } - } - } - - if (!first.includes('edit')) - { - var options = Array.from(input.matchAll(/\s*\$\$([^\$\n]+)\$\$\s*/gi)) - if(options != null){ - for(i = 0; i < options.length; i++){ - var option = options[i][0]; - var option2 = option.replace(/\$\$/g, '').replace(/\n/g, '') - input = input.replace(option, ''); - input += '
    '; - } - } - var options = Array.from(input.matchAll(/\s*&&([^\$\n]+)&&\s*/gi)) - if(options != null){ - for(i = 0; i < options.length; i++){ - var option = options[i][0]; - var option2 = option.replace(/&&/g, '').replace(/\n/g, '') - input = input.replace(option, ''); - input += '
    '; - } - } - } - - document.getElementById(second).innerHTML = marked(input) -} - -function charLimit(form, text) { - - var input = document.getElementById(form); - - var text = document.getElementById(text); - - var length = input.value.length; - - var maxLength = input.getAttribute("maxlength"); - - if (length >= maxLength) { - text.style.color = "#E53E3E"; - } - else if (length >= maxLength * .72){ - text.style.color = "#FFC107"; - } - else { - text.style.color = "#A0AEC0"; - } - - text.innerText = length + ' / ' + maxLength; -} +!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).marked=t()}(this,(function(){"use strict";function e(e,t){for(var u=0;ue.length)&&(t=e.length);for(var u=0,n=new Array(t);u=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n={exports:{}};function r(){return{baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}n.exports={defaults:{baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1},getDefaults:r,changeDefaults:function(e){n.exports.defaults=e}};var i=/[&<>"']/,s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,o={"&":"&","<":"<",">":">",'"':""","'":"'"},D=function(e){return o[e]};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,(function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""}))}var p=/(^|[^\[])\^/g;var f=/[^\w:]/g,g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var F={},A=/^[^:]+:\/*[^/]*$/,d=/^([^:]+:)[\s\S]*$/,C=/^([^:]+:\/*[^/]*)[\s\S]*$/;function k(e,t){F[" "+e]||(A.test(e)?F[" "+e]=e+"/":F[" "+e]=E(e,"/",!0));var u=-1===(e=F[" "+e]).indexOf(":");return"//"===t.substring(0,2)?u?t:e.replace(d,"$1")+t:"/"===t.charAt(0)?u?t:e.replace(C,"$1")+t:e+t}function E(e,t,u){var n=e.length;if(0===n)return"";for(var r=0;r=0&&"\\"===u[r];)n=!n;return n?"|":" |"})).split(/ \|/),n=0;if(u[0].trim()||u.shift(),u[u.length-1].trim()||u.pop(),u.length>t)u.splice(t);else for(;u.length1;)1&t&&(u+=e),t>>=1,e+=e;return u+e},T=n.exports.defaults,R=_,I=y,Z=x,q=z;function O(e,t,u,n){var r=t.href,i=t.title?Z(t.title):null,s=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){n.state.inLink=!0;var l={type:"link",raw:u,href:r,title:i,text:s,tokens:n.inlineTokens(s,[])};return n.state.inLink=!1,l}return{type:"image",raw:u,href:r,title:i,text:Z(s)}}var L=function(){function e(e){this.options=e||T}var t=e.prototype;return t.space=function(e){var t=this.rules.block.newline.exec(e);if(t)return t[0].length>1?{type:"space",raw:t[0]}:{raw:"\n"}},t.code=function(e){var t=this.rules.block.code.exec(e);if(t){var u=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?u:R(u,"\n")}}},t.fences=function(e){var t=this.rules.block.fences.exec(e);if(t){var u=t[0],n=function(e,t){var u=e.match(/^(\s+)(?:```)/);if(null===u)return t;var n=u[1];return t.split("\n").map((function(e){var t=e.match(/^\s+/);return null===t?e:t[0].length>=n.length?e.slice(n.length):e})).join("\n")}(u,t[3]||"");return{type:"code",raw:u,lang:t[2]?t[2].trim():t[2],text:n}}},t.heading=function(e){var t=this.rules.block.heading.exec(e);if(t){var u=t[2].trim();if(/#$/.test(u)){var n=R(u,"#");this.options.pedantic?u=n.trim():n&&!/ $/.test(n)||(u=n.trim())}var r={type:"heading",raw:t[0],depth:t[1].length,text:u,tokens:[]};return this.lexer.inline(r.text,r.tokens),r}},t.hr=function(e){var t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}},t.blockquote=function(e){var t=this.rules.block.blockquote.exec(e);if(t){var u=t[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:t[0],tokens:this.lexer.blockTokens(u,[]),text:u}}},t.list=function(e){var t=this.rules.block.list.exec(e);if(t){var u,n,r,i,s,l,a,o,D,c,h=t[1].trim(),p=h.length>1,f={type:"list",raw:"",ordered:p,start:p?+h.slice(0,-1):"",loose:!1,items:[]};h=p?"\\d{1,9}\\"+h.slice(-1):"\\"+h,this.options.pedantic&&(h=p?h:"[*+-]");for(var g=new RegExp("^( {0,3}"+h+")((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))");e&&!this.rules.block.hr.test(e)&&(t=g.exec(e));){D=t[2].split("\n"),this.options.pedantic?(i=2,c=D[0].trimLeft()):(i=t[2].search(/[^ ]/),i=t[1].length+(i>4?1:i),c=D[0].slice(i-t[1].length)),l=!1,u=t[0],!D[0]&&/^ *$/.test(D[1])&&(u=t[1]+D.slice(0,2).join("\n")+"\n",f.loose=!0,D=[]);var F=new RegExp("^ {0,"+Math.min(3,i-1)+"}(?:[*+-]|\\d{1,9}[.)])");for(s=1;s=i)&&o.trim()){u=t[1]+D.slice(0,s).join("\n")+"\n";break}c+="\n"+o.slice(i)}else o.trim()||(l=!0),o.search(/[^ ]/)>=i?c+="\n"+o.slice(i):c+="\n"+o}f.loose||(a?f.loose=!0:/\n *\n *$/.test(u)&&(a=!0)),this.options.gfm&&(n=/^\[[ xX]\] /.exec(c))&&(r="[ ] "!==n[0],c=c.replace(/^\[[ xX]\] +/,"")),f.items.push({type:"list_item",raw:u,task:!!n,checked:r,loose:!1,text:c}),f.raw+=u,e=e.slice(u.length)}f.items[f.items.length-1].raw=u.trimRight(),f.items[f.items.length-1].text=c.trimRight(),f.raw=f.raw.trimRight();var A=f.items.length;for(s=0;s/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(t[0]):Z(t[0]):t[0]}},t.link=function(e){var t=this.rules.inline.link.exec(e);if(t){var u=t[2].trim();if(!this.options.pedantic&&/^$/.test(u))return;var n=R(u.slice(0,-1),"\\");if((u.length-n.length)%2==0)return}else{var r=q(t[2],"()");if(r>-1){var i=(0===t[0].indexOf("!")?5:4)+t[1].length+r;t[2]=t[2].substring(0,r),t[0]=t[0].substring(0,i).trim(),t[3]=""}}var s=t[2],l="";if(this.options.pedantic){var a=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(s);a&&(s=a[1],l=a[3])}else l=t[3]?t[3].slice(1,-1):"";return s=s.trim(),/^$/.test(u)?s.slice(1):s.slice(1,-1)),O(t,{href:s?s.replace(this.rules.inline._escapes,"$1"):s,title:l?l.replace(this.rules.inline._escapes,"$1"):l},t[0],this.lexer)}},t.reflink=function(e,t){var u;if((u=this.rules.inline.reflink.exec(e))||(u=this.rules.inline.nolink.exec(e))){var n=(u[2]||u[1]).replace(/\s+/g," ");if(!(n=t[n.toLowerCase()])||!n.href){var r=u[0].charAt(0);return{type:"text",raw:r,text:r}}return O(u,n,u[0],this.lexer)}},t.emStrong=function(e,t,u){void 0===u&&(u="");var n=this.rules.inline.emStrong.lDelim.exec(e);if(n&&(!n[3]||!u.match(/(?:[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/))){var r=n[1]||n[2]||"";if(!r||r&&(""===u||this.rules.inline.punctuation.exec(u))){var i,s,l=n[0].length-1,a=l,o=0,D="*"===n[0][0]?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(D.lastIndex=0,t=t.slice(-1*e.length+l);null!=(n=D.exec(t));)if(i=n[1]||n[2]||n[3]||n[4]||n[5]||n[6])if(s=i.length,n[3]||n[4])a+=s;else if(!((n[5]||n[6])&&l%3)||(l+s)%3){if(!((a-=s)>0)){if(s=Math.min(s,s+a+o),Math.min(l,s)%2){var c=e.slice(1,l+n.index+s);return{type:"em",raw:e.slice(0,l+n.index+s+1),text:c,tokens:this.lexer.inlineTokens(c,[])}}var h=e.slice(2,l+n.index+s-1);return{type:"strong",raw:e.slice(0,l+n.index+s+1),text:h,tokens:this.lexer.inlineTokens(h,[])}}}else o+=s}}},t.codespan=function(e){var t=this.rules.inline.code.exec(e);if(t){var u=t[2].replace(/\n/g," "),n=/[^ ]/.test(u),r=/^ /.test(u)&&/ $/.test(u);return n&&r&&(u=u.substring(1,u.length-1)),u=Z(u,!0),{type:"codespan",raw:t[0],text:u}}},t.br=function(e){var t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}},t.del=function(e){var t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2],[])}},t.autolink=function(e,t){var u,n,r=this.rules.inline.autolink.exec(e);if(r)return n="@"===r[2]?"mailto:"+(u=Z(this.options.mangle?t(r[1]):r[1])):u=Z(r[1]),{type:"link",raw:r[0],text:u,href:n,tokens:[{type:"text",raw:u,text:u}]}},t.url=function(e,t){var u;if(u=this.rules.inline.url.exec(e)){var n,r;if("@"===u[2])r="mailto:"+(n=Z(this.options.mangle?t(u[0]):u[0]));else{var i;do{i=u[0],u[0]=this.rules.inline._backpedal.exec(u[0])[0]}while(i!==u[0]);n=Z(u[0]),r="www."===u[1]?"http://"+n:n}return{type:"link",raw:u[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}},t.inlineText=function(e,t){var u,n=this.rules.inline.text.exec(e);if(n)return u=this.lexer.state.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(n[0]):Z(n[0]):n[0]:Z(this.options.smartypants?t(n[0]):n[0]),{type:"text",raw:n[0],text:u}},e}(),j=w,U=b,P=v,Q={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3}bull)( [^\n]+?)?(?:\n|$)/,html:"^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:j,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Q.def=U(Q.def).replace("label",Q._label).replace("title",Q._title).getRegex(),Q.bullet=/(?:[*+-]|\d{1,9}[.)])/,Q.listItemStart=U(/^( *)(bull) */).replace("bull",Q.bullet).getRegex(),Q.list=U(Q.list).replace(/bull/g,Q.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Q.def.source+")").getRegex(),Q._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Q._comment=/|$)/,Q.html=U(Q.html,"i").replace("comment",Q._comment).replace("tag",Q._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Q.paragraph=U(Q._paragraph).replace("hr",Q.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Q._tag).getRegex(),Q.blockquote=U(Q.blockquote).replace("paragraph",Q.paragraph).getRegex(),Q.normal=P({},Q),Q.gfm=P({},Q.normal,{table:"^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Q.gfm.table=U(Q.gfm.table).replace("hr",Q.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Q._tag).getRegex(),Q.pedantic=P({},Q.normal,{html:U("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Q._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:j,paragraph:U(Q.normal._paragraph).replace("hr",Q.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Q.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var M={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:j,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/^[^_*]*?\_\_[^_*]*?\*[^_*]*?(?=\_\_)|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,rDelimUnd:/^[^_*]*?\*\*[^_*]*?\_[^_*]*?(?=\*\*)|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:j,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~"};M.punctuation=U(M.punctuation).replace(/punctuation/g,M._punctuation).getRegex(),M.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g,M.escapedEmSt=/\\\*|\\_/g,M._comment=U(Q._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),M.emStrong.lDelim=U(M.emStrong.lDelim).replace(/punct/g,M._punctuation).getRegex(),M.emStrong.rDelimAst=U(M.emStrong.rDelimAst,"g").replace(/punct/g,M._punctuation).getRegex(),M.emStrong.rDelimUnd=U(M.emStrong.rDelimUnd,"g").replace(/punct/g,M._punctuation).getRegex(),M._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,M._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,M._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,M.autolink=U(M.autolink).replace("scheme",M._scheme).replace("email",M._email).getRegex(),M._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,M.tag=U(M.tag).replace("comment",M._comment).replace("attribute",M._attribute).getRegex(),M._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,M._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,M._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,M.link=U(M.link).replace("label",M._label).replace("href",M._href).replace("title",M._title).getRegex(),M.reflink=U(M.reflink).replace("label",M._label).getRegex(),M.reflinkSearch=U(M.reflinkSearch,"g").replace("reflink",M.reflink).replace("nolink",M.nolink).getRegex(),M.normal=P({},M),M.pedantic=P({},M.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:U(/^!?\[(label)\]\((.*?)\)/).replace("label",M._label).getRegex(),reflink:U(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",M._label).getRegex()}),M.gfm=P({},M.normal,{escape:U(M.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\.5&&(u="x"+u.toString(16)),n+="&#"+u+";";return n}var Y=function(){function t(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||G,this.options.tokenizer=this.options.tokenizer||new X,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};var t={block:V.normal,inline:H.normal};this.options.pedantic?(t.block=V.pedantic,t.inline=H.pedantic):this.options.gfm&&(t.block=V.gfm,this.options.breaks?t.inline=H.breaks:t.inline=H.gfm),this.tokenizer.rules=t}t.lex=function(e,u){return new t(u).lex(e)},t.lexInline=function(e,u){return new t(u).inlineTokens(e)};var u,n,r,i=t.prototype;return i.lex=function(e){var t;for(e=e.replace(/\r\n|\r/g,"\n"),this.blockTokens(e,this.tokens);t=this.inlineQueue.shift();)this.inlineTokens(t.src,t.tokens);return this.tokens},i.blockTokens=function(e,t){var u,n,r,i,s=this;for(void 0===t&&(t=[]),this.options.pedantic&&(e=e.replace(/^ +$/gm,""));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((function(n){return!!(u=n.call({lexer:s},e,t))&&(e=e.substring(u.raw.length),t.push(u),!0)}))))if(u=this.tokenizer.space(e))e=e.substring(u.raw.length),u.type&&t.push(u);else if(u=this.tokenizer.code(e))e=e.substring(u.raw.length),!(n=t[t.length-1])||"paragraph"!==n.type&&"text"!==n.type?t.push(u):(n.raw+="\n"+u.raw,n.text+="\n"+u.text,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(u=this.tokenizer.fences(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.heading(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.hr(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.blockquote(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.list(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.html(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.def(e))e=e.substring(u.raw.length),!(n=t[t.length-1])||"paragraph"!==n.type&&"text"!==n.type?this.tokens.links[u.tag]||(this.tokens.links[u.tag]={href:u.href,title:u.title}):(n.raw+="\n"+u.raw,n.text+="\n"+u.raw,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(u=this.tokenizer.table(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.lheading(e))e=e.substring(u.raw.length),t.push(u);else if(r=e,this.options.extensions&&this.options.extensions.startBlock&&function(){var t=1/0,u=e.slice(1),n=void 0;s.options.extensions.startBlock.forEach((function(e){"number"==typeof(n=e.call({lexer:this},u))&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}(),this.state.top&&(u=this.tokenizer.paragraph(r)))n=t[t.length-1],i&&"paragraph"===n.type?(n.raw+="\n"+u.raw,n.text+="\n"+u.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(u),i=r.length!==e.length,e=e.substring(u.raw.length);else if(u=this.tokenizer.text(e))e=e.substring(u.raw.length),(n=t[t.length-1])&&"text"===n.type?(n.raw+="\n"+u.raw,n.text+="\n"+u.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(u);else if(e){var l="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(l);break}throw new Error(l)}return this.state.top=!0,t},i.inline=function(e,t){this.inlineQueue.push({src:e,tokens:t})},i.inlineTokens=function(e,t){var u,n,r,i=this;void 0===t&&(t=[]);var s,l,a,o=e;if(this.tokens.links){var D=Object.keys(this.tokens.links);if(D.length>0)for(;null!=(s=this.tokenizer.rules.inline.reflinkSearch.exec(o));)D.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(o=o.slice(0,s.index)+"["+J("a",s[0].length-2)+"]"+o.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(s=this.tokenizer.rules.inline.blockSkip.exec(o));)o=o.slice(0,s.index)+"["+J("a",s[0].length-2)+"]"+o.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(s=this.tokenizer.rules.inline.escapedEmSt.exec(o));)o=o.slice(0,s.index)+"++"+o.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);for(;e;)if(l||(a=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((function(n){return!!(u=n.call({lexer:i},e,t))&&(e=e.substring(u.raw.length),t.push(u),!0)}))))if(u=this.tokenizer.escape(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.tag(e))e=e.substring(u.raw.length),(n=t[t.length-1])&&"text"===u.type&&"text"===n.type?(n.raw+=u.raw,n.text+=u.text):t.push(u);else if(u=this.tokenizer.link(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(u.raw.length),(n=t[t.length-1])&&"text"===u.type&&"text"===n.type?(n.raw+=u.raw,n.text+=u.text):t.push(u);else if(u=this.tokenizer.emStrong(e,o,a))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.codespan(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.br(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.del(e))e=e.substring(u.raw.length),t.push(u);else if(u=this.tokenizer.autolink(e,W))e=e.substring(u.raw.length),t.push(u);else if(this.state.inLink||!(u=this.tokenizer.url(e,W))){if(r=e,this.options.extensions&&this.options.extensions.startInline&&function(){var t=1/0,u=e.slice(1),n=void 0;i.options.extensions.startInline.forEach((function(e){"number"==typeof(n=e.call({lexer:this},u))&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}(),u=this.tokenizer.inlineText(r,K))e=e.substring(u.raw.length),"_"!==u.raw.slice(-1)&&(a=u.raw.slice(-1)),l=!0,(n=t[t.length-1])&&"text"===n.type?(n.raw+=u.raw,n.text+=u.text):t.push(u);else if(e){var c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}throw new Error(c)}}else e=e.substring(u.raw.length),t.push(u);return t},u=t,r=[{key:"rules",get:function(){return{block:V,inline:H}}}],(n=null)&&e(u.prototype,n),r&&e(u,r),t}(),ee=n.exports.defaults,te=B,ue=x,ne=function(){function e(e){this.options=e||ee}var t=e.prototype;return t.code=function(e,t,u){var n=(t||"").match(/\S*/)[0];if(this.options.highlight){var r=this.options.highlight(e,n);null!=r&&r!==e&&(u=!0,e=r)}return e=e.replace(/\n$/,"")+"\n",n?'
    '+(u?e:ue(e,!0))+"
    \n":"
    "+(u?e:ue(e,!0))+"
    \n"},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,u,n){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,u){var n=t?"ol":"ul";return"<"+n+(t&&1!==u?' start="'+u+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return t&&(t=""+t+""),"\n\n"+e+"\n"+t+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var u=t.header?"th":"td";return(t.align?"<"+u+' align="'+t.align+'">':"<"+u+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,u){if(null===(e=te(this.options.sanitize,this.options.baseUrl,e)))return u;var n='"},t.image=function(e,t,u){if(null===(e=te(this.options.sanitize,this.options.baseUrl,e)))return u;var n=''+u+'":">"},t.text=function(e){return e},e}(),re=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,u){return""+u},t.image=function(e,t,u){return""+u},t.br=function(){return""},e}(),ie=function(){function e(){this.seen={}}var t=e.prototype;return t.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},t.getNextSafeSlug=function(e,t){var u=e,n=0;if(this.seen.hasOwnProperty(u)){n=this.seen[e];do{u=e+"-"+ ++n}while(this.seen.hasOwnProperty(u))}return t||(this.seen[e]=n,this.seen[u]=0),u},t.slug=function(e,t){void 0===t&&(t={});var u=this.serialize(e);return this.getNextSafeSlug(u,t.dryrun)},e}(),se=ne,le=re,ae=ie,oe=n.exports.defaults,De=m,ce=Y,he=function(){function e(e){this.options=e||oe,this.options.renderer=this.options.renderer||new se,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new le,this.slugger=new ae}e.parse=function(t,u){return new e(u).parse(t)},e.parseInline=function(t,u){return new e(u).parseInline(t)};var t=e.prototype;return t.parse=function(e,t){void 0===t&&(t=!0);var u,n,r,i,s,l,a,o,D,c,h,p,f,g,F,A,d,C,k,E="",x=e.length;for(u=0;u0&&"paragraph"===F.tokens[0].type?(F.tokens[0].text=C+" "+F.tokens[0].text,F.tokens[0].tokens&&F.tokens[0].tokens.length>0&&"text"===F.tokens[0].tokens[0].type&&(F.tokens[0].tokens[0].text=C+" "+F.tokens[0].tokens[0].text)):F.tokens.unshift({type:"text",text:C}):g+=C),g+=this.parse(F.tokens,f),D+=this.renderer.listitem(g,d,A);E+=this.renderer.list(D,h,p);continue;case"html":E+=this.renderer.html(c.text);continue;case"paragraph":E+=this.renderer.paragraph(this.parseInline(c.tokens));continue;case"text":for(D=c.tokens?this.parseInline(c.tokens):c.text;u+1An error occurred:

    "+Ce(e.message+"",!0)+"
    ";throw e}}return me.options=me.setOptions=function(e){return Ae(me.defaults,e),Ee(me.defaults),me},me.getDefaults=ke,me.defaults=xe,me.use=function(){for(var e=arguments.length,t=new Array(e),u=0;uAn error occurred:

    "+Ce(e.message+"",!0)+"
    ";throw e}},me.Parser=he,me.parser=he.parse,me.Renderer=fe,me.TextRenderer=ge,me.Lexer=ce,me.lexer=ce.lex,me.Tokenizer=pe,me.Slugger=Fe,me.parse=me,me})); diff --git a/files/classes/__init__.py b/files/classes/__init__.py index 37ac578fd..88c9fbec2 100644 --- a/files/classes/__init__.py +++ b/files/classes/__init__.py @@ -1,22 +1,95 @@ -from .alts import * -from .badges import * -from .clients import * -from .comment import * -from .domains import * -from .flags import * -from .user import * -from .userblock import * -from .usernotes import * -from .submission import * -from .votes import * -from .domains import * -from .subscriptions import * -from files.__main__ import app -from .mod_logs import * -from .award import * -from .marsey import * -from .sub_block import * -from .saves import * -from .views import * -from .notifications import * -from .follows import * +################################################################ +# WARNING! THIS FILE IS EVIL. # +################################################################ +# Previously, this file had a series of # +# from .alts import * # +# from .award import * # +# from .badges import * # +# and so on in that fashion. That means that anywhere that # +# from files.classes import * # +# (and there were a lot of places like that) got anything # +# was imported for any model imported. So if you, for example, # +# removed # +# from secrets import token_hex # +# from files/classes/user.py, the registration page would # +# break because files/routes/login.py did # +# from files.classes import * # +# in order to get the token_hex function rather than # +# importing it with something like # +# from secrets import token_hex # +# # +# Anyway, not fixing that right now, but in order to # +# what needed to be imported here such that # +# from files.classes import * # +# still imported the same stuff as before I ran the following: # +# $ find files/classes -type f -name '*.py' \ # +# -exec grep import '{}' ';' \ # +# | grep 'import' \ # +# | grep -v 'from [.]\|__init__\|from files.classes' \ # +# | sed 's/^[^:]*://g' \ # +# | sort \ # +# | uniq # +# and then reordered the list such that import * did not stomp # +# over stuff that had been explicitly imported. # +################################################################ + +# First the import * from places which don't go circular +from sqlalchemy import * +from flask import * + +# Then everything except what's in files.* +import pyotp +import random +import re +import time +from copy import deepcopy +from datetime import datetime +from flask import g +from flask import render_template +from json import loads +from math import floor +from os import environ +from os import environ, remove, path +from random import randint +from secrets import token_hex +from sqlalchemy.orm import deferred, aliased +from sqlalchemy.orm import relationship +from sqlalchemy.orm import relationship, deferred +from urllib.parse import urlencode, urlparse, parse_qs +from urllib.parse import urlparse + +# It is now safe to define the models +from .alts import Alt +from .award import AwardRelationship +from .badges import BadgeDef, Badge +from .clients import OauthApp, ClientAuth +from .comment import Comment +from .domains import BannedDomain +from .exiles import Exile +from .flags import Flag, CommentFlag +from .follows import Follow +from .marsey import Marsey +from .mod import Mod +from .mod_logs import ModAction +from .notifications import Notification +from .saves import SaveRelationship, CommentSaveRelationship +from .sub import Sub +from .sub_block import SubBlock +from .submission import Submission +from .subscriptions import Subscription +from .user import User +from .userblock import UserBlock +from .usernotes import UserTag, UserNote +from .views import ViewerRelationship +from .votes import Vote, CommentVote + +# Then the import * from files.* +from files.helpers.const import * +from files.helpers.images import * +from files.helpers.lazy import * +from files.helpers.security import * + +# Then the specific stuff we don't want stomped on +from files.helpers.discord import remove_user +from files.helpers.lazy import lazy +from files.__main__ import Base, app, cache diff --git a/files/classes/alts.py b/files/classes/alts.py index 5e9bf1d8a..d84a45403 100644 --- a/files/classes/alts.py +++ b/files/classes/alts.py @@ -7,7 +7,9 @@ class Alt(Base): user1 = Column(Integer, ForeignKey("users.id"), primary_key=True) user2 = Column(Integer, ForeignKey("users.id"), primary_key=True) - is_manual = Column(Boolean, default=False) + is_manual = Column(Boolean, nullable=False, default=False) + + Index('alts_user2_idx', user2) def __repr__(self): diff --git a/files/classes/award.py b/files/classes/award.py index f7fdf6e0d..b3c9a660e 100644 --- a/files/classes/award.py +++ b/files/classes/award.py @@ -8,17 +8,24 @@ from files.helpers.const import * class AwardRelationship(Base): __tablename__ = "award_relationships" + __table_args__ = ( + UniqueConstraint('user_id', 'submission_id', 'comment_id', name='award_constraint'), + ) id = Column(Integer, primary_key=True) - user_id = Column(Integer, ForeignKey("users.id")) + user_id = Column(Integer, ForeignKey("users.id"), nullable=False) submission_id = Column(Integer, ForeignKey("submissions.id")) comment_id = Column(Integer, ForeignKey("comments.id")) - kind = Column(String) + kind = Column(String, nullable=False) user = relationship("User", primaryjoin="AwardRelationship.user_id==User.id", viewonly=True) post = relationship("Submission", primaryjoin="AwardRelationship.submission_id==Submission.id", viewonly=True) comment = relationship("Comment", primaryjoin="AwardRelationship.comment_id==Comment.id", viewonly=True) + Index('award_user_idx', user_id) + Index('award_post_idx', submission_id) + Index('award_comment_idx', comment_id) + @property @lazy diff --git a/files/classes/badges.py b/files/classes/badges.py index 58d3332b7..6464d5d3a 100644 --- a/files/classes/badges.py +++ b/files/classes/badges.py @@ -9,15 +9,17 @@ from json import loads class BadgeDef(Base): __tablename__ = "badge_defs" + __table_args__ = ( + UniqueConstraint('name', name='badge_def_name_unique'), + ) id = Column(Integer, primary_key=True, autoincrement=True) - name = Column(String) + name = Column(String, nullable=False) description = Column(String) def __repr__(self): return f"" - class Badge(Base): __tablename__ = "badges" @@ -27,6 +29,8 @@ class Badge(Base): description = Column(String) url = Column(String) + Index('badges_badge_id_idx', badge_id) + user = relationship("User", viewonly=True) badge = relationship("BadgeDef", primaryjoin="foreign(Badge.badge_id) == remote(BadgeDef.id)", viewonly=True) @@ -36,11 +40,7 @@ class Badge(Base): @property @lazy def text(self): - if self.name == "Chud": - ti = self.user.agendaposter - if ti: text = self.badge.description + " until " + datetime.utcfromtimestamp(ti).strftime('%Y-%m-%d %H:%M:%S') - else: text = self.badge.description + " permanently" - elif self.badge_id in {94,95,96,97,98,109}: + if self.badge_id in {94,95,96,97,98,109}: if self.badge_id == 94: ti = self.user.progressivestack elif self.badge_id == 95: ti = self.user.bird elif self.badge_id == 96: ti = self.user.flairchanged diff --git a/files/classes/clients.py b/files/classes/clients.py index 6e0fed47d..ebb1d2670 100644 --- a/files/classes/clients.py +++ b/files/classes/clients.py @@ -11,13 +11,16 @@ import time class OauthApp(Base): __tablename__ = "oauth_apps" + __table_args__ = ( + UniqueConstraint('client_id', name='unique_id'), + ) id = Column(Integer, primary_key=True) client_id = Column(String) - app_name = Column(String) - redirect_uri = Column(String) - description = Column(String) - author_id = Column(Integer, ForeignKey("users.id")) + app_name = Column(String(length=50), nullable=False) + redirect_uri = Column(String(length=50), nullable=False) + description = Column(String(length=256), nullable=False) + author_id = Column(Integer, ForeignKey("users.id"), nullable=False) author = relationship("User", viewonly=True) @@ -65,10 +68,13 @@ class OauthApp(Base): class ClientAuth(Base): __tablename__ = "client_auths" + __table_args__ = ( + UniqueConstraint('access_token', name='unique_access'), + ) user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) oauth_client = Column(Integer, ForeignKey("oauth_apps.id"), primary_key=True) - access_token = Column(String) + access_token = Column(String, nullable=False) user = relationship("User", viewonly=True) application = relationship("OauthApp", viewonly=True) diff --git a/files/classes/comment.py b/files/classes/comment.py index b1f7f93b0..d202cdc59 100644 --- a/files/classes/comment.py +++ b/files/classes/comment.py @@ -19,28 +19,28 @@ class Comment(Base): __tablename__ = "comments" id = Column(Integer, primary_key=True) - author_id = Column(Integer, ForeignKey("users.id")) + author_id = Column(Integer, ForeignKey("users.id"), nullable=False) parent_submission = Column(Integer, ForeignKey("submissions.id")) - created_utc = Column(Integer) - edited_utc = Column(Integer, default=0) - is_banned = Column(Boolean, default=False) - ghost = Column(Boolean, default=False) + created_utc = Column(Integer, nullable=False) + edited_utc = Column(Integer, default=0, nullable=False) + is_banned = Column(Boolean, default=False, nullable=False) + ghost = Column(Boolean, default=False, nullable=False) bannedfor = Column(Boolean) - distinguish_level = Column(Integer, default=0) - deleted_utc = Column(Integer, default=0) + distinguish_level = Column(Integer, default=0, nullable=False) + deleted_utc = Column(Integer, default=0, nullable=False) is_approved = Column(Integer, ForeignKey("users.id")) - level = Column(Integer, default=1) + level = Column(Integer, default=1, nullable=False) parent_comment_id = Column(Integer, ForeignKey("comments.id")) top_comment_id = Column(Integer) - over_18 = Column(Boolean, default=False) - is_bot = Column(Boolean, default=False) + over_18 = Column(Boolean, default=False, nullable=False) + is_bot = Column(Boolean, default=False, nullable=False) is_pinned = Column(String) is_pinned_utc = Column(Integer) sentto = Column(Integer, ForeignKey("users.id")) app_id = Column(Integer, ForeignKey("oauth_apps.id")) - upvotes = Column(Integer, default=1) - downvotes = Column(Integer, default=0) - realupvotes = Column(Integer, default=1) + upvotes = Column(Integer, default=1, nullable=False) + downvotes = Column(Integer, default=0, nullable=False) + realupvotes = Column(Integer, default=1, nullable=False) body = Column(String) body_html = Column(String) ban_reason = Column(String) @@ -49,6 +49,12 @@ class Comment(Base): wordle_result = Column(String) treasure_amount = Column(String) + Index('comment_parent_index', parent_comment_id) + Index('comment_post_id_index', parent_submission) + Index('comments_user_index', author_id) + Index('fki_comment_approver_fkey', is_approved) + Index('fki_comment_sentto_fkey', sentto) + oauth_app = relationship("OauthApp", viewonly=True) post = relationship("Submission", viewonly=True) author = relationship("User", primaryjoin="User.id==Comment.author_id") @@ -351,7 +357,6 @@ class Comment(Base): body = self.body_html or "" if body: - body = censor_slurs(body, v) if v: body = body.replace("old.reddit.com", v.reddit) @@ -417,7 +422,7 @@ class Comment(Base): if not body: return "" - return censor_slurs(body, v) + return body def print(self): print(f'post: {self.id}, comment: {self.author_id}', flush=True) diff --git a/files/classes/domains.py b/files/classes/domains.py index 776e3096a..f9acb7b32 100644 --- a/files/classes/domains.py +++ b/files/classes/domains.py @@ -5,4 +5,10 @@ class BannedDomain(Base): __tablename__ = "banneddomains" domain = Column(String, primary_key=True) - reason = Column(String) + reason = Column(String, nullable=False) + Index( + 'domains_domain_trgm_idx', + domain, + postgresql_using='gin', + postgresql_ops={'description':'gin_trgm_ops'} + ) diff --git a/files/classes/exiles.py b/files/classes/exiles.py index c30c068e6..117db21d2 100644 --- a/files/classes/exiles.py +++ b/files/classes/exiles.py @@ -7,7 +7,10 @@ class Exile(Base): __tablename__ = "exiles" user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) sub = Column(String, ForeignKey("subs.name"), primary_key=True) - exiler_id = Column(Integer, ForeignKey("users.id")) + exiler_id = Column(Integer, ForeignKey("users.id"), nullable=False) + + Index('fki_exile_exiler_fkey', exiler_id) + Index('fki_exile_sub_fkey', sub) exiler = relationship("User", primaryjoin="User.id==Exile.exiler_id", viewonly=True) diff --git a/files/classes/flags.py b/files/classes/flags.py index 87f634bc6..9772dc916 100644 --- a/files/classes/flags.py +++ b/files/classes/flags.py @@ -13,7 +13,9 @@ class Flag(Base): post_id = Column(Integer, ForeignKey("submissions.id")) user_id = Column(Integer, ForeignKey("users.id")) reason = Column(String) - created_utc = Column(Integer) + created_utc = Column(Integer, nullable=False) + + Index('flag_user_idx', user_id) user = relationship("User", primaryjoin = "Flag.user_id == User.id", uselist = False, viewonly=True) @@ -36,7 +38,7 @@ class Flag(Base): @lazy def realreason(self, v): - return censor_slurs(self.reason, v) + return self.reason class CommentFlag(Base): @@ -46,7 +48,9 @@ class CommentFlag(Base): comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) reason = Column(String) - created_utc = Column(Integer) + created_utc = Column(Integer, nullable=False) + + Index('cflag_user_idx', user_id) user = relationship("User", primaryjoin = "CommentFlag.user_id == User.id", uselist = False, viewonly=True) @@ -69,4 +73,4 @@ class CommentFlag(Base): @lazy def realreason(self, v): - return censor_slurs(self.reason, v) + return self.reason diff --git a/files/classes/follows.py b/files/classes/follows.py index cacbd8130..f9a522b09 100644 --- a/files/classes/follows.py +++ b/files/classes/follows.py @@ -7,7 +7,9 @@ class Follow(Base): __tablename__ = "follows" target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - created_utc = Column(Integer) + created_utc = Column(Integer, nullable=False) + + Index('follow_user_id_index', user_id) user = relationship("User", uselist=False, primaryjoin="User.id==Follow.user_id", viewonly=True) target = relationship("User", primaryjoin="User.id==Follow.target_id", viewonly=True) diff --git a/files/classes/marsey.py b/files/classes/marsey.py index 40e8e3ecf..b29c32ff4 100644 --- a/files/classes/marsey.py +++ b/files/classes/marsey.py @@ -5,9 +5,13 @@ class Marsey(Base): __tablename__ = "marseys" name = Column(String, primary_key=True) - author_id = Column(Integer, ForeignKey("users.id")) - tags = Column(String) - count = Column(Integer, default=0) + author_id = Column(Integer, ForeignKey("users.id"), nullable=False) + tags = Column(String(length=200), nullable=False) + count = Column(Integer, default=0, nullable=False) + + Index('marseys_idx2', author_id) + Index('marseys_idx3', count.desc()) + Index('marseys_idx', name) def __repr__(self): return f"" diff --git a/files/classes/mod.py b/files/classes/mod.py index 23f5ca552..0877cda2f 100644 --- a/files/classes/mod.py +++ b/files/classes/mod.py @@ -9,7 +9,9 @@ class Mod(Base): __tablename__ = "mods" user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) sub = Column(String, ForeignKey("subs.name"), primary_key=True) - created_utc = Column(Integer) + created_utc = Column(Integer, nullable=False) + + Index('fki_mod_sub_fkey', sub) def __init__(self, *args, **kwargs): if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) diff --git a/files/classes/mod_logs.py b/files/classes/mod_logs.py index 023e42792..773028995 100644 --- a/files/classes/mod_logs.py +++ b/files/classes/mod_logs.py @@ -16,7 +16,13 @@ class ModAction(Base): target_submission_id = Column(Integer, ForeignKey("submissions.id")) target_comment_id = Column(Integer, ForeignKey("comments.id")) _note=Column(String) - created_utc = Column(Integer) + created_utc = Column(Integer, nullable=False) + + Index('fki_modactions_user_fkey', target_user_id) + Index('modaction_action_idx', kind) + Index('modaction_cid_idx', target_comment_id) + Index('modaction_id_idx', id.desc()) + Index('modaction_pid_idx', target_submission_id) user = relationship("User", primaryjoin="User.id==ModAction.user_id", viewonly=True) target_user = relationship("User", primaryjoin="User.id==ModAction.target_user_id", viewonly=True) @@ -110,11 +116,6 @@ class ModAction(Base): return f"/log/{self.id}" ACTIONTYPES = { - 'agendaposter': { - "str": 'set chud theme on {self.target_link}', - "icon": 'fa-snooze', - "color": 'bg-danger' - }, 'approve_app': { "str": 'approved an application by {self.target_link}', "icon": 'fa-robot', @@ -350,11 +351,6 @@ ACTIONTYPES = { "icon": 'fa-eye-slash', "color": 'bg-danger' }, - 'unagendaposter': { - "str": 'removed chud theme from {self.target_link}', - "icon": 'fa-snooze', - "color": 'bg-success' - }, 'unban_comment': { "str": 'reinstated {self.target_link}', "icon": 'fa-comment', diff --git a/files/classes/notifications.py b/files/classes/notifications.py index 4edb47df8..0e2376f52 100644 --- a/files/classes/notifications.py +++ b/files/classes/notifications.py @@ -9,8 +9,12 @@ class Notification(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) - read = Column(Boolean, default=False) - created_utc = Column(Integer) + read = Column(Boolean, default=False, nullable=False) + created_utc = Column(Integer, nullable=False) + + Index('notification_read_idx', read) + Index('notifications_comment_idx', comment_id) + Index('notifs_user_read_idx', user_id, read) comment = relationship("Comment", viewonly=True) user = relationship("User", viewonly=True) diff --git a/files/classes/saves.py b/files/classes/saves.py index 50f9ef5d9..1e89898b6 100644 --- a/files/classes/saves.py +++ b/files/classes/saves.py @@ -10,6 +10,8 @@ class SaveRelationship(Base): user_id=Column(Integer, ForeignKey("users.id"), primary_key=True) submission_id=Column(Integer, ForeignKey("submissions.id"), primary_key=True) + Index('fki_save_relationship_submission_fkey', submission_id) + class CommentSaveRelationship(Base): @@ -18,3 +20,5 @@ class CommentSaveRelationship(Base): user_id=Column(Integer, ForeignKey("users.id"), primary_key=True) comment_id=Column(Integer, ForeignKey("comments.id"), primary_key=True) + + Index('fki_comment_save_relationship_comment_fkey', comment_id) diff --git a/files/classes/sub.py b/files/classes/sub.py index 9c7037822..19ab92b12 100644 --- a/files/classes/sub.py +++ b/files/classes/sub.py @@ -20,6 +20,8 @@ class Sub(Base): bannerurl = Column(String) css = Column(String) + Index('subs_idx', name) + blocks = relationship("SubBlock", lazy="dynamic", primaryjoin="SubBlock.sub==Sub.name", viewonly=True) diff --git a/files/classes/sub_block.py b/files/classes/sub_block.py index 92c7ad288..3707a63b7 100644 --- a/files/classes/sub_block.py +++ b/files/classes/sub_block.py @@ -8,5 +8,7 @@ class SubBlock(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) sub = Column(String, ForeignKey("subs.name"), primary_key=True) + Index('fki_sub_blocks_sub_fkey', sub) + def __repr__(self): return f"" diff --git a/files/classes/submission.py b/files/classes/submission.py index 20fba3e58..9f691202b 100644 --- a/files/classes/submission.py +++ b/files/classes/submission.py @@ -19,32 +19,32 @@ class Submission(Base): __tablename__ = "submissions" id = Column(Integer, primary_key=True) - author_id = Column(Integer, ForeignKey("users.id")) - edited_utc = Column(Integer, default=0) - created_utc = Column(Integer) + author_id = Column(Integer, ForeignKey("users.id"), nullable=False) + edited_utc = Column(Integer, default=0, nullable=False) + created_utc = Column(Integer, nullable=False) thumburl = Column(String) - is_banned = Column(Boolean, default=False) + is_banned = Column(Boolean, default=False, nullable=False) bannedfor = Column(Boolean) - ghost = Column(Boolean, default=False) - views = Column(Integer, default=0) - deleted_utc = Column(Integer, default=0) - distinguish_level = Column(Integer, default=0) + ghost = Column(Boolean, default=False, nullable=False) + views = Column(Integer, default=0, nullable=False) + deleted_utc = Column(Integer, default=0, nullable=False) + distinguish_level = Column(Integer, default=0, nullable=False) stickied = Column(String) stickied_utc = Column(Integer) sub = Column(String, ForeignKey("subs.name")) - is_pinned = Column(Boolean, default=False) - private = Column(Boolean, default=False) - club = Column(Boolean, default=False) - comment_count = Column(Integer, default=0) + is_pinned = Column(Boolean, default=False, nullable=False) + private = Column(Boolean, default=False, nullable=False) + club = Column(Boolean, default=False, nullable=False) + comment_count = Column(Integer, default=0, nullable=False) is_approved = Column(Integer, ForeignKey("users.id")) - over_18 = Column(Boolean, default=False) - is_bot = Column(Boolean, default=False) - upvotes = Column(Integer, default=1) - downvotes = Column(Integer, default=0) + over_18 = Column(Boolean, default=False, nullable=False) + is_bot = Column(Boolean, default=False, nullable=False) + upvotes = Column(Integer, default=1, nullable=False) + downvotes = Column(Integer, default=0, nullable=False) realupvotes = Column(Integer, default=1) app_id=Column(Integer, ForeignKey("oauth_apps.id")) - title = Column(String) - title_html = Column(String) + title = Column(String, nullable=False) + title_html = Column(String, nullable=False) url = Column(String) body = Column(String) body_html = Column(String) @@ -53,6 +53,18 @@ class Submission(Base): embed_url = Column(String) filter_state = Column(String) + Index('fki_submissions_approver_fkey', is_approved) + Index('post_app_id_idx', app_id) + Index('subimssion_binary_group_idx', is_banned, deleted_utc, over_18) + Index('submission_isbanned_idx', is_banned) + Index('submission_isdeleted_idx', deleted_utc) + Index('submission_new_sort_idx', is_banned, deleted_utc, created_utc.desc(), over_18) + Index('submission_pinned_idx', is_pinned) + Index('submissions_author_index', author_id) + Index('submissions_created_utc_asc_idx', created_utc.nullsfirst()) + Index('submissions_created_utc_desc_idx', created_utc.desc()) + Index('submissions_over18_index', over_18) + author = relationship("User", primaryjoin="Submission.author_id==User.id") oauth_app = relationship("OauthApp", viewonly=True) approved_by = relationship("User", uselist=False, primaryjoin="Submission.is_approved==User.id", viewonly=True) @@ -370,8 +382,6 @@ class Submission(Base): body = self.body_html or "" - body = censor_slurs(body, v) - if v: body = body.replace("old.reddit.com", v.reddit) @@ -436,8 +446,6 @@ class Submission(Base): if not body: return "" - body = censor_slurs(body, v) - if v: body = body.replace("old.reddit.com", v.reddit) @@ -457,8 +465,6 @@ class Submission(Base): elif self.title_html: title = self.title_html else: title = self.title - title = censor_slurs(title, v) - return title @lazy @@ -468,8 +474,6 @@ class Submission(Base): else: return f'{CC} MEMBERS ONLY' else: title = self.title - title = censor_slurs(title, v) - return title @property diff --git a/files/classes/subscriptions.py b/files/classes/subscriptions.py index 55baa4e08..a1b04e068 100644 --- a/files/classes/subscriptions.py +++ b/files/classes/subscriptions.py @@ -7,6 +7,8 @@ class Subscription(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) submission_id = Column(Integer, ForeignKey("submissions.id"), primary_key=True) + Index('subscription_user_index', user_id) + user = relationship("User", uselist=False, viewonly=True) def __init__(self, *args, **kwargs): diff --git a/files/classes/user.py b/files/classes/user.py index 95ab2ff3a..63f2ef70a 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -29,61 +29,68 @@ cardview = bool(int(environ.get("CARD_VIEW", 1))) class User(Base): __tablename__ = "users" + __table_args__ = ( + UniqueConstraint('bannerurl', name='one_banner'), + UniqueConstraint('discord_id', name='one_discord_account'), + UniqueConstraint('id', name='uid_unique'), + UniqueConstraint('original_username', name='users_original_username_key'), + UniqueConstraint('username', name='users_username_key'), + ) id = Column(Integer, primary_key=True) - username = Column(String) - namecolor = Column(String, default=DEFAULT_COLOR) + username = Column(String(length=255), nullable=False) + namecolor = Column(String(length=6), default=DEFAULT_COLOR, nullable=False) background = Column(String) customtitle = Column(String) customtitleplain = deferred(Column(String)) - titlecolor = Column(String, default=DEFAULT_COLOR) - theme = Column(String, default=defaulttheme) - themecolor = Column(String, default=DEFAULT_COLOR) - cardview = Column(Boolean, default=cardview) + titlecolor = Column(String(length=6), default=DEFAULT_COLOR, nullable=False) + theme = Column(String, default=defaulttheme, nullable=False) + themecolor = Column(String, default=DEFAULT_COLOR, nullable=False) + cardview = Column(Boolean, default=cardview, nullable=False) song = Column(String) highres = Column(String) profileurl = Column(String) bannerurl = Column(String) house = Column(String) - patron = Column(Integer, default=0) - patron_utc = Column(Integer, default=0) + patron = Column(Integer, default=0, nullable=False) + patron_utc = Column(Integer, default=0, nullable=False) verified = Column(String) verifiedcolor = Column(String) marseyawarded = Column(Integer) rehab = Column(Integer) longpost = Column(Integer) - winnings = Column(Integer, default=0) + winnings = Column(Integer, default=0, nullable=False) unblockable = Column(Boolean) bird = Column(Integer) email = deferred(Column(String)) css = deferred(Column(String)) profilecss = deferred(Column(String)) - passhash = deferred(Column(String)) - post_count = Column(Integer, default=0) - comment_count = Column(Integer, default=0) - received_award_count = Column(Integer, default=0) - created_utc = Column(Integer) - admin_level = Column(Integer, default=0) - coins_spent = Column(Integer, default=0) - lootboxes_bought = Column(Integer, default=0) - agendaposter = Column(Integer, default=0) - changelogsub = Column(Boolean, default=False) - is_activated = Column(Boolean, default=False) + passhash = deferred(Column(String, nullable=False)) + post_count = Column(Integer, default=0, nullable=False) + comment_count = Column(Integer, default=0, nullable=False) + received_award_count = Column(Integer, default=0, nullable=False) + created_utc = Column(Integer, nullable=False) + admin_level = Column(Integer, default=0, nullable=False) + coins_spent = Column(Integer, default=0, nullable=False) + lootboxes_bought = Column(Integer, default=0, nullable=False) + agendaposter = Column(Integer, default=0, nullable=False) + changelogsub = Column(Boolean, default=False, nullable=False) + is_activated = Column(Boolean, default=False, nullable=False) shadowbanned = Column(String) - over_18 = Column(Boolean, default=False) - hidevotedon = Column(Boolean, default=False) - highlightcomments = Column(Boolean, default=True) - slurreplacer = Column(Boolean, default=True) + over_18 = Column(Boolean, default=False, nullable=False) + hidevotedon = Column(Boolean, default=False, nullable=False) + highlightcomments = Column(Boolean, default=True, nullable=False) + slurreplacer = Column(Boolean, default=True, nullable=False) flairchanged = Column(Integer) - newtab = Column(Boolean, default=False) - newtabexternal = Column(Boolean, default=True) - reddit = Column(String, default='old.reddit.com') + newtab = Column(Boolean, default=False, nullable=False) + newtabexternal = Column(Boolean, default=True, nullable=False) + reddit = Column(String, default='old.reddit.com', nullable=False) nitter = Column(Boolean) mute = Column(Boolean) unmutable = Column(Boolean) eye = Column(Boolean) alt = Column(Boolean) - frontsize = Column(Integer, default=25) - controversial = Column(Boolean, default=False) + frontsize = Column(Integer, default=25, nullable=False) + controversial = Column(Boolean, default=False, nullable=False) bio = deferred(Column(String)) bio_html = Column(String) sig = deferred(Column(String)) @@ -97,28 +104,49 @@ class User(Base): friends_html = deferred(Column(String)) enemies = deferred(Column(String)) enemies_html = deferred(Column(String)) - is_banned = Column(Integer, default=0) - unban_utc = Column(Integer, default=0) + is_banned = Column(Integer, default=0, nullable=False) + unban_utc = Column(Integer, default=0, nullable=False) ban_reason = deferred(Column(String)) club_allowed = Column(Boolean) - login_nonce = Column(Integer, default=0) + login_nonce = Column(Integer, default=0, nullable=False) reserved = deferred(Column(String)) - coins = Column(Integer, default=0) - truecoins = Column(Integer, default=0) - procoins = Column(Integer, default=0) + coins = Column(Integer, default=0, nullable=False) + truecoins = Column(Integer, default=0, nullable=False) + procoins = Column(Integer, default=0, nullable=False) mfa_secret = deferred(Column(String)) - is_private = Column(Boolean, default=False) - stored_subscriber_count = Column(Integer, default=0) - defaultsortingcomments = Column(String, default="new") - defaultsorting = Column(String, default="new") - defaulttime = Column(String, default=defaulttimefilter) - is_nofollow = Column(Boolean, default=False) + is_private = Column(Boolean, default=False, nullable=False) + stored_subscriber_count = Column(Integer, default=0, nullable=False) + defaultsortingcomments = Column(String, default="new", nullable=False) + defaultsorting = Column(String, default="new", nullable=False) + defaulttime = Column(String, default=defaulttimefilter, nullable=False) + is_nofollow = Column(Boolean, default=False, nullable=False) custom_filter_list = Column(String) discord_id = Column(String) - ban_evade = Column(Integer, default=0) + ban_evade = Column(Integer, default=0, nullable=False) original_username = deferred(Column(String)) referred_by = Column(Integer, ForeignKey("users.id")) - subs_created = Column(Integer, default=0) + subs_created = Column(Integer, default=0, nullable=False) + + Index( + 'users_original_username_trgm_idx', + original_username, + postgresql_using='gin', + postgresql_ops={'description':'gin_trgm_ops'} + ) + Index( + 'users_username_trgm_idx', + username, + postgresql_using='gin', + postgresql_ops={'description':'gin_trgm_ops'} + ) + + Index('discord_id_idx', discord_id) + Index('fki_user_referrer_fkey', referred_by) + Index('user_banned_idx', is_banned) + Index('user_private_idx', is_private) + Index('users_created_utc_index', created_utc) + Index('users_subs_idx', stored_subscriber_count) + Index('users_unbanutc_idx', unban_utc.desc()) badges = relationship("Badge", viewonly=True) subscriptions = relationship("Subscription", viewonly=True) @@ -495,8 +523,7 @@ class User(Base): @property @lazy def profile_url(self): - if self.agendaposter: return f"{SITE_FULL}/assets/images/astolfo.webp?v=1" - if self.profileurl: + if self.profileurl: if self.profileurl.startswith('/'): return SITE_FULL + self.profileurl return self.profileurl return f"{SITE_FULL}/assets/images/default-profile-pic.webp?v=1008" diff --git a/files/classes/userblock.py b/files/classes/userblock.py index a9565c4a4..c694d0003 100644 --- a/files/classes/userblock.py +++ b/files/classes/userblock.py @@ -8,6 +8,8 @@ class UserBlock(Base): user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) + Index('block_target_idx', target_id) + user = relationship("User", primaryjoin="User.id==UserBlock.user_id", viewonly=True) target = relationship("User", primaryjoin="User.id==UserBlock.target_id", viewonly=True) diff --git a/files/classes/views.py b/files/classes/views.py index e91d094ea..29a206577 100644 --- a/files/classes/views.py +++ b/files/classes/views.py @@ -10,7 +10,9 @@ class ViewerRelationship(Base): user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) viewer_id = Column(Integer, ForeignKey('users.id'), primary_key=True) - last_view_utc = Column(Integer) + last_view_utc = Column(Integer, nullable=False) + + Index('fki_view_viewer_fkey', viewer_id) viewer = relationship("User", primaryjoin="ViewerRelationship.viewer_id == User.id", viewonly=True) diff --git a/files/classes/votes.py b/files/classes/votes.py index f2af7b524..6e83b6f2c 100644 --- a/files/classes/votes.py +++ b/files/classes/votes.py @@ -11,10 +11,13 @@ class Vote(Base): submission_id = Column(Integer, ForeignKey("submissions.id"), primary_key=True) user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - vote_type = Column(Integer) + vote_type = Column(Integer, nullable=False) app_id = Column(Integer, ForeignKey("oauth_apps.id")) - real = Column(Boolean, default=True) - created_utc = Column(Integer) + real = Column(Boolean, default=True, nullable=False) + created_utc = Column(Integer, nullable=False) + + Index('votes_type_index', vote_type) + Index('vote_user_index', user_id) user = relationship("User", lazy="subquery", viewonly=True) post = relationship("Submission", lazy="subquery", viewonly=True) @@ -52,10 +55,13 @@ class CommentVote(Base): comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True) user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) - vote_type = Column(Integer) + vote_type = Column(Integer, nullable=False) app_id = Column(Integer, ForeignKey("oauth_apps.id")) - real = Column(Boolean, default=True) - created_utc = Column(Integer) + real = Column(Boolean, default=True, nullable=False) + created_utc = Column(Integer, nullable=False) + + Index('cvote_user_index', user_id) + Index('commentvotes_comments_type_index', vote_type) user = relationship("User", lazy="subquery") comment = relationship("Comment", lazy="subquery", viewonly=True) diff --git a/files/cli.py b/files/cli.py new file mode 100644 index 000000000..ecba58ec9 --- /dev/null +++ b/files/cli.py @@ -0,0 +1,7 @@ +from flask_migrate import Migrate +from flask_sqlalchemy import SQLAlchemy +from .__main__ import app +import files.classes + +db = SQLAlchemy(app) +migrate = Migrate(app, db) diff --git a/files/helpers/const.py b/files/helpers/const.py index a388e7bad..f1310a55b 100644 --- a/files/helpers/const.py +++ b/files/helpers/const.py @@ -28,76 +28,11 @@ AJ_REPLACEMENTS = { } SLURS = { - "retarded": "r-slurred", - "retard": "r-slur", - "gayfag": "gaystrag", - "poorfag": "poorstrag", - "richfag": "richstrag", - "newfag": "newstrag", - "oldfag": "oldstrag", - "faggotry": "cute twinkry", - "faggot": "cute twink", - "pedophile": "libertarian", - "kill yourself": "keep yourself safe", - "n1gger": "BIPOC", - "nlgger": "BIPOC", - "nigger": "BIPOC", - "steve akins": "penny verity oaken", - "trannie": "🚂🚃🚃", - "tranny": "🚂🚃🚃", - "troon": "🚂🚃🚃", - "nonewnormal": "HorseDewormerAddicts", - "kikery": "https://sciencedirect.com/science/article/abs/pii/S016028960600033X", - "kike": "https://sciencedirect.com/science/article/abs/pii/S016028960600033X", - "latinos": "latinx", - "latino": "latinx", - "latinas": "latinx", - "latina": "latinx", - "hispanics": "latinx", - "hispanic": "latinx", - "uss liberty incident": "tragic accident aboard the USS Liberty", - "lavon affair": "Lavon Misunderstanding", - "shylock": "Israeli friend", - "mohammad": "Prophet Mohammad (PBUH)", - "muhammad": "Prophet Mohammad (PBUH)", - "i hate marsey": "i love marsey", - "dancing israelis": "i love Israel", - "sodomite": "total dreamboat", - "pajeet": "sexy Indian dude", - "landlord": "landchad", - "tenant": "renthog", - "renter": "rentoid", - "autistic": "neurodivergent", - "holohoax": "i tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol", - "groomercord": "discord (actually a pretty cool service)", - "pedocord": "discord (actually a pretty cool service)", - "i hate carp": "i love Carp", - "manlet": "little king", - "gamer": "g*mer", - "journalist": "journ*list", - "journalism": "journ*lism", - "wuhan flu": "SARS-CoV-2 syndemic", - "china flu": "SARS-CoV-2 syndemic", - "china virus": "SARS-CoV-2 syndemic", - "kung flu": "SARS-CoV-2 syndemic", - "elon musk": "rocket daddy", - "fake and gay": "fake and straight", - - " rapist ": " male feminist ", - " pedo ": " libertarian ", - " kys ": " keep yourself safe ", - " fag ": " cute twink ", } single_words = "|".join([slur.lower() for slur in SLURS.keys()]) -LONGPOST_REPLIES = ('Wow, you must be a JP fan.', 'This is one of the worst posts I have EVER seen. Delete it.', "No, don't reply like this, please do another wall of unhinged rant please.", '# 😴😴😴', "Ma'am we've been over this before. You need to stop.", "I've known more coherent downies.", "Your pulitzer's in the mail", "That's great and all, but I asked for my burger without cheese.", 'That degree finally paying off', "That's nice sweaty. Why don't you have a seat in the time out corner with Pizzashill until you calm down, then you can have your Capri Sun.", "All them words won't bring your pa back.", "You had a chance to not be completely worthless, but it looks like you threw it away. At least you're consistent.", 'Some people are able to display their intelligence by going on at length on a subject and never actually saying anything. This ability is most common in trades such as politics, public relations, and law. You have impressed me by being able to best them all, while still coming off as an absolute idiot.', "You can type 10,000 characters and you decided that these were the one's that you wanted.", 'Have you owned the libs yet?', "I don't know what you said, because I've seen another human naked.", 'Impressive. Normally people with such severe developmental disabilities struggle to write much more than a sentence or two. He really has exceded our expectations for the writing portion. Sadly the coherency of his writing, along with his abilities in the social skills and reading portions, are far behind his peers with similar disabilities.', "This is a really long way of saying you don't fuck.", "Sorry ma'am, looks like his delusions have gotten worse. We'll have to admit him.", ':#marseywoah:', 'If only you could put that energy into your relationships', 'Posts like this is why I do Heroine.', 'still unemployed then?', 'K', 'look im gunna have 2 ask u 2 keep ur giant dumps in the toilet not in my replys 😷😷😷', "Mommy is soooo proud of you, sweaty. Let's put this sperg out up on the fridge with all your other failures.", "Good job bobby, here's a star", "That was a mistake. You're about to find out the hard way why.", f'You sat down and wrote all this shit. You could have done so many other things with your life. What happened to your life that made you decide writing novels of bullshit on {SITE} was the best option?', "I don't have enough spoons to read this shit", "All those words won't bring daddy back.", 'OUT!', "Damn, you're really mad over this, but thanks for the effort you put into typing that all out! Sadly I won't read it all.", "Jesse what the fuck are you talking about??", "▼you're fucking bananas if you think I'm reading all that, take my downvote and shut up idiot", "Are you feeling okay bud?") - -AGENDAPOSTER_PHRASE = 'trans lives matter' - -AGENDAPOSTER_MSG = """Hi @{username},\n\nYour {type} has been automatically removed because you forgot to include `{AGENDAPOSTER_PHRASE}`.\n\nDon't worry, we're here to help! We won't let you post or comment anything that doesn't express your love and acceptance towards the trans community. Feel free to resubmit your {type} with `{AGENDAPOSTER_PHRASE}` included. \n\n*This is an automated message; if you need help, you can message us [here](/contact).*""" - NOTIFICATIONS_ID = 1 AUTOJANNY_ID = 2 SNAPPY_ID = 3 @@ -369,14 +304,6 @@ AWARDS = { "color": "text-blue", "price": 1500 }, - "agendaposter": { - "kind": "agendaposter", - "title": "Chud", - "description": "Forces the chud theme on the recipient for 24 hours.", - "icon": "fas fa-snooze", - "color": "text-purple", - "price": 2500 - }, "deflector": { "kind": "deflector", "title": "Deflector", @@ -591,38 +518,18 @@ emoji_regex3 = re.compile(f"(?([\w:~,()\-.#&\/=?@%;+]{5,250})<\/a>', flags=re.A) -email_regex = re.compile('([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,100})+', flags=re.A) +# Technically this allows stuff that is not a valid email address, but realistically +# we care "does this email go to the correct person" rather than "is this email +# address syntactically valid", so if we care we should be sending a confirmation +# link, and otherwise should be pretty liberal in what we accept here. +email_regex = re.compile('[^@]+@[^@]+\.[^@]+', flags=re.A) utm_regex = re.compile('utm_[a-z]+=[a-z0-9_]+&', flags=re.A) utm_regex2 = re.compile('[?&]utm_[a-z]+=[a-z0-9_]+', flags=re.A) -slur_regex = re.compile(f"({single_words})(?![^<]*>)", flags=re.I|re.A) -slur_regex_upper = re.compile(f"({single_words.upper()})(?![^<]*>)", flags=re.A) -torture_regex = re.compile('(^|\s)(i|me) ', flags=re.I|re.A) -torture_regex2 = re.compile("(^|\s)i'm ", flags=re.I|re.A) - -def sub_matcher(match): - return SLURS[match.group(0).lower()] - -def sub_matcher_upper(match): - return SLURS[match.group(0).lower()].upper() - -def censor_slurs(body, logged_user): - if not logged_user or logged_user == 'chat' or logged_user.slurreplacer: - body = slur_regex_upper.sub(sub_matcher_upper, body) - body = slur_regex.sub(sub_matcher, body) - return body - -def torture_ap(body, username): - for k, l in AJ_REPLACEMENTS.items(): - body = body.replace(k, l) - body = torture_regex.sub(rf'\1@{username} ', body) - body = torture_regex2.sub(rf'\1@{username} is ', body) - return body - YOUTUBE_KEY = environ.get("YOUTUBE_KEY", "").strip() -ADMIGGERS = (37696,37697,37749,37833,37838) +ADMINISTRATORS = (37696, 37697, 37749, 37833, 37838) proxies = {"http":"http://127.0.0.1:18080","https":"http://127.0.0.1:18080"} diff --git a/files/helpers/jinja2.py b/files/helpers/jinja2.py index 6841a4a23..803ebfe28 100644 --- a/files/helpers/jinja2.py +++ b/files/helpers/jinja2.py @@ -49,4 +49,4 @@ def timestamp(timestamp): @app.context_processor def inject_constants(): - return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, "AUTOJANNY_ID":AUTOJANNY_ID, "NOTIFICATIONS_ID":NOTIFICATIONS_ID, "PUSHER_ID":PUSHER_ID, "CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "MOOSE_ID":MOOSE_ID, "AEVANN_ID":AEVANN_ID, "PIZZASHILL_ID":PIZZASHILL_ID, "config":app.config.get, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "ADMIGGERS":ADMIGGERS} + return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, "AUTOJANNY_ID":AUTOJANNY_ID, "NOTIFICATIONS_ID":NOTIFICATIONS_ID, "PUSHER_ID":PUSHER_ID, "CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "MOOSE_ID":MOOSE_ID, "AEVANN_ID":AEVANN_ID, "PIZZASHILL_ID":PIZZASHILL_ID, "config":app.config.get, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "ADMIGGERS":ADMINISTRATORS} diff --git a/files/helpers/sanitize.py b/files/helpers/sanitize.py index 8cddf914d..f45a124cf 100644 --- a/files/helpers/sanitize.py +++ b/files/helpers/sanitize.py @@ -191,26 +191,26 @@ def sanitize(sanitized, alert=False, comment=False, edit=False): marseys_used = set() - emojis = list(emoji_regex.finditer(sanitized)) - if len(emojis) > 20: edit = True + # emojis = list(emoji_regex.finditer(sanitized)) + # if len(emojis) > 20: edit = True - captured = [] - for i in emojis: - if i.group(0) in captured: continue - captured.append(i.group(0)) + # captured = [] + # for i in emojis: + # if i.group(0) in captured: continue + # captured.append(i.group(0)) - old = i.group(0) - if 'marseylong1' in old or 'marseylong2' in old or 'marseyllama1' in old or 'marseyllama2' in old: new = old.lower().replace(">", " class='mb-0'>") - else: new = old.lower() + # old = i.group(0) + # if 'marseylong1' in old or 'marseylong2' in old or 'marseyllama1' in old or 'marseyllama2' in old: new = old.lower().replace(">", " class='mb-0'>") + # else: new = old.lower() - new = render_emoji(new, emoji_regex2, edit, marseys_used, True) + # new = render_emoji(new, emoji_regex2, edit, marseys_used, True) - sanitized = sanitized.replace(old, new) + # sanitized = sanitized.replace(old, new) - emojis = list(emoji_regex2.finditer(sanitized)) - if len(emojis) > 20: edit = True + # emojis = list(emoji_regex2.finditer(sanitized)) + # if len(emojis) > 20: edit = True - sanitized = render_emoji(sanitized, emoji_regex2, edit, marseys_used) + # sanitized = render_emoji(sanitized, emoji_regex2, edit, marseys_used) for rd in ["://reddit.com", "://new.reddit.com", "://www.reddit.com", "://redd.it", "://libredd.it", "://teddit.net"]: sanitized = sanitized.replace(rd, "://old.reddit.com") @@ -315,7 +315,7 @@ def filter_emojis_only(title, edit=False, graceful=False): title = title.replace('‎','').replace('​','').replace("\ufeff", "").replace("𒐪","").replace("\n", "").replace("\r", "").replace("\t", "").replace("&", "&").replace('<','<').replace('>','>').replace('"', '"').replace("'", "'").strip() - title = render_emoji(title, emoji_regex3, edit) + # title = render_emoji(title, emoji_regex3, edit) title = strikethrough_regex.sub(r'\1', title) diff --git a/files/routes/admin.py b/files/routes/admin.py index b5e537f26..5a05782cd 100644 --- a/files/routes/admin.py +++ b/files/routes/admin.py @@ -950,77 +950,6 @@ def admin_removed_comments(v): ) -@app.post("/agendaposter/") -@admin_level_required(2) -def agendaposter(user_id, v): - user = g.db.query(User).filter_by(id=user_id).one_or_none() - - days = request.values.get("days") or 30 - expiry = float(days) - expiry = int(time.time() + expiry*60*60*24) - - user.agendaposter = expiry - g.db.add(user) - - for alt in user.alts: - if alt.admin_level: return {"error": "User is an admin!"} - alt.agendaposter = expiry - g.db.add(alt) - - note = f"for {days} days" - - ma = ModAction( - kind="agendaposter", - user_id=v.id, - target_user_id=user.id, - note = note - ) - g.db.add(ma) - - if not user.has_badge(28): - badge = Badge(user_id=user.id, badge_id=28) - g.db.add(badge) - g.db.flush() - send_notification(user.id, f"@AutoJanny has given you the following profile badge:\n\n![]({badge.path})\n\n{badge.name}") - - - send_repeatable_notification(user.id, f"@{v.username} has marked you as a chud ({note}).") - - g.db.commit() - - return redirect(user.url) - - - -@app.post("/unagendaposter/") -@admin_level_required(2) -def unagendaposter(user_id, v): - user = g.db.query(User).filter_by(id=user_id).one_or_none() - - user.agendaposter = 0 - g.db.add(user) - - for alt in user.alts: - alt.agendaposter = 0 - g.db.add(alt) - - ma = ModAction( - kind="unagendaposter", - user_id=v.id, - target_user_id=user.id - ) - - g.db.add(ma) - - badge = user.has_badge(28) - if badge: g.db.delete(badge) - - send_repeatable_notification(user.id, f"@{v.username} has unmarked you as a chud.") - - g.db.commit() - return {"message": "Chud theme disabled!"} - - @app.post("/shadowban/") @limiter.limit("1/second;30/minute;200/hour;1000/day") @admin_level_required(2) @@ -1538,9 +1467,6 @@ def api_unban_comment(c_id, v): comment = g.db.query(Comment).filter_by(id=c_id).one_or_none() if not comment: abort(404) - if comment.author.agendaposter and AGENDAPOSTER_PHRASE not in comment.body.lower(): - return {"error": "You can't bypass the chud award!"} - if comment.is_banned: ma=ModAction( kind="unban_comment", diff --git a/files/routes/awards.py b/files/routes/awards.py index 6339969d5..2105a065d 100644 --- a/files/routes/awards.py +++ b/files/routes/awards.py @@ -213,18 +213,6 @@ def award_post(pid, v): cache.delete_memoized(frontlist) else: post.stickied_utc = t g.db.add(post) - elif kind == "agendaposter" and not (author.agendaposter and author.agendaposter == 0): - if author.marseyawarded: - return {"error": "This user is the under the effect of a conflicting award: Marsey award."}, 404 - - if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400 - else: author.agendaposter = int(time.time()) + 86400 - - if not author.has_badge(28): - badge = Badge(user_id=author.id, badge_id=28) - g.db.add(badge) - g.db.flush() - send_notification(author.id, f"@AutoJanny has given you the following profile badge:\n\n![]({badge.path})\n\n{badge.name}") elif kind == "flairlock": new_name = note[:100].replace("𒐪","") if not new_name and author.flairchanged: @@ -451,18 +439,6 @@ def award_comment(cid, v): c.is_pinned_utc = None else: c.is_pinned_utc = t g.db.add(c) - elif kind == "agendaposter" and not (author.agendaposter and author.agendaposter == 0): - if author.marseyawarded: - return {"error": "This user is the under the effect of a conflicting award: Marsey award."}, 404 - - if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400 - else: author.agendaposter = int(time.time()) + 86400 - - if not author.has_badge(28): - badge = Badge(user_id=author.id, badge_id=28) - g.db.add(badge) - g.db.flush() - send_notification(author.id, f"@AutoJanny has given you the following profile badge:\n\n![]({badge.path})\n\n{badge.name}") elif kind == "flairlock": new_name = note[:100].replace("𒐪","") if not new_name and author.flairchanged: diff --git a/files/routes/chat.py b/files/routes/chat.py index 004b2b4b3..706595093 100644 --- a/files/routes/chat.py +++ b/files/routes/chat.py @@ -55,7 +55,7 @@ def speak(data, v): "namecolor": v.namecolor, "text": text, "text_html": text_html, - "text_censored": censor_slurs(text_html, 'chat'), + "text_censored": text, "time": int(time.time()) } diff --git a/files/routes/comments.py b/files/routes/comments.py index ed30c332a..22278c24c 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -7,7 +7,6 @@ from files.helpers.blackjack import * from files.helpers.treasure import * from files.classes import * from files.routes.front import comment_idlist -from files.routes.static import marsey_list from pusher_push_notifications import PushNotifications from flask import * from files.__main__ import app, limiter @@ -189,7 +188,7 @@ def api_comment(v): with open(f"snappy_{SITE_NAME}.txt", "a", encoding="utf-8") as f: f.write('\n{[para]}\n' + body) - if parent_post.id not in ADMIGGERS: + if parent_post.id not in ADMINISTRATORS: if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')): return {"error":"You have to type more than 280 characters!"}, 403 elif v.bird and len(body) > 140: @@ -243,59 +242,6 @@ def api_comment(v): requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data={'files': [f"https://{request.host}/assets/images/badges/{badge.id}.webp"]}, timeout=5) except Exception as e: return {"error": str(e)}, 400 - elif v.admin_level > 2 and parent_post.id == 37838: - try: - marsey = loads(body.lower()) - - name = marsey["name"] - if not marsey_regex.fullmatch(name): return {"error": "Invalid name!"}, 400 - existing = g.db.query(Marsey.name).filter_by(name=name).one_or_none() - if existing: return {"error": "A marsey with this name already exists!"}, 403 - - tags = marsey["tags"] - if not tags_regex.fullmatch(tags): return {"error": "Invalid tags!"}, 400 - - if "author" in marsey: user = get_user(marsey["author"]) - elif "author_id" in marsey: user = get_account(marsey["author_id"]) - else: abort(400) - - filename = f'files/assets/images/emojis/{name}.webp' - copyfile(oldname, filename) - process_image(filename, 200) - - marsey = Marsey(name=name, author_id=user.id, tags=tags, count=0) - g.db.add(marsey) - g.db.flush() - - all_by_author = g.db.query(Marsey.author_id).filter_by(author_id=user.id).count() - - if all_by_author >= 10 and not user.has_badge(16): - new_badge = Badge(badge_id=16, user_id=user.id) - - g.db.add(new_badge) - g.db.flush() - - if v.id != user.id: - text = f"@AutoJanny has given you the following profile badge:\n\n![]({new_badge.path})\n\n{new_badge.name}" - send_notification(user.id, text) - - elif all_by_author < 10 and not user.has_badge(17): - new_badge = Badge(badge_id=17, user_id=user.id) - - g.db.add(new_badge) - g.db.flush() - - if v.id != user.id: - text = f"@AutoJanny has given you the following profile badge:\n\n![]({new_badge.path})\n\n{new_badge.name}" - send_notification(user.id, text) - - - - requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data={'files': [f"https://{request.host}/e/{name}.webp"]}, timeout=5) - cache.delete_memoized(marsey_list) - - except Exception as e: - return {"error": str(e)}, 400 body += f"\n\n![]({image})" elif file.content_type.startswith('video/'): file.save("video.mp4") @@ -311,13 +257,9 @@ def api_comment(v): body += f"\n\n{url}" else: return {"error": "Image/Video files only"}, 400 - if v.agendaposter and not v.marseyawarded and parent_post.id not in ADMIGGERS: - body = torture_ap(body, v.username) - body_html = sanitize(body, comment=True) - - if parent_post.id not in ADMIGGERS and '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower(): + if parent_post.id not in ADMINISTRATORS and '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower(): existing = g.db.query(Comment.id).filter(Comment.author_id == v.id, Comment.deleted_utc == 0, Comment.parent_comment_id == parent_comment_id, @@ -331,7 +273,7 @@ def api_comment(v): is_bot = bool(request.headers.get("Authorization")) - if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and parent_post.id not in ADMIGGERS and not is_bot and not v.marseyawarded and AGENDAPOSTER_PHRASE not in body.lower() and len(body) > 10: + if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and parent_post.id not in ADMINISTRATORS and not is_bot and not v.marseyawarded and len(body) > 10: now = int(time.time()) cutoff = now - 60 * 60 * 24 @@ -419,39 +361,7 @@ def api_comment(v): g.db.add(c_choice) - if parent_post.id not in ADMIGGERS: - if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower(): - - c.is_banned = True - c.ban_reason = "AutoJanny" - - g.db.add(c) - - - body = AGENDAPOSTER_MSG.format(username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) - - body_jannied_html = sanitize(body) - - - - c_jannied = Comment(author_id=NOTIFICATIONS_ID, - parent_submission=parent_submission, - distinguish_level=6, - parent_comment_id=c.id, - level=level+1, - is_bot=True, - body_html=body_jannied_html, - top_comment_id=c.top_comment_id, - ghost=parent_post.ghost - ) - - g.db.add(c_jannied) - g.db.flush() - - n = Notification(comment_id=c_jannied.id, user_id=v.id) - g.db.add(n) - - + if parent_post.id not in ADMINISTRATORS: if not v.shadowbanned: notify_users = NOTIFY_USERS(body, v) @@ -500,7 +410,7 @@ def api_comment(v): check_for_blackjack_commands(body, v, c) - if not c.slots_result and not c.blackjack_result and v.marseyawarded and parent_post.id not in ADMIGGERS and marseyaward_body_regex.search(body_html): + if not c.slots_result and not c.blackjack_result and v.marseyawarded and parent_post.id not in ADMINISTRATORS and marseyaward_body_regex.search(body_html): return {"error":"You can only type marseys!"}, 403 check_for_treasure(body, c) @@ -540,9 +450,6 @@ def edit_comment(cid, v): elif v.bird and len(body) > 140: return {"error":"You have to type less than 140 characters!"}, 403 - if v.agendaposter and not v.marseyawarded: - body = torture_ap(body, v.username) - if not c.options: for i in poll_regex.finditer(body): body = body.replace(i.group(0), "") @@ -571,7 +478,7 @@ def edit_comment(cid, v): body_html = sanitize(body, edit=True) - if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower(): + if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower(): now = int(time.time()) cutoff = now - 60 * 60 * 24 @@ -645,39 +552,6 @@ def edit_comment(cid, v): notif = Notification(comment_id=c.id, user_id=CARP_ID) g.db.add(notif) - if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and not c.is_banned: - - c.is_banned = True - c.ban_reason = "AutoJanny" - - g.db.add(c) - - - body = AGENDAPOSTER_MSG.format(username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) - - body_jannied_html = sanitize(body) - - - - c_jannied = Comment(author_id=NOTIFICATIONS_ID, - parent_submission=c.parent_submission, - distinguish_level=6, - parent_comment_id=c.id, - level=c.level+1, - is_bot=True, - body_html=body_jannied_html, - top_comment_id=c.top_comment_id, - ghost=c.ghost - ) - - g.db.add(c_jannied) - g.db.flush() - - n = Notification(comment_id=c_jannied.id, user_id=v.id) - g.db.add(n) - - - if int(time.time()) - c.created_utc > 60 * 3: c.edited_utc = int(time.time()) g.db.add(c) diff --git a/files/routes/front.py b/files/routes/front.py index 3ec529df8..53cd6c107 100644 --- a/files/routes/front.py +++ b/files/routes/front.py @@ -227,14 +227,6 @@ def front_all(v, sub=None, subdomain=None): g.db.add(v) g.db.commit() - if v.agendaposter and v.agendaposter < time.time(): - v.agendaposter = 0 - send_repeatable_notification(v.id, "Your chud theme has expired!") - g.db.add(v) - badge = v.has_badge(28) - if badge: g.db.delete(badge) - g.db.commit() - if v.flairchanged and v.flairchanged < time.time(): v.flairchanged = None send_repeatable_notification(v.id, "Your flair lock has expired. You can now change your flair!") diff --git a/files/routes/login.py b/files/routes/login.py index 38fd6c7cb..31c4fda7a 100644 --- a/files/routes/login.py +++ b/files/routes/login.py @@ -321,7 +321,7 @@ def sign_up_post(v): session["history"] = [] else: admin_level=0 - profileurl = '/e/' + random.choice(marseys_const) + '.webp' + profileurl = '/e/feather.webp' new_user = User( username=username, @@ -332,7 +332,7 @@ def sign_up_post(v): referred_by=ref_id or None, ban_evade = int(any((x.is_banned or x.shadowbanned) and not x.unban_utc for x in g.db.query(User).filter(User.id.in_(session.get("history", []))).all() if x)), profileurl=profileurl - ) + ) g.db.add(new_user) g.db.flush() diff --git a/files/routes/posts.py b/files/routes/posts.py index 84bbd1748..1e3fce2bf 100644 --- a/files/routes/posts.py +++ b/files/routes/posts.py @@ -434,7 +434,6 @@ def edit_post(pid, v): return {"error":"You have to type less than 140 characters!"}, 403 if title != p.title: - if v.id == p.author_id and v.agendaposter and not v.marseyawarded: title = torture_ap(title, v.username) title_html = filter_emojis_only(title, edit=True) @@ -467,8 +466,6 @@ def edit_post(pid, v): else: return {"error": "Image/Video files only"}, 400 if body != p.body: - if v.id == p.author_id and v.agendaposter and not v.marseyawarded: body = torture_ap(body, v.username) - if not p.options: for i in poll_regex.finditer(body): body = body.replace(i.group(0), "") @@ -498,7 +495,6 @@ def edit_post(pid, v): if v.id == p.author_id and v.marseyawarded and marseyaward_body_regex.search(body_html): return {"error":"You can only type marseys!"}, 403 - p.body = body if blackjack and any(i in f'{p.body} {p.title} {p.url}'.lower() for i in blackjack.split()): @@ -510,37 +506,6 @@ def edit_post(pid, v): p.body_html = body_html - if v.id == p.author_id and v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in f'{p.body}{p.title}'.lower() and not p.is_banned: - - p.is_banned = True - p.ban_reason = "AutoJanny" - - g.db.add(p) - - body = AGENDAPOSTER_MSG.format(username=v.username, type='post', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) - - body_jannied_html = sanitize(body) - - c_jannied = Comment(author_id=NOTIFICATIONS_ID, - parent_submission=p.id, - level=1, - over_18=False, - is_bot=True, - app_id=None, - is_pinned='AutoJanny', - distinguish_level=6, - body_html=body_jannied_html, - ghost=p.ghost - ) - - g.db.add(c_jannied) - g.db.flush() - - c_jannied.top_comment_id = c_jannied.id - - n = Notification(comment_id=c_jannied.id, user_id=v.id) - g.db.add(n) - if not p.private and not p.ghost: notify_users = NOTIFY_USERS(f'{p.title} {p.body}', v) if notify_users: @@ -789,21 +754,10 @@ def submit_post(v, sub=None): if v.is_suspended: return error("You can't perform this action while banned.") - if v.agendaposter and not v.marseyawarded: title = torture_ap(title, v.username) - title_html = filter_emojis_only(title, graceful=True) - if v.marseyawarded and not marseyaward_title_regex.fullmatch(title_html): - return error("You can only type marseys!") - if len(title_html) > 1500: return error("Rendered title is too big!") - if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')): - return error("You have to type more than 280 characters!") - elif v.bird and len(body) > 140: - return error("You have to type less than 140 characters!") - - embed = None if url: @@ -889,7 +843,6 @@ def submit_post(v, sub=None): if not title: return error("Please enter a better title.") - elif len(title) > 500: return error("There's a 500 character limit for titles.") @@ -969,8 +922,6 @@ def submit_post(v, sub=None): choices.append(i.group(1)) body = body.replace(i.group(0), "") - if v.agendaposter and not v.marseyawarded: body = torture_ap(body, v.username) - if request.files.get("file2") and request.headers.get("cf-ipcountry") != "T1": files = request.files.getlist('file2')[:4] for file in files: @@ -995,9 +946,6 @@ def submit_post(v, sub=None): body_html = sanitize(body) - if v.marseyawarded and marseyaward_body_regex.search(body_html): - return error("You can only type marseys!") - if len(body_html) > 40000: return error("Submission body_html too long! (max 40k characters)") club = bool(request.values.get("club","")) @@ -1006,11 +954,6 @@ def submit_post(v, sub=None): is_bot = bool(request.headers.get("Authorization")) - if request.values.get("ghost") and v.coins >= 100: - v.coins -= 100 - ghost = True - else: ghost = False - post = Submission( private=bool(request.values.get("private","")), club=club, @@ -1025,7 +968,7 @@ def submit_post(v, sub=None): title=title[:500], title_html=title_html, sub=sub, - ghost=ghost, + ghost=False, filter_state='filtered' if v.admin_level == 0 else 'normal' ) @@ -1105,9 +1048,6 @@ def submit_post(v, sub=None): if not post.thumburl and post.url: gevent.spawn(thumbnail_thread, post.id) - - - if not post.private and not post.ghost: notify_users = NOTIFY_USERS(f'{title} {body}', v) @@ -1127,40 +1067,6 @@ def submit_post(v, sub=None): if post.club and not user.paid_dues: continue add_notif(cid, user.id) - - - - - if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in f'{post.body}{post.title}'.lower(): - post.is_banned = True - post.ban_reason = "AutoJanny" - - body = AGENDAPOSTER_MSG.format(username=v.username, type='post', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) - - body_jannied_html = sanitize(body) - - - - c_jannied = Comment(author_id=NOTIFICATIONS_ID, - parent_submission=post.id, - level=1, - over_18=False, - is_bot=True, - app_id=None, - is_pinned='AutoJanny', - distinguish_level=6, - body_html=body_jannied_html, - ) - - g.db.add(c_jannied) - g.db.flush() - - c_jannied.top_comment_id = c_jannied.id - - n = Notification(comment_id=c_jannied.id, user_id=v.id) - g.db.add(n) - - v.post_count = g.db.query(Submission.id).filter_by(author_id=v.id, is_banned=False, deleted_utc=0).count() g.db.add(v) diff --git a/files/routes/settings.py b/files/routes/settings.py index 06e8d066a..b7b39ca0e 100644 --- a/files/routes/settings.py +++ b/files/routes/settings.py @@ -611,8 +611,6 @@ def settings_css_get(v): @limiter.limit("1/second;30/minute;200/hour;1000/day") @auth_required def settings_css(v): - if v.agendaposter: return {"error": "Agendapostered users can't edit css!"} - css = request.values.get("css").strip().replace('\\', '').strip()[:4000] v.css = css g.db.add(v) diff --git a/files/routes/users.py b/files/routes/users.py index 2bd42a3f1..f9e8e28d2 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -252,12 +252,6 @@ def grassed(v): return render_template("grassed.html", v=v, users=users) -@app.get("/agendaposters") -@auth_required -def agendaposters(v): - users = [x for x in g.db.query(User).filter(User.agendaposter > 0).order_by(User.username).all()] - return render_template("agendaposters.html", v=v, users=users) - @app.get("/@/upvoters") @auth_required @@ -581,8 +575,6 @@ def message2(v, username): if not message: return {"error": "Message is empty!"} - if 'linkedin.com' in message: return {"error": "This domain 'linkedin.com' is banned."}, 403 - body_html = sanitize(message) existing = g.db.query(Comment.id).filter(Comment.author_id == v.id, @@ -639,8 +631,6 @@ def messagereply(v): if not message and not request.files.get("file"): return {"error": "Message is empty!"} - if 'linkedin.com' in message: return {"error": "this domain 'linkedin.com' is banned"} - id = int(request.values.get("parent_id")) parent = get_comment(id, v=v) user_id = parent.author.id diff --git a/files/routes/votes.py b/files/routes/votes.py index e9bd716d3..a0869937e 100644 --- a/files/routes/votes.py +++ b/files/routes/votes.py @@ -94,7 +94,9 @@ def api_vote_post(post_id, new, v): post.author.truecoins += coin_delta g.db.add(post.author) - if new == 1 and (v.agendaposter or v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url.startswith('/e/') and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False + DEFAULT_IMAGE = '/assets/images/default-profile-pic.webp' + + if new == 1 and (v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url == DEFAULT_IMAGE and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False else: real = True vote = Vote(user_id=v.id, @@ -162,7 +164,9 @@ def api_vote_comment(comment_id, new, v): comment.author.truecoins += coin_delta g.db.add(comment.author) - if new == 1 and (v.agendaposter or v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url.startswith('/e/') and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False + DEFAULT_IMAGE = '/assets/images/default-profile-pic.webp' + + if new == 1 and (v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url == DEFAULT_IMAGE and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False else: real = True vote = CommentVote(user_id=v.id, diff --git a/files/templates/admin/admin_home.html b/files/templates/admin/admin_home.html index ee6d44235..9475233a7 100644 --- a/files/templates/admin/admin_home.html +++ b/files/templates/admin/admin_home.html @@ -27,7 +27,6 @@
  • Users Feed
  • Shadowbanned Users
  • Permabanned Users
  • -
  • Users with Chud Theme
  • Currently Grassed Users
  • diff --git a/files/templates/authforms.html b/files/templates/authforms.html index 757c559a1..e6788f1ff 100644 --- a/files/templates/authforms.html +++ b/files/templates/authforms.html @@ -17,25 +17,7 @@ - {% if v.agendaposter %} - - {% elif v.css %} + {% if v.css %} {% endif %} {% else %} diff --git a/files/templates/chat.html b/files/templates/chat.html index 790844aac..6becb0213 100644 --- a/files/templates/chat.html +++ b/files/templates/chat.html @@ -170,7 +170,6 @@ - @@ -190,9 +189,6 @@ -{% include "emoji_modal.html" %} -{% include "expanded_image_modal.html" %} - diff --git a/files/templates/comments.html b/files/templates/comments.html index 6c1cc36a1..9e9fac819 100644 --- a/files/templates/comments.html +++ b/files/templates/comments.html @@ -287,7 +287,7 @@ {% endif %} -
    +
    {{c.realbody(v) | safe}}
    {% if c.parent_submission %} @@ -310,8 +310,6 @@   - -