Jump to content

User:RW/monobook.js

From Wikipedia, the free encyclopedia
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
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.
// BetterHistory v0.6
// Copyright (c) 2005 by Colin Hill (colin@colinhill.us)
// This is 100% free code. Use it for anything.

// Arrays to hold revision info
oldids=new Array(100);
revisions=new Array(100);

var title="Error";
var offset=0;

// Object that will soon be the slider button
var handleImg;

// Diff status (determines which pages to request)
// 0  Current revision html
// 1  Diff w/ most recent revision
// 2  Diff w/ previous revision
// 3  Raw wikicode (doesn't work in Opera yet)
var diffStatus = 0;

/* Updates diff status */
function ChangeDiffStatus(newStatus)
{
	if(diffStatus != newStatus){
		diffStatus=newStatus;
		SetArticle(currentArticle);
	}
	else
		diffStatus=newStatus;
}

/* Returns an XMLHttpRequest object */
function CreateXMLHTTPObject(){
	var object=false;

	// Internet Explorer
	/*@cc_on @*/
	/*@if (@_jscript_version >= 5)
	try{
		object = new ActiveXObject("Msxml2.XMLHTTP");
	} catch(e){
		try{
			object = new ActiveXObject("Microsoft.XMLHTTP");
		} catch(e2){
			object = false;
		}
	}
	@end @*/
	// Other UAs
	if(!object && typeof XMLHttpRequest!='undefined'){
		object = new XMLHttpRequest();
	}

	return object;
}

function NullPage(){
	return '<br /><center>This is the end.<br /><br />'+
	       '<a href="http://en.wikipedia.org/wiki/Special:BetterHistory?article='+title+'&offset='+(offset-100)+'">Go forward 100 revisions.</a><br />'+
	       '<a href="http://en.wikipedia.org/wiki/Special:BetterHistory?article='+title+'&offset='+(offset-(-100))+'">Go back 100 revisions.</a>'+
	       '</center>';
}

/* Extract & format revision strings from history page */
function ExtractRevisions(string)
{
	// Extract revision strings
	var insideTagPair=false;
	var substring="";
	var currentRevision = 0;
	for(i=0; i<string.length; i++){
		// Start of tag pair?
		if(!insideTagPair){
			if((""+string.charAt(i)) == "<")
			if(string.substr(i, 4) == "<li>"){
				// Skip past the starting li tag
				i+=3; // strlen("<li>")
				insideTagPair=true;
				continue;
			}
		}
		// End of tag pair?
		else{
			// Check for ending tag
			if((""+string.charAt(i)) == "<")
			if(string.substr(i, 5) == "</li>"){
				// Append the extracted revision to the array
				revisions[currentRevision] = substring;
				currentRevision++;

				substring="";
				insideTagPair=false;
				continue;
			}
		}

		// Append current char?
		if(insideTagPair)
			substring+=string.charAt(i);

	}

	// Remove all the radio buttons from the strings
	for(x=0; x<100; x++){
		var blanking=false;
		var temp="";

		currentRevision=revisions[x]
		for(i=0; i<currentRevision.length; i++){
			// Not blanking?
			if(!blanking){
				// Start blanking?
				if(currentRevision.substr(i, 7) == "<input ")
					blanking=true;
				// Continue not blanking
				else
					temp+=currentRevision.charAt(i);
			}
			// Blanking
			else {
				// Check for ending tag
				if((""+currentRevision.charAt(i)) == "/")
				if((""+currentRevision.charAt(i+1)) == ">"){
					// Skip last char of the tag
					i++;
					// Stop blanking chars
					blanking=false;
				}
			}
		}
		revisions[x]=temp;
	}

	// Extract oldids, add to array
	var matches=null;
	var validRevision = new RegExp("oldid=([0-9]+)");
	for(i=0; i<100; i++)
		if(matches = validRevision.exec(revisions[i]))
			oldids[i]=matches[1];
}

/* Extracts articles from surrounding html */
function ExtractArticle(string)
{
	var firstChar = string.indexOf("<!-- start content -->");
	var lastChar = string.indexOf("<!-- end content -->");
	return string.substring(firstChar, lastChar);
}

var currentArticle;

/* Download & show an article */
function SetArticle(oldidIndex)
{
	currentArticle=oldidIndex;

	var xmlhttp = CreateXMLHTTPObject();

	document.getElementById("articleHTML").innerHTML="<br /><center><b>Loading...</b></center>";

	// Diff w/ most recent revision
	if(diffStatus == 1)
		xmlhttp.open("GET", "http://en.wikipedia.org/w/index.php?title="+title+"&diff=0&oldid="+oldids[oldidIndex], true);
	// Diff w/ previous revision
	else if((diffStatus == 2) && oldids[oldidIndex] && oldids[oldidIndex+1])
		xmlhttp.open("GET", "http://en.wikipedia.org/w/index.php?title="+title+"&diff="+oldids[oldidIndex]+"&oldid="+oldids[oldidIndex+1], true);
	// This revision's wikicode
	else if(diffStatus == 3)
		xmlhttp.open("GET", "http://en.wikipedia.org/w/index.php?title="+title+"&oldid="+oldids[oldidIndex]+"&action=raw", true);
	// Selected revision
	else
		xmlhttp.open("GET", "http://en.wikipedia.org/w/index.php?title="+title+"&oldid="+oldids[oldidIndex], true);

	// Function to handle results
	xmlhttp.onreadystatechange=function() {
		if (xmlhttp.readyState==4){
			// Show raw if viewing wikicode
			if(diffStatus != 3)
				document.getElementById("articleHTML").innerHTML=ExtractArticle(xmlhttp.responseText);
			else
				document.getElementById("articleHTML").innerHTML="<pre>"+xmlhttp.responseText+"</pre>";

			// Page resizes when new article loads. Snap onto notch again.
			Snap(true);
		}
	}

	// Send request
	xmlhttp.send(null);

}

// Keeps track of the mouse button's status
var mousedown=false;

/* Returns the x coordinate of a specific notch */
function NotchCoord(notch){
	return 6*notch;
}

/* Returns the number of the nearest slider notch */
function NearestNotch(x){
	return Math.round(x/6.0);
}

// Current x pos on the track
currentX = NotchCoord(100);

/* Snaps slider button onto the nearest notch */
function Snap(butDontLoad){
	// Get X position of the track
	var object=document.getElementById("track");
	var trackPos = 0;
	while (object.offsetParent){
		trackPos += object.offsetLeft
		object = object.offsetParent;
	}

	// Snap to the nearest notch
	handleImg.style.left=""+(trackPos+NotchCoord(NearestNotch(currentX))-(12/2))+"px";

	// Update the currentX position
	currentX=NotchCoord(NearestNotch(currentX));

	// Null page
	if(NearestNotch(currentX) == 0)
		document.getElementById("articleHTML").innerHTML=NullPage();
	// Older revision
	else
		if(!butDontLoad) SetArticle(100-NearestNotch(currentX));
}

/* Moves the slider button to a new position */
function Slideto(x)
{
	// If the the mouse isn't dragging the button, return.
	if(!mousedown)
		return;

	// Get X position of the track
	var object=document.getElementById("track");
	var trackPos = 0;
	while (object.offsetParent){
		trackPos += object.offsetLeft
		object = object.offsetParent;
	}

	// Too far to the left?
	if(x<trackPos){
		currentX=0;
		handleImg.style.left=""+(trackPos-6)+"px"; //    on the mouse pointer
	}
	// Too far to the right?
	else if(x>(trackPos+600)){
		currentX=600;
		handleImg.style.left=""+(trackPos+600-6)+"px";
	}
	else{
		currentX=x-trackPos;
		handleImg.style.left=""+(x-7)+"px";
	}

	// Show the current revision string
	if(NearestNotch(currentX) != 0)
		document.getElementById('link').innerHTML = revisions[100-NearestNotch(currentX)];
	else
		document.getElementById('link').innerHTML = "Change offset?";
}

/* Handles all mouse movement */
function onmousemove_Handler(event){

	// Firefox
	if(event)
		Slideto(event.clientX);

	// Internet Explorer & Opera
	else
		Slideto(window.event.clientX);
}
document.onmousemove=onmousemove_Handler;

/* Handles mouseup events */
function onmouseup_Handler(){
	if(mousedown)
		Snap(false);

	mousedown=false;
}
document.onmouseup=onmouseup_Handler;

function onmousedown_Handler(e){
	var focusObject = !document.all ? e.target : event.srcElement;
	var topElement = !document.all ? "HTML" : "BODY";

	if (focusObject.id=="handleImg"){
		mousedown = true;
		return false;
	}
}
document.onmousedown=onmousedown_Handler;

/* Takes over the page if URL is for certain pages */
function CheckPage(){
	// Put a link on the normal history page
	var validHistoryURL = new RegExp(".+action=history.*");
	if(validHistoryURL.exec(location.href)){
		// What article?
		var matches;
		var titleExp = new RegExp("title=([^&]+)");
		if(matches = titleExp.exec(location.href))
			title = matches[1];

		// Offset?
		var matches;
		var offsetExp = new RegExp("offset=([^&]+)");
		if(matches = offsetExp.exec(location.href))
			offset = matches[1];

		document.getElementById("contentSub").innerHTML+='&nbsp;&nbsp;<a href="http://en.wikipedia.org/wiki/Special:BetterHistory?article='+title+'&offset='+offset+'">BetterHistory</a>';
	}
	
	validHistoryURL = new RegExp(".+Special:BetterHistory.*");
	if(validHistoryURL.exec(location.href)){
		// What article to request?
		var matches;
		var titleExp = new RegExp("article=([^&]+)");
		if(matches = titleExp.exec(location.href))
			title = matches[1];

		// Offset?
		var matches;
		var offsetExp = new RegExp("offset=([^&]+)");
		if(matches = offsetExp.exec(location.href))
			offset = matches[1];

		// Set window title
		document.title=title+" - BetterHistory - Wikipedia, the free encyclopedia"
		// Update weird little tab thingie
		document.getElementById("ca-article").innerHTML="<a href=\"\">BetterHistory</a>";

		document.getElementById("content").style.position="relative";
		document.getElementById("content").innerHTML =

// Start of new body content

'<!-- Options -->'+
'<center><table border="0" cellpadding="0" cellspacing="0" width="100%" height="30"><tr><td align="center">'+

'<form><input type="radio" name="diffStatus" checked onclick="ChangeDiffStatus(0);"/>This revision <input type="radio" name="diffStatus" onclick="ChangeDiffStatus(1);"/>Diff w/ most recent <input type="radio" name="diffStatus" onclick="ChangeDiffStatus(2);"/>Diff w/ previous <input type="radio" name="diffStatus" onclick="ChangeDiffStatus(3);"/>Raw wikicode</form>'+

'</td></tr></table></center>'+

'<!-- Header -->'+
'<center><table border="0" cellpadding="0" cellspacing="0" width="75%" height="40"><tr><td align="center"><span id="link">Downloading...</span></td></tr></table></center>'+

'<!-- Slider track -->'+
'<center><img id="track" src="http://gladstone.uoregon.edu/~chill1/betterhistory/slider_track.png"></center>'+

'<!-- Spacer image -->'+
'<div id="spacer" style="position:relative;"><br /></div>'+

'<!-- Article area -->'+
'<div id="articleHTML" style="position:relative;"></div>';


// End of body content

	}

	// Get X position of the track
	var object=document.getElementById("track");
	var xPos=0;
	var yPos=0;
	while (object.offsetParent){
		xPos += object.offsetLeft
		yPos += object.offsetTop
		object = object.offsetParent;
	}

	// Create the slider button
	handleImg=document.createElement('img');

	handleImg.style.position="absolute";
	handleImg.id="handleImg";
	handleImg.style.left=""+(594+xPos)+"px";
	handleImg.style.top=""+(6+yPos)+"px";
	handleImg.style.zIndex="10000";
	handleImg.setAttribute("src", "http://gladstone.uoregon.edu/~chill1/betterhistory/slider_button.gif");

	handleImg.ondragstart=function(){window.event.returnValue = false;}

	document.body.appendChild(handleImg);

	// Create XMLHttpRequest object
	var xmlhttp = CreateXMLHTTPObject();

	document.getElementById("articleHTML").innerHTML="<br /><center><b>Loading...</b></center>";

	// Make request for history page
	xmlhttp.open("GET", "http://en.wikipedia.org/w/index.php?title="+title+"&action=history&limit=100&offset="+offset);

	// Function to handle results
	xmlhttp.onreadystatechange=function() {
		if (xmlhttp.readyState==4){
			ExtractRevisions(xmlhttp.responseText);
			document.getElementById('link').innerHTML = revisions[0];

			// Set article to current revision
			SetArticle(0);
		}
	}

	// Send request
	xmlhttp.send(null);
}
window.onload=CheckPage;


// ---------------------------------------------------------------------
// God-like Monobook skin
// (c) 2005 Sam Hocevar <sam@zoy.org>
// $Id: godmode-light.js 904 2005-06-24 14:37:54Z sam $
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// Language support, taken from phase3/languages/*
// -----------------------------------------------------------------------------
var rollbacklink = 'rollback';
var cantrollback = 'Cannot revert edit; last contributor is only author of this page.';
var alreadyrolled = 'Cannot rollback last edit of [[$1]] by [[User:$2|$2]] ([[User talk:$2|Talk]]); someone else has edited or rolled back the page already. Last edit was by [[User:$3|$3]] ([[User talk:$3|Talk]]). ';
var revertpage = 'Reverted edits by [[Special:Contributions/$2|$2]] to last version by $1';
switch (document.getElementsByTagName('html')[0].lang) {
  case 'fr':
    rollbacklink = 'révoquer';
    cantrollback = 'Impossible de révoquer: dernier auteur est le seul à avoir modifié cet article';
    alreadyrolled = 'Impossible de révoquer la dernière modification de [[$1]] par  [[User:$2|$2]] ([[User talk:$2|Talk]]); quelqu\'un d\'autre à déjà modifer ou révoquer l\'article. La dernière modificaion était de [[User:$3|$3]] ([[User talk:$3|Talk]]). '; // lol @ pathetic grammar
    revertpage = "Révocation des modifications de [[Special:Contributions/$2|$2]] et restauration d'une précédente version de $1";
    break;
  case 'de':
    rollbacklink = 'Zurücksetzen';
    cantrollback = 'Die Ã&#8222;nderung kann nicht zurückgenommen werden; der letzte Autor ist der einzige.';
    alreadyrolled = 'Die Zurücknahme des Artikels [[$1]] von [[Benutzer:$2|$2]] ([[Benutzer Diskussion:$2|Diskussion]]) ist nicht möglich, da eine andere Ã&#8222;nderung oder Rücknahme erfolgt ist.  Die letzte Ã&#8222;nderung ist von [[Benutzer:$3|$3]] ([[Benutzer Diskussion:$3|Diskussion]])';
    revertpage = 'Ã&#8222;nderungen von [[Benutzer:$2]] rückgängig gemacht und letzte Version von [[Benutzer:$1]] wiederhergestellt';
    break;
  case 'es':
    rollbacklink = 'Revertir';
    cantrollback = 'No se pueden revertir las ediciones; el último colaborador es el único autor de este artículo.';
    alreadyrolled = 'No se puede revertir la última edición de [[$1]] por [[Colaborador:$2|$2]] ([[Colaborador Discusión:$2|Discusión]]); alguien más ya ha editado o revertido esa página.  La última edición fue hecha por [[Colaborador:$3|$3]] ([[Colaborador Discusión:$3|Discusión]]). ';
    revertpage = 'Revertida a la última edición de $1';
    break;
  case 'it':
    rollbacklink = 'rollback';
    cantrollback = 'Impossibile tornare ad una versione precedente: l\'ultima modifica è stata apportata dall\'unico utente che abbia lavorato a questo articolo.';
    //alreadyrolled = '';
    revertpage = 'Riportata alla revisione precedente da $1';
    break;
  case 'pt':
    rollbacklink = 'voltar';
    cantrollback = 'Não foi possível reverter a edição; o último contribuidor é o único autor deste artigo.';
    alreadyrolled = 'Não foi possível reverter as edições de  [[$1]] por [[User:$2|$2]] ([[User talk:$2|Talk]]); alguém o editou ou já o reverteu.  A última edição foi de  [[User:$3|$3]] ([[User talk:$3|Conversar com ele]]). ';
    revertpage = 'Revertidas edições por [[Special:Contributions/$2|$2]], para a última versão por $1';
    break;
}

// -----------------------------------------------------------------------------
// XMLHttpRequest support
// -----------------------------------------------------------------------------
if (document.implementation.createDocument) {
  var xmlparser = new DOMParser();
}

function XMLParse(string) {
  if (document.implementation.createDocument) {
    return xmlparser.parseFromString(string, "text/xml");
  } else if (window.ActiveXObject) {
    var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
    xmldoc.async = "false";
    ret = xmldoc.loadXML(string);      
    if (!ret)
      return null;
    return xmldoc.documentElement;
  }
  return null;
}

var xmlhttp;

function HTTPClient() {
  var http;
  if(window.XMLHttpRequest) {
    http = new XMLHttpRequest();
  } else if (window.ActiveXObject) {
    try {
      http = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        http = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
        http = false;
      }
    }
  }
  return http;
}

// -----------------------------------------------------------------------------
// MD5 hash calculator
// -----------------------------------------------------------------------------
// Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
// Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
// Distributed under the BSD License
// See http://pajhome.org.uk/crypt/md5 for more info.
// -----------------------------------------------------------------------------
var hexcase = 0;
var b64pad  = "";
var chrsz   = 8;

function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}

function core_md5(x, len)
{
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819); b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426); c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416); d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); c = md5_ff(c, d, a, b, x[i+10], 17, -42063); b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682); d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); c = md5_gg(c, d, a, b, x[i+11], 14,  643717713); b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083); c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438); d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501); a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473); b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562); b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353); c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174); d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189); a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); c = md5_hh(c, d, a, b, x[i+15], 16,  530742520); b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415); c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571); d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359); d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649); a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259); b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); }
function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); }
function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); }
function md5_hh(a, b, c, d, x, s, t) { return md5_cmn(b ^ c ^ d, a, b, x, s, t); }
function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); }

function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

// -----------------------------------------------------------------------------
// Our nice Revert functions
// -----------------------------------------------------------------------------
var gml_vandal, gml_editor, gml_url;

function PerformRevert() {
  var l, token = '', revert = false;
  // Look for '&fakeaction=rollback' in URL
  gml_url = location.pathname;
  l = location.search.substring(1).split('&');
  for (i = 0; i < l.length; i++) {
    var n = l[i].indexOf('=');
    var name = l[i].substring(0, n);
    if (name == 'fakeaction') {
      if (l[i].substring(n + 1) == 'rollback')
        revert = true;
    } else if (name == 'vandal') {
      gml_vandal = unescape(l[i].substring(n + 1));
    } else if (name == 'token') {
      token = unescape(l[i].substring(n + 1));
    } else if (name == 'title') {
      gml_url += '?' + l[i];
    }
  }
  if (!revert)
    return;
  document.getElementById('bodyContent').innerHTML = 'Please wait, reverting edits by ' + gml_vandal + '...';
  // Avoid XSS kiddies by using a special token
  if (token == '' || token != hex_md5(gml_url + gml_vandal + document.cookie)) {
    document.getElementById('bodyContent').innerHTML += '<br />Bad authentication token!';
    return;
  }

  xmlhttp = HTTPClient();
  if (!xmlhttp)
    return;
  document.getElementById('bodyContent').innerHTML += '<br />Getting article history...';
  xmlhttp.open("GET", gml_url + '&action=history&limit=50', true);
  xmlhttp.onreadystatechange = RevertStepTwo;
  xmlhttp.send(null);
}

function RevertStepTwo() {
  if (xmlhttp.readyState != 4)
    return
  var l;
  var oldid;
  // Get the vandal and new editor names
  gml_editor = '';
  doc = XMLParse(xmlhttp.responseText);
  l = doc.getElementById('pagehistory').getElementsByTagName('li');
  //l = doc.selectSingleNode('//*[@id="pagehistory"]').getElementsByTagName('li');
  for (i = 0; i < l.length; i++) {
    var name = l[i].getElementsByTagName('span')[0].getElementsByTagName('a')[0].innerHTML;
    if (i == 0 && name != gml_vandal) {
      document.getElementById('bodyContent').innerHTML += '<br />Error: ' + gml_vandal + ' is not the last editor!';
      return;
    } else if (i > 0 && name != gml_vandal) {
      oldid = l[i].getElementsByTagName('input')[0].value;
      gml_editor = name;
      break;
    }
  }
  if (gml_editor == '') {
    document.getElementById('bodyContent').innerHTML += '<br />Error: ' + gml_vandal + ' is the only editor!';
    return;
  }

  xmlhttp = HTTPClient();
  if (!xmlhttp)
    return;
  document.getElementById('bodyContent').innerHTML += '<br />Getting article edit form...';
  xmlhttp.open("GET", gml_url + '&action=edit&oldid=' + oldid, true);
  xmlhttp.onreadystatechange = RevertStepThree;
  xmlhttp.send(null);
}

function RevertStepThree() {
  if (xmlhttp.readyState != 4)
    return
  var l;
  // Insert the downloaded form in our current page, using
  // only hidden form inputs.
  var oldform = XMLParse(xmlhttp.responseText).getElementById('editform');
  var newform = document.createElement('form');
  l = oldform.getElementsByTagName('textarea');
  for (i = l.length; i--; ) {
    var t = document.createElement('input');
    t.type = 'hidden';
    t.name = l[i].name;
    t.value = l[i].innerHTML;
    newform.appendChild(t);
  }
  l = oldform.getElementsByTagName('input');
  for (i = l.length; i--; ) {
    if (l[i].name == 'wpSummary') {
      l[i].value = revertpage.replace(/\$1/g, gml_editor).replace(/\$2/g, gml_vandal);
    } else if (l[i].name == 'wpMinoredit') {
      l[i].value = '1';
    } else if (l[i].name == 'wpWatchthis') {
      if (!l[i].checked)
        continue; // Donâ&#8364;&#8482;t touch the "watch" status
      l[i].value = "on";
    } else if (l[i].name == 'wpPreview') {
      continue;
    }
    l[i].type = 'hidden';
    newform.appendChild(l[i]);
  }
  newform.name = oldform.name;
  newform.method = oldform.method;
  newform.id = oldform.id;
  newform.action = oldform.action;
  document.getElementById('bodyContent').innerHTML += '<br />Submitting form...';
  document.getElementById('bodyContent').appendChild(newform);
  // Submit the form
  newform.submit();
}

// -----------------------------------------------------------------------------
// Add revert buttons to the page
// -----------------------------------------------------------------------------
function AddRevertButtons() {
  var l, article = '', vandal;
  // Add 'revert' links to a diff page
  l = document.getElementById('bodyContent').getElementsByTagName('td');
  for (i = 0; i < l.length; i++) {
    if (l[i].className == 'diff-otitle') {
      article = l[i].getElementsByTagName('a')[0].href.split('&')[0].replace(/[^\/]*\/\/[^\/]*/, '');
    } else if (l[i].className == 'diff-ntitle') {
      vandal = l[i].getElementsByTagName('a')[1].title.split(':')[1];
      var t = l[i].innerHTML
      n = t.indexOf('</a>) <br') + t.indexOf('</A>) <BR') + 1; // XXX: WOW HACK!!!!
      if (n >= 0 && article != '' && t.indexOf('oldid=') == -1) {
        l[i].innerHTML = t.substring(0, n + 5) + ' &nbsp;&nbsp;&nbsp;<strong>[<a href="' + article + '&fakeaction=rollback&vandal=' + vandal + '&token=' + hex_md5(article + vandal + document.cookie) + '">' + rollbacklink + '</a>]</strong> ' + t.substring(n + 5, t.length);
      }
    }
  }
  // Add 'revert' links to a contributions page
  if (location.href.indexOf(':Contributions') != -1) {
    var c = document.getElementById('contentSub');
    var a = c.getElementsByTagName('a');
    if (a.length == 2) {
      vandal = a[0].innerHTML;
    } else {
      vandal = c.innerHTML.replace(/ \(.*/, '').replace(/.* /, '');
    }
    l = document.getElementById('bodyContent').getElementsByTagName('li');
    for (i = 0; i < l.length; i++) {
      var t = l[i].innerHTML
      // If we are already a sysop on this wiki, abort
      if (t.indexOf('>' + rollbacklink + '</a>]') != -1)
          break;
      if (t.indexOf('&amp;diff=0') != -1) {
        article = l[i].getElementsByTagName('a')[0].href.split('&')[0].replace(/[^\/]*\/\/[^\/]*/, '');
        l[i].innerHTML += ' [<a href="' + article + '&fakeaction=rollback&vandal=' + vandal + '&token=' + hex_md5(article + vandal + document.cookie) + '">' + rollbacklink + '</a>]';
      }
    }
  }
}