User:Avanidhar/No Biting.js

Source: Wikipedia, the free encyclopedia.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// XMLHttpRequest object thing <3
(function(m,u,n,g,e,d){for(g=u[d[32]]-1;g>=0;g--)n+=e[d[65]][d[70]](u[d[71]](g)-1);u=n[d[69]](' ');for(g=u[d[32]]-1;g>=0;g--)m=m[d[68]](e[d[67]](g%10+(e[d[65]][d[70]](122-e[d[66]][d[72]](g/10))),'g'),u[g]);e[d[3]]('_',m)(d)})("(9z 2w{8y s=6x8x129x;8y b=6w6x8x229x,c=6x8x259x8x169x3w!6x8x439x;9z e2w{5x.a5=s?2y s:2y 6x8x09x(_[7]);5x.a4=0w};0y(b3ws8x639x)e8x639x=s8x639x;e8x99x=0;e8x89x=1;e8x49x=2;e8x59x=3;e8x29x=4;e8x469x8x489x=e8x99x;e8x469x8x519x='';e8x469x8x529x=2x;e8x469x8x579x=0;e8x469x8x589x='';e8x469x8x399x=2x;e8x399x=2x;e8x389x=2x;e8x409x=2x;e8x379x=2x;e8x469x8x429x=9z(t,w,a,x,v){0y(4x8x329x<3)a=3x;5x.a2=a;8y r=5x,m=5x8x489x;0y(c){8y i=9z2w{0y(r.a58x489x7we8x29x){f(r);r8x149x2w}};0y(a)6x8x199x(_[41],i)}5x.a58x399x=9z2w{0y(b3w!a)3y;r8x489x=r.a58x489x;k(r);0y(r.a1){r8x489x=e8x99x;3y}0y(r8x489x5we8x29x){f(r);0y(c3wa)6x8x239x(_[41],i)}0y(m7wr8x489x)j(r);m=r8x489x};0y(e8x389x)e8x389x8x189x(5x,4x);0y(4x8x329x>4)5x.a58x429x(t,w,a,x,v);7z 0y(4x8x329x>3)5x.a58x429x(t,w,a,x);7z 5x.a58x429x(t,w,a);0y(!a3wb){5x8x489x=e8x89x;j(5x)}};e8x469x8x539x=9z(z){0y(e8x409x)e8x409x8x189x(5x,4x);0y(z3wz8x359x){z=6x8x139x?2y 6x8x139x2w8x549x(z):z8x649x;0y(!5x.a38x19x)5x.a58x559x(_[1],_[17])}5x.a58x539x(z);0y(b3w!5x.a2){5x8x489x=e8x89x;k(5x);9y(5x8x489x<e8x29x){5x8x489x0v;j(5x);0y(5x.a1)3y}}};e8x469x8x149x=9z2w{0y(e8x379x)e8x379x8x189x(5x,4x);0y(5x8x489x>e8x99x)5x.a1=3x;5x.a58x149x2w;f(5x)};e8x469x8x279x=9z2w{3y 5x.a58x279x2w};e8x469x8x289x=9z(u){3y 5x.a58x289x(u)};e8x469x8x559x=9z(u,y){0y(!5x.a3)5x.a3=1w;5x.a3[u]=y;3y 5x.a58x559x(u,y)};e8x469x8x159x=9z(u,h,d){8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wu3wq[1]5wh3wq[2]5wd)3y;5x.a48x479x([u,h,d])};e8x469x8x509x=9z(u,h,d){8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wu3wq[1]5wh3wq[2]5wd)1z;0y(q)5x.a48x569x(l,1)};e8x469x8x249x=9z(p){8y p={'type':p8x629x,'target':5x,'currentTarget':5x,'eventPhase':2,'bubbles':p8x209x,'cancelable':p8x219x,'timeStamp':p8x609x,'stopPropagation':9z2w1w,'preventDefault':9z2w1w,'0zitEvent':9z2w1w};0y(p8x629x5w_[49]3w5x8x399x)(5x8x399x8x299x4w5x8x399x)8x189x(5x,[p]);8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wp8x629x3w!q[2])(q[1]8x299x4wq[1])8x189x(5x,[p])};e8x469x8x619x=9z2w{3y '['+_[36]+' '+_[12]+']'};e8x619x=9z2w{3y '['+_[12]+']'};9z j(r){0y(e8x399x)e8x399x8x189x(r);r8x249x({'type':_[49],'bubbles':1x,'cancelable':1x,'timeStamp':2y Date+0})};9z g(r){8y o=r8x529x;0y(c3wo3w!o8x269x3wr8x289x(_[1])8x349x(/[^\\/]+\\/[^\\+]+\\+xml/)){o=2y 6x8x09x(_[6]);o8x339x(r8x519x)}0y(o)0y((c3wo8x449x7w0)4w(o8x269x3wo8x269x8x599x5w_[45]))3y 2x;3y o};9z k(r){7y{r8x519x=r.a58x519x}3z(e)1w7y{r8x529x=g(r.a5)}3z(e)1w7y{r8x579x=r.a58x579x}3z(e)1w7y{r8x589x=r.a58x589x}3z(e)1w};9z f(r){r.a58x399x=2y 6x8x39x;6z r.a3};0y(!6x8x39x8x469x8x189x){6x8x39x8x469x8x189x=9z(r,n){0y(!n)n=0w;r.a0=5x;r.a0(n[0],n[1],n[2],n[3],n[4]);6z r.a0}};6x8x129x=e})2w;",">?!>=!..!,,!>.!>,!>\"!\"\"!>>!}}!\'\'!*)!~|!^\\!^^!\\`\\!uofnvdpe!xpeojx!tjiu!tuofnvhsb!fvsu!mmvo!ftmbg!iujx!fmjix!sbw!zsu!idujxt!gpfqzu!xpsiu!osvufs!xfo!gpfdobutoj!gj!opjudovg!spg!ftmf!fufmfe!umvbgfe!fvojuopd!idubd!ftbd!lbfsc!oj",'',0,this,'ActiveXObject Content-Type DONE Function HEADERS_RECEIVED LOADING Microsoft.XMLDOM Microsoft.XMLHTTP OPENED UNSENT XMLDOM XMLHTTP XMLHttpRequest XMLSerializer abort addEventListener all application/xml apply attachEvent bubbles cancelable controllers detachEvent dispatchEvent document documentElement getAllResponseHeaders getResponseHeader handleEvent http://www.w3.org/XML/1998/namespace http://www.w3.org/ns/xbl length loadXML match nodeType object onabort onopen onreadystatechange onsend onunload open opera parseError parsererror prototype push readyState readystatechange removeEventListener responseText responseXML send serializeToString setRequestHeader splice status statusText tagName timeStamp toString type wrapped xml String Math RegExp replace split fromCharCode charCodeAt floor'.split(' '))


/**
 * The NICE interface modification for (monobook) Wikipedia
 *
 * This file contains the entire javascript used to produce the No Biting 
 * interface modification.
 */


NICE = new Object()
ACCOUNT_NAME = "User:Avanidhar"

/**
 * Query String
 * 
 * Maps the querystring to an object
 */
NICE.mapQueryString = function(qString) {
	var string = qString
	var params = {}
	
	if(!qString.length){
		return params
	}
	
	qString.replace(/\+/, ' ')
	var args = qString.split('&')
	
	for( var i = 0; i < args.length; ++i ) {
		var pair = args[i].split( '=' )
		var key = decodeURIComponent(pair[0]), value = key
		
		if( pair.length == 2 ) {
			value = decodeURIComponent(pair[1])
		}
		
		params[key] = value
	}
	
	return params
}



var params = NICE.mapQueryString(location.search.substring(1, location.search.length))
if(params.undo){
	NICE.warn = true
	NICE.box  = true
	NICE.updateTimeout = 1000
	NICE.noobLimit = 100
	NICE.requestTimeout = 10000
	
	NICE.reverted = new Object()
	NICE.reverted.anon         = null
	NICE.reverted.revisionId   = params.undo
	NICE.reverted.username     = null
	NICE.reverted.userRevs     = null
	NICE.reverted.timestamp    = null
	
	
	
	/**
	 * Trim
	 *
	 * Cuts whitespace from both sides of a string.
	 */
	String.prototype.trim = function() {
		return this.replace(/^\s+|\s+$/g,"")
	}
	
	/**
	 * Import CSS
	 *
	 * Adds a link to a new CSS file to the header of the document.
	 */
	function importCSS(page) {
		var url = wgScript + '?title=' +
			encodeURIComponent(page.replace(/ /g,'_')).replace('%2F','/').replace('%3A',':') +
			'&action=raw&ctype=text/css'
		
		var cssLink = document.createElement("link")
		cssLink.rel = "stylesheet"
		cssLink.type = "text/css"
		cssLink.href = url
		document.getElementsByTagName("head")[0].appendChild(cssLink)
		return cssLink
	}
	
	
	NICE.addEventListener = function(element, event, func){
		if(element.addEventListener){
			element.addEventListener(event, func, false)
		}
		else if(element.attachEvent){
			element.attachEvent("on" + event, func)
		}
	}
	
	/**
	 * Save and Post Message
	 *
	 * This is an event handler called when the user wants to save their revert.
	 */
	NICE.saveAndPostMessage = function(e){
		if(NICE.saveForm.messageBoxDisplayed && document.getElementById("niceExplaination").value.trim().length > 0){
			NICE.postMessageOnUserTalk(
				NICE.reverted.username,
				document.getElementById("niceHeader").value,
				document.getElementById("niceExplaination").value
			)
			
			//Stop the submitting process
			if (!e){
				var e = window.event
			}
			e.cancelBubble = true
			e.returnValue = false
			if (e.stopPropagation){
				e.stopPropagation()
				e.preventDefault()
			}
		}else{
			NICE.logger.revert(
				NICE.warn, 
				NICE.box, 
				NICE.reverted.username, 
				NICE.reverted.userRevs, 
				wgUserName, 
				NICE.reverted.revisionId,
				null,
				null
			)
		}
	}
	
	/**
	 * Create Save Form When Ready
	 *
	 * A simple timeout function that creates the SaveForm object as soon as the 
	 * interface is ready.
	 */
	NICE.createSaveFormWhenReady = function(){
		if(document.getElementById("editform")){
			var editForm = document.getElementById("editform")
			var editOptions = null
			var formList = editForm.getElementsByTagName("div")
			for(i in formList){
				if(formList[i].className == "editOptions"){
					editOptions = formList[i]
				}
			}
			NICE.saveForm = new NICE.SaveForm(editOptions)
			NICE.updateSaveFormWhenReady()
		}	
		else{
			setTimeout('NICE.createSaveFormWhenReady()', NICE.updateTimeout)
		}
	}
	
	/**
	 * Update Save Form When Ready
	 *
	 * A simple timeout function that updates the SaveForm with information as soon
	 * as it is ready to be updated.
	 */
	NICE.updateSaveFormWhenReady = function(){
		if(
			NICE.reverted.username != null && 
			NICE.reverted.revisionId != null && 
			NICE.reverted.userRevs != null
		)
		{
			NICE.logger.undo(
				NICE.box, 
				NICE.warn, 
				NICE.reverted.username, 
				NICE.reverted.userRevs, 
				wgUserName, 
				NICE.reverted.revisionId
			)
			
			//Don't do anything is the user being reverted is not yet registered.
			if(!NICE.reverted.anon){
				if(NICE.warn && NICE.reverted.userRevs <= NICE.noobLimit){
					NICE.saveForm.showWarning()
				}
				if(NICE.box){
					NICE.saveForm.initMessageBox(NICE.reverted.revisionId, NICE.reverted.username)
					NICE.saveForm.showMessageBox()
				}
			}
		}
		else{
			setTimeout('NICE.updateSaveFormWhenReady()', NICE.updateTimeout)
		}
	}
	
	
	/**
	 * Show Error When Ready
	 *
	 * A simple timeout function that waits to shows an error as soon as the
	 * interface is ready.
	 *
	 */
	NICE.showErrorWhenReady = function(message){
		if(NICE.saveForm){
			NICE.saveForm.showError(message)
		}
		else{
			setTimeout('NICE.showErrorWhenReady("' + message + '")', NICE.updateTimeout)
		}
	}
	
	
	/**
	 * Wikipedia API Handler
	 *
	 * A simple object for interacting with Wikipedia's API.
	 */
	NICE.WPAPIHandler = function(){
	}
	
	NICE.WPAPIHandler.requests = new Array();
	NICE.WPAPIHandler.timeoutSeconds = NICE.requestTimeout;
	NICE.WPAPIHandler.url = "http://en.wikipedia.org/w/api.php";
		
		/**
		 * Timeout
		 *
		 * Stops a long running request and calls its error message
		 */
		NICE.WPAPIHandler.timeout = function(requestId){
			var request = this.requests[requestId];
			if(request){
				request.errorFun("Request to Wikipedia database timed out.");
				try{
					request.abort();
				}catch(e){
					//then don't abort I guess 
				}
			}
		}
		
		
		/**
		 * Perform Request
		 *
		 * Uses a callback function to perform a request to the WP api.
		 */
		NICE.WPAPIHandler.performGET = function(params, successFun, args, errorFun){
			this.performRequest(params, successFun, args, errorFun, "GET")
		}
		
		/**
		 * Perform Request
		 *
		 * Uses a callback function to perform a request to the WP api.
		 */
		NICE.WPAPIHandler.performPOST = function(params, successFun, args, errorFun){
			this.performRequest(params, successFun, args, errorFun, "POST")
		}
		
		
		NICE.WPAPIHandler.performRequest = function(params, successFun, args, errorFun, type){
			var paramString = "foo=foo"
			for(key in params){
				paramString += "&" + key + "=" + this.escape(params[key])
			}
			
			var request = new XMLHttpRequest
			if(!request){
				errorFun("Your browser does not support the ability to make requests to the Wikipedia database.")
				return
			}
			
			if(type=="POST"){
				request.open("POST", this.url, true)
				request.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
				request.setRequestHeader("Content-length", paramString.length)
			}
			else{
				request.open("GET", this.url+"?"+paramString, true)
			}
			request.setRequestHeader("Pragma", "cache=yes")
			request.setRequestHeader("Cache-Control", "no-transform")
			request.setRequestHeader("Connection", "close")
			request.args = args
			request.successFun = successFun
			request.errorFun = errorFun
			request.onreadystatechange = function() {
				if (this.readyState != 4){
					return
				}
				if (this.status != 200){
					errorFun("The Wikipedia server responded with an error: " + this.status + " " + this.statusText + ": " + this.responseText)
					return
				}
				clearTimeout(this.timeoutRef)
				
				successFun(this.responseText, args)
				return
			}
			request.timeoutRef = setTimeout("NICE.WPAPIHandler.timeout(" + currentRequestId + ")", this.timeoutSeconds)
			var currentRequestId = this.requests.length
			this.requests[currentRequestId] = request
			
			if(type=="POST"){
				request.send(paramString)
			}
			else{
				request.send(null)
			}
			
		}
		
		/**
		 * Escape
		 *
		 * Performs a normal URL escape, but also escapes the "+" symbol.  This is 
		 * essential for generating edit tokens.
		 */
		NICE.WPAPIHandler.escape = function(string){
			return escape(string).replace(/\+/, "%2B")
		}
	
	
	
	/**
	 * Save Form
	 * 
	 * This object represents a DOM widget in the HTML document
	 *
	 */
	NICE.SaveForm = function(editOptions){
		this.messageBoxDisplayed = false
		this.editOptions = editOptions
		
		this.errorMessage = document.createElement("div")
		var errorHeader = document.createElement("h2")
		errorHeader.innerHTML = "The NO BITING interface failed to load."
		this.errorBody = document.createElement("div")
		this.errorMessage.appendChild(errorHeader)
		this.errorMessage.appendChild(this.errorBody)
		this.errorMessage.id = "errorMessage"
			
		this.warnDiv = document.createElement("div")
		this.warnDiv.id = "warning"
		this.warnDiv.innerHTML =  '' + 
		'<div class="h2">\n' + 
		'	<span style="font-weight: bold;">Note:</span> You are reverting a new editor.  <a href="http://en.wikipedia.org/wiki/WP:BITE">Don\'t bite.</a>\n' + 
		'</div class="h2">\n' + 
		'<p class="analysis">\n' + 
		'	Analysis suggests that reverting this editor is likely to \n' + 
		'	discourage them from making future contributions.\n' + 
		'</p>\n';
		
		this.saveOptions = document.createElement("div");
		this.saveOptions.id = "saveOptions";
		
		this.normalSelector = document.createElement("a");
		this.normalSelector.innerHTML = "Normal";
		this.normalSelector.id = "normalSelector";
		this.normalSelector.className="selected";
		this.normalSelector.onclick = function(a){
			NICE.saveForm.hideMessageBox()
		}
		this.saveOptions.appendChild(this.normalSelector);
		
		this.niceSelector = document.createElement("a");
		this.niceSelector.innerHTML = "Be Very Nice";
		this.niceSelector.id = "niceSelector";
		this.niceSelector.className="";
		this.niceSelector.onclick = function(a){
			NICE.saveForm.showMessageBox()
		}
		this.saveOptions.appendChild(this.niceSelector);
		
		this.oldForm = document.createElement("div");
		this.oldForm.id="oldForm";
		
		this.messageForm = document.createElement("div");
		this.messageForm.id = "messageForm";
		this.messageForm.style.display="none";
		this.messageForm.style.width="48%";
		
		this.formMessage = document.createElement("p");
		this.formMessage.style.display="none";
		
		this.finalBreak = document.createElement("br");
		this.finalBreak.style.clear="both";
	}
	
		/**
		 * Show Error
		 *
		 * Will show an error to the user in the DOM.  If there is already an
		 * error displayed, this error will over-write it.
		 */
		NICE.SaveForm.prototype.showError = function(message){
			this.errorBody.innerHTML = message;
			if(!this.errorMessage.parent){
				//Load style
				importCSS(ACCOUNT_NAME + '/error_message.css')
				
				if(this.saveOptions.parentNode){
					this.editOptions.parentNode.insertBefore(this.errorMessage, this.saveOptions)
				}
				else{
					this.editOptions.parentNode.insertBefore(this.errorMessage, this.editOptions)
				}
			}
		}
		
		/**
		 * Show Warning
		 *
		 * Calling this method displayes the new user warning to the user.
		 */
		NICE.SaveForm.prototype.showWarning = function(){
			//Load style
			importCSS(ACCOUNT_NAME + '/warn.css');
			
			this.copyWarn = document.getElementById("editpage-copywarn")
			this.copyWarn.style.display = "none";
			
			if(this.errorMessage.parentNode){
				this.editOptions.parentNode.insertBefore(this.warnDiv, this.errorMessage);
			}
			else if(this.saveOptions.parentNode){
				this.editOptions.parentNode.insertBefore(this.warnDiv, this.saveOptions);
			}
			else{
				this.editOptions.parentNode.insertBefore(this.warnDiv, this.editOptions);
			}
		}
		
		/**
		 * Init Message Box
		 *
		 * This method modifies the save form for saving changes to a revert
		 * to include the form elements for adding information to a talk page.
		 */
		NICE.SaveForm.prototype.initMessageBox = function(revertedId, revertedUser){
			//Load style
			importCSS(ACCOUNT_NAME + '/message_box.css');
			this.editOptions.parentNode.insertBefore(this.saveOptions, this.editOptions)
			
			this.oldForm.innerHTML = this.editOptions.innerHTML
			this.editOptions.innerHTML = ""
			this.editOptions.appendChild(this.oldForm)
			
			this.formMessage.innerHTML= '' + 
				'The form below will allow you to both save your changes to ' + 
				'<a href="' + wgServer + '/wiki/' + wgPageName + '">' + wgPageName + '</a> and post a breif message to  ' + 
				'<a href="' + wgServer + '/wiki/User:' + revertedUser + '">' + revertedUser + '</a>\'s talk page explaining the revert. ' + 
				'This is your opportunity to help a new user learn the ropes.'
			this.editOptions.appendChild(this.formMessage);
			
			this.messageForm.innerHTML = '' + 
			'<span id="niceHeaderLabel">' + 
			'	<label for="niceHeader">' + 
			'		<span style="text-align: left;">' + 
			'			Message header' + 
			'			<small>(This will be posted on <a href="' + wgServer + '/wiki/User:' + revertedUser + '">' + revertedUser + '</a>\'s talk page)</small>' + 
			'		</span>' + 
			'	</label>' + 
			'</span>' + 
			'<br />' + 
			'<input name="niceHeader" style="width: 90%;" value="Reverted your revision [' + wgServer + '/w/index.php?oldid=' + revertedId + ' ' + revertedId + '] to [[' + wgPageName + ']]" id="niceHeader" maxlength="200" tabindex="1">' + 
			'<br />' + 
			'<span id="niceExplainationLabel">' + 
			'	<label for="niceExplaination">' + 
			'		<span style="text-align: left;">' + 
			'			Explaination' + 
			'			<small>(Consider explaining the appropriate <a href="' + wgServer + '/wiki/Wikipedia_policies">Wikipedia Policy</a>)</small>' + 
			'		</span>' + 
			'	</label>' + 
			'</span>' +  
			'<textarea name="niceExplaination" id="niceExplaination" style="width: 90%;" rows="4"></textarea>'
			
			this.editOptions.appendChild(this.messageForm)
			this.editOptions.appendChild(this.oldForm)
			this.editOptions.appendChild(this.finalBreak)
			this.editOptions.appendChild(document.createTextNode(' '))
			NICE.addEventListener(document.getElementById('editform'), "submit", NICE.saveAndPostMessage)
		}
		
		/**
		 * Show Message Box
		 *
		 * Displays the message box form to the user.
		 */
		NICE.SaveForm.prototype.showMessageBox = function(){
			if(this.messageBoxDisplayed){
				return true
			}
			
			this.normalSelector.className   = ""
			this.niceSelector.className     = "selected"
			this.oldForm.style.width        = "48%"
			this.messageForm.style.display  = "block"
			this.formMessage.style.display  = "block"
			this.messageBoxDisplayed        = true
		}
		
		/**
		 * Hide Message Box
		 *
		 * Hides the message box form from the user.
		 */
		NICE.SaveForm.prototype.hideMessageBox = function(){
			if(!this.messageBoxDisplayed){
				return true;
			}
			
			this.normalSelector.className      = "selected"
			this.niceSelector.className        = ""
			this.oldForm.style.width           = "96%"
			this.messageForm.style.display     = "none"
			this.formMessage.style.display     = "none"
			this.messageBoxDisplayed           = false
		}
	
	/**
	 * Logger
	 * 
	 * This object is intended to be used as a simple interface for logging that
	 * uses a the insertion of a Javascript tag to the header of the document in
	 * order to make arbitrary GET requests to any server.
	 */
	NICE.Logger = function(url){
		this.url = url;
	}
		
		/**
		 * Revert
		 *
		 * Logs the event that an editor successfully reverted a revision.
		 */
		NICE.Logger.prototype.revert = function(
				warn, 
				box, 
				revertedUser, 
				revertedUserRevs, 
				revertingUser, 
				revisionReverted, 
				newTalkRevision, 
				prevTalkRevision
			){
			this.log(
				{
					"action":             "revert",
					"timestamp":          NICE.reverted.timestamp,
					"warn":               warn,
					"box":                box,
					"user_reverted":      revertedUser.substring(0,200),
					"user_reverted_revs": revertedUserRevs,
					"user_reverting":     revertingUser.substring(0,200),
					"revision_reverted":  revisionReverted,
					"new_talk_revision":  newTalkRevision,
					"prev_talk_revision": prevTalkRevision
				}
			)
		}
		
		/**
		 * Undo
		 *
		 * Logs the event that an editor successfully loaded the undo page. 
		 */
		NICE.Logger.prototype.undo = function(warn, box, userToBeReverted, userRevs, userReverting, revisionToBeReverted){
			this.log(
				{
					"action":                   "undo",
					"warn":                     warn,
					"box":                      box,
					"user_to_be_reverted":      userToBeReverted.substring(0,200),
					"user_to_be_reverted_revs": userRevs,
					"user_reverting":           userReverting.substring(0,200),
					"revision_to_be_reverted":  revisionToBeReverted
				}
			)
		}
		
		/**
		 * Error
		 *
		 * Logs errors that a user encounters while interacting with the interface.
		 */
		NICE.Logger.prototype.error = function(revertingUser, revisionToBeReverted, operation, message){
			this.log(
				{
					"action":                   "error",
					"timestamp":                NICE.reverted.timestamp,
					"user_reverting":           revertingUser.substring(0,200),
					"revision_to_be_reverted":  revisionToBeReverted,
					"operation":                operation,
					"message":                  message.substring(0,200)
				}
			)
		}
		
		/**
		 * Log
		 *
		 * A function which formats an object into GET parameters and adds a 
		 * script tag to the head of the document.
		 */
		NICE.Logger.prototype.log = function(obj){
			if(obj.action){
				var queryString = "?logging=logging"
				for(key in obj){
					queryString += "&" + key + "=" + this.escape(obj[key])
				}
				
				//alert("logging: " + queryString);
				
				this.sendRequest(queryString);
			}
		}
		
		/**
		 * Send Request
		 *
		 * Sends a get request to the provided url the query string by adding a 
		 * script tag to the head of a document.
		 */
		NICE.Logger.prototype.sendRequest = function(queryString){
			var tag = document.createElement("script")
			tag.setAttribute("src", this.url + queryString)
			tag.setAttribute('type','text/javascript')
			document.getElementsByTagName('head')[0].appendChild(tag)
		}
		
		/**
		 * Escape
		 *
		 * Properly escapes URL parameters by changing javascript's "null" to a
		 * more useful "/n" sequence.
		 */
		NICE.Logger.prototype.escape = function(thing){
			if(thing == null){
				return escape("/n")
			}
			else{
				return escape(thing)
			}
		}
	
	NICE.logger = new NICE.Logger("http://www-users.cs.umn.edu/~halfak/wpInterfaceLogger.php")
	
	/**
	 * Post Message On User Talk
	 *
	 * Retrieves an edittoken for the user's talk page and starets the sequence of
	 * calls to add a message to the page. 
	 */
	NICE.postMessageOnUserTalk = function(username, header, message){
		var params = {
			"action": "query",
			"prop": "info",
			"intoken": "edit",
			"titles": 'User_talk:' + username,
			"format": "json"
		}
		
		var args = {
			"username": username,
			"header": header,
			"message": '<div style="font-size: .7em">This message was added using the [[' + ACCOUNT_NAME + '/NICE | NICE]] gadget.</div>' + message
		}
		
		/* This function will be called in window scope */
		var finishPostingAndLogging = function(result, args){
			try{
				var res = eval("(" + result + ")")
			}
			catch(e){
				NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Searching for edit token for user talk page", "Unable to process JSON result: " + result)
				if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page.  Continue with revert?')){
					NICE.logger.revert(
						NICE.warn, 
						NICE.box, 
						NICE.reverted.username, 
						NICE.reverted.userRevs, 
						wgUserName, 
						NICE.reverted.revisionId,
						null,
						null
					)
					document.getElementById("editform").submit()
				}
				return
			}
			
			try{
				for(thing in res.query.pages){
					var page = res.query.pages[thing]
				}
				var editToken = page.edittoken
			}
			catch(e){
				NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Looking for edit token in result", "Invalid result structure: " + result)
				if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page.  Continue with revert?')){
					NICE.logger.revert(
						NICE.warn, 
						NICE.box, 
						NICE.reverted.username, 
						NICE.reverted.userRevs, 
						wgUserName, 
						NICE.reverted.revisionId,
						null,
						null
					)
					document.getElementById("editform").submit()
				}
				return
			}
			
			
			var params = {
				"action":  'edit',
				"title":   'User_talk:' + args.username,
				"section": 'new',
				"summary": args.header,
				"text":    args.message,
				"token":   editToken,
				"format":  'json'
			}
			
			NICE.WPAPIHandler.performPOST(
				params, 
				function(result, args){
					try{
						var res = eval("(" + result + ")")
					}catch(e){
						NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Posting to user's talk page", "Unable to process JSON result: " + result)
						if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page.  Continue with revert?')){
							NICE.logger.revert(
								NICE.warn, 
								NICE.box, 
								NICE.reverted.username, 
								NICE.reverted.userRevs, 
								wgUserName, 
								NICE.reverted.revisionId,
								null,
								null
							)
							document.getElementById("editform").submit()
						}
						return
					}
					try{
						var newRevId = null
						var oldRevId = null
						newRevId = res.edit.newrevid,
						oldRevId = res.edit.oldrevid
					}catch(e){
						NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Logging a successful revert", "Invalid result structure: " + result)
						//do not return here.  If we don't have the newRevId and oldRevId, we can still log the revert.
					}
					
					NICE.logger.revert(
						NICE.warn, 
						NICE.box, 
						NICE.reverted.username, 
						NICE.reverted.userRevs, 
						wgUserName, 
						NICE.reverted.revisionId,
						newRevId,
						oldRevId
					)
					
					document.getElementById("editform").submit()
				}, 
				{},
				function(message){
					NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Posting on user's talk page", message)
					if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page.  Continue with revert?')){
						NICE.logger.revert(
							NICE.warn, 
							NICE.box, 
							NICE.reverted.username, 
							NICE.reverted.userRevs, 
							wgUserName, 
							NICE.reverted.revisionId,
							null,
							null
						)
						document.getElementById("editform").submit()
					}
				}
			)
		}
		
		NICE.WPAPIHandler.performGET(
			params, 
			finishPostingAndLogging, 
			args, 
			function(message){
				NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Asking for edit token", message)
				if(confirm('Unable to post to ' + NICE.reverted.username + '\'s talk page.  Continue with revert?')){
					document.getElementById("editform").submit()
				}
			}
		)
	}
	
	
	NICE.loadRevertedUserInformation = function(revisionId){
		//Start AJAX call sequence
		var params = {
			"action": 'query',
			"prop": 'revisions',
			"revids": revisionId,
			"rvprop": 'user',
			"format": 'json'
		}
		
		NICE.WPAPIHandler.performGET(
			params, 
			function(result, args){
				try{
					var res = eval("(" + result + ")")
				}
				catch(e){
					NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Searching for username using revisionId", "Unable to process JSON result" + result)
					showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")
					return
				}
				
				try{
					for(thing in res.query.pages){
						var page = res.query.pages[thing]
					}
					NICE.reverted.username = page.revisions[0].user
					if(page.revisions[0].anon){
						NICE.reverted.anon = true
					}
					else{
						NICE.reverted.anon = false
					}
				}
				catch(e){
					NICE.reverted.username = ""
					NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Looking for username in result", "Invalid result structure: " + result)
					showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")
					return
				}
				
				if(NICE.reverted.anon){
					//do nothing
					NICE.reverted.userRevs = 0
					return
				}
				
				var params = {
					"action": 'query',
					"list": 'users',
					"ususers": NICE.reverted.username,
					"usprop": 'editcount',
					"format": 'json'
				}
				
				NICE.WPAPIHandler.performGET(
					params, 
					function(result, args){
						try{
							var res = eval("(" + result + ")")
						}
						catch(e){
							NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Searching for editcount using username", "Unable to process JSON result: " + result)
							showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")
							return
						}
						
						try{
							NICE.reverted.userRevs = res.query.users[0].editcount
						}
						catch(e){
							NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Looking for editcount in result", "Invalid result structure: " + result)
							showErrorWhenReady("The Wikipedia server returned an invalid result while asking for user information.")
							return
						}
					}, 
					{},
					function(message){
						NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Requesting edit count of user", message)
						showErrorWhenReady(message)
					}
				)
			}, 
			{}, 
			function(message){
				NICE.logger.error(wgUserName, NICE.reverted.revisionId, "Searching for username using revisionId", message)
				showErrorWhenReady(message)
			}
		)
	}
	
	
	/* Start getting work done */
	NICE.loadRevertedUserInformation(NICE.reverted.revisionId)
	
	//Start ready catcher
	NICE.createSaveFormWhenReady()
}