User:The General/monobook.js

TwinkleConfig = { revertMaxRevisions             :       50, userTalkPageMode               :       'tab', showSharedIPNotice             :       true, openTalkPage                   :       [ 'agf', 'norm', 'vand' ], openTalkPageOnAutoRevert       :       false, summaryAd                      :       " using TW", deletionSummaryAd              :       " using TW", protectionSummaryAd            :       " using TW", watchSpeedyPages               :       [ 'g3', 'g5', 'g10', 'g11', 'g12' ], watchProdPages                 :       true, openUserTalkPageOnSpeedyDelete :       [ 'g1', 'g2', 'g10', 'g11', 'g12', 'a1', 'a7', 'i3', 'i4', 'i5', 'i6', 'i7', 'u3', 't1' ], watchRevertedPages             :       [ 'agf', 'norm', 'vand', 'torev' ], markRevertedPagesAsMinor       :       [ 'agf', 'norm', 'vand', 'torev' ], deleteTalkPageOnDelete         :       false, watchWarnings                  :       true, markAIVReportAsMinor           :       true, markSpeedyPagesAsMinor         :       true, offerReasonOnNormalRevert      :       true, orphanBacklinksOnSpeedyDelete  :       {orphan:true, exclude:['g6']} };

// (C) Andrea Giammarchi - JSL 1.4b var undefined; function $JSL{ this.inArray=function{ var tmp=false,i=arguments[1].length; while(i&&!tmp)tmp=arguments[1][--i]===arguments[0]; return tmp; };	this.has=function(str){return $JSL.inArray(str,$has)}; this.random=function(elm){ var tmp=$JSL.$random; while(typeof(elm[tmp])!=="undefined")tmp=$JSL.$random; return tmp; };	this.$random=function{return (Math.random*1234567890).toString}; this.reverse=function(str){return str.split("").reverse.join("")}; this.replace=function(str){ var tmp=str.split(""),i=tmp.length; while(i>0)tmp[--i]=$JSL.$replace(tmp[i]); return tmp.join(""); };	this.$replace=function(tmp){ var i=tmp.length===1?tmp.charCodeAt(0):0; switch(i) { case 8	:tmp="\\b";break; case 10	:tmp="\\n";break; case 11	:tmp="\\v";break; case 12	:tmp="\\f";break; case 13	:tmp="\\r";break; case 34	:tmp="\\\"";break;			case 92	:tmp="\\\\";break;			default:				tmp=tmp.replace(/([\x00-\x07]|[\x0E-\x1F]|[\x7F-\xFF])/g,function(a,b){return "\\x"+$JSL.charCodeAt(b)}).					replace(/([\u0100-\uFFFF])/g,function(a,b){b=$JSL.charCodeAt(b);return b.length<4?"\\u0"+b:"\\u"+b});				break;		};		return tmp;	};	this.charCodeAt=function(str){return $JSL.$charCodeAt(str.charCodeAt(0))};	this.$charCodeAt=function(i){		var str=i.toString(16).toUpperCase;		return str.length<2?"0"+str:str;	};	this.$toSource=function(elm){return elm.toSource.replace(/^(\(new \w+\([^\000]+)(\)\))$/,"$2")};	this.$toInternalSource=function(elm){		var tmp=null;		switch(elm.constructor) {			case Boolean:			case Number:				tmp=elm;				break;			case String:				tmp=$JSL.$toSource(elm);				break;			default:				tmp=elm.toSource;				break;		};		return tmp;	};	this.getElementsByTagName=function(scope,i,elm,str){		var tmp=$JSL.$getElementsByTagName(scope),j=tmp.length,$tmp=[]; while(i<j){if(tmp[i][str]===elm||elm==="*")$tmp.push($JSL.$getElementsByName(tmp[i]));++i}; if(!$tmp.item){if(!$JSL.has("item"))$has.push("item");$tmp.item=function(tmp){return this[tmp]}}; return $tmp; };	this.$getElementsByTagName=function(scope){return scope.layers||scope.all}; this.$getElementsByName=function(elm) { if(!elm.getElementsByTagName)	elm.getElementsByTagName=document.getElementsByTagName; return elm; };	this.encodeURI=function(str){return str.replace(/"/g,"%22").replace(/\\/g,"%5C")};	this.$encodeURI=function(str){return $JSL.$charCodeAt(str)};	this.$encodeURIComponent=function(a,b){		var i=b.charCodeAt(0),str=[];		if(i<128)		str.push(i);		else if(i<2048)		str.push(0xC0+(i>>6),0x80+(i&0x3F));		else if(i<65536)	str.push(0xE0+(i>>12),0x80+(i>>6&0x3F),0x80+(i&0x3F));		else			str.push(0xF0+(i>>18),0x80+(i>>12&0x3F),0x80+(i>>6&0x3F),0x80+(i&0x3F));		return "%"+str.map($JSL.$encodeURI).join("%");	};	this.$decodeURIComponent=function(a,b,c,d,e){		var i=0;		if(e)	 i=parseInt(e.substr(1,2),16);		else if(d)i=((parseInt(d.substr(1,2),16)-0xC0)<<6)+(parseInt(d.substr(4,2),16)-0x80);		else if(c)i=((parseInt(c.substr(1,2),16)-0xE0)<<12)+((parseInt(c.substr(4,2),16)-0x80)<<6)+(parseInt(c.substr(7,2),16)-0x80);		else	  i=((parseInt(b.substr(1,2),16)-0xF0)<<18)+((parseInt(b.substr(4,2),16)-0x80)<<12)+((parseInt(b.substr(7,2),16)-0x80)<<6)+(parseInt(b.substr(10,2),16)-0x80); return String.fromCharCode(i); };	var $has=[]; if(!Function.prototype.apply){$has[$has.length]="apply";Function.prototype.apply=function{ var i=arguments.length===2?arguments[1].length:0,str,tmp=[],elm=(""+this).replace(/[^\(]+/,"function");		if(!arguments[0])arguments[0]={};		while(i)tmp.unshift("arguments[1]["+(--i)+"]");		do{str="__".concat($JSL.random(arguments[0]).replace(/\./,"_"),"__")}while(new RegExp(str).test(elm));		eval("var ".concat(str,"=arguments[0];tmp=(",elm.replace(/([^$])\bthis\b([^$])/g,"$1".concat(str,"$2")),")(",tmp.join(","),")"));		return tmp;	}};	if(!Function.prototype.call){$has[$has.length]="call";Function.prototype.call=function{		var i=arguments.length,tmp=[];		while(i>1)tmp.unshift(arguments[--i]);		return this.apply((i?arguments[0]:{}),tmp);	}};	if(!Array.prototype.pop){$has[$has.length]="pop";Array.prototype.pop=function{		var a=this.length,r=this[--a];		if(a>=0)this.length=a;		return r;	}};	if(!Array.prototype.push){$has[$has.length]="push";Array.prototype.push=function{		var a=0,b=arguments.length,r=this.length; while(a1){ arguments[0]=parseInt(arguments[0]); arguments[1]=parseInt(arguments[1]); c=arguments[0]+arguments[1]; for(a=0,b=this.length;a=c){ if(a===c&&d>2){ for(a=2;a0)this.push(arguments[--i]); this.reverse; return this.length; }};	if(!Array.prototype.indexOf){$has[$has.length]="indexOf";Array.prototype.indexOf=function(elm,i){ var j=this.length; if(!i)i=0; if(i>=0){while(i=0){do{if(this[i--]===elm){ j=i+1;i=0; }}while(i>0)} else if(i>-this.length) j=this.lastIndexOf(elm,this.length+i); return j;	}}; if(!Array.prototype.every){$has[$has.length]="every";Array.prototype.every=function(callback,elm){ var b=false,i=0,j=this.length; if(!elm){	while(i<j&&!b)	b=!callback(this[i]||this.charAt(i),i++,this)} else {		while(i<j&&!b)	b=!callback.apply(elm,[this[i]||this.charAt(i),i++,this]);} return !b; }};	if(!Array.prototype.filter){$has[$has.length]="filter";Array.prototype.filter=function(callback,elm){ var r=[],i=0,j=this.length; if(!elm){while(i<j){if(callback(this[i],i++,this)) r.push(this[i-1]); }} else {while(i<j){if(callback.apply(elm,[this[i],i++,this])) r.push(this[i-1]); }}		return r;	}}; if(!Array.prototype.forEach){$has[$has.length]="forEach";Array.prototype.forEach=function(callback,elm){ var i=0,j=this.length; if(!elm){	while(i<j)	callback(this[i],i++,this)} else {		while(i<j)	callback.apply(elm,[this[i],i++,this]);} }};	if(!Array.prototype.map){$has[$has.length]="map";Array.prototype.map=function(callback,elm){ var r=[],i=0,j=this.length; if(!elm){	while(i<j)	r.push(callback(this[i],i++,this))} else {		while(i<j)	r.push(callback.apply(elm,[this[i],i++,this]));} return r;	}}; if(!Array.prototype.some){$has[$has.length]="some";Array.prototype.some=function(callback,elm){ var b=false,i=0,j=this.length; if(!elm){	while(i<j&&!b)	b=callback(this[i],i++,this)} else {		while(i<j&&!b)	b=callback.apply(elm,[this[i],i++,this]);} return b;	}}; if(!String.prototype.lastIndexOf){if(!this.inArray("lastIndexOf",$has))$has[$has.length]="lastIndexOf";String.prototype.lastIndexOf=function(elm,i){ var str=$JSL.reverse(this),elm=$JSL.reverse(elm),r=str.indexOf(elm,i); return r<0?r:this.length-r; }};	if("aa".replace(/\w/g,function{return arguments[1]+" "})!=="0 1 "){$has[$has.length]="replace";String.prototype.replace=function(replace){return function(reg,func){ var r="",tmp=$JSL.random(String); String.prototype[tmp]=replace; if(func.constructor!==Function) r=this[tmp](reg,func); else { function getMatches(reg,pos,a) { function io { var a=reg.indexOf("(",pos),b=a;					while(a>0&&reg.charAt(--a)==="\\"){};					pos=b!==-1?b+1:b;					return (b-a)%2===1?1:0;				};				do{a+=io}while(pos!==-1);				return a;			};			function $replace(str){				var j=str.length-1;				while(j>0)str[--j]='"'+str[j].substr(1,str[j--].length-2)[tmp](/(\\|")/g,'\\$1')+'"';				return str.join("");			};			var p=-1,i=getMatches(""+reg,0,0),args=[],$match=this.match(reg),elm=$JSL.$random[tmp](/\./,'_AG_');			while(this.indexOf(elm)!==-1)elm=$JSL.$random[tmp](/\./,'_AG_');			while(i)args[--i]=[elm,'"$',(i+1),'"',elm].join("");			if(!args.length)r="$match[i],(p=this.indexOf($match[i++],p+1)),this";			else		r="$match[i],"+args.join(",")+",(p=this.indexOf($match[i++],p+1)),this";			r=eval('['+$replace((elm+('"'+this[tmp](reg,'"'+elm+',func('+r+'),'+elm+'"')+'"')+elm).split(elm))[tmp](/\n/g,'\\n')[tmp](/\r/g,'\\r')+'].join("")');		};		delete String.prototype[tmp]; return r;	}}(String.prototype.replace)}; if((new Date.getYear).toString.length===4){$has[$has.length]="getYear";Date.prototype.getYear=function{ return this.getFullYear-1900; }}; };$JSL=new $JSL; if(typeof(encodeURI)==="undefined"){function encodeURI(str){ var elm=/([\x00-\x20]|[\x25|\x3C|\x3E|\x5B|\x5D|\x5E|\x60|\x7F]|[\x7B-\x7D]|[\x80-\uFFFF])/g; return $JSL.encodeURI(str.toString.replace(elm,$JSL.$encodeURIComponent)); }}; if(typeof(encodeURIComponent)==="undefined"){function encodeURIComponent(str){ var elm=/([\x23|\x24|\x26|\x2B|\x2C|\x2F|\x3A|\x3B|\x3D|\x3F|\x40])/g; return $JSL.encodeURI(encodeURI(str).replace(elm,function(a,b){return "%"+$JSL.charCodeAt(b)})); }}; if(typeof(decodeURIComponent)==="undefined"){function decodeURIComponent(str){ var elm=/(%F[0-9A-F]%E[0-9A-F]%[A-B][0-9A-F]%[8-9A-B][0-9A-F])|(%E[0-9A-F]%[A-B][0-9A-F]%[8-9A-B][0-9A-F])|(%[C-D][0-9A-F]%[8-9A-B][0-9A-F])|(%[0-9A-F]{2})/g; return str.toString.replace(elm,$JSL.$decodeURIComponent); }}; if(typeof(decodeURI)==="undefined"){function decodeURI(str){ return decodeURIComponent(str); }}; if(!document.getElementById){document.getElementById=function(elm){ return $JSL.$getElementsByName($JSL.$getElementsByTagName(this)[elm]); }}; if(!document.getElementsByTagName){document.getElementsByTagName=function(elm){ return $JSL.getElementsByTagName(this,0,elm.toUpperCase,"tagName"); }}; if(!document.getElementsByName){document.getElementsByName=function(elm){ return $JSL.getElementsByTagName(this,0,elm,"name"); }}; if(typeof(XMLHttpRequest)==="undefined"){XMLHttpRequest=function{ var tmp=null,elm=navigator.userAgent; if(elm.toUpperCase.indexOf("MSIE 4")<0&&window.ActiveXObject) tmp=elm.indexOf("MSIE 5")<0?new ActiveXObject("Msxml2.XMLHTTP"):new ActiveXObject("Microsoft.XMLHTTP"); return tmp; }}; if(typeof(Error)==="undefined")Error=function{}; Error = function(base){return function(message){ var tmp=new base; tmp.message=message||""; if(!tmp.fileName) tmp.fileName=document.location.href; if(!tmp.lineNumber) tmp.lineNumber=0; if(!tmp.stack) tmp.stack="Error@:0\n(\""+this.message+"\")@"+tmp.fileName+":"+this.lineNumber+"\n@"+tmp.fileName+":"+this.lineNumber; if(!tmp.name) tmp.name="Error"; return tmp; }}(Error);

QuickForm = function QuickForm( event, eventType ) {

this.root = new QuickForm.element( { type: 'form', event: event, eventType:eventType } );

var cssNode = document.createElement('style'); cssNode.type = 'text/css'; cssNode.rel = 'stylesheet'; cssNode.appendChild( document.createTextNode("")); // Safari bugfix document.getElementsByTagName("head")[0].appendChild(cssNode); var styles = cssNode.sheet ? cssNode.sheet : cssNode.stylesSheet; styles.insertRule("form.quickform { width: 96%; margin:auto; padding: .5em; vertical-align: middle}", 0); styles.insertRule("form.quickform * { font-family: sans-serif; vertical-align: middle}", 0); styles.insertRule("form.quickform select { width: 30em; border: 1px solid gray; font-size: 1.1em}", 0); styles.insertRule("form.quickform h5 { border-top: 1px solid gray;}", 0); styles.insertRule("form.quickform textarea { width: 100%; height: 6em }", 0); styles.insertRule("form.quickform .tooltipButtonContainer { position: relative; width: 100%; }", 0); styles.insertRule("form.quickform .tooltipButton { padding: .2em; color: blue; font-weight: bold; cursor:help;}", 0); styles.insertRule(".quickformtooltip { z-index: 200; position: absolute; padding: .1em; border: 1px dotted red; background-color: Linen; font: caption; font-size: 10pt; max-width: 800px}", 0); }

QuickForm.prototype.render = function QuickFormRender { return this.root.render; } QuickForm.prototype.append = function QuickFormAppend( data ) { return this.root.append( data ); }

QuickForm.element = function QuickFormElement( data ) { this.data = data; this.childs = []; this.id = QuickForm.element.id++; }

QuickForm.element.id = 0;

QuickForm.element.prototype.append = function QuickFormElementAppend( data ) { if( data instanceof QuickForm.element ) { var child = data; } else { var child = new QuickForm.element( data ); }	this.childs.push( child ); return child; }

QuickForm.element.prototype.render = function QuickFormElementRender { var currentNode = this.compute( this.data );

for( var i = 0; i < this.childs.length; ++i ) { currentNode[1].appendChild( this.childs[i].render ); }	return currentNode[0]; }

QuickForm.element.prototype.compute = function QuickFormElementCompute( data ) { var node; var childContainder = null; var label; var id = 'node_' + this.id; if( data.adminonly && !userIsInGroup( 'sysop' ) ) { // hell hack alpha data.type = hidden; }	switch( data.type ) { case 'form': node = document.createElement( 'form' ); node.setAttribute( 'name', 'id' ); node.className = "quickform"; node.setAttribute( 'action', 'javascript:void(0);'); if( data.event ) { node.addEventListener( data.eventType || 'submit', data.event, false ); }		break; case 'select': node = document.createElement( 'div' );

node.setAttribute( 'id', 'div_' + id ); if( data.label ) { label = node.appendChild( document.createElement( 'label' ) ); label.setAttribute( 'for', id ); label.appendChild( document.createTextNode( data.label ) ); }		var select = node.appendChild( document.createElement( 'select' ) ); if( data.event ) { select.addEventListener( 'change', data.event, false ); }		if( data.multiple ) { select.setAttribute( 'multiple', 'multiple' ); }		if( data.size ) { select.setAttribute( 'size', data.size ); }		select.setAttribute( 'name', data.name );

if( data.list ) { for( var i = 0; i < data.list.length; ++i ) {

var current = data.list[i];

if( current.list ) { current.type = 'optgroup'; } else { current.type = 'option'; }

var res = this.compute( current ); select.appendChild( res[0] ); }		}		childContainder = select; break; case 'option': node = document.createElement( 'option' ); node.setAttribute( 'value', data.value ); if( data.selected ) { node.setAttribute( 'selected', 'selected' ); }		if( data.disabled ) { node.setAttribute( 'disabled', 'disabled' ); }		node.setAttribute( 'label', data.label ); node.appendChild( document.createTextNode( data.label ) ); break; case 'optgroup': node = document.createElement( 'optgroup' ); node.setAttribute( 'label', data.label );

if( data.list ) { for( var i = 0; i < data.list.length; ++i ) {

var current = data.list[i];

current.type = 'option'; //must be options here

var res = this.compute( current ); node.appendChild( res[0] ); }		}		break; case 'field': node = document.createElement( 'fieldset' ); label = node.appendChild( document.createElement( 'legend' ) ); label.appendChild( document.createTextNode( data.label ) ); if( data.name ) { node.setAttribute( 'name', data.name ); }		break; case 'checkbox': case 'radio': node = document.createElement( 'div' ); if( data.list ) { for( var i = 0; i < data.list.length; ++i ) { var cur_id = id + '_' + i;				var current = data.list[i]; cur_node = node.appendChild( document.createElement( 'div' ) ); var input = cur_node.appendChild( document.createElement( 'input' ) ); input.setAttribute( 'value', current.value ); input.setAttribute( 'name', current.name || data.name ); input.setAttribute( 'type', data.type ); input.setAttribute( 'id', cur_id ); if( current.checked ) { input.setAttribute( 'checked', 'checked' ); }				if( current.disabled ) { input.setAttribute( 'disabled', 'disabled' ); }				if( data.event ) { input.addEventListener( 'change', data.event, false ); } else if ( current.event ) { input.addEventListener( 'change', current.event, true ); }				var label = cur_node.appendChild( document.createElement( 'label' ) ); label.appendChild( document.createTextNode( current.label ) ); label.setAttribute( 'for', cur_id ); if( current.tooltip ) { QuickForm.element.generateTooltip( label, current ); }			}		}		break; case 'input': node = document.createElement( 'div' );

if( data.label ) { label = node.appendChild( document.createElement( 'label' ) ); label.appendChild( document.createTextNode( data.label ) ); label.setAttribute( 'for', id ); }

var input = node.appendChild( document.createElement( 'input' ) ); if( data.value ) { input.setAttribute( 'value', data.value ); }		input.setAttribute( 'name', data.name ); input.setAttribute( 'type', 'text' ); if( data.size ) { input.setAttribute( 'size', data.size ); }		if( data.disabled ) { input.setAttribute( 'disabled', 'disabled' ); }		if( data.readonly ) { input.setAttribute( 'readonly', 'readonly' ); }		if( data.maxlength ) { input.setAttribute( 'maxlength', data.maxlength ); }		if( data.event ) { input.addEventListener( 'keyup', data.event, false ); }		break; case 'hidden': var node = document.createElement( 'input' ); node.setAttribute( 'type', 'hidden' ); node.setAttribute( 'value', data.value ); node.setAttribute( 'name', data.name ); break; case 'header': node = document.createElement( 'h5' ); node.appendChild( document.createTextNode( data.label ) ); break; case 'div': node = document.createElement( 'div' ); break; case 'submit': node = document.createElement( 'span' ); childContainder = node.appendChild(document.createElement( 'input' )); childContainder.setAttribute( 'type', 'submit' ); if( data.label ) { childContainder.setAttribute( 'value', data.label ); }		childContainder.setAttribute( 'name', data.name || 'submit' ); if( data.disabled ) { childContainder.setAttribute( 'disabled', 'disabled' ); }		break; case 'button': node = document.createElement( 'span' ); childContainder = node.appendChild(document.createElement( 'input' )); childContainder.setAttribute( 'type', 'button' ); if( data.label ) { childContainder.setAttribute( 'value', data.label ); }		childContainder.setAttribute( 'name', data.name ); if( data.disabled ) { childContainder.setAttribute( 'disabled', 'disabled' ); }		if( data.event ) { childContainder.addEventListener( 'click', data.event, false ); }		break; case 'textarea': node = document.createElement( 'div' ); if( data.label ) { label = node.appendChild( document.createElement( 'label' ) ); label.appendChild( document.createTextNode( data.label ) ); label.setAttribute( 'for', id ); }		node.appendChild( document.createElement( 'br' ) ); textarea = node.appendChild( document.createElement( 'textarea' ) ); textarea.setAttribute( 'name', data.name ); if( data.cols ) { textarea.setAttribute( 'cols', data.cols ); }		if( data.rows ) { textarea.setAttribute( 'rows', data.rows ); }		if( data.disabled ) { textarea.setAttribute( 'disabled', 'disabled' ); }		if( data.readonly ) { textarea.setAttribute( 'readonly', 'readonly' ); }		break;

}

if( childContainder == null ) { childContainder = node; } 	if( data.tooltip ) { QuickForm.element.generateTooltip( label || node, data ); }

if( data.extra ) { childContainder.extra = extra; }	childContainder.setAttribute( 'id', id );

return [ node, childContainder ]; }

QuickForm.element.generateTooltip = function QuickFormElementGenerateTooltip( node, data ) { var tooltipButtonContainer = node.appendChild( document.createElement( 'span' ) ); tooltipButtonContainer.className = 'tooltipButtonContainer'; var tooltipButton = tooltipButtonContainer.appendChild( document.createElement( 'span' ) ); tooltipButton.className = 'tooltipButton'; tooltipButton.appendChild( document.createTextNode( '?' ) ); var tooltip = document.createElement( 'div' ); tooltip.className = 'quickformtooltip'; tooltip.appendChild( document.createTextNode( data.tooltip ) ); tooltipButton.tooltip = tooltip; tooltipButton.showing = false; tooltipButton.interval = null; tooltipButton.addEventListener( 'mouseover', QuickForm.element.generateTooltip.display, false ); tooltipButton.addEventListener( 'mouseout', QuickForm.element.generateTooltip.fade, false );

} QuickForm.element.generateTooltip.display = function QuickFormElementGenerateTooltipDisplay(e) { window.clearInterval( e.target.interval ); e.target.tooltip.style.setProperty( '-moz-opacity', 1, null); e.target.tooltip.style.setProperty( 'opacity', 1, null); e.target.tooltip.style.left = (e.pageX - e.layerX + 24) + "px"; e.target.tooltip.style.top = (e.pageY - e.layerY + 12) + "px"; document.body.appendChild( e.target.tooltip ); e.target.showing = true; }

QuickForm.element.generateTooltip.fade = function QuickFormElementGenerateTooltipFade( e ) { e.target.opacity = 1.2; e.target.interval = window.setInterval(function(e){			e.target.tooltip.style.setProperty( '-moz-opacity', e.target.opacity, null);			e.target.tooltip.style.setProperty( 'opacity', e.target.opacity, null);			e.target.opacity -= 0.1;			if( e.target.opacity <= 0 ) {				window.clearInterval( e.target.interval );				document.body.removeChild( e.target.tooltip );e.target.showing = false;			}		},50,e); }

/** RegExp.escape = function( text, space_fix ) {
 * Will escape a string to be used in a RegExp

if ( !arguments.callee.sRE ) { arguments.callee.sRE = /(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^)/g; }

text = text.replace( arguments.callee.sRE, '\\$1' );

// Special Mediawiki escape, underscore/space is the same, often at lest:

if( space_fix ) { text = text.replace( / |_/g, '[_ ]' ); }

return text;

}

// Sprintf implementation based on perl similar function sprintf { if( arguments.length == 0 ) { throw "Not enough arguments for sprintf"; }	var result = ""; var format = arguments[0];

var index = 1; var current_index = 1; var flags = {}; var in_operator = false; var relative = false; var precision = false; var fixed = false; var vector = false; var vector_delimiter = '.';

for( var i = 0; i < format.length; ++i ) { var current_char = format.charAt(i); if( in_operator ) { switch( current_char ) { case 'i': current_char = 'd'; break; case 'F': current_char = 'f'; break; case '%': case 'c': case 's': case 'd': case 'u': case 'o': case 'x': case 'e': case 'f': case 'g': case 'X': case 'E': case 'G': case 'b': var value = arguments[current_index]; if( vector ) { r = value.toString.split( '' ); result += value.toString.split('').map( function( value ) {							return sprintf.format( current_char, value.charCodeAt, flags );						}).join( vector_delimiter ); } else { result += sprintf.format( current_char, value, flags ); }				if( !fixed ) { ++index; }				current_index = index; flags = {}; relative = false; in_operator = false; precision = false; fixed = false; vector = false; vector_delimiter = '.'; break; case 'v': vector = true; break; case ' ': case '0': case '-': case '+': case '#': flags[current_char] = true; break; case '*': relative = true; break; case '.': precision = true; break; }			if( /\d/.test( current_char ) ) { var num = parseInt( format.substr( i ) ); var len = num.toString.length; i += len - 1; var next = format.charAt( i + 1 ); if( next == '$' ) { if( num <= 0 || num >= arguments.length ) { throw "out of bound"; }					if( relative ) { if( precision ) { flags['precision'] = arguments[num]; precision = false; } else if( format.charAt( i + 2 ) == 'v' ) { vector_delimiter = arguments[num]; }else { flags['width'] = arguments[num]; }						relative = false; } else { fixed = true; current_index = num; }					++i; } else if( precision ) { flags['precision'] = num; precision = false; } else { flags['width'] = num; }			} else if ( relative && !/\d/.test( format.charAt( i + 1 ) ) ) { if( precision ) { flags['precision'] = arguments[current_index]; precision = false; } else if( format.charAt( i + 1 ) == 'v' ) { vector_delimiter = arguments[current_index]; } else { flags['width'] = arguments[current_index]; }				++index; if( !fixed ) { current_index++; }				relative = false; }		} else { if( current_char == '%' ) { in_operator = true; continue; } else { result += current_char; continue; }		}	}	return result; }

sprintf.format = function sprintfFormat( type, value, flags ) {

// Similar to how perl printf works if( value == undefined ) { if( type == 's' ) { return ''; } else { return '0'; }	}

var result; var prefix = ''; var fill = ''; var fillchar = ' '; switch( type ) { case '%': result = '%'; break; case 'c': result = String.fromCharCode( parseInt( value ) ); break; case 's': result = value.toString; break; case 'd': result = parseInt( value ).toString; break; case 'u': result = Math.abs( parseInt( value ) ).toString; // it's not correct, but JS lacks unsigned ints break; case 'o': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(8); break; case 'x': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16); break; case 'b': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(2); break; case 'e': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toExponential( digits ).toString; break; case 'f': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toFixed( digits ).toString; case 'g': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toPrecision( digits ).toString; break; case 'X': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16).toUpperCase; break; case 'E': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toExponential( digits ).toString.toUpperCase; break; case 'G': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toPrecision( digits ).toString.toUpperCase; break; }

if(flags['+'] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) { prefix = '+'; }

if(flags[' '] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) { prefix = ' '; }

if( flags['#'] && parseInt( value ) != 0 ) { switch(type) { case 'o': prefix = '0'; break; case 'x': case 'X': prefix = '0x'; break; case 'b': prefix = '0b'; break; }	}

if( flags['0'] && !flags['-'] ) { fillchar = '0'; }

if( flags['width'] && flags['width'] > ( result.length + prefix.length ) ) { var tofill = flags['width'] - result.length - prefix.length; for( var i = 0; i < tofill; ++i ) { fill += fillchar; }	}

if( flags['-'] && !flags['0'] ) { result += fill; } else { result = fill + result; }	return prefix + result; }

String.prototype.splitWeightedByKeys = function stringPrototypeSplitWeightedByKeys( start, end ) { if( start.length != end.length ) { throw 'start marker and end marker must be of the same length'; }	var level = 0; var initial = null; var result = []; for( var i = 0; i < this.length; ++i ) { if( this.substr( i, start.length ) == start ) { if( initial == null ) { initial = i;			} ++level; i += start.length - 1; } else if( this.substr( i, end.length ) == end ) { --level; i += end.length - 1; }		if( level == 0 && initial != null ) { result.push( this.substring( initial, i + 1 ) ); initial = null; }	}

return result; }

Array.prototype.uniq = function arrayPrototypeUniq { var result = []; for( var i = 0; i < this.length; ++i ) { var current = this[i]; if( result.indexOf( current ) == -1 ) { result.push( current ); }	}	return result; }

Array.prototype.dups = function arrayPrototypeUniq { var uniques = []; var result = []; for( var i = 0; i < this.length; ++i ) { var current = this[i]; if( uniques.indexOf( current ) == -1 ) { uniques.push( current ); } else { result.push( current ); }	}	return result; }

Array.prototype.chunk = function arrayChunk( size ) { if( size <= 0 ) { return this; }	var result = []; var current; for(var i = 0; i < this.length; ++i ) { if( i % size == 0 ) { current = []; result.push( current ); }		current.push( this[i] ); }   return result; }

function clone( obj, deep ) { var objectClone = new obj.constructor; for ( var property in obj ) if ( !deep ) { objectClone[property] = obj[property]; }   else if ( typeof obj[property] == 'object' ) { objectClone[property] = clone( obj[property], deep ); }   else { objectClone[property] = obj[property]; } return objectClone; }

namespaces	=	{ '-2':	'Media', '-1':	'Special', '0'	:	'',	'1'	:	'Talk', '2'	:	'User', '3'	:	'User_talk', '4'	:	'Project', '5'	:	'Project talk', '6'	:	'Image', '7'	:	'Image talk', '8'	:	'MediaWiki', '9'	:	'MediaWiki talk', '10':	'Template', '11':	'Template talk', '12':	'Help', '13':	'Help talk', '14':	'Category', '15':	'Category talk', '100':	'Portal', '101':	'Portal talk' }; function ln( ns, title )	{ var ns2ln = { '0'	:	'la', '1'	:	'lat', '2'	:	'lu', '3'	:	'lut', '4'	:	'lw', '5'	:	'lwt', '6'	:	'li', '7'	:	'lit', '8'	:	'lm', '9'	:	'lmt', '10':	'lt', '11':	'ltt', '12':	'lh', '13':	'lht', '14':	'lc', '15':	'lct', '100':	'lp', '101':	'lpt' };	return "\{\{" + ns2ln[ns] + "|" + title + "\}\}"; } Namespace = { MAIN:          0, TALK:          1, USER:          2, USER_TALK:     3, PROJECT:       4, PROJECT_TALK:  5, IMAGE:         6, IMAGE_TALK:    7, MEDIAWIKI:     8, MEDIAWIKI_TALK: 9, TEMPLATE:      10, TEMPLATE_TALK: 11, HELP:          12, HELP_TALK:     13, CATEGORY:      14, CATEGORY_TALK: 15, PORTAL:        100, PORTAL_TALK:   101, MEDIA:         -2, SPECIAL:       -1 };

// Helper functions to change case of a string String.prototype.toUpperCaseFirstChar = function { return this.substr( 0, 1 ).toUpperCase + this.substr( 1 ); }

String.prototype.toLowerCaseFirstChar = function { return this.substr( 0, 1 ).toLowerCase + this.substr( 1 ); }

String.prototype.toUpperCaseEachWord = function( delim ) { delim = delim ? delim : ' '; return this.split( delim ).map( function(v) { return v.toUpperCaseFirstChar } ).join( delim ); }

String.prototype.toLowerCaseEachWord = function( delim ) { delim = delim ? delim : ' '; return this.split( delim ).map( function(v) { return v.toLowerCaseFirstChar } ).join( delim ); }

/**
 * Helper functions to get the month as a string instead of a number

Date.monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; Date.monthNamesAbbrev = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];

Date.prototype.getMonthName = function { return Date.monthNames[ this.getMonth ]; }

Date.prototype.getMonthNameAbbrev = function { return Date.monthNamesAbbrev[ this.getMonth ]; } Date.prototype.getUTCMonthName = function { return Date.monthNames[ this.getUTCMonth ]; }

Date.prototype.getUTCMonthNameAbbrev = function { return Date.monthNamesAbbrev[ this.getUTCMonth ]; }

// Accessor functions for wikiediting and api-access Wikipedia = {};

// we dump all XHR here so they won't loose props Wikipedia.dump = [];

Wikipedia.numberOfActionsLeft = 0; Wikipedia.nbrOfCheckpointsLeft = 0;

Wikipedia.actionCompleted = function( self ) { if( --Wikipedia.numberOfActionsLeft <= 0 && Wikipedia.nbrOfCheckpointsLeft <= 0 ) { Wikipedia.actionCompleted.event( self ); } }

// Change per action wanted Wikipedia.actionCompleted.event = function { new Status( Wikipedia.actionCompleted.notice, Wikipedia.actionCompleted.postfix, 'info' ); if( Wikipedia.actionCompleted.redirect != null ) { // if it isn't an url, make it an relative to self (probably this is the case) if( !/^\w+\:\/\//.test( Wikipedia.actionCompleted.redirect ) ) { Wikipedia.actionCompleted.redirect = wgServer + wgArticlePath.replace( '$1', Wikipedia.actionCompleted.redirect ); }		window.setTimeout( function { window.location = Wikipedia.actionCompleted.redirect }, Wikipedia.actionCompleted.timeOut ); } } wpActionCompletedTimeOut = typeof(wpActionCompletedTimeOut) == 'undefined' ? 5000 : wpActionCompletedTimeOut; wpMaxLag = typeof(wpMaxLag) == 'undefined' ? 10 : wpMaxLag; // Maximum lag allowed, 5-10 is a good value, the higher value, the more agressive.

Wikipedia.firstEdit = true; Wikipedia.actionCompleted.timeOut = wpActionCompletedTimeOut; Wikipedia.actionCompleted.redirect = null; Wikipedia.actionCompleted.notice = 'Action'; Wikipedia.actionCompleted.postfix = 'completed';

Wikipedia.addCheckpoint = function { ++Wikipedia.nbrOfCheckpointsLeft; }

Wikipedia.removeCheckpoint = function { if( --Wikipedia.nbrOfCheckpointsLeft <= 0 && Wikipedia.numberOfActionsLeft <= 0 ) { Wikipedia.actionCompleted.event; } }

/* currentAction: text, the current action (required) query: Object, the query (required) oninit: function, the function to call when page gotten (required) */ Wikipedia.api = function( currentAction, query, oninit, statelem ) { this.currentAction = currentAction; this.query = query; this.query['format'] = 'xml'; //LET THE FORCE BE WITH YOU!!! this.oninit = oninit; if( statelem ) { statelem.status( currentAction ) } else { this.statelem = new Status( currentAction ); }	++Wikipedia.numberOfActionsLeft; } Wikipedia.api.prototype = { currentAction: '', oninit: null, query: null, responseXML: null, statelem: null, counter: 0, post: function { var xmlhttp = sajax_init_object; Wikipedia.dump.push( xmlhttp ); xmlhttp.obj = this; xmlhttp.overrideMimeType('text/xml'); xmlhttp.open( 'POST', wgServer + wgScriptPath + '/api.php', true); xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded'); xmlhttp.onerror = function { var self = this.obj; self.statelem.error( "Error " + this.target.status + " occurred while quering the api." ); }		xmlhttp.onload = function { this.obj.responseXML = this.responseXML; this.obj.oninit( this.obj ); Wikipedia.actionCompleted; };		xmlhttp.send( QueryString.create( this.query ) ); } }

/* currentAction: text, the current action (required) query: Object, the query (required) oninit: function, the function to call when page gotten (required) onsuccess: function, a function to call when post succeeded onerror: function, a function to call when we abort failed posts onretry: function, a function to call when we try to retry a post */ Wikipedia.wiki = function( currentAction, query, oninit, onsuccess, onerror, onretry ) { this.currentAction = currentAction; this.query = query; this.oninit = oninit; this.onsuccess = onsuccess; this.onerror = onerror; this.onretry = onretry; this.statelem = new Status( currentAction ); ++Wikipedia.numberOfActionsLeft; }

Wikipedia.wiki.prototype = { currentAction: '', onsuccess: null, onerror: null, onretry: null, oninit: null, query: null, postData: null, responseXML: null, statelem: null, counter: 0, post: function( data ) { this.postData = data; if( ! Wikipedia.firstEdit ) { this.query['maxlag'] = wpMaxLag; // are we a bot? } 		Wikipedia.firstEdit = false;

var xmlhttp = sajax_init_object; Wikipedia.dump.push( xmlhttp ); xmlhttp.obj = this; xmlhttp.overrideMimeType('text/xml'); xmlhttp.open( 'POST', wgServer + wgScriptPath + '/index.php?' + QueryString.create( this.query ), true); xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded'); xmlhttp.onerror = function(e) { var self = this.obj; self.statelem.error( "Error " + e.target.status + " occurred while posting the document." ); }		xmlhttp.onload = function(e) { var self = this.obj; var status = e.target.status; if( status != 200 ) { if( status == 503 ) { var retry = e.target.getResponseHeader( 'Retry-After' ); var lag = e.target.getResponseHeader( 'X-Database-Lag' ); if( lag ) { self.statelem.warn( "current lag of " + lag + " seconds is more than our defined maximum lag of " + wpMaxLag + " seconds, will retry in " + retry + " seconds" ); window.setTimeout( function( self ) { self.post( self.postData ); }, retry * 1000, self ); return; } else { self.statelem.error( "Error " + status + " occurred while posting the document." ); }				}				return; }			var xmlDoc; xmlDoc = self.responseXML = this.responseXML; var xpathExpr = 'boolean(//div[@class=\'previewnote\']/p/strong[contains(.,\'Sorry! We could not process your edit due to a loss of session data\')])'; var nosession = xmlDoc.evaluate( xpathExpr, xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue; if( nosession ) { // Grabbing the shipping token, and repost var new_token = xmlDoc.evaluate( '//input[@name="wfEditToken"]/@value', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue; self.postData['wfEditToken'] = new_token; self.post( self.postData ); } else { if( self.onsuccess ) { self.onsuccess( self ); } else { var link = document.createElement( 'a' ); link.setAttribute( 'href', wgArticlePath.replace( '$1', self.query['title'] ) ); link.setAttribute( 'title', self.query['title'] ); link.appendChild( document.createTextNode( self.query['title'] ) );

self.statelem.info( [ 'completed (', link , ')' ] ); }				Wikipedia.actionCompleted; }		};		xmlhttp.send( QueryString.create( this.postData ) ); },	get: function { this.onloading( this ); var redirect_query = { 'action': 'query', 'titles': this.query['title'], 'redirects': '' }

var wikipedia_api = new Wikipedia.api( "resolving eventual redirect", redirect_query, this.postget, this.statelem ); wikipedia_api.parent = this; wikipedia_api.post; },	postget: function { var xmlDoc = self.responseXML = this.responseXML; var to = xmlDoc.evaluate( '//redirects/r/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue; if( !this.followRedirect ) { this.parent.statelem.info('ignoring eventual redirect'); } else if( to ) { this.parent.query['title'] = to; }		this.parent.onloading( this ); var xmlhttp = sajax_init_object; Wikipedia.dump.push( xmlhttp ); xmlhttp.obj = this.parent; xmlhttp.overrideMimeType('text/xml'); xmlhttp.open( 'GET', wgServer + wgScriptPath + '/index.php?' + QueryString.create( this.parent.query ), true); xmlhttp.onerror = function { var self = this.obj; self.statelem.error( "Error " + this.status + " occurred while recieving the document." ); }		xmlhttp.onload = function { this.obj.onloaded( this.obj ); this.obj.responseXML = this.responseXML; this.obj.responseText = this.responseText; this.obj.oninit( this.obj ); };		xmlhttp.send( null ); },	onloading: function { this.statelem.status( 'loading data...' ); },	onloaded: function { this.statelem.status( 'data loaded...' ); } }

Number.prototype.zeroFill = function( length ) { var str = this.toFixed; if( !length ) { return str; } while( str.length < length ) { str = '0' + str; } return str; }

Mediawiki = {};

Mediawiki.Page = function mediawikiPage( text ) { this.text = text; }

Mediawiki.Page.prototype = { text: '', removeLink: function( link_target ) { var first_char = link_target.substr( 0, 1 ); var link_re_string = "[" + first_char.toUpperCase + first_char.toLowerCase + ']' + RegExp.escape( link_target.substr( 1 ), true ); var link_simple_re = new RegExp( "\\[\\[(" + link_re_string + ")\\|?\\]\\]", 'g' ); var link_named_re = new RegExp( "\\[\\[" + link_re_string + "\\|(.+?)\\]\\]", 'g' ); if( link_simple_re.test(this.text) ) { this.text = this.text.replace( link_simple_re, "$1" ); } else { this.text = this.text.replace( link_named_re, "$1" ); }	},	commentOutImage: function( image, reason ) { reason = reason ? ' ' + reason + ': ' : ''; var first_char = image.substr( 0, 1 ); var image_re_string = "[" + first_char.toUpperCase + first_char.toLowerCase + ']' + RegExp.escape( image.substr( 1 ), true ); var links_re = new RegExp( "\\[\\Ii]mage:\\s*" + image_re_string );		var allLinks = this.text.splitWeightedByKeys( '[[',  ).uniq;		for( var i = 0; i < allLinks.length; ++i ) {			if( links_re.test( allLinks[i] ) ) {				var replacement = ;				this.text = this.text.replace( allLinks[i], replacement );			}		}

var gallery_re = new RegExp( "^\\s*((?:\\|?\\s*\\w+\\s*\\=\\s*)(?:[Ii]mage:\\s*)?" + image_re_string + '.*?)$', 'mg' ); var replacement = "";

this.text = this.text.replace( gallery_re, replacement ); },	addToImageComment: function( image, data ) { var first_char = image.substr( 0, 1 ); var image_re_string = "[Ii]mage:\\s*[" + first_char.toUpperCase + first_char.toLowerCase + ']' + RegExp.escape( image.substr( 1 ), true ); var links_re = new RegExp( "\\[\\[" + image_re_string ); var allLinks = this.text.splitWeightedByKeys( ,  ).uniq; for( var i = 0; i < allLinks.length; ++i ) { if( links_re.test( allLinks[i] ) ) { var replacement = allLinks[i]; // just put it at the end? replacement = replacement.replace( /\]\]$/, '|' + data + ']]' ); this.text = this.text.replace( allLinks[i], replacement ); }		}		var gallery_re = new RegExp( "^(\\s*" + image_re_string + '.*?)\\|?(.*?)$', 'mg' ); var replacement = "$1|$2 " + data; this.text = this.text.replace( gallery_re, replacement ); },	getText: function { return this.text; } }

// Simple helper functions to see what groups a user might belong

function userIsInGroup( group ) {

return ( wgUserGroups != null && wgUserGroups.indexOf( group ) != -1 ) || ( wgUserGroups == null && group == 'anon' ); }

function userIsAnon { return wgUserGroups == null; }

// AOL Proxy IP Addresses (2007-02-03) var AOLNetworks = [ '64.12.96.0/19',	'149.174.160.0/20',	'152.163.240.0/21',	'152.163.248.0/22',	'152.163.252.0/23',	'152.163.96.0/22',	'152.163.100.0/23',	'195.93.32.0/22',	'195.93.48.0/22',	'195.93.64.0/19',	'195.93.96.0/19',	'195.93.16.0/20',	'198.81.0.0/22',	'198.81.16.0/20',	'198.81.8.0/23',	'202.67.64.128/25',	'205.188.192.0/20',	'205.188.208.0/23',	'205.188.112.0/20',	'205.188.146.144/30',	'207.200.112.0/21', ];

// AOL Client IP Addresses (2007-02-03) var AOLClients = [ '172.128.0.0/10',	'172.192.0.0/12',	'172.208.0.0/14',	'202.67.66.0/23',	'172.200.0.0/15',	'172.202.0.0/15',	'172.212.0.0/14',	'172.216.0.0/16',	'202.67.68.0/22',	'202.67.72.0/21',	'202.67.80.0/20',	'202.67.96.0/19', ];

/**
 * ipadress is in the format 1.2.3.4 and network is in the format 1.2.3.4/5

function isInNetwork( ipaddress, network ) { var iparr = ipaddress.split('.'); var ip = (parseInt(iparr[0]) << 24) + (parseInt(iparr[1]) << 16) + (parseInt(iparr[2]) << 8) + (parseInt(iparr[3]));

var netmask = 0xffffffff << network.split('/')[1];

var netarr = network.split('/')[0].split('.'); var net = (parseInt(netarr[0]) << 24) + (parseInt(netarr[1]) << 16) + (parseInt(netarr[2]) << 8) + (parseInt(netarr[3]));

return (ip & netmask) == net; }

/* Returns true if given string contains a valid IP-address, that is, from 0.0.0.0 to 255.255.255.255*/ function isIPAddress( string ){ var res = /(\d{1,4})\.(\d{1,3})\.(\d{1,3})\.(\d{1,4})/.exec( string ); return res != null && res.slice( 1, 5 ).every( function( e ) { return e < 256; } ); }

/** function QueryString(qString) { this.string = qString; this.params = {};
 * Maps the querystring to an object
 * Functions:
 * QueryString.exists(key)
 * returns true if the particular key is set
 * QueryString.get(key)
 * returns the value associated to the key
 * QueryString.equals(key, value)
 * returns true if the value associated with given key equals given value
 * QueryString.toString
 * returns the query string as a string
 * QueryString.create( hash )
 * creates an querystring and encodes strings via encodeURIComponent and joins arrays with |
 * In static context, the value of location.search.substring(1), else the value given to the constructor is going to be used. The mapped hash is saved in the object.
 * Example:
 * var value = QueryString.get('key');
 * var obj = new QueryString('foo=bar&baz=quux');
 * value = obj.get('foo');
 * Example:
 * var value = QueryString.get('key');
 * var obj = new QueryString('foo=bar&baz=quux');
 * value = obj.get('foo');
 * value = obj.get('foo');

if( qString.length == 0 ) { return; }

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] ); }

this.params[key] = value; } }

QueryString.static = null;

QueryString.staticInit = function { if( QueryString.static == null ) { QueryString.static = new QueryString(location.search.substring(1)); } }

QueryString.get = function(key) { QueryString.staticInit; return QueryString.static.get(key); };

QueryString.prototype.get = function(key) { return this.params[key] ? this.params[key] : null; };

QueryString.exists = function(key) { QueryString.staticInit; return QueryString.static.exists(key); }

QueryString.prototype.exists = function(key) { return this.params[key] ? true : false; }

QueryString.equals = function(key, value) { QueryString.staticInit; return QueryString.static.equals(key, value); }

QueryString.prototype.equals = function(key, value) { return this.params[key] == value ? true : false; }

QueryString.toString = function { QueryString.staticInit; return QueryString.static.toString; }

QueryString.prototype.toString = function { return this.string ? this.string : null; }

QueryString.create = function( arr ) { var resarr = Array; for( var i in arr ) { if( typeof arr[i] == 'undefined' ) { continue; }		if( arr[i] instanceof Array ){ var v = Array; for(var j = 0; j < arr[i].length; ++j ) { v[j] = encodeURIComponent( arr[i][j] ); }			resarr.push( encodeURIComponent( i ) + '=' + v.join('|') ); } else { resarr.push( encodeURIComponent( i ) + '=' + encodeURIComponent( arr[i] ) ); }	}

return resarr.join('&'); } QueryString.prototype.create = QueryString.create;

/**
 * Simple exception handling

Exception = function( str ) { this.str = str || ''; }

Exception.prototype.what = function { return this.str; }

function Status( text, stat, type ) { this.text = this.codify(text); this.stat = this.codify(stat); this.type = type || 'status'; this.generate; if( stat ) { this.render; } } Status.init = function( root ) { if( !( root instanceof Element ) ) { throw new Exception( 'object not an instance of Element' ); }	while( root.hasChildNodes ) { root.removeChild( root.firstChild ); }	Status.root = root;

var cssNode = document.createElement('style'); cssNode.type = 'text/css'; cssNode.rel = 'stylesheet'; cssNode.appendChild( document.createTextNode("")); // Safari bugfix document.getElementsByTagName("head")[0].appendChild(cssNode); var styles = cssNode.sheet ? cssNode.sheet : cssNode.stylesSheet; styles.insertRule(".tw_status_status { color: SteelBlue; }", 0); styles.insertRule(".tw_status_info { color: ForestGreen; }", 0); styles.insertRule(".tw_status_warn { color: OrangeRed; }", 0); styles.insertRule(".tw_status_error { color: OrangeRed; font-weight: 900; }", 0); } Status.root = null;

Status.prototype = { stat: null, text: null, type: 'status', target: null, node: null, linked: false, link: function { if( ! this.linked && Status.root ) { Status.root.appendChild( this.node ); this.linked = true; }	},	unlink: function { if( this.linked ) { Status.root.removeChild( this.node ); this.linked = false; }	},	codify: function( obj ) { if ( ! ( obj instanceof Array ) ) { obj = [ obj ]; }		var result; result = document.createDocumentFragment; for( var i = 0; i < obj.length; ++i ) { if( typeof obj[i] == 'string' ) { result.appendChild( document.createTextNode( obj[i] ) ); } else if( obj[i] instanceof Element ) { result.appendChild( obj[i] ); } // Else cosmic radiation made something shit }		return result;

},	update: function( status, type ) { this.stat = this.codify( status ); if( type ) { this.type = type; }		this.render; },	generate: function { this.node = document.createElement( 'div' ); this.node.appendChild( document.createElement('span') ).appendChild( this.text ); this.node.appendChild( document.createElement('span') ).appendChild( document.createTextNode( ': ' ) ); this.target = this.node.appendChild( document.createElement( 'span' ) ); this.target.appendChild( document.createTextNode( '' ) ); // dummy node },	render: function { this.node.className = 'tw_status_' + this.type; while( this.target.hasChildNodes ) { this.target.removeChild( this.target.firstChild ); }		this.target.appendChild( this.stat ); this.link; },	status: function( status ) { this.update( status, 'status'); },	info: function( status ) { this.update( status, 'info'); },	warn: function( status ) { this.update( status, 'warn'); },	error: function( status ) { this.update( status, 'error'); } }

Status.status = function( text, status ) { return new Status( text, status, 'status' ); } Status.info = function( text, status ) { return new Status( text, status, 'info' ); } Status.warn = function( text, status ) { return new Status( text, status, 'error' ); } Status.error = function( text, status ) { return new Status( text, status, 'error' ); }

// Simple helper function to create a simple node function htmlNode( type, content, color ) { var node = document.createElement( type ); if( color ) { node.style.color = color; }	node.appendChild( document.createTextNode( content ) ); return node; }

// A simple dragable window

function SimpleWindow( width, height ) { var stylesheet = document.createElement('style'); stylesheet.type = 'text/css'; stylesheet.rel = 'stylesheet'; stylesheet.appendChild( document.createTextNode("") ); // Safari bugfix document.getElementsByTagName("head")[0].appendChild(stylesheet); var styles = stylesheet.sheet ? stylesheet.sheet : stylesheet.styleSheet; styles.insertRule(		".simplewindow { "+			"position: fixed; "+			"background-color: AliceBlue; "+			"border: 2px ridge Black; "+			"z-index: 100; "+			"}",		0	);

styles.insertRule(		".simplewindow .content { "+			"position: absolute; "+			"top: 20px; "+			"bottom: 0; "+			"overflow: auto; "+			"width: 100%; "+			"}",		0	);

styles.insertRule(		".simplewindow .resizebuttonhorizontal { "+			"position: absolute; "+			"background-color: MediumPurple; "+			"opacity: 0.5; "+			"right: -2px; "+			"bottom: -2px; "+			"width: 20px; "+			"height: 4px; "+			"cursor: se-resize; "+			"}",		0	); styles.insertRule(		".simplewindow .resizebuttonvertical { "+			"position: absolute; "+			"opacity: 0.5; "+			"background-color: MediumPurple; "+			"right: -2px; "+			"bottom: -2px; "+			"width: 4px; "+			"height: 20px; "+			"cursor: se-resize; "+			"}",		0	);

styles.insertRule( 		".simplewindow .closebutton {"+			"position: absolute; "+			"font: 100 0.8em sans-serif; "+			"top: 1px; "+			"left: 1px; "+			"height: 100%; "+			"cursor: pointer; "+			"}",		0	);

styles.insertRule(		".simplewindow .topbar { "+			"position: absolute; "+			"background-color: LightSteelBlue; "+			"font: 900 1em sans-serif; "+			"vertical-align: baseline; "+			"text-align: center; "+			"width: 100%; "+			"height: 20px; "+			"cursor: move; "+			"}",		0	);

this.width = width; this.height = height;

var frame = document.createElement( 'div' ); var content = document.createElement( 'div' ); var topbar = document.createElement( 'div' ); var title = document.createElement( 'span' ); var closeButton = document.createElement( 'span' ); var resizeButton2 = document.createElement( 'div' ); var resizeButton1 = document.createElement( 'div' );

this.frame = frame; this.title = title; this.content = content;

frame.className = 'simplewindow'; content.className = 'content'; topbar.className = 'topbar'; resizeButton1.className = 'resizebuttonvertical'; resizeButton2.className = 'resizebuttonhorizontal'; closeButton.className = 'closebutton'; title.className = 'title';

topbar.appendChild( closeButton ); topbar.appendChild( title ); frame.appendChild( topbar ); frame.appendChild( content ); frame.appendChild( resizeButton1 ); frame.appendChild( resizeButton2 );

frame.style.width = width + 'px'; frame.style.height = height + 'px'; frame.style.top = parseInt( window.innerHeight - this.height )/2 + 'px' ; frame.style.left = parseInt( window.innerWidth - this.width )/2 + 'px'; var img = document.createElement( 'img' ); img.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Nuvola_apps_error.png/18px-Nuvola_apps_error.png"; closeButton.appendChild( img );

var self = this;

// Specific events frame.addEventListener( 'mousedown', function(event) { self.focus(event); }, false ); closeButton.addEventListener( 'click', function(event) {self.close(event); }, false ); topbar.addEventListener( 'mousedown', function(event) {self.initMove(event); }, false ); resizeButton1.addEventListener( 'mousedown', function(event) {self.initResize(event); }, false ); resizeButton2.addEventListener( 'mousedown', function(event) {self.initResize(event); }, false );

// Generic events window.addEventListener( 'mouseover', function(event) {self.handleEvent(event); }, false ); window.addEventListener( 'mousemove', function(event) {self.handleEvent(event); }, false ); window.addEventListener( 'mouseup', function(event) {self.handleEvent(event); }, false ); this.currentState = this.initialState; }

SimpleWindow.prototype = { focusLayer: 100, width: 800, height: 600, initialState: "Inactive", currentState: null, // current state of finite state machine (one of 'actionTransitionFunctions' properties) focus: function(event) { this.frame.style.zIndex = ++this.focusLayer; },	close: function(event) { event.preventDefault; document.body.removeChild( this.frame ); },	initMove: function(event) { event.preventDefault; this.initialX = parseInt( event.clientX - this.frame.offsetLeft ); this.initialY = parseInt( event.clientY - this.frame.offsetTop ); this.frame.style.opacity = '0.5'; this.currentState = 'Move'; },	initResize: function(event) { event.preventDefault; this.frame.style.opacity = '0.5'; this.currentState = 'Resize'; },	handleEvent: function(event) { event.preventDefault; var actionTransitionFunction = this.actionTransitionFunctions[this.currentState][event.type]; if( !actionTransitionFunction ) { actionTransitionFunction = this.unexpectedEvent; }		var nextState = actionTransitionFunction.call(this, event); if( !nextState ){ nextState = this.currentState; }       if( !this.actionTransitionFunctions[nextState] ){ nextState = this.undefinedState(event, nextState); }       this.currentState = nextState; event.stopPropagation; },   unexpectedEvent: function(event) { throw ("Handled unexpected event '" + event.type + "' in state '" + this.currentState); return this.initialState; },     undefinedState: function(event, state) { throw ("Transitioned to undefined state '" + state + "' from state '" + this.currentState + "' due to event '" + event.type); return this.initialState; }, 	actionTransitionFunctions: { Inactive: { mouseover: function(event) { return this.currentState; },           mousemove: function(event) { return this.currentState; },           mouseup: function(event) { return this.currentState; }       },         Move: { mouseover: function(event) { this.moveWindow( event.clientX, event.clientY ); return this.currentState; },           mousemove: function(event) { return this.doActionTransition("Move", "mouseover", event); },           mouseup: function(event) { this.frame.style.opacity = '1'; return 'Inactive'; }       }, 		Resize: { mouseover: function(event) { this.resizeWindow( event.clientX, event.clientY ); return this.currentState; },			mousemove: function(event) { return this.doActionTransition("Resize", "mouseover", event); },			mouseup: function(event) { this.frame.style.opacity = '1'; return 'Inactive'; }		}	},	doActionTransition: function(anotherState, anotherEventType, event) { return this.actionTransitionFunctions[anotherState][anotherEventType].call(this,event); },	display: function { document.body.appendChild( this.frame ); },	setTitle: function( title ) { this.title.textContent = title; },	setWidth: function( width ) { this.frame.style.width = width; },	setHeight: function( height ) { this.frame.style.height = height; },	setContent: function( content ) { this.purgeContent; this.addContent( content ); },	addContent: function( content ) { this.content.appendChild( content ); },	purgeContent: function( content ) { while( this.content.hasChildNodes ) { this.content.removeChild( this.content.firstChild ); }	},	moveWindow: function( x, y ) { this.frame.style.left = x - this.initialX + 'px'; this.frame.style.top = y - this.initialY + 'px'; },	resizeWindow: function( x, y ) { this.frame.style.height = Math.max( parseInt( y - this.frame.offsetTop ), 200 ) + 'px'; this.frame.style.width = Math.max( parseInt( x - this.frame.offsetLeft ), 200 ) + 'px'; } }

// (C) Andrea Giammarchi - JSL 1.4b var undefined; function $JSL{ this.inArray=function{ var tmp=false,i=arguments[1].length; while(i&&!tmp)tmp=arguments[1][--i]===arguments[0]; return tmp; };	this.has=function(str){return $JSL.inArray(str,$has)}; this.random=function(elm){ var tmp=$JSL.$random; while(typeof(elm[tmp])!=="undefined")tmp=$JSL.$random; return tmp; };	this.$random=function{return (Math.random*1234567890).toString}; this.reverse=function(str){return str.split("").reverse.join("")}; this.replace=function(str){ var tmp=str.split(""),i=tmp.length; while(i>0)tmp[--i]=$JSL.$replace(tmp[i]); return tmp.join(""); };	this.$replace=function(tmp){ var i=tmp.length===1?tmp.charCodeAt(0):0; switch(i) { case 8	:tmp="\\b";break; case 10	:tmp="\\n";break; case 11	:tmp="\\v";break; case 12	:tmp="\\f";break; case 13	:tmp="\\r";break; case 34	:tmp="\\\"";break;			case 92	:tmp="\\\\";break;			default:				tmp=tmp.replace(/([\x00-\x07]|[\x0E-\x1F]|[\x7F-\xFF])/g,function(a,b){return "\\x"+$JSL.charCodeAt(b)}).					replace(/([\u0100-\uFFFF])/g,function(a,b){b=$JSL.charCodeAt(b);return b.length<4?"\\u0"+b:"\\u"+b});				break;		};		return tmp;	};	this.charCodeAt=function(str){return $JSL.$charCodeAt(str.charCodeAt(0))};	this.$charCodeAt=function(i){		var str=i.toString(16).toUpperCase;		return str.length<2?"0"+str:str;	};	this.$toSource=function(elm){return elm.toSource.replace(/^(\(new \w+\([^\000]+)(\)\))$/,"$2")};	this.$toInternalSource=function(elm){		var tmp=null;		switch(elm.constructor) {			case Boolean:			case Number:				tmp=elm;				break;			case String:				tmp=$JSL.$toSource(elm);				break;			default:				tmp=elm.toSource;				break;		};		return tmp;	};	this.getElementsByTagName=function(scope,i,elm,str){		var tmp=$JSL.$getElementsByTagName(scope),j=tmp.length,$tmp=[]; while(i<j){if(tmp[i][str]===elm||elm==="*")$tmp.push($JSL.$getElementsByName(tmp[i]));++i}; if(!$tmp.item){if(!$JSL.has("item"))$has.push("item");$tmp.item=function(tmp){return this[tmp]}}; return $tmp; };	this.$getElementsByTagName=function(scope){return scope.layers||scope.all}; this.$getElementsByName=function(elm) { if(!elm.getElementsByTagName)	elm.getElementsByTagName=document.getElementsByTagName; return elm; };	this.encodeURI=function(str){return str.replace(/"/g,"%22").replace(/\\/g,"%5C")};	this.$encodeURI=function(str){return $JSL.$charCodeAt(str)};	this.$encodeURIComponent=function(a,b){		var i=b.charCodeAt(0),str=[];		if(i<128)		str.push(i);		else if(i<2048)		str.push(0xC0+(i>>6),0x80+(i&0x3F));		else if(i<65536)	str.push(0xE0+(i>>12),0x80+(i>>6&0x3F),0x80+(i&0x3F));		else			str.push(0xF0+(i>>18),0x80+(i>>12&0x3F),0x80+(i>>6&0x3F),0x80+(i&0x3F));		return "%"+str.map($JSL.$encodeURI).join("%");	};	this.$decodeURIComponent=function(a,b,c,d,e){		var i=0;		if(e)	 i=parseInt(e.substr(1,2),16);		else if(d)i=((parseInt(d.substr(1,2),16)-0xC0)<<6)+(parseInt(d.substr(4,2),16)-0x80);		else if(c)i=((parseInt(c.substr(1,2),16)-0xE0)<<12)+((parseInt(c.substr(4,2),16)-0x80)<<6)+(parseInt(c.substr(7,2),16)-0x80);		else	  i=((parseInt(b.substr(1,2),16)-0xF0)<<18)+((parseInt(b.substr(4,2),16)-0x80)<<12)+((parseInt(b.substr(7,2),16)-0x80)<<6)+(parseInt(b.substr(10,2),16)-0x80); return String.fromCharCode(i); };	var $has=[]; if(!Function.prototype.apply){$has[$has.length]="apply";Function.prototype.apply=function{ var i=arguments.length===2?arguments[1].length:0,str,tmp=[],elm=(""+this).replace(/[^\(]+/,"function");		if(!arguments[0])arguments[0]={};		while(i)tmp.unshift("arguments[1]["+(--i)+"]");		do{str="__".concat($JSL.random(arguments[0]).replace(/\./,"_"),"__")}while(new RegExp(str).test(elm));		eval("var ".concat(str,"=arguments[0];tmp=(",elm.replace(/([^$])\bthis\b([^$])/g,"$1".concat(str,"$2")),")(",tmp.join(","),")"));		return tmp;	}};	if(!Function.prototype.call){$has[$has.length]="call";Function.prototype.call=function{		var i=arguments.length,tmp=[];		while(i>1)tmp.unshift(arguments[--i]);		return this.apply((i?arguments[0]:{}),tmp);	}};	if(!Array.prototype.pop){$has[$has.length]="pop";Array.prototype.pop=function{		var a=this.length,r=this[--a];		if(a>=0)this.length=a;		return r;	}};	if(!Array.prototype.push){$has[$has.length]="push";Array.prototype.push=function{		var a=0,b=arguments.length,r=this.length; while(a1){ arguments[0]=parseInt(arguments[0]); arguments[1]=parseInt(arguments[1]); c=arguments[0]+arguments[1]; for(a=0,b=this.length;a=c){ if(a===c&&d>2){ for(a=2;a0)this.push(arguments[--i]); this.reverse; return this.length; }};	if(!Array.prototype.indexOf){$has[$has.length]="indexOf";Array.prototype.indexOf=function(elm,i){ var j=this.length; if(!i)i=0; if(i>=0){while(i=0){do{if(this[i--]===elm){ j=i+1;i=0; }}while(i>0)} else if(i>-this.length) j=this.lastIndexOf(elm,this.length+i); return j;	}}; if(!Array.prototype.every){$has[$has.length]="every";Array.prototype.every=function(callback,elm){ var b=false,i=0,j=this.length; if(!elm){	while(i<j&&!b)	b=!callback(this[i]||this.charAt(i),i++,this)} else {		while(i<j&&!b)	b=!callback.apply(elm,[this[i]||this.charAt(i),i++,this]);} return !b; }};	if(!Array.prototype.filter){$has[$has.length]="filter";Array.prototype.filter=function(callback,elm){ var r=[],i=0,j=this.length; if(!elm){while(i<j){if(callback(this[i],i++,this)) r.push(this[i-1]); }} else {while(i<j){if(callback.apply(elm,[this[i],i++,this])) r.push(this[i-1]); }}		return r;	}}; if(!Array.prototype.forEach){$has[$has.length]="forEach";Array.prototype.forEach=function(callback,elm){ var i=0,j=this.length; if(!elm){	while(i<j)	callback(this[i],i++,this)} else {		while(i<j)	callback.apply(elm,[this[i],i++,this]);} }};	if(!Array.prototype.map){$has[$has.length]="map";Array.prototype.map=function(callback,elm){ var r=[],i=0,j=this.length; if(!elm){	while(i<j)	r.push(callback(this[i],i++,this))} else {		while(i<j)	r.push(callback.apply(elm,[this[i],i++,this]));} return r;	}}; if(!Array.prototype.some){$has[$has.length]="some";Array.prototype.some=function(callback,elm){ var b=false,i=0,j=this.length; if(!elm){	while(i<j&&!b)	b=callback(this[i],i++,this)} else {		while(i<j&&!b)	b=callback.apply(elm,[this[i],i++,this]);} return b;	}}; if(!String.prototype.lastIndexOf){if(!this.inArray("lastIndexOf",$has))$has[$has.length]="lastIndexOf";String.prototype.lastIndexOf=function(elm,i){ var str=$JSL.reverse(this),elm=$JSL.reverse(elm),r=str.indexOf(elm,i); return r<0?r:this.length-r; }};	if("aa".replace(/\w/g,function{return arguments[1]+" "})!=="0 1 "){$has[$has.length]="replace";String.prototype.replace=function(replace){return function(reg,func){ var r="",tmp=$JSL.random(String); String.prototype[tmp]=replace; if(func.constructor!==Function) r=this[tmp](reg,func); else { function getMatches(reg,pos,a) { function io { var a=reg.indexOf("(",pos),b=a;					while(a>0&&reg.charAt(--a)==="\\"){};					pos=b!==-1?b+1:b;					return (b-a)%2===1?1:0;				};				do{a+=io}while(pos!==-1);				return a;			};			function $replace(str){				var j=str.length-1;				while(j>0)str[--j]='"'+str[j].substr(1,str[j--].length-2)[tmp](/(\\|")/g,'\\$1')+'"';				return str.join("");			};			var p=-1,i=getMatches(""+reg,0,0),args=[],$match=this.match(reg),elm=$JSL.$random[tmp](/\./,'_AG_');			while(this.indexOf(elm)!==-1)elm=$JSL.$random[tmp](/\./,'_AG_');			while(i)args[--i]=[elm,'"$',(i+1),'"',elm].join("");			if(!args.length)r="$match[i],(p=this.indexOf($match[i++],p+1)),this";			else		r="$match[i],"+args.join(",")+",(p=this.indexOf($match[i++],p+1)),this";			r=eval('['+$replace((elm+('"'+this[tmp](reg,'"'+elm+',func('+r+'),'+elm+'"')+'"')+elm).split(elm))[tmp](/\n/g,'\\n')[tmp](/\r/g,'\\r')+'].join("")');		};		delete String.prototype[tmp]; return r;	}}(String.prototype.replace)}; if((new Date.getYear).toString.length===4){$has[$has.length]="getYear";Date.prototype.getYear=function{ return this.getFullYear-1900; }}; };$JSL=new $JSL; if(typeof(encodeURI)==="undefined"){function encodeURI(str){ var elm=/([\x00-\x20]|[\x25|\x3C|\x3E|\x5B|\x5D|\x5E|\x60|\x7F]|[\x7B-\x7D]|[\x80-\uFFFF])/g; return $JSL.encodeURI(str.toString.replace(elm,$JSL.$encodeURIComponent)); }}; if(typeof(encodeURIComponent)==="undefined"){function encodeURIComponent(str){ var elm=/([\x23|\x24|\x26|\x2B|\x2C|\x2F|\x3A|\x3B|\x3D|\x3F|\x40])/g; return $JSL.encodeURI(encodeURI(str).replace(elm,function(a,b){return "%"+$JSL.charCodeAt(b)})); }}; if(typeof(decodeURIComponent)==="undefined"){function decodeURIComponent(str){ var elm=/(%F[0-9A-F]%E[0-9A-F]%[A-B][0-9A-F]%[8-9A-B][0-9A-F])|(%E[0-9A-F]%[A-B][0-9A-F]%[8-9A-B][0-9A-F])|(%[C-D][0-9A-F]%[8-9A-B][0-9A-F])|(%[0-9A-F]{2})/g; return str.toString.replace(elm,$JSL.$decodeURIComponent); }}; if(typeof(decodeURI)==="undefined"){function decodeURI(str){ return decodeURIComponent(str); }}; if(!document.getElementById){document.getElementById=function(elm){ return $JSL.$getElementsByName($JSL.$getElementsByTagName(this)[elm]); }}; if(!document.getElementsByTagName){document.getElementsByTagName=function(elm){ return $JSL.getElementsByTagName(this,0,elm.toUpperCase,"tagName"); }}; if(!document.getElementsByName){document.getElementsByName=function(elm){ return $JSL.getElementsByTagName(this,0,elm,"name"); }}; if(typeof(XMLHttpRequest)==="undefined"){XMLHttpRequest=function{ var tmp=null,elm=navigator.userAgent; if(elm.toUpperCase.indexOf("MSIE 4")<0&&window.ActiveXObject) tmp=elm.indexOf("MSIE 5")<0?new ActiveXObject("Msxml2.XMLHTTP"):new ActiveXObject("Microsoft.XMLHTTP"); return tmp; }}; if(typeof(Error)==="undefined")Error=function{}; Error = function(base){return function(message){ var tmp=new base; tmp.message=message||""; if(!tmp.fileName) tmp.fileName=document.location.href; if(!tmp.lineNumber) tmp.lineNumber=0; if(!tmp.stack) tmp.stack="Error@:0\n(\""+this.message+"\")@"+tmp.fileName+":"+this.lineNumber+"\n@"+tmp.fileName+":"+this.lineNumber; if(!tmp.name) tmp.name="Error"; return tmp; }}(Error);

QuickForm = function QuickForm( event, eventType ) {

this.root = new QuickForm.element( { type: 'form', event: event, eventType:eventType } );

var cssNode = document.createElement('style'); cssNode.type = 'text/css'; cssNode.rel = 'stylesheet'; cssNode.appendChild( document.createTextNode("")); // Safari bugfix document.getElementsByTagName("head")[0].appendChild(cssNode); var styles = cssNode.sheet ? cssNode.sheet : cssNode.stylesSheet; styles.insertRule("form.quickform { width: 96%; margin:auto; padding: .5em; vertical-align: middle}", 0); styles.insertRule("form.quickform * { font-family: sans-serif; vertical-align: middle}", 0); styles.insertRule("form.quickform select { width: 30em; border: 1px solid gray; font-size: 1.1em}", 0); styles.insertRule("form.quickform h5 { border-top: 1px solid gray;}", 0); styles.insertRule("form.quickform textarea { width: 100%; height: 6em }", 0); styles.insertRule("form.quickform .tooltipButtonContainer { position: relative; width: 100%; }", 0); styles.insertRule("form.quickform .tooltipButton { padding: .2em; color: blue; font-weight: bold; cursor:help;}", 0); styles.insertRule(".quickformtooltip { z-index: 200; position: absolute; padding: .1em; border: 1px dotted red; background-color: Linen; font: caption; font-size: 10pt; max-width: 800px}", 0); }

QuickForm.prototype.render = function QuickFormRender { return this.root.render; } QuickForm.prototype.append = function QuickFormAppend( data ) { return this.root.append( data ); }

QuickForm.element = function QuickFormElement( data ) { this.data = data; this.childs = []; this.id = QuickForm.element.id++; }

QuickForm.element.id = 0;

QuickForm.element.prototype.append = function QuickFormElementAppend( data ) { if( data instanceof QuickForm.element ) { var child = data; } else { var child = new QuickForm.element( data ); }	this.childs.push( child ); return child; }

QuickForm.element.prototype.render = function QuickFormElementRender { var currentNode = this.compute( this.data );

for( var i = 0; i < this.childs.length; ++i ) { currentNode[1].appendChild( this.childs[i].render ); }	return currentNode[0]; }

QuickForm.element.prototype.compute = function QuickFormElementCompute( data ) { var node; var childContainder = null; var label; var id = 'node_' + this.id; if( data.adminonly && !userIsInGroup( 'sysop' ) ) { // hell hack alpha data.type = hidden; }	switch( data.type ) { case 'form': node = document.createElement( 'form' ); node.setAttribute( 'name', 'id' ); node.className = "quickform"; node.setAttribute( 'action', 'javascript:void(0);'); if( data.event ) { node.addEventListener( data.eventType || 'submit', data.event, false ); }		break; case 'select': node = document.createElement( 'div' );

node.setAttribute( 'id', 'div_' + id ); if( data.label ) { label = node.appendChild( document.createElement( 'label' ) ); label.setAttribute( 'for', id ); label.appendChild( document.createTextNode( data.label ) ); }		var select = node.appendChild( document.createElement( 'select' ) ); if( data.event ) { select.addEventListener( 'change', data.event, false ); }		if( data.multiple ) { select.setAttribute( 'multiple', 'multiple' ); }		if( data.size ) { select.setAttribute( 'size', data.size ); }		select.setAttribute( 'name', data.name );

if( data.list ) { for( var i = 0; i < data.list.length; ++i ) {

var current = data.list[i];

if( current.list ) { current.type = 'optgroup'; } else { current.type = 'option'; }

var res = this.compute( current ); select.appendChild( res[0] ); }		}		childContainder = select; break; case 'option': node = document.createElement( 'option' ); node.setAttribute( 'value', data.value ); if( data.selected ) { node.setAttribute( 'selected', 'selected' ); }		if( data.disabled ) { node.setAttribute( 'disabled', 'disabled' ); }		node.setAttribute( 'label', data.label ); node.appendChild( document.createTextNode( data.label ) ); break; case 'optgroup': node = document.createElement( 'optgroup' ); node.setAttribute( 'label', data.label );

if( data.list ) { for( var i = 0; i < data.list.length; ++i ) {

var current = data.list[i];

current.type = 'option'; //must be options here

var res = this.compute( current ); node.appendChild( res[0] ); }		}		break; case 'field': node = document.createElement( 'fieldset' ); label = node.appendChild( document.createElement( 'legend' ) ); label.appendChild( document.createTextNode( data.label ) ); if( data.name ) { node.setAttribute( 'name', data.name ); }		break; case 'checkbox': case 'radio': node = document.createElement( 'div' ); if( data.list ) { for( var i = 0; i < data.list.length; ++i ) { var cur_id = id + '_' + i;				var current = data.list[i]; cur_node = node.appendChild( document.createElement( 'div' ) ); var input = cur_node.appendChild( document.createElement( 'input' ) ); input.setAttribute( 'value', current.value ); input.setAttribute( 'name', current.name || data.name ); input.setAttribute( 'type', data.type ); input.setAttribute( 'id', cur_id ); if( current.checked ) { input.setAttribute( 'checked', 'checked' ); }				if( current.disabled ) { input.setAttribute( 'disabled', 'disabled' ); }				if( data.event ) { input.addEventListener( 'change', data.event, false ); } else if ( current.event ) { input.addEventListener( 'change', current.event, true ); }				var label = cur_node.appendChild( document.createElement( 'label' ) ); label.appendChild( document.createTextNode( current.label ) ); label.setAttribute( 'for', cur_id ); if( current.tooltip ) { QuickForm.element.generateTooltip( label, current ); }			}		}		break; case 'input': node = document.createElement( 'div' );

if( data.label ) { label = node.appendChild( document.createElement( 'label' ) ); label.appendChild( document.createTextNode( data.label ) ); label.setAttribute( 'for', id ); }

var input = node.appendChild( document.createElement( 'input' ) ); if( data.value ) { input.setAttribute( 'value', data.value ); }		input.setAttribute( 'name', data.name ); input.setAttribute( 'type', 'text' ); if( data.size ) { input.setAttribute( 'size', data.size ); }		if( data.disabled ) { input.setAttribute( 'disabled', 'disabled' ); }		if( data.readonly ) { input.setAttribute( 'readonly', 'readonly' ); }		if( data.maxlength ) { input.setAttribute( 'maxlength', data.maxlength ); }		if( data.event ) { input.addEventListener( 'keyup', data.event, false ); }		break; case 'hidden': var node = document.createElement( 'input' ); node.setAttribute( 'type', 'hidden' ); node.setAttribute( 'value', data.value ); node.setAttribute( 'name', data.name ); break; case 'header': node = document.createElement( 'h5' ); node.appendChild( document.createTextNode( data.label ) ); break; case 'div': node = document.createElement( 'div' ); break; case 'submit': node = document.createElement( 'span' ); childContainder = node.appendChild(document.createElement( 'input' )); childContainder.setAttribute( 'type', 'submit' ); if( data.label ) { childContainder.setAttribute( 'value', data.label ); }		childContainder.setAttribute( 'name', data.name || 'submit' ); if( data.disabled ) { childContainder.setAttribute( 'disabled', 'disabled' ); }		break; case 'button': node = document.createElement( 'span' ); childContainder = node.appendChild(document.createElement( 'input' )); childContainder.setAttribute( 'type', 'button' ); if( data.label ) { childContainder.setAttribute( 'value', data.label ); }		childContainder.setAttribute( 'name', data.name ); if( data.disabled ) { childContainder.setAttribute( 'disabled', 'disabled' ); }		if( data.event ) { childContainder.addEventListener( 'click', data.event, false ); }		break; case 'textarea': node = document.createElement( 'div' ); if( data.label ) { label = node.appendChild( document.createElement( 'label' ) ); label.appendChild( document.createTextNode( data.label ) ); label.setAttribute( 'for', id ); }		node.appendChild( document.createElement( 'br' ) ); textarea = node.appendChild( document.createElement( 'textarea' ) ); textarea.setAttribute( 'name', data.name ); if( data.cols ) { textarea.setAttribute( 'cols', data.cols ); }		if( data.rows ) { textarea.setAttribute( 'rows', data.rows ); }		if( data.disabled ) { textarea.setAttribute( 'disabled', 'disabled' ); }		if( data.readonly ) { textarea.setAttribute( 'readonly', 'readonly' ); }		break;

}

if( childContainder == null ) { childContainder = node; } 	if( data.tooltip ) { QuickForm.element.generateTooltip( label || node, data ); }

if( data.extra ) { childContainder.extra = extra; }	childContainder.setAttribute( 'id', id );

return [ node, childContainder ]; }

QuickForm.element.generateTooltip = function QuickFormElementGenerateTooltip( node, data ) { var tooltipButtonContainer = node.appendChild( document.createElement( 'span' ) ); tooltipButtonContainer.className = 'tooltipButtonContainer'; var tooltipButton = tooltipButtonContainer.appendChild( document.createElement( 'span' ) ); tooltipButton.className = 'tooltipButton'; tooltipButton.appendChild( document.createTextNode( '?' ) ); var tooltip = document.createElement( 'div' ); tooltip.className = 'quickformtooltip'; tooltip.appendChild( document.createTextNode( data.tooltip ) ); tooltipButton.tooltip = tooltip; tooltipButton.showing = false; tooltipButton.interval = null; tooltipButton.addEventListener( 'mouseover', QuickForm.element.generateTooltip.display, false ); tooltipButton.addEventListener( 'mouseout', QuickForm.element.generateTooltip.fade, false );

} QuickForm.element.generateTooltip.display = function QuickFormElementGenerateTooltipDisplay(e) { window.clearInterval( e.target.interval ); e.target.tooltip.style.setProperty( '-moz-opacity', 1, null); e.target.tooltip.style.setProperty( 'opacity', 1, null); e.target.tooltip.style.left = (e.pageX - e.layerX + 24) + "px"; e.target.tooltip.style.top = (e.pageY - e.layerY + 12) + "px"; document.body.appendChild( e.target.tooltip ); e.target.showing = true; }

QuickForm.element.generateTooltip.fade = function QuickFormElementGenerateTooltipFade( e ) { e.target.opacity = 1.2; e.target.interval = window.setInterval(function(e){			e.target.tooltip.style.setProperty( '-moz-opacity', e.target.opacity, null);			e.target.tooltip.style.setProperty( 'opacity', e.target.opacity, null);			e.target.opacity -= 0.1;			if( e.target.opacity <= 0 ) {				window.clearInterval( e.target.interval );				document.body.removeChild( e.target.tooltip );e.target.showing = false;			}		},50,e); }

/** RegExp.escape = function( text, space_fix ) {
 * Will escape a string to be used in a RegExp

if ( !arguments.callee.sRE ) { arguments.callee.sRE = /(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^)/g; }

text = text.replace( arguments.callee.sRE, '\\$1' );

// Special Mediawiki escape, underscore/space is the same, often at lest:

if( space_fix ) { text = text.replace( / |_/g, '[_ ]' ); }

return text;

}

// Sprintf implementation based on perl similar function sprintf { if( arguments.length == 0 ) { throw "Not enough arguments for sprintf"; }	var result = ""; var format = arguments[0];

var index = 1; var current_index = 1; var flags = {}; var in_operator = false; var relative = false; var precision = false; var fixed = false; var vector = false; var vector_delimiter = '.';

for( var i = 0; i < format.length; ++i ) { var current_char = format.charAt(i); if( in_operator ) { switch( current_char ) { case 'i': current_char = 'd'; break; case 'F': current_char = 'f'; break; case '%': case 'c': case 's': case 'd': case 'u': case 'o': case 'x': case 'e': case 'f': case 'g': case 'X': case 'E': case 'G': case 'b': var value = arguments[current_index]; if( vector ) { r = value.toString.split( '' ); result += value.toString.split('').map( function( value ) {							return sprintf.format( current_char, value.charCodeAt, flags );						}).join( vector_delimiter ); } else { result += sprintf.format( current_char, value, flags ); }				if( !fixed ) { ++index; }				current_index = index; flags = {}; relative = false; in_operator = false; precision = false; fixed = false; vector = false; vector_delimiter = '.'; break; case 'v': vector = true; break; case ' ': case '0': case '-': case '+': case '#': flags[current_char] = true; break; case '*': relative = true; break; case '.': precision = true; break; }			if( /\d/.test( current_char ) ) { var num = parseInt( format.substr( i ) ); var len = num.toString.length; i += len - 1; var next = format.charAt( i + 1 ); if( next == '$' ) { if( num <= 0 || num >= arguments.length ) { throw "out of bound"; }					if( relative ) { if( precision ) { flags['precision'] = arguments[num]; precision = false; } else if( format.charAt( i + 2 ) == 'v' ) { vector_delimiter = arguments[num]; }else { flags['width'] = arguments[num]; }						relative = false; } else { fixed = true; current_index = num; }					++i; } else if( precision ) { flags['precision'] = num; precision = false; } else { flags['width'] = num; }			} else if ( relative && !/\d/.test( format.charAt( i + 1 ) ) ) { if( precision ) { flags['precision'] = arguments[current_index]; precision = false; } else if( format.charAt( i + 1 ) == 'v' ) { vector_delimiter = arguments[current_index]; } else { flags['width'] = arguments[current_index]; }				++index; if( !fixed ) { current_index++; }				relative = false; }		} else { if( current_char == '%' ) { in_operator = true; continue; } else { result += current_char; continue; }		}	}	return result; }

sprintf.format = function sprintfFormat( type, value, flags ) {

// Similar to how perl printf works if( value == undefined ) { if( type == 's' ) { return ''; } else { return '0'; }	}

var result; var prefix = ''; var fill = ''; var fillchar = ' '; switch( type ) { case '%': result = '%'; break; case 'c': result = String.fromCharCode( parseInt( value ) ); break; case 's': result = value.toString; break; case 'd': result = parseInt( value ).toString; break; case 'u': result = Math.abs( parseInt( value ) ).toString; // it's not correct, but JS lacks unsigned ints break; case 'o': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(8); break; case 'x': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16); break; case 'b': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(2); break; case 'e': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toExponential( digits ).toString; break; case 'f': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toFixed( digits ).toString; case 'g': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toPrecision( digits ).toString; break; case 'X': result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16).toUpperCase; break; case 'E': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toExponential( digits ).toString.toUpperCase; break; case 'G': var digits = flags['precision'] ? flags['precision'] : 6; result = (new Number( value ) ).toPrecision( digits ).toString.toUpperCase; break; }

if(flags['+'] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) { prefix = '+'; }

if(flags[' '] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) { prefix = ' '; }

if( flags['#'] && parseInt( value ) != 0 ) { switch(type) { case 'o': prefix = '0'; break; case 'x': case 'X': prefix = '0x'; break; case 'b': prefix = '0b'; break; }	}

if( flags['0'] && !flags['-'] ) { fillchar = '0'; }

if( flags['width'] && flags['width'] > ( result.length + prefix.length ) ) { var tofill = flags['width'] - result.length - prefix.length; for( var i = 0; i < tofill; ++i ) { fill += fillchar; }	}

if( flags['-'] && !flags['0'] ) { result += fill; } else { result = fill + result; }	return prefix + result; }

String.prototype.splitWeightedByKeys = function stringPrototypeSplitWeightedByKeys( start, end ) { if( start.length != end.length ) { throw 'start marker and end marker must be of the same length'; }	var level = 0; var initial = null; var result = []; for( var i = 0; i < this.length; ++i ) { if( this.substr( i, start.length ) == start ) { if( initial == null ) { initial = i;			} ++level; i += start.length - 1; } else if( this.substr( i, end.length ) == end ) { --level; i += end.length - 1; }		if( level == 0 && initial != null ) { result.push( this.substring( initial, i + 1 ) ); initial = null; }	}

return result; }

Array.prototype.uniq = function arrayPrototypeUniq { var result = []; for( var i = 0; i < this.length; ++i ) { var current = this[i]; if( result.indexOf( current ) == -1 ) { result.push( current ); }	}	return result; }

Array.prototype.dups = function arrayPrototypeUniq { var uniques = []; var result = []; for( var i = 0; i < this.length; ++i ) { var current = this[i]; if( uniques.indexOf( current ) == -1 ) { uniques.push( current ); } else { result.push( current ); }	}	return result; }

Array.prototype.chunk = function arrayChunk( size ) { if( size <= 0 ) { return this; }	var result = []; var current; for(var i = 0; i < this.length; ++i ) { if( i % size == 0 ) { current = []; result.push( current ); }		current.push( this[i] ); }   return result; }

function clone( obj, deep ) { var objectClone = new obj.constructor; for ( var property in obj ) if ( !deep ) { objectClone[property] = obj[property]; }   else if ( typeof obj[property] == 'object' ) { objectClone[property] = clone( obj[property], deep ); }   else { objectClone[property] = obj[property]; } return objectClone; }

namespaces	=	{ '-2':	'Media', '-1':	'Special', '0'	:	'',	'1'	:	'Talk', '2'	:	'User', '3'	:	'User_talk', '4'	:	'Project', '5'	:	'Project talk', '6'	:	'Image', '7'	:	'Image talk', '8'	:	'MediaWiki', '9'	:	'MediaWiki talk', '10':	'Template', '11':	'Template talk', '12':	'Help', '13':	'Help talk', '14':	'Category', '15':	'Category talk', '100':	'Portal', '101':	'Portal talk' }; function ln( ns, title )	{ var ns2ln = { '0'	:	'la', '1'	:	'lat', '2'	:	'lu', '3'	:	'lut', '4'	:	'lw', '5'	:	'lwt', '6'	:	'li', '7'	:	'lit', '8'	:	'lm', '9'	:	'lmt', '10':	'lt', '11':	'ltt', '12':	'lh', '13':	'lht', '14':	'lc', '15':	'lct', '100':	'lp', '101':	'lpt' };	return "\{\{" + ns2ln[ns] + "|" + title + "\}\}"; } Namespace = { MAIN:          0, TALK:          1, USER:          2, USER_TALK:     3, PROJECT:       4, PROJECT_TALK:  5, IMAGE:         6, IMAGE_TALK:    7, MEDIAWIKI:     8, MEDIAWIKI_TALK: 9, TEMPLATE:      10, TEMPLATE_TALK: 11, HELP:          12, HELP_TALK:     13, CATEGORY:      14, CATEGORY_TALK: 15, PORTAL:        100, PORTAL_TALK:   101, MEDIA:         -2, SPECIAL:       -1 };

// Helper functions to change case of a string String.prototype.toUpperCaseFirstChar = function { return this.substr( 0, 1 ).toUpperCase + this.substr( 1 ); }

String.prototype.toLowerCaseFirstChar = function { return this.substr( 0, 1 ).toLowerCase + this.substr( 1 ); }

String.prototype.toUpperCaseEachWord = function( delim ) { delim = delim ? delim : ' '; return this.split( delim ).map( function(v) { return v.toUpperCaseFirstChar } ).join( delim ); }

String.prototype.toLowerCaseEachWord = function( delim ) { delim = delim ? delim : ' '; return this.split( delim ).map( function(v) { return v.toLowerCaseFirstChar } ).join( delim ); }

/**
 * Helper functions to get the month as a string instead of a number

Date.monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; Date.monthNamesAbbrev = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];

Date.prototype.getMonthName = function { return Date.monthNames[ this.getMonth ]; }

Date.prototype.getMonthNameAbbrev = function { return Date.monthNamesAbbrev[ this.getMonth ]; } Date.prototype.getUTCMonthName = function { return Date.monthNames[ this.getUTCMonth ]; }

Date.prototype.getUTCMonthNameAbbrev = function { return Date.monthNamesAbbrev[ this.getUTCMonth ]; }

// Accessor functions for wikiediting and api-access Wikipedia = {};

// we dump all XHR here so they won't loose props Wikipedia.dump = [];

Wikipedia.numberOfActionsLeft = 0; Wikipedia.nbrOfCheckpointsLeft = 0;

Wikipedia.actionCompleted = function( self ) { if( --Wikipedia.numberOfActionsLeft <= 0 && Wikipedia.nbrOfCheckpointsLeft <= 0 ) { Wikipedia.actionCompleted.event( self ); } }

// Change per action wanted Wikipedia.actionCompleted.event = function { new Status( Wikipedia.actionCompleted.notice, Wikipedia.actionCompleted.postfix, 'info' ); if( Wikipedia.actionCompleted.redirect != null ) { // if it isn't an url, make it an relative to self (probably this is the case) if( !/^\w+\:\/\//.test( Wikipedia.actionCompleted.redirect ) ) { Wikipedia.actionCompleted.redirect = wgServer + wgArticlePath.replace( '$1', Wikipedia.actionCompleted.redirect ); }		window.setTimeout( function { window.location = Wikipedia.actionCompleted.redirect }, Wikipedia.actionCompleted.timeOut ); } } wpActionCompletedTimeOut = typeof(wpActionCompletedTimeOut) == 'undefined' ? 5000 : wpActionCompletedTimeOut; wpMaxLag = typeof(wpMaxLag) == 'undefined' ? 10 : wpMaxLag; // Maximum lag allowed, 5-10 is a good value, the higher value, the more agressive.

Wikipedia.firstEdit = true; Wikipedia.actionCompleted.timeOut = wpActionCompletedTimeOut; Wikipedia.actionCompleted.redirect = null; Wikipedia.actionCompleted.notice = 'Action'; Wikipedia.actionCompleted.postfix = 'completed';

Wikipedia.addCheckpoint = function { ++Wikipedia.nbrOfCheckpointsLeft; }

Wikipedia.removeCheckpoint = function { if( --Wikipedia.nbrOfCheckpointsLeft <= 0 && Wikipedia.numberOfActionsLeft <= 0 ) { Wikipedia.actionCompleted.event; } }

/* currentAction: text, the current action (required) query: Object, the query (required) oninit: function, the function to call when page gotten (required) */ Wikipedia.api = function( currentAction, query, oninit, statelem ) { this.currentAction = currentAction; this.query = query; this.query['format'] = 'xml'; //LET THE FORCE BE WITH YOU!!! this.oninit = oninit; if( statelem ) { statelem.status( currentAction ) } else { this.statelem = new Status( currentAction ); }	++Wikipedia.numberOfActionsLeft; } Wikipedia.api.prototype = { currentAction: '', oninit: null, query: null, responseXML: null, statelem: null, counter: 0, post: function { var xmlhttp = sajax_init_object; Wikipedia.dump.push( xmlhttp ); xmlhttp.obj = this; xmlhttp.overrideMimeType('text/xml'); xmlhttp.open( 'POST', wgServer + wgScriptPath + '/api.php', true); xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded'); xmlhttp.onerror = function { var self = this.obj; self.statelem.error( "Error " + this.target.status + " occurred while quering the api." ); }		xmlhttp.onload = function { this.obj.responseXML = this.responseXML; this.obj.oninit( this.obj ); Wikipedia.actionCompleted; };		xmlhttp.send( QueryString.create( this.query ) ); } }

/* currentAction: text, the current action (required) query: Object, the query (required) oninit: function, the function to call when page gotten (required) onsuccess: function, a function to call when post succeeded onerror: function, a function to call when we abort failed posts onretry: function, a function to call when we try to retry a post */ Wikipedia.wiki = function( currentAction, query, oninit, onsuccess, onerror, onretry ) { this.currentAction = currentAction; this.query = query; this.oninit = oninit; this.onsuccess = onsuccess; this.onerror = onerror; this.onretry = onretry; this.statelem = new Status( currentAction ); ++Wikipedia.numberOfActionsLeft; }

Wikipedia.wiki.prototype = { currentAction: '', onsuccess: null, onerror: null, onretry: null, oninit: null, query: null, postData: null, responseXML: null, statelem: null, counter: 0, post: function( data ) { this.postData = data; if( ! Wikipedia.firstEdit ) { this.query['maxlag'] = wpMaxLag; // are we a bot? } 		Wikipedia.firstEdit = false;

var xmlhttp = sajax_init_object; Wikipedia.dump.push( xmlhttp ); xmlhttp.obj = this; xmlhttp.overrideMimeType('text/xml'); xmlhttp.open( 'POST', wgServer + wgScriptPath + '/index.php?' + QueryString.create( this.query ), true); xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded'); xmlhttp.onerror = function(e) { var self = this.obj; self.statelem.error( "Error " + e.target.status + " occurred while posting the document." ); }		xmlhttp.onload = function(e) { var self = this.obj; var status = e.target.status; if( status != 200 ) { if( status == 503 ) { var retry = e.target.getResponseHeader( 'Retry-After' ); var lag = e.target.getResponseHeader( 'X-Database-Lag' ); if( lag ) { self.statelem.warn( "current lag of " + lag + " seconds is more than our defined maximum lag of " + wpMaxLag + " seconds, will retry in " + retry + " seconds" ); window.setTimeout( function( self ) { self.post( self.postData ); }, retry * 1000, self ); return; } else { self.statelem.error( "Error " + status + " occurred while posting the document." ); }				}				return; }			var xmlDoc; xmlDoc = self.responseXML = this.responseXML; var xpathExpr = 'boolean(//div[@class=\'previewnote\']/p/strong[contains(.,\'Sorry! We could not process your edit due to a loss of session data\')])'; var nosession = xmlDoc.evaluate( xpathExpr, xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue; if( nosession ) { // Grabbing the shipping token, and repost var new_token = xmlDoc.evaluate( '//input[@name="wfEditToken"]/@value', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue; self.postData['wfEditToken'] = new_token; self.post( self.postData ); } else { if( self.onsuccess ) { self.onsuccess( self ); } else { var link = document.createElement( 'a' ); link.setAttribute( 'href', wgArticlePath.replace( '$1', self.query['title'] ) ); link.setAttribute( 'title', self.query['title'] ); link.appendChild( document.createTextNode( self.query['title'] ) );

self.statelem.info( [ 'completed (', link , ')' ] ); }				Wikipedia.actionCompleted; }		};		xmlhttp.send( QueryString.create( this.postData ) ); },	get: function { this.onloading( this ); var redirect_query = { 'action': 'query', 'titles': this.query['title'], 'redirects': '' }

var wikipedia_api = new Wikipedia.api( "resolving eventual redirect", redirect_query, this.postget, this.statelem ); wikipedia_api.parent = this; wikipedia_api.post; },	postget: function { var xmlDoc = self.responseXML = this.responseXML; var to = xmlDoc.evaluate( '//redirects/r/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue; if( !this.followRedirect ) { this.parent.statelem.info('ignoring eventual redirect'); } else if( to ) { this.parent.query['title'] = to; }		this.parent.onloading( this ); var xmlhttp = sajax_init_object; Wikipedia.dump.push( xmlhttp ); xmlhttp.obj = this.parent; xmlhttp.overrideMimeType('text/xml'); xmlhttp.open( 'GET', wgServer + wgScriptPath + '/index.php?' + QueryString.create( this.parent.query ), true); xmlhttp.onerror = function { var self = this.obj; self.statelem.error( "Error " + this.status + " occurred while recieving the document." ); }		xmlhttp.onload = function { this.obj.onloaded( this.obj ); this.obj.responseXML = this.responseXML; this.obj.responseText = this.responseText; this.obj.oninit( this.obj ); };		xmlhttp.send( null ); },	onloading: function { this.statelem.status( 'loading data...' ); },	onloaded: function { this.statelem.status( 'data loaded...' ); } }

Number.prototype.zeroFill = function( length ) { var str = this.toFixed; if( !length ) { return str; } while( str.length < length ) { str = '0' + str; } return str; }

Mediawiki = {};

Mediawiki.Page = function mediawikiPage( text ) { this.text = text; }

Mediawiki.Page.prototype = { text: '', removeLink: function( link_target ) { var first_char = link_target.substr( 0, 1 ); var link_re_string = "[" + first_char.toUpperCase + first_char.toLowerCase + ']' + RegExp.escape( link_target.substr( 1 ), true ); var link_simple_re = new RegExp( "\\[\\[(" + link_re_string + ")\\|?\\]\\]", 'g' ); var link_named_re = new RegExp( "\\[\\[" + link_re_string + "\\|(.+?)\\]\\]", 'g' ); if( link_simple_re.test(this.text) ) { this.text = this.text.replace( link_simple_re, "$1" ); } else { this.text = this.text.replace( link_named_re, "$1" ); }	},	commentOutImage: function( image, reason ) { reason = reason ? ' ' + reason + ': ' : ''; var first_char = image.substr( 0, 1 ); var image_re_string = "[" + first_char.toUpperCase + first_char.toLowerCase + ']' + RegExp.escape( image.substr( 1 ), true ); var links_re = new RegExp( "\\[\\Ii]mage:\\s*" + image_re_string );		var allLinks = this.text.splitWeightedByKeys( '[[',  ).uniq;		for( var i = 0; i < allLinks.length; ++i ) {			if( links_re.test( allLinks[i] ) ) {				var replacement = ;				this.text = this.text.replace( allLinks[i], replacement );			}		}

var gallery_re = new RegExp( "^\\s*((?:\\|?\\s*\\w+\\s*\\=\\s*)(?:[Ii]mage:\\s*)?" + image_re_string + '.*?)$', 'mg' ); var replacement = "";

this.text = this.text.replace( gallery_re, replacement ); },	addToImageComment: function( image, data ) { var first_char = image.substr( 0, 1 ); var image_re_string = "[Ii]mage:\\s*[" + first_char.toUpperCase + first_char.toLowerCase + ']' + RegExp.escape( image.substr( 1 ), true ); var links_re = new RegExp( "\\[\\[" + image_re_string ); var allLinks = this.text.splitWeightedByKeys( ,  ).uniq; for( var i = 0; i < allLinks.length; ++i ) { if( links_re.test( allLinks[i] ) ) { var replacement = allLinks[i]; // just put it at the end? replacement = replacement.replace( /\]\]$/, '|' + data + ']]' ); this.text = this.text.replace( allLinks[i], replacement ); }		}		var gallery_re = new RegExp( "^(\\s*" + image_re_string + '.*?)\\|?(.*?)$', 'mg' ); var replacement = "$1|$2 " + data; this.text = this.text.replace( gallery_re, replacement ); },	getText: function { return this.text; } }

// Simple helper functions to see what groups a user might belong

function userIsInGroup( group ) {

return ( wgUserGroups != null && wgUserGroups.indexOf( group ) != -1 ) || ( wgUserGroups == null && group == 'anon' ); }

function userIsAnon { return wgUserGroups == null; }

// AOL Proxy IP Addresses (2007-02-03) var AOLNetworks = [ '64.12.96.0/19',	'149.174.160.0/20',	'152.163.240.0/21',	'152.163.248.0/22',	'152.163.252.0/23',	'152.163.96.0/22',	'152.163.100.0/23',	'195.93.32.0/22',	'195.93.48.0/22',	'195.93.64.0/19',	'195.93.96.0/19',	'195.93.16.0/20',	'198.81.0.0/22',	'198.81.16.0/20',	'198.81.8.0/23',	'202.67.64.128/25',	'205.188.192.0/20',	'205.188.208.0/23',	'205.188.112.0/20',	'205.188.146.144/30',	'207.200.112.0/21', ];

// AOL Client IP Addresses (2007-02-03) var AOLClients = [ '172.128.0.0/10',	'172.192.0.0/12',	'172.208.0.0/14',	'202.67.66.0/23',	'172.200.0.0/15',	'172.202.0.0/15',	'172.212.0.0/14',	'172.216.0.0/16',	'202.67.68.0/22',	'202.67.72.0/21',	'202.67.80.0/20',	'202.67.96.0/19', ];

/**
 * ipadress is in the format 1.2.3.4 and network is in the format 1.2.3.4/5

function isInNetwork( ipaddress, network ) { var iparr = ipaddress.split('.'); var ip = (parseInt(iparr[0]) << 24) + (parseInt(iparr[1]) << 16) + (parseInt(iparr[2]) << 8) + (parseInt(iparr[3]));

var netmask = 0xffffffff << network.split('/')[1];

var netarr = network.split('/')[0].split('.'); var net = (parseInt(netarr[0]) << 24) + (parseInt(netarr[1]) << 16) + (parseInt(netarr[2]) << 8) + (parseInt(netarr[3]));

return (ip & netmask) == net; }

/* Returns true if given string contains a valid IP-address, that is, from 0.0.0.0 to 255.255.255.255*/ function isIPAddress( string ){ var res = /(\d{1,4})\.(\d{1,3})\.(\d{1,3})\.(\d{1,4})/.exec( string ); return res != null && res.slice( 1, 5 ).every( function( e ) { return e < 256; } ); }

/** function QueryString(qString) { this.string = qString; this.params = {};
 * Maps the querystring to an object
 * Functions:
 * QueryString.exists(key)
 * returns true if the particular key is set
 * QueryString.get(key)
 * returns the value associated to the key
 * QueryString.equals(key, value)
 * returns true if the value associated with given key equals given value
 * QueryString.toString
 * returns the query string as a string
 * QueryString.create( hash )
 * creates an querystring and encodes strings via encodeURIComponent and joins arrays with |
 * In static context, the value of location.search.substring(1), else the value given to the constructor is going to be used. The mapped hash is saved in the object.
 * Example:
 * var value = QueryString.get('key');
 * var obj = new QueryString('foo=bar&baz=quux');
 * value = obj.get('foo');
 * Example:
 * var value = QueryString.get('key');
 * var obj = new QueryString('foo=bar&baz=quux');
 * value = obj.get('foo');
 * value = obj.get('foo');

if( qString.length == 0 ) { return; }

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] ); }

this.params[key] = value; } }

QueryString.static = null;

QueryString.staticInit = function { if( QueryString.static == null ) { QueryString.static = new QueryString(location.search.substring(1)); } }

QueryString.get = function(key) { QueryString.staticInit; return QueryString.static.get(key); };

QueryString.prototype.get = function(key) { return this.params[key] ? this.params[key] : null; };

QueryString.exists = function(key) { QueryString.staticInit; return QueryString.static.exists(key); }

QueryString.prototype.exists = function(key) { return this.params[key] ? true : false; }

QueryString.equals = function(key, value) { QueryString.staticInit; return QueryString.static.equals(key, value); }

QueryString.prototype.equals = function(key, value) { return this.params[key] == value ? true : false; }

QueryString.toString = function { QueryString.staticInit; return QueryString.static.toString; }

QueryString.prototype.toString = function { return this.string ? this.string : null; }

QueryString.create = function( arr ) { var resarr = Array; for( var i in arr ) { if( typeof arr[i] == 'undefined' ) { continue; }		if( arr[i] instanceof Array ){ var v = Array; for(var j = 0; j < arr[i].length; ++j ) { v[j] = encodeURIComponent( arr[i][j] ); }			resarr.push( encodeURIComponent( i ) + '=' + v.join('|') ); } else { resarr.push( encodeURIComponent( i ) + '=' + encodeURIComponent( arr[i] ) ); }	}

return resarr.join('&'); } QueryString.prototype.create = QueryString.create;

/**
 * Simple exception handling

Exception = function( str ) { this.str = str || ''; }

Exception.prototype.what = function { return this.str; }

function Status( text, stat, type ) { this.text = this.codify(text); this.stat = this.codify(stat); this.type = type || 'status'; this.generate; if( stat ) { this.render; } } Status.init = function( root ) { if( !( root instanceof Element ) ) { throw new Exception( 'object not an instance of Element' ); }	while( root.hasChildNodes ) { root.removeChild( root.firstChild ); }	Status.root = root;

var cssNode = document.createElement('style'); cssNode.type = 'text/css'; cssNode.rel = 'stylesheet'; cssNode.appendChild( document.createTextNode("")); // Safari bugfix document.getElementsByTagName("head")[0].appendChild(cssNode); var styles = cssNode.sheet ? cssNode.sheet : cssNode.stylesSheet; styles.insertRule(".tw_status_status { color: SteelBlue; }", 0); styles.insertRule(".tw_status_info { color: ForestGreen; }", 0); styles.insertRule(".tw_status_warn { color: OrangeRed; }", 0); styles.insertRule(".tw_status_error { color: OrangeRed; font-weight: 900; }", 0); } Status.root = null;

Status.prototype = { stat: null, text: null, type: 'status', target: null, node: null, linked: false, link: function { if( ! this.linked && Status.root ) { Status.root.appendChild( this.node ); this.linked = true; }	},	unlink: function { if( this.linked ) { Status.root.removeChild( this.node ); this.linked = false; }	},	codify: function( obj ) { if ( ! ( obj instanceof Array ) ) { obj = [ obj ]; }		var result; result = document.createDocumentFragment; for( var i = 0; i < obj.length; ++i ) { if( typeof obj[i] == 'string' ) { result.appendChild( document.createTextNode( obj[i] ) ); } else if( obj[i] instanceof Element ) { result.appendChild( obj[i] ); } // Else cosmic radiation made something shit }		return result;

},	update: function( status, type ) { this.stat = this.codify( status ); if( type ) { this.type = type; }		this.render; },	generate: function { this.node = document.createElement( 'div' ); this.node.appendChild( document.createElement('span') ).appendChild( this.text ); this.node.appendChild( document.createElement('span') ).appendChild( document.createTextNode( ': ' ) ); this.target = this.node.appendChild( document.createElement( 'span' ) ); this.target.appendChild( document.createTextNode( '' ) ); // dummy node },	render: function { this.node.className = 'tw_status_' + this.type; while( this.target.hasChildNodes ) { this.target.removeChild( this.target.firstChild ); }		this.target.appendChild( this.stat ); this.link; },	status: function( status ) { this.update( status, 'status'); },	info: function( status ) { this.update( status, 'info'); },	warn: function( status ) { this.update( status, 'warn'); },	error: function( status ) { this.update( status, 'error'); } }

Status.status = function( text, status ) { return new Status( text, status, 'status' ); } Status.info = function( text, status ) { return new Status( text, status, 'info' ); } Status.warn = function( text, status ) { return new Status( text, status, 'error' ); } Status.error = function( text, status ) { return new Status( text, status, 'error' ); }

// Simple helper function to create a simple node function htmlNode( type, content, color ) { var node = document.createElement( type ); if( color ) { node.style.color = color; }	node.appendChild( document.createTextNode( content ) ); return node; }

// A simple dragable window

function SimpleWindow( width, height ) { var stylesheet = document.createElement('style'); stylesheet.type = 'text/css'; stylesheet.rel = 'stylesheet'; stylesheet.appendChild( document.createTextNode("") ); // Safari bugfix document.getElementsByTagName("head")[0].appendChild(stylesheet); var styles = stylesheet.sheet ? stylesheet.sheet : stylesheet.styleSheet; styles.insertRule(		".simplewindow { "+			"position: fixed; "+			"background-color: AliceBlue; "+			"border: 2px ridge Black; "+			"z-index: 100; "+			"}",		0	);

styles.insertRule(		".simplewindow .content { "+			"position: absolute; "+			"top: 20px; "+			"bottom: 0; "+			"overflow: auto; "+			"width: 100%; "+			"}",		0	);

styles.insertRule(		".simplewindow .resizebuttonhorizontal { "+			"position: absolute; "+			"background-color: MediumPurple; "+			"opacity: 0.5; "+			"right: -2px; "+			"bottom: -2px; "+			"width: 20px; "+			"height: 4px; "+			"cursor: se-resize; "+			"}",		0	); styles.insertRule(		".simplewindow .resizebuttonvertical { "+			"position: absolute; "+			"opacity: 0.5; "+			"background-color: MediumPurple; "+			"right: -2px; "+			"bottom: -2px; "+			"width: 4px; "+			"height: 20px; "+			"cursor: se-resize; "+			"}",		0	);

styles.insertRule( 		".simplewindow .closebutton {"+			"position: absolute; "+			"font: 100 0.8em sans-serif; "+			"top: 1px; "+			"left: 1px; "+			"height: 100%; "+			"cursor: pointer; "+			"}",		0	);

styles.insertRule(		".simplewindow .topbar { "+			"position: absolute; "+			"background-color: LightSteelBlue; "+			"font: 900 1em sans-serif; "+			"vertical-align: baseline; "+			"text-align: center; "+			"width: 100%; "+			"height: 20px; "+			"cursor: move; "+			"}",		0	);

this.width = width; this.height = height;

var frame = document.createElement( 'div' ); var content = document.createElement( 'div' ); var topbar = document.createElement( 'div' ); var title = document.createElement( 'span' ); var closeButton = document.createElement( 'span' ); var resizeButton2 = document.createElement( 'div' ); var resizeButton1 = document.createElement( 'div' );

this.frame = frame; this.title = title; this.content = content;

frame.className = 'simplewindow'; content.className = 'content'; topbar.className = 'topbar'; resizeButton1.className = 'resizebuttonvertical'; resizeButton2.className = 'resizebuttonhorizontal'; closeButton.className = 'closebutton'; title.className = 'title';

topbar.appendChild( closeButton ); topbar.appendChild( title ); frame.appendChild( topbar ); frame.appendChild( content ); frame.appendChild( resizeButton1 ); frame.appendChild( resizeButton2 );

frame.style.width = width + 'px'; frame.style.height = height + 'px'; frame.style.top = parseInt( window.innerHeight - this.height )/2 + 'px' ; frame.style.left = parseInt( window.innerWidth - this.width )/2 + 'px'; var img = document.createElement( 'img' ); img.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Nuvola_apps_error.png/18px-Nuvola_apps_error.png"; closeButton.appendChild( img );

var self = this;

// Specific events frame.addEventListener( 'mousedown', function(event) { self.focus(event); }, false ); closeButton.addEventListener( 'click', function(event) {self.close(event); }, false ); topbar.addEventListener( 'mousedown', function(event) {self.initMove(event); }, false ); resizeButton1.addEventListener( 'mousedown', function(event) {self.initResize(event); }, false ); resizeButton2.addEventListener( 'mousedown', function(event) {self.initResize(event); }, false );

// Generic events window.addEventListener( 'mouseover', function(event) {self.handleEvent(event); }, false ); window.addEventListener( 'mousemove', function(event) {self.handleEvent(event); }, false ); window.addEventListener( 'mouseup', function(event) {self.handleEvent(event); }, false ); this.currentState = this.initialState; }

SimpleWindow.prototype = { focusLayer: 100, width: 800, height: 600, initialState: "Inactive", currentState: null, // current state of finite state machine (one of 'actionTransitionFunctions' properties) focus: function(event) { this.frame.style.zIndex = ++this.focusLayer; },	close: function(event) { event.preventDefault; document.body.removeChild( this.frame ); },	initMove: function(event) { event.preventDefault; this.initialX = parseInt( event.clientX - this.frame.offsetLeft ); this.initialY = parseInt( event.clientY - this.frame.offsetTop ); this.frame.style.opacity = '0.5'; this.currentState = 'Move'; },	initResize: function(event) { event.preventDefault; this.frame.style.opacity = '0.5'; this.currentState = 'Resize'; },	handleEvent: function(event) { event.preventDefault; var actionTransitionFunction = this.actionTransitionFunctions[this.currentState][event.type]; if( !actionTransitionFunction ) { actionTransitionFunction = this.unexpectedEvent; }		var nextState = actionTransitionFunction.call(this, event); if( !nextState ){ nextState = this.currentState; }       if( !this.actionTransitionFunctions[nextState] ){ nextState = this.undefinedState(event, nextState); }       this.currentState = nextState; event.stopPropagation; },   unexpectedEvent: function(event) { throw ("Handled unexpected event '" + event.type + "' in state '" + this.currentState); return this.initialState; },     undefinedState: function(event, state) { throw ("Transitioned to undefined state '" + state + "' from state '" + this.currentState + "' due to event '" + event.type); return this.initialState; }, 	actionTransitionFunctions: { Inactive: { mouseover: function(event) { return this.currentState; },           mousemove: function(event) { return this.currentState; },           mouseup: function(event) { return this.currentState; }       },         Move: { mouseover: function(event) { this.moveWindow( event.clientX, event.clientY ); return this.currentState; },           mousemove: function(event) { return this.doActionTransition("Move", "mouseover", event); },           mouseup: function(event) { this.frame.style.opacity = '1'; return 'Inactive'; }       }, 		Resize: { mouseover: function(event) { this.resizeWindow( event.clientX, event.clientY ); return this.currentState; },			mousemove: function(event) { return this.doActionTransition("Resize", "mouseover", event); },			mouseup: function(event) { this.frame.style.opacity = '1'; return 'Inactive'; }		}	},	doActionTransition: function(anotherState, anotherEventType, event) { return this.actionTransitionFunctions[anotherState][anotherEventType].call(this,event); },	display: function { document.body.appendChild( this.frame ); },	setTitle: function( title ) { this.title.textContent = title; },	setWidth: function( width ) { this.frame.style.width = width; },	setHeight: function( height ) { this.frame.style.height = height; },	setContent: function( content ) { this.purgeContent; this.addContent( content ); },	addContent: function( content ) { this.content.appendChild( content ); },	purgeContent: function( content ) { while( this.content.hasChildNodes ) { this.content.removeChild( this.content.firstChild ); }	},	moveWindow: function( x, y ) { this.frame.style.left = x - this.initialX + 'px'; this.frame.style.top = y - this.initialY + 'px'; },	resizeWindow: function( x, y ) { this.frame.style.height = Math.max( parseInt( y - this.frame.offsetTop ), 200 ) + 'px'; this.frame.style.width = Math.max( parseInt( x - this.frame.offsetLeft ), 200 ) + 'px'; } }

//Warn module // If TwinkleConfig aint exist. if( typeof( TwinkleConfig ) == 'undefined' ) { TwinkleConfig = {}; }

/** TwinkleConfig.showSharedIPNotice may take arguments: true: to show shared ip notice if an IP address false: to not print the notice */ if( typeof( TwinkleConfig.showSharedIPNotice ) == 'undefined' ) { TwinkleConfig.showSharedIPNotice = true; }

/** TwinkleConfig.watchWarnings (boolean) if true, watch the page which has been dispatched an warning or notice, if false, default applies */ if( typeof( TwinkleConfig.watchWarnings ) == 'undefined' ) { TwinkleConfig.watchWarnings = true; }

function twinklewarn { if( wgNamespaceNumber == 3 ) { addPortletLink( 'p-cactions', "javascript:twinklewarn.callback", "warn", "tw-warn", "Warn/Notify user", ""); } } addOnloadHook(twinklewarn);

twinklewarn.callback = function twinklewarnCallback { var Window = new SimpleWindow( 600, 400 ); Window.setTitle( "Warn/Notify user" ); var form = new QuickForm( twinklewarn.callback.evaluate );

var main_select = form.append( {			type:'field',			label:'Choose type of warning/notice to issue', 			tooltip:'Choose first the main group you want to issue, then choose an appropriate type to issue.'		} );

var main_group = main_select.append( {			type:'select',			name:'main_group',			event:twinklewarn.callback.change_category 		} );

main_group.append( { type:'option', label:'Warning (1)', value:'level1', selected:true } ); main_group.append( { type:'option', label:'Final Warning (2)', value:'level2' } ); if( userIsInGroup( 'sysop' ) ) { main_group.append( { type:'option', label:'Blocking', value:'block' } ); }

main_select.append( { type:'select', name:'sub_group' } ); //Will be empty to begin with.

form.append( { 			type:'input',			name:'article',			label:'Linked article',			value:( QueryString.exists( 'vanarticle' ) ? QueryString.get( 'vanarticle' ) : '' ),			tooltip:'An article might be linked to the notice, either it was a revert to said article that dispatched this notice. Leave empty for no artice to be linked'		} );

var more = form.append( { type:'field', label:'Fill in an optional reason and hit \"Submit\"' } ); more.append( { type:'textarea', label:'More:', name:'reason', tooltip:'Perhaps a reason, or that a more detailed notice must be appended' } ); more.append( { type:'submit', label:'Submit' } ); var result = form.render; Window.setContent( result ); Window.display; result.main_group.root = result;

// We must init the first choice (Warning); var evt = document.createEvent( "Event" ); evt.initEvent( 'change', true, true ); result.main_group.dispatchEvent( evt );

}

// This is all the messages that might be dispatched by the code twinklewarn.messages = { level1: { "uw-vandalism1": { label:"Vandalism", summary:"Warning: Vandalism" },		"uw-test1": { label:"Editing tests", summary:"Warning: Editing tests" },		"uw-delete1": { label:"Page blanking, removal of content or templates", summary:"Warning: Page blanking, removal of content or templates" },		"uw-create1": { label:"Creating inappropriate pages", summary:"Warning: Creating inappropriate pages" },		"uw-upload1": { label:"Uploading inappropriate images", summary:"Warning: Uploading inappropriate images" },		"uw-spam1": { label:"Adding spam links", summary:"Warning: Adding spam links" },		"uw-uncen1": { label:"Censorship of material", summary:"Warning: Censorship of material" },		"uw-move1": { label:"Page moves", summary:"Warning: Page moves" },		"uw-chat1": { label:"Using talk page as forum", summary:"Warning: Using talk page as forum" },		"uw-speedy1": { label:"Removing \{\{speedy deletion\}\} templates", summary:"Warning: Removing \{\{speedy deletion\}\} templates" }	},	level2: { "uw-vandalism2": { label:"Vandalism", summary:"Final warning: Vandalism" },		"uw-delete2": { label:"Page blanking, removal of content or templates", summary:"Final warning: Page blanking, removal of content or templates" },		"uw-create2": { label:"Creating inappropriate pages", summary:"Final warning: Creating inappropriate pages" },		"uw-upload2": { label:"Uploading inappropriate images", summary:"Final warning: Uploading inappropriate images" }		"uw-spam2": { label:"Adding spam links", summary:"Final warning: Adding spam links" },		"uw-move2": { label:"Page moves", summary:"Final warning: Page moves" },		"uw-speedy2": { label:"Removing \{\{speedy deletion\}\} templates", summary:"Final warning: Removing \{\{speedy deletion\}\} templates" }	},	block: { "uw-block1": { 'label':"Block level 1", 'summary':"You have been temporarily blocked" },		"uw-block2": { 'label':"Block level 3", 'summary':"You have been indefinitely blocked" },		"uw-ablock": { 'label':"Anonymous block", 'summary':"Your IP address has been blocked" }	} };

twinklewarn.callback.change_category = function twinklewarnCallbackChangeCategory(e) { var value = e.target.value; var sub_group = e.target.root.sub_group; var messages = twinklewarn.messages[ value ]; sub_group.main_group = value; var old_subvalue = sub_group.value; if( old_subvalue ) { old_subvalue = old_subvalue.replace(/\d*(im)?$/, '' ); var old_subvalue_re = new RegExp( RegExp.escape( old_subvalue ) + "(\\d*(?:im)?)$" ); }

while( sub_group.hasChildNodes ){ sub_group.removeChild( sub_group.firstChild ); }

for( var i in messages ) { var selected = false; if( old_subvalue && old_subvalue_re.test( i ) ) { selected = true; }		var elem = new QuickForm.element( { type:'option', label:"[" + i + "]: " + messages[i].label, value:i, selected: selected } ); sub_group.appendChild( elem.render ); }

if( value == 'block' ) { var more = new QuickForm.element( {				type: 'input',				name: 'block_timer',				label: 'Period of blocking: ',				tooltip: 'The period the blocking is due for, for example 24 hours, 2 weeks, indefinite etc...'			} ); e.target.root.insertBefore( more.render, e.target.root.lastChild ); e.target.root.article.disabled = true; } else if( e.target.root.block_timer ) { e.target.root.removeChild( e.target.root.block_timer.parentNode ); e.target.root.article.disabled = false; } }

twinklewarn.callbacks = { main: function( self ) { var form = self.responseXML.getElementById( 'editform' ); var text = form.wpTextbox1.value;

var history_re = /\<\!\-\-\ Template\:(uw\-.*?)\ \-\-\>.*?(\d{1,2}:\d{1,2}, \d{1,2} \w+ \d{4}) \(UTC\)/g; var history = {}; var latest = { date:new Date( 0 ), type:'' };

var current;

while( ( current = history_re.exec( text ) ) != undefined ) { var current_date = new Date( current[2] + ' UTC' ); if( !( current[1] in history ) || history[ current[1] ] < current_date ) { history[ current[1] ] = current_date; }			if( current_date > latest.date ) { latest.date = current_date; latest.type = current[1]; }		}

var date = new Date;

if( self.params.sub_group in history ) { var temp_time = new Date( history[ self.params.sub_group ] ); temp_time.setUTCHours( temp_time.getUTCHours + 24 );

if( temp_time > date ) { Status.info( 'Info', "an identical " + self.params.sub_group + " has been issued in the last 24 hours" ); if( !confirm( "Will you still add a warning/notice?" ) ) {					self.statelem.info( 'aborted per user request' ); return; }			}		}

latest.date.setUTCMinutes( latest.date.getUTCMinutes + 1 ); // after long debate, one minute is max

if( latest.date > date ) { Status.info('Info', "a " + latest.type + " has been issued in the last minute" ); if( !confirm( "Will you still add a warning/notice?" ) ) {					self.statelem.info( 'aborted per user request' ); return; }		}

var mainheaderRe = /==+\\s*Warnings\\s*==+/; var headerRe = new RegExp( "^==+\\s*" + date.getUTCMonthName + "\\s+" + date.getUTCFullYear + "\\s*==+", 'm' );

if( text.length > 0 ) { text += "\n"; }

if( !headerRe.exec( text ) ) { Status.info( 'Info', 'Will create a new level 2 heading for the date, as none was found for this month' ); text += "== " + date.getUTCMonthName + " " + date.getUTCFullYear + " ==\n"; }		if( self.params.main_group == 'block' ) { var time = null; if( /te?mp|^\s*$|min/.exec( self.params.block_timer ) ) { time = ''; } else if( /indef|\*|max/.exec( self.params.block_timer ) ) { time = '|indef=yes'; } else { time = '|time=' + self.params.block_timer; }

text += "\{\{subst:" + self.params.sub_group + time + (self.params.reason ? '|reason=' + self.params.reason : '' ) + "|sig=true\}\}"; } else { text += "\{\{subst:" + self.params.sub_group + ( self.params.article ? '|' + self.params.article :  ) + "\}\}" + (self.params.reason ? " " + self.params.reason + "'' ": ' ' ) + "\~\~\~\~"; }

if ( TwinkleConfig.showSharedIPNotice && isIPAddress( wgTitle ) ) { Status.info( 'Info', 'Adding a shared ip notice' ); switch( QueryString.get( 'type' ) ) { case 'vand': text += "\n:If this is a shared IP address, and you didn't make any unconstructive edits, consider creating an account for yourself so you can avoid further irrelevant warnings. "; break; default: text += "\n:If this is a shared IP address, and you didn't make the edit, consider creating an account for yourself so you can avoid further irrelevant notices. "; break; }		}		var postData = { 'wpMinoredit': form.wpMinoredit.checked ? 1 : undefined, 'wpWatchthis': TwinkleConfig.watchWarnings ? 1 : form.wpWatchthis.checked ? 1 : undefined, 'wpStarttime': form.wpStarttime.value, 'wpEdittime': form.wpEdittime.value, 'wpAutoSummary': form.wpAutoSummary.value, 'wpEditToken': form.wpEditToken.value, 'wpSummary': twinklewarn.messages[self.params.main_group][self.params.sub_group].summary + ( self.params.article ? ' on ' + self.params.article +  :  ) + '.' + TwinkleConfig.summaryAd, 'wpTextbox1': text };

self.post( postData ); } }

twinklewarn.callback.evaluate = function twinklewarnCallbackEvaluate(e) {

// First, grab all the values provided by the form var params = { reason: e.target.reason.value, main_group: e.target.main_group.value, sub_group: e.target.sub_group.value, article: e.target.article.value.replace( /^(Image|Category):/i, ':$1:' ), block_timer: e.target.block_timer ? e.target.block_timer.value : null }

Status.init( e.target );

var query = { 'title': wgPageName, 'action': 'submit' };	Wikipedia.actionCompleted.redirect = wgPageName; Wikipedia.actionCompleted.notice = "Warning complete, reloading talk page in some seconds"; var wikipedia_wiki = new Wikipedia.wiki( 'User talk page modification', query, twinklewarn.callbacks.main ); wikipedia_wiki.params = params; wikipedia_wiki.get; }

// If TwinkleConfig aint exist. if( typeof( TwinkleConfig ) == 'undefined' ) { TwinkleConfig = {}; }

/** TwinkleConfig.summaryAd (string) If ad should be added or not to summary, default TWINKLE */ if( typeof( TwinkleConfig.summaryAd ) == 'undefined' ) { TwinkleConfig.summaryAd = " using TW"; }

/** TwinkleConfig.deletionSummaryAd (string) If ad should be added or not to deletion summary, default TWINKLE */ if( typeof( TwinkleConfig.deletionSummaryAd ) == 'undefined' ) { TwinkleConfig.deletionSummaryAd = " using TW"; }

/** TwinkleConfig.watchSpeedyPages (array) What types of actions that should result in forced addition to watchlist */ if( typeof( TwinkleConfig.watchSpeedyPages ) == 'undefined' ) { TwinkleConfig.watchSpeedyPages = [ 'g3', 'g5', 'g10', 'g11', 'g12' ]; }

/** TwinkleConfig.markSpeedyPagesAsMinor (boolean) If, when applying speedy template to page, to mark the edit as minor, default true */ if( typeof( TwinkleConfig.markSpeedyPagesAsMinor ) == 'undefined' ) { TwinkleConfig.markSpeedyPagesAsMinor = true; }

/** TwinkleConfig.notifyUserOnSpeedyDeletionNomination (array) What types of actions that should result that the author of the page should be notified of nomination */ if( typeof( TwinkleConfig.notifyUserOnSpeedyDeletionNomination ) == 'undefined' ) { TwinkleConfig.notifyUserOnSpeedyDeletionNomination = [ 'g1', 'g2', 'g10', 'g11', 'g12', 'a1', 'a7', 'i3', 'i4', 'i5', 'i6', 'i7', 'u3', 't1' ]; }

/** TwinkleConfig.userTalkPageMode may take arguments: 'window': open a new window, remmenber the opened window 'tab': opens in a new tab, if possible. 'blank': force open in a new window, even if a such window exist */ if( typeof( TwinkleConfig.userTalkPageMode ) == 'undefined' ) { TwinkleConfig.userTalkPageMode = 'window'; }

/** TwinkleConfig.deleteTalkPageOnDelete If talk page if exists should also be deleted (CSD G8) when spedying a page (admin only) */ if( typeof( TwinkleConfig.deleteTalkPageOnDelete ) == 'undefined' ) { TwinkleConfig.deleteTalkPageOnDelete = false; }

/** TwinkleConfig.toolboxButtons (string) If id defined in this array, the button of the action is located inthe toolbox instead of in the actions bar. */ if( typeof( TwinkleConfig.toolboxButtons ) == 'undefined' ) { TwinkleConfig.toolboxButtons = []; }

/** TwinkleConfig.orphanNormalPagesOnSpeedyDelete (hash) Defines if all backlinks to a page should be removed. property 'exclude' defined actions not to orphan */ if( typeof( TwinkleConfig.orphanBacklinksOnSpeedyDelete ) == 'undefined' ) { TwinkleConfig.orphanBacklinksOnSpeedyDelete = { exclude: ['g6'], orphan:true }; }

function twinklespeedy { if( wgNamespaceNumber < 0 || wgCurRevisionId == false ) { return; }	if( userIsInGroup( 'sysop' ) ) { addPortletLink( 'p-cactions', "javascript:twinklespeedy.callback", "csd", "tw-csd", "Speedy delete according to WP:CSD", ""); } else { addPortletLink( 'p-cactions', "javascript:twinklespeedy.callback", "csd", "tw-csd", "Request speedy deletion according to WP:CSD", ""); }	} addOnloadHook(twinklespeedy);

twinklespeedy.callback = function twinklespeedyCallback { var Window = new SimpleWindow( 800, 400 ); Window.setTitle( "Choose criteria for speedy deletion" );

var form = new QuickForm( userIsInGroup( 'sysop' ) ? twinklespeedy.callback.evaluateSysop : twinklespeedy.callback.evaluateUser, 'change' ); if( userIsInGroup( 'sysop' ) ) { form.append( {				type: 'checkbox',				list: [					{						label: 'Tag page only, don\'t delete',						value: 'tag_only',						name: 'tag_only',						tooltip: 'If you just want to tag the page, instead of deleting it now',						event: function( event ) {							event.stopPropagation;						}					},					{						label: 'Orphan backlinks',						value: 'orphan_backlinks',						name: 'orphan_backlinks',						tooltip: 'If you want to orphan all backlinks to current page, if checked, excludes will still apply.',						checked: TwinkleConfig.orphanBacklinksOnSpeedyDelete.orphan,						event: function( event ) {							TwinkleConfig.orphanBacklinksOnSpeedyDelete.orphan = event.target.checked;							event.stopPropagation;						}					}				]			} ); }	if( wgNamespaceNumber == 6 ) { form.append( {type:'header', label:'Images/Media' } ); form.append ( {				type: 'radio',				name: 'csd',				list: [					{ 						label: 'I1: Redundant image',						value: 'redundantimage',						tooltip: 'Any image that is a redundant copy, in the same image file format and same or lower resolution, of something else on the Scroll Wars Wiki. Likewise, other media that is a redundant copy, in the same format and of the same or lower quality.' 					},					{ 						label: 'I2: Unused image',						value: 'unusedimage', 						tooltip: 'Any image which has gone unused for a long period of time, as defined by the dletion guidelines.' 					},				]			} ); }

form.append( { type:'header', label:'General criteria' } ); form.append( {			type: 'radio',			name: 'csd',			list: [				{ 					label: 'G1: Nonsense', 					value: 'nonsense', 					tooltip: 'Patent nonsense and gibberish, an unsalvageably incoherent page with no meaningful content. This does not include: poor writing, partisan screeds, obscene remarks, vandalism, fictional material, material not in English, badly translated material, implausible theories, or hoaxes' },				{ 					label: 'G2: Test page',					value: 'test',					tooltip: 'e.g., "Can I really create a page here?"' 				},				{ 					label: 'G3: Pure vandalism',					value: 'vandalism',					tooltip: 'Plain pure vandalism'				},				{ 					label: 'G3: Pagemove', 					value: 'pagemove',					tooltip: 'Nonsense redirects that are created from the cleanup of page move vandalism.'				},				{					label: 'G4: Recreation of deleted material',					value: 'repost',					tooltip: 'A copy, by any title, of a page that was deleted via an XfD process or Deletion review, provided that the copy is substantially identical to the deleted version and that any revisions made clearly do not address the reasons for which the page was deleted. This clause does not apply to content that has been "userfied", to content undeleted as a result of Deletion review, or if the prior deletions were proposed or speedy deletions, although in this last case, the previous speedy criterion, or other speedy deletion criteria, may apply.' },				{					label: 'G5: Banned user', value: 'banned', tooltip: 'Pages created by banned users while they were banned' },				{					label: 'G6: History merge', value: 'histmerge', tooltip: 'Temporarily deleting a page in order to merge page histories' },				{					label: 'G6: Move', value: 'move', tooltip: 'Making way for a move, such as reversing a redirect' },				{					label: 'G7: Author requests deletion', value: 'author', tooltip: 'Any page for which deletion is requested by the original author in good faith, provided the page\'s only substantial content was added by its author' },				{					label: 'G7: Author blanked', value: 'blanked', tooltip: ' If the author blanks the page, this can be taken as a deletion request' },				{					label: 'G8: Leftover talk page', value: 'talk', tooltip: 'A Talk page left over ' }			]		});

form.append( { type:'header', label:'Articles' } ); form.append( {			type: 'radio',			name: 'csd',			list: [				{					label: 'A1: Little or no context',					value: 'nocontext',					tooltip: 'Very short articles providing little or no context (e.g., "He is a funny man that has created Factory and the Hacienda. And, by the way, his wife is great."). Limited content is not in itself a reason to delete if there is enough context for the article to qualify as a valid stub'				},				{					label: 'A3: No content whatsoever',					value: 'nocontent',					tooltip: 'Any article consisting only of links elsewhere (including hyperlinks, category tags and "see also" sections), a rephrasing of the title, and/or attempts to correspond with the person or group named by its title. This does not include disambiguation pages'				}			]		} );

form.append( { type:'header', label: 'Redirects' } ); form.append( {			type: 'radio',			name: 'csd',			list: [				{ 					label: 'R1: Redirects to nonexistent pages',					value: 'redirnone'				},				{ 					label: 'R2: Redirects to the Talk:, User: or User talk: namespace from the article space', 					value: 'rediruser', 					tooltip: '(this does not include the Wikipedia shortcut pseudo-namespaces). If this was the result of a page move, consider waiting a day or two before deleting the redirect'				},				{ 					label: 'R3: Redirects as a result of an implausible typo that were recently created', 					value: 'redirtypo', 					tooltip: 'However, redirects from common misspellings or misnomers are generally useful, as are redirects in other languages'				}			]		} );

form.append( { type:'header', label: 'Categories' } ); form.append( {			type: 'radio',			name: 'csd',			list: [				{ 					label: 'C1: Empty categories',					value: 'catempty',					tooltip: '(no articles or subcategories for at least four days) whose only content has consisted of links to parent categories. This does not apply to categories being discussed on WP:CFD or WP:SFD, or disambiguation categories. If the category isn\'t relatively new, it possibly contained articles earlier, and deeper investigation is needed'				},				{					label: 'C3: Template categories',					value: 'catfd',					tooltip: 'If a category is solely populated from a template and the template is deleted per deletion policy, the category can also be deleted without further discussion'				}			]		} );

form.append( { type:'header', label: 'User pages' } ); form.append( {			type: 'radio',			name: 'csd',			list: [				{					label: 'U1: User request',					value: 'userreq',					tooltip: 'Personal subpages, upon request by their user. In some rare cases there may be administrative need to retain the page. Also, sometimes, main user pages may be deleted as well. See Wikipedia:User page for full instructions and guidelines'				},				{					label: 'U2: Nonexistent user',					value: 'nouser',					tooltip: 'User pages of users that do not exist (Check Special:Listusers)'				},			]		} );

form.append( { type:'header', label: 'Templates' } ); form.append( {			type: 'radio',			name: 'csd',			list: [

{ 					label: 'T1: Templates that are divisive and inflammatory', value: 'divisive' }			]		} );

var result = form.render; Window.setContent( result ); Window.display; }

twinklespeedy.normalizeHash = { 'nonsense': 'g1', 'test': 'g2', 'vandalism': 'g3', 'pagemove': 'g3', 'repost': 'g4', 'banned': 'g5', 'move': 'g6', 'author': 'g7', 'blanked': 'g7', 'talk': 'g8', 'nocontext': 'a1', 'nocontent': 'a3', 'redirnone': 'r1', 'rediruser': 'r2', 'redirtypo': 'r3', 'redundantimage': 'i1', 'noimage': 'i2', 'catempty': 'c1', 'catfd': 'c3', 'userreq': 'u1', 'nouser': 'u2', 'u3': 'u3', 'divisive': 't1', };

twinklespeedy.reasonHash = { 'nonsense': 'was patent nonsense: an unsalvageably incoherent page with no meaningful content', 'test': 'was a test page', 'vandalism': 'was pure vandalism', 'pagemove': 'was a redirect created during cleanup of page move vandalism', 'repost': 'was a copy of material previously deleted per XfD', 'banned': 'was a contribution was made by a banned user', 'histmerge': 'temporary deletion in order to merge page histories', 'move': 'making way for a non-controversial move', 'afd': 'deleting page per result of AfD discussion', 'g6': 'non-controversial housekeeping deletion', 'author': 'only editor requested deletion', 'blanked': 'only editor has blanked the page', 'talk': 'was a talk page whose corresponding page does not exist', 'attack': 'was a attack page intented to disparage its subject', 'spam': 'was blatant advertising, used only to promote someone or something', 'copyvio': 'was a blatant copyright infringement', 'nocontext': 'was a very short article providing little or no context', 'foreign': 'was a foreign language article that exists on another Wikimedia project', 'nocontent': 'had no content whatsoever except possibly links elsewhere, a rephrasing of the title, and/or attempts to correspond', 'transwiki': 'was properly transwikified elsewhere', 'bio': 'was an article about a real person, group of people, band, club, company, or web content that didn\'t assert the importance or significance of its subject', 'web': 'was an article about a web site, blog, online forum, webcomic, podcast, or similar web content that didn\'t assert the importance or significance of its subject.', 'inc': 'was an article about a company or corporation that didn\'t assert the importance or significance of its subject.', 'club': 'was an article about a club that didn\'t assert the importance or significance of the subject.', 'band': 'was an article about a band, singer, musician, or musical ensemble that didn\'t assert the importance or significance of the subject.', 'redirnone': 'was a redirect to an non-existent page', 'rediruser': 'was a redirect to the Talk:, User: or User talk: space', 'redirtypo': 'was a redirect based on an implausible typo', 'redundantimage': 'a same or better image exists on Wikipedia', 'noimage': 'was a corrupt or empty image', 'noncom': 'was licensed as "for non-commercial use only", "non-derivative use" or "used with permission", uploaded on or after May 19, 2005, and no assertion of fair use was provided', 'unksource': 'was an image lacking sources or licensing information for more than seven days', 'unfree': 'was an unfree image unused for more than seven days', 'norat': 'was an image with fair use tag but no fair use rationale for more than seven days', 'badfairuse': 'was an image with an invalid fair use rationale and the uploader was notified more than 48 hours ago', 'nowcommons': 'was an image available as a bit-for-bit identical copy on the Wikimedia Commons', 'imgcopyvio': 'was an image that was a suspected copyright infringement, and the uploader didn\'t assert public domain, fair use, or a free license', 'catempty': 'was an empty category for at least four days', 'catfd': 'was a category solely populated from a now deleted template', 'userreq': 'was a user page whose user requested deletion', 'nouser': 'was a user page of a user that did not exist', 'u3': 'was a gallery in the user space which consisted mostly of fair use images', 'divisive': 'was an divisive and inflammatory template', };

twinklespeedy.callbacks = { sysop: { main: function( self ) { var xmlDoc = self.responseXML; var normal = xmlDoc.evaluate( '//normalized/n/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue; if( normal ) { wgPageName = normal; }			var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;

if( ! exists ) { self.statelem.error( "It seems that the page doesn't exists, perhaps it has already been deleted" ); return; }			var query = { 'title': wgPageName, 'action': 'delete' };

var wikipedia_wiki = new Wikipedia.wiki( 'Deleting page', query, twinklespeedy.callbacks.sysop.deletePage ); wikipedia_wiki.params = self.params; wikipedia_wiki.followRedirect = false; wikipedia_wiki.get;

if( 				TwinkleConfig.deleteTalkPageOnDelete && 				wgNamespaceNumber % 2 == 0 && 				document.getElementById( 'ca-talk' ).className != 'new' 			) { var talk_page = namespaces[ wgNamespaceNumber + 1 ] + ':' + wgTitle; var query = query = { 'title': talk_page, 'action': 'delete' };				var wikipedia_wiki = new Wikipedia.wiki( 'Deleting talk page', query, twinklespeedy.callbacks.sysop.deleteTalkPage ); wikipedia_wiki.params = self.params; wikipedia_wiki.followRedirect = false; wikipedia_wiki.get; }

if( wgNamespaceNumber == 6 && self.params.normalized != 'i8' ) { var query = { 'action': 'query', 'list': 'imageusage', 'titles': wgPageName, 'iulimit': userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops };				var wikipedia_api = new Wikipedia.api( 'Grabbing image links', query, twinklespeedy.callbacks.sysop.unlinkImageInstancesMain ); wikipedia_api.params = self.params; wikipedia_api.post; }			var doOrphan = TwinkleConfig.orphanBacklinksOnSpeedyDelete; if( 				doOrphan.orphan && 				doOrphan.exclude.indexOf( self.params.normalized.toLowerCase ) == -1 			) { var query = { 'action': 'query', 'list': 'backlinks', 'blfilterredir': 'nonredirects', 'bltitle': wgPageName, 'bllimit': userIsInGroup( 'sysop' ) ? 5000 : 500, // 500 is max for normal users, 5000 for bots and sysops 'blnamespace': [0, 100] // Main namespace and portal namespace only, keep on talk pages. };				var wikipedia_api = new Wikipedia.api( 'Grabbing backlinks', query, twinklespeedy.callbacks.sysop.unlinkBacklinksMain ); wikipedia_api.params = self.params; wikipedia_api.post; }			var query = { 'action': 'query', 'list': 'backlinks', 'blfilterredir': 'redirects', 'bltitle': wgPageName, 'bllimit': userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops };			var wikipedia_api = new Wikipedia.api( 'Grabbing redirects', query, twinklespeedy.callbacks.sysop.deleteRedirectsMain ); wikipedia_api.params = self.params; wikipedia_api.post;

},		unlinkBacklinksMain: function( self ) { var xmlDoc = self.responseXML; var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

if( snapshot.snapshotLength == 0 ) { return; }

var statusIndicator = new Status('Removing backlinks', '0%');

var total = snapshot.snapshotLength * 2;

var onsuccess = function( self ) { var obj = self.params.obj; var total = self.params.total; var now = parseInt( 100 * ++(self.params.current)/total ) + '%'; obj.update( now ); self.statelem.unlink; if( self.params.current >= total ) { obj.info( now + ' (completed)' ); Wikipedia.removeCheckpoint; }			}			var onloaded = onsuccess;

var onloading = function( self ) {}

Wikipedia.addCheckpoint; if( snapshot.snapshotLength == 0 ) { statusIndicator.info( '100% (completed)' ); Wikipedia.removeCheckpoint; return; }

var params = clone( self.params ); params.current = 0; params.total = total; params.obj = statusIndicator; params.page = wgPageName;

for ( var i = 0; i < snapshot.snapshotLength; ++i ) { var title = snapshot.snapshotItem(i).value; var query = { 'title': title, 'action': 'submit' }				var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinklespeedy.callbacks.sysop.unlinkBacklinks ); wikipedia_wiki.params = params; wikipedia_wiki.onloading = onloading; wikipedia_wiki.onloaded = onloaded; wikipedia_wiki.onsuccess = onsuccess; wikipedia_wiki.get; }		},		unlinkBacklinks: function( self ) { var form = self.responseXML.getElementById('editform'); var text = form.wpTextbox1.value; var old_text = text; var wikiPage = new Mediawiki.Page( text ); wikiPage.removeLink( self.params.page );

text = wikiPage.getText; if( text == old_text ) { // Nothing to do, return self.onsuccess( self ); Wikipedia.actionCompleted( self ); return; }			var postData = { 'wpMinoredit': form.wpMinoredit.checked ? '' : undefined, 'wpWatchthis': undefined, 'wpStarttime': form.wpStarttime.value, 'wpEdittime': form.wpEdittime.value, 'wpAutoSummary': form.wpAutoSummary.value, 'wpEditToken': form.wpEditToken.value, 'wpSummary': 'Removing backlinks to ' + self.params.page + " that has been speedily deleted per (CSD " + self.params.normalized.toUpperCase + ")" + "; " + TwinkleConfig.deletionSummaryAd, 'wpTextbox1': text };			self.post( postData ); },		deleteRedirectsMain: function( self ) { var xmlDoc = self.responseXML; var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

var total = snapshot.snapshotLength * 2;

if( snapshot.snapshotLength == 0 ) { return; }

var statusIndicator = new Status('Deleting redirects', '0%');

var onsuccess = function( self ) { var obj = self.params.obj; var total = self.params.total; var now = parseInt( 100 * ++(self.params.current)/total ) + '%'; obj.update( now ); self.statelem.unlink; if( self.params.current >= total ) { obj.info( now + ' (completed)' ); Wikipedia.removeCheckpoint; }			}			var onloaded = onsuccess;

var onloading = function( self ) {}

Wikipedia.addCheckpoint; if( snapshot.snapshotLength == 0 ) { statusIndicator.info( '100% (completed)' ); Wikipedia.removeCheckpoint; return; }

var params = clone( self.params ); params.current = 0; params.total = total; params.obj = statusIndicator;

for ( var i = 0; i < snapshot.snapshotLength; ++i ) { var title = snapshot.snapshotItem(i).value; var query = { 'title': title, 'action': 'delete' }				var wikipedia_wiki = new Wikipedia.wiki( "Deleting " + title, query, twinklespeedy.callbacks.sysop.deleteRedirects ); wikipedia_wiki.params = params; wikipedia_wiki.onloading = onloading; wikipedia_wiki.onloaded = onloaded; wikipedia_wiki.onsuccess = onsuccess; wikipedia_wiki.followRedirect = false; wikipedia_wiki.get; }		},		deleteRedirects: function( self ) { var form = this.responseXML.getElementById( 'deleteconfirm' ); if( ! form ) { // Hell, image deletion is b0rked :(				form = this.responseXML.getElementsByTagName( 'form' )[0];				var postData = {					'wpReason': "Speedy deleted per (CSD R1), Redirect to deleted page \"" + wgPageName + "\"." + TwinkleConfig.deletionSummaryAd,					'wpEditToken': form.wpEditToken.value				}			} else {

var postData = { 'wpWatch': form.wpWatch.checked ? '' : undefined, 'wpReason': "Speedy deleted per (CSD R1), Redirect to deleted page \"" + wgPageName + "\"." + TwinkleConfig.deletionSummaryAd, 'wpEditToken': form.wpEditToken.value }			}			self.post( postData ); },		unlinkImageInstancesMain: function( self ) { var xmlDoc = self.responseXML; var snapshot = xmlDoc.evaluate('//imageusage/iu/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

if( snapshot.snapshotLength == 0 ) { return; }

var statusIndicator = new Status('Unlinking instances image', '0%');

var total = snapshot.snapshotLength * 2;

var onsuccess = function( self ) { var obj = self.params.obj; var total = self.params.total; var now = parseInt( 100 * ++(self.params.current)/total ) + '%'; obj.update( now ); self.statelem.unlink; if( self.params.current >= total ) { obj.info( now + ' (completed)' ); Wikipedia.removeCheckpoint; }			}			var onloaded = onsuccess;

var onloading = function( self ) {}

Wikipedia.addCheckpoint; if( snapshot.snapshotLength == 0 ) { statusIndicator.info( '100% (completed)' ); Wikipedia.removeCheckpoint; return; }

var params = clone( self.params ); params.current = 0; params.total = total; params.obj = statusIndicator; params.image = wgTitle;

for ( var i = 0; i < snapshot.snapshotLength; ++i ) { var title = snapshot.snapshotItem(i).value; var query = { 'title': title, 'action': 'submit' }				var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinklespeedy.callbacks.sysop.unlinkImageInstances ); wikipedia_wiki.params = params; wikipedia_wiki.onloading = onloading; wikipedia_wiki.onloaded = onloaded; wikipedia_wiki.onsuccess = onsuccess; wikipedia_wiki.get; }		},		unlinkImageInstances: function( self ) { var form = self.responseXML.getElementById('editform'); var text = form.wpTextbox1.value; var old_text = text; var wikiPage = new Mediawiki.Page( text ); wikiPage.commentOutImage( self.params.image, 'Commented out because image was deleted' );

text = wikiPage.getText; if( text == old_text ) { // Nothing to do, return self.onsuccess( self ); Wikipedia.actionCompleted( self ); return; }			var postData = { 'wpMinoredit': form.wpMinoredit.checked ? '' : undefined, 'wpWatchthis': undefined, 'wpStarttime': form.wpStarttime.value, 'wpEdittime': form.wpEdittime.value, 'wpAutoSummary': form.wpAutoSummary.value, 'wpEditToken': form.wpEditToken.value, 'wpSummary': 'Removing instance of image ' + self.params.image + " that has been speedily deleted per (CSD " + self.params.normalized.toUpperCase + ")" + "; " + TwinkleConfig.deletionSummaryAd, 'wpTextbox1': text };			self.post( postData ); },		deletePage: function( self ) { var form = this.responseXML.getElementById( 'deleteconfirm' ); if( ! form ) { // Hell, image deletion is b0rked :(				form = this.responseXML.getElementsByTagName( 'form' )[0];				var postData = {					'wpReason': "Speedy deleted per (CSD " + self.params.normalized.toUpperCase + "), " + self.params.reason + "." + TwinkleConfig.deletionSummaryAd,					'wpEditToken': form.wpEditToken.value				}				self.post( postData );			} else {

var postData = { 'wpWatch': self.params.watch || form.wpWatch.checked ? '' : undefined, 'wpReason': "Speedy deleted per (CSD " + self.params.normalized.toUpperCase + "), " + self.params.reason + "." + TwinkleConfig.deletionSummaryAd, 'wpEditToken': form.wpEditToken.value }				self.post( postData ); }		},		deleteTalkPage: function( self ) { form = this.responseXML.getElementById( 'deleteconfirm' );

var postData = { 'wpWatch': self.params.watch || form.wpWatch.checked ? '' : undefined, 'wpReason': "Speedy deleted per (CSD g8), was a talk page of deleted page." + TwinkleConfig.deletionSummaryAd, 'wpEditToken': form.wpEditToken.value }			self.post( postData ); }	},	user: { main: function( self ) { var xmlDoc = self.responseXML;

var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;

if( ! exists ) { self.statelem.error( "It seems that the page doesn't exists, perhaps it has already been deleted" ); return; }			var query = { 'title': wgPageName, 'action': 'submit' };

var wikipedia_wiki = new Wikipedia.wiki( 'Tagging page', query, twinklespeedy.callbacks.user.tagPage ); wikipedia_wiki.params = self.params; wikipedia_wiki.followRedirect = false; wikipedia_wiki.get; },		tagPage: function( self ) { form = this.responseXML.getElementById( 'editform' );

var text = form.wpTextbox1.value;

self.statelem.status( 'Checking for tags on the page...' );

var tag = /(\{\{(?:db-?|delete)\|?.*?\}\})/.exec( text );

if( tag ) { self.statelem.error( [ htmlNode( 'strong', tag[0] ), " is alread placed on the page." ] ) return; }

var xfd = /(\{\{(?:[rsaitcm]fd|md1)[^{}]*?\}\})/i.exec( text );

if( xfd && !confirm( "The deletion related template " + xfd[0] + " is already present on the page, do you still want to apply CSD template?" ) ) {				return; }			var code; switch( self.params.normalized ) { case 'i8': var date = new Date; var code = "\{\{NowCommons|month=" + date.getUTCMonthName + "|day=" + date.getUTCDate + "|year=" + date.getUTCFullYear + "|1=" + wgPageName.replace( '_', ' ' ) + "\}\}"; break; case 'g12': var url = prompt( 'please enter url if available, including the http://' ); if( url == null ) { return; }				code = "\{\{db-" + self.params.value + "|url=" + url + "\}\}"; break; case 'i1': var img = prompt( 'enter the image this is redundant to, excluding the Image: prefix' ); if( img == null ) { return; }				code = "\{\{db-" + self.params.value + "|1=" + img + "\}\}"; break; default: code = "\{\{db-" + self.params.value + "\}\}"; break; }

// Notification to first contributor var query = { 'action': 'query', 'prop': 'revisions', 'titles': wgPageName, 'rvlimit': 1, 'rvprop': 'user', 'rvdir': 'newer' }			var callback = function( self ) { var xmlDoc = self.responseXML; var user = xmlDoc.evaluate( '//rev/@user', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue; var query = { 'title': 'User talk:' + user, 'action': 'submit' };				var wikipedia_wiki = new Wikipedia.wiki( 'Notifying of initial contributor (' + user + ')', query, twinklespeedy.callbacks.user.userNotification ); wikipedia_wiki.params = self.params; wikipedia_wiki.get; }

if( self.params.usertalk ) { var wikipedia_api = new Wikipedia.api( 'Grabbing data of initial contributor', query, callback ); wikipedia_api.params = self.params; wikipedia_api.post; }

var postData = { 'wpMinoredit': TwinkleConfig.markSpeedyPagesAsMinor ? '' : undefined, 'wpWatchthis': self.params.watch ? '' : undefined, 'wpStarttime': form.wpStarttime.value, 'wpEdittime': form.wpEdittime.value, 'wpAutoSummary': form.wpAutoSummary.value, 'wpEditToken': form.wpEditToken.value, 'wpSummary': "Requesting speedy deletion (CSD " + self.params.normalized.toUpperCase + ")." + TwinkleConfig.summaryAd, 'wpTextbox1': code + "\n" + text };			self.post( postData ); },		userNotification: function( self ) { var form = self.responseXML.getElementById( 'editform' ); var text = form.wpTextbox1.value; text += "\n\{\{subst:db-csd-notice|1=" + wgPageName + "|2=" + self.params.normalized.toUpperCase + "\}\}"; var postData = { 'wpMinoredit': form.wpMinoredit.checked ? '' : undefined, 'wpWatchthis': form.wpWatchthis.checked ? '' : undefined, 'wpStarttime': form.wpStarttime.value, 'wpEdittime': form.wpEdittime.value, 'wpAutoSummary': form.wpAutoSummary.value, 'wpEditToken': form.wpEditToken.value, 'wpSummary': 'Notification: Speedy deletion nomination of \[\[' + wgPageName + '\]\].' + TwinkleConfig.summaryAd, 'wpTextbox1': text };			self.post( postData ); }	} }

twinklespeedy.callback.evaluateSysop = function twinklespeedyCallbackEvaluateSysop(e) {

wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country!

var tag_only = e.target.form.tag_only; if( tag_only && tag_only.checked ) { return twinklespeedy.callback.evaluateUser(e); }

var value = e.target.value; var normalized = twinklespeedy.normalizeHash[ value ];

var params = { value: value, normalized: normalized, watch: TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1, reason: twinklespeedy.reasonHash[ value ] };	Status.init( e.target.form );

var query = { 'action': 'query', 'titles': wgPageName }	var wikipedia_api = new Wikipedia.api( 'Checking if page exists', query, twinklespeedy.callbacks.sysop.main ); wikipedia_api.params = params; wikipedia_api.post; }

twinklespeedy.callback.evaluateUser = function twinklespeedyCallbackEvaluateUser(e) { wgPageName = wgPageName.replace( /_/g, ' ' ); // for queen/king/whatever and country! var value = e.target.value; var normalized = twinklespeedy.normalizeHash[ value ];

var params = { value: value, normalized: normalized, watch: TwinkleConfig.watchSpeedyPages.indexOf( normalized ) != -1, usertalk: TwinkleConfig.notifyUserOnSpeedyDeletionNomination.indexOf( normalized ) != -1 };

Status.init( e.target.form );

Wikipedia.actionCompleted.redirect = wgPageName; Wikipedia.actionCompleted.notice = "Tagging complete";

var query = { 'action': 'query', 'titles': wgPageName }

var wikipedia_api = new Wikipedia.api( 'Checking if page exists', query, twinklespeedy.callbacks.user.main ); wikipedia_api.params = params; wikipedia_api.post;

}