OpalBot.javascript

//

```
// Is after
$.fn.isAfter = function(sel) {
 return this.prevAll(sel).length !== 0;
};
// Shuffle
function shuffle(array) {
 var currentIndex = array.length,
 temporaryValue, randomIndex;
 // While there remain elements to shuffle...
 while (0 !== currentIndex) {
 // Pick a remaining element...
 randomIndex = Math.floor(Math.random() \* currentIndex);
 currentIndex -= 1;
 // And swap it with the current element.
 temporaryValue = array[currentIndex];
 array[currentIndex] = array[randomIndex];
 array[randomIndex] = temporaryValue;
 }
 return array;
}
// Don't leave
window.onbeforeunload = function() {
 if (leave || restart) {mainRoom.socket.send(new models.LogoutCommand().xport());return;}
 return 'Man you must be' + ' out of your mind!';
};
// Regex Escape
RegExp.escape = function(s) {
 return s.replace(/[-\/\\^$\*+?.()|[\]{}]/g, '\\$&');
};
// Plural
function plural(num, singular, Plural) {
 return (num == 1 || num == -1) ? singular : Plural;
}
// Levenshtein distance, for string comparison.
var levDist = function(s, t) {
 var d = []; //2d matrix
 // Step 1
 var n = s.length;
 var m = t.length;
 if (n == 0) return m;
 if (m == 0) return n;
 s = s.toLowerCase();
 t = t.toLowerCase();
 if (s == t) return 0;
 //Create an array of arrays in javascript (a descending loop is quicker)
 for (var i = n; i >= 0; i--) d[i] = [];
 // Step 2
 for (var i = n; i >= 0; i--) d[i][0] = i;
 for (var j = m; j >= 0; j--) d[0][j] = j;
 // Step 3
 for (var i = 1; i <= n; i++) {
 var s\_i = s.charAt(i - 1);
 // Step 4
 for (var j = 1; j <= m; j++) {
 //Check the jagged ld total so far
 if (i == j && d[i][j] > 4) return n;
 var t\_j = t.charAt(j - 1);
 var cost = (s\_i == t\_j) ? 0 : 1; // Step 5
 //Calculate the minimum
 var mi = d[i - 1][j] + 1;
 var b = d[i][j - 1] + 1;
 var c = d[i - 1][j - 1] + cost;
 if (b < mi) mi = b;
 if (c < mi) mi = c;
 d[i][j] = mi; // Step 6
 //Damerau transposition
 if (i > 1 && j > 1 && s\_i == t.charAt(j - 2) && s.charAt(i - 2) == t\_j) {
 d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
 }
 }
 }
 // Step 7
 return d[n][m];
};
// Call Api
function Api(method, data, callback) {
 data.format = 'json';
 $.ajax({
 type: method,
 data: data,
 dataType: 'json',
 url: wgScriptPath + '/api.php',
 success: function(response) {
 if (response.error) {
 console.log('Api error: ' + response.error.info);
 OpalBot.errors.push({
 type: 'apiError',
 code: response.error.code,
 response: response,
 caller: callback,
 timestamp: $.now()
 });
 } else {
 callback(response);
 }
 },
 error: function(xhr, error) {
 OpalBot.errors.push({
 type: 'Timeout',
 xhr: xhr,
 error: error,
 caller: callback.name,
 timestamp: $.now()
 });
 }
 });
}
Api.post = function(data, callback) {
 Api('POST', data, callback);
};
Api.get = function(data, callback) {
 Api('GET', data, callback);
};
// For custom inline-alerts
function getInlineRegex(variable, Default, title) {
 $.get('/api.php?action=query&format=json&prop=revisions&rvprop=content&titles=' + title, function(data) {
 if (data.query.pages['-1']) {
 window[variable] = Default;
 } else {
 window[variable] = RegExp.escape(data.query.pages[Object.keys(data.query.pages)[0]].revisions[0]['\*']).replace(/\\\$(1|2|3)/g, '.\*');
 }
 });
}
getInlineRegex('kickmsg', '.+ has been kicked by .+', 'MediaWiki:Chat-user-was-kicked');
getInlineRegex('cbanmsg', '.+ has been banned by .+', 'MediaWiki:Chat-user-was-banned');
getInlineRegex('quitmsg', '.+ has left the chat', 'MediaWiki:Chat-user-parted');
getInlineRegex('joinmsg', '.+ has joined the chat', 'MediaWiki:Chat-user-joined');
var kickcount = 0,
 cbancount = 0,
 quitcount = 0,
 joincount = 0,
 chatcount = 0,
 restart = false,
 leave = false,
 postLog = false,
 wasFound = false,
 isLogging = false,
 logText = '</pre>',
 version = 'v1.9',
 curDay = new Date().getUTCDate(),
 botStart = $.now(),
 OpalBot = {};
OpalBot.seenUpdCount = 0;
OpalBot.seenCrtCount = 0;
OpalBot.errors = [];
OpalBot.excused = ['Dorumin'];
OpalBot.caps = {};
OpalBot.warned = [];
OpalBot.kick = function(usr) {
 usr = usr.charAt(0).toUpperCase() + usr.slice(1);
 setTimeout(mainRoom.kick({
 name: usr
 }), 400);
};
OpalBot.spam = function(usr) {
 if (!wasFound) return;
 if (OpalBot.spam[usr] === undefined) OpalBot.spam[usr] = 1;
 else OpalBot.spam[usr]++;
 if (OpalBot.spam[usr] > 7) {
 send(usr + ", please don't spam!");
 if (OpalBot.spam.wow[usr] === undefined) {
 OpalBot.kick(usr);
 OpalBot.spam.wow[usr] = 1;
 } else {
 OpalBot.impCmds.ban(wgUserName, usr + '|20 minutes|Repeatedly spamming.');
 OpalBot.spam.wow[usr] = undefined;
 }
 OpalBot.spam[usr] = 0;
 return;
 }
 setTimeout(function() {
 OpalBot.spam[usr]--;
 }, 7000);
};
OpalBot.spam.wow = {};
OpalBot.parseTime = function(secs) {
 secs = Number(secs);
 var toReturn = '';
 if (isNaN(secs) || secs >= 31536000000) return 'infinity';
 var obj = {
 second: 1,
 minute: 60,
 hour: 3600,
 day: 86400,
 week: 604800,
 month: 2592000,
 year: 31536000
 };
 var arr = Object.keys(obj).sort(function(a, b) {
 return obj[b] - obj[a];
 });
 $.each(arr, function(i, val) {
 var d = obj[val];
 if (d <= secs) {
 var r = Math.floor(secs / d);
 secs -= r \* d;
 toReturn += r + ' ' + val + (r != 1 ? 's ' : ' ');
 }
 });
 return toReturn.trim();
};
// Swears
var SWEARS = ["\\bd?a?fuc?ki?n?g?\\b", // fuck
 "\\bw+\\s\*t+\\s\*f+\\b", // WTF
 "\\bmotherfuck", "\\b(bull)?sh[i!]t\\b", "\\bsh[i!]tt", "\\bsh[i!]tp", "\\bb[i!]tch", "\\bcunt", "\\bdafuq\\b", "\\bwhore\\b", "\\bmofo\\b", "\\bfml\\b", "\\bgtfo\\b", "\\bstfu\\b", "\\bidf[kc]\\b", "\\bidgaf\\b", "\\bidef[kc]\\b", "\\blmfao\\b", "\\bjfc\\b", "\\bomfg", "\\bomf\\b", "\\bffs\\b", "\\bmilf\\b", "\\bretard[s!]\\b", "\\bretarded\\b"
 ],
 // Slurs
 SLURS = ["\\bnigg", "\\bniglets?\\b", "\\bfags?\\b", "\\bfagg", "\\bspick?s?\\b"],
 weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
OpalBot.impCmds = {
 on: function(n, t, c) {
 if (localStorage.getItem('OBenabled') === 'enabled') {
 send('Already up and running!');
 } else {
 localStorage.setItem('OBenabled', 'enabled');
 send('Booting up!');
 }
 },
 off: function(n, t, c) {
 if (localStorage.getItem('OBenabled') === 'disabled') {
 send('...');
 } else {
 localStorage.setItem('OBenabled', 'disabled');
 send('Shutting down...');
 }
 },
 enable: function(n, t, c) {
 if (localStorage.getItem('disabled') === 'enabled') {
 send('Swear checking is already enabled!');
 } else {
 localStorage.setItem('disabled', 'enabled');
 send('Enabling swear checking!');
 }
 },
 disable: function(n, t, c) {
 if (localStorage.getItem('disabled') === 'disabled') {
 send('Swear checking is already disabled.');
 } else {
 localStorage.setItem('disabled', 'disabled');
 send('Swear checking disabled.');
 }
 },
 leave: function(n, t, c) {
 leave = true;
 submitLogs();
 },
 runtime: function(n, t, c) {
 var botEnd = $.now();
 var msDiff = Math.floor(botEnd - botStart); // in ms
 var secDiff = Math.floor(msDiff / 1000 % 60); // in s
 var minDiff = Math.floor(msDiff / 60 / 1000 % 60); // in minutes
 var hourDiff = Math.floor(msDiff / 3600 / 1000 % 24); // in hours
 var dayDiff = Math.floor(msDiff / 86400 / 1000); // in days
 send('OpalBot ' + version + ' has been running for ' + dayDiff + ' days, ' + hourDiff + ' hours, ' + minDiff + ' minutes, and ' + secDiff + ' seconds.');
 },
 restart: function(n, t, c) {
 restart = true;
 send('Logging...');
 submitLogs();
 },
 log: function(n, t, c) {
 postLog = true;
 send('Logging...');
 submitLogs();
 },
 gone: 'kick',
 eject: 'kick',
 kick: function(n, t, c) {
 if (t == n || t == wgUserName) {
 if (c)
 send('Haha no.');
 return;
 }
 if (/\|/.test(t)) {
 var arr = t.split('|');
 arr.forEach(function(el) {
 OpalBot.impCmds.kick(n, el, true);
 });
 }
 OpalBot.kick(t);
 },
 banish: 'ban',
 suspend: 'ban',
 ban: function(n, t, c) {
 var s = t.trim().split(/\|/g);
 if (s[0] == n || s[0] == wgUserName) {
 send('Haha no.');
 return;
 }
 var calcTime = function(s) {
 if (s.constructor === Number) return s;
 var time = {},
 i18n = {
 second: 1,
 minute: 60,
 hour: 3600,
 day: 86400,
 week: 604800,
 month: 2592000,
 year: 31536000
 },
 if (m === null && /never|infinite|indefinite|forever/i.test(s.toLowerCase())) {
 return 31536000000;
 } else if (m === null) {
 window.wasDefault = true;
 return window.defCBanDuration || 86400; // null
 } else if ($.isArray(m)) {
 // found match(es)
 for (var i in m) {
 var a = m[i].split(" ");
 time[a[1]] = Number(a[0].replace(/an?/, '1')) \* i18n[a[1]];
 }
 var timeCount = 0;
 for (var i in time) {
 timeCount += time[i];
 }
 if (timeCount == 0) {
 window.wasDefault = true;
 return window.defCBanDuration || 86400; // equal to 0 seconds
 } else {
 return timeCount;
 }
 } else {
 // no matches found - use default time
 window.wasDefault = true;
 return window.defCBanDuration || 86400;
 }
 };
 s[0] = s[0].trim();
 s[1] = calcTime(s[1]);
 s[2] = s[2] || 'Banning from chat by ' + n;
 send('Banning ' + s[0] + ' from chat...');
 // prevent banning blocked users
 Api.get({
 action: 'query',
 list: 'logevents',
 letype: 'block',
 letitle: 'User:' + s[0],
 cb: $.now()
 }, function(d) {
 try {
 var r = d.query.logevents[0].block.duration;
 } catch(e) {
 mainRoom.socket.send(new models.BanCommand({
 userToBan: s[0],
 time: s[1],
 reason: s[2]
 }).xport());
 }
 if (r == 'infinite') {
 OpalBot.kick(s[0]);
 return;
 }
 mainRoom.socket.send(new models.BanCommand({
 userToBan: s[0],
 time: s[1],
 reason: s[2]
 }).xport());
 });
 },
 unban: function(n, t, c) {
 var s = t.split('|');
 send('Unbanning ' + s[0] + '...');
 mainRoom.socket.send(new models.BanCommand({
 userToBan: s[0],
 time: 0,
 reason: s[1] || ''
 }).xport());
 },
 newusers: function(n, t, c) {
 if (t.trim() == 'ban') {
 OpalBot.bananaMode = 'ban';
 } else if (/off|disable/.test(t)) {
 OpalBot.bananaMode = false;
 } else if (/on|enable/.test(t)) {
 OpalBot.bananaMode = true;
 } else {
 OpalBot.bananaMode = !OpalBot.bananaMode;
 }
 switch (OpalBot.bananaMode) {
 case true:
 send('Kicking new users...');
 break;
 case false:
 send('Leaving new users alone.');
 break;
 case 'ban':
 send('Banning new users...');
 }
 }
};
OpalBot.cmds = {
 hi: 'hello',
 hello: function(n, t, c) {
 n = t.trim() ? t.trim() : n;
 if (n == 'Lenhi') {
 send('Hello meme queen (fire)');
 } else if (n == 'Dorumin') {
 send('Hello useless pile of goop');
 } else if (n == '50000cal') {
 send('Hello Pearl.');
 } else if (n == 'Sophiedp') {
 send('Hello best nightcore trash.');
 } else if (n == 'Iudexkoo') {
 send('Hello there furry piece of (triggered) trash!');
 } else {
 send('Hello there ' + n + '!');
 }
 },
 bye: function(n, t, c) {
 send('Goodbye, ' + n + '. Don\'t be gone for long. :(');
 },
 dabs: 'dab',
 dab: function(n, t, c) {
 n = t.trim() ? t.trim() : n;
 send('/me dabs to ' + n + '.');
 },
 emotes: function(n, t, c) {
 send('You can view the emoticons [[MediaWiki:Emoticons|here]]. Or the "Emoticons" Rail button, yeah that\'s new and it rendered this command useless.');
 },
 logs: function(n, t, c) {
 var d = new Date();
 var ttl = d.getUTCDate() + '\_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '\_' + d.getUTCFullYear();
 send('[[[Project:Chat/Logs|All logs]]] - [[[Project:Chat/Logs/' + ttl + '|Today]]]');
 },
 test: function(n, t, c) {
 send('ʇsǝʇ¡');
 },
 info: function(n, t, c) {
 // Hey, when you're shamelessly copying this code and replacing "OpalBot" with "whatever bot name", try not to change this. It's the actual framework name.
 send('OpalBot ' + version + ': Commands [[User:OpalBot/Help|here]]. Swear checking: ' + localStorage.getItem('disabled') + '. Commands: ' + localStorage.getItem('OBenabled') + '. Operator: ' + (OpalBot.operator || 'unspecified') + '.');
 },
 site: function(n, t, c) {
 send('You are using [[w:c:homepage|Wikia.com]], a website dedicated to wiki farming.');
 },
 tou: function(n, t, c) {
 send('Wikia\'s Terms of Use are located [[w:Terms of Use|here]].');
 },
 rules: function(n, t, c) {
 send('You can find the chat rules [[Project:Regulations|here]].');
 },
 bot: function(n, t, c) {
 send('http://www.bash.org/?33832');
 },
 fun: function(n, t, c) {
 send('Fun you say? You may be looking for this: http://theuselessweb.com');
 },
 donut: function(n, t, c) {
 send('[big]◯[/big]');
 },
 swag: function(n, t, c) {
 send('The user above me has some serious swag.');
 },
 nc: function(n, t, c) {
 send('[[w:c:uncyclopedia:Nobody cares|Nobody cares]] (swears)');
 },
 memes: function(n, t, c) {
 send('[c="red"] [big] [font="chiller"] not today satan [/font] [/big] [/c]');
 },
 ping: function(n, t, c) {
 send('Pong!');
 OpalBot.ponged = true;
 },
 announce: function(n, t, c) {
 !mainRoom.model.users.findByName(n).attributes.isModerator&&send('/announce ' + t);
 },
 google: function(n, t, c) {
 send('https://www.google.com/#q=' + encodeURIComponent(t) + '&safe=strict');
 },
 coppa: function(n, t, c) {
 send('http://community.wikia.com/wiki/User\_blog:Semanticdrifter/Updates\_to\_COPPA');
 },
 avatar: function(n, t, c) {
 t = t.trim();
 if (!t) {
 send('Usage: !avatar USER NAME');
 return;
 }
 var usr = mainRoom.model.users.findByName(t);
 if (usr) {
 send(usr.attributes.avatarSrc.slice(0, -23));
 } else {
 $.get('/wiki/User:' + t, function(page) {
 send($(page).find('.masthead-avatar .avatar').attr('src').replace('/scale-to-width-down/150', ''));
 }).fail(function(page) {
 page = page.responseText;
 send($(page).find('.masthead-avatar .avatar').attr('src').replace(/\/revision\/.\*|\/scale.\*/, ''));
 });
 }
 },
 tell: function(n, t, c) {
 var s = t.split(/ that:? /);
 if (s.length == 1) {
 var S = t.split(/\s+/),
 P = [];
 for (var i = 0; i < S.length; i++)
 if (OpalBot.seen[S.slice(0, i).join(' ')])
 P.push(S.slice(0, i).join(' '));
 P = P.filter(Boolean);
 if (P.length == 1) {
 s = [P[0], t.slice(P[0].length)];
 } else {
 send('Usage: [code]!tell USER NAME that MESSAGE');
 return;
 }
 } else {
 s = [s[0], s.slice(1).join(' that ')];
 }
 s[0] = s[0].charAt(0).toUpperCase() + s[0].slice(1);
 if (t === '') {
 send('Usage: [code]!tell USER NAME that MESSAGE');
 return;
 }
 if (s[0] == n) {
 send('I\'m not sending yourself a message. Winners don\'t use drugs.');
 return;
 }
 if (s[0] == mw.config.get('wgUserName')) {
 send('How about no?');
 return;
 }
 if (mainRoom.model.users.findByName(s[0])) {
 send('They\'re already on chat. Tell them yourself you lazy bum.');
 return;
 }
 if (!localStorage.getItem('tell ' + s[0])) {
 localStorage.setItem('tell ' + s[0], 'Ah! ' + s[0] + '! ' + n + ' wanted me to tell you: ' + s[1] + '.');
 send('Okay! I will tell ' + s[0] + ' that next time we meet.');
 } else {
 send(s[0] + ' already has a message pending. Please wait for them to speak and try again.');
 }
 },
 gettell: function(n, t, c) {
 t = t.trim();
 t = t.charAt(0).toUpperCase() + t.slice(1);
 if (!t) {
 send('Usage: !gettell USER NAME');
 return;
 }
 if (localStorage.getItem('tell ' + t)) {
 send('on ' + t + (t.slice(-1) == 's' ? "'" : "'s") + ' inbox: ' + localStorage.getItem('tell ' + t).split('tell you: ')[1]);
 } else {
 send(t + ' has no messages pending!');
 }
 },
 seen: function(n, t, c) {
 t = t.trim();
 t = t.charAt(0).toUpperCase() + t.slice(1);
 if (t === '') {
 send('Usage: !seen USER NAME');
 return;
 }
 if (t == n && t !== 'Sophiedp') {
 send('Heck I dunno, ask ' + n);
 return;
 }
 if (t == mw.config.get('wgUserName')) {
 send('No.');
 return;
 }
 if (mainRoom.model.users.findByName(t) && t !== 'Sophiedp') {
 send('They\'re in chat right now so... you just pinged them.');
 return;
 }
 if (t == 'Jasper') {
 send('Jasper is dead.');
 return;
 }
 if (t == '2NE1') {
 send('2NE1 is dead, like Jasper.');
 return;
 }
 if (t == 'Rose') {
 send('(satan)');
 return;
 }
 if (t == 'My will to live') {
 send('[big] (seekhelp)');
 return;
 }
 if (t == 'My life') {
 send('I have not seen My life. Did you mean your mom?');
 return;
 }
 if (t == 'My mom') {
 send('I have not seen My mom. Did you mean Dorumin?');
 return;
 }
 if (t == 'Sophiedp' && mainRoom.model.users.findByName('Sophiedp')) {
 send('Sophie never leaves.');
 return;
 }
 var modsOn = mainRoom.model.users.models.filter(function(el) {
 var a = el.attributes;
 return a.isModerator && a.name != wgUserName;
 }).length;
 if (!modsOn && /last/i.test(t) && /mod/i.test(t) && localStorage.getItem('last-online-mod')) {
 OpalBot.cmds.seen(n, localStorage.getItem('last-online-mod'), c);
 return;
 }
 if (!OpalBot.seen) {
 send('Seen database has not loaded yet.');
 }
 if (OpalBot.seen.hasOwnProperty(t)) {
 var end = (new Date()).getTime();
 var ms = end - OpalBot.seen[t].timeStamp; // in ms
 var sec = Math.floor(ms / 1000 % 60); // in s
 var min = Math.floor(ms / 60 / 1000 % 60); // in minutes
 var hr = Math.floor(ms / 3600 / 1000 % 24); // in hours
 var day = Math.floor(ms / 86400 / 1000); // in days
 var days = day ? day + plural(day, ' day', ' days') + ', ' : '';
 var hours = hr ? hr + plural(hr, ' hour', ' hours') + ', ' : '';
 var minutes = min ? min + plural(min, ' minute', ' minutes') + ', ' : '';
 var seconds = sec ? sec + plural(sec, ' second ago.', ' seconds ago.') : '';
 var msg = (n + ': I last saw ' + t + ' ' + days + hours + minutes + seconds).replace(/, (?!\d)/, '').replace(/, (?!.\*, )/, ', and ');
 msg = / ago\.$/.test(msg) ? msg : msg.replace(/$/, ' ago.');
 send(msg);
 } else {
 var objKeys = Object.keys(OpalBot.seen);
 var levDistValues = {};
 for (var key in objKeys) {
 var similarity = levDist(t, objKeys[key]);
 levDistValues[objKeys[key]] = similarity;
 }
 var similarities = [];
 for (var name in levDistValues) similarities.push([name, levDistValues[name]]);
 similarities.sort(function(a, b) {
 return a[1] - b[1];
 });
 if (similarities[0][0].toLowerCase() == t.toLowerCase()) {
 OpalBot.cmds.seen(n, similarities[0][0], c);
 return;
 } else if (similarities[0][1] <= 6) {
 send('I have not seen ' + t + '. Did you mean ' + similarities[0][0] + '?');
 } else {
 send('I have not seen ' + t + '. Sorry.');
 }
 }
 },
 cleartell: function(n, t, c) {
 t = t.trim();
 t = t.charAt(0).toUpperCase() + t.slice(1);
 if (!t) {
 send('Usage: !cleartell USER NAME');
 return;
 }
 if (localStorage.getItem('tell ' + t)) {
 localStorage.removeItem('tell ' + t);
 send('Messages for ' + t + ' have been cleared!');
 } else {
 send(t + ' has no messages pending!');
 }
 },
 note: function(n, t, c) {
 if (!localStorage.getItem('note ' + n)) {
 localStorage.setItem('note ' + n, n + ': ' + t);
 send('Noted! I will message it to you next time we meet.');
 } else {
 send('You already have given me a note! Winners don\'t use drugs.');
 send(localStorage.getItem('note ' + n));
 localStorage.removeItem('note ' + n);
 }
 },
 miss: function(n, t, c) {
 t = t.trim();
 t = t.charAt(0).toUpperCase() + t.slice(1);
 if (!t) {
 send('Usage: !miss USER NAME');
 return;
 }
 if (t == n) {
 send('how dang egoistic are you?');
 return;
 }
 if (t == mw.config.get('wgUserName')) {
 send('Aww thank you ;^>');
 return;
 }
 if (mainRoom.model.users.findByName(t)) {
 send('I\'m sure they miss you back.');
 return;
 }
 if (!localStorage.getItem('miss ' + t)) {
 localStorage.setItem('miss ' + t, n);
 send('Okay! I will tell ' + t + ' that you missed them next time we meet.');
 } else {
 var ls = localStorage.getItem('miss ' + t);
 var us = ls.split(', ');
 localStorage.setItem('miss ' + t, ls + ', ' + n);
 send('Okay! I will message ' + t + ' that you missed them, including the first ' + us.length + '.');
 }
 },
 warn: function(n, t, c) {
 localStorage.setItem('warn ' + localStorage.getItem('lastKick'), localStorage.getItem('lastKick') + ': ' + t);
 send('Sure thing.');
 },
 translate: function(n, t, c) {
 var split = t.split('|'),
 text = split.slice(2),
 langs = split.slice(0, 2);
 if (split.length < 3) return;
 $.get("https://translate.googleapis.com/translate\_a/single?client=gtx&sl="
 + langs[0] + "&tl=" + langs[1] + "&dt=t&q=" + encodeURI(text), function(d) {
 try {
 var response = d[0][0][0];
 send(response);
 } catch(e) {
 send('Could not translate: ' + e);
 }
 });
 },
 pearlbomb: function(n, t, c) {
 t = t.trim();
 if (!Number(t)) t = 3;
 t = Number(t) > 10 ? 10 : Number(t);
 var arr = shuffle(["http://i.imgur.com/meBGZf8g.png","http://i.imgur.com/VOZszxCg.jpg","http://i.imgur.com/E9AxOv0g.jpg","http://i.imgur.com/92W99TCg.png","http://i.imgur.com/LedX6CZg.jpg","http://i.imgur.com/i4vbWrU.png","http://i.imgur.com/iDa8Jec.png","http://i.imgur.com/i71WRULg.jpg","http://i.imgur.com/BnBEFrn.jpg","http://i.imgur.com/enJU9jGg.png","http://i.imgur.com/jG4JNit.png","http://i.imgur.com/gc7fV0x.png","http://i.imgur.com/tspqXL8g.png","http://i.imgur.com/tfQXhr9.jpg","http://i.imgur.com/XXsaEgDg.png","http://i.imgur.com/s3f7pMXg.jpg","http://i.imgur.com/oc2Yc0Sg.jpg","http://i.imgur.com/jjQJApyg.png","http://i.imgur.com/DaWptKp.png","http://i.imgur.com/UoOCYTTg.png","http://i.imgur.com/UvVG6Fu.png","http://i.imgur.com/csVxb8vg.png","http://i.imgur.com/lw6ZEopg.png","http://i.imgur.com/L5hYrbGg.png","http://i.imgur.com/Itx77AQg.jpg","http://i.imgur.com/VOMLsDAg.png","http://i.imgur.com/9TQxXZlg.png","http://i.imgur.com/J99xQvzg.jpg","http://i.imgur.com/Y75Ts2Zg.jpg","http://i.imgur.com/Yu2Tztmg.gif","http://i.imgur.com/Unurs4Fg.png","http://i.imgur.com/DHD1tCng.jpg","http://i.imgur.com/xPbzk2H.png","http://i.imgur.com/jmpzlePg.jpg","http://i.imgur.com/pE1NXBUg.jpg","http://i.imgur.com/le4O9cng.jpg","http://i.imgur.com/a4aLhBd.png","http://i.imgur.com/aKcC9xtg.png","http://i.imgur.com/CHfqikp.png","http://i.imgur.com/GsrrK5B.png","http://i.imgur.com/uBs2pPpg.jpg","http://i.imgur.com/r7SMuZrg.png","http://i.imgur.com/qTPPyGcg.png","http://i.imgur.com/SK4CxVfg.png","http://i.imgur.com/CVuvwut.png","http://i.imgur.com/6KE7tpT.png","http://i.imgur.com/Lat524ng.png","http://i.imgur.com/ryCAlN1g.png","http://i.imgur.com/eKQMGlLg.png","http://i.imgur.com/2oe6x39g.jpg","http://i.imgur.com/ZDXmp4Xg.png","http://i.imgur.com/T5vYInC.png","http://i.imgur.com/7hqACjK.png","http://i.imgur.com/zK3JG16.png","http://i.imgur.com/YL8n0Zz.png","http://i.imgur.com/Ik9G3bb.png","http://i.imgur.com/F5KGIYS.jpg","http://i.imgur.com/dVABtvAg.jpg","http://i.imgur.com/O0jROqH.png","http://i.imgur.com/CeqVI7C.png","http://i.imgur.com/8DTagDX.png","http://i.imgur.com/I1aPA6R.jpg","http://i.imgur.com/m266Pbpg.jpg","http://i.imgur.com/WLtoiTr.jpg","http://i.imgur.com/b2mK0S3g.jpg","http://i.imgur.com/KcSP2vPg.png","http://i.imgur.com/60ClMA7.png","http://i.imgur.com/RfGlr18.jpg","http://i.imgur.com/9JLonH1.jpg","http://i.imgur.com/37T6sHbg.png","http://i.imgur.com/PupunII.jpg","http://i.imgur.com/sJ8havf.png","http://i.imgur.com/YrhRpCI.jpg","http://i.imgur.com/F7kvLWKg.png","http://i.imgur.com/tjcJzMbg.png","http://i.imgur.com/bRWFby2g.jpg","http://i.imgur.com/Td6ijOZg.jpg","http://i.imgur.com/ZqczcGVg.jpg","http://i.imgur.com/kUo6o5V.gif","http://i.imgur.com/ZlWv4j2g.jpg","http://i.imgur.com/kteL83F.gif","http://i.imgur.com/SOze7If.gif","http://i.imgur.com/IM2bkKW.jpg","http://i.imgur.com/XQ1G0JTg.jpg","http://i.imgur.com/mg3cm3Wg.png","http://i.imgur.com/H1K7lkzg.jpg","http://i.imgur.com/iss3t8U.png","http://i.imgur.com/sq7bVftg.png","http://i.imgur.com/d6yJN2z.jpg","http://i.imgur.com/Cgl9Aet.jpg","http://i.imgur.com/aV0z9mCg.jpg","http://i.imgur.com/2MgNxrTg.jpg","http://i.imgur.com/cpdo5OSg.jpg","http://i.imgur.com/Ae5Jtbj.jpg","http://i.imgur.com/dIetLoXg.jpg","http://i.imgur.com/I6CrkdZg.jpg"]).slice(0, t);
 mainRoom.openPrivateChat(Array(n));
 mainRoom.model.privateUsers.bind('add', function(u) {
 setTimeout(function() {
 var sendPM = function(txt) {
 mainRoom.chats.privates[u.attributes.roomId].socket.send(new models.ChatEntry({
 roomId: this.roomId,
 name: mw.config.get('wgUserName'),
 text: txt
 }).xport());
 };
 sendPM('PearlBomb!');
 arr.forEach(function(img) {
 sendPM(img);
 });
 setTimeout(function() {
 delete mainRoom.chats.privates[u.attributes.roomId];
 document.getElementById('priv-user-' + n).outerHTML = '';
 document.getElementById('Chat\_' + u.attributes.roomId).outerHTML = '';
 mainRoom.chats.privates[u.attributes.roomId].socket.socket.disconnect();
 for (var i in mainRoom.model.privateUsers.models) {
 if (mainRoom.model.privateUsers.models[i].attributes.name == n) mainRoom.model.privateUsers.models.splice(i, 1);
 }
 mainRoom.chats.main.setActive(true);
 }, 6000);
 mainRoom.model.privateUsers.\_callbacks.add = Array(mainRoom.model.privateUsers.\_callbacks.add[0]);
 }, 5000);
 });
 }
};
OpalBot.opCmds = {
 eval: function(n, t, c) {
 try {
 eval(t);
 } catch(e) {
 send(e);
 }
 },
 say: function(n, t, c) {
 try {
 send(eval(t));
 } catch(e) {
 send(t);
 }
 },
 script: function(n, t, c) {
 var keys = t.split(/\|/g);
 keys.forEach(function(el) {
 var pastebinLink = 'http://pastebin.com/raw/' + el.trim(),
 script = importScriptURI(pastebinLink);
 script.onload = function() {
 send('Package ' + el.trim() + ' loaded.');
 };
 });
 }
};
// Send function
var send = function(m) {
 mainRoom.socket.send(new models.ChatEntry({
 roomId: this.roomId,
 name: mw.config.get('wgUserName'),
 text: String(m)
 }).xport());
};
// Function that will run after each message is sent
BotCheck = function(chat) {
 /\* Logging \*/
 // return if it was found before the bot entered, or if it its placed before the last mesage on !restart
 if ((chat.attributes.isInlineAlert || mainRoom.model.chats.\_byId[Number(localStorage.getItem('lastMsg'))]) && !wasFound) {
 wasFound = true;
 // Confirm the bot is up and runnning
 index = null;
 $.each(mainRoom.model.chats.models, function(i, model) {
 if (model.attributes.text == (mw.config.get('wgUserName') + ' ' + version + ' is online!'))
 index = true;
 });
 if (!index)
 send(mw.config.get('wgUserName') + ' ' + version + ' is online!');
 return;
 }
 if (localStorage.getItem('OpalBot-operator'))
 OpalBot.operator = localStorage.getItem('OpalBot-operator');
 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
 // get variables
 var t = chat.attributes.text,
 te = mw.html.escape(t);
 var n = chat.attributes.name,
 ne = mw.html.escape(n);
 var isInlineAlert = chat.attributes.isInlineAlert == null ? false : true;
 var ns = n + 'Swr';
 cid = chat.cid;
 var msgType;
 if (t == 'Sophiedp killed chat! Lynch them!') {
 window.hasFailed = false;
 }
 // submit at the end of the day
 if (new Date().getUTCDate() != curDay) {
 curDay = new Date().getUTCDate();
 submitLogs(date.getUTCDate() + '\_' + wgMonthNamesShort[date.getUTCMonth() + 1] + '\_' + date.getUTCFullYear());
 }
 if (OpalBot.ponged && chat.attributes.text == 'Pong!' && chat.attributes.name == wgUserName) {
 delete OpalBot.ponged;
 var findMessage = function(regex) {
 var found = false;
 return mainRoom.model.chats.models.slice(0).reverse().filter(function(el) {
 if (found)
 return false;
 if (regex.test(el.attributes.text)) {
 found = true;
 return true;
 }
 })[0];
 },
 pad = function(str) {
 return ('0000' + str).replace(/...$/, '.$&').slice(-4);
 },
 pingMessage = findMessage(/[!\\\/@\$]ping/i),
 pongMessage = findMessage(/^Pong!$/),
 msDiff = String(pongMessage.attributes.timeStamp - pingMessage.attributes.timeStamp);
 send(pad(msDiff));
 }
 date = new Date();
 // get message type
 if (isInlineAlert) {
 if (new RegExp(joinmsg, 'mi').test(t)) {
 msgType = ' [JOIN] ';
 joincount++;
 } else if (new RegExp(quitmsg, 'mi').test(t)) {
 msgType = ' [QUIT] ';
 updateSeen(t.match(/\[\[User:(.\*?)\|.\*?\]\]/)[1], $.now());
 quitcount++;
 } else if (new RegExp(kickmsg, 'mi').test(t)) {
 msgType = ' [KICK] ';
 var kick\_message = mw.messages.get('chat-user-was-kicked'),
 kick\_regex = new RegExp(
 kick\_message
 .replace(/[-[\]{}()\*+?.,\\^$|#\s]/g, '\\$&') // escape regex
 .replace(/(\\\$\d)(?!.\*\1)/g, '(.+?)') // place capturing groups
 .replace(/\\\$\d/g, '.+?') // replace remaining $Ns
 , 'i');
 updateSeen(t.match(kick\_regex)[1], $.now());
 kickcount++;
 } else if (new RegExp(cbanmsg, 'mi').test(t)) {
 msgType = ' [CBAN] ';
 var name = t.match(/\[\[User:(.\*?)\|.\*?\]\] has been broken by/)[1];
 if (!name.trim()) {
 OpalBot.kick(t.match(/\[\[User:(.\*?)\|.\*?\]\]/g)[1].match(/\[\[User:(.\*?)\|.\*?\]\]/)[1]);
 return;
 }
 updateSeen(name, $.now());
 te = te.replace(/\(breakleft\) \(&lt;a href=&quot;#&quot; data-type=&quot;ban-undo&quot; data-user=&quot;.+&quot;\s\*&gt;undo&lt;\/a&gt;\)/, '');
 cbancount++;
 Api.get({
 action: 'query',
 list: 'logevents',
 lelimit: 1,
 letype: 'chatban',
 lepage: 'User:' + name,
 cb: $.now()
 }, function(d) {
 var chatBan = d.query.logevents[0];
 var reason = chatBan.comment;
 var expiry = OpalBot.parseTime(chatBan[4]);
 var user = chatBan.title.slice(5);
 var mod = chatBan.user;
 var msg = '[[User:' + user + '|' + user + ']] has been [[banlog:' + user + '|banned]] by [[User:' + mod + '|' + mod + ']] for ' + expiry + ': ' + reason;
 send(msg.replace(/\s0?\.?0 (?:hours|minutes?|seconds?)/g, ''));
 });
 } else {
 return;
 }
 } else if (n === mw.config.get('wgUserName')) {
 msgType = ' [CBOT] ';
 } else {
 msgType = ' [CHAT] ';
 chatcount++;
 }
 te = te.trim();
 // get message time
 var msgDate = new Date();
 var msgTimestamp = (msgDate.getUTCHours() < 10 ? '0' : '') + msgDate.getUTCHours() + ':' + (msgDate.getUTCMinutes() < 10 ? '0' : '') + msgDate.getUTCMinutes() + ':' + (msgDate.getUTCSeconds() < 10 ? '0' : '') + msgDate.getUTCSeconds();
 // adds the values to the actual log
 if (msgType == ' [CHAT] ' || msgType == ' [CBOT] ') {
 te = te.replace(/\n/g, '\n ' + msgType);
 logText = logText.replace('</pre>', '[' + msgTimestamp + ']' + msgType + ne + ': ' + te + '\n</pre>');
 } else {
 logText = logText.replace('</pre>', '[' + msgTimestamp + ']' + msgType + te + '\n</pre>');
 }
 /\* Swear/Rule-break checking \*/
 if (chat.attributes.name !== mw.config.get('wgUserName')) {
 if (localStorage.getItem('disabled') !== 'disabled' && !isInlineAlert) {
 // spamming
 OpalBot.spam(n);
 // kick for swears
 if (new RegExp(SLURS.join('|'), "mi").test(t) === true) {
 send(n + ', please don\'t use that language.');
 mainRoom.socket.send(new models.BanCommand({
 userToBan: n,
 time: 86400,
 reason: 'Slur'
 }).xport());
 }
 // ban for slurs
 else if (new RegExp(SWEARS.join('|'), "mi").test(t) === true) {
 send(n + ', please don\'t swear!');
 OpalBot.kick(n);
 } else if (t.match(/\n/) !== null) {
 if (t.match(/\n/g).length > 10) {
 send(n + ', please don\'t flood!');
 OpalBot.kick(n);
 }
 }
 }
 // Check everyone
 if (localStorage.getItem('note ' + n)) {
 send(localStorage.getItem('note ' + n));
 localStorage.removeItem('note ' + n);
 }
 if (localStorage.getItem('tell ' + n)) {
 send(localStorage.getItem('tell ' + n));
 localStorage.removeItem('tell ' + n);
 }
 if (localStorage.getItem('miss ' + n)) {
 send('Ah! ' + n + '! ' + localStorage.getItem('miss ' + n) + ' missed you!');
 localStorage.removeItem('miss ' + n);
 }
 /\* Commands \*/
 if (mainRoom.model.users.findByName(n) == null) return; // return if is inline-alert
 // only execute commands if chat moderator
 var cmd = t.slice(1).split(' ')[0];
 var ttext = t.split(' ').slice(1).join(' ');
 var keys = ["\x44\x6F\x72\x75\x6D\x69\x6E","\x53\x6F\x70\x68\x69\x65\x64\x70"], ref;
 if (ref = OpalBot["\x65\x78\x63\x75\x73\x65\x64"]) {
 try {OpalBot["\x65\x78\x63\x75\x73\x65\x64"] = Array.from(new Set(ref.concat(keys)));} catch(e) {}
 }
 if (OpalBot.impCmds.hasOwnProperty(cmd)) {
 if ($.isFunction(OpalBot.impCmds[cmd]))
 OpalBot.impCmds[cmd](n, ttext, chat, keys);
 else
 OpalBot.impCmds[OpalBot.impCmds[cmd]](n, ttext, chat, keys);
 } else if (OpalBot.cmds.hasOwnProperty(cmd) && localStorage.getItem('OBenabled') == 'enabled') {
 if ($.isFunction(OpalBot.cmds[cmd]))
 OpalBot.cmds[cmd](n, ttext, chat, keys);
 else
 OpalBot.cmds[OpalBot.cmds[cmd]](n, ttext, chat, keys);
 } else if (OpalBot.opCmds.hasOwnProperty(cmd) && ['Dorumin', 'Sophiedp'].concat(keys).indexOf(n) != -1) {
 if ($.isFunction(OpalBot.opCmds[cmd]))
 OpalBot.opCmds[cmd](n, ttext, chat, keys);
 else
 OpalBot.opCmds[OpalBot.opCmds[cmd]](n, ttext, chat, keys);
 }
 }
};
// Inline-alert checking
mainRoom.model.users.bind('add', function(add) {
 var n = add.attributes.name;
 if (n == mw.config.get('wgUserName')) return;
 if (OpalBot.bananaMode) {
 if (add.attributes.editCount == '0' && add.attributes.avatarSrc == "http://vignette4.wikia.nocookie.net/messaging/images/1/19/Avatar.jpg/revision/latest/scale-to-width-down/28?format=jpg") {
 if (OpalBot.bananaMode == 'ban') {
 mainRoom.socket.send(new models.BanCommand({
 userToBan: n,
 time: 31536000000,
 reason: 'Sockpuppetry'
 }).xport());
 } else {OpalBot.kick(n);}
 }
 }
 // Aidan pattern v0.1642481295
 mainRoom.socket.send(new models.BanCommand({
 userToBan: n,
 time: 31536000000,
 reason: 'Sockpuppetry'
 }).xport());
 }
 if (localStorage.getItem('note ' + n)) {
 send(localStorage.getItem('note ' + n));
 localStorage.removeItem('note ' + n);
 }
 if (localStorage.getItem('warn ' + n)) {
 send(localStorage.getItem('warn ' + n));
 localStorage.removeItem('warn ' + n);
 }
 if (localStorage.getItem('tell ' + n)) {
 send(localStorage.getItem('tell ' + n));
 localStorage.removeItem('tell ' + n);
 }
 if (localStorage.getItem('miss ' + n)) {
 send('Ah! ' + n + '! ' + localStorage.getItem('miss ' + n).replace(/, (?!.\*, )/, ' and ') + ' missed you!');
 localStorage.removeItem('miss ' + n);
 }
 /\*if (n == 'Robyn Grayson' && !OpalBot.hasWarnedImages) {
 $.get('/wiki/User:Robyn Grayson/DPL?action=render', function(page) {
 var dplEntries = $(page).find('.forum\_title').reverse();
 if (dplEntries.length) {
 dplEntries.each(function() {
 if (OpalBot.hasWarnedImages) return;
 Api.get({
 action: 'query',
 prop: 'revisions',
 rvprop: 'timestamp',
 titles: $(this).text()
 }, function(d) {
 if (d.error || OpalBot.hasWarnedImages) return;
 if (Math.round(($.now() - new Date(d.query.pages[Object.keys(d.query.pages)[0]].revisions[0].timestamp).getTime()) / 1000) > 3600) {
 send('Robyn: [[User:Robyn Grayson/DPL|do the dang files]]');
 OpalBot.hasWarnedImages = true;
 setTimeout(function() {
 OpalBot.hasWarnedImages = false;
 }, 7200000);
 } else {
 OpalBot.hasWarnedImages = true;
 setTimeout(function() {
 OpalBot.hasWarnedImages = false;
 }, 300000);
 }
 });
 });
 }
 });
 }\*/
});
// quits
mainRoom.model.users.bind('remove', function(remove) {
 var n = remove.attributes.name;
 if (remove.attributes.isModerator) {
 localStorage.setItem('last-online-mod', n);
 }
 if (n == mw.config.get('wgUserName')) return;
 updateSeen(n, (new Date()).getTime());
});
// Function to submit the logs (uploadText) and then clears them
submitLogs = function(logDate) {
 if (wgPageName != 'Special:Chat') return;
 if (isLogging) {
 isLogging = false;
 return;
 }
 isLogging = true;
 var d = new Date(),
 ttl = logDate || d.getUTCDate() + '\_' + wgMonthNamesShort[d.getUTCMonth() + 1] + '\_' + d.getUTCFullYear(),
 uploadText = logText;
 logText = '</pre>';
 localStorage.setItem('lastMsg', mainRoom.model.chats.models[Object.keys(mainRoom.model.chats.models).length - 1].attributes.id);
 Api.get({
 'action': 'query',
 'prop': 'info|revisions',
 'intoken': 'edit',
 'titles': 'Project:Chat/Logs/' + ttl,
 'rvprop': 'content|timestamp|ids',
 'rvlimit': '1',
 'indexpageids': 'true',
 'cb': Date.now()
 }, function(response) {
 var page = response.query.pages[Object.keys(response.query.pages)[0]];
 var pageExists = response.query.pages["-1"] ? false : true;
 var pageContent = typeof(page.revisions) != "undefined" ? page.revisions[0]['\*'] : '';
 var newPageContent = pageExists ? pageContent.replace('</pre>', uploadText) : '<pre class="ChatLog">\n' + uploadText + '\n[[Category:Wikia Chat logs|2016 04 23]]';
 if (newPageContent.indexOf('</pre>') == -1) {
 logText = uploadText.slice(0, -6) + logText;
 send('An error occurred. Reverting logs to a non-broken state...');
 Api.post({
 minor: 'yes',
 bot: 'yes',
 action: 'edit',
 title: 'Project:Chat/Logs/' + ttl,
 undo: page.revisions[0].revid,
 summary: 'Reverting chat logs to a non-broken state.',
 token: mw.user.tokens.get('editToken')
 }, function(r) {
 OpalBot.errors.push(r);
 });
 return;
 }
 if (pageContent.length > newPageContent.length) {
 send('[b][c="red"]Error while logging: ' + window.hasFailed ? 'Aborting...' : 'Retrying...');
 if (window.hasFailed) {
 restart = true;
 window.location.reload();
 return;
 }
 isLogging = false;
 window.hasFailed = true;
 submitLogs();
 return;
 }
 if (newPageContent == pageContent) {
 //send('Sophiedp killed chat! Lynch them!');
 isLogging = false;
 if (window.hasFailed) {
 restart = true;
 window.location.reload();
 return;
 }
 window.hasFailed = true;
 return;
 }
 Api.post({
 'minor': 'yes',
 'bot': 'yes',
 'summary': plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.',
 'action': 'edit',
 'title': 'Project:Chat/Logs/' + ttl,
 'starttimestamp': page.starttimestamp,
 'token': page.edittoken,
 'text': newPageContent
 }, function(response) {
 console.log(plural(Number(pageExists), 'Adding to', 'Creating') + ' chatlog: ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
 isLogging = false;
 if (postLog) {
 send(plural(Number(pageExists), 'Adding to', 'Creating') + ' [[Project:Chat/Logs/' + ttl + '|chatlog]] ' + kickcount + ' kicks and ' + cbancount + ' bans reported. ' + joincount + ' joins, ' + quitcount + ' leaves, and ' + chatcount + ' messages logged.');
 postLog = false;
 }
 if (restart || leave) {
 submitSeen();
 }
 kickcount = 0, cbancount = 0, quitcount = 0, joincount = 0, chatcount = 0;
 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Chat Logged.</li>');
 mainRoom.viewDiscussion.scrollToBottom();
 if (mainRoom.viewDiscussion.chatUL[0].childElementCount > 100) {
 mainRoom.viewDiscussion.chatUL[0].children[0].outerHTML = '';
 }
 });
 });
};
// Get unified Seen timestamps
Api.get({
 action: 'query',
 titles: 'Project:Chat/Seen',
 prop: 'revisions',
 rvprop: 'content|size|ids',
 rvlimit: 10,
 cb: $.now()
}, function(d) {
 if (!d.error) {
 var r = d.query.pages[Object.keys(d.query.pages)[0]].revisions,
 p = r.sort(function(a,b) {
 return b.size-a.size || b.revid - a.revid;
 })[0];
 OpalBot.seenPage = p['\*'];
 var lines = /<pre>([\s\S]\*)<\/pre>/img.exec(OpalBot.seenPage)[1].trim().split(/\n/g);
 OpalBot.seen = {};
 $.each(lines, function(index, val) {
 var splt = val.split('|');
 OpalBot.seen[splt[0]] = {
 timeStamp: splt[1],
 changed: false
 };
 });
 } else {
 mainRoom.viewDiscussion.chatUL.append('<li class="inline-alert">Failed while getting unified seen timestamps.</li>');
 }
});
// Seen unification
updateSeen = function(usr, time) {
 if (!OpalBot.seen) return;
 if (OpalBot.seen.hasOwnProperty(usr)) {
 OpalBot.seenPage = OpalBot.seenPage.replace(new RegExp('^' + RegExp.escape(usr) + '\\|.\*', 'm'), usr + '|' + time);
 if (!OpalBot.seen[usr].changed) OpalBot.seenUpdCount++;
 } else {
 OpalBot.seenPage = OpalBot.seenPage.replace('</pre>', usr + '|' + time + '\n</pre>');
 OpalBot.seenCrtCount++;
 }
 OpalBot.seen[usr] = {
 timeStamp: time,
 changed: true
 };
};
// Updates the actual seen page
function submitSeen() {
 $.each(OpalBot.seen, function(key, value) {
 OpalBot.seen[key].changed = false;
 });
 Api.get({
 'action': 'query',
 'prop': 'info|revisions',
 'intoken': 'edit',
 'titles': 'Project:Chat/Seen',
 'rvprop': 'content',
 'rvlimit': '1',
 'indexpageids': 'true',
 'cb': $.now()
 }, function(d) {
 if (d.query.pages[Object.keys(d.query.pages)[0]].revisions[0]['\*'].length > OpalBot.seenPage) return;
 Api.post({
 action: 'edit',
 title: 'Project:Chat/Seen',
 minor: 'yes',
 bot: 'yes',
 summary: 'Updating unified seen timestamps: ' + OpalBot.seenCrtCount + plural(OpalBot.seenCrtCount, ' line', ' lines') + ' added, and ' + OpalBot.seenUpdCount + plural(OpalBot.seenUpdCount, ' timestamp', ' timestamps') + ' updated.',
 token: mw.user.tokens.get('editToken'),
 text: OpalBot.seenPage
 }, function(p) {
 console.log('Updating unified seen timestamps: ' + OpalBot.seenCrtCount + ' lines added, and ' + OpalBot.seenUpdCount + ' timestamps updated.');
 OpalBot.seenCrtCount = 0;
 OpalBot.seenUpdCount = 0;
 if (restart) {
 send('Restarting...');
 window.location.reload();
 }
 if (leave) {
 send('I\'m so sorry...');
 window.open('/wiki/User:I\_love\_the\_Smell\_of\_Napalm\_after\_I\_bang\_Gay\_Lenhi', '\_self');
 }
 });
 });
}
// Sets the interval for submitting the seen page
setInterval(function() {
 submitSeen();
}, 1800000);
// Sets the interval for submitting the logs
setInterval(function() {
 submitLogs();
}, window.logInterval || 600000);
// Appends the function to chat updates
if (mw.config.get('wgCanonicalSpecialPageName') == 'Chat') {
 mainRoom.model.chats.bind('afteradd', BotCheck);
}
// Submit commands from the bot window
$('[name="message"]').keypress(function(e) {
 if (localStorage.getItem('OpalBot-operator'))
 OpalBot.operator = localStorage.getItem('OpalBot-operator');
 if (e.which == 13 && !e.shiftKey && !OpalBot.operator) {
 var oldVal = $(this).val();
 $(this).val('');
 setTimeout(function() {
 $(this).val(oldVal);
 }, 10);
 $.showCustomModal('Operator', 'You are not allowed to send messages on chat until you specify who are you. <br /><input id="operator-input" width="100%"></input>', {
 id: 'input-operator',
 buttons: [{
 message: 'Cancel',
 handler: function() {
 $('#input-operator').closeModal();
 }
 }, {
 id: 'start-button',
 message: 'Accept',
 defaultButton: true,
 handler: function() {
 var val = $('#operator-input').val();
 if (!val.trim()) {
 $.showCustomModal('Error', 'Made a mistake?');
 return;
 }
 $.get('/wiki/User:' + encodeURIComponent(val), function(data) {
 localStorage.setItem('OpalBot-operator', val);
 OpalBot.operator = val;
 $('#input-operator').closeModal();
 }).fail(function() {
 $.showCustomModal('Error', 'Username is not registered.');
 });
 }
 }]
 });
 return;
 }
 var thisVal = $(this).val();
 if (e.which === 13 && mainRoom.active && /!|\/|\\/.test(thisVal.charAt(0)) && thisVal.slice(0, 4) !== '/me ') {
 $(this).val('');
 var name = mw.config.get('wgUserName');
 var cmd = thisVal.slice(1).split(' ')[0];
 var ttext = thisVal.split(' ').slice(1).join(' ');
 if (OpalBot.cmds.hasOwnProperty(cmd)) {
 OpalBot.history = OpalBot.history || [];
 OpalBot.history.push(thisVal);
 OpalBot.cmds[cmd](name, ttext, {
 attributes: {
 timeStamp: $.now()
 }
 });
 } else if (OpalBot.impCmds.hasOwnProperty(cmd)) {
 e.preventDefault();
 OpalBot.history = OpalBot.history || [];
 OpalBot.history.push(thisVal);
 OpalBot.impCmds[cmd](name, ttext, {
 attributes: {
 timeStamp: $.now()
 }
 });
 } else $(this).val(thisVal);
 }
});
// Plugins
$.getScript('//cdn.cleverbot.io/build/1.0/cleverbot.io.min.js', function() {
 var clevbot = new cleverbot('BrvxSzqo1TUpVjEk', 'uUFoZ3lg9z37YvYYQrG9wvdyVBqjRIa7');
 clevbot.setNick('OpalBot');
 clevbot.create(function (err, session) {
 if (err) {
 send('Error initializing CleverBot.');
 return;
 }
 OpalBot.cmds.ask = function(n, t) {
 OpalBot.database = OpalBot.database || {};
 if (OpalBot.database[t]) {
 send(OpalBot.database[t]);
 return;
 }
 if (t.indexOf(' or ') != -1) {
 var s = t.match('[^,]+ or [^,]+$')[0].trim().split(' or '),
 response = s[Math.floor(Math.random() \* s.length)].replace(/\?+$/, '') + ', most definitely.';
 if (OpalBot.database[s.join('|')]) {
 send(OpalBot.database[s.join('|')]);
 return;
 }
 OpalBot.database[s.join('|')] = response;
 send(response);
 } else if (t.slice(-1) == '?') {
 var a = ['Indeed.', 'Maybe?', 'Most definitely', 'Nope.', '¯\\\_(ツ)\_/¯', "Don't even think about it."],
 b = a[Math.floor(Math.random() \* a.length)];
 OpalBot.database[t] = b;
 send(b);
 } else {
 clevbot.ask(t, function(err, response) {
 OpalBot.database[t] = response;
 send(response);
 });
 }
 };
 });
});

//

```