مدیاویکی:Gadget-twinkleblock-2022.js

از ویکی‌پدیا، دانشنامهٔ آزاد

نکته: برای دیدن تغییرات، ممکن است نیاز باشد که حافظهٔ نهانی مرورگر خود را پس از انتشار پاک‌سازی کنید. گوگل کروم، فایرفاکس، مایکروسافت اج و سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload در نوار ابزار مرورگر کلیک کنید. برای آگاهی از جزئیات و نحوهٔ پاک‌سازی حافظهٔ نهانی سایر مرورگرها، صفحهٔ ویکی‌پدیا:میانگیر مرورگرتان را خالی کنید را ببینید.

// <nowiki>


(function($) {

var api = new mw.Api(), relevantUserName, blockedUserName;
var menuFormattedNamespaces = $.extend({}, mw.config.get('wgFormattedNamespaces'));
menuFormattedNamespaces[0] = '(مقاله)';
var logActionsTranslations = {
	'block': 'قطع دسترسی شده',
	'reblock': 'قطع دسترسی مجدد',
	'unblock': 'بازشده'
};

/*
 ****************************************
 *** twinkleblock.js: Block module
 ****************************************
 * Mode of invocation:     Tab ("Block")
 * Active on:              Any page with relevant user name (userspace, contribs, etc.)
 */

Twinkle.block = function twinkleblock() {
	relevantUserName = mw.config.get('wgRelevantUserName');
	// should show on Contributions or Block pages, anywhere there's a relevant user
	// Ignore ranges wider than the CIDR limit
	if (Morebits.userIsSysop && relevantUserName && (!Morebits.ip.isRange(relevantUserName) || Morebits.ip.validCIDR(relevantUserName))) {
		Twinkle.addPortletLink(Twinkle.block.callback, 'قطع دسترسی', 'tw-block', 'قطع دسترسی کاربر مرتبط');
	}
};

Twinkle.block.callback = function twinkleblockCallback() {
	if (relevantUserName === mw.config.get('wgUserName') &&
			!confirm('شما در حال قطع دسترسی خودتان هستید! آیا مطمئن هستید که می‌خواهید ادامه دهید؟')) {
		return;
	}

	Twinkle.block.currentBlockInfo = undefined;
	Twinkle.block.field_block_options = {};
	Twinkle.block.field_template_options = {};

	var Window = new Morebits.simpleWindow(650, 530);
	// need to be verbose about who we're blocking
	Window.setTitle('قطع دسترسی یا ارسال اعلان قطع دسترسی برای ' + relevantUserName);
	Window.setScriptName('توینکل');
	Window.addFooterLink('الگوهای قطع دسترسی', 'الگو:قطع_دسترسی/توضیحات/الگوهای_قطع_دسترسی');
	Window.addFooterLink('سیاست قطع دسترسی', 'وپ:قطع دسترسی');
	Window.addFooterLink('ترجیحات قطع دسترسی', 'وپ:توینکل/ترجیحات#بستن کاربر');
	Window.addFooterLink('راهنمای توینکل', 'وپ:توتو#بستن');
	Window.addFooterLink('ارائهٔ بازخورد', 'بوپ:توینکل');

	// Always added, hidden later if actual user not blocked
	Window.addFooterLink('باز کردن کاربر', 'ویژه:باز کردن/' + relevantUserName, true);

	var form = new Morebits.quickForm(Twinkle.block.callback.evaluate);
	var actionfield = form.append({
		type: 'field',
		label: 'نوع عمل'
	});
	actionfield.append({
		type: 'checkbox',
		name: 'actiontype',
		event: Twinkle.block.callback.change_action,
		list: [
			{
				label: 'قطع دسترسی کاربر',
				value: 'block',
				tooltip: 'قطع دسترسی کاربر مرتبط با تنظیمات مشخص‌شده. اگر قطع دسترسی موردی غیرفعال شود، این قطع دسترسی به‌صورت کلی خواهد بود.',
				checked: true
			},
			{
				label: 'قطع دسترسی موردی',
				value: 'partial',
				tooltip: 'فعال‌سازی قطع دسترسی موردی و الگوهای قطع دسترسی موردی.',
				checked: Twinkle.getPref('defaultToPartialBlocks') // Overridden if already blocked
			},
			{
				label: 'افزودن الگوی قطع دسترسی به صفحهٔ بحث کاربر',
				value: 'template',
				tooltip: 'اگر مدیر قطع‌کنندهٔ دسترسی فراموش کرده‌است که الگوی قطع دسترسی را ارسال کند، یا این که خودتان دسترسی کاربر را هم‌اکنون بدون ارسال الگو قطع کرده‌اید، می‌توانید از این گزینه برای ارسال الگوی مناسب استفاده کنید. برای مشاهدهٔ الگوهای قطع دسترسی موردی، گزینهٔ قطع دسترسی موردی را فعال کنید.',
				// Disallow when viewing the block dialog on an IP range
				checked: !Morebits.ip.isRange(relevantUserName),
				disabled: Morebits.ip.isRange(relevantUserName)
			}
		]
	});

	/*
	  Add option for IPv6 ranges smaller than /64 to upgrade to the 64
	  CIDR ([[WP:/64]]).  This is one of the few places where we want
	  wgRelevantUserName since this depends entirely on the original user.
	  In theory, we shouldn't use Morebits.ip.get64 here since since we want
	  to exclude functionally-equivalent /64s.  That'd be:
	  // if (mw.util.isIPv6Address(mw.config.get('wgRelevantUserName'), true) &&
	  // (mw.util.isIPv6Address(mw.config.get('wgRelevantUserName')) || parseInt(mw.config.get('wgRelevantUserName').replace(/^(.+?)\/?(\d{1,3})?$/, '$2'), 10) > 64)) {
	  In practice, though, since functionally-equivalent ranges are
	  (mis)treated as separate by MediaWiki's logging ([[phab:T146628]]),
	  using Morebits.ip.get64 provides a modicum of relief in thise case.
	*/
	var sixtyFour = Morebits.ip.get64(mw.config.get('wgRelevantUserName'));
	if (sixtyFour && sixtyFour !== mw.config.get('wgRelevantUserName')) {
		var block64field = form.append({
			type: 'field',
			label: 'تبدیل به قطع دسترسی بازهٔ /64',
			name: 'field_64'
		});
		block64field.append({
			type: 'div',
			style: 'margin-bottom: 0.5em',
			label: ['حتی اگر بهتر نباشد، معمولاً خوب است که ', $.parseHTML('<a target="_blank" href="' + mw.util.getUrl('WP:/64') + '">تنها بازهٔ /64 را ببندید</a>')[0], ' (',
				$.parseHTML('<a target="_blank" href="' + mw.util.getUrl('ویژه:مشارکت‌ها/' + sixtyFour) + '">' + sixtyFour + '</a>)')[0], ').']
		});
		block64field.append({
			type: 'checkbox',
			name: 'block64',
			event: Twinkle.block.callback.change_block64,
			list: [{
				checked: Twinkle.getPref('defaultToBlock64'),
				label: 'قطع دسترسی بازهٔ /64',
				value: 'block64',
				tooltip: Morebits.ip.isRange(mw.config.get('wgRelevantUserName')) ? 'از قرار دادن الگو اجتناب خواهد شد.' : 'هر الگویی که ارسال شود، به دست آی‌پی  اصلی خواهد رسید: ' + mw.config.get('wgRelevantUserName')
			}]
		});
	}

	form.append({ type: 'field', label: 'پیش‌تنظیم', name: 'field_preset' });
	form.append({ type: 'field', label: 'گزینه‌های الگو', name: 'field_template_options' });
	form.append({ type: 'field', label: 'گزینه‌های قطع دسترسی', name: 'field_block_options' });

	form.append({ type: 'submit' });

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

	Twinkle.block.fetchUserInfo(function() {
		// Toggle initial partial state depending on prior block type,
		// will override the defaultToPartialBlocks pref
		if (blockedUserName === relevantUserName) {
			$(result).find('[name=actiontype][value=partial]').prop('checked', Twinkle.block.currentBlockInfo.partial === '');
		}

		// clean up preset data (defaults, etc.), done exactly once, must be before Twinkle.block.callback.change_action is called
		Twinkle.block.transformBlockPresets();

		// init the controls after user and block info have been fetched
		var evt = document.createEvent('Event');
		evt.initEvent('change', true, true);

		if (result.block64 && result.block64.checked) {
			// Calls the same change_action event once finished
			result.block64.dispatchEvent(evt);
		} else {
			result.actiontype[0].dispatchEvent(evt);
		}
	});
};

// Store fetched user data, only relevant if switching IPv6 to a /64
Twinkle.block.fetchedData = {};
// Processes the data from a a query response, separated from
// Twinkle.block.fetchUserInfo to allow reprocessing of already-fetched data
Twinkle.block.processUserInfo = function twinkleblockProcessUserInfo(data, fn) {
	var blockinfo = data.query.blocks[0],
		userinfo = data.query.users[0];
	// If an IP is blocked *and* rangeblocked, the above finds
	// whichever block is more recent, not necessarily correct.
	// Three seems... unlikely
	if (data.query.blocks.length > 1 && blockinfo.user !== relevantUserName) {
		blockinfo = data.query.blocks[1];
	}
	// Cache response, used when toggling /64 blocks
	Twinkle.block.fetchedData[userinfo.name] = data;

	Twinkle.block.isRegistered = !!userinfo.userid;
	if (Twinkle.block.isRegistered) {
		Twinkle.block.userIsBot = !!userinfo.groupmemberships && userinfo.groupmemberships.map(function(e) {
			return e.group;
		}).indexOf('bot') !== -1;
	} else {
		Twinkle.block.userIsBot = false;
	}

	if (blockinfo) {
		// handle frustrating system of inverted boolean values
		blockinfo.disabletalk = blockinfo.allowusertalk === undefined;
		blockinfo.hardblock = blockinfo.anononly === undefined;
	}
	// will undefine if no blocks present
	Twinkle.block.currentBlockInfo = blockinfo;
	blockedUserName = Twinkle.block.currentBlockInfo && Twinkle.block.currentBlockInfo.user;

	// Toggle unblock link if not the user in question; always first
	var unblockLink = document.querySelector('.morebits-dialog-footerlinks a');
	if (blockedUserName !== relevantUserName) {
		unblockLink.hidden = true, unblockLink.nextSibling.hidden = true; // link+trailing bullet
	} else {
		unblockLink.hidden = false, unblockLink.nextSibling.hidden = false; // link+trailing bullet
	}

	// Semi-busted on ranges, see [[phab:T270737]] and [[phab:T146628]].
	// Basically, logevents doesn't treat functionally-equivalent ranges
	// as equivalent, meaning any functionally-equivalent IP range is
	// misinterpreted by the log throughout.  Without logevents
	// redirecting (like Special:Block does) we would need a function to
	// parse ranges, which is a pain.  IPUtils has the code, but it'd be a
	// lot of cruft for one purpose.
	Twinkle.block.hasBlockLog = !!data.query.logevents.length;
	Twinkle.block.blockLog = Twinkle.block.hasBlockLog && data.query.logevents;
	// Used later to check if block status changed while filling out the form
	Twinkle.block.blockLogId = Twinkle.block.hasBlockLog ? data.query.logevents[0].logid : false;

	if (typeof fn === 'function') {
		return fn();
	}
};

Twinkle.block.fetchUserInfo = function twinkleblockFetchUserInfo(fn) {
	var query = {
		format: 'json',
		action: 'query',
		list: 'blocks|users|logevents',
		letype: 'block',
		lelimit: 1,
		letitle: 'کاربر:' + relevantUserName,
		bkprop: 'expiry|reason|flags|restrictions|range|user',
		ususers: relevantUserName
	};

	// bkusers doesn't catch single IPs blocked as part of a range block
	if (mw.util.isIPAddress(relevantUserName, true)) {
		query.bkip = relevantUserName;
	} else {
		query.bkusers = relevantUserName;
		// groupmemberships only relevant for registered users
		query.usprop = 'groupmemberships';
	}

	api.get(query).then(function(data) {
		Twinkle.block.processUserInfo(data, fn);
	}, function(msg) {
		Morebits.status.init($('div[name="currentblock"] span').last()[0]);
		Morebits.status.warn('خطا در واکشی اطلاعات کاربر', msg);
	});
};

Twinkle.block.callback.saveFieldset = function twinkleblockCallbacksaveFieldset(fieldset) {
	Twinkle.block[$(fieldset).prop('name')] = {};
	$(fieldset).serializeArray().forEach(function(el) {
		// namespaces and pages for partial blocks are overwritten
		// here, but we're handling them elsewhere so that's fine
		Twinkle.block[$(fieldset).prop('name')][el.name] = el.value;
	});
};

Twinkle.block.callback.change_block64 = function twinkleblockCallbackChangeBlock64(e) {
	var $form = $(e.target.form), $block64 = $form.find('[name=block64]');

	// Show/hide block64 button
	// Single IPv6, or IPv6 range smaller than a /64
	var priorName = relevantUserName;
	if ($block64.is(':checked')) {
		relevantUserName = Morebits.ip.get64(mw.config.get('wgRelevantUserName'));
	} else {
		relevantUserName = mw.config.get('wgRelevantUserName');
	}
	// No templates for ranges, but if the original user is a single IP, offer the option
	// (done separately in Twinkle.block.callback.issue_template)
	var originalIsRange = Morebits.ip.isRange(mw.config.get('wgRelevantUserName'));
	$form.find('[name=actiontype][value=template]').prop('disabled', originalIsRange).prop('checked', !originalIsRange);

	// Refetch/reprocess user info then regenerate the main content
	var regenerateForm = function() {
		// Tweak titlebar text.  In theory, we could save the dialog
		// at initialization and then use `.setTitle` or
		// `dialog('option', 'title')`, but in practice that swallows
		// the scriptName and requires `.display`ing, which jumps the
		// window.  It's just a line of text, so this is fine.
		var titleBar = document.querySelector('.ui-dialog-title').firstChild.nextSibling;
		titleBar.nodeValue = titleBar.nodeValue.replace(priorName, relevantUserName);
		// Tweak unblock link
		var unblockLink = document.querySelector('.morebits-dialog-footerlinks a');
		unblockLink.href = unblockLink.href.replace(priorName, relevantUserName);
		unblockLink.title = unblockLink.title.replace(priorName, relevantUserName);

		// Correct partial state
		$form.find('[name=actiontype][value=partial]').prop('checked', Twinkle.getPref('defaultToPartialBlocks'));
		if (blockedUserName === relevantUserName) {
			$form.find('[name=actiontype][value=partial]').prop('checked', Twinkle.block.currentBlockInfo.partial === '');
		}

		// Set content appropriately
		Twinkle.block.callback.change_action(e);
	};

	if (Twinkle.block.fetchedData[relevantUserName]) {
		Twinkle.block.processUserInfo(Twinkle.block.fetchedData[relevantUserName], regenerateForm);
	} else {
		Twinkle.block.fetchUserInfo(regenerateForm);
	}
};

Twinkle.block.callback.change_action = function twinkleblockCallbackChangeAction(e) {
	var field_preset, field_template_options, field_block_options, $form = $(e.target.form);
	// Make ifs shorter
	var blockBox = $form.find('[name=actiontype][value=block]').is(':checked');
	var templateBox = $form.find('[name=actiontype][value=template]').is(':checked');
	var $partial = $form.find('[name=actiontype][value=partial]');
	var partialBox = $partial.is(':checked');
	var blockGroup = partialBox ? Twinkle.block.blockGroupsPartial : Twinkle.block.blockGroups;

	$partial.prop('disabled', !blockBox && !templateBox);

	// Add current block parameters as default preset
	var prior = { label: 'قطع دسترسی پیشین' };
	if (blockedUserName === relevantUserName) {
		Twinkle.block.blockPresetsInfo.prior = Twinkle.block.currentBlockInfo;
		// value not a valid template selection, chosen below by setting templateName
		prior.list = [{ label: 'تنظیمات قطع دسترسی پیشین', value: 'prior', selected: true }];

		// Arrays of objects are annoying to check
		if (!blockGroup.some(function(bg) {
			return bg.label === prior.label;
		})) {
			blockGroup.push(prior);
		}

		// Always ensure proper template exists/is selected when switching modes
		if (partialBox) {
			Twinkle.block.blockPresetsInfo.prior.templateName = Morebits.string.isInfinity(Twinkle.block.currentBlockInfo.expiry) ? 'هبک-بستن موردی بی‌پایان' : 'هبک-بستن موردی';
		} else {
			if (!Twinkle.block.isRegistered) {
				Twinkle.block.blockPresetsInfo.prior.templateName = 'هبک-قطع دسترسی ناشناس';
			} else {
				Twinkle.block.blockPresetsInfo.prior.templateName = Morebits.string.isInfinity(Twinkle.block.currentBlockInfo.expiry) ? 'هبک-قطع دسترسی بی‌پایان' : 'هبک-قطع دسترسی';
			}
		}
	} else {
		// But first remove any prior prior
		blockGroup = blockGroup.filter(function(bg) {
			return bg.label !== prior.label;
		});
	}

	// Can be in preset or template field, so the old one in the template
	// field will linger. No need to keep the old value around, so just
	// remove it; saves trouble when hiding/evaluating
	$form.find('[name=dstopic]').parent().remove();

	Twinkle.block.callback.saveFieldset($('[name=field_block_options]'));
	Twinkle.block.callback.saveFieldset($('[name=field_template_options]'));

	if (blockBox) {
		field_preset = new Morebits.quickForm.element({ type: 'field', label: 'پیش‌تنظیم', name: 'field_preset' });
		field_preset.append({
			type: 'select',
			name: 'preset',
			label: 'یک پیش‌تنظیم را انتخاب کنید:',
			event: Twinkle.block.callback.change_preset,
			list: Twinkle.block.callback.filtered_block_groups(blockGroup)
		});

		field_block_options = new Morebits.quickForm.element({ type: 'field', label: 'گزینه‌های قطع دسترسی', name: 'field_block_options' });
		field_block_options.append({ type: 'div', name: 'currentblock', label: ' ' });
		field_block_options.append({ type: 'div', name: 'hasblocklog', label: ' ' });
		field_block_options.append({
			type: 'select',
			name: 'expiry_preset',
			label: 'انقضاء:',
			event: Twinkle.block.callback.change_expiry,
			list: [
				{ label: 'سفارشی', value: 'custom', selected: true },
				{ label: 'بی‌پایان', value: 'infinity' },
				{ label: '۳ ساعت', value: '3 hours' },
				{ label: '۱۲ ساعت', value: '12 hours' },
				{ label: '۲۴ ساعت', value: '24 hours' },
				{ label: '۳۱ ساعت', value: '31 hours' },
				{ label: '۳۶ ساعت', value: '36 hours' },
				{ label: '۴۸ ساعت', value: '48 hours' },
				{ label: '۶۰ ساعت', value: '60 hours' },
				{ label: '۷۲ ساعت', value: '72 hours' },
				{ label: '۱ هفته', value: '1 week' },
				{ label: '۲ هفته', value: '2 weeks' },
				{ label: '۱ ماه', value: '1 month' },
				{ label: '۳ ماه', value: '3 months' },
				{ label: '۶ ماه', value: '6 months' },
				{ label: '۱ سال', value: '1 year' },
				{ label: '۲ سال', value: '2 years' },
				{ label: '۳ سال', value: '3 years' }
			]
		});
		field_block_options.append({
			type: 'input',
			name: 'expiry',
			label: 'انقضای سفارشی',
			tooltip: 'می‌توانید از زمان نسبی نظیر «1 minute» یا «19 days» یا برچسب زمان دقیق مانند «yyyymmddhhmm» (برای مثال، «200602011405» برابر با ۱ فوریه ۲۰۰۶ ساعت ۱۴:۰۵  UTC است) استفاده کنید.',
			value: Twinkle.block.field_block_options.expiry || Twinkle.block.field_template_options.template_expiry
		});

		if (partialBox) { // Partial block
			field_block_options.append({
				type: 'select',
				multiple: true,
				name: 'pagerestrictions',
				label: 'صفحه‌های خاص برای قطع دسترسی ویرایشی',
				value: '',
				tooltip: 'حداکثر ۱۰ صفحه.'
			});
			var ns = field_block_options.append({
				type: 'select',
				multiple: true,
				name: 'namespacerestrictions',
				label: 'قطع دسترسی از فضاین ام',
				value: '',
				tooltip: 'قطع دسترسی ویرایشی کاربر در این فضاهای نام.'
			});
			$.each(menuFormattedNamespaces, function(number, name) {
				// Ignore -1: Special; -2: Media; and 2300-2303: Gadget (talk) and Gadget definition (talk)
				if (number >= 0 && number < 830) {
					ns.append({ type: 'option', label: name, value: number });
				}
			});
		}

		var blockoptions = [
			{
				checked: Twinkle.block.field_block_options.nocreate,
				label: 'جلوگیری از ایجاد حساب',
				name: 'nocreate',
				value: '1'
			},
			{
				checked: Twinkle.block.field_block_options.noemail,
				label: 'جلوگیری از ارسال ایمیل توسط کاربر',
				name: 'noemail',
				value: '1'
			},
			{
				checked: Twinkle.block.field_block_options.disabletalk,
				label: 'جلوگیری از ویرایش صفحهٔ بحث توسط کاربر در زمان بسته بودن',
				name: 'disabletalk',
				value: '1',
				tooltip: partialBox ? 'اگر در حال اعمال قطع دسترسی موردی هستید، این گزینه را نباید فعال کنید؛ مگر آن که قصد داشته باشید دسترسی کاربر به فضای نام بحث کاربر را نیز ببندید' : ''
			}
		];

		if (Twinkle.block.isRegistered) {
			blockoptions.push({
				checked: Twinkle.block.field_block_options.autoblock,
				label: 'قطع دسترسی خودکار نشانی‌های آی‌پی مورد استفادهٔ کاربر (قطع دسترسی سخت)',
				name: 'autoblock',
				value: '1'
			});
		} else {
			blockoptions.push({
				checked: Twinkle.block.field_block_options.hardblock,
				label: 'قطع دسترسی کاربران وارد شده به سامانه که از این نشانی آی‌پی استفاده می‌کنند (قطع دسترسی سخت)',
				name: 'hardblock',
				value: '1'
			});
		}

		blockoptions.push({
			checked: Twinkle.block.field_block_options.watchuser,
			label: 'پی‌گیری صفحه‌های کاربری و بحث کاربر',
			name: 'watchuser',
			value: '1'
		});

		field_block_options.append({
			type: 'checkbox',
			name: 'blockoptions',
			list: blockoptions
		});
		field_block_options.append({
			type: 'textarea',
			label: 'دلیل (برای درج در سیاههٔ قطع دسترسی):',
			name: 'reason',
			tooltip: 'لطفاً جزئیات مفید را به ادامهٔ دلیل پیش‌فرض اضافه کنید.',
			value: Twinkle.block.field_block_options.reason
		});

		field_block_options.append({
			type: 'div',
			name: 'filerlog_label',
			label: 'همچنین ببینید:',
			style: 'display:inline-block;font-style:normal !important',
			tooltip: 'درج یک پیام «همچنین ببینید» برای نشان دادن این که سیاههٔ پالایه یا مشارکت‌های حذف‌شده نقشی در تصمیم‌گیری برای قطع دسترسی کاربر داشته‌اند.'
		});
		field_block_options.append({
			type: 'checkbox',
			name: 'filter_see_also',
			event: Twinkle.block.callback.toggle_see_alsos,
			style: 'display:inline-block; margin-left:5px',
			list: [
				{
					label: 'سیاههٔ پالایه',
					checked: false,
					value: 'سیاههٔ پالایه'
				}
			]
		});
		field_block_options.append({
			type: 'checkbox',
			name: 'deleted_see_also',
			event: Twinkle.block.callback.toggle_see_alsos,
			style: 'display:inline-block',
			list: [
				{
					label: 'مشارکت‌های حذف‌شده',
					checked: false,
					value: 'مشارکت‌های حذف‌شده'
				}
			]
		});

		// Yet-another-logevents-doesn't-handle-ranges-well
		if (blockedUserName === relevantUserName) {
			field_block_options.append({ type: 'hidden', name: 'reblock', value: '1' });
		}
	}

	// grab discretionary sanctions list from en-wiki
	/* Twinkle.block.dsinfo = Morebits.wiki.getCachedJson('Template:Ds/topics.json');

	Twinkle.block.dsinfo.then(function(dsinfo) {
		var $select = $('[name="dstopic"]');
		var $options = $.map(dsinfo, function (value, key) {
			return $('<option>').val(value.code).text(key).prop('label', key);
		});
		$select.append($options);
	}); */

	// DS selection visible in either the template field set or preset,
	// joint settings saved here
	/* var dsSelectSettings = {
		type: 'select',
		name: 'dstopic',
		label: 'DS topic',
		value: '',
		tooltip: 'If selected, it will inform the template and may be added to the blocking message',
		event: Twinkle.block.callback.toggle_ds_reason
	}; */
	if (templateBox) {
		field_template_options = new Morebits.quickForm.element({ type: 'field', label: 'گزینه‌های الگو', name: 'field_template_options' });
		field_template_options.append({
			type: 'select',
			name: 'template',
			label: 'الگوی صفحهٔ بحث را انتخاب کنید:',
			event: Twinkle.block.callback.change_template,
			list: Twinkle.block.callback.filtered_block_groups(blockGroup, true),
			value: Twinkle.block.field_template_options.template
		});

		// Only visible for aeblock and aepblock, toggled in change_template
		// field_template_options.append(dsSelectSettings);

		field_template_options.append({
			type: 'input',
			name: 'article',
			label: 'صفحه برای پیوند دادن',
			value: '',
			tooltip: 'اگر صفحهٔ خاصی هدف اخلالگری بوده، می‌توان آن را از درون الگو پیوند داد. برای جلوگیری از پیونددهی، این جعبه را خالی بگذارید.'
		});

		// Only visible if partial and not blocking
		field_template_options.append({
			type: 'input',
			name: 'area',
			label: 'محدودهٔ قطع دسترسی',
			value: '',
			tooltip: 'توضیح اختیاری پیرامون صفحه‌ها یا فضاهای نامی که دسترسی کاربر به آن‌ها بسته شده‌است.'
		});

		if (!blockBox) {
			field_template_options.append({
				type: 'input',
				name: 'template_expiry',
				label: 'مدت‌زمان قطع دسترسی:',
				value: '',
				tooltip: 'دورهٔ زمانی قطع دسترسی، برای مثال، ۲۴ ساعت، ۱ هفته، بی‌پایان و...'
			});
		}
		field_template_options.append({
			type: 'input',
			name: 'block_reason',
			label: '«دسترسی ویرایشی شما بسته شده‌است، زیرا ...»',
			tooltip: 'دلیل اختیاری برای جایگزینی با دلیل عمومی پیش‌فرض. تنها برای الگوهای قطع دسترسی عمومی در دسترس است.',
			value: Twinkle.block.field_template_options.block_reason
		});

		if (blockBox) {
			field_template_options.append({
				type: 'checkbox',
				name: 'blank_duration',
				list: [
					{
						label: 'عدم درج زمان انقضا در الگو',
						checked: Twinkle.block.field_template_options.blank_duration,
						tooltip: 'به‌جای گنجاندن مدت، الگو طوری تنظیم می‌شود که متن آن مشابه «دسترسی شما به‌طور موقت بسته شده است...» باشد'
					}
				]
			});
		} else {
			field_template_options.append({
				type: 'checkbox',
				list: [
					{
						label: 'دسترسی به صفحهٔ بحث ستانده شد',
						name: 'notalk',
						checked: Twinkle.block.field_template_options.notalk,
						tooltip: 'تنظیم الگو به گونه‌ای که به سلب دسترسی کاربر به صفحهٔ بحث خودش اشاره کند'
					},
					{
						label: 'امکان ارسال ایمیل از کاربر گرفته شد',
						name: 'noemail_template',
						checked: Twinkle.block.field_template_options.noemail_template,
						tooltip: 'اگر فضای قطع دسترسی مشخص نشده‌باشد، الگوی قطع دسترسی طوری تنظیم می‌شود که به سلب دسترسی کاربر به ارسال ایمیل اشاره کند.'
					},
					{
						label: 'قابلیت ایجاد حساب غیرفعال شد',
						name: 'nocreate_template',
						checked: Twinkle.block.field_template_options.nocreate_template,
						tooltip: 'اگر فضای قطع دسترسی مشخص نشده‌باشد، الگوی قطع دسترسی طوری تنظیم می‌شود که به غیرفعال شدن قابلیت ایجاد حساب جدید برای کاربر اشاره کند.'
					}
				]
			});
		}

		var $previewlink = $('<a id="twinkleblock-preview-link">پیش‌نمایش</a>');
		$previewlink.off('click').on('click', function() {
			Twinkle.block.callback.preview($form[0]);
		});
		$previewlink.css({cursor: 'pointer'});
		field_template_options.append({ type: 'div', id: 'blockpreview', label: [ $previewlink[0] ] });
		field_template_options.append({ type: 'div', id: 'twinkleblock-previewbox', style: 'display: none' });
	} else if (field_preset) {
		// Only visible for arbitration enforcement, toggled in change_preset
		// field_preset.append(dsSelectSettings);
	}

	var oldfield;
	if (field_preset) {
		oldfield = $form.find('fieldset[name="field_preset"]')[0];
		oldfield.parentNode.replaceChild(field_preset.render(), oldfield);
	} else {
		$form.find('fieldset[name="field_preset"]').hide();
	}
	if (field_block_options) {
		oldfield = $form.find('fieldset[name="field_block_options"]')[0];
		oldfield.parentNode.replaceChild(field_block_options.render(), oldfield);
		$form.find('fieldset[name="field_64"]').show();


		$form.find('[name=pagerestrictions]').select2({
			width: '100%',
			placeholder: 'صفحه‌های مورد نظر برای قطع دسترسی کاربر به آن‌ها',
			language: {
				errorLoading: function() {
					return 'عبارت جستجوی ناقص یا نامعتبر';
				}
			},
			maximumSelectionLength: 10, // Software limitation [[phab:T202776]]
			minimumInputLength: 1, // prevent ajax call when empty
			ajax: {
				url: mw.util.wikiScript('api'),
				dataType: 'json',
				delay: 100,
				data: function(params) {
					var title = mw.Title.newFromText(params.term);
					if (!title) {
						return;
					}
					return {
						action: 'query',
						format: 'json',
						list: 'allpages',
						apfrom: title.title,
						apnamespace: title.namespace,
						aplimit: '10'
					};
				},
				processResults: function(data) {
					return {
						results: data.query.allpages.map(function(page) {
							var title = mw.Title.newFromText(page.title, page.ns).toText();
							return {
								id: title,
								text: title
							};
						})
					};
				}
			},
			templateSelection: function(choice) {
				return $('<a>').text(choice.text).attr({
					href: mw.util.getUrl(choice.text),
					target: '_blank'
				});
			}
		});

		$form.find('[name=namespacerestrictions]').select2({
			width: '100%',
			matcher: Morebits.select2.matchers.wordBeginning,
			language: {
				searching: Morebits.select2.queryInterceptor
			},
			templateResult: Morebits.select2.highlightSearchMatches,
			placeholder: 'فضاهای نام مورد نظر برای قطع دسترسی کاربر به آن‌ها'
		});

		mw.util.addCSS(
			// Reduce padding
			'.select2-results .select2-results__option { padding-top: 1px; padding-bottom: 1px; }' +
			// Adjust font size
			'.select2-container .select2-dropdown .select2-results { font-size: 13px; }' +
			'.select2-container .selection .select2-selection__rendered { font-size: 13px; }' +
			// Remove black border
			'.select2-container--default.select2-container--focus .select2-selection--multiple { border: 1px solid #aaa; }' +
			// Make the tiny cross larger
			'.select2-selection__choice__remove { font-size: 130%; }'
		);
	} else {
		$form.find('fieldset[name="field_block_options"]').hide();
		$form.find('fieldset[name="field_64"]').hide();
		// Clear select2 options
		$form.find('[name=pagerestrictions]').val(null).trigger('change');
		$form.find('[name=namespacerestrictions]').val(null).trigger('change');
	}

	if (field_template_options) {
		oldfield = $form.find('fieldset[name="field_template_options"]')[0];
		oldfield.parentNode.replaceChild(field_template_options.render(), oldfield);
		e.target.form.root.previewer = new Morebits.wiki.preview($(e.target.form.root).find('#twinkleblock-previewbox').last()[0]);
	} else {
		$form.find('fieldset[name="field_template_options"]').hide();
	}

	// Any block, including ranges
	if (Twinkle.block.currentBlockInfo) {
		// false for an ip covered by a range or a smaller range within a larger range;
		// true for a user, single ip block, or the exact range for a range block
		var sameUser = blockedUserName === relevantUserName;

		Morebits.status.init($('div[name="currentblock"] span').last()[0]);
		var statusStr = 'دسترسی ' + relevantUserName + (Twinkle.block.currentBlockInfo.partial === '' ? 'به‌صورت موردی' : 'به‌صورت کلی');

		// Range blocked
		if (Twinkle.block.currentBlockInfo.rangestart !== Twinkle.block.currentBlockInfo.rangeend) {
			if (sameUser) {
				statusStr += ' در قالب قطع دسترسی بازهٔ آی‌پی';
			} else {
				statusStr += ' در چارچوب یک قطع دسترسی بازه' + (Morebits.ip.get64(relevantUserName) === blockedUserName ? 'ٔ /64' : '');
				// Link to the full range
				var $rangeblockloglink = $('<span>').append($('<a target="_blank" href="' + mw.util.getUrl('ویژه:سیاهه‌ها', {action: 'view', page: blockedUserName, type: 'block'}) + '">' + blockedUserName + '</a>)'));
				statusStr += 'بسته شده‌است (' + $rangeblockloglink.html() + ')';
			}
		}

		if (Twinkle.block.currentBlockInfo.expiry === 'infinity') {
			statusStr += ' (بی‌پایان)';
		} else if (new Morebits.date(Twinkle.block.currentBlockInfo.expiry).isValid()) {
			statusStr += ' (در ' + new Morebits.date(Twinkle.block.currentBlockInfo.expiry).calendar('utc') + ' منقضی خواهد شد)';
		}


		var infoStr = 'این فرم';
		if (sameUser) {
			infoStr += ' آن قطع دسترسی را تغییر می‌دهد';
			if (Twinkle.block.currentBlockInfo.partial === undefined && partialBox) {
				infoStr += ' و آن را به یک قطع دسترسی موردی تبدیل می‌کند';
			} else if (Twinkle.block.currentBlockInfo.partial === '' && !partialBox) {
				infoStr += ' و آن را به یک قطع دسترسی کلی تبدیل می‌کند';
			}
			infoStr += '.';
		} else {
			infoStr += ' یک قطع دسترسی ' + (partialBox ? 'موردی ' : '') + 'دیگر را اضافه می‌کند.';
		}

		Morebits.status.warn(statusStr, infoStr);

		// Default to the current block conditions on intial form generation
		Twinkle.block.callback.update_form(e, Twinkle.block.currentBlockInfo);
	}

	// This is where T146628 really comes into play: a rangeblock will
	// only return the correct block log if wgRelevantUserName is the
	// exact range, not merely a funtional equivalent
	if (Twinkle.block.hasBlockLog) {
		var $blockloglink = $('<span>').append($('<a target="_blank" href="' + mw.util.getUrl('ویژه:سیاهه‌ها', {action: 'view', page: relevantUserName, type: 'block'}) + '">سیاههٔ قطع دسترسی</a>)'));
		if (!Twinkle.block.currentBlockInfo) {
			var lastBlockAction = Twinkle.block.blockLog[0];
			if (lastBlockAction.action === 'unblock') {
				$blockloglink.append(' (باز شده در ' + new Morebits.date(lastBlockAction.timestamp).calendar('utc') + ')');
			} else { // block or reblock
				$blockloglink.append(' (' + lastBlockAction.params.duration + '، مقضی‌شده در ' + new Morebits.date(lastBlockAction.params.expiry).calendar('utc') + ')');
			}
		}

		Morebits.status.init($('div[name="hasblocklog"] span').last()[0]);
		Morebits.status.warn(Twinkle.block.currentBlockInfo ? 'قطع دسترسی‌های پیشین' : 'این ' + (Morebits.ip.isRange(relevantUserName) ? 'بازه' : 'کاربر') + ' در گذشته بسته شده‌است', $blockloglink[0]);
	}

	// Make sure all the fields are correct based on initial defaults
	if (blockBox) {
		Twinkle.block.callback.change_preset(e);
	} else if (templateBox) {
		Twinkle.block.callback.change_template(e);
	}
};

/*
 * Keep alphabetized by key name, Twinkle.block.blockGroups establishes
 *    the order they will appear in the interface
 *
 * Block preset format, all keys accept only 'true' (omit for false) except where noted:
 * <title of block template> : {
 *   autoblock: <autoblock any IP addresses used (for registered users only)>
 *   disabletalk: <disable user from editing their own talk page while blocked>
 *   expiry: <string - expiry timestamp, can include relative times like "5 months", "2 weeks" etc>
 *   forAnonOnly: <show block option in the interface only if the relevant user is an IP>
 *   forRegisteredOnly: <show block option in the interface only if the relevant user is registered>
 *   label: <string - label for the option of the dropdown in the interface (keep brief)>
 *   noemail: prevent the user from sending email through Special:Emailuser
 *   pageParam: <set if the associated block template accepts a page parameter>
 *   prependReason: <string - prepends the value of 'reason' to the end of the existing reason, namely for when revoking talk page access>
 *   nocreate: <block account creation from the user's IP (for anonymous users only)>
 *   nonstandard: <template does not conform to stewardship of WikiProject User Warnings and may not accept standard parameters>
 *   reason: <string - block rationale, as would appear in the block log,
 *            and the edit summary for when adding block template, unless 'summary' is set>
 *   reasonParam: <set if the associated block template accepts a reason parameter>
 *   sig: <string - set to ~~~~ if block template does not accept "true" as the value, or set null to omit sig param altogether>
 *   summary: <string - edit summary for when adding block template to user's talk page, if not set, 'reason' is used>
 *   suppressArticleInSummary: <set to suppress showing the article name in the edit summary, as with attack pages>
 *   templateName: <string - name of template to use (instead of key name), entry will be omitted from the Templates list.
 *                  (e.g. use another template but with different block options)>
 *   useInitialOptions: <when preset is chosen, only change given block options, leave others as they were>
 *
 * WARNING: 'anononly' and 'allowusertalk' are enabled by default.
 *   To disable, set 'hardblock' and 'disabletalk', respectively
 */
Twinkle.block.blockPresetsInfo = {
	'قطع دسترسی ناشناس': {
		expiry: '31 hours',
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{قطع دسترسی ناشناس}}',
		sig: '~~~~'
	},
	'قطع دسترسی ناشناس - مدرسه': {
		expiry: '36 hours',
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{قطع دسترسی ناشناس}} <!-- احتمالاً مستقر در یک دانشگاه طبق شواهد رفتاری -->',
		templateName: 'قطع دسترسی ناشناس',
		sig: '~~~~'
	},
	'پروکسی باز': {
		expiry: '1 year',
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		hardblock: true,
		reason: '{{پروکسی باز}}',
		sig: null
	},
	'قطع دسترسی بازرسی کاربر': {
		expiry: '1 week',
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{قطع دسترسی بازرسی کاربر}}',
		sig: '~~~~'
	},
	'بندایش بازرسی کاربر-حساب کاربری': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{بندایش بازرسی کاربر-حساب کاربری}}',
		sig: '~~~~'
	},
	'قطع دسترسی بازرسی کاربر-کلی': {
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{قطع دسترسی بازرسی کاربر-کلی}}',
		sig: '~~~~'
	},
	'میزبانی‌وب‌سرور': {
		expiry: '1 year',
		forAnonOnly: true,
		nonstandard: true,
		reason: '{{میزبانی‌وب‌سرور}}',
		sig: null
	},
	'قطع دسترسی پنهان‌گر': {
		autoblock: true,
		expiry: 'infinity',
		nocreate: true,
		nonstandard: true,
		reason: '{{هبک-قطع دسترسی پنهان‌گر}}',
		sig: '~~~~'
	},
	'قطع دسترسی مدرسه': {
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{قطع دسترسی مدرسه}}',
		sig: '~~~~'
	},
	'بستن فهرست سیاه': {
		forAnonOnly: true,
		expiry: '1 month',
		disabletalk: true,
		nocreate: true,
		reason: '{{هبک-بستن فهرست سیاه}} <!-- ویرایشگر تنها اقدام به افزودن پیوندهای قرارگرفته در فهرست سیاه می‌کند؛ [[ویژه:سیاهه‌ها/spamblacklist]] را ببینید -->'
	},
	'قطع دسترسی بازه آی‌پی': {
		reason: '{{قطع دسترسی بازه آی‌پی}}',
		nocreate: true,
		nonstandard: true,
		forAnonOnly: true,
		sig: '~~~~'
	},
	'تور': {
		expiry: '1 year',
		forAnonOnly: true,
		nonstandard: true,
		reason: '{{تور}}',
		sig: null
	},
	'میزبان وب بسته‌شده': {
		expiry: '1 year',
		forAnonOnly: true,
		nonstandard: true,
		reason: '{{میزبان وب بسته‌شده}}',
		sig: null
	},
	// uw-prefixed (هبک)
	'هبک-قطع دسترسی ۳ب': {
		autoblock: true,
		expiry: '24 hours',
		nocreate: true,
		pageParam: true,
		reason: 'نقض [[وپ:۳ب|قاعدهٔ سه برگردان]]',
		summary: 'دسترسی ویرایشی شما به‌دلیل نقض [[وپ:۳ب|قاعدهٔ سه برگردان]] بسته شده است'
	},
	'هبک-قطع دسترسی ناشناس': {
		autoblock: true,
		expiry: '31 hours',
		forAnonOnly: true,
		nocreate: true,
		pageParam: true,
		reasonParam: true,
		summary: 'دسترسی ویرایشی نشانی آی‌پی شما بسته شده است',
		suppressArticleInSummary: true
	},
	'هبک-قطع دسترسی هرزنگاری': {
		autoblock: true,
		nocreate: true,
		pageParam: true,
		reason: 'استفاده از ویکی‌پدیا برای [[وپ:هرز|هرزنگاری]] یا [[وپ:تبلیغ|تبلیغات]]',
		summary: 'دسترسی ویرایشی شما به دلیل [[وپ:منبر|تبلیغات یا ترویج]] بسته شده است'
	},
/*	'uw-aeblock': {
		autoblock: true,
		nocreate: true,
		pageParam: true,
		reason: '[[WP:Arbitration enforcement|Arbitration enforcement]]',
		reasonParam: true,
		summary: 'You have been blocked from editing for violating an [[WP:Arbitration|arbitration decision]]'
	}, */
	'هبک-قطع دسترسی زندگان': {
		autoblock: true,
		nocreate: true,
		pageParam: true,
		reason: 'نقض سیاست [[وپ:زندگی‌نامه زندگان|زندگی‌نامهٔ افراد زنده]]',
		summary: 'دسترسی ویرایشی شما به دلیل نقض [[وپ:زنده|سیاست زندگی‌نامهٔ افراد زنده]] ویکی‌پدیا بسته شده است'
	},
	'قطع دسترسی': {
		autoblock: true,
		expiry: '24 hours',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: true,
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما بسته شده است',
		suppressArticleInSummary: true
	},
	'هبک-قطع دسترسی بی‌پایان': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: true,
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است',
		suppressArticleInSummary: true
	},
	'هبک-قطع دسترسی بحث': {
		disabletalk: true,
		pageParam: true,
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما بسته شده است و دسترسی شما به صفحهٔ بحث‌تان نیز غیرفعال شده است',
		suppressArticleInSummary: true
	},
	'هبک-قطع دسترسی ربات': {
		forRegisteredOnly: true,
		pageParam: true,
		reason: 'راندن [[وپ:ربات|اسکریپت ربات]] بدون [[وپ:پرچم|مجوز]]',
		summary: 'دسترسی ویرایشی شما بسته شده است؛ زیرا به‌نظر می‌رسد که در حال راندن یک [[وپ:ربات|اسکریپت ربات]] بدون [[وپ:پرچم|کسب مجوز]] هستید'
	},
	'هبک-بستن نام کاربری ربات': {
		expiry: 'infinity',
		forRegisteredOnly: true,
		reason: '{{هبک-بستن نام کاربری ربات}} <!-- نام کاربری مشابه نام ربات است؛ قطع دسترسی نرم -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا [[وپ:نام|نام کاربری]] شما نشان می‌دهد که این حساب یک [[وپ:ربات|حساب ربات]] است که در حال حاضر فاقد مجوز است'
	},
	'هبک-بستن سخت نام ربات': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		reason: '{{هبک-بستن سخت نام ربات}} <!-- نام کاربری مشابه نام ربات است؛ قطع دسترسی سخت -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا نام کاربری شما آشکارا ناقض [[وپ:نام|سیاست نام کاربری]] است.'
	},
	'هبک-قطع دسترسی جنبش': {
		expiry: 'infinity',
		forRegisteredOnly: true,
		reason: '{{هبک-قطع دسترسی جنبش}} <!-- نام کاربری نمایندهٔ یک سازمان ناسودبر است، قطع دسترسی نرم -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا به‌نظر می‌رسد که [[وپ:نام|نام کاربری]] شما نمایندهٔ یک گروه، سازمان، یا وبگاه است'
	},
	'هبک-بستن حساب به‌خطر افتاده': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		reason: 'حساب به خطر افتاده',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا باور بر این است که [[وپ:امنیت|امنیت حساب کاربری شما]] به خطر افتاده است'
	},
	'هبک-قطع دسترسی حق تکثیر': {
		autoblock: true,
		expiry: 'infinity',
		nocreate: true,
		pageParam: true,
		reason: '[[وپ:حق تکثیر|نقض حق تکثیر]]',
		summary: 'دسترسی ویرایشی شما به دلیل [[وپ:حت|نقض حق تکثیر]] ادامه‌دار بسته شده است'
	},
	'هبک-قطع دسترسی حذف محتوا': {
		autoblock: true,
		nocreate: true,
		reason: 'حذف مکرر محتوا',
		pageParam: true,
		summary: 'دسترسی ویرایشی شما به دلیل [[وپ:خ|حذف محتوای صفحه‌ها]] بسته شده است'
	},
	'هبک-قطع دسترسی اخلالگری': {
		autoblock: true,
		nocreate: true,
		reason: '[[وپ:ویرایش اخلالگرانه|ویرایش اخلالگرانه]]',
		summary: 'دسترسی ویرایشی شما به دلیل [[وپ:ویرایش اخلالگرانه|ویرایش اخلالگرانه]] بسته شده است'
	},
	'هبک-قطع دسترسی پالایه ویرایش': {
		autoblock: true,
		nocreate: true,
		reason: 'فعال‌سازی مکرر [[وپ:پالایه ویرایش|پالایهٔ ویرایش]]',
		summary: 'دسترسی ویرایشی شما به دلیل تکرار ویرایش‌های اخلالگرانه‌ای که مکرراً [[وپ:پالایه|پالایهٔ ویرایش]] را فعال کرده‌اند، بسته شده است'
	},
	'هبک-قطع دسترسی جنگ ویرایشی': {
		autoblock: true,
		expiry: '24 hours',
		nocreate: true,
		pageParam: true,
		reason: '[[وپ:جنگ|جنگ ویرایشی]]',
		summary: 'دسترسی ویرایشی شما به‌منظور جلوگیری از [[وپ:ویرایش اخلالگرانه|اخلال]] بیشتر به‌واسطهٔ درگیر شدن شما در [[وپ:جنگ|جنگ ویرایشی]] بسته شده است'
	},
	'هبک-قطع دسترسی آزار': {
		autoblock: true,
		nocreate: true,
		pageParam: true,
		reason: '[[وپ:حمله شخصی ممنوع|حمله شخصی]] یا [[وپ:آزار|آزار و اذیت]]',
		summary: 'دسترسی ویرایشی شما به دلیل اقدام به [[وپ:آزار|آزار و اذیت]] کاربران دیگر بسته شده است'
	},
	'هبک-بستن دور زدن قطع دسترسی': {
		forAnonOnly: true,
		nocreate: true,
		reason: '[[وپ:دور زدن|دور زدن قطع دسترسی]]',
		summary: 'دسترسی ویرایشی نشانی آی‌پی شما بسته شده است؛ زیرا از آن برای [[وپ:دور زدن|دور زدن قطع دسترسی پیشین]] استفاده شده است'
	},
	'هبک-قطع دسترسی تهدید': {
		autoblock: true,
		expiry: 'infinity',
		nocreate: true,
		reason: '[[وپ:تهدید قانونی ممنوع|تهدید قانونی]]',
		summary: 'دسترسی ویرایشی شما به دلیل [[وپ:تهدید قانونی|تهدید قانونی یا اقدامات حقوقی]] بسته شده است'
	},
	'هبک-قطع دسترسی اینجا نه': {
		autoblock: true,
		expiry: 'infinity',
		nocreate: true,
		reason: 'واضح است که [[وپ:اینجا نه|برای کمک به دانشنامه اینجا نیست]]',
		forRegisteredOnly: true,
		summary: 'دسترسی ویرایشی شما بسته شده است؛ زیرا به‌نظر می‌رسد که [[وپ:اینجا نه|برای کمک به دانشنامه اینجا نیستید]]'
	},
	'هبک-قطع دسترسی بی‌معنی': {
		autoblock: true,
		nocreate: true,
		pageParam: true,
		reason: 'ایجاد [[وپ:بی‌معنی|صفحه‌های بی‌معنی]] یا سایر صفحه‌های نامناسب',
		summary: 'دسترسی ویرایشی شما به دلیل ایجاد [[وپ:بی‌معنی|صفحه‌های بی‌معنی]] بسته شده است'
	},
	'هبک-قطع دسترسی حمله شخصی': {
		autoblock: true,
		expiry: '31 hours',
		nocreate: true,
		reason: '[[وپ:حمله|حملهٔ شخصی]] یا [[وپ:آزار|آزار و اذیت]]',
		summary: 'دسترسی ویرایشی شما به دلیل [[وپ:حمله|حملهٔ شخصی]] به کاربران دیگر بسته شده است'
	},
	'هبک-قطع دسترسی اسپم': {
		autoblock: true,
		nocreate: true,
		reason: 'استفاده از ویکی‌پدیا برای [[وپ:هرز|هرزنگاری]]',
		summary: 'دسترسی ویرایشی شما به دلیل استفاده از ویکی‌پدیا برای [[وپ:هرز|هرزنگاری]] بسته شده است'
	},
	'هبک-بستن حساب هرزنگار': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: true,
		reason: 'حساب ایجاد شده برای [[وپ:هرز|هرزنگاری]] یا [[وپ:تبلیغ|تبلیغات]]',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا از حساب کاربری خود تنها برای [[وپ:هرز|هرزنگاری، تبلیغات یا ترویج]] استفاده کرده‌اید'
	},
	'هبک-قطع دسترسی شبکه اجتماعی': {
		autoblock: true,
		nocreate: true,
		pageParam: true,
		reason: 'استفاده از ویکی‌پدیا به‌عنوان یک [[وپ:فیسبوک نیست|وب‌نوشت، میزبان وب، شبکهٔ اجتماعی یا انجمن]]',
		summary: 'دسترسی ویرایشی شما به دلیل استفاده از صفحه‌های کاربری و/یا مقاله‌ها به‌عنوان [[وپ:فیسبوک نیست|وب‌نوشت، میزبان وب، شبکهٔ اجتماعی یا انجمن]] بسته شده است'
	},
	'هبک-قطع دسترسی زاپاس': {
		autoblock: true,
		forRegisteredOnly: true,
		nocreate: true,
		reason: 'سوءاستفاده از [[وپ:زاپاس‌بازی|چند حساب کاربری]]',
		summary: 'دسترسی ویرایشی شما به دلیل سوءاستفاده از [[وپ:زاپاس|چند حساب کاربر]] بسته شده است'
	},
	'هبک-قطع دسترسی نرم نام کاربری': {
		expiry: 'infinity',
		forRegisteredOnly: true,
		reason: '{{هبک-قطع دسترسی نرم نام کاربری}} <!-- نام کاربری تبلیغاتی، قطع دسترسی نرم -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا [[وپ:نام|نام کاربری]] به گونه‌ای است که گویی این حساب نمایندهٔ یک گروه، سازمان یا وبگاه است'
	},
	'هبک-قطع دسترسی نرم هرزنگاری': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		reason: '{{هبک-قطع دسترسی نرم هرزنگاری}} <!-- نام کاربری تبلیغاتی، ویرایش‌های تبلیغاتی -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا حساب کاربری شما تنها برای [[وپ:هرز|هرزنگاری یا تبلیغات]] استفاده شده و نام کاربری شما ناقض [[وپ:نام|سیاست نام کاربری]] است'
	},
	'بستن زاپاس': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		reason: '[[وپ:زاپاس|زاپاس‌بازی]]',
		summary: 'دسترسی این حساب کاربری به‌عنوان یک [[وپ:زاپاس|حساب زاپاس]] ایجادشده با هدف نقض سیاست‌های ویکی‌پدیا، بسته شده است'
	},
	'بسته‌شده بدون دسترسی بحث-اعلان': {
		disabletalk: true,
		reason: 'گرفتن دسترسی بحث: استفادهٔ نادرست از صفحهٔ بحث کاربری در زمان بسته بودن',
		prependReason: true,
		summary: 'دسترسی شما به صفحهٔ بحث‌تان غیرفعال شده است',
		useInitialOptions: true
	},
	'هبک-قطع دسترسی نام کاربری': {
		expiry: 'infinity',
		forRegisteredOnly: true,
		reason: '{{هبک-قطع دسترسی نام کاربری}} <!-- نقض سیاست نام کاربری، قطع دسترسی نرم -->',
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا نام کاربری شما ناقض [[وپ:نام|سیاست نام کاربری]] است'
	},
	'هبک-قطع دسترسی نام کاربری-تکراری': {
		expiry: 'infinity',
		forRegisteredOnly: true,
		reason: '{{هبک-قطع دسترسی نام کاربری-تکراری}} <!-- نام کاربری بسیار مشابه نام یک کاربر دیگر است، قطع دسترسی نرم -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا [[وپ:نام|نام کاربری]] شما بسیار مشابه نام کاربری یک ویرایشگر دیگر در ویکی‌پدیا است'
	},
	'هبک-قطع دسترسی مطالب بدون منبع': {
		autoblock: true,
		expiry: '31 hours',
		nocreate: true,
		pageParam: true,
		reason: 'افزودن مکرر [[وپ:مقدارج|مطالب بدون منبع]]',
		summary: 'دسترسی ویرایشی شما به دلیل افزودن مداوم [[وپ:مقدارج|مطالب بدون منبع]] بسته شده است'
	},
	'هبک-بستن سخت نام کاربری': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		reason: '{{هبک-بستن سخت نام کاربری}} <!-- نقض سیاست نام کاربری، قطع دسترسی سخت -->',
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا نام کاربری شما آشکارا ناقض [[وپ:نام|سیاست نام کاربری]] است'
	},
	'بستن نام واقعی': {
		expiry: 'infinity',
		forRegisteredOnly: true,
		reason: '{{بستن نام واقعی}} <!-- نام کاربری همنام با یک شخص سرشناس، قطع دسترسی نرم -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا [[وپ:نام|نام کاربری]] شما با نام یک شخص زندهٔ سرشناس یکسان است'
	},
	'هبک-بستن سخت نام کاربری-تکراری': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		reason: '{{هبک-بستن سخت نام کاربری-تکراری}} <!-- اقدام به جعل هویت کاربر دیگر، قطع دسترسی سخت -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا [[وپ:نام|نام کاربری]] شما منجر به جعل هویت یک کاربر قدیمی دیگر ویکی‌پدیا می‌شود'
	},
	'هبک-بستن نام کاربری دستمزد ': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: true,
		reason: '[[وپ:مزد|ویرایش در برابر دستمزد فاش نشده]] در تضاد با [[وپ:شا|شرایط استفادهٔ]] بنیاد ویکی‌مدیا',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا از حساب کاربری خود در تضاد با [[وپ:مزد|سیاست ویکی‌پدیا برای مشارکت در برابر دستمزد فاش‌نشده]] استفاده کرده‌اید'
	},
	'هبک-بستن نام کاربری خرابکاری': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: true,
		reason: '{{هبک-بستن نام کاربری خرابکاری}} <!-- نقض سیاست نام کاربری، حساب ایجادشده برای خرابکاری -->',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا حساب کاربری شما [[وپ:حفخ|تنها برای خرابکاری استفاده شده]] و نام کاربری شما آشکارا ناقض [[وپ:نام|سیاست نام کاربری]] است'
	},
	'هبک-قطع دسترسی خرابکاری': {
		autoblock: true,
		expiry: '31 hours',
		nocreate: true,
		pageParam: true,
		reason: '[[وپ:خرابکاری|خرابکاری]]',
		summary: 'دسترسی ویرایشی شما به‌منظور جلوگیری از ادامه‌یافتن [[وپ:خ|خرابکاری]] بسته شده است'
	},
	'هبک-قطع دسترسی حساب خرابکار': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: true,
		reason: '[[وپ:حساب ساخته‌شده برای خرابکاری|حساب ایجادشده برای خرابکاری]]',
		summary: 'دسترسی ویرایشی شما برای مدت نامعین بسته شده است؛ زیرا حساب کاربری شما [[وپ:حفخ|تنها برای خرابکاری ساخته شده است]]'
	},
	'زامبی پراکسی': {
		expiry: '1 month',
		forAnonOnly: true,
		nocreate: true,
		nonstandard: true,
		reason: '{{زامبی پراکسی}}',
		sig: null
	},

	// Begin partial block templates, accessed in Twinkle.block.blockGroupsPartial
	'هبک-بستن موردی ایجاد حساب': {
		autoblock: true,
		expiry: '48 hours',
		nocreate: true,
		pageParam: false,
		reasonParam: true,
		reason: 'سوءاستفاده از [[وپ:زاپاس‌بازی|چند حساب کاربری]]',
		summary: 'به‌دلیل سوءاستفاده از [[وپ:زاپاس|چند حساب کاربری]]، [[وپ:موردی|دسترسی ایجاد حساب برای شما بسته شده است]]'
	},
	'هبک-بستن موردی ایجاد حساب بی‌پایان': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: true,
		pageParam: false,
		reasonParam: true,
		reason: 'سوءاستفاده از [[وپ:زاپاس‌بازی|چند حساب کاربری]]',
		summary: 'به‌دلیل سوءاستفاده از [[وپ:زاپاس|چند حساب کاربری]]، [[WP:PB|دسترسی ایجاد حساب برای شما برای مدت نامعین بسته شده است]]'
	},
/*	'uw-aepblock': {
		autoblock: true,
		nocreate: false,
		pageParam: false,
		reason: '[[WP:Arbitration enforcement|Arbitration enforcement]]',
		reasonParam: true,
		summary: 'You have been [[WP:PB|partially blocked]] from editing for violating an [[WP:Arbitration|arbitration decision]]'
	}, */
	'هبک-بستن موردی ایمیل': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: false,
		noemail: true,
		pageParam: false,
		reasonParam: true,
		reason: '[[وپ:آزار|آزار و اذیت]] از طریق ایمیل',
		summary: 'به‌دلیل [[وپ:آزار|آزار و اذیت]] ویرایشگران دیگر، [[وپ:موردی|دسترسی شما به ارسال ایمیل بسته شده است]]'
	},
	'هبک-بستن موردی جنگ': {
		autoblock: true,
		expiry: '24 hours',
		nocreate: false,
		pageParam: false,
		reasonParam: true,
		reason: '[[وپ:جنگ ویرایشی|جنگ ویرایشی]]',
		summary: 'به‌منظور جلوگیری از ادامه‌یافتن [[وپ:ویرایش اخلالگرانه|اخلال]] به‌واسطهٔ [[وپ:جنگ|جنگ ویرایشی]]، دسترسی ویرایشی شما به برخی فضاهای خاص در دانشنامه [[وپ:موردی|به‌صورت موردی بسته شده است]]'
	},
	'هبک-بستن موردی': {
		autoblock: true,
		expiry: '24 hours',
		nocreate: false,
		pageParam: false,
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما به برخی فضاهای خاص دانشنامه [[وپ:موردی|به‌صورت موردی بسته شده است]]'
	},
	'هبک-بستن موردی بی‌پایان': {
		autoblock: true,
		expiry: 'infinity',
		forRegisteredOnly: true,
		nocreate: false,
		pageParam: false,
		reasonParam: true,
		summary: 'دسترسی ویرایشی شما به برخی فضاهای خاص دانشنامه برای مدت نامعین و [[وپ:موردی|به‌صورت موردی بسته شده است]]'
	}
};

Twinkle.block.transformBlockPresets = function twinkleblockTransformBlockPresets() {
	// supply sensible defaults
	$.each(Twinkle.block.blockPresetsInfo, function(preset, settings) {
		settings.summary = settings.summary || settings.reason;
		settings.sig = settings.sig !== undefined ? settings.sig : 'yes';
		settings.indefinite = settings.indefinite || Morebits.string.isInfinity(settings.expiry);

		if (!Twinkle.block.isRegistered && settings.indefinite) {
			settings.expiry = '31 hours';
		} else {
			settings.expiry = settings.expiry || '31 hours';
		}

		Twinkle.block.blockPresetsInfo[preset] = settings;
	});
};

// These are the groups of presets and defines the order in which they appear. For each list item:
//   label: <string, the description that will be visible in the dropdown>
//   value: <string, the key of a preset in blockPresetsInfo>
Twinkle.block.blockGroups = [
	{
		label: 'دلایل مرسوم قطع دسترسی',
		list: [
			{ label: 'ناشناس', value: 'قطع دسترسی ناشناس' },
			{ label: 'ناشناس - احتمالاً مدرسه', value: 'قطع دسترسی ناشناس - مدرسه' },
			{ label: 'قطع دسترسی مدرسه', value: 'قطع دسترسی مدرسه' },
			{ label: 'قطع دسترسی عمومی (دلیل سفارشی)', value: 'قطع دسترسی' }, // ends up being default for registered users
			{ label: 'قطع دسترسی عمومی (دلیل سفارشی) - آی‌پی', value: 'هبک-قطع دسترسی ناشناس', selected: true }, // set only when blocking IP
			{ label: 'قطع دسترسی عمومی (دلیل سفارشی) - بی‌پایان', value: 'هبک-قطع دسترسی بی‌پایان' },
			{ label: 'ویرایش اخلالگرانه', value: 'هبک-قطع دسترسی اخلالگری' },
			{ label: 'استفادهٔ نادرست از صفحهٔ بحث هنگام بسته بودن', value: 'بسته‌شده بدون دسترسی بحث-اعلان' },
			{ label: 'برای کمک به دانشنامه اینجا نیست', value: 'هبک-قطع دسترسی اینجا نه' },
			{ label: 'مطالب بدون منبع', value: 'هبک-قطع دسترسی مطالب بدون منبع' },
			{ label: 'خرابکاری', value: 'هبک-قطع دسترسی خرابکاری' },
			{ label: 'حساب ایجادشده برای خرابکاری', value: 'هبک-قطع دسترسی حساب خرابکار' }
		]
	},
	{
		label: 'دلایل بیشتر',
		list: [
			{ label: 'تبلیغات', value: 'هبک-قطع دسترسی هرزنگاری' },
		//	{ label: 'Arbitration enforcement', value: 'uw-aeblock' },
			{ label: 'دور زدن قطع دسترسی - آی‌پی', value: 'هبک-بستن دور زدن قطع دسترسی' },
			{ label: 'نقض وپ:زنده', value: 'هبک-قطع دسترسی زندگان' },
			{ label: 'نقض حق تکثیر', value: 'هبک-قطع دسترسی حق تکثیر' },
			{ label: 'ایجاد صفحه‌های نامفهوم', value: 'هبک-قطع دسترسی بی‌معنی' },
			{ label: 'مرتبط با پالایه', value: 'هبک-قطع دسترسی پالایه ویرایش' },
			{ label: 'جنگ ویرایشی', value: 'هبک-قطع دسترسی جنگ ویرایشی' },
			{ label: 'قطع دسترسی عمومی به‌همراه گرفتن دسترسی بحث', value: 'هبک-قطع دسترسی بحث' },
			{ label: 'آزار و اذیت', value: 'هبک-قطع دسترسی آزار' },
			{ label: 'تهدید قانونی', value: 'هبک-قطع دسترسی تهدید' },
			{ label: 'حمله شخصی یا آزار و اذیت', value: 'هبک-قطع دسترسی حمله شخصی' },
			{ label: 'احتمال به خطر افتادن حساب', value: 'هبک-بستن حساب به‌خطر افتاده' },
			{ label: 'حذف محتوا', value: 'هبک-قطع دسترسی حذف محتوا' },
			{ label: 'زاپاس‌بازی (حساب اصلی)', value: 'هبک-قطع دسترسی زاپاس' },
			{ label: 'زاپاس‌بازی (حساب زاپاس)', value: 'بستن زاپاس' },
			{ label: 'استفاده مشابه شبکه‌های اجتماعی', value: 'هبک-قطع دسترسی شبکه اجتماعی' },
			{ label: 'هرزنگاری', value: 'هبک-قطع دسترسی اسپم' },
			{ label: 'حساب ایجاد شده برای هرزنگاری/تبلیغات', value: 'هبک-بستن حساب هرزنگار' },
			{ label: 'ربات فاقد مجوز', value: 'هبک-قطع دسترسی ربات' },
			{ label: 'ویرایش در برابر دستمزد فاش‌نشده', value: 'هبک-بستن نام کاربری دستمزد ' },
			{ label: 'نقض قاعدهٔ سه‌برگردان', value: 'هبک-قطع دسترسی ۳ب' }
		]
	},
	{
		label: 'نقض سیاست نام کاربری',
		list: [
			{ label: 'نام کاربری ربات، قطع دسترسی نرم', value: 'هبک-بستن نام کاربری ربات' },
			{ label: 'نام کاربری ربات، قطع دسترسی سخت', value: 'هبک-بستن سخت نام ربات' },
			{ label: 'نام کاربری تبلیغاتی، قطع دسترسی سخت', value: 'هبک-قطع دسترسی نرم هرزنگاری' },
			{ label: 'نام کاربری تبلیغاتی، قطع دسترسی نرم', value: 'هبک-قطع دسترسی نرم نام کاربری' },
			{ label: 'نام کاربری مشابه، قطع دسترسی نرم', value: 'هبک-قطع دسترسی نام کاربری-تکراری' },
			{ label: 'نقض سیاست نام کاربری، قطع دسترسی نرم', value: 'هبک-قطع دسترسی نام کاربری' },
			{ label: 'نقض سیاست نام کاربری، قطع دسترسی سخت', value: 'هبک-بستن سخت نام کاربری' },
			{ label: 'جعل هویت با نام کاربری، قطع دسترسی سخت', value: 'هبک-بستن سخت نام کاربری-تکراری' },
			{ label: 'نام کاربری نمایندهٔ شخص سرشناس، قطع دسترسی نرم', value: 'بستن نام واقعی' },
			{ label: 'نام کاربری نمایندهٔ سازمان ناسودبر، قطع دسترسی نرم', value: 'هبک-قطع دسترسی جنبش' },
			{ label: 'نقض سیاست نام کاربری، حساب ایجادشده برای خرابکاری', value: 'هبک-بستن نام کاربری خرابکاری' }
		]
	},
	{
		label: 'دلیل‌های حاوی الگو',
		list: [
			{ label: 'پروکسی بسته شده', value: 'پروکسی باز' },
			{ label: 'قطع دسترسی بازرسی کاربر', value: 'قطع دسترسی بازرسی کاربر' },
			{ label: 'قطع دسترسی بازرسی کاربر-حساب کاربری', value: 'بندایش بازرسی کاربر-حساب کاربری' },
			{ label: 'قطع دسترسی بازرسی کاربر-کلی', value: 'قطع دسترسی بازرسی کاربر-کلی' },
			{ label: 'میزبانی وب‌سرور', value: 'میزبانی‌وب‌سرور' },
			{ label: 'قطع دسترسی پنهان‌گر', value: 'قطع دسترسی پنهان‌گر' },
			{ label: 'قطع دسترسی بازه آی‌پی', value: 'قطع دسترسی بازه آی‌پی' }, // Only for IP ranges, selected for non-/64 ranges in filtered_block_groups
			{ label: 'قطع دسترسی فهرست سیاه', value: 'بستن فهرست سیاه' },
			{ label: 'تور', value: 'تور' },
			{ label: 'میزبان وب بسته‌شده', value: 'میزبان وب بسته‌شده' },
			{ label: 'زامبی پراکسی', value: 'زامبی پراکسی' }
		]
	}
];

Twinkle.block.blockGroupsPartial = [
	{
		label: 'دلایل مرسوم برای قطع دسترسی موردی',
		list: [
			{ label: 'قطع دسترسی موردی عمومی (دلیل سفارشی)', value: 'هبک-بستن موردی', selected: true },
			{ label: 'قطع دسترسی موردی عمومی (دلیل سفارشی) - بی‌پایان', value: 'هبک-بستن موردی بی‌پایان' },
			{ label: 'جنگ ویرایشی', value: 'هبک-بستن موردی جنگ' }
		]
	},
	{
		label: 'دلایل بیشتر قطع دسترسی موردی',
		list: [
			//{ label: 'Arbitration enforcement', value: 'uw-aepblock' },
			{ label: 'آزار و اذیت از طریق ایمیل', value: 'هبک-بستن موردی ایمیل' },
			{ label: 'سوءاستفاده از چند حساب کاربری', value: 'هبک-بستن موردی ایجاد حساب' },
			{ label: 'سوءاستفاده از چند حساب کاربری - پی‌پایان', value: 'هبک-بستن موردی ایجاد حساب بی‌پایان' }
		]
	}
];


Twinkle.block.callback.filtered_block_groups = function twinkleblockCallbackFilteredBlockGroups(group, show_template) {
	return $.map(group, function(blockGroup) {
		var list = $.map(blockGroup.list, function(blockPreset) {
			switch (blockPreset.value) {
				case 'بسته‌شده بدون دسترسی بحث-اعلان':
					if (blockedUserName !== relevantUserName) {
						return;
					}
					break;
				case 'قطع دسترسی بازه آی‌پی':
					if (!Morebits.ip.isRange(relevantUserName)) {
						return;
					}
					blockPreset.selected = !Morebits.ip.get64(relevantUserName);
					break;
				case 'قطع دسترسی بازرسی کاربر':
				case 'بندایش بازرسی کاربر-حساب کاربری':
				case 'قطع دسترسی بازرسی کاربر-کلی':
					if (!Morebits.userIsInGroup('checkuser')) {
						return;
					}
					break;
				case 'قطع دسترسی پنهان‌گر':
					if (!Morebits.userIsInGroup('suppress')) {
						return;
					}
					break;
				default:
					break;
			}

			var blockSettings = Twinkle.block.blockPresetsInfo[blockPreset.value];
			var registrationRestrict = blockSettings.forRegisteredOnly ? Twinkle.block.isRegistered : blockSettings.forAnonOnly ? !Twinkle.block.isRegistered : true;
			if (!(blockSettings.templateName && show_template) && registrationRestrict) {
				var templateName = blockSettings.templateName || blockPreset.value;
				return {
					label: (show_template ? '{{' + templateName + '}}: ' : '') + blockPreset.label,
					value: blockPreset.value,
					data: [{
						name: 'template-name',
						value: templateName
					}],
					selected: !!blockPreset.selected,
					disabled: !!blockPreset.disabled
				};
			}
		});
		if (list.length) {
			return {
				label: blockGroup.label,
				list: list
			};
		}
	});
};

Twinkle.block.callback.change_preset = function twinkleblockCallbackChangePreset(e) {
	var form = e.target.form, key = form.preset.value;
	if (!key) {
		return;
	}

	Twinkle.block.callback.update_form(e, Twinkle.block.blockPresetsInfo[key]);
	if (form.template) {
		form.template.value = Twinkle.block.blockPresetsInfo[key].templateName || key;
		Twinkle.block.callback.change_template(e);
	} else {
		Morebits.quickForm.setElementVisibility(form.dstopic.parentNode, key === 'uw-aeblock' || key === 'uw-aepblock');
	}
};

Twinkle.block.callback.change_expiry = function twinkleblockCallbackChangeExpiry(e) {
	var expiry = e.target.form.expiry;
	if (e.target.value === 'custom') {
		Morebits.quickForm.setElementVisibility(expiry.parentNode, true);
	} else {
		Morebits.quickForm.setElementVisibility(expiry.parentNode, false);
		expiry.value = e.target.value;
	}
};

Twinkle.block.seeAlsos = [];
Twinkle.block.callback.toggle_see_alsos = function twinkleblockCallbackToggleSeeAlso() {
	var reason = this.form.reason.value.replace(
		new RegExp('( <!--|؛) ' + 'همچنین ' + Twinkle.block.seeAlsos.join(' و ') + ' را ببینید( -->)?'), ''
	);

	Twinkle.block.seeAlsos = Twinkle.block.seeAlsos.filter(function(el) {
		return el !== this.value;
	}.bind(this));

	if (this.checked) {
		Twinkle.block.seeAlsos.push(this.value);
	}
	var seeAlsoMessage = Twinkle.block.seeAlsos.join(' و ');

	if (!Twinkle.block.seeAlsos.length) {
		this.form.reason.value = reason;
	} else if (reason.indexOf('{{') !== -1) {
		this.form.reason.value = reason + ' <!-- همچنین ' + seeAlsoMessage + ' را ببینید -->';
	} else {
		this.form.reason.value = reason + '؛ همچنین ' + seeAlsoMessage + ' را ببینید';
	}
};

/* Localized [Removed; no DS in fawiki]
Twinkle.block.dsReason = '';
Twinkle.block.callback.toggle_ds_reason = function twinkleblockCallbackToggleDSReason() {
	var reason = this.form.reason.value.replace(
		new RegExp(' ?\\(\\[\\[' + Twinkle.block.dsReason + '\\]\\]\\)'), ''
	);

	Twinkle.block.dsinfo.then(function(dsinfo) {
		var sanctionCode = this.selectedIndex;
		var sanctionName = this.options[sanctionCode].label;
		Twinkle.block.dsReason = dsinfo[sanctionName].page;
		if (!this.value) {
			this.form.reason.value = reason;
		} else {
			this.form.reason.value = reason + ' ([[' + Twinkle.block.dsReason + ']])';
		}
	}.bind(this));
}; */

Twinkle.block.callback.update_form = function twinkleblockCallbackUpdateForm(e, data) {
	var form = e.target.form, expiry = data.expiry;

	// don't override original expiry if useInitialOptions is set
	if (!data.useInitialOptions) {
		if (Date.parse(expiry)) {
			expiry = new Date(expiry).toGMTString();
			form.expiry_preset.value = 'custom';
		} else {
			form.expiry_preset.value = data.expiry || 'custom';
		}

		form.expiry.value = expiry;
		if (form.expiry_preset.value === 'custom') {
			Morebits.quickForm.setElementVisibility(form.expiry.parentNode, true);
		} else {
			Morebits.quickForm.setElementVisibility(form.expiry.parentNode, false);
		}
	}

	// boolean-flipped options, more at [[mw:API:Block]]
	data.disabletalk = data.disabletalk !== undefined ? data.disabletalk : false;
	data.hardblock = data.hardblock !== undefined ? data.hardblock : false;

	// disable autoblock if blocking a bot
	if (Twinkle.block.userIsBot || /bot\b/i.test(relevantUserName) || /بات$/.test(relevantUserName)) {
		data.autoblock = false;
	}

	$(form).find('[name=field_block_options]').find(':checkbox').each(function(i, el) {
		// don't override original options if useInitialOptions is set
		if (data.useInitialOptions && data[el.name] === undefined) {
			return;
		}

		var check = data[el.name] === '' || !!data[el.name];
		$(el).prop('checked', check);
	});

	if (data.prependReason && data.reason) {
		form.reason.value = data.reason + '؛ ' + form.reason.value;
	} else {
		form.reason.value = data.reason || '';
	}

	// Clear and/or set any partial page or namespace restrictions
	if (form.pagerestrictions) {
		var $pageSelect = $(form).find('[name=pagerestrictions]');
		var $namespaceSelect = $(form).find('[name=namespacerestrictions]');

		// Respect useInitialOptions by clearing data when switching presets
		// In practice, this will always clear, since no partial presets use it
		if (!data.useInitialOptions) {
			$pageSelect.val(null).trigger('change');
			$namespaceSelect.val(null).trigger('change');
		}

		// Add any preset options; in practice, just used for prior block settings
		if (data.restrictions) {
			if (data.restrictions.pages && !$pageSelect.val().length) {
				var pages = data.restrictions.pages.map(function(pr) {
					return pr.title;
				});
				// since page restrictions use an ajax source, we
				// short-circuit that and just add a new option
				pages.forEach(function(page) {
					if (!$pageSelect.find("option[value='" + $.escapeSelector(page) + "']").length) {
						var newOption = new Option(page, page, true, true);
						$pageSelect.append(newOption);
					}
				});
				$pageSelect.val($pageSelect.val().concat(pages)).trigger('change');
			}
			if (data.restrictions.namespaces) {
				$namespaceSelect.val($namespaceSelect.val().concat(data.restrictions.namespaces)).trigger('change');
			}
		}
	}
};

Twinkle.block.callback.change_template = function twinkleblockcallbackChangeTemplate(e) {
	var form = e.target.form, value = form.template.value, settings = Twinkle.block.blockPresetsInfo[value];

	var blockBox = $(form).find('[name=actiontype][value=block]').is(':checked');
	var partialBox = $(form).find('[name=actiontype][value=partial]').is(':checked');
	var templateBox = $(form).find('[name=actiontype][value=template]').is(':checked');

	// Block form is not present
	if (!blockBox) {
		if (settings.indefinite || settings.nonstandard) {
			if (Twinkle.block.prev_template_expiry === null) {
				Twinkle.block.prev_template_expiry = form.template_expiry.value || '';
			}
			form.template_expiry.parentNode.style.display = 'none';
			form.template_expiry.value = 'infinity';
		} else if (form.template_expiry.parentNode.style.display === 'none') {
			if (Twinkle.block.prev_template_expiry !== null) {
				form.template_expiry.value = Twinkle.block.prev_template_expiry;
				Twinkle.block.prev_template_expiry = null;
			}
			form.template_expiry.parentNode.style.display = 'block';
		}
		if (Twinkle.block.prev_template_expiry) {
			form.expiry.value = Twinkle.block.prev_template_expiry;
		}
		Morebits.quickForm.setElementVisibility(form.notalk.parentNode, !settings.nonstandard);
		// Partial
		Morebits.quickForm.setElementVisibility(form.noemail_template.parentNode, partialBox);
		Morebits.quickForm.setElementVisibility(form.nocreate_template.parentNode, partialBox);
	} else if (templateBox) { // Only present if block && template forms both visible
		Morebits.quickForm.setElementVisibility(
			form.blank_duration.parentNode,
			!settings.indefinite && !settings.nonstandard
		);
	}

	Morebits.quickForm.setElementVisibility(form.dstopic.parentNode, value === 'uw-aeblock' || value === 'uw-aepblock');

	// Only particularly relevant if template form is present
	Morebits.quickForm.setElementVisibility(form.article.parentNode, settings && !!settings.pageParam);
	Morebits.quickForm.setElementVisibility(form.block_reason.parentNode, settings && !!settings.reasonParam);

	// Partial block
	Morebits.quickForm.setElementVisibility(form.area.parentNode, partialBox && !blockBox);

	form.root.previewer.closePreview();
};
Twinkle.block.prev_template_expiry = null;

Twinkle.block.callback.preview = function twinkleblockcallbackPreview(form) {
	var params = {
		article: form.article.value,
		blank_duration: form.blank_duration ? form.blank_duration.checked : false,
		disabletalk: form.disabletalk.checked || (form.notalk ? form.notalk.checked : false),
		expiry: form.template_expiry ? form.template_expiry.value : form.expiry.value,
		hardblock: Twinkle.block.isRegistered ? form.autoblock.checked : form.hardblock.checked,
		indefinite: Morebits.string.isInfinity(form.template_expiry ? form.template_expiry.value : form.expiry.value),
		reason: form.block_reason.value,
		template: form.template.value,
		dstopic: form.dstopic.value,
		partial: $(form).find('[name=actiontype][value=partial]').is(':checked'),
		pagerestrictions: $(form.pagerestrictions).val() || [],
		namespacerestrictions: $(form.namespacerestrictions).val() || [],
		noemail: form.noemail.checked || (form.noemail_template ? form.noemail_template.checked : false),
		nocreate: form.nocreate.checked || (form.nocreate_template ? form.nocreate_template.checked : false),
		area: form.area.value
	};

	var templateText = Twinkle.block.callback.getBlockNoticeWikitext(params);

	form.previewer.beginRender(templateText, 'بحث_کاربر:' + relevantUserName); // Force wikitext/correct username
};

Twinkle.block.callback.evaluate = function twinkleblockCallbackEvaluate(e) {
	var $form = $(e.target),
		toBlock = $form.find('[name=actiontype][value=block]').is(':checked'),
		toWarn = $form.find('[name=actiontype][value=template]').is(':checked'),
		toPartial = $form.find('[name=actiontype][value=partial]').is(':checked'),
		blockoptions = {}, templateoptions = {};

	Twinkle.block.callback.saveFieldset($form.find('[name=field_block_options]'));
	Twinkle.block.callback.saveFieldset($form.find('[name=field_template_options]'));

	blockoptions = Twinkle.block.field_block_options;

	templateoptions = Twinkle.block.field_template_options;

	templateoptions.disabletalk = !!(templateoptions.disabletalk || blockoptions.disabletalk);
	templateoptions.hardblock = !!blockoptions.hardblock;

	delete blockoptions.expiry_preset; // remove extraneous

	// Partial API requires this to be gone, not false or 0
	if (toPartial) {
		blockoptions.partial = templateoptions.partial = true;
	}
	templateoptions.pagerestrictions = $form.find('[name=pagerestrictions]').val() || [];
	templateoptions.namespacerestrictions = $form.find('[name=namespacerestrictions]').val() || [];
	// Format for API here rather than in saveFieldset
	blockoptions.pagerestrictions = templateoptions.pagerestrictions.join('|');
	blockoptions.namespacerestrictions = templateoptions.namespacerestrictions.join('|');

	// use block settings as warn options where not supplied
	templateoptions.summary = templateoptions.summary || blockoptions.reason;
	templateoptions.expiry = templateoptions.template_expiry || blockoptions.expiry;

	if (toBlock) {
		if (blockoptions.partial) {
			if (blockoptions.disabletalk && blockoptions.namespacerestrictions.indexOf('3') === -1) {
				return alert('قطع دسترسی موردی مانع از دسترسی کاربر به صفحهٔ بحث نمی‌شود؛ مگر آن که دسترسی کاربر به‌صورت موردی به فضای نام بحث کاربر نیز بسته شود!');
			}
			if (!blockoptions.namespacerestrictions && !blockoptions.pagerestrictions) {
				if (!blockoptions.noemail && !blockoptions.nocreate) { // Blank entries technically allowed [[phab:T208645]]
					return alert('هیچ صفحه یا فضای نامی انتخاب نشده است و محدودیتی برای ایمیل یا ایجاد حساب نیز اعمال نشده است؛ برای اعمال قطع دسترسی موردی لطفاً دست کم یک گزینه را انتخاب کنید!');
				} else if ((templateoptions.template !== 'هبک-بستن موردی ایمیل' || $form.find('select[name="preset"]').val() !== 'هبک-بستن موردی ایمیل') &&
					// Don't require confirmation if email harassment defaults are set
					!confirm('شما در حال قطع دسترسی بدون اعمال محدودیت ویرایشی در صفحه‌ها یا فضاهای نام خاص هستید. آیا می‌خواهید ادامه دهید؟')) {
					return;
				}
			}
		}
		if (!blockoptions.expiry) {
			return alert('لطفاً تاریخ منقضی شدن قطع دسترسی را مشخص کنید!');
		} else if (Morebits.string.isInfinity(blockoptions.expiry) && !Twinkle.block.isRegistered) {
			return alert("نشانی‌های آی‌پی را نمی‌توان بی‌پایان بست!");
		}
		if (!blockoptions.reason) {
			return alert('لطفاً دلیلی برای قطع دسترسی وارد کنید!');
		}

		Morebits.simpleWindow.setButtonsEnabled(false);
		Morebits.status.init(e.target);
		var statusElement = new Morebits.status('در حال اعمال قطع دسترسی');
		blockoptions.action = 'block';

		blockoptions.user = relevantUserName;

		// boolean-flipped options
		blockoptions.anononly = blockoptions.hardblock ? undefined : true;
		blockoptions.allowusertalk = blockoptions.disabletalk ? undefined : true;

		/*
		  Check if block status changed while processing the form.

		  There's a lot to consider here. list=blocks provides the
		  current block status, but there are at least two issues with
		  relying on it. First, the id doesn't update on a reblock,
		  meaning the individual parameters need to be compared. This
		  can be done roughly with JSON.stringify - we can thankfully
		  rely on order from the server, although sorting would be
		  fine if not - but falsey values are problematic and is
		  non-ideal. More importantly, list=blocks won't indicate if a
		  non-blocked user is blocked then unblocked. This should be
		  exceedingy rare, but regardless, we thus need to check
		  list=logevents, which has a nicely updating logid
		  parameter. We can't rely just on that, though, since it
		  doesn't account for blocks that have expired on their own.

		  As such, we use both. Using some ternaries, the logid
		  variables are false if there's no logevents, so if they
		  aren't equal we defintely have a changed entry (send
		  confirmation). If they are equal, then either the user was
		  never blocked (the block statuses will be equal, no
		  confirmation) or there's no new block, in which case either
		  a block expired (different statuses, confirmation) or the
		  same block is still active (same status, no confirmation).
		*/
		var query = {
			format: 'json',
			action: 'query',
			list: 'blocks|logevents',
			letype: 'block',
			lelimit: 1,
			letitle: 'کاربر:' + blockoptions.user
		};
		// bkusers doesn't catch single IPs blocked as part of a range block
		if (mw.util.isIPAddress(blockoptions.user, true)) {
			query.bkip = blockoptions.user;
		} else {
			query.bkusers = blockoptions.user;
		}
		api.get(query).then(function(data) {
			var block = data.query.blocks[0];
			// As with the initial data fetch, if an IP is blocked
			// *and* rangeblocked, this would only grab whichever
			// block is more recent, which would likely mean a
			// mismatch.  However, if the rangeblock is updated
			// while filling out the form, this won't detect that,
			// but that's probably fine.
			if (data.query.blocks.length > 1 && block.user !== relevantUserName) {
				block = data.query.blocks[1];
			}
			var logevents = data.query.logevents[0];
			var logid = data.query.logevents.length ? logevents.logid : false;

			if (logid !== Twinkle.block.blockLogId || !!block !== !!Twinkle.block.currentBlockInfo) {
				var message = 'وضعیت قطع دسترسی ' + blockoptions.user + ' تغییر یافت. ';
				if (block) {
					message += 'وضعیت جدید: ';
				} else {
					message += 'آخرین مورد: ';
				}

				var logExpiry = '';
				if (logevents.params.duration) {
					if (logevents.params.duration === 'infinity') {
						logExpiry = '؛ بی‌پایان';
					} else {
						var expiryDate = new Morebits.date(logevents.params.expiry);
						logExpiry += (expiryDate.isBefore(new Date()) ? '، منقضی‌شده در ' : ' تا ') + expiryDate.calendar();
					}
				} else { // no duration, action=unblock, just show timestamp
					logExpiry = ' ' + new Morebits.date(logevents.timestamp).calendar();
				}
				message += logActionsTranslations[logevents.action] + ' توسط ' + logevents.user + logExpiry +
					' با دلیل «' + logevents.comment + '». آیا می‌خواهید تنظیمات خود را جایگزین کنید؟';

				if (!confirm(message)) {
					Morebits.status.info('در حال اعمال قطع دسترسی', 'توسط کاربر لغو شد');
					return;
				}
				blockoptions.reblock = 1; // Writing over a block will fail otherwise
			}

			// execute block
			blockoptions.tags = Twinkle.changeTags;
			blockoptions.token = mw.user.tokens.get('csrfToken');
			var mbApi = new Morebits.wiki.api('در حال اعمال قطع دسترسی', blockoptions, function() {
				statusElement.info('کامل شد');
				if (toWarn) {
					Twinkle.block.callback.issue_template(templateoptions);
				}
			});
			mbApi.post();
		});
	} else if (toWarn) {
		Morebits.simpleWindow.setButtonsEnabled(false);

		Morebits.status.init(e.target);
		Twinkle.block.callback.issue_template(templateoptions);
	} else {
		return alert('از توینکل می‌خواهید که چه کاری را انجام دهد؟!');
	}
};

Twinkle.block.callback.issue_template = function twinkleblockCallbackIssueTemplate(formData) {
	// Use wgRelevantUserName to ensure the block template goes to a single IP and not to the
	// "talk page" of an IP range (which does not exist)
	var userTalkPage = 'بحث_کاربر:' + mw.config.get('wgRelevantUserName');

	var params = $.extend(formData, {
		messageData: Twinkle.block.blockPresetsInfo[formData.template],
		reason: Twinkle.block.field_template_options.block_reason,
		disabletalk: Twinkle.block.field_template_options.notalk,
		noemail: Twinkle.block.field_template_options.noemail_template,
		nocreate: Twinkle.block.field_template_options.nocreate_template
	});

	Morebits.wiki.actionCompleted.redirect = userTalkPage;
	Morebits.wiki.actionCompleted.notice = 'کارها انجام شدند؛ در حال بارگیری صفحهٔ بحث کاربر تا چند لحظهٔ دیگر';

	var wikipedia_page = new Morebits.wiki.page(userTalkPage, 'اعمال تغییرات در صفحهٔ بحث کاربر');
	wikipedia_page.setCallbackParameters(params);
	wikipedia_page.load(Twinkle.block.callback.main);
};

Twinkle.block.callback.getBlockNoticeWikitext = function(params) {
	var text = '{{', settings = Twinkle.block.blockPresetsInfo[params.template];
	if (!settings.nonstandard) {
		text += 'جا:' + params.template;
		if (params.article && settings.pageParam) {
			text += '|page=' + params.article;
		}
		if (params.dstopic) {
			text += '|topic=' + params.dstopic;
		}

		if (!/te?mp|^\s*$|min/.exec(params.expiry)) {
			if (params.indefinite) {
				text += '|indef=yes';
			} else if (!params.blank_duration && !new Morebits.date(params.expiry).isValid()) {
				// Block template wants a duration, not date
				text += '|time=' + params.expiry;
			}
		}

		if (!Twinkle.block.isRegistered && !params.hardblock) {
			text += '|anon=yes';
		}

		if (params.reason) {
			text += '|reason=' + params.reason;
		}
		if (params.disabletalk) {
			text += '|notalk=yes';
		}

		// Currently, all partial block templates are "standard"
		// Building the template, however, takes a fair bit of logic
		if (params.partial) {
			if (params.pagerestrictions.length || params.namespacerestrictions.length) {
				var makeSentence = function (array) {
					if (array.length < 3) {
						return array.join(' و ');
					}
					var last = array.pop();
					return array.join('، ') + ' و ' + last;

				};
				text += '|area=' + (params.indefinite ? 'برخی ' : 'از برخی ');
				if (params.pagerestrictions.length) {
					text += 'صفحه‌ها (' + makeSentence(params.pagerestrictions.map(function(p) {
						return '[[:' + p + ']]';
					}));
					text += params.namespacerestrictions.length ? ') و برخی ' : ')';
				}
				if (params.namespacerestrictions.length) {
					// 1 => Talk, 2 => User, etc.
					var namespaceNames = params.namespacerestrictions.map(function(id) {
						return menuFormattedNamespaces[id];
					});
					text += '[[ویکی‌پدیا:فضای نام|فضاهای نام]] (' + makeSentence(namespaceNames) + ')';
				}
			} else if (params.area) {
				text += '|area=' + params.area;
			} else {
				if (params.noemail) {
					text += '|email=yes';
				}
				if (params.nocreate) {
					text += '|accountcreate=yes';
				}
			}
		}
	} else {
		text += params.template;
	}

	if (settings.sig) {
		text += '|sig=' + settings.sig;
	}
	return text + '}}';
};

Twinkle.block.callback.main = function twinkleblockcallbackMain(pageobj) {
	var params = pageobj.getCallbackParameters(),
		date = new Morebits.date(pageobj.getLoadTime()),
		messageData = params.messageData,
		text;

	params.indefinite = Morebits.string.isInfinity(params.expiry);

	if (Twinkle.getPref('blankTalkpageOnIndefBlock') && params.template !== 'هبک-قطع دسترسی تهدید' && params.indefinite) {
		Morebits.status.info('اطلاعات', 'در حال خالی کردن صفحهٔ بحث با پیروی از ترجیحات و ایجاد یک بخش جدید برای ماه کنونی');
		text = date.monthHeader() + '\n';
	} else {
		text = pageobj.getPageText();

		var dateHeaderRegex = date.monthHeaderRegex(), dateHeaderRegexLast, dateHeaderRegexResult;
		while ((dateHeaderRegexLast = dateHeaderRegex.exec(text)) !== null) {
			dateHeaderRegexResult = dateHeaderRegexLast;
		}
		// If dateHeaderRegexResult is null then lastHeaderIndex is never checked. If it is not null but
		// \n== is not found, then the date header must be at the very start of the page. lastIndexOf
		// returns -1 in this case, so lastHeaderIndex gets set to 0 as desired.
		var lastHeaderIndex = text.lastIndexOf('\n==') + 1;

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

		if (!dateHeaderRegexResult || dateHeaderRegexResult.index !== lastHeaderIndex) {
			Morebits.status.info('اطلاعات', 'از آنجا که بخشی برای ماه کنونی در صفحهٔ بحث یافت نشد، بخشی جدید برای این ماه ایجاد خواهد شد');
			text += date.monthHeader() + '\n';
		}
	}

	params.expiry = typeof params.template_expiry !== 'undefined' ? params.template_expiry : params.expiry;

	text += Twinkle.block.callback.getBlockNoticeWikitext(params);

	// build the edit summary
	var summary = messageData.summary;
	if (messageData.suppressArticleInSummary !== true && params.article) {
		summary += ' در [[:' + params.article + ']]';
	}
	summary += '.';

	pageobj.setPageText(text);
	pageobj.setEditSummary(summary);
	pageobj.setChangeTags(Twinkle.changeTags);
	pageobj.setWatchlist(Twinkle.getPref('watchWarnings'));
	pageobj.save();
};

Twinkle.addInitCallback(Twinkle.block, 'block');
})(jQuery);


// </nowiki>