From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

// (C) Andrea Giammarchi - JSL 1.4b

var undefined;

function $JSL(){

	this.inArray=function(){

		var tmp=false,i=arguments1].length;

		while(i&&!tmp)tmp=arguments1][--i===arguments0];

		return tmp;

	};

	this.has=function(str){return $JSL.inArray(str,$has)};

	this.random=function(elm){

		var tmp=$JSL.$random();

		while(typeof(elmtmp])!=="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(tmpi]);

		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(tmpi][str===elm||elm==="*")$tmp.push($JSL.$getElementsByName(tmpi]));++i};

		if(!$tmp.item){if(!$JSL.has("item"))$has.push("item");$tmp.item=function(tmp){return thistmp]}};

		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?arguments1].length:0,str,tmp=[],elm=(""+this).replace(/[^\(]+/,"function");

		if(!arguments0])arguments0={};

		while(i)tmp.unshift("arguments[1]["+(--i)+"]");

		do{str="__".concat($JSL.random(arguments0]).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?arguments0:{}),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(a<b)thisr++=argumentsa++];

		return r;

	}};

	if(!Array.prototype.shift){$has$has.length="shift";Array.prototype.shift=function(){

		this.reverse();

		var r=this.pop();

		this.reverse();

		return r;

	}};

	if(!Array.prototype.splice){$has$has.length="splice";Array.prototype.splice=function(){

		var a,b,c,d=arguments.length,tmp=[],r=[];

		if(d>1){

			arguments0=parseInt(arguments0]);

			arguments1=parseInt(arguments1]);

			c=arguments0+arguments1];

			for(a=0,b=this.length;a<b;a++){

				if(a<arguments0||a>=c){

					if(a===c&&d>2){

						for(a=2;a<d;a++)tmp.push(argumentsa]);

						a=c;

					};

					tmp.push(thisa]);

				}

				else

					r.push(thisa]);

			};

			for(a=0,b=tmp.length;a<b;a++)

				thisa=tmpa];

			this.length = a;

		};

		return r;

	}};

	if(!Array.prototype.unshift){$has$has.length="unshift";Array.prototype.unshift=function(){

		var i=arguments.length;

		this.reverse();

		while(i>0)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<j){if(thisi++===elm){

			i=i-1+j;j=i-j;

		}}}

		else

			j=this.indexOf(elm,j+i);

		return j!==this.length?j:-1;

	}};

	if(!Array.prototype.lastIndexOf){$has$has.length="lastIndexOf";Array.prototype.lastIndexOf=function(elm,i){

		var j=-1;

		if(!i)i=this.length;

		if(i>=0){do{if(thisi--===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(thisi||this.charAt(i),i++,this)}

		else {		while(i<j&&!b)	b=!callback.apply(elm,[thisi||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(thisi],i++,this))

			r.push(thisi-1]);

		}} else {while(i<j){if(callback.apply(elm,[thisi],i++,this]))

			r.push(thisi-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(thisi],i++,this)}

		else {		while(i<j)	callback.apply(elm,[thisi],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(thisi],i++,this))}

		else {		while(i<j)	r.push(callback.apply(elm,[thisi],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(thisi],i++,this)}

		else {		while(i<j&&!b)	b=callback.apply(elm,[thisi],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 arguments1+" "})!=="0 1 "){$has$has.length="replace";String.prototype.replace=function(replace){return function(reg,func){

		var r="",tmp=$JSL.random(String);

		String.prototypetmp=replace;

		if(func.constructor!==Function)

			r=thistmp](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='"'+strj].substr(1,strj--].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+('"'+thistmp](reg,'"'+elm+',func('+r+'),'+elm+'"')+'"')+elm).split(elm))[tmp](/\n/g,'\\n')[tmp](/\r/g,'\\r')+'].join("")');

		};

		delete String.prototypetmp];

		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 ) {

		currentNode1].appendChild( this.childsi].render() );

	}

	return currentNode0];

}

 

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.listi];

 

				if( current.list ) {

					current.type = 'optgroup';

				} else {

					current.type = 'option';

				}

 

				var res = this.compute( current );

				select.appendChild( res0 );

			}

		}

		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.listi];

 

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

 

				var res = this.compute( current );

				node.appendChild( res0 );

			}

		}

		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.listi];

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

				}

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

}

 

/**

* return 'p-tb' if id is included in array, else return 'p-cactions';

*/

 

function chooseBox( id, arr ) {

	return arr.indexOf( id ) == -1 ? 'p-cactions' : 'p-tb';

}

 

/**

* Will escape a string to be used in a RegExp

*/

RegExp.escape = function( text, space_fix ) {

 

	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 = arguments0];

 

	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 = argumentscurrent_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 '#':

				flagscurrent_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' = argumentsnum];

							precision = false;

						} else if( format.charAt( i + 2 ) == 'v' ) {

							vector_delimiter = argumentsnum];

						}else {

							flags'width' = argumentsnum];

						}

						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' = argumentscurrent_index];

					precision = false;

				} else if( format.charAt( i + 1 ) == 'v' ) {

					vector_delimiter = argumentscurrent_index];

				} else {

					flags'width' = argumentscurrent_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 = thisi];

		if( result.indexOf( current ) == -1 ) {

			result.push( current );

		}

	}

	return result;

}

 

Array.prototype.uniq.dontEnum = true;

 

Array.prototype.dups = function arrayPrototypeUniq() {

	var uniques = [];

	var result = [];

	for( var i = 0; i < this.length; ++i ) {

		var current = thisi];

		if( uniques.indexOf( current ) == -1 ) {

			uniques.push( current );

		} else {

			result.push( current );

		}

	}

	return result;

}

 

Array.prototype.dups.dontEnum = true;

 

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 "\{\{" + ns2lnns + "|" + 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 = mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace( '$1', Wikipedia.actionCompleted.redirect );

		}

		window.setTimeout( function() { window.location = Wikipedia.actionCompleted.redirect } , Wikipedia.actionCompleted.timeOut );

	}

}

wpActionCompletedTimeOut = 500;

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' , mw.config.get('wgServer') + mw.config.get('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;

		var xmlhttp = sajax_init_object();

		Wikipedia.dump.push( xmlhttp );

		xmlhttp.obj = this;

		xmlhttp.overrideMimeType('text/xml');

		xmlhttp.open( 'POST' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( this.query ), true);

		xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');

		xmlhttp.onerror = function() {

			var self = this.obj;

			self.statelem.error( "Error " + this.status + " occurred while posting the document." );

		}

		xmlhttp.onload = function() {

			var self = this.obj;

			var xmlDoc;

			xmlDoc = self.responseXML = this.responseXML;

			var nsResolver = xmlDoc.createNSResolver( xmlDoc.ownerDocument == null ? xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement );

			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, nsResolver, XPathResult.BOOLEAN_TYPE, null ).booleanValue;

			if( nosession ) {

				if( self.counter > 5 ) {

					if( self.onerror ) {

						self.onerror( self );

					} else {

						self.statelem.error( "session failed, aborting." );

						return;

					}

				} else if( self.counter == 4 ) {

					++self.counter;

					if( self.onretry ) {

						self.onretry( self );

					} else {

						self.statelem.warn( "failed to get session, last retry (" + self.counter + ')...' );

					}

					self.get(); // last time we tries to reget it

 

				} else {

					++self.counter;

					if( self.onretry ) {

						self.onretry( self );

					} else {

						self.statelem.warn( "failed to get session, retrying (" + self.counter + ')...' );

					}

					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' , mw.config.get('wgServer') + mw.config.get('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( allLinksi ) ) {

				var replacement = '<!-- ' + reason + allLinksi + ' -->';

				this.text = this.text.replace( allLinksi], replacement );

			}

		}

 

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

		var replacement = "<!-- " + reason + "$1 -->";

 

		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( allLinksi ) ) {

				var replacement = allLinksi];

				// just put it at the end?

				replacement = replacement.replace( /\]\]$/, '|' + data + ']]' );

				this.text = this.text.replace( allLinksi], 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(iparr0]) << 24) + (parseInt(iparr1]) << 16) + (parseInt(iparr2]) << 8) + (parseInt(iparr3]));

 

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

 

	var netarr = network.split('/')[0].split('.');

	var net = (parseInt(netarr0]) << 24) + (parseInt(netarr1]) << 16) + (parseInt(netarr2]) << 8) + (parseInt(netarr3]));

 

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

}

 

/**

* 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');

*/

function QueryString(qString) {

	this.string = qString;

	this.params = {};

 

	if( qString.length == 0 ) {

		return;

	}

 

	qString.replace(/\+/, ' ');

	var args = qString.split('&');

 

	for( var i = 0; i < args.length; ++i ) {

		var pair = argsi].split( '=' );

		var key = decodeURIComponent( pair0 ), value = key;

 

		if( pair.length == 2 ) {

			value = decodeURIComponent( pair1 );

		}

 

		this.paramskey = 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.paramskey ? this.paramskey : null;

};

 

QueryString.exists = function(key) {

	QueryString.staticInit();

	return QueryString.static.exists(key);

}

 

QueryString.prototype.exists = function(key) {

	return this.paramskey ? true : false;

}

 

QueryString.equals = function(key, value) {

	QueryString.staticInit();

	return QueryString.static.equals(key, value);

}

 

QueryString.prototype.equals = function(key, value) {

	return this.paramskey == 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 arri == 'undefined' ) {

			continue;

		}

		if( arri instanceof Array ){

			var v =  Array();

			for(var j = 0; j < arri].length; ++j ) {

				vj = encodeURIComponent( arri][j );

			}

			resarr.push( encodeURIComponent( i ) + '=' +  v.join('|') );

		} else {

			resarr.push( encodeURIComponent( i ) + '=' + encodeURIComponent( arri ) );

		}

	}

 

	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.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 obji == 'string' ) {

				result.appendChild( document.createTextNode( obji ) );

			} else if( obji instanceof Element ) {

				result.appendChild( obji );

			} // 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.actionTransitionFunctionsthis.currentState][event.type];

		if( !actionTransitionFunction ) {

			actionTransitionFunction = this.unexpectedEvent;

		}

		var nextState = actionTransitionFunction.call(this, event);

		if( !nextState ){

			nextState = this.currentState;

		}

        if( !this.actionTransitionFunctionsnextState ){

			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.actionTransitionFunctionsanotherState][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';

	}

}
From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.

// (C) Andrea Giammarchi - JSL 1.4b

var undefined;

function $JSL(){

	this.inArray=function(){

		var tmp=false,i=arguments1].length;

		while(i&&!tmp)tmp=arguments1][--i===arguments0];

		return tmp;

	};

	this.has=function(str){return $JSL.inArray(str,$has)};

	this.random=function(elm){

		var tmp=$JSL.$random();

		while(typeof(elmtmp])!=="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(tmpi]);

		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(tmpi][str===elm||elm==="*")$tmp.push($JSL.$getElementsByName(tmpi]));++i};

		if(!$tmp.item){if(!$JSL.has("item"))$has.push("item");$tmp.item=function(tmp){return thistmp]}};

		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?arguments1].length:0,str,tmp=[],elm=(""+this).replace(/[^\(]+/,"function");

		if(!arguments0])arguments0={};

		while(i)tmp.unshift("arguments[1]["+(--i)+"]");

		do{str="__".concat($JSL.random(arguments0]).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?arguments0:{}),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(a<b)thisr++=argumentsa++];

		return r;

	}};

	if(!Array.prototype.shift){$has$has.length="shift";Array.prototype.shift=function(){

		this.reverse();

		var r=this.pop();

		this.reverse();

		return r;

	}};

	if(!Array.prototype.splice){$has$has.length="splice";Array.prototype.splice=function(){

		var a,b,c,d=arguments.length,tmp=[],r=[];

		if(d>1){

			arguments0=parseInt(arguments0]);

			arguments1=parseInt(arguments1]);

			c=arguments0+arguments1];

			for(a=0,b=this.length;a<b;a++){

				if(a<arguments0||a>=c){

					if(a===c&&d>2){

						for(a=2;a<d;a++)tmp.push(argumentsa]);

						a=c;

					};

					tmp.push(thisa]);

				}

				else

					r.push(thisa]);

			};

			for(a=0,b=tmp.length;a<b;a++)

				thisa=tmpa];

			this.length = a;

		};

		return r;

	}};

	if(!Array.prototype.unshift){$has$has.length="unshift";Array.prototype.unshift=function(){

		var i=arguments.length;

		this.reverse();

		while(i>0)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<j){if(thisi++===elm){

			i=i-1+j;j=i-j;

		}}}

		else

			j=this.indexOf(elm,j+i);

		return j!==this.length?j:-1;

	}};

	if(!Array.prototype.lastIndexOf){$has$has.length="lastIndexOf";Array.prototype.lastIndexOf=function(elm,i){

		var j=-1;

		if(!i)i=this.length;

		if(i>=0){do{if(thisi--===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(thisi||this.charAt(i),i++,this)}

		else {		while(i<j&&!b)	b=!callback.apply(elm,[thisi||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(thisi],i++,this))

			r.push(thisi-1]);

		}} else {while(i<j){if(callback.apply(elm,[thisi],i++,this]))

			r.push(thisi-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(thisi],i++,this)}

		else {		while(i<j)	callback.apply(elm,[thisi],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(thisi],i++,this))}

		else {		while(i<j)	r.push(callback.apply(elm,[thisi],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(thisi],i++,this)}

		else {		while(i<j&&!b)	b=callback.apply(elm,[thisi],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 arguments1+" "})!=="0 1 "){$has$has.length="replace";String.prototype.replace=function(replace){return function(reg,func){

		var r="",tmp=$JSL.random(String);

		String.prototypetmp=replace;

		if(func.constructor!==Function)

			r=thistmp](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='"'+strj].substr(1,strj--].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+('"'+thistmp](reg,'"'+elm+',func('+r+'),'+elm+'"')+'"')+elm).split(elm))[tmp](/\n/g,'\\n')[tmp](/\r/g,'\\r')+'].join("")');

		};

		delete String.prototypetmp];

		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 ) {

		currentNode1].appendChild( this.childsi].render() );

	}

	return currentNode0];

}

 

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.listi];

 

				if( current.list ) {

					current.type = 'optgroup';

				} else {

					current.type = 'option';

				}

 

				var res = this.compute( current );

				select.appendChild( res0 );

			}

		}

		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.listi];

 

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

 

				var res = this.compute( current );

				node.appendChild( res0 );

			}

		}

		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.listi];

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

				}

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

}

 

/**

* return 'p-tb' if id is included in array, else return 'p-cactions';

*/

 

function chooseBox( id, arr ) {

	return arr.indexOf( id ) == -1 ? 'p-cactions' : 'p-tb';

}

 

/**

* Will escape a string to be used in a RegExp

*/

RegExp.escape = function( text, space_fix ) {

 

	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 = arguments0];

 

	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 = argumentscurrent_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 '#':

				flagscurrent_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' = argumentsnum];

							precision = false;

						} else if( format.charAt( i + 2 ) == 'v' ) {

							vector_delimiter = argumentsnum];

						}else {

							flags'width' = argumentsnum];

						}

						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' = argumentscurrent_index];

					precision = false;

				} else if( format.charAt( i + 1 ) == 'v' ) {

					vector_delimiter = argumentscurrent_index];

				} else {

					flags'width' = argumentscurrent_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 = thisi];

		if( result.indexOf( current ) == -1 ) {

			result.push( current );

		}

	}

	return result;

}

 

Array.prototype.uniq.dontEnum = true;

 

Array.prototype.dups = function arrayPrototypeUniq() {

	var uniques = [];

	var result = [];

	for( var i = 0; i < this.length; ++i ) {

		var current = thisi];

		if( uniques.indexOf( current ) == -1 ) {

			uniques.push( current );

		} else {

			result.push( current );

		}

	}

	return result;

}

 

Array.prototype.dups.dontEnum = true;

 

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 "\{\{" + ns2lnns + "|" + 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 = mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace( '$1', Wikipedia.actionCompleted.redirect );

		}

		window.setTimeout( function() { window.location = Wikipedia.actionCompleted.redirect } , Wikipedia.actionCompleted.timeOut );

	}

}

wpActionCompletedTimeOut = 500;

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' , mw.config.get('wgServer') + mw.config.get('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;

		var xmlhttp = sajax_init_object();

		Wikipedia.dump.push( xmlhttp );

		xmlhttp.obj = this;

		xmlhttp.overrideMimeType('text/xml');

		xmlhttp.open( 'POST' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( this.query ), true);

		xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');

		xmlhttp.onerror = function() {

			var self = this.obj;

			self.statelem.error( "Error " + this.status + " occurred while posting the document." );

		}

		xmlhttp.onload = function() {

			var self = this.obj;

			var xmlDoc;

			xmlDoc = self.responseXML = this.responseXML;

			var nsResolver = xmlDoc.createNSResolver( xmlDoc.ownerDocument == null ? xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement );

			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, nsResolver, XPathResult.BOOLEAN_TYPE, null ).booleanValue;

			if( nosession ) {

				if( self.counter > 5 ) {

					if( self.onerror ) {

						self.onerror( self );

					} else {

						self.statelem.error( "session failed, aborting." );

						return;

					}

				} else if( self.counter == 4 ) {

					++self.counter;

					if( self.onretry ) {

						self.onretry( self );

					} else {

						self.statelem.warn( "failed to get session, last retry (" + self.counter + ')...' );

					}

					self.get(); // last time we tries to reget it

 

				} else {

					++self.counter;

					if( self.onretry ) {

						self.onretry( self );

					} else {

						self.statelem.warn( "failed to get session, retrying (" + self.counter + ')...' );

					}

					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' , mw.config.get('wgServer') + mw.config.get('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( allLinksi ) ) {

				var replacement = '<!-- ' + reason + allLinksi + ' -->';

				this.text = this.text.replace( allLinksi], replacement );

			}

		}

 

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

		var replacement = "<!-- " + reason + "$1 -->";

 

		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( allLinksi ) ) {

				var replacement = allLinksi];

				// just put it at the end?

				replacement = replacement.replace( /\]\]$/, '|' + data + ']]' );

				this.text = this.text.replace( allLinksi], 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(iparr0]) << 24) + (parseInt(iparr1]) << 16) + (parseInt(iparr2]) << 8) + (parseInt(iparr3]));

 

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

 

	var netarr = network.split('/')[0].split('.');

	var net = (parseInt(netarr0]) << 24) + (parseInt(netarr1]) << 16) + (parseInt(netarr2]) << 8) + (parseInt(netarr3]));

 

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

}

 

/**

* 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');

*/

function QueryString(qString) {

	this.string = qString;

	this.params = {};

 

	if( qString.length == 0 ) {

		return;

	}

 

	qString.replace(/\+/, ' ');

	var args = qString.split('&');

 

	for( var i = 0; i < args.length; ++i ) {

		var pair = argsi].split( '=' );

		var key = decodeURIComponent( pair0 ), value = key;

 

		if( pair.length == 2 ) {

			value = decodeURIComponent( pair1 );

		}

 

		this.paramskey = 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.paramskey ? this.paramskey : null;

};

 

QueryString.exists = function(key) {

	QueryString.staticInit();

	return QueryString.static.exists(key);

}

 

QueryString.prototype.exists = function(key) {

	return this.paramskey ? true : false;

}

 

QueryString.equals = function(key, value) {

	QueryString.staticInit();

	return QueryString.static.equals(key, value);

}

 

QueryString.prototype.equals = function(key, value) {

	return this.paramskey == 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 arri == 'undefined' ) {

			continue;

		}

		if( arri instanceof Array ){

			var v =  Array();

			for(var j = 0; j < arri].length; ++j ) {

				vj = encodeURIComponent( arri][j );

			}

			resarr.push( encodeURIComponent( i ) + '=' +  v.join('|') );

		} else {

			resarr.push( encodeURIComponent( i ) + '=' + encodeURIComponent( arri ) );

		}

	}

 

	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.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 obji == 'string' ) {

				result.appendChild( document.createTextNode( obji ) );

			} else if( obji instanceof Element ) {

				result.appendChild( obji );

			} // 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.actionTransitionFunctionsthis.currentState][event.type];

		if( !actionTransitionFunction ) {

			actionTransitionFunction = this.unexpectedEvent;

		}

		var nextState = actionTransitionFunction.call(this, event);

		if( !nextState ){

			nextState = this.currentState;

		}

        if( !this.actionTransitionFunctionsnextState ){

			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.actionTransitionFunctionsanotherState][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';

	}

}

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook