注意:儲存之後,你可能要兜過你嘅瀏覽器快取至睇到更改。Internet Explorer: 撳住Ctrl掣再撳重新整理掣。 Firefox: 撳住Shift掣再撳重新載入(又或者撳Ctrl-Shift-R)。 Google Chrome同埋Safari用戶就噉撳個重載掣。
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
	TwinkleConfig = {};
}

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

/**
 TwinkleConfig.markAIVReportAsMinor (boolean)
 Defines if a reports to AIV should be marked as minor, if false, default is applied as per preference.
 */
if( typeof( TwinkleConfig.markAIVReportAsMinor ) == 'undefined' ) {
	TwinkleConfig.markAIVReportAsMinor = true;
}

/**
 TwinkleConfig.confirmUsernameToAIV (boolean) (deprecated)
 Defines if a username reports to AIV should be confirmed before sent.
 */
if( typeof( TwinkleConfig.confirmUsernameToAIV ) == 'undefined' ) {
	TwinkleConfig.confirmUsernameToAIV = true;
}

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

function getChecked( nodelist ) {
	if( !( nodelist instanceof NodeList ) ) {
		throw nodelist + " not instance of NodeList";
	}
	var result = [];
	for(var i in nodelist ) {
		if( nodelist[i].checked ) {
			result.push( nodelist[i].value );
		}
	}
	return result;
}

function getTexts( nodelist ) {
	if ( nodelist instanceof HTMLInputElement ) {
		return [ nodelist.value ];
	}
	if( !( nodelist instanceof NodeList ) ) {
		throw nodelist + " not instance of NodeList";
	}
	var result = [];
	for(var i in nodelist ) {
		if( nodelist[i].type == 'text' && nodelist[i].value != '' ) {
			result.push( nodelist[i].value );
		}
	}
	return result;
}

function num2order( num ) {
	switch( num ) {
	case 1: return '';
	case 2: return '2nd';
	case 3: return '3rd';
	default: return num + 'th';
	}
}

$( twinklearv );
function twinklearv(){
	var username;


	if ( wgNamespaceNumber == 3 || wgNamespaceNumber == 2 || ( wgNamespaceNumber == -1 && wgTitle == "Contributions" )){

		// If we are on the contributions page, need to parse some then
		if( wgNamespaceNumber == -1 && wgTitle == "Contributions" ) {
			username = document.getElementById( 'contentSub' ).getElementsByTagName( 'a' )[0].getAttribute('title').split(':')[1];
		} else {
			username = wgTitle.split( '/' )[0].replace( /\"/, "\\\""); // only first part before any slashes
		}

		if( !username ) {
			// Something is fishy, there was no user? lets about everything
			throw "given username was " + username + " and thus makes no sense.";
		}

		var name = isIPAddress( username ) ? 'Report IP' : 'Report';
		var title =  isIPAddress( username ) ? 'Report IP to Administators' : 'Report user to Administrators';

		mw.util.addPortletLink( 'p-cactions', "javascript:twinklearv.callback(\"" + username + "\")", "arv", "tw-arv", name, title );
	}
}

twinklearv.callback = function twinklearvCallback( uid ) {
	if( uid == wgUserName ){
		alert( 'You don\'t want to report yourself , do you?' );
		return;
	}

	var Window = new SimpleWindow( 600, 400 );
	Window.setTitle( "Advance Reporting and Vetting" ); //Backronym

	var form = new QuickForm( twinklearv.callback.evaluate );
	var categories = form.append( {
			type: 'select',
			name: 'category',
			label: 'Select wanted type of report: ',
			event: twinklearv.callback.change_category
		} );
	categories.append( {
			type: 'option',
			label: 'Vandalism',
			value: 'aiv'
		} );
	categories.append( {
			type: 'option',
			label: 'Username',
			value: 'username'
		} );
	categories.append( {
			type: 'option',
			label: 'Sockpuppet',
			value: 'sock'
		} );

	form.append( {
			type: 'field',
			label:'Work area',
			name: 'work_area'
		} );
	form.append( {
			type: 'hidden',
			name: 'uid',
			value: uid
		} );
	
	var result = form.render();
	Window.setContent( result );
	Window.display();

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

}

twinklearv.callback.change_category = function twinklearvCallbackChangeCategory(e) {
	var value = e.target.value;
	var root = e.target.form;
	var old_area;
	for( var i in root.childNodes ) {
		var node = root.childNodes[i];
		if( 
			node instanceof Element &&
			node.getAttribute( 'name' ) == 'work_area' 
		) {
			old_area = node;
			break;
		}
	}
	var work_area = null;

	switch( value ) {
	default:
	case 'aiv':
		work_area = new QuickForm.element( { 
				type: 'field',
				label: 'Report user for vandalism',
				name: 'work_area'
			} );
		work_area.append( {
				type: 'input',
				name: 'page',
				label: 'Primary linked page: ',
				tooltip: 'Leave blank for no linked page in report',
				value: QueryString.exists( 'vanarticle' ) ? QueryString.get( 'vanarticle' ) : '',
				event: function(e) {
					var value = e.target.value;
					var root = e.target.form;
					if( value == '' ) {
						root.badid.disabled = root.goodid.disabled = true;
					} else {
						root.badid.disabled = false;
						root.goodid.disabled = root.badid.value == '';
					}
				}
			} );
		work_area.append( {
				type: 'input',
				name: 'badid',
				label: 'Revision ID for target page when vandalised: ',
				tooltip: 'Leave blank for no diff link',
				value: QueryString.exists( 'vanarticlerevid' ) ? QueryString.get( 'vanarticlerevid' ) : '',
				disabled: !QueryString.exists( 'vanarticle' ),
				event: function(e) {
					var value = e.target.value;
					var root = e.target.form;
					root.goodid.disabled = value == '';
				}
			} );
		work_area.append( {
				type: 'input',
				name: 'goodid',
				label: 'Last good revision ID before vandalism of target page: ',
				tooltip: 'Leave blank for diff link to previous revision',
				value: QueryString.exists( 'vanarticlegoodrevid' ) ? QueryString.get( 'vanarticlegoodrevid' ) : '',
				disabled: !QueryString.exists( 'vanarticle' ) || QueryString.exists( 'vanarticlerevid' )
			} );
		work_area.append( {
				type: 'checkbox',
				name: 'arvtype',
				list: [
					{ 
						label: 'Vandalism after final warning given',
						value: 'final'
					},
					{ 
						label: 'Vandalism after recent release of block',
						value: 'postblock'
					},
					{ 
						label: 'Evidently vandalism only account',
						value: 'vandalonly'
					},
					{ 
						label: 'Account is evidently a spambot or a compromized account',
						value: 'spambot'
					}
				]
			} );
		work_area.append( {
				type: 'textarea',
				name: 'reason',
				label: 'Comment: '
			} );
		work_area.append( { type:'submit' } );
		work_area = work_area.render();
		old_area.parentNode.replaceChild( work_area, old_area );
		break;
	case 'username':
		work_area = new QuickForm.element( { 
				type: 'field',
				label: 'Report username violation',
				name: 'work_area'
			} );
		var types = work_area.append( {
				type: 'field',
				label: 'Type of violation',
				tooltip: 'A valid report must include at least one of following types'
			} );

		types.append ( { 
				type:'header', 
				label:'Confusing usernames',
				tooltip: 'Confusing usernames that make it unduly difficult to identify users by their username'
			} );
		types.append( {
				type: 'checkbox',
				name: 'arvtype',
				list: [
					{ 
						label: 'Usernames that closely resemble the name of another Wikipedia user and may cause confusion',
						value: 'closely resembles the name of another wikipedia user and may cause confusion'
					},
					{
						label: 'Usernames that confusingly refer to a Wikipedia process, namespace, or toolbar item',
						value: 'confusingly refers to a Wikipedia process, namespace or toolbar item'
					},
					{
						label: 'Usernames that consist of a lengthy or apparently random sequence of characters',
						value: 'consists of a lengthy or apparently random sequence of characters',
						tooltip: 'E.g. "aaaaaaaaaaaa" or "ghfjkghdfjgkdhfjkg"'
					},
					{
						label: 'Usernames that are extremely lengthy',
						value: 'is extremely lengthy',
						tooltip: 'E.g. "Super Ultra Mege Bob of Waverly Drive from Mars146366"' 
					}
				]
			} );

		types.append ( { 
				type:'header', 
				label:'Misleading usernames',
				tooltip: 'Misleading usernames that imply relevant, misleading things about the user'
			} );
		types.append( {
				type: 'checkbox',
				name: 'arvtype',
				list: [
					{
						label: 'Usernames that imply the user is an admin or other official figure on Wikipedia, or of the Wikimedia foundation',
						value: 'implies that the user is an admin or other official figure on Wikipedia, or of the Wikimedia foundation'
					},
					{
						label: 'Usernames that match the name of a well-known living or recently deceased person',
						value: 'matches the name of a well-known living or recently deceased person',
						tooltip: 'Unless user verifiably is that person. Wikipedians with articles is a list of such users.'
					},
					{
						label: 'Usernames that imply an automated account',
						value: 'implies an automated account',
						tooltip: 'Such as names containing "robot", "bot", or a variation thereof. Such usernames are reserved for bot accounts'
					}
				]
			} );

		types.append ( { 
				type:'header', 
				label:'Disruptive usernames',
				tooltip: 'Disruptive usernames that disrupt or misuse Wikipedia, or imply an intent to do so'
			} );
		types.append( {
				type: 'checkbox',
				name: 'arvtype',
				list: [
					{
						label: 'Usernames that are similar to those used by known vandals',
						value: 'is similar to those used by known vandals'
					},
					{
						label: 'Usernames that are attacks on specific users',
						value: 'is an attack on an specific user'
					},
					{
						label: 'Usernames that contain personal information about people',
						value: 'contains personal information about people',
						tooltip: 'Such as a telephone number or street address'
					},
					{
						label: 'Usernames that allude to hacking, trolling, vandalism, legal threats, or computer viruses',
						value: 'alludes to hacking, trolling, vandalism, legal threats, or computer viruses'
					},
					{
						label: 'Usernames that include profanity, or obscenities, or references to genitalia or sexual slang',
						value: 'includes profanities, obscenities, or references to genitalias or sexual slangs'
					}
				]
			} );

		types.append ( { 
				type:'header', 
				label:'Promotional usernames',
				tooltip: 'Promotional usernames that attempt to promote a group or company on Wikipedia'
			} );
		types.append( {
				type: 'checkbox',
				name: 'arvtype',
				list: [
					{
						label: 'Usernames that match the name of a company or group',
						value: 'matches the name of a company or group',
						tooltip: 'Especially if the user promotes it'
					},
					{
						label: 'E-mail addresses or web page addresses are generally considered likely to be promotional',
						value: 'resembles e-mail addresses or web page addresses and is likely to be promotional',
						tooltip: 'Note that for a long time, email addresses were not prohibited. Usernames created before January 1, 2007 that are email addresses are grandfathered under this policy and are not prohibited'
					}
				]
			} );
		
		types.append ( { 
				type:'header', 
				label:'Offensive usernames',
				tooltip: 'Offensive usernames that may make harmonious editing difficult or impossible'
			} );
		types.append( {
				type: 'checkbox',
				name: 'arvtype',
				list: [
					{
						label: 'Usernames that promote a controversial or potentially inflammatory point of view',
						value: 'promotes a controversial or potentially inflammatory point of view'
					},
					{
						label: 'Usernames that are defamatory or insulting to other people or groups',
						value: 'is defamatory or insulting to other people or groups'
					},
					{
						label: 'Usernames that invoke the name of a religious figure or religion in a distasteful, disrespectful, or provocative way, or promote one religion over another',
						value: 'invokes the name of a religious figure/religion in a distasteful, disrespectful, or provocative way, or promotes one religion over another',
						tooltip: 'Note that simple expressions of faith are allowed unless they are disruptive, but are discouraged'
					},
					{
						label: 'Usernames that refer to real-world violent actions',
						value: 'refers to a violent real-world action'
					},
					{
						label: 'Usernames that refer or include allusions to racism, sexism, hate speech, et cetera',
						value: 'refers or includes allusions to racism, sexism, hate speech, et cetera'
					},
					{
						label: 'Usernames that refer to a medical condition or disability, especially in a belittling way',
						value: 'refers to a medical condition or disability'
					},
					{
						label: 'Usernames that include slurs, or references to reproductive or excretory bodily functions',
						value: 'includes slurs or references to reproductive/excretory bodily functions'
					}
				]
			} );
		work_area.append( {
				type: 'textarea',
				name: 'reason',
				label: 'Comment:'
			} );
		work_area.append( { type:'submit' } );
		work_area = work_area.render();
		old_area.parentNode.replaceChild( work_area, old_area );
		break;

	case 'sock':
		work_area = new QuickForm.element( { 
				type: 'field',
				label: 'Report suspected sockpuppeter',
				name: 'work_area'
			} );
		var sock_area = work_area.append( { type:'div' } );
		sock_area.append( {
				type: 'button',
				label: 'More socks',
				name: 'more_socks_button',
				event: function (e){
					var area = e.target.parentNode.parentNode;
					var new_node = new QuickForm.element( {
							type: 'input',
							label: 'Sockpuppet: ',
							name: 'sockpuppet'
						} );
					if( area.childNodes.length > 1 ) {
						new_node.append( {
								type: 'button',
								label: 'remove',
								event: function (e){
									var node_to_remove = e.target.parentNode.parentNode;
									node_to_remove.parentNode.removeChild( node_to_remove );
								}
							} );
					}
					area.insertBefore( new_node.render(), area.lastChild );
				}
			} );

		work_area.append( {
				type: 'textarea',
				label: 'Evidence:',
				name: 'evidence'
			} );
		work_area.append( { type:'submit' } );
		work_area = work_area.render();
		old_area.parentNode.replaceChild( work_area, old_area );

		var evt = document.createEvent( "MouseEvent" );
		evt.initEvent( 'click', true, true );
		work_area.form.more_socks_button.dispatchEvent( evt );
		break;
	}
}

twinklearv.callback.evaluate = function(e) {
	var form = e.target;
	var reason = "";
	if( form.reason ) {
		comment = form.reason.value;
	}
	var uid = form.uid.value;
	switch( form.category.value ) {
	default:
	case 'aiv':
		var types = getChecked( form.arvtype );
		if( types.length == 0 && comment == '' ) {
			alert( 'You must specify some reason' );
			return;
		}

		types = types.map( function(v) {
				switch(v) {
				case 'final':
					return 'vandalism after final warning';
					break;
				case 'postblock':
					return 'vandalism directly after release of block';
					break;
				case 'spambot':
					return 'account is evidently a spambot or a compromized account';
					break;
				case 'vandalonly':
					return 'actions evidently indicate a vandalism only account';
					break;
				}
			} ).join( ', ' );


		if( form.page.value != '' ) {
			reason += 'On [[' + form.page.value.replace( /^(Image|Category):/i, ':$1:' ) + ']]';

			if( form.badid.value != '' ) {
				var query = {
					'title': form.page.value,
					'diff': form.badid.value,
					'oldid': form.goodid.value
				};
				reason += ' ([' +  mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( query ) + ' diff])';
			}
			reason += ';';
		}

		if( types ) {
			reason += " " + types;
		}
		if (comment != '' ) {
			reason += ". " + comment + '.';
		}
		Status.init( form );

		Status.status( "Grabbing AIV page" );
		var xmlhttp = sajax_init_object();
		xmlhttp.query = {
			'title': 'Wikipedia:Administrator intervention against vandalism',
			'action': 'submit',
			'section': 1
		};
		xmlhttp.params = { reason:reason, uid:uid };

		xmlhttp.overrideMimeType('text/xml');
		xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
		xmlhttp.onload = function() {
			uid = this.params.uid;
			reason = this.params.reason;
			var form = this.responseXML.getElementById('editform');

			if( !form ) {
				Status.error( 'Failed to retrieve edit form.' );
				return;
			}
			var text = form.wpTextbox1.value;

			var re = new RegExp( "\\{\\{\\s*(?:(?:[Ii][Pp])?[Vv]andal|[Uu]serlinks)\\s*\\|\\s*(?:1=)?\\s*" + RegExp.escape( uid, true ) + "\\s*\\}\\}" );

			var myArr;
			if( ( myArr = re.exec( text ) ) ) {
				Status.info( 'Report already present, will not add a new one' );
				return;
			}
			Status.status( 'Adding new report...' );
			var postData = {
				'wpMinoredit': TwinkleConfig.markAIVReportAsMinor ? '' : form.wpMinoredit.checked ? '' : undefined, 
				'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
				'wpStarttime': form.wpStarttime.value,
				'wpEdittime': form.wpEdittime.value,
				'wpAutoSummary': form.wpAutoSummary.value,
				'wpEditToken': form.wpEditToken.value,
				'wpSummary': 'Reporting [[Special:Contributions/' + uid + '|' + uid + ']].'+ TwinkleConfig.summaryAd,
				'wpTextbox1': text + '*{{' + ( isIPAddress( uid ) ? 'IPvandal' : 'vandal' ) + '|' + (/\=/.test( uid ) ? '1=' : '' ) + uid + '}} - ' + reason + ' ~~' + '~~'
			};
			var xmlhttp = sajax_init_object();
			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.onload = function() { window.location =  mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace( '$1', 'Wikipedia:Administrator intervention against vandalism' ); }
			xmlhttp.send( QueryString.create( postData ) );

		}
		xmlhttp.send( null );

		break;

	case 'username':
		var types = getChecked( form.arvtype );
		if( types.length == 0 ) {
			alert( 'You must specify at least one breached violation' );
			return;
		}
		types = types.map( function( v ) { return v.toLowerCaseFirstChar(); } );

		if( types.length <= 2 ) {
			types = types.join( ' and ' ).toUpperCaseFirstChar();
		} else {
			types = [ types.slice( 0, -1 ).join( ', ' ), types.slice( -1 ) ].join( ', and ' ).toUpperCaseFirstChar();
		}
		reason = "*\{\{userlinks|" + uid + "\}\} &mdash; Violation of username policy because: " + types + "; ";
		if (comment != '' ) {
			reason += "''" + comment.toUpperCaseFirstChar() + "''. ";
		}
		reason += "\~\~\~\~";
		Status.init( form );

		Status.status( "Grabbing UAA page" );
		var xmlhttp = sajax_init_object();
		xmlhttp.query = {
			'title': 'Wikipedia:Usernames for administrator attention',
			'action': 'submit',
			'section': 1
		};
		xmlhttp.params = { reason:reason, uid:uid };
		xmlhttp.overrideMimeType('text/xml');
		xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
		xmlhttp.onload = function() {
			uid = this.params.uid;
			reason = this.params.reason;
			var form = this.responseXML.getElementById('editform');

			if( !form ) {
				Status.error( 'Failed to retrieve edit form.' );
				return;
			}
			var text = form.wpTextbox1.value;

			Status.status( 'Adding new report...' );
			var postData = {
				'wpMinoredit': form.wpMinoredit.checked ? '' : undefined, 
				'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
				'wpStarttime': form.wpStarttime.value,
				'wpEdittime': form.wpEdittime.value,
				'wpAutoSummary': form.wpAutoSummary.value,
				'wpEditToken': form.wpEditToken.value,
				'wpSummary': 'Reporting [[Special:Contributions/' + uid + '|' + uid + ']].'+ TwinkleConfig.summaryAd,
				'wpTextbox1': text.replace( /-->/, "-->\n" + reason.replace( '\$', "$$$$" ) )
			};
			var xmlhttp = sajax_init_object();
			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.onload = function() { window.location =  mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace( '$1', 'Wikipedia:Usernames for administrator attention' ); }
			xmlhttp.send( QueryString.create( postData ) );

		}
		xmlhttp.send( null );
		break;
	case 'sock':
		var sockpuppets = getTexts( form.sockpuppet );
		var evidence = form.evidence.value;
		Status.init( form );

		Status.status( 'Grabbing data of eventual previous reports' );

		var xmlhttp = sajax_init_object();
		xmlhttp.query = {
			'title': 'Special:Prefixindex',
			'from': 'Suspected sock puppets/' + uid,
			'namespace': 4
		};
		xmlhttp.params = { uid:uid, sockpuppets:sockpuppets, evidence:evidence };
		xmlhttp.overrideMimeType('text/xml');
		xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
		xmlhttp.onload = function() {
			var a_tags = this.responseXML.getElementsByTagName('a');
			var re = new RegExp( RegExp.escape( 'Suspected sock puppets/' + this.params.uid ) );
			var number = 0;
			for( var i in a_tags ) {
				var title = a_tags[i].title;
				if( re.exec( title ) ) {
					var n = /\(\s*(\d+)(?:th|nd|rd|st)\s*\)\s*$/.exec( title );
					if( n && n[1] > number ) {
						number = n[1];
					} else if( number == 0 ) {
						number = 1;
					}
				}
			}

			if( number == 0 ) {
				this.params.numbering = this.params.number = '';
			} else {
				this.params.number = num2order( parseInt( number ) + 1);
				this.params.numbering = ' (' + this.params.number + ')';
			}

			Status.status( 'Creating report page [[Wikipedia:Suspected sock puppets/' +  this.params.uid + this.params.numbering + ']]');

			var xmlhttp = sajax_init_object();
			xmlhttp.query = {
				'title': 'Wikipedia:Suspected sock puppets/' +  this.params.uid + this.params.numbering,
				'action': 'submit'
			};
			xmlhttp.params = this.params;
			xmlhttp.overrideMimeType('text/xml');
			xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
			xmlhttp.onload = function() {
				var form = this.responseXML.getElementById('editform');
				var text = 
					"===[[User:" + this.params.uid + "]]===\n" +
					";Suspected sockpuppeteer\n" +
					":\{\{user5|" + this.params.uid + "\}\}\n\n" +
					";Suspected sockpuppets\n" + 
					this.params.sockpuppets.map( function(v) { return ":\{\{user5|" + v + "\}\}" } ).join( "\n" ) + "\n\n" +
					";Report submission by\n" +
					"\~\~\~\~\n\n" +
					";Evidence\n" +
					this.params.evidence + "\n\n" +
					";Comments\n\n\n" +
					";Conclusions\n\n\n" +
					"----\n</div>\n";


				var postData = {
					'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
					'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
					'wpStarttime': form.wpStarttime.value,
					'wpEdittime': form.wpEdittime.value,
					'wpAutoSummary': form.wpAutoSummary.value,
					'wpEditToken': form.wpEditToken.value,
					'wpSummary': "Creating report for [[User:" +  this.params.uid + ']].' + TwinkleConfig.summaryAd,
					'wpTextbox1': text
				};
				var xmlhttp = sajax_init_object();
				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.onload = function() { Status.info( 'Report created' ) }
				xmlhttp.send( QueryString.create( postData ) );
			}
			xmlhttp.send( null );

			Status.status( 'Linking report to open cases');
			var xmlhttp = sajax_init_object();
			xmlhttp.query = {
				'title': 'Wikipedia:Suspected sock puppets',
				'section': 4,
				'action': 'submit'
			};
			xmlhttp.params = this.params;
			xmlhttp.overrideMimeType('text/xml');
			xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
			xmlhttp.onload = function() {
				var form = this.responseXML.getElementById('editform');
				text = form.wpTextbox1.value.replace( /(<!-- Add .*? list\. -->)/, "$1\n\{\{Wikipedia:Suspected sock puppets/" + this.params.uid + this.params.numbering + "\}\}");
				var postData = {
					'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
					'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
					'wpStarttime': form.wpStarttime.value,
					'wpEdittime': form.wpEdittime.value,
					'wpAutoSummary': form.wpAutoSummary.value,
					'wpEditToken': form.wpEditToken.value,
					'wpSummary': "Adding report for [[User:" +  this.params.uid + ']].' + TwinkleConfig.summaryAd,
					'wpTextbox1': text
				};
				var xmlhttp = sajax_init_object();
				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.onload = function() { Status.info( 'Added to open cases' ) }
				xmlhttp.send( QueryString.create( postData ) );
			}
			xmlhttp.send( null );

			Status.status( 'Notifying suspected sockpuppeter');
			var xmlhttp = sajax_init_object();
			xmlhttp.query = {
				'title': 'User talk:' + this.params.uid,
				'action': 'submit'
			};
			xmlhttp.params = this.params;
			xmlhttp.overrideMimeType('text/xml');
			xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
			xmlhttp.onload = function() {
				var form = this.responseXML.getElementById('editform');
				text = form.wpTextbox1.value;
				var postData = {
					'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
					'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
					'wpStarttime': form.wpStarttime.value,
					'wpEdittime': form.wpEdittime.value,
					'wpAutoSummary': form.wpAutoSummary.value,
					'wpEditToken': form.wpEditToken.value,
					'wpSummary': "Notifying about suspicion of sockpuppertering." + TwinkleConfig.summaryAd,
					'wpTextbox1': text + "\n\{\{subst:socksuspectnotice|1=" + this.params.uid + this.params.numbering + "\}\} \~\~\~\~"
				};
				var xmlhttp = sajax_init_object();
				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.onload = function() { Status.info( 'Suspected sockpuppeter notified' ) }
				xmlhttp.send( QueryString.create( postData ) );
			}
			xmlhttp.send( null );

			var statusIndicator = document.createElement( 'div' );
			Status.status( [ statusIndicator ] );
			statusIndicator.appendChild( document.createTextNode( 'Tagging suspected socs, status: ' ) );
			statusIndicator.appendChild( document.createTextNode( '0%' ) );
			var nofnodes = this.params.sockpuppets.length * 2;
			counter = 0;
			updateCounter = function(obj, total) {
				obj.replaceChild( document.createTextNode( parseInt( 100 * ++counter/total ) + '%' ), obj.lastChild );
				if( counter == total ) {
					Status.info( 'tagging of sockpuppets complete.' );

				}
			}
			for( var i in this.params.sockpuppets ) {
				(function(current, total, obj, params) {
						var xmlhttp = sajax_init_object();
						xmlhttp.query = {
							'title': 'User:' + params.sockpuppets[current],
							'action': 'submit'
						};
						xmlhttp.overrideMimeType('text/xml');
						xmlhttp.open( 'GET' , mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?' + QueryString.create( xmlhttp.query ), true);
						xmlhttp.onload = function() {
							updateCounter( obj, total );
							var form = this.responseXML.getElementById('editform');
							text = form.wpTextbox1.value;
							if( /\{\{sockpuppet.*?\}\}/.exec( text ) ) { // already marked as a sock, just ignore then
								updateCounter( obj, total );
								return;
							}
							var postData = {
								'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
								'wpWatchthis': form.wpWatchthis.checked ? '' : undefined,
								'wpStarttime': form.wpStarttime.value,
								'wpEdittime': form.wpEdittime.value,
								'wpAutoSummary': form.wpAutoSummary.value,
								'wpEditToken': form.wpEditToken.value,
								'wpSummary': "Adding supsected sockpuppet tag for suspected sockpuppeter [[User:" +  params.uid + ']].' + TwinkleConfig.summaryAd,
								'wpTextbox1': "\{\{subst:socksuspect|1=" + params.uid + "\}\}\n" + text
							};
							var xmlhttp = sajax_init_object();
							xmlhttp.current = this.current;
							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.onload = function() { 
								updateCounter( obj, total );
							}
							xmlhttp.send( QueryString.create( postData ) );
						}
						xmlhttp.send( null );
					})( i, nofnodes, statusIndicator, this.params );

			}

		}
		xmlhttp.send( null );
	}
}