// vim:set fileencoding=utf-8 sw=2 ts=2 sts=2: // encoding test: rød grød med fløde æ ø å // ==UserScript== // @name TK-navne på Facebook // @author Asger Hautop Drewsen // @namespace http://tyilo.com/ // @description Ændrer folks navne til hvad de er kendt som på TÅGEKAMMERET // @include https://www.facebook.com/* // @include https://www.messenger.com/* // @version 0.5.6 // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== var C = ('' +'\u2102'); window['TKconfig'] = ({ // We don't write RemToR anywhere //'epsilon': 'e', // Dollar sign used to write KA$$ 'dollar': '$', // C used to write CERM 'cermC': C, // C used to write VC 'vcC': C, // Whether exponents should be written as superscripts 'eksponent': true, // From which year prefixes are computed 'gf': 2022, // True if we should write a prefix in front of a FU title 'FUprefix': false }); var EFUITcount = -1; function TK(key) { return window['TKconfig'][key]; } function tk_prefix(year) { var prefixes = ['', 'G', 'B', 'O', 'TO']; if (0 <= year && year < prefixes.length) { return prefixes[year]; } if (year == -1) return 'K'; var negative = false; var exponent = year - 3; if (year < 0) { exponent = -year; negative = true; } exponent = exponent+''; var exponentString = ''; if (TK('eksponent')) { var s = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'] for (var i = 0; i < exponent.length; ++i) exponentString += s[exponent.charCodeAt(i) - 48]; } else { exponentString = exponent; } return negative ? 'K'+exponentString : 'T'+exponentString+'O'; } function year_prefix(year) { return tk_prefix(TK('gf') - year); } function title_bling(title) { if (title == "KASS") return "KA" + TK('dollar') + TK('dollar'); if (title == 'CERM') return TK('cermC') + "ERM"; if (title == 'VC') return "V" + TK('vcC'); return title; } var svg = {}; var html_TK = ( 'TÅGEKAMMER'); var html_TKET = html_TK + 'ET'; /////////////////////////////////////////////////////////////////////////////// // Callback generator for add_alias. /////////////////////////////////////////////////////////////////////////////// function insert_TK_html(h) { return function (n, orig_string) { var replaced = document.createElement('span'); replaced.style.fontFamily = 'monospace'; replaced.style.fontWeight = 'normal'; replaced.style.display = 'inline-block'; replaced.style.whiteSpace = 'nowrap'; replaced.className = 'tket'; replaced.innerHTML = h; n.parentNode.insertBefore(replaced, n); }; } var aliases = {'replacements': {}, 'targets': []}; /////////////////////////////////////////////////////////////////////////////// // Add a text replacement. // // `source` is a string to watch for in DOM text nodes. // Whenever `source` is found, the function `destination` is invoked with two // parameters: the insertion point of the replacement text, and the original // replaced text. /////////////////////////////////////////////////////////////////////////////// function add_alias(source, destination) { // June 12, 2013: // On latin1 pages, the utf8 strings in this script do not match with // non-ascii characters. I don't know how to do this for all // characters, so give special treatment to those special letters. // This appears to fix it for both Firefox 24 and Chromium 27. source = (source .replace(/æ/g, '\xe6') .replace(/ø/g, '\xf8') .replace(/å/g, '\xe5') .replace(/Æ/g, '\xc6') .replace(/Ø/g, '\xd8') .replace(/Å/g, '\xc5')); aliases.targets.push('\\b' + source + '\\b'); aliases.replacements[source] = destination; } function like_button(s) { return function like_button_cb(ip, txt) { if (ip.parentNode.classList.contains('UFILikeLink')) { ip.parentNode.insertBefore(document.createTextNode(s), ip); } else { return false; } }; } function like_verb(s) { return function like_verb_cb(ip, txt) { if (ip.parentNode.parentNode.parentNode.classList.contains('UFILikeSentenceText')) { ip.parentNode.insertBefore(document.createTextNode(s), ip); } else { return false; } }; } add_alias('TÅGEKAMMERET', insert_TK_html(html_TKET)); add_alias('TÅGEKAMMER', insert_TK_html(html_TK)); //add_alias('Like', like_button('Find this strange')); //add_alias('Unlike', like_button('No longer find this strange')); //add_alias('likes this', like_verb('finds this strange')); //add_alias('like this', like_verb('find this strange')); //add_alias('Synes godt om', like_button('Finder det unaturligt')); //add_alias('Synes ikke længere godt om', like_button('Finder det ikke længere unaturligt')); //add_alias('synes godt om dette', like_verb('finder dette unaturligt')); var alias_regexp; function compute_alias_regexp() { alias_regexp = new RegExp(aliases.targets.join('|')); } compute_alias_regexp(); /////////////////////////////////////////////////////////////////////////////// // Parse input line to an object. /////////////////////////////////////////////////////////////////////////////// function parse_alias(line) { var prefixed = /^(\d+) +([^ ]+) +(.*)/.exec(line); if (prefixed) { var o = {'name': prefixed[3], 'year': parseInt(prefixed[1]), 'title': prefixed[2]}; if (o['title'] == 'EFUIT') { EFUITcount = Math.max(EFUITcount, o['year']); } return o; } var hangaround = /^"([^"]*)" +(.*)/.exec(line); if (hangaround) { return {'name': hangaround[2], 'nickname': hangaround[1]}; } return null; } /////////////////////////////////////////////////////////////////////////////// // Parse input lines, sending objects to a callback function. /////////////////////////////////////////////////////////////////////////////// function parse_aliases(input, cb) { var lineMatch; var re = /^.+$/mg; while (lineMatch = re.exec(input)) { var line = lineMatch[0]; var parsed = parse_alias(line); cb(parsed, line); } } /////////////////////////////////////////////////////////////////////////////// // Given a parsed input line object, produce the fancy unicode text to insert. /////////////////////////////////////////////////////////////////////////////// function make_title(o) { if (o['nickname']) return o['nickname']; var title = o['title']; var fancy = title_bling(o['title']); if ('year' in o) { var year = o['year']; var addPrefix = false; var efuit = false; if (title == 'FUAN') { addPrefix = true; } else if (title == 'FU') { // Unnamed FU (e.g. KFU); always show prefix addPrefix = true; } else if (title == 'EFUIT') { // EFUIT title addPrefix = false; efuit = true; } else if (title.substring(0, 2) != 'FU') { // BEST title addPrefix = true; } else { // Ordinary FU addPrefix = TK('FUprefix'); } if (efuit) { fancy = tk_prefix(EFUITcount - year) + fancy; } if (addPrefix) { fancy = year_prefix(year) + fancy; } } return fancy; } /////////////////////////////////////////////////////////////////////////////// // Callback generator for add_alias. /////////////////////////////////////////////////////////////////////////////// function insert_alias(o) { var cb = function (n, orig_string) { var str = make_title(o); var prefixSVG = o['title'] ? (/^FU/.exec(o['title']) ? 'FU' : o['title']) : (/^(T[0-9]*O|[GBO]?)EFUIT/.exec(o['nickname']) ? 'EFUIT' : ''); if (o['title'] == 'KASS' && o['year'] < 2014) { prefixSVG = 'INKA'; } // TODO make sure the svg is not separated by a line break from the title. if (svg[prefixSVG]) { var before = document.createElement('span'); before.innerHTML = svg[prefixSVG]; n.parentNode.insertBefore(before, n); } var replaced = document.createElement('span'); replaced.title = orig_string; replaced.className = 'tk_title'; replaced.innerHTML = str; n.parentNode.insertBefore(replaced, n); }; return cb; } /////////////////////////////////////////////////////////////////////////////// // Given a parsed input line object, add the appropriate alias. /////////////////////////////////////////////////////////////////////////////// function add_parsed_alias(o, origLine) { if (!o) { // parse error console.log("Failed to parse input line: ["+origLine+"]"); return; } add_alias(o['name'], insert_alias(o)); } /////////////////////////////////////////////////////////////////////////////// // Recursively apply transformation to all text nodes in a DOM subtree. /////////////////////////////////////////////////////////////////////////////// function search_for_names(n) { var to_visit = [n]; var l = 1; var first = true; while (l > 0) { var n = to_visit[--l]; if (n.nodeType == 1) { // Recurse through all child nodes of this DOM element. var c = n.lastChild; while (c) { var n = c.previousSibling; to_visit[l++] = c; c = n; } } else if (n.nodeType == 3) { if (n.parentNode.isContentEditable) continue; // We are in a DOM text node. // Replace every occurrence of a real name with an alias. // If the node contains x substrings, // we split this text node into 2x+1 parts. var o = alias_regexp.exec(n.nodeValue); while (o) { // We currently have n.nodeValue == a+b+c, // and b needs to be replaced with f(b). // f(b) is not necessarily just a text string; // it could be an arbitrary sequence of DOM nodes. // Therefore, we split `n` into three parts: // A text node containing `a`, the dom nodes `f(b)`, // and a text node containing `c`. // We have to recurse on `c` (the rest of the text), // so in reality we just insert `a` and `f(b)` // before `n` and replace `n` with `c`. // Insert (possibly empty) text node `a` before `n`: var prev = n.previousSibling; var before = document.createTextNode(n.nodeValue.substring(0, o.index)); if (!first) n.parentNode.insertBefore(before, n); var next = n; // Insert nodes `f(b)` before n (might be a no-op if f(b) is empty): if (aliases.replacements[o[0]](n, o[0]) === false) { if (first) { // Nothing was inserted and nothing has been done yet. } else { // Nothing was inserted, but we previously changed something. n.parentNode.insertBefore(document.createTextNode(o[0]), n); } } else { if (first) { // The replacement inserted something but we didn't insert `before`. var afterprev = ((prev === null) ? n.parentNode.firstChild : prev = prev.nextSibling); if (afterprev === null) { n.parentNode.appendChild(before); } else { n.parentNode.insertBefore(before, afterprev); } first = false; } else { // The replacement inserted something and we already inserted `before`. } } var i = before.nextSibling; var oldText = o[0]; while (i && i != next) { if (i.setAttribute) i.setAttribute('data-tk-prev', oldText); oldText = ''; i = i.nextSibling; } // Set the text of the `n` node to the remaining (maybe empty) text `c`: if (!first) { n.nodeValue = n.nodeValue.substring(o.index + o[0].length, n.nodeValue.length); } // Find the next occurrence: o = alias_regexp.exec(n.nodeValue); } } } if (first) { //console.log("Nothing was changed"); } else { //console.log("Something was changed"); } } /////////////////////////////////////////////////////////////////////////////// // Add aliases from input alias specification. /////////////////////////////////////////////////////////////////////////////// function add_aliases(input) { parse_aliases(input, add_parsed_alias); } function node_depth(v) { var d = 0; while (v) { ++d; v = v.parentNode; } return d; } function lowest_common_ancestor(u, v) { var du = node_depth(u), dv = node_depth(v); while (du > dv) { u = u.parentNode; --du; } while (dv > du) { v = v.parentNode; --dv; } while (u != v && du > 0 && dv > 0) { u = u.parentNode; --du; v = v.parentNode; --dv; } return u; } function activate_fbtk() { compute_alias_regexp(); search_for_names(document.body); if (window.theTKTitleObserver) { window.theTKTitleObserver.disconnect(); } window.theTKTitleObserver = new MutationObserver(function (mutations) { if (mutations.length == 0) return; var p = mutations[0].target; //var depths = [node_depth(p)]; for (var i = 1, l = mutations.length; i < l; ++i) { p = lowest_common_ancestor(p, mutations[i].target); //depths.push(node_depth(mutations[i].target)); } //depths.sort(); //console.log("Node depths ("+depths.join(', ')+") combined to depth "+node_depth(p)); if (p) { search_for_names(p); } }); window.theTKTitleObserver.observe(document.body, { 'childList': true, 'characterData': true, 'subtree': true }); } function deactivate_fbtk() { if (window.theTKTitleObserver) { window.theTKTitleObserver.disconnect(); window.theTKTitleObserver = null; } var q = [document.body]; var l = 1; while (l > 0) { var el = q[--l]; if (!el) continue; q[l++] = el.nextSibling; if (el.nodeType != 1) continue; q[l++] = el.firstChild; if (el.hasAttribute('data-tk-prev')) { var txt = document.createTextNode(el.getAttribute('data-tk-prev')); el.parentNode.insertBefore(txt, el); el.parentNode.removeChild(el); } } } function toggle_fbtk() { if (window.theTKTitleObserver) deactivate_fbtk(); else activate_fbtk(); } function toggle_fu_prefix() { window['TKconfig']['FUprefix'] = !TK('FUprefix'); deactivate_fbtk(); activate_fbtk(); } window.TKsetgf = function TKsetgf(year) { window['TKconfig']['gf'] = year; deactivate_fbtk(); activate_fbtk(); } window.TKsetup = function TKsetup(config) { for (var k in config) { if (!(k in window['TKconfig'])) throw('Unknown key '+k); } for (var k in config) { window['TKconfig'][k] = config[k]; } deactivate_fbtk(); activate_fbtk(); } function save_prefs() { if(!window.GM_setValue) { return; } GM_setValue('FUprefix', window['TKconfig']['FUprefix']); GM_setValue('gf', window['TKconfig']['gf']); GM_setValue('enabled', !!window.theTKTitleObserver); } function tk_keypress(e) { if (!e.target || e.target.nodeType != 1) return true; var tgt = e.target; var tag = tgt.tagName.toLowerCase(); if (tag == 'textarea' || tag == 'input' || tgt.isContentEditable) return true; var cc = e.charCode; var gf = TK('gf'); if (cc == 45) // minus window.TKsetgf(gf-1); else if (cc == 43) // plus window.TKsetgf(gf+1); else if (cc == 42) // asterisk toggle_fbtk(); else if (cc == 33) // exclamation mark toggle_fu_prefix(); else return true; save_prefs(); e.stopPropagation(); e.preventDefault(); return false; } window.addEventListener('keypress', tk_keypress, false); var svg_style = 'style="height: 1em; width: 1.5em; margin-right: .3em"'; svg['CERM'] = ( ''+ ''+ ''+ ''+ '' ); svg['FORM'] = ( ''+ ''+ ''+ ''+ ''+ '' ); svg['INKA'] = ( ''+ ''+ ''+ ''+ ''+ '' ); svg['NF'] = ( ''+ ''+ ''+ ''+ ''+ '' ); svg['PR'] = ( ''+ ''+ ''+ ''+ ''+ '' ); svg['SEKR'] = ( ''+ ''+ ''+ ''+ ''+ '' ); svg['VC'] = ( ''+ ''+ ''+ ''+ ''+ '' ); svg['KASS'] = ' '; svg['FU'] = ( ''+ ''+ ''+ '' ); svg['EFUIT'] = ( ''+ ''+ '' ); add_aliases( '1999 FORM Jacob Sherson\n'+ '2002 FORM Nikolaj Thomas Zinner\n'+ '2002 KASS Rasmus Villemoes\n'+ '2003 CERM Sune S. Thomsen\n'+ '2004 VC Christina Koch Perry\n'+ '2005 CERM Ole Søe Sørensen\n'+ '2005 FORM Dan Beltoft\n'+ '2005 KASS Tanja Kragbæk Vilhelmsen\n'+ '2005 VC Rasmus Ragnvald Olofsson\n'+ '2006 CERM Tine Vraast-Thomsen\n'+ '2006 FORM Michael Volf Henneberg\n'+ '2006 KASS Lars Thorhauge\n'+ '2006 NF Aslak Thorndahl Lindballe\n'+ '2006 PR Mia Dyhr Christensen\n'+ '2006 SEKR Lasse Kragbæk Vilhelmsen\n'+ '2006 VC Martin Studsgaard Christensen\n'+ '2007 CERM Johan Sigfred Abildskov\n'+ '2007 FORM Jan Munksgård Baggesen\n'+ '2007 KASS Mads Baggesen\n'+ '2007 NF Eva Lykkegaard Poulsen\n'+ '2007 PR Sidse Damgaard\n'+ '2007 SEKR Ninni Schaldemose\n'+ '2007 VC Kasper Søgaard Deleuran\n'+ '2008 CERM Sofie Kastbjerg\n'+ '2008 FORM Tue Christensen\n'+ '2008 KASS Adam Ehlers Nyholm Thomsen\n'+ '2008 PR Cecilie Vahlstrup\n'+ '2009 CERM Christian Bladt Brandt\n'+ '2009 FORM Jonas Bæklund\n'+ '2009 KASS Rikke Aagaard\n'+ '2009 NF Ditte Både Sandkamm\n'+ '2009 PR Nikolaj Andresen\n'+ '2009 SEKR Anne Clemmensen\n'+ '2009 VC Troels Tinggaard Hahn\n'+ '2010 FORM Mie Elholm Birkbak\n'+ '2010 KASS Torben Muldvang Andersen\n'+ '2010 NF Morten Jensen\n'+ '2010 PR Kristoffer L. Winge\n'+ '2010 PR Kristoffer Winge\n'+ '2010 PR Kristoffer Larsen Winge\n'+ '2010 SEKR Maria Kragelund\n'+ '2010 VC Morten Rasmussen\n'+ '2011 CERM Sabrina Tang Christensen\n'+ '2011 FORM Jakob Schultz-Falk\n'+ '2011 KASS Britt Videbæk Fredsgaard\n'+ '2011 NF Kasper Monrad\n'+ '2011 PR Marie Kirkegaard\n'+ '2011 SEKR Niels Ramskov Bøje\n'+ '2011 VC Maiken Haahr Hansen\n'+ '2012 CERM Mads Fabricius\n'+ '2012 FORM Steffen Videbæk Fredsgaard\n'+ '2012 KASS Eva Gjaldbæk Frandsen\n'+ '2012 NF Johannes Christensen\n'+ '2012 PR Nana Halle\n'+ '2012 SEKR Jakob Rørsted Mosumgaard\n'+ '2012 VC Peter Slemming-Adamsen\n'+ '2013 CERM Diana Christensen\n'+ '2013 FORM Mathias Rav\n'+ '2013 KASS Christina Moeslund Zeuthen\n'+ '2013 NF Christian Fretté\n'+ '2013 PR Mette Lysgaard Schulz\n'+ '2013 SEKR Karina Sunds Nielsen\n'+ '2013 VC Mathias Dannesbo\n'+ '2014 CERM Jonas Kielsholm\n'+ '2014 FORM Martin Sand Halle\n'+ '2014 INKA Henrik Lund Mortensen\n'+ '2014 KASS Mathias Jaquet Mavraganis\n'+ '2014 NF Jacob Schnedler\n'+ '2014 PR Alexandra Fabricius Porsgaard\n'+ '2014 SEKR Camilla Pedersen\n'+ '2014 VC Peter Matzen\n'+ '2015 CERM Andreas Bock Michelsen\n'+ '2015 FORM Christian Bonar Zeuthen\n'+ '2015 INKA Oliver Emil Harritslev Christensen\n'+ '2015 KASS Amalie Stokholm\n'+ '2015 NF Anne Dorte Rafn Spangsberg\n'+ '2015 PR Liv Medum Bundgaard\n'+ '2015 SEKR Janne Højmark Mønster\n'+ '2015 VC Lone Koed Thorhauge\n'+ '2016 CERM William Heyman\n'+ '2016 FORM Frederik Jerløv\n'+ '2016 INKA Halvor Høen Hval\n'+ '2016 KASS Emma Hillgaard\n'+ '2016 NF Martin Aakjær Jørgensen\n'+ '2016 PR Katrine Alice Glasscock\n'+ '2016 SEKR Anne Tarp\n'+ '2016 VC Hans Christian Tankred\n'+ '2017 CERM Nikolaj Færgemand Andersen\n'+ '2017 FORM Sofie Filskov Hermansen\n'+ '2017 INKA Klaus Skovgaard Olesen\n'+ '2017 INKA Klaus Olesen\n'+ '2017 KASS Magnus Graf Skou\n'+ '2017 KASS Magnus Graf\n'+ '2017 NF Julie Thiim Gadeberg\n'+ '2017 NF Julie Gadeberg\n'+ '2017 PR Kirstine Friis Jensen\n'+ '2017 SEKR Per Næsby Høgfeldt\n'+ '2017 SEKR Per Høgfeldt\n'+ '2017 VC Mark Lykke Winther\n'+ '2018 CERM Fredrik Egil Helsengreen\n'+ '2018 FORM Thomas Skovlund Hansen\n'+ '2018 INKA Jens Christian Jørgensen\n'+ '2018 KASS Johanne Tankred\n'+ '2018 NF Søren István Adorján Dyhr\n'+ '2018 PR Ida Meyer Granum\n'+ '2018 SEKR Luna Lynge Malzard\n'+ '2018 VC Sille P. Andresen\n'+ '2019 CERM Jesper Dam Knudgaard\n'+ '2019 FORM Jacob Fjerbæk Olsen\n'+ '2019 INKA Ida Rose Nielsen\n'+ '2019 KASS Tessa Cecilia Broeders\n'+ '2019 KASS Tessa Broeders\n'+ '2019 NF Johannes Jensen\n'+ '2019 PR Morten Hulbæk Fog\n'+ '2019 SEKR Sarah Eckholdt Jensen\n'+ '2019 SEKR Sarah Eckholdt\n'+ '2019 VC Jens Trolle\n'+ '2020 CERM Agnete Bie Westphael\n'+ '2020 FORM Maja Dybboe\n'+ '2020 INKA Nichlas Nordestgaard Vingtoft\n'+ '2020 INKA Nichlas Vingtoft\n'+ '2020 KASS Lærke Niclasen\n'+ '2020 NF Mathias Ravn Tversted\n'+ '2020 PR Mathilde Ørsted Toft\n'+ '2020 SEKR Mikala Mai Halbirk\n'+ '2020 SEKR Mikala Halbirk\n'+ '2020 VC Simon Bølling Nordentoft\n'+ '2021 CERM Ida Fricke Jørgensen\n'+ '2021 FORM Peter Juelsgaard\n'+ '2021 INKA Maria Askholm Nielsen\n'+ '2021 KASS Frederik Würtz Sørensen\n'+ '2021 NF Christian Børsen Smedegaard\n'+ '2021 PR Josefine Bjørndal Robl\n'+ '2021 SEKR Jakob Lauritsen\n'+ '2021 VC Christian Voldby\n'+ '2022 CERM Asger Weeth\n'+ '2022 FORM Casper Rysgaard\n'+ '2022 INKA Benjamin Nørmølle Buttenschøn\n'+ '2022 KASS Søren Kjærsgaard\n'+ '2022 NF Toke Marstrand Pontoppidan Lindhard\n'+ '2022 PR Marie-Louise Lykke Nielsen\n'+ '2022 SEKR Clara Bjergsø\n'+ '2022 VC Sif Floor\n'+ '2005 FUJA Jane Drejer\n'+ '2006 FUZA Sarah Zakarias\n'+ '2007 FUAN Kenneth Sejdenfaden Bøgh\n'+ '2007 FUHO Daniel Dalhoff Hviid\n'+ '2007 FUME Mette Aagaard\n'+ '2008 FUAN Andreas Sand Gregersen\n'+ '2008 FUNÉ René Søndergaard\n'+ '2008 FURU Jesper Unna\n'+ '2009 FUBR Rune Bjerring Haugaard\n'+ '2009 FUBS Sandra Pedersen\n'+ '2009 FUBS Sandra Bleuenn Picard Svejgaard Pedersen\n'+ '2009 FUBS Sandra Bleuenn Picard S. Pedersen\n'+ '2009 FUHN Mette Tranberg Hansen\n'+ '2009 FUØL Carina Kjeldahl Møller\n'+ '2009 FUØR Signe Grønborg\n'+ '2010 FUAN Andreas Nikolai Kyed Bovin\n'+ '2010 FUNI Asbjørn Stensgaard\n'+ '2010 FUPH Pernille Hornemann Jensen\n'+ '2010 FURØ Lærke Rønlev Reinholdt\n'+ '2011 FUFR Anders Friis Jensen\n'+ '2011 FUIØ Mathilde Biørn Madsen\n'+ '2011 FULA Camilla Skree Sørensen\n'+ '2011 FUNU Andreas Bendix Nuppenau\n'+ //'2011 FURI Frederik Jerløv\n'+ '2012 FULI Line Bjerg Sørensen\n'+ '2012 FULS Sara Poulsen\n'+ '2012 FUMO Marianne Ostenfeldt Mortensen\n'+ '2012 FUMY Rasmus Thygesen\n'+ '2013 FUAN Dennis Krongaard Mikkelsen\n'+ '2013 FUBI Benedikte Sofie Dalhoff Werk\n'+ '2013 FUGR Asger Holm Agergaard\n'+ '2013 FUSE Mie Christine Wilhelmsen\n'+ '2013 FUTN Anja T Nielsen\n'+ '2013 FUUS Rasmus Korsgaard Kjeldgaard\n'+ //'2014 FUAT Anne Kristine Tarp\n'+ //'2014 FUAT Anne Tarp\n'+ '2014 FUIS Astrid Christiansen\n'+ '2014 FUIK Frederik Riis Nielsen\n'+ '2014 FUFF Helle Weinkouff Petersen\n'+ '2014 FUAN Isaac Appelqvist Løge\n'+ '2014 FUAN Isaac Appelquist Løge\n'+ '2014 FUON Jonas Joachim Junker Zarling\n'+ '2014 FUON Jonas Zarling\n'+ '2014 FUSØ Søren Kenneth Højgaard Sørensen\n'+ //'2014 FUWI William Heyman Krill\n'+ //'2014 FUWI William Heyman\n'+ //'2015 FUAK Martin Aakjær Jørgensen\n'+ //'2015 FUAN Per Næsby Høgfeldt\n'+ //'2015 FUAN Per Høgfeldt\n'+ //'2015 FUGL Katrine Alice Glasscock\n'+ '2015 FUGO Asger Roed-Åstrøm\n'+ //'2015 FUIL Sille Eline Piilgard Andersen\n'+ //'2015 FUIL Sille P. Andresen\n'+ '2015 FUNN Anna Mie Hansen\n'+ '2015 FUPI Freja Frederikke Pinderup\n'+ //'2015 FUSJ Kirstine Friis Jensen\n'+ '2015 FUTØ Marcus Høgsholt Nilson\n'+ //'2015 FUVE Thomas Skovlund Hansen\n'+ //'2016 FUYE Ida Meyer Granum\n'+ //'2016 FUKS Sarah Eckholdt Jensen\n'+ //'2016 FUKS Sarah Eckholdt\n'+ //'2016 FUJI Julie Thiim Gadeberg\n'+ //'2016 FUJI Julie Gadeberg\n'+ //'2016 FULI Tessa Cecilia Broeders\n'+ //'2016 FULI Tessa Broeders\n'+ '2016 FUKI Rasmus Kimose Hvid Nielsen\n'+ '2016 FUAN Jesper Brink Andersen\n'+ '2016 FUAN Jesper Brink\n'+ '2016 FUBØ Mathias Bøjlesen Bertelsen\n'+ '2016 FUBØ Mathias Bertelsen\n'+ '2016 FUBL Jacob Bech-Larsen\n'+ '2016 FULK Jonas Folke Nielsen\n'+ //'2016 FUIV Nichlas Nordestgaard Vingtoft\n'+ //'2016 FUIV Nichlas Vingtoft\n'+ '2017 FUAN Christian Haag Frederiksen\n'+ //'2017 FUDL Ida Rose Nielsen\n'+ //'2017 FUDO Søren István Adorján Dyhr\n'+ '2017 FUFI Signe Fischer Lambertsen\n'+ '2017 FULA Bjørg Glad\n'+ //'2017 FULZ Luna Lynge Malzard\n'+ '2017 FUMI Martin Mikkelsen\n'+ '2017 FUOÜ Rolf Jürgensen Aaskov\n'+ '2017 FURE Kathrine Thorsøe\n'+ '2017 FUTR Viktor Hjorth Miltersen\n'+ '2017 FUTR Viktor Miltersen\n'+ '2018 FUAN Mathias K. Nielsen\n'+ '2018 FUEA Linnea Skafte\n'+ //'2018 FUES Jens Trolle\n'+ //'2018 FUFO Morten Hulbæk Fog\n'+ '2018 FUIB Sofie Behrmann\n'+ '2018 FUNØ Katrine Høholt Kaspersen\n'+ //'2018 FURA Maria Askholm Nielsen\n'+ '2018 FURO Frederik Kobemis Andersen\n'+ '2018 FUUF Albert Freud Abildgaard\n'+ //'2018 FUYO Maja Dybboe\n'+ '2019 FUAN Nicolaj Kuno Bræmhøj\n'+ '2019 FUDA Nikolaj Dahl Hansen\n'+ //'2019 FUHØ Christian Børsen Smedegaard\n'+ '2019 FULE Jacob Birkeland Steenstrup\n'+ //'2019 FULR Toke Marstrand Pontoppidan Lindhard\n'+ //'2019 FUOM Mathilde Ørsted Toft\n'+ '2019 FUSR Josephine Mai Scharf Andersen\n'+ '2019 FUTE Mette Rydder\n'+ //'2019 FUTÜ Frederik Würtz Sørensen\n'+ //'2019 FUWA Agnete Bie Westphael\n'+ //'2020 FUAN Jakob Lauritsen\n'+ '2020 FUDI Freja Marie Dithmer Gam\n'+ '2020 FUDI Freja Gam\n'+ '2020 FUEI Lea Vibe Pedersen\n'+ '2020 FUML Heidi Dueholm Lunde\n'+ '2020 FUML Heidi Lunde\n'+ '2020 FUMS Kurt Herlev Rasmussen\n'+ //'2020 FUMØ Benjamin Nørmølle Buttenschøn\n'+ '2020 FUNÉ André Slot Kristensen\n'+ '2020 FUNI Andrea Skadhede Kristensen\n'+ '2020 FUNI Andrea Skadhede\n'+ '2021 FUAN Jakob Sandø Lund\n'+ //'2021 FUFR Sif Floor\n'+ '2021 FUGA Caspar Agerskov Madsen\n'+ //'2021 FULU Marie-Louise Lykke Nielsen\n'+ '2021 FURP Jeppe Pedersen\n'+ '2021 FUSA David Kildahl Larsen\n'+ '2021 FUSB Johanne Bojsen Kjær\n'+ '2021 FUTM Emil Tejn Rasmussen\n'+ '2021 FUÄU Katrine Bräuner\n'+ '2021 FUØX Emil Sixhøj Mors\n'+ '2022 FUAN Julius Thomas\n'+ '2022 FUCI Alice Pernille Bach Hjort\n'+ '2022 FUDS Jens Magnus Lunding Kusk\n'+ '2022 FUEG Thomas Vang Jensen\n'+ '2022 FUGO Sigurd Lund Boytang\n'+ '2022 FUIR Ida Sofie Pedersen Damkjær\n'+ '2022 FUJR Rikke Johanning\n'+ '2022 FUND Anne Sofie Gam Husted\n'+ '2022 FUNO Simon Malthe Hansen\n'+ '2022 FUXR Alexander Arp Steenberg Johansen\n'+ //'2020 FURY Christian Voldby\n'+ '2020 FUUD Lotte Munkvad\n'+ '1 EFUIT Lauge Mølgaard Hoyer\n'+ '2 EFUIT Philip Tchernavskij\n'+ //'3 EFUIT Oliver Emil Harritslev Christensen\n'+ '4 EFUIT Jonas Tranberg Sørensen\n'+ //'5 EFUIT Johannes Jensen\n'+ '6 EFUIT Mathias Old Jensen\n'+ //'7 EFUIT Mathias Ravn Tversted\n'+ '8 EFUIT Mikkel Wienberg Madsen\n'+ //'9 EFUIT Ida Fricke Jørgensen\n'+ //'10 EFUIT Sofie Kirk Nielsen\n'+ '11 EFUIT Magnus Bech Wind\n'+ '"ADAM" Adam Etches\n'+ '"Nissen" Anders Hauge Nissen\n'+ '"Metal Bo" Bo Mortensen\n'+ '"CBM" Christian Brandt Møller\n'+ '"J-DAG" Jacob Damgaard Jensen\n'+ '"Jen_s" Jens Kusk Block\n'+ '"Have" Martin Anker Have\n'+ '"Vester" Mikkel Bak Vester\n'+ '"M3" Morten Schaumburg\n'+ '"Cramer" Morten \'Cramer\' Nikolaj Pløger\n'+ '"#" Rikke Hein\n'+ '"Sean" Sean Geggie\n'+ '"Køleren" Karsten Handrup\n'+ '"P∀" Palle Jørgensen\n'+ '"Thyregod" Klaus Eriksen\n'+ '"Graa mand" Per Graa\n'+ '"Łabich" Anders Labich\n'+ '"Onklen" Henrik Bindesbøll Nørregaard\n'+ '"Clausen" Jakob Clausen\n'+ '"Dobbelt Wester" Michael Westergaard\n'+ '"Brøl" Morten Grud Rasmussen\n'+ '"Stive-Anna" Anna Sejersen Riis\n'+ '"Ålen" Frederik Brinck Truelsen\n'+ '"Blomsterpenis" Morten Stockmarr Liljegren\n'+ '"Smør" Kenneth Lund Kjærgaard\n'+ //'"Kalus" Klaus Olesen\n'+ '"Ion" Rune Naujokat Troelsgaard Thorsen\n'+ '"HH" Hans-Henrik Sztuk Teut\n'+ '' ); var enabled = true; if (window.GM_getValue) { window['TKconfig']['FUprefix'] = GM_getValue('FUprefix', window['TKconfig']['FUprefix']); window['TKconfig']['gf'] = GM_getValue('gf', window['TKconfig']['gf']); enabled = GM_getValue('enabled', true); } activate_fbtk(); if (!enabled) { deactivate_fbtk(); }