Benutzer:Schnark/js/bot.js

aus Wikipedia, der freien Enzyklopädie
< Benutzer:Schnark‎ | js
Dies ist die aktuelle Version dieser Seite, zuletzt bearbeitet am 31. Oktober 2019 um 21:11 Uhr durch imported>Krinkle(731718) (Maintenance: mw:RL/MGU - Updated deprecated module name).
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
//Dokumentation unter [[Benutzer:Schnark/js/bot]] <nowiki>
/*global mw: true */
(function($, libs){

var version = 1.2;

var defaultConfig = {
	max: 50,
	followredirects: false
};
function isBot () {
	return $.inArray('bot', mw.config.get('wgUserGroups')) > -1;
}
function getMaxTitles () {
	return isBot() ? 500 : 50;
}
function getMaxLimit (max, small) {
	var limit = small ? 50 : 500;
	if (isBot()) {
		limit *= 10;
	}
	if (max === undefined || max > limit) {
		return 'max';
	} else {
		return String(max);
	}
}
function extend (to, from) {
	for (var p in from) {
		if (!(p in to)) {
			to[p] = from[p];
		} else if ($.isArray(to[p]) && $.isArray(from[p])) {
			to[p] = to[p].concat(from[p]);
		} else if ($.isPlainObject(to[p])) {
			extend(to[p], from[p]);
		} else {
			to[p] = from[p];
		}
	}
}

var stopped = false, aborted = false, contAfter = [];
function stop () {
	stopped = true;
}
function cont () {
	stopped = false;
	while (contAfter.length > 0) {
		(contAfter.pop())();
	}
}
function abort () {
	aborted = true;
	if (stopped) {
		cont();
	}
}
function executeStoppable (f) {
	if (stopped) {
		contAfter.push(f);
	} else {
		f();
	}
}
var stopOnNewMessageDelay = 20;
function stopOnNewMessage (delay) {
	if (delay) {
		stopOnNewMessageDelay = delay;
	}
	$.getJSON(mw.util.wikiScript('api'), {action: 'query', meta: 'userinfo', uiprop: 'hasmsg', format: 'json'}, function (json) {
		if (!json || !json.query || !json.query.userinfo || json.query.userinfo.messages === '') {
			stop();
			if (window.confirm('Fortfahren?')) {
				cont();
			} else {
				abort();
			}
		}
		if (!aborted) {
			window.setTimeout(stopOnNewMessage, stopOnNewMessageDelay * 1000);
		}
	});
}

var CSSforDiffAdded = false;
function waitForSchnarkDiffAndDialog (f) {
	function callback () {
		if (!CSSforDiffAdded) {
			mw.util.addCSS(libs.schnark_diff.getCSS());
			CSSforDiffAdded = true;
		}
		mw.loader.using('jquery.ui', f);
	}

	if (typeof libs.schnark_diff === 'object') {
		return callback();
	}
	if (typeof libs.jsmodules === 'object' && typeof libs.jsmodules.load === 'function' && typeof libs.jsmodules.local === 'function') {
		libs.jsmodules.local(true);
		//</nowiki>
		libs.jsmodules.load('[[Benutzer:Schnark/js/diff.js/core.js]]', {after: callback});
		//<nowiki>
		libs.jsmodules.local();
		return;
	}
	$(document).bind('loadWikiScript', function (e, name) {
		if (name === 'Benutzer:Schnark/js/diff.js/core.js') {
			callback();
		}
	});
	mw.loader.load('//de.wikipedia.org/w/index.php?title=Benutzer:Schnark/js/diff.js/core.js&action=raw&ctype=text/javascript');
}

function getFormatter (data) {
	if (data === undefined) {
		return {pre: '',
			line: function (title) {return title + '\n';},
			post: ''};
	}
	if (data === ',') {
		return {pre: '',
			line: function (title, prop, count) {return ((count === 1) ? '' : ', ') + '[[:' + title + ']]';},
			post: ''};
	}
	if (data === '*') {
		return {pre: '',
			line: function (title) {return '* [[:' + title + ']]\n';},
			post: ''};
	}
	if (data === '#') {
		return {pre: '',
			line: function (title) {return '# [[:' + title + ']]\n';},
			post: ''};
	}
	if (data === 'gallery') {
		return {pre: '<gallery showfilename>\n',
			line: function (title) {return title + '\n';},
			post: '</gallery>'};
	}
	if (typeof data === 'string') {
		return {pre: data + '\n',
			line: function (title) {return '* [[:' + title + ']]\n';},
			post: ''};
	}
	if ($.isFunction(data)) {
		return {pre: '',
			line: data,
			post: ''};
	}
	if ($.isArray(data)) {
		return {pre: '{| class="wikitable"\n! ' + data.join(' !! ') + '\n',
			line: function (title, props, count) {
				var list = [];
				for (var i = 0; i < data.length; i++) {
					if (data[i] === '#') {
						list.push(String(count));
					} else if (data[i] === 'title') {
						list.push('[[:' + title + ']]');
					} else {
						var text = '', prop = props[data[i]];
						if (prop === undefined) {
							text = '<span style="color:red;">✘</span>';
						} else if (prop === '') {
							text = '<span style="color:green;">✔</span>';
						} else if (typeof prop === 'string') {
							text = prop;
						} else if ($.isArray(prop)) {
							text = '[' + prop.join(', ') + ']';
						} else if ($.isPlainObject(prop)) {
							var content = [];
							for (var name in prop) {
								content.push("''" + name + "'': " + prop[name]);
							}
							text = '{' + content.join(', ') + '}';
						} else {
							text = String(prop);
						}
						list.push(text);
					}
				}
				return '|-\n|' + list.join(' || ') + '\n';
			},
			post: '|}\n'};
	}
	return data;
}

function getNS (ns) {
	if ($.isArray(ns)) {
		return $.map(ns, getNS).join('|');
	}
	var ret = String(ns), allns = mw.config.get('wgNamespaceIds');
	ret = ret.toLowerCase().replace(/[ _]+/g, '_').replace(/:$/, '');
	if (ret in allns) {
		ret = allns[ret];
	}
	return ret;
}

function unique (array) {
	var uniqueArray = [];
	for (var i = 0; i < array.length; i++) {
		var item = array[i];
		if ($.inArray(item, uniqueArray) === -1) {
			uniqueArray.push(item);
		}
	}
	return uniqueArray;
}

function edit (title, prop, change, callback, redir) {
	if (aborted) {
		return callback({editStatus: 'aborted'});
	}

	var queryparam = {
		action: 'query',
		prop: 'info|revisions',
		rvprop: 'timestamp|content',
		intoken: 'edit',
		format: 'json'
	}, editparam = {
		action: 'edit',
		watchlist: 'nochange',
		format: 'json'
	};
	queryparam.titles = title;
	editparam.title = title;
	if (redir) {
		queryparam.redirects = true;
		editparam.redirects = true;
	}
	$.getJSON(mw.util.wikiScript('api'), queryparam, function (json) {
		if (!json || !json.query || !json.query.pages) {
			return callback({editStatus: 'error'});
		}
		var text = '';
		for (var p in json.query.pages) {
			editparam.starttimestamp = json.query.pages[p].starttimestamp.replace(/\D/g, '');
			editparam.basetimestamp = editparam.starttimestamp;
			editparam.token = json.query.pages[p].edittoken;
			if (json.query.pages[p].missing === undefined) {
				editparam.basetimestamp = json.query.pages[p].revisions[0].timestamp.replace(/\D/g, '');
				text = json.query.pages[p].revisions[0]['*'];
			}
		}
		prop.text = text;
		if (editparam.token === '\\+') {
			abort();
			return callback({editStatus: 'lost login, aborted'});
		}
		var ret = change(title, prop);
		if (aborted || !ret) {
			return callback({editStatus: 'aborted'});
		}
		if (ret.text === undefined) {
			return callback({editStatus: 'aborted – ' + ret.reason});
		}
		editparam.text = ret.text;
		editparam.summary = ret.summary;
		if (ret.nominor) {
			editparam.notminor = true;
		} else {
			editparam.minor = true;
		}
		if (!ret.nobot) {
			editparam.bot = true;
		}

		var doEdit = function () {
			$.post(mw.util.wikiScript('api'), editparam, function (json) {
				if (!json) {
					return callback({editStatus: 'error'});
				}
				if (json.edit && json.edit.result === 'Success') {
					return callback({editDone: '', editStatus: 'success'});
				}
				if (json.error && (json.error.code === 'pagedeleted' || json.error.code === 'editconflict')) {
					return callback({editStatus: 'editconflict'});
				}
				callback({editStatus: 'error'});
			});
		};

		var confirm = prop.confirmEdit;
		if (confirm) {
			waitForSchnarkDiffAndDialog(function () {
				var $div = mw.html.element('div', {}, new mw.html.Raw(libs.schnark_diff.html_diff(text, editparam.text))),
					$dialog = $(mw.html.element('div', {title: title + ' – ' + editparam.summary})).append($div);
				if (confirm === 'show' || confirm === 'simulate') {
					$dialog.dialog();
					if (confirm === 'show') {
						executeStoppable(doEdit);
					} else {
						callback({editDone: '', editStatus: 'simulate'});
					}
				} else if (confirm === 'confirm') {
					$dialog.dialog({buttons: {OK: function () {
						$(this).dialog('close');
						executeStoppable(doEdit);
					}, Cancel: function () {
						$(this).dialog('close');
						callback({editStatus: 'aborted by user'});
					}}});
				}
			});
		} else {
			executeStoppable(doEdit);
		}
	});
}

function JSBot (param) {
	if (typeof param === 'string') {
		param = {list: [param]};
	} else if ($.isArray(param)) {
		param = {list: [].slice.call(param)};
	}
	var opt = $.extend({list: [], props: {}, ready: true, callbacks: []}, defaultConfig, param);
	this.list = opt.list;
	this.followredirects = opt.followredirects;
	this.props = opt.props;
	this.max = opt.max;
	this.ready = opt.ready;
	this.callbacks = opt.callbacks;
	return this;
}
function getNewJSBot (that) {
	return new JSBot ({ready: false, max: that.max, followredirects: that.followredirects});
}

JSBot.prototype = {
	set: function (opt) {
		if (opt.max) {
			this.max = opt.max;
		}
		if (opt.followredirects !== undefined) {
			this.followredirects = opt.followredirects;
		}
		return this;
	},

	wait: function (callback) {
		if (this.ready) {
			callback.apply(this);
		} else {
			this.callbacks.push(callback);
		}
		return this;
	},
	toArray: function () {
		return [].slice.call(this.list); //kopieren
	},
	toObject: function (list) {
		if (list === undefined) {
			list = this.list;
		}
		var props = {};
		for (var i = 0; i < list.length; i++) {
			var title = list[i];
			props[title] = $.extend({}, this.props[title]); //kopieren
		}
		return props;
	},
	toString: function (formatter) {
		formatter = getFormatter(formatter);
		var text = formatter.pre;
		for (var i = 0; i < this.list.length; i++) {
			text += formatter.line(this.list[i], this.props[this.list[i]] || {}, i + 1);
		}
		text += formatter.post;
		return text;
	},

	callAPIQueryList: function (list, param, titleFrom, prefix, callback) {
		var _this = this;
		if (_this.followredirects) {
			param.redirects = true;
		}
		param.action = 'query';
		param.list = list;
		param.format = 'json';
		param.rawcontinue = '';
		$.getJSON(mw.util.wikiScript('api'), param, function (json) {
			if (json && json.query && json.query[list]) {
				for (var i = 0; i < json.query[list].length; i++) {
					var	page = json.query[list][i],
						title = page[titleFrom || 'title'];
					if (prefix) {
						title = prefix + title;
					}
					_this.list.push(title);
				}
			}
			if (_this.list.length < _this.max && json && json['query-continue'] && json['query-continue'][list]) {
				_this.callAPIQueryList.apply(_this, [list, $.extend({}, param, json['query-continue'][list]), titleFrom, prefix, callback]);
			} else {
				if (callback) {
					callback.apply(_this);
				} else {
					_this.setReady();
				}
			}
		});
	},
	callAPIQueryPageList: function (param) {
		var _this = this;
		if (_this.followredirects) {
			param.redirects = true;
		}
		param.action = 'query';
		param.list = 'querypage';
		param.format = 'json';
		param.rawcontinue = '';
		$.getJSON(mw.util.wikiScript('api'), param, function (json) {
			if (json && json.query && json.query.querypage && json.query.querypage.results) {
				for (var i = 0; i < json.query.querypage.results.length; i++) {
					_this.list.push(json.query.querypage.results[i].title);
				}
			}
			if (_this.list.length < _this.max && json && json['query-continue'] && json['query-continue'].querypage) {
				_this.callAPIQueryPageList.apply(_this, [$.extend({}, param, json['query-continue'].querypage)]);
			} else {
				_this.setReady();
			}
		});
	},
	callAPIQueryListWithTitles: function (titles, list, title, param) {
		var _this = this;
		_this.list = unique(_this.list);
		if (titles.length === 0 || _this.list.length >= _this.max) {
			return _this.setReady();
		}
		param[title] = titles.pop();
		_this.callAPIQueryList(list, param, undefined, undefined, function () {
			_this.callAPIQueryListWithTitles.apply(_this, [titles, list, title, param]);
		});
	},
	callAPIQueryPropWithTitles: function (titles, prop, param) {
		var _this = this;
		_this.list = unique(_this.list);
		if (titles.length === 0 || _this.list.length >= _this.max) {
			return _this.setReady();
		}
		var fewTitles = titles.splice(0, getMaxTitles());
		_this.callAPIQueryPropWithFewTitles(fewTitles, prop, param, function () {
			_this.callAPIQueryPropWithTitles.apply(_this, [titles, prop, param]);
		});
	},
	callAPIQueryPropWithFewTitles: function (titles, prop, param, callback) {
		var _this = this;
		if (_this.followredirects) {
			param.redirects = true;
		}
		param.action = 'query';
		param.prop = prop;
		param.format = 'json';
		param.rawcontinue = '';
		param.titles = titles.join('|');
		$.getJSON(mw.util.wikiScript('api'), param, function (json) {
			if (json && json.query && json.query.pages) {
				for (var p in json.query.pages) {
					var list = json.query.pages[p][prop] || [];
					for (var i = 0; i < list.length; i++) {
						_this.list.push(list[i].title);
					}
				}
			}
			if (_this.list.length < _this.max && json && json['query-continue'] && json['query-continue'][prop]) {
				_this.callAPIQueryPropWithFewTitles(titles, prop, $.extend({}, param, json['query-continue'][prop]), callback);
			} else {
				callback.apply(_this);
			}
		});
	},
	callAPIQueryPropWithTitlesForInfo: function (titles, param) {
		var _this = this;
		if (titles.length === 0) {
			return _this.setReady();
		}
		var fewTitles = titles.splice(0, getMaxTitles());
		_this.callAPIQueryPropWithFewTitlesForInfo(fewTitles, param, function () {
			_this.callAPIQueryPropWithTitlesForInfo.apply(_this, [titles, param]);
		});
	},
	callAPIQueryPropWithFewTitlesForInfo: function (titles, param, callback) {
		var _this = this;
		var redirects = {};
		if (_this.followredirects) {
			param.redirects = true;
		}
		param.action = 'query';
		param.format = 'json';
		param.rawcontinue = '';
		param.titles = titles.join('|');
		$.getJSON(mw.util.wikiScript('api'), param, function (json) {
			if (json && json.query && json.query.redirects) {
				for (var i = 0; i < json.query.redirects.length; i++) {
					redirects[json.query.redirects[i].to] = json.query.redirects[i].from;
				}
			}
			if (json && json.query && json.query.pages) {
				for (var p in json.query.pages) {
					var title = json.query.pages[p].title;
					if (title in redirects) {
						title = redirects[title];
					}
					extend(_this.props[title], json.query.pages[p]);
				}
			}
			var needContinue = false, continueParam = {};
			if (json && json['query-continue']) {
				for (var cont in json['query-continue']) {
					if (cont === 'iiprop' || cont === 'revisions') {
						continue;
					}
					needContinue = true;
					$.extend(continueParam, json['query-continue'][cont]);
				}
			}
			if (needContinue) {
				_this.callAPIQueryPropWithFewTitlesForInfo(titles, $.extend({}, param, continueParam), callback);
			} else {
				callback.apply(_this);
			}
		});
	},
	callAPIQueryPropWithTitlesHas: function (titles, prop, param) {
		var _this = this;
		if (titles.length === 0) {
			var list = [];
			for (var i = 0; i < _this.list.length; i++) {
				var title = _this.list[i];
				if (_this.props[title].has) {
					delete _this.props[title].has;
					list.push(title);
				}
			}
			_this.list = list;
			return _this.setReady();
		}
		var fewTitles = titles.splice(0, getMaxTitles());
		_this.callAPIQueryPropWithFewTitlesHas(fewTitles, prop, param, function () {
			_this.callAPIQueryPropWithTitlesHas.apply(_this, [titles, prop, param]);
		});
	},
	callAPIQueryPropWithFewTitlesHas: function (titles, prop, param, callback) {
		var _this = this;
		var redirects = {};
		if (_this.followredirects) {
			param.redirects = true;
		}
		param.action = 'query';
		param.prop = prop;
		param.format = 'json';
		param.rawcontinue = '';
		param.titles = titles.join('|');
		$.getJSON(mw.util.wikiScript('api'), param, function (json) {
			if (json && json.query && json.query.redirects) {
				for (var i = 0; i < json.query.redirects.length; i++) {
					redirects[json.query.redirects[i].to] = json.query.redirects[i].from;
				}
			}
			if (json && json.query && json.query.pages) {
				for (var p in json.query.pages) {
					if (json.query.pages[p][prop] && json.query.pages[p][prop].length > 0) {
						var title = json.query.pages[p].title;
						if (title in redirects) {
							title = redirects[title];
						}
						_this.props[title].has = true;
					}
				}
			}
			if (json && json['query-continue'] && json['query-continue'][prop]) {
				_this.callAPIQueryPropWithFewTitlesHas(titles, prop, $.extend({}, param, json['query-continue'][prop]), callback);
			} else {
				callback.apply(_this);
			}
		});
	},
	callAPIPurge: function (titles, param) {
		var _this = this;
		if (titles.length === 0) {
			return _this.setReady();
		}
		var fewTitles = titles.splice(0, getMaxTitles());
		_this.callAPIPurgeWithFewTitles(fewTitles, param, function () {
			_this.callAPIPurge.apply(_this, [titles, param]);
		});
	},
	callAPIPurgeWithFewTitles: function (titles, param, callback) {
		var _this = this;
		param.action = 'purge';
		param.format = 'json';
		param.titles = titles.join('|');
		$.post(mw.util.wikiScript('api'), param, function (json) {
			if (json && json.purge) {
				for (var i = 0; i < json.purge.length; i++) {
					var title = json.purge[i].title;
					$.extend(_this.props[title], json.purge[i]);
				}
			}
			callback();
		});
	},
	setReady: function () {
		this.ready = true;
		while (this.callbacks.length > 0) {
			this.callbacks.pop().apply(this);
		}
	},

	allcategories: function (opt) { //Liste mit (benutzten) Kategorien
		var newJSBot = getNewJSBot(this);
		var param = {aclimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {from: '!'};
		}
		if (opt.from) { //ab diesem String
			param.acfrom = opt.from;
		}
		if (opt.prefix) { //alle mit diesem Präfix
			param.acprefix = opt.prefix;
		}
		if (opt.min) { //Mindestanzahl in Kategorie
			param.acmin = opt.min;
		}
		if (opt.max) { //Maximalanzahl in Kategorie
			param.acmax = opt.max;
		}
		newJSBot.callAPIQueryList('allcategories', param, '*', mw.config.get('wgFormattedNamespaces')['14'] + ':');
		return newJSBot;
	},
	allimages: function (opt) { //Liste mit (benutzten) Dateien
		var newJSBot = getNewJSBot(this);
		var param = {ailimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {from: '!'};
		}
		if (opt.from) {
			param.aifrom = opt.from;
		}
		if (opt.prefix) {
			param.aiprefix = opt.prefix;
		}
		if (opt.min) {
			param.aiminsize = opt.min;
		}
		if (opt.max) {
			param.aimaxsize = opt.max;
		}
		newJSBot.callAPIQueryList('allimages', param);
		return newJSBot;
	},
	allpages: function (opt) { //Liste mit allen Seiten in einem Namensraum
		var newJSBot = getNewJSBot(this);
		var param = {aplimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {from: '!'};
		}
		if (opt.from) {
			param.apfrom = opt.from;
		}
		if (opt.prefix) {
			param.apprefix = opt.prefix;
		}
		if (opt.ns) {
			param.apnamespace = getNS(opt.ns);
		}
		if (opt.redir !== undefined) {
			if (opt.redir) {
				param.apfilterredir = 'redirects';
			} else {
				param.apfilterredir = 'nonredirects';
			}
		}
		if (opt.iw !== undefined) {
			if (opt.iw) {
				param.apfilterlanglinks = 'withlanglinks';
			} else {
				param.apfilterlanglinks = 'withoutlanglinks';
			}
		}
		if (opt.min) {
			param.apminsize = opt.min;
		}
		if (opt.max) {
			param.apmaxsize = opt.max;
		}
		if (opt.protect) {
			param.apprtype = opt.protect.type || 'edit';
			param.apprlevel = opt.protect.level || 'sysop';
			if (opt.protect.cascade !== undefined) {
				if (opt.protect.cascade) {
					param.apprfiltercascade = 'cascading';
				} else {
					param.apprfiltercascade = 'noncascading';
				}
			}
			if (opt.protect.expiry !== undefined) {
				if (opt.protect.expiry) {
					param.apprexpiry = 'definite';
				} else {
					param.apprexpiry = 'indefinite';
				}
			}
		}
		newJSBot.callAPIQueryList('allpages', param);
		return newJSBot;
	},
	allusers: function (opt) { //Liste aller Benutzer
		var newJSBot = getNewJSBot(this);
		var param = {aulimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {from: '!'};
		}
		if (opt.from) {
			param.aufrom = opt.from;
		}
		if (opt.prefix) {
			param.auprefix = opt.prefix;
		}
		if (opt.group) {
			if (opt.invert) {
				param.auexcludegroup = opt.goup;
			} else {
				param.augroup = opt.group;
			}
		}
		if (opt.rights) {
			param.aurights = opt.right;
		}
		if (opt.edits) {
			param.auwitheditsonly = true;
		}
		if (opt.active) {
			param.auactiveusers = true;
		}
		newJSBot.callAPIQueryList('allusers', param, 'name', mw.config.get('wgFormattedNamespaces')['2'] + ':');
		return newJSBot;
	},
	exturlusage: function (opt) { //Liste aller Seiten, die eine URL verlinken
		var newJSBot = getNewJSBot(this);
		var param = {eulimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.url) {
			param.euquery = opt.url;
		}
		if (opt.proto) {
			param.euprotocol = opt.proto;
		}
		if (opt.ns) {
			param.eunamespace = getNS(opt.ns);
		}
		newJSBot.callAPIQueryList('exturlusage', param);
		return newJSBot;
	},
	iwbacklinks: function (opt) { //Liste aller Seiten, die ein anderes Wiki verlinken
		var newJSBot = getNewJSBot(this);
		var param = {iwbllimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.prefix) {
			param.iwblprefix = opt.prefix;
		}
		if (opt.title) {
			param.iwbltitle = opt.title;
		}
		newJSBot.callAPIQueryList('iwbacklinks', param);
		return newJSBot;
	},
	langbacklinks: function (opt) { //Liste aller Seiten, die eine andere Sprache verlinken
		var newJSBot = getNewJSBot(this);
		var param = {lbllimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.lang) {
			param.lbllang = opt.lang;
		}
		if (opt.title) {
			param.lbltitle = opt.title;
		}
		newJSBot.callAPIQueryList('langbacklinks', param);
		return newJSBot;
	},
	querypage: function (opt) {
		var newJSBot = getNewJSBot(this);
		var param = {qpllimit: getMaxLimit(this.max)};
		param.qppage = opt.page;
		newJSBot.callAPIQueryPageList(param);
		return newJSBot;
	},
	recentchanges: function (opt) { //Liste aller in letzter Zeit bearbeiteten Seiten
		var newJSBot = getNewJSBot(this);
		var param = {rclimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.end) {
			param.rcend = opt.end;
		}
		if (opt.ns) {
			param.rcnamespace = getNS(opt.ns);
		}
		if (opt.onlynew) {
			param.rctype = 'new';
		} else {
			param.rctype = 'edit|new';
			param.rctoponly = true;
		}
		if (opt.tag) {
			param.rctag = opt.tag;
		}
		var show = [];
		if (opt.minor !== undefined) {
			if (opt.minor) {
				show.push('minor');
			} else {
				show.push('!minor');
			}
		}
		if (opt.bot !== undefined) {
			if (opt.bot) {
				show.push('bot');
			} else {
				show.push('!bot');
			}
		}
		if (opt.anon !== undefined) {
			if (opt.anon) {
				show.push('anon');
			} else {
				show.push('!anon');
			}
		}
		if (show.length > 0) {
			param.rcshow = show.join('|');
		}
		newJSBot.callAPIQueryList('recentchanges', param);
		return newJSBot;
	},
	search: function (opt) { //Liste aller Seiten mit bestimmtem Text
		var newJSBot = getNewJSBot(this);
		var param = {srlimit: getMaxLimit(this.max, true)};
		param.srsearch = opt.search;
		if (opt.ns) {
			param.srnamespace = getNS(opt.ns);
		}
		if (opt.redir) {
			param.srredirects = true;
		}
		newJSBot.callAPIQueryList('search', param);
		return newJSBot;
	},

	categories: function (opt) { //Liste aller verwendeten Kategorien
		var newJSBot = getNewJSBot(this);
		var param = {cllimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.hidden !== undefined) {
			if (opt.hidden) {
				param.clshow = 'hidden';
			} else {
				param.clshow = '!hidden';
			}
		}
		this.wait(function () {
			newJSBot.callAPIQueryPropWithTitles(this.toArray(), 'categories', param);
		});
		return newJSBot;
	},
	images: function () { //Liste aller verwendeten Dateien
		var newJSBot = getNewJSBot(this);
		this.wait(function(){
			newJSBot.callAPIQueryPropWithTitles(this.toArray(), 'images', {
				imlimit: getMaxLimit(this.max)
			});
		});
		return newJSBot;
	},
	links: function (opt) { //Liste aller verlinkten Seiten
		var newJSBot = getNewJSBot(this);
		var param = {pllimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.ns) {
			param.plnamespace = getNS(opt.ns);
		}
		this.wait(function () {
			newJSBot.callAPIQueryPropWithTitles(this.toArray(), 'links', param);
		});
		return newJSBot;
	},
	templates: function (opt) { //Liste aller verwendeten Vorlagen
		var newJSBot = getNewJSBot(this);
		var param  = {tllimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.ns) {
			param.tlnamespace = getNS(opt.ns);
		}
		this.wait(function () {
			newJSBot.callAPIQueryPropWithTitles(this.toArray(), 'templates', param);
		});
		return newJSBot;
	},
	backlinks: function (opt) { //Liste aller verlinkenden Seiten
		var newJSBot = getNewJSBot(this);
		var param = {bllimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (this.followredirects) {
			param.blredirect = true;
		}
		if (opt.ns) {
			param.blnamespace = getNS(opt.ns);
		}
		if (opt.redir !== undefined) {
			if (opt.redir) {
				param.blfilterredir = 'redirects';
			} else {
				param.blfilterredir = 'nonredirects';
			}
		}
		this.wait(function () {
			newJSBot.callAPIQueryListWithTitles(this.toArray(), 'backlinks', 'bltitle', param);
		});
		return newJSBot;
	},
	categorymembers: function (opt) { //Liste aller direkt in Kategorie einsortierten Seiten
		var newJSBot = getNewJSBot(this);
		var param = {cmlimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.ns) {
			opt.ns = getNS(opt.ns);
			if (opt.ns === '14') { //für MiserMode
				param.cmtype = 'subcat';
			} else if (opt.ns === '6') {
				param.cmtype = 'file';
			} else if (opt.ns === '6|14' || opt.ns === '14|6') {
				param.cmtype = 'file|subcat';
			} else {
				param.cmnamespace = opt.ns;
			}
		}
		this.wait(function () {
			newJSBot.callAPIQueryListWithTitles(this.toArray(), 'categorymembers', 'cmtitle', param);
		});
		return newJSBot;
	},
	categorytree: function () { //Liste aller (auch indirekt) in Kategorie einsortierten Kategorien
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			var todo = this.toArray();
			newJSBot.list = this.toArray();

			var callback = function () {
				if (todo.length === 0 || newJSBot.list.length >= newJSBot.max) {
					return newJSBot.setReady();
				}
				(new JSBot({list: [todo.shift()], max: newJSBot.max}))
					.categorymembers({ns: 'Category'})
					.wait(function () {
						var list = this.toArray();
						for (var i = 0; i < list.length; i++) {
							if ($.inArray(list[i], newJSBot.list) === -1) { //noch unbekannt
								newJSBot.list.push(list[i]);
								todo.push(list[i]);
							}
						}
						callback();
					});
			};
			callback();
		});
		return newJSBot;
	},
	embeddedin: function (opt) { //Liste aller einbindenen Seiten
		var newJSBot = getNewJSBot(this);
		var param = {eilimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.ns) {
			param.einamespace = getNS(opt.ns);
		}
		if (opt.redir !== undefined) {
			if (opt.redir) {
				param.eifilterredir = 'redirects';
			} else {
				param.eifilterredir = 'nonredirects';
			}
		}
		this.wait(function () {
			newJSBot.callAPIQueryListWithTitles(this.toArray(), 'embeddedin', 'eititle', param);
		});
		return newJSBot;
	},
	imageusage: function (opt) { //Liste aller verwendenden Seiten
		var newJSBot = getNewJSBot(this);
		var param = {iulimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (this.followredirects) {
			param.iuredirect = true;
		}
		if (opt.ns) {
			param.iunamespace = getNS(opt.ns);
		}
		if (opt.redir !== undefined) {
			if (opt.redir) {
				param.iufilterredir = 'redirects';
			} else {
				param.iufilterredir = 'nonredirects';
			}
		}
		this.wait(function () {
			newJSBot.callAPIQueryListWithTitles(this.toArray(), 'imageusage', 'iutitle', param);
		});
		return newJSBot;
	},
	usercontribs: function (opt) { //Liste aller bearbeiteten Seiten
		var newJSBot = getNewJSBot(this);
		var param = {uctoponly: true, uclimit: getMaxLimit(this.max)};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.ns) {
			param.ucnamespace = getNS(opt.ns);
		}
		var show = [];
		if (opt.minor !== undefined) {
			if (opt.minor) {
				show.push('minor');
			} else {
				show.push('!minor');
			}
		}
		if (show.length > 0) {
			param.ucshow = show.join('|');
		}
		this.wait(function () {
			var list = this.toArray();
			for (var i = 0; i < list.length; i++) {
				list[i] = list[i].replace(/^[^:]+:/, '');
			}
			newJSBot.callAPIQueryListWithTitles(list, 'usercontribs', 'ucuser', param);
		});
		return newJSBot;
	},

	getProps: function (propList) { //Eigenschaften hinzufügen
		var newJSBot = getNewJSBot(this);
		var prefix = {
			categories: 'cl',
			extlinks: 'el',
			globalusage: 'gu',
			imageinfo: 'ii',
			images: 'im',
			info: 'in',
			iwlinks: 'iw',
			langlinks: 'll',
			links: 'pl',
			pageprops: 'pp',
			revisions: 'rv',
			templates: 'tl'
		};
		var param = {}, props = [], subprops = {}, i;
		for (i = 0; i < propList.length; i++) {
			var prop = propList[i], subprop = '',
				limit = false,
				index = prop.indexOf('.');
			if (index > -1) {
				subprop = prop.substr(index + 1);
				prop = prop.substr(0, index);
			}
			switch (prop) {
			case 'touched':
			case 'lastrevid':
			case 'length':
			case 'redirect':
			case 'new':
				prop = 'info';
				break;
			case 'protection':
			case 'talkid':
			case 'watched':
			case 'subjectid':
			case 'preload':
			case 'displaytitle':
				subprop = prop;
				prop = 'info';
				break;
			case 'editurl':
			case 'fullurl':
				prop = 'info';
				subprop = 'url';
				break;
			case 'categories':
			case 'extlinks':
			case 'globalusage':
			case 'images':
			case 'iwlinks':
			case 'langlinks':
			case 'links':
			case 'templates':
				limit = getMaxLimit();
				break;
			case 'imageinfo':
			case 'revisions':
				limit = 1;
				break;
			}
			if ($.inArray(prop, props) === -1) {
				props.push(prop);
				if (limit) {
					param[prefix[prop] + 'limit'] = limit;
				}
				subprops[prop] = [];
			}
			if (subprop !== '' && $.inArray(subprop, subprops[prop]) === -1) {
				subprops[prop].push(subprop);
			}
		}
		if (props.length > 0) {
			param.prop = props.join('|');
		}
		for (i = 0; i < props.length; i++) {
			if (subprops[props[i]].length > 0) {
				param[prefix[props[i]] + 'prop'] = subprops[props[i]].join('|');
			}
		}
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			newJSBot.callAPIQueryPropWithTitlesForInfo(this.toArray(), param); //andere Kopie als newJSBot.list
		});
		return newJSBot;
	},
	addProps: function (f) {
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			for (var i = 0; i < newJSBot.list.length; i++) {
				var title = newJSBot.list[i];
				$.extend(true, newJSBot.props[title], f(title, newJSBot.props[title]));
			}
			newJSBot.setReady();
		});
		return newJSBot;
	},
	userconfirm: function (formatter) {
		formatter = formatter || {pre: '<ul>', post: '</ul>', line: function (t, p, n) { //FIXME
			return '<li><input type="checkbox"' + (p.selected === '' ? ' checked="checked"' : '') + '>' + t + '</li>';
		}};
		mw.loader.load('jquery.ui');
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			var i, html = formatter.pre;
			for (i = 0; i < newJSBot.list.length; i++) {
				html += formatter.line(this.list[i], this.props[this.list[i]] || {}, i + 1);
			}
			html += formatter.post;
			var $div = $(mw.html.element('div', {style: 'over' + 'flow:auto; height: 30em;'})).html(html); //blöder Spamschutzfilter
			mw.loader.using('jquery.ui', function () {
				$(mw.html.element('div', {title: 'Auswahl'})).append($div).dialog({buttons: {OK: function () {
					$(this).dialog('close');
					var $checkboxes = $div.find('input[type="checkbox"]');
					for (i = 0; i < newJSBot.list.length; i++) {
						var title = newJSBot.list[i];
						if ($checkboxes.eq(i).prop('checked')) {
							newJSBot.props[title].selected = '';
						} else {
							delete newJSBot.props[title].selected;
						}
					}
					newJSBot.setReady();
				}}});
			});
		});
		return newJSBot;
	},

	hasCategories: function (opt) { //nach Seiten filtern, die in bestimmten Kategorien sind
		var newJSBot = getNewJSBot(this);
		var param = {cllimit: getMaxLimit(), clcategories: opt.categories};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.hidden !== undefined) {
			if (opt.hidden) {
				param.clshow = 'hidden';
			} else {
				param.clshow = '!hidden';
			}
		}
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			newJSBot.callAPIQueryPropWithTitlesHas(this.toArray(), 'categories', param);
		});
		return newJSBot;
	},
	hasImages: function (opt) { //nach Seiten filtern, die bestimmte Dateien verwenden
		var newJSBot = getNewJSBot(this);
		var param = {imlimit: getMaxLimit(), imimages: opt.images};
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			newJSBot.callAPIQueryPropWithTitlesHas(this.toArray(), 'images', param);
		});
		return newJSBot;
	},
	hasLinks: function (opt) { //nach Seiten flitern, die bestimmte Seiten verlinken
		var newJSBot = getNewJSBot(this);
		var param = {pllimit: getMaxLimit(), pltitles: opt.links};
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			newJSBot.callAPIQueryPropWithTitlesHas(this.toArray(), 'links', param);
		});
		return newJSBot;
	},
	hasTemplates: function (opt) { //nach Seiten filtern, die bestimmte Vorlagen verwenden
		var newJSBot = getNewJSBot(this);
		var param  = {tllimit: getMaxLimit(), tltemplates: opt.templates};
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			newJSBot.callAPIQueryPropWithTitlesHas(this.toArray(), 'templates', param);
		});
		return newJSBot;
	},
	filter: function (f) {
		var _this = this;
		var newJSBot = getNewJSBot(_this);
		_this.wait(function () {
			var list = _this.toArray(), n = 0;
			newJSBot.list = $.grep(list, function (p) {
				return f(p, _this.props[p] || {}, ++n);
			});
			newJSBot.props = _this.toObject(newJSBot.list);
			newJSBot.setReady();
		});
		return newJSBot;
	},

	map: function (f) {
		var _this = this;
		var newJSBot = getNewJSBot(_this);
		_this.wait(function () {
			var list = _this.toArray();
			newJSBot.list = $.map(list, function (t, n) {
				return f(t, _this.props[t] || {}, n);
			});
			newJSBot.setReady();
		});
		return newJSBot;
	},

	sort: function (f) {
		var _this = this;
		var newJSBot = getNewJSBot(_this);
		_this.wait(function () {
			newJSBot.list = _this.toArray();
			newJSBot.props = _this.toObject();
			newJSBot.list.sort(function (a, b) {
				return f({title: a, props: newJSBot.props[a]}, {title: b, props: newJSBot.props[b]});
			});
			newJSBot.setReady();
		});
		return newJSBot;
	},

	add: function (pages) { //fügt einzelne Seiten hinzu
		if (!$.isArray(pages)) {
			this.list.push(pages);
		} else {
			this.list = this.list.concat(pages);
		}
		return this;
	},
	and: function (bot) {
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			var list1 = this.toArray();
			newJSBot.props = this.toObject();
			bot.wait(function () {
				var list2 = bot.toArray();
				for (var i = 0; i < list1.length; i++) {
					if ($.inArray(list1[i], list2) > -1) {
						newJSBot.list.push(list1[i]);
					}
				}
				$.extend(true, newJSBot.props, bot.toObject(newJSBot.list));
				newJSBot.setReady();
			});
		});
		return newJSBot;
	},
	or: function (bot) {
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			var list = this.toArray();
			newJSBot.props = this.toObject();
			bot.wait(function () {
				list = list.concat(bot.toArray());
				newJSBot.list = unique(list);
				$.extend(true, newJSBot.props, bot.toObject());
				newJSBot.setReady();
			});
		});
		return newJSBot;
	},
	not: function (bot) {
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			var list1 = this.toArray();
			newJSBot.props = this.toObject();
			bot.wait(function () {
				var list2 = bot.toArray();
				for (var i = 0; i < list1.length; i++) {
					if ($.inArray(list1[i], list2) === -1) {
						newJSBot.list.push(list1[i]);
					}
				}
				newJSBot.setReady();
			});
		});
		return newJSBot;
	},

	alert: function (formatter, logger) {
		var _this = this;
		_this.wait(function () {
			var msg = _this.toString(formatter);
			if (logger) {
				logger(msg);
			} else {
				window.alert(msg);
			}
		});
		return _this;
	},
	show: function (formatter) {
		mw.loader.load('jquery.ui');
		return this.alert(formatter, function (wiki) {
			var param = {
				action: 'parse',
				text: wiki,
				prop: 'text',
				pst: true,
				format: 'json'
			};
			$.getJSON(mw.util.wikiScript('api'), param, function (json) {
				var html = '';
				if (json && json.parse && json.parse.text) {
					html = json.parse.text['*'];
				}
				if (html) {
					html += mw.html.element('hr');
				}
				html += mw.html.element('textarea', {rows: 10}, wiki);
				var $div = $(mw.html.element('div', {style: 'over' + 'flow:auto; height: 30em;'})).html(html); //blöder Spamschutzfilter
				mw.loader.using('jquery.ui', function () {
					$(mw.html.element('div', {title: 'Ergebnis'})).append($div).dialog();
				});
			});
		});
	},
	purge: function (opt) {
		var newJSBot = getNewJSBot(this);
		var param = {};
		if (opt === undefined) {
			opt = {};
		}
		if (opt.force) {
			param.forcelinkupdate = true;
		}
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			newJSBot.callAPIPurge(this.toArray(), param);
		});
		return newJSBot;
	},
	edit: function (change, confirm, delay) {
		var newJSBot = getNewJSBot(this);
		if (delay === undefined) {
			delay = 10;
		}
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			var toEdit = 0;
			function editNext () {
				if (toEdit === newJSBot.list.length) {
					newJSBot.setReady();
				} else {
					var title = newJSBot.list[toEdit++];
					if (confirm) {
						newJSBot.props[title].confirmEdit = confirm;
					}
					edit(title, newJSBot.props[title], change, function (prop) {
						$.extend(newJSBot.props[title], prop);
						var ms = prop.editDone === '' ? delay * 1000 : 0;
						window.setTimeout(editNext, ms);
					}, this.followredirects);
				}
			}
			editNext();
		});
		return newJSBot;
	},
	autoedit: function (opt) {
		var newJSBot = getNewJSBot(this);
		this.wait(function () {
			newJSBot.list = this.toArray();
			newJSBot.props = this.toObject();
			libs.autoedit.massedit(this.toArray(), opt, function (a, b, c, status) {
				for (var title in status) {
					newJSBot.props[title].status = status[title];
				}
				newJSBot.setReady();
			});
		});
		return newJSBot;
	},
	dump: function (opt) {
		if (opt === undefined) {
			opt = {};
		}
		return this.wait(function () {
			var param = {pages: this.toString(), wpDownload: true};
			if (!opt.history) {
				param.curonly = true;
			}
			if (opt.templates) {
				param.templates = true;
			}
			document.location.href = mw.util.getUrl('Special:Export', param);
		});
	}
};

libs.JSBot = JSBot;
libs.JSBotFn = {
	version: version,
	defaultConfig: defaultConfig,
	isBot: isBot,
	stop: stop,
	cont: cont,
	abort: abort,
	stopOnNewMessage: stopOnNewMessage
};

$(document).trigger('loadWikiScript', ['Benutzer:Schnark/js/bot.js', null]);

})(jQuery, mw.libs);
//</nowiki>