<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
	<id>https://wiki.conlinguistics.jp/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Yuhr</id>
	<title>人工言語学Wiki - 利用者の投稿記録 [ja]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.conlinguistics.jp/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Yuhr"/>
	<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/%E7%89%B9%E5%88%A5:%E6%8A%95%E7%A8%BF%E8%A8%98%E9%8C%B2/Yuhr"/>
	<updated>2026-04-19T08:44:28Z</updated>
	<subtitle>利用者の投稿記録</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked.js&amp;diff=967</id>
		<title>MediaWiki:Gadget-MarkBLocked.js</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked.js&amp;diff=967"/>
		<updated>2025-04-13T16:36:01Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「//&amp;lt;nowiki&amp;gt; /* global mw */ (() =&amp;gt; { 	const moduleName = &amp;#039;ext.gadget.MarkBLocked-core&amp;#039;; 	const loadModule = () =&amp;gt; { 		mw.loader.using(moduleName) 			.then((req) =&amp;gt; { 				const MarkBLocked = req(moduleName); 				MarkBLocked.init({ 					lang: &amp;#039;ja&amp;#039;, 					contribsCA: [ 						&amp;#039;投稿記録&amp;#039;, 						&amp;#039;アカウント統一管理&amp;#039;, 						&amp;#039;統一ログインの管理&amp;#039; 					] 				}); 			}) 			.catch(console.error); 	}; 	if (!mw.loader.getState(moduleName)) { // Module doesn&amp;#039;t e…」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;//&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/* global mw */&lt;br /&gt;
(() =&amp;gt; {&lt;br /&gt;
	const moduleName = &#039;ext.gadget.MarkBLocked-core&#039;;&lt;br /&gt;
	const loadModule = () =&amp;gt; {&lt;br /&gt;
		mw.loader.using(moduleName)&lt;br /&gt;
			.then((req) =&amp;gt; {&lt;br /&gt;
				const MarkBLocked = req(moduleName);&lt;br /&gt;
				MarkBLocked.init({&lt;br /&gt;
					lang: &#039;ja&#039;,&lt;br /&gt;
					contribsCA: [&lt;br /&gt;
						&#039;投稿記録&#039;,&lt;br /&gt;
						&#039;アカウント統一管理&#039;,&lt;br /&gt;
						&#039;統一ログインの管理&#039;&lt;br /&gt;
					]&lt;br /&gt;
				});&lt;br /&gt;
			})&lt;br /&gt;
			.catch(console.error);&lt;br /&gt;
	};&lt;br /&gt;
	if (!mw.loader.getState(moduleName)) { // Module doesn&#039;t exist locally&lt;br /&gt;
		mw.loader.getScript(&#039;https://dev-wiki.conlinguistics.jp/load.php?modules=&#039; + moduleName) // Import the module&lt;br /&gt;
			.then(loadModule)&lt;br /&gt;
			.catch(console.error);&lt;br /&gt;
	} else {&lt;br /&gt;
		loadModule();&lt;br /&gt;
	}&lt;br /&gt;
	const lang = mw.config.get(&#039;wgContentLanguage&#039;);&lt;br /&gt;
	if (lang !== &#039;ja&#039;) {&lt;br /&gt;
		console.warn(&lt;br /&gt;
			&#039;Language mismatch: [[w:ja:MediaWiki:Gadget-MarkBLocked.js]] is configured specifically for Japanese wikis, &#039; +&lt;br /&gt;
			`but this wiki uses &amp;quot;${lang}&amp;quot; as its content language.`&lt;br /&gt;
		);&lt;br /&gt;
	}&lt;br /&gt;
})();&lt;br /&gt;
//&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked-core.js&amp;diff=966</id>
		<title>MediaWiki:Gadget-MarkBLocked-core.js</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked-core.js&amp;diff=966"/>
		<updated>2025-04-13T16:35:34Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「/**  * MarkBLocked-core  * @author User:Dragoniez  * @version 3.1.4  *  * @see https://ja.wikipedia.org/wiki/MediaWiki:Gadget-MarkBLocked-core.css Style sheet  * @see https://ja.wikipedia.org/wiki/MediaWiki:Gadget-MarkBLocked.js Loader module  *  * Information:  * @see https://ja.wikipedia.org/wiki/Help:MarkBLocked About the jawiki gadget  *  * Global user script that uses this module:  * @see https://meta.wikimedia.org/wiki/User:Dragoniez/MarkBLockedGlobal.js…」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/**&lt;br /&gt;
 * MarkBLocked-core&lt;br /&gt;
 * @author [[User:Dragoniez]]&lt;br /&gt;
 * @version 3.1.4&lt;br /&gt;
 *&lt;br /&gt;
 * @see https://ja.wikipedia.org/wiki/MediaWiki:Gadget-MarkBLocked-core.css Style sheet&lt;br /&gt;
 * @see https://ja.wikipedia.org/wiki/MediaWiki:Gadget-MarkBLocked.js Loader module&lt;br /&gt;
 *&lt;br /&gt;
 * Information:&lt;br /&gt;
 * @see https://ja.wikipedia.org/wiki/Help:MarkBLocked About the jawiki gadget&lt;br /&gt;
 *&lt;br /&gt;
 * Global user script that uses this module:&lt;br /&gt;
 * @see https://meta.wikimedia.org/wiki/User:Dragoniez/MarkBLockedGlobal.js&lt;br /&gt;
 * @see https://meta.wikimedia.org/wiki/User:Dragoniez/MarkBLockedGlobal English help page&lt;br /&gt;
 * @see https://meta.wikimedia.org/wiki/User:Dragoniez/MarkBLockedGlobal/ja Japanese help page&lt;br /&gt;
 *&lt;br /&gt;
 * You can import this gadget to your (WMF) wiki by preparing a loader module for it.&lt;br /&gt;
 * See the coding of the loader module above and `ConstructorConfig` below.&lt;br /&gt;
 *&lt;br /&gt;
 * You can also find helper type definitions on:&lt;br /&gt;
 * @link https://github.com/Dr4goniez/wiki-gadgets/blob/main/src/window/MarkBLocked.d.ts&lt;br /&gt;
 */&lt;br /&gt;
// @ts-check&lt;br /&gt;
/// &amp;lt;reference path=&amp;quot;./window/MarkBLocked.d.ts&amp;quot; /&amp;gt;&lt;br /&gt;
/* global mw, OO */&lt;br /&gt;
//&amp;lt;nowiki&amp;gt;&lt;br /&gt;
// const MarkBLocked = (() =&amp;gt; {&lt;br /&gt;
module.exports = (() =&amp;gt; {&lt;br /&gt;
class MarkBLocked {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * @typedef {object} UserOptions&lt;br /&gt;
	 * @property {boolean} genportlet&lt;br /&gt;
	 * @property {boolean} rangeblocks&lt;br /&gt;
	 * @property {boolean} g_locks&lt;br /&gt;
	 * @property {boolean} g_blocks&lt;br /&gt;
	 * @property {boolean} g_rangeblocks&lt;br /&gt;
	 */&lt;br /&gt;
	/**&lt;br /&gt;
	 * @typedef {object} ConstructorConfig&lt;br /&gt;
	 * @property {Partial&amp;lt;UserOptions&amp;gt;} [defaultOptions] Configured default option values, which will be merged into the&lt;br /&gt;
	 * default config options (i.e. supports partial overrides).&lt;br /&gt;
	 * @property {string} [optionKey] The key of `mw.user.options`, defaulted to `userjs-markblocked-config`.&lt;br /&gt;
	 * @property {boolean} [globalize] If `true`, save the options into global preferences.&lt;br /&gt;
	 * @property {Record&amp;lt;string, Lang&amp;gt;} [i18n] A language object to merge to {@link MarkBLocked.i18n}. Using this config makes&lt;br /&gt;
	 * it possible to configure the default interface messages and add a new interface language (for the latter to work, the&lt;br /&gt;
	 * {@link ConstructorConfig.lang|lang} config must also be configured.&lt;br /&gt;
	 * @property {string} [lang] The code of the language for the interface messages, defaulted to `en`.&lt;br /&gt;
	 * @property {string[]} [contribsCA] Special page aliases for Contributions and CentralAuth in the local language (no need&lt;br /&gt;
	 * to pass `Contributions`, `Contribs`, `CentralAuth`, `CA`, and `GlobalAccount`). If not provided, aliases are fetched from&lt;br /&gt;
	 * the API.&lt;br /&gt;
	 * @property {string[]} [groupsAHL] Local user groups with the `apihighlimits` user right, defaulted to `[&#039;sysop&#039;, &#039;bot&#039;]`.&lt;br /&gt;
	 */&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize `MarkBLocked`.&lt;br /&gt;
	 * @param {ConstructorConfig} [config]&lt;br /&gt;
	 * @returns {JQueryPromise&amp;lt;MarkBLocked&amp;gt;}&lt;br /&gt;
	 */&lt;br /&gt;
	static init(config) {&lt;br /&gt;
&lt;br /&gt;
		// Disallow a second run&lt;br /&gt;
		if (window.MarkBLockedLoaded) {&lt;br /&gt;
			const err = &#039;Looks like MarkBLocked is loaded from multiple sources.&#039;;&lt;br /&gt;
			mw.notify(err, {type: &#039;error&#039;, autoHideSeconds: &#039;long&#039;});&lt;br /&gt;
			throw new Error(err);&lt;br /&gt;
		} else {&lt;br /&gt;
			window.MarkBLockedLoaded = true;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		const cfg = config || {};&lt;br /&gt;
&lt;br /&gt;
		// Wait for dependent modules to get ready&lt;br /&gt;
		const modules = [&lt;br /&gt;
			&#039;mediawiki.user&#039;,&lt;br /&gt;
			&#039;mediawiki.api&#039;,&lt;br /&gt;
			&#039;mediawiki.ForeignApi&#039;,&lt;br /&gt;
			&#039;mediawiki.util&#039;,&lt;br /&gt;
			&#039;jquery.ui&#039;,&lt;br /&gt;
			&#039;oojs-ui&#039;,&lt;br /&gt;
			&#039;oojs-ui.styles.icons-moderation&#039;,&lt;br /&gt;
		];&lt;br /&gt;
		const onConfig = mw.config.get(&#039;wgNamespaceNumber&#039;) === -1 &amp;amp;&amp;amp; /^(markblockedconfig|mblc)$/i.test(mw.config.get(&#039;wgTitle&#039;));&lt;br /&gt;
		const isRCW = [&#039;Recentchanges&#039;, &#039;Watchlist&#039;].indexOf(mw.config.get(&#039;wgCanonicalSpecialPageName&#039;) || &#039;&#039;) !== -1;&lt;br /&gt;
		if (!onConfig &amp;amp;&amp;amp; !isRCW) {&lt;br /&gt;
			modules.splice(5);&lt;br /&gt;
		}&lt;br /&gt;
		return mw.loader.using(modules).then(() =&amp;gt; { // When ready&lt;br /&gt;
&lt;br /&gt;
			// For backwards compatibility, clear old config if any&lt;br /&gt;
			/** @type {JQueryPromise&amp;lt;void&amp;gt;} */&lt;br /&gt;
			const backwards = (() =&amp;gt; {&lt;br /&gt;
				const oldOptionKey = &#039;userjs-gmbl-preferences&#039;;&lt;br /&gt;
				/** @type {string?} */&lt;br /&gt;
				const oldCfgStr = mw.user.options.get(oldOptionKey);&lt;br /&gt;
				if (&lt;br /&gt;
					oldCfgStr &amp;amp;&amp;amp;&lt;br /&gt;
					(cfg.optionKey === void 0 || cfg.optionKey === MarkBLocked.defaultOptionKey) &amp;amp;&amp;amp;&lt;br /&gt;
					!mw.user.options.get(MarkBLocked.defaultOptionKey)&lt;br /&gt;
				) {&lt;br /&gt;
					const options = {&lt;br /&gt;
						[oldOptionKey]: null,&lt;br /&gt;
						[MarkBLocked.defaultOptionKey]: oldCfgStr&lt;br /&gt;
					};&lt;br /&gt;
					return new mw.Api(this.getApiOptions()).saveOptions(options).then(() =&amp;gt; {&lt;br /&gt;
						mw.user.options.set(options);&lt;br /&gt;
					});&lt;br /&gt;
				} else {&lt;br /&gt;
					return $.Deferred().resolve();&lt;br /&gt;
				}&lt;br /&gt;
			})();&lt;br /&gt;
&lt;br /&gt;
			// Entry point&lt;br /&gt;
			const /** @type {JQueryPromise&amp;lt;string[]?&amp;gt;} */ ccaDeferred =&lt;br /&gt;
				onConfig ?&lt;br /&gt;
				$.Deferred().resolve([]) :&lt;br /&gt;
				cfg.contribsCA ?&lt;br /&gt;
				$.Deferred().resolve(cfg.contribsCA) :&lt;br /&gt;
				this.getContribsCA();&lt;br /&gt;
			return $.when(ccaDeferred, backwards, $.ready).then((contribsCA) =&amp;gt; { // contribsCA and backwards are resolved, and the DOM is ready&lt;br /&gt;
&lt;br /&gt;
				if (contribsCA) {&lt;br /&gt;
					cfg.contribsCA = contribsCA;&lt;br /&gt;
				} else {&lt;br /&gt;
					console.warn(&#039;MarkBLocked: Failed to get special page aliases.&#039;);&lt;br /&gt;
					cfg.contribsCA = [];&lt;br /&gt;
				}&lt;br /&gt;
&lt;br /&gt;
				const mbl = new MarkBLocked(cfg);&lt;br /&gt;
				if (onConfig) {&lt;br /&gt;
					mbl.createConfigInterface();&lt;br /&gt;
				} else {&lt;br /&gt;
&lt;br /&gt;
					mbl.createPortletLink();&lt;br /&gt;
&lt;br /&gt;
					// wikipage.content hook handler&lt;br /&gt;
					/**&lt;br /&gt;
					 * @type {NodeJS.Timeout=}&lt;br /&gt;
					 */&lt;br /&gt;
					let hookTimeout;&lt;br /&gt;
					/**&lt;br /&gt;
					 * @param {JQuery&amp;lt;HTMLElement&amp;gt;} [$content] Fall back to `.mw-body-content`&lt;br /&gt;
					 */&lt;br /&gt;
					const markup = ($content) =&amp;gt; {&lt;br /&gt;
						hookTimeout = void 0; // Reset the value of `hookTimeout`&lt;br /&gt;
						mbl.abort().markup($content || $(&#039;.mw-body-content&#039;));&lt;br /&gt;
					};&lt;br /&gt;
					/**&lt;br /&gt;
					 * A callback to `mw.hook(&#039;wikipage.content&#039;).add`.&lt;br /&gt;
					 * @param {JQuery&amp;lt;HTMLElement&amp;gt;} $content&lt;br /&gt;
					 * @see https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.hook-event-wikipage_content&lt;br /&gt;
					 */&lt;br /&gt;
					const hookHandler = ($content) =&amp;gt; {&lt;br /&gt;
						const isConnected = !!$(document).find($content).length;&lt;br /&gt;
						if (isConnected) {&lt;br /&gt;
							// Ensure that $content is attached to the DOM. The same hook can be fired multiple times,&lt;br /&gt;
							// but in some of them the hook is fired on an element detached (and removed) from the DOM.&lt;br /&gt;
							// It&#039;s useless to parse links in the element in such cases because the links are inaccessible.&lt;br /&gt;
							clearTimeout(hookTimeout); // Clear the reserved `markup` call, if any&lt;br /&gt;
							if ($content.find(&#039;a&#039;).length) {&lt;br /&gt;
								markup($content);&lt;br /&gt;
							}&lt;br /&gt;
						} else if (typeof hookTimeout !== &#039;number&#039;) {&lt;br /&gt;
							// When the hook is fired (any number of times), we want to ensure that `markup` is called&lt;br /&gt;
							// at least once. Reserve a `markup` call for when the `isConnected` block is never reached&lt;br /&gt;
							// in the set of `wikipage.content` events.&lt;br /&gt;
							hookTimeout = setTimeout(markup, 100);&lt;br /&gt;
						}&lt;br /&gt;
					};&lt;br /&gt;
					mw.hook(&#039;wikipage.content&#039;).add(hookHandler);&lt;br /&gt;
&lt;br /&gt;
					// Add a toggle button on RCW&lt;br /&gt;
					if (isRCW) {&lt;br /&gt;
						mbl.createToggleButton(hookHandler);&lt;br /&gt;
					}&lt;br /&gt;
&lt;br /&gt;
				}&lt;br /&gt;
				return mbl;&lt;br /&gt;
&lt;br /&gt;
			});&lt;br /&gt;
&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * @typedef {object} ApiOptions&lt;br /&gt;
	 * @property {number} [timeout]&lt;br /&gt;
	 * @property {boolean} [nonwritepost] Whether the instance is used only to read data though it issues POST requests&lt;br /&gt;
	 */&lt;br /&gt;
	/**&lt;br /&gt;
	 * Get API options to initialize a `mw.Api` instance.&lt;br /&gt;
	 *&lt;br /&gt;
	 * This method adds a User-Agent header and sets the default query parameters of:&lt;br /&gt;
	 * ```&lt;br /&gt;
	 * {&lt;br /&gt;
	 * 	action: &#039;query&#039;,&lt;br /&gt;
	 * 	format: &#039;json&#039;,&lt;br /&gt;
	 * 	formatversion: &#039;2&#039;&lt;br /&gt;
	 * }&lt;br /&gt;
	 * ```&lt;br /&gt;
	 * @param {ApiOptions} [options]&lt;br /&gt;
	 */&lt;br /&gt;
	static getApiOptions(options = {}) {&lt;br /&gt;
		const ret = {&lt;br /&gt;
			ajax: {&lt;br /&gt;
				headers: {&lt;br /&gt;
					&#039;Api-User-Agent&#039;: &#039;MarkBLocked-core/3.1.4 (https://ja.wikipedia.org/wiki/MediaWiki:Gadget-MarkBLocked-core.js)&#039;&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
			parameters: {&lt;br /&gt;
				action: &#039;query&#039;,&lt;br /&gt;
				format: &#039;json&#039;,&lt;br /&gt;
				formatversion: &#039;2&#039;&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		if (typeof options.timeout === &#039;number&#039;) {&lt;br /&gt;
			ret.ajax.timeout = options.timeout;&lt;br /&gt;
		}&lt;br /&gt;
		if (options.nonwritepost) {&lt;br /&gt;
			/** @see https://www.mediawiki.org/wiki/API:Etiquette#Other_notes */&lt;br /&gt;
			ret.ajax.headers[&#039;Promise-Non-Write-API-Action&#039;] = true;&lt;br /&gt;
		}&lt;br /&gt;
		return ret;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Get special page aliases for `Contributions` and `CentralAuth`.&lt;br /&gt;
	 * @returns {JQueryPromise&amp;lt;string[]?&amp;gt;}&lt;br /&gt;
	 * @requires mediawiki.api&lt;br /&gt;
	 * @requires mediawiki.ForeignApi&lt;br /&gt;
	 */&lt;br /&gt;
	static getContribsCA() {&lt;br /&gt;
		return new mw.Api(this.getApiOptions()).get({&lt;br /&gt;
			meta: &#039;siteinfo&#039;,&lt;br /&gt;
			siprop: &#039;specialpagealiases&#039;&lt;br /&gt;
		}).then(/** @param {ApiResponse} res */ (res) =&amp;gt; {&lt;br /&gt;
			const resSpa = res &amp;amp;&amp;amp; res.query &amp;amp;&amp;amp; res.query.specialpagealiases;&lt;br /&gt;
			if (Array.isArray(resSpa)) {&lt;br /&gt;
				const defaults = [&#039;Contributions&#039;, &#039;Contribs&#039;, &#039;CentralAuth&#039;, &#039;CA&#039;, &#039;GlobalAccount&#039;];&lt;br /&gt;
				return resSpa.reduce(/** @param {string[]} acc */ (acc, {realname, aliases}) =&amp;gt; {&lt;br /&gt;
					if (realname === &#039;Contributions&#039; || realname === &#039;CentralAuth&#039;) {&lt;br /&gt;
						acc = acc.concat(aliases.filter(el =&amp;gt; defaults.indexOf(el) === -1));&lt;br /&gt;
					}&lt;br /&gt;
					return acc;&lt;br /&gt;
				}, []);&lt;br /&gt;
			} else {&lt;br /&gt;
				return null;&lt;br /&gt;
			}&lt;br /&gt;
		}).catch((_, err) =&amp;gt; {&lt;br /&gt;
			console.warn(err);&lt;br /&gt;
			return null;&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Initialize the properties of the `MarkBLocked` class. This is only to be called by {@link MarkBLocked.init}.&lt;br /&gt;
	 * @param {ConstructorConfig} [cfg]&lt;br /&gt;
	 * @requires mediawiki.api&lt;br /&gt;
	 * @requires mediawiki.ForeignApi&lt;br /&gt;
	 * @requires mediawiki.user&lt;br /&gt;
	 */&lt;br /&gt;
	constructor(cfg = {}) {&lt;br /&gt;
&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {mw.Api}&lt;br /&gt;
		 */&lt;br /&gt;
		this.api = new mw.Api(MarkBLocked.getApiOptions({timeout: 60*1000}));&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {mw.Api}&lt;br /&gt;
		 */&lt;br /&gt;
		this.readApi = new mw.Api(MarkBLocked.getApiOptions({timeout: 60*1000, nonwritepost: true}));&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {mw.Api}&lt;br /&gt;
		 */&lt;br /&gt;
		this.metaApi = mw.config.get(&#039;wgWikiID&#039;) === &#039;metawiki&#039; ?&lt;br /&gt;
			this.api :&lt;br /&gt;
			new mw.ForeignApi(&lt;br /&gt;
				&#039;https://meta.wikimedia.org/w/api.php&#039;,&lt;br /&gt;
				/**&lt;br /&gt;
				 * On mobile devices, cross-origin requests may fail becase of a &amp;quot;badtoken&amp;quot; error related to&lt;br /&gt;
				 * `centralauthtoken`. This never happened with the `{anonymous: true}` option for `mw.ForeignApi`,&lt;br /&gt;
				 * hence included.&lt;br /&gt;
				 * @see https://doc.wikimedia.org/mediawiki-core/1.32.0/js/#!/api/mw.ForeignApi-method-constructor&lt;br /&gt;
				 * We will only need to send GET requests to fetch data, so this shouldn&#039;t be problematic.&lt;br /&gt;
				 */&lt;br /&gt;
				Object.assign(MarkBLocked.getApiOptions({timeout: 60*1000}), {anonymous: true})&lt;br /&gt;
			);&lt;br /&gt;
&lt;br /&gt;
		// Show Warning if the config has any invalid property&lt;br /&gt;
		const validKeys = [&#039;defaultOptions&#039;, &#039;optionKey&#039;, &#039;globalize&#039;, &#039;i18n&#039;, &#039;lang&#039;, &#039;contribsCA&#039;, &#039;groupsAHL&#039;];&lt;br /&gt;
		const invalidKeys = Object.keys(cfg).reduce(/** @param {string[]} acc */ (acc, key) =&amp;gt; {&lt;br /&gt;
			if (validKeys.indexOf(key) === -1) {&lt;br /&gt;
				acc.push(key);&lt;br /&gt;
			}&lt;br /&gt;
			return acc;&lt;br /&gt;
		}, []);&lt;br /&gt;
		if (invalidKeys.length) {&lt;br /&gt;
			console.error(&#039;MarkBLocked: Detected invalid constructor options: &#039; + invalidKeys.join(&#039;, &#039;));&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// User options&lt;br /&gt;
		/**&lt;br /&gt;
		 * The key of `mw.user.options`.&lt;br /&gt;
		 */&lt;br /&gt;
		this.optionKey = cfg.optionKey || MarkBLocked.defaultOptionKey;&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {UserOptions}&lt;br /&gt;
		 */&lt;br /&gt;
		this.options = (() =&amp;gt; {&lt;br /&gt;
			const defaultOptions = Object.assign({&lt;br /&gt;
				genportlet: true,&lt;br /&gt;
				rangeblocks: false,&lt;br /&gt;
				g_locks: false,&lt;br /&gt;
				g_blocks: false,&lt;br /&gt;
				g_rangeblocks: false&lt;br /&gt;
			}, cfg.defaultOptions);&lt;br /&gt;
			/** @type {string} */&lt;br /&gt;
			const optionsStr = mw.user.options.get(this.optionKey) || &#039;{}&#039;;&lt;br /&gt;
			/** @type {Record&amp;lt;string, boolean&amp;gt;} */&lt;br /&gt;
			let options;&lt;br /&gt;
			try {&lt;br /&gt;
				options = JSON.parse(optionsStr);&lt;br /&gt;
				// For backwards compatibility&lt;br /&gt;
				if (options.localips) {&lt;br /&gt;
					options.rangeblocks = options.localips;&lt;br /&gt;
					delete options.localips;&lt;br /&gt;
				}&lt;br /&gt;
				if (options.globalusers) {&lt;br /&gt;
					options.g_locks = options.globalusers;&lt;br /&gt;
					delete options.globalusers;&lt;br /&gt;
				}&lt;br /&gt;
				if (options.globalips) {&lt;br /&gt;
					options.g_rangeblocks = options.globalips;&lt;br /&gt;
					delete options.globalips;&lt;br /&gt;
				}&lt;br /&gt;
			} catch(err) {&lt;br /&gt;
				console.error(err);&lt;br /&gt;
				options = defaultOptions;&lt;br /&gt;
			}&lt;br /&gt;
			/** @type {UserOptions} */&lt;br /&gt;
			const ret = Object.assign(defaultOptions, options);&lt;br /&gt;
			if (ret.g_rangeblocks) {&lt;br /&gt;
				// g_blocks must be enabled when g_rangeblocks is enabled&lt;br /&gt;
				ret.g_blocks = true;&lt;br /&gt;
			}&lt;br /&gt;
			return ret;&lt;br /&gt;
		})();&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {boolean}&lt;br /&gt;
		 */&lt;br /&gt;
		this.globalize = !!cfg.globalize;&lt;br /&gt;
		console.log(&#039;MarkBLocked globalization: &#039; + this.globalize);&lt;br /&gt;
&lt;br /&gt;
		// Language options&lt;br /&gt;
		if (typeof cfg.i18n === &#039;object&#039; &amp;amp;&amp;amp; !Array.isArray(cfg.i18n) &amp;amp;&amp;amp; cfg.i18n !== null) {&lt;br /&gt;
			Object.assign(MarkBLocked.i18n, cfg.i18n);&lt;br /&gt;
		}&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {Lang}&lt;br /&gt;
		 */&lt;br /&gt;
		this.msg = (() =&amp;gt; {&lt;br /&gt;
			let langCode = &#039;en&#039;;&lt;br /&gt;
			if (cfg.lang !== void 0) {&lt;br /&gt;
				cfg.lang = String(cfg.lang);&lt;br /&gt;
			}&lt;br /&gt;
			if (cfg.lang) {&lt;br /&gt;
				if (cfg.lang in MarkBLocked.i18n) {&lt;br /&gt;
					langCode = cfg.lang;&lt;br /&gt;
				} else {&lt;br /&gt;
					console.error(`MarkBLocked does not have &amp;quot;${cfg.lang}&amp;quot; language support for its interface.`);&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			return MarkBLocked.i18n[langCode];&lt;br /&gt;
		})();&lt;br /&gt;
&lt;br /&gt;
		/**&lt;br /&gt;
		 * Regular expressions to collect user links.&lt;br /&gt;
		 * @typedef {object} LinkRegex&lt;br /&gt;
		 * @property {RegExp} article `/wiki/PAGENAME`: $1: PAGENAME&lt;br /&gt;
		 * @property {RegExp} script `/w/index.php?title=PAGENAME`: $1: PAGENAME&lt;br /&gt;
		 * @property {RegExp} contribsCA `^Special:(?:Contribs|CA)($|/)`&lt;br /&gt;
		 * @property {RegExp} user `^(?:Special:.../|User:)(USERNAME|CIDR)`: $1: USERNAME or CIDR&lt;br /&gt;
		 */&lt;br /&gt;
		/**&lt;br /&gt;
		 * @type {LinkRegex}&lt;br /&gt;
		 */&lt;br /&gt;
		this.regex = (() =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
			const wgNamespaceIds = mw.config.get(&#039;wgNamespaceIds&#039;); // {&amp;quot;special&amp;quot;: -1, &amp;quot;user&amp;quot;: 2, ...}&lt;br /&gt;
			const /** @type {string[]} */ specialAliases = [];&lt;br /&gt;
			const /** @type {string[]} */ userAliases = [];&lt;br /&gt;
			for (const alias in wgNamespaceIds) {&lt;br /&gt;
				const namespaceId = wgNamespaceIds[alias];&lt;br /&gt;
				switch(namespaceId) {&lt;br /&gt;
					case -1:&lt;br /&gt;
						specialAliases.push(alias);&lt;br /&gt;
						break;&lt;br /&gt;
					case 2:&lt;br /&gt;
					case 3:&lt;br /&gt;
						userAliases.push(alias);&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			let rContribsCA = cfg.contribsCA &amp;amp;&amp;amp; cfg.contribsCA.length ? &#039;|&#039; + cfg.contribsCA.join(&#039;|&#039;) : &#039;&#039;;&lt;br /&gt;
			rContribsCA = &#039;(?:&#039; + specialAliases.join(&#039;|&#039;) + &#039;):(?:contrib(?:ution)?s|ca|centralauth|globalaccount&#039; + rContribsCA + &#039;)&#039;;&lt;br /&gt;
			const rUser = &#039;(?:&#039; + userAliases.join(&#039;|&#039;) + &#039;):&#039;;&lt;br /&gt;
&lt;br /&gt;
			return {&lt;br /&gt;
				article: new RegExp(mw.config.get(&#039;wgArticlePath&#039;).replace(&#039;$1&#039;, &#039;([^#?]+)&#039;)),&lt;br /&gt;
				script: new RegExp(mw.config.get(&#039;wgScript&#039;) + &#039;\\?title=([^#&amp;amp;]+)&#039;),&lt;br /&gt;
				contribsCA: new RegExp(&#039;^&#039; + rContribsCA + &#039;($|/)&#039;, &#039;i&#039;),&lt;br /&gt;
				user: new RegExp(&#039;^(?:&#039; + rContribsCA + &#039;/|&#039; + rUser + &#039;)([^/#]+|[a-f\\d:\\.]+/\\d\\d)$&#039;, &#039;i&#039;)&lt;br /&gt;
			};&lt;br /&gt;
&lt;br /&gt;
		})();&lt;br /&gt;
&lt;br /&gt;
		/**&lt;br /&gt;
		 * The maximum number of batch parameter values for the API.&lt;br /&gt;
		 * @type {500|50}&lt;br /&gt;
		 */&lt;br /&gt;
		this.apilimit = (() =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
			const groupsAHLLocal = cfg.groupsAHL || [&#039;sysop&#039;, &#039;bot&#039;];&lt;br /&gt;
			const groupsAHLGlobal = [&lt;br /&gt;
				&#039;apihighlimits-requestor&#039;,&lt;br /&gt;
				&#039;founder&#039;,&lt;br /&gt;
				&#039;global-bot&#039;,&lt;br /&gt;
				// &#039;global-sysop&#039;,&lt;br /&gt;
				&#039;staff&#039;,&lt;br /&gt;
				&#039;steward&#039;,&lt;br /&gt;
				&#039;sysadmin&#039;,&lt;br /&gt;
				&#039;wmf-researcher&#039;&lt;br /&gt;
			];&lt;br /&gt;
			const groupsAHL = groupsAHLLocal.concat(groupsAHLGlobal);&lt;br /&gt;
			// @ts-ignore&lt;br /&gt;
			const hasAHL = mw.config.get(&#039;wgUserGroups&#039;, []).concat(mw.config.get(&#039;wgGlobalGroups&#039;, [])).some((group) =&amp;gt; groupsAHL.indexOf(group) !== -1);&lt;br /&gt;
&lt;br /&gt;
			return hasAHL ? 500 : 50;&lt;br /&gt;
&lt;br /&gt;
		})();&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Replace the page content with the MarkBLocked config interface.&lt;br /&gt;
	 * @returns {void}&lt;br /&gt;
	 * @requires oojs-ui&lt;br /&gt;
	 * @requires oojs-ui.styles.icons-moderation&lt;br /&gt;
	 * @requires mediawiki.api&lt;br /&gt;
	 * @requires mediawiki.user&lt;br /&gt;
	 */&lt;br /&gt;
	createConfigInterface() {&lt;br /&gt;
&lt;br /&gt;
		document.title = &#039;MarkBLockedConfig - &#039; + mw.config.get(&#039;wgSiteName&#039;);&lt;br /&gt;
&lt;br /&gt;
		// Collect DOM elements&lt;br /&gt;
		const $heading = $(&#039;.mw-first-heading&#039;);&lt;br /&gt;
		const $body = $(&#039;.mw-body-content&#039;);&lt;br /&gt;
		if (!$heading.length || !$body.length) {&lt;br /&gt;
			mw.notify(this.getMessage(&#039;config-notify-notloaded&#039;));&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		$heading.text(this.getMessage(&#039;config-label-heading&#039;));&lt;br /&gt;
&lt;br /&gt;
		// Transparent overlay of the container used to make elements in it unclickable&lt;br /&gt;
		const $overlay = $(&#039;&amp;lt;div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
		// General options&lt;br /&gt;
		const genportlet = new OO.ui.CheckboxInputWidget({&lt;br /&gt;
			selected: this.options.genportlet&lt;br /&gt;
		});&lt;br /&gt;
		const fsGeneral = new OO.ui.FieldsetLayout({&lt;br /&gt;
			label: this.getMessage(&#039;config-label-fsgeneral&#039;),&lt;br /&gt;
			items: [&lt;br /&gt;
				new OO.ui.FieldLayout(genportlet, {&lt;br /&gt;
					label: this.getMessage(&#039;config-label-genportlet&#039;),&lt;br /&gt;
					align: &#039;inline&#039;&lt;br /&gt;
				})&lt;br /&gt;
			]&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
		// Markup options&lt;br /&gt;
		const rangeblocks = new OO.ui.CheckboxInputWidget({&lt;br /&gt;
			selected: this.options.rangeblocks&lt;br /&gt;
		});&lt;br /&gt;
		const g_locks = new OO.ui.CheckboxInputWidget({&lt;br /&gt;
			selected: this.options.g_locks&lt;br /&gt;
		});&lt;br /&gt;
		const g_blocks = new OO.ui.CheckboxInputWidget({&lt;br /&gt;
			selected: this.options.g_blocks&lt;br /&gt;
		});&lt;br /&gt;
		const g_rangeblocks = new OO.ui.CheckboxInputWidget({&lt;br /&gt;
			selected: this.options.g_rangeblocks,&lt;br /&gt;
			disabled: !g_blocks.isSelected()&lt;br /&gt;
		});&lt;br /&gt;
		g_blocks.off(&#039;change&#039;).on(&#039;change&#039;, () =&amp;gt; {&lt;br /&gt;
			if (!g_blocks.isSelected()) {&lt;br /&gt;
				g_rangeblocks.setSelected(false).setDisabled(true);&lt;br /&gt;
			} else {&lt;br /&gt;
				g_rangeblocks.setDisabled(false);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
		/**&lt;br /&gt;
		 * @param {keyof Lang} key&lt;br /&gt;
		 * @param {boolean} [empty]&lt;br /&gt;
		 * @returns {JQuery&amp;lt;HTMLSpanElement&amp;gt;}&lt;br /&gt;
		 */&lt;br /&gt;
		const getExclMessage = (key, empty = false) =&amp;gt; {&lt;br /&gt;
			return $(&#039;&amp;lt;span&amp;gt;&#039;).append(&lt;br /&gt;
				$(&#039;&amp;lt;b&amp;gt;&#039;)&lt;br /&gt;
					.addClass(&#039;mblc-exclamation&#039;)&lt;br /&gt;
					.text(empty ? &#039;&#039; : &#039;!&#039;),&lt;br /&gt;
				this.getMessage(key)&lt;br /&gt;
			);&lt;br /&gt;
		};&lt;br /&gt;
		const fsMarkup = new OO.ui.FieldsetLayout({&lt;br /&gt;
			label: this.getMessage(&#039;config-label-fsmarkup&#039;),&lt;br /&gt;
			help: this.getMessage(&#039;config-help-resources&#039;),&lt;br /&gt;
			helpInline: true,&lt;br /&gt;
			items: [&lt;br /&gt;
				new OO.ui.FieldLayout(rangeblocks, {&lt;br /&gt;
					label: getExclMessage(&#039;config-label-rangeblocks&#039;),&lt;br /&gt;
					align: &#039;inline&#039;&lt;br /&gt;
				}),&lt;br /&gt;
				new OO.ui.FieldLayout(g_locks, {&lt;br /&gt;
					label: getExclMessage(&#039;config-label-g_locks&#039;),&lt;br /&gt;
					align: &#039;inline&#039;&lt;br /&gt;
				}),&lt;br /&gt;
				new OO.ui.FieldLayout(g_blocks, {&lt;br /&gt;
					label: getExclMessage(&#039;config-label-g_blocks&#039;, true),&lt;br /&gt;
					align: &#039;inline&#039;&lt;br /&gt;
				}),&lt;br /&gt;
				new OO.ui.FieldLayout(g_rangeblocks, {&lt;br /&gt;
					label: getExclMessage(&#039;config-label-g_rangeblocks&#039;),&lt;br /&gt;
					align: &#039;inline&#039;,&lt;br /&gt;
					help: this.getMessage(&#039;config-help-g_rangeblocks&#039;),&lt;br /&gt;
					helpInline: true&lt;br /&gt;
				})&lt;br /&gt;
			]&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
		// Save button&lt;br /&gt;
		const saveButton = new OO.ui.ButtonWidget({&lt;br /&gt;
			id: &#039;mblc-save&#039;,&lt;br /&gt;
			label: this.getMessage(&#039;config-label-save&#039;),&lt;br /&gt;
			icon: &#039;bookmarkOutline&#039;,&lt;br /&gt;
			flags: [&#039;primary&#039;, &#039;progressive&#039;]&lt;br /&gt;
		}).off(&#039;click&#039;).on(&#039;click&#039;, () =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
			$overlay.show();&lt;br /&gt;
&lt;br /&gt;
			// Change the save button&#039;s label&lt;br /&gt;
			saveButton.setIcon(null).setLabel(&lt;br /&gt;
				$(&#039;&amp;lt;span&amp;gt;&#039;)&lt;br /&gt;
					.append(&lt;br /&gt;
						$(&#039;&amp;lt;img&amp;gt;&#039;)&lt;br /&gt;
							.prop(&#039;src&#039;, &#039;//upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif&#039;)&lt;br /&gt;
							.css({&lt;br /&gt;
								verticalAlign: &#039;middle&#039;,&lt;br /&gt;
								height: &#039;1em&#039;,&lt;br /&gt;
								border: &#039;0&#039;,&lt;br /&gt;
								marginRight: &#039;1em&#039;&lt;br /&gt;
							}),&lt;br /&gt;
							document.createTextNode(this.getMessage(&#039;config-label-saving&#039;))&lt;br /&gt;
					)&lt;br /&gt;
			);&lt;br /&gt;
&lt;br /&gt;
			// Get config&lt;br /&gt;
			const /** @type {UserOptions} */ cfg = {&lt;br /&gt;
				genportlet: genportlet.isSelected(),&lt;br /&gt;
				rangeblocks: rangeblocks.isSelected(),&lt;br /&gt;
				g_locks: g_locks.isSelected(),&lt;br /&gt;
				g_blocks: g_blocks.isSelected(),&lt;br /&gt;
				g_rangeblocks: g_rangeblocks.isSelected()&lt;br /&gt;
			};&lt;br /&gt;
			const cfgStr = JSON.stringify(cfg);&lt;br /&gt;
&lt;br /&gt;
			// Save config&lt;br /&gt;
			this.api.postWithToken(&#039;csrf&#039;, {&lt;br /&gt;
				action: this.globalize ? &#039;globalpreferences&#039; : &#039;options&#039;,&lt;br /&gt;
				optionname: this.optionKey,&lt;br /&gt;
				optionvalue: cfgStr&lt;br /&gt;
			}).then(() =&amp;gt; {&lt;br /&gt;
				mw.user.options.set(this.optionKey, cfgStr);&lt;br /&gt;
				return null;&lt;br /&gt;
			}).catch(/** @param {string} code */ (code, err) =&amp;gt; {&lt;br /&gt;
				console.warn(err);&lt;br /&gt;
				return code;&lt;br /&gt;
			}).then(/** @param {string?} err */ (err) =&amp;gt; {&lt;br /&gt;
				if (err) {&lt;br /&gt;
					mw.notify(this.getMessage(&#039;config-notify-savefailed&#039;) + &#039;(&#039; + err + &#039;)&#039;, {type: &#039;error&#039;});&lt;br /&gt;
				} else {&lt;br /&gt;
					mw.notify(this.getMessage(&#039;config-notify-savedone&#039;), {type: &#039;success&#039;});&lt;br /&gt;
				}&lt;br /&gt;
				saveButton.setIcon(&#039;bookmarkOutline&#039;).setLabel(this.getMessage(&#039;config-label-save&#039;));&lt;br /&gt;
				$overlay.hide();&lt;br /&gt;
			});&lt;br /&gt;
&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
		// Construct the config body&lt;br /&gt;
		$body.empty().append(&lt;br /&gt;
			$(&#039;&amp;lt;div&amp;gt;&#039;)&lt;br /&gt;
				.prop(&#039;id&#039;, &#039;mblc-container&#039;)&lt;br /&gt;
				.append(&lt;br /&gt;
					$(&#039;&amp;lt;div&amp;gt;&#039;)&lt;br /&gt;
						.prop(&#039;id&#039;, &#039;mblc-optionfield&#039;)&lt;br /&gt;
						.append(&lt;br /&gt;
							fsGeneral.$element,&lt;br /&gt;
							fsMarkup.$element&lt;br /&gt;
						),&lt;br /&gt;
					saveButton.$element&lt;br /&gt;
				),&lt;br /&gt;
			$overlay&lt;br /&gt;
				.prop(&#039;id&#039;, &#039;mblc-container-overlay&#039;)&lt;br /&gt;
				.hide()&lt;br /&gt;
		);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Get an interface message of MarkBLocked.&lt;br /&gt;
	 * @param {keyof Lang} key&lt;br /&gt;
	 * @returns {string}&lt;br /&gt;
	 */&lt;br /&gt;
	getMessage(key) {&lt;br /&gt;
		return this.msg[key];&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Create a portlet link to the config page.&lt;br /&gt;
	 * @returns {void}&lt;br /&gt;
	 * @requires mediawiki.util&lt;br /&gt;
	 */&lt;br /&gt;
	createPortletLink() {&lt;br /&gt;
		if (this.options.genportlet) {&lt;br /&gt;
			const portlet = mw.util.addPortletLink(&lt;br /&gt;
				document.getElementById(&#039;p-tb&#039;) ? &#039;p-tb&#039; : &#039;p-personal&#039;, // p-tb doesn&#039;t exist on minerva&lt;br /&gt;
				mw.util.getUrl(&#039;Special:MarkBLockedConfig&#039;),&lt;br /&gt;
				this.getMessage(&#039;portlet-text&#039;),&lt;br /&gt;
				&#039;ca-mblc&#039;,&lt;br /&gt;
				this.getMessage(&#039;portlet-title&#039;)&lt;br /&gt;
			);&lt;br /&gt;
			if (!portlet) {&lt;br /&gt;
				console.error(&#039;Failed to create a portlet link for MarkBLocked.&#039;);&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Abort all unfinished requests issued by the MarkBLocked class instance.&lt;br /&gt;
	 * @returns {MarkBLocked}&lt;br /&gt;
	 */&lt;br /&gt;
	abort() {&lt;br /&gt;
		this.api.abort();&lt;br /&gt;
		this.readApi.abort();&lt;br /&gt;
		this.metaApi.abort();&lt;br /&gt;
		return this;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Create a button to enable/disable MarkBLocked (for Special:Recentchanges and Special:Watchlist, on which `markup`&lt;br /&gt;
	 * is recursively called when the page content is updated.)&lt;br /&gt;
	 * @param {($content: JQuery&amp;lt;HTMLElement&amp;gt;) =&amp;gt; void} hookHandler A function to (un)bind to the `wikipage.content` hook.&lt;br /&gt;
	 */&lt;br /&gt;
	createToggleButton(hookHandler) {&lt;br /&gt;
&lt;br /&gt;
		// Create toggle button&lt;br /&gt;
		const toggle = new OO.ui.ButtonWidget({&lt;br /&gt;
			id: &#039;mbl-toggle&#039;,&lt;br /&gt;
			label: &#039;MBL&#039;,&lt;br /&gt;
			icon: &#039;unLock&#039;,&lt;br /&gt;
			flags: &#039;progressive&#039;,&lt;br /&gt;
			title: this.getMessage(&#039;toggle-title-enabled&#039;)&lt;br /&gt;
		}).off(&#039;click&#039;).on(&#039;click&#039;, () =&amp;gt; {&lt;br /&gt;
			const disable = toggle.getFlags().indexOf(&#039;progressive&#039;) !== -1;&lt;br /&gt;
			let icon, title, hookToggle, msg;&lt;br /&gt;
			if (disable) {&lt;br /&gt;
				icon = &#039;lock&#039;;&lt;br /&gt;
				title = this.getMessage(&#039;toggle-title-disabled&#039;);&lt;br /&gt;
				hookToggle = mw.hook(&#039;wikipage.content&#039;).remove;&lt;br /&gt;
				msg = this.getMessage(&#039;toggle-notify-disabled&#039;);&lt;br /&gt;
				$(&#039;.mbl-userlink&#039;).removeClass((_, className) =&amp;gt; { // Remove all mbl- classes from user links&lt;br /&gt;
					return (className.match(/(^|\s)mbl-\S+/) || []).join(&#039; &#039;);&lt;br /&gt;
				});&lt;br /&gt;
			} else {&lt;br /&gt;
				icon = &#039;unLock&#039;;&lt;br /&gt;
				title = this.getMessage(&#039;toggle-title-enabled&#039;);&lt;br /&gt;
				hookToggle = mw.hook(&#039;wikipage.content&#039;).add;&lt;br /&gt;
				msg = this.getMessage(&#039;toggle-notify-enabled&#039;);&lt;br /&gt;
				// Hook.add fires the `wikipage.content` hook, meaning that `markup` is automatically called and classes are reassigned&lt;br /&gt;
			}&lt;br /&gt;
			toggle&lt;br /&gt;
				.setFlags({progressive: !disable, destructive: disable})&lt;br /&gt;
				.setIcon(icon)&lt;br /&gt;
				.setTitle(title);&lt;br /&gt;
			hookToggle(hookHandler);&lt;br /&gt;
			mw.notify(msg);&lt;br /&gt;
		});&lt;br /&gt;
		const $wrapper = $(&#039;&amp;lt;div&amp;gt;&#039;)&lt;br /&gt;
			.prop(&#039;id&#039;, &#039;mbl-toggle-wrapper&#039;)&lt;br /&gt;
			.append(toggle.$element);&lt;br /&gt;
&lt;br /&gt;
		// Append the toggle button&lt;br /&gt;
		const spName = mw.config.get(&#039;wgCanonicalSpecialPageName&#039;);&lt;br /&gt;
		let selector = &#039;&#039;;&lt;br /&gt;
		if (spName === &#039;Recentchanges&#039;) {&lt;br /&gt;
			selector = &#039;.mw-rcfilters-ui-cell.mw-rcfilters-ui-rcTopSectionWidget-savedLinks&#039;;&lt;br /&gt;
			$(selector).eq(0).before($wrapper);&lt;br /&gt;
		} else if (spName === &#039;Watchlist&#039;) {&lt;br /&gt;
			selector = &#039;.mw-rcfilters-ui-cell.mw-rcfilters-ui-watchlistTopSectionWidget-savedLinks&#039;;&lt;br /&gt;
			$(selector).eq(0).before($wrapper);&lt;br /&gt;
			$wrapper.css(&#039;margin-left&#039;, &#039;auto&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Mark up user links.&lt;br /&gt;
	 * @param {JQuery&amp;lt;HTMLElement&amp;gt;} $content&lt;br /&gt;
	 * @returns {void}&lt;br /&gt;
	 * @requires mediawiki.util&lt;br /&gt;
	 * @requires mediawiki.api&lt;br /&gt;
	 * @requires mediawiki.ForeignApi&lt;br /&gt;
	 */&lt;br /&gt;
	markup($content) {&lt;br /&gt;
&lt;br /&gt;
		if (!this.options.g_blocks &amp;amp;&amp;amp; this.options.g_rangeblocks) {&lt;br /&gt;
			throw new Error(&#039;g_rangeblocks is unexpectedly turned on when g_blocks is turned off.&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// Collect user links&lt;br /&gt;
		const {userLinks, users, ips} = this.collectLinks($content);&lt;br /&gt;
		if ($.isEmptyObject(userLinks)) {&lt;br /&gt;
			console.log(&#039;MarkBLocked&#039;, {&lt;br /&gt;
				$content,&lt;br /&gt;
				links: 0&lt;br /&gt;
			});&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		const allUsers = users.concat(ips);&lt;br /&gt;
&lt;br /&gt;
		// Start markup&lt;br /&gt;
		$.when(&lt;br /&gt;
			this.bulkMarkup(&#039;local&#039;, userLinks, allUsers),&lt;br /&gt;
			this.bulkMarkup(&#039;global&#039;, userLinks, this.options.g_blocks ? allUsers : [])&lt;br /&gt;
		).then((markedUsers, g_markedUsers) =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
			if (markedUsers === null &amp;amp;&amp;amp; g_markedUsers === null) { // Aborted&lt;br /&gt;
				return;&lt;br /&gt;
			} else if (markedUsers === null || g_markedUsers === null) {&lt;br /&gt;
				// bulkMarkup uses the same mw.Api instance, so the code is never supposed to reach this block&lt;br /&gt;
				throw new Error(&#039;Unexpected abortion&#039;);&lt;br /&gt;
			} else {&lt;br /&gt;
				console.log(&#039;MarkBLocked&#039;, {&lt;br /&gt;
					$content,&lt;br /&gt;
					links: $(&#039;.mbl-userlink&#039;).length,&lt;br /&gt;
					user_registered: users.length,&lt;br /&gt;
					user_anonymous: ips.length&lt;br /&gt;
				});&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			// Create a batch array for additional markups&lt;br /&gt;
			/** @type {BatchObject[]} */&lt;br /&gt;
			const batchArray = [];&lt;br /&gt;
			/**&lt;br /&gt;
			 * An array of IP addresses that are not blocked in themselves. Using this array, we will check&lt;br /&gt;
			 * for range blocks affecting the IPs. IPs can have multiple blocks in theory, but we filter&lt;br /&gt;
			 * out those that are CIDR-wise not narrowest. This means that blocked IPs&#039; user links will&lt;br /&gt;
			 * never be assigned more than one CSS class each, among `mbl-blocked-indef`, `mbl-blocked-temp`,&lt;br /&gt;
			 * and `mbl-blocked-partial`.&lt;br /&gt;
			 */&lt;br /&gt;
			let remainingIps;&lt;br /&gt;
			if (this.options.rangeblocks &amp;amp;&amp;amp; (remainingIps = ips.filter((ip) =&amp;gt; markedUsers.indexOf(ip) === -1)).length) {&lt;br /&gt;
				remainingIps.forEach((ip) =&amp;gt; {&lt;br /&gt;
					batchArray.push({&lt;br /&gt;
						username: ip,&lt;br /&gt;
						params: {&lt;br /&gt;
							list: &#039;blocks&#039;,&lt;br /&gt;
							bkip: ip,&lt;br /&gt;
							bkprop: &#039;user|by|expiry|reason|restrictions&#039;&lt;br /&gt;
						},&lt;br /&gt;
						callback: (res) =&amp;gt; {&lt;br /&gt;
							// An IP may have multiple blocks&lt;br /&gt;
							const resBlk = res &amp;amp;&amp;amp; res.query &amp;amp;&amp;amp; res.query.blocks || [];&lt;br /&gt;
							const resObj = resBlk.reduce(/** @param {ApiResponseQueryListBlocks?} acc */ (acc, obj, i) =&amp;gt; {&lt;br /&gt;
								if (i === 0) {&lt;br /&gt;
									acc = obj; // Just save the object in the first loop&lt;br /&gt;
								} else {&lt;br /&gt;
									// If the IP has multiple blocks, find the narrowest one CIDR-wise&lt;br /&gt;
									let m;&lt;br /&gt;
									const lastRange = acc &amp;amp;&amp;amp; (m = acc.user.match(/\/(\d+)$/)) ? parseInt(m[1]) : 128;&lt;br /&gt;
									const thisRange = (m = obj.user.match(/\/(\d+)$/)) !== null ? parseInt(m[1]) : 128;&lt;br /&gt;
									if (thisRange &amp;gt; lastRange) { // e.g., /24 is narrower than /23&lt;br /&gt;
										acc = obj; // Overwrite the previously substituted object&lt;br /&gt;
									}&lt;br /&gt;
								}&lt;br /&gt;
								return acc;&lt;br /&gt;
							}, null);&lt;br /&gt;
							if (resObj) {&lt;br /&gt;
								const {user, by, expiry, reason, restrictions} = resObj;&lt;br /&gt;
								const partialBlk = restrictions &amp;amp;&amp;amp; !Array.isArray(restrictions);&lt;br /&gt;
								let clss;&lt;br /&gt;
								const range = (user.match(/\/(\d+)$/) || [&#039;&#039;, &#039;??&#039;])[1];&lt;br /&gt;
								// $1: Domain, $2: CIDR range, $3: Expiry, $4: Blocking admin, $5: Reason&lt;br /&gt;
								const titleVars = [this.getMessage(&#039;title-domain-local&#039;), range, &#039;&#039;, by, reason];&lt;br /&gt;
								if (/^in/.test(expiry)) {&lt;br /&gt;
									clss = partialBlk ? &#039;mbl-blocked-partial&#039; : &#039;mbl-blocked-indef&#039;;&lt;br /&gt;
									titleVars[2] = this.getMessage(&#039;title-expiry-indefinite&#039;);&lt;br /&gt;
								} else {&lt;br /&gt;
									clss = partialBlk ? &#039;mbl-blocked-partial&#039; : &#039;mbl-blocked-temp&#039;;&lt;br /&gt;
									titleVars[2] = this.getMessage(&#039;title-expiry-temporary&#039;).replace(&#039;$1&#039;, expiry);&lt;br /&gt;
								}&lt;br /&gt;
								const tooltip = mw.format(this.getMessage(&#039;title-rangeblocked&#039;), ...titleVars);&lt;br /&gt;
								MarkBLocked.addClass(userLinks, ip, clss, tooltip);&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
					});&lt;br /&gt;
				});&lt;br /&gt;
			}&lt;br /&gt;
			if (this.options.g_locks &amp;amp;&amp;amp; users.length) {&lt;br /&gt;
				users.forEach((user) =&amp;gt; {&lt;br /&gt;
					batchArray.push({&lt;br /&gt;
						username: user,&lt;br /&gt;
						api: this.metaApi,&lt;br /&gt;
						params: {&lt;br /&gt;
							list: &#039;globalallusers|logevents&#039;,&lt;br /&gt;
							agulimit: 1,&lt;br /&gt;
							agufrom: user,&lt;br /&gt;
							aguto: user,&lt;br /&gt;
							aguprop: &#039;lockinfo&#039;,&lt;br /&gt;
							leaction: &#039;globalauth/setstatus&#039;,&lt;br /&gt;
							leprop: &#039;user|timestamp|comment|details&#039;,&lt;br /&gt;
							letitle: `User:${user}@global`&lt;br /&gt;
						},&lt;br /&gt;
						callback: (res) =&amp;gt; {&lt;br /&gt;
							if (res &amp;amp;&amp;amp; res.query) {&lt;br /&gt;
								const resLck = res.query.globalallusers;&lt;br /&gt;
								if (resLck &amp;amp;&amp;amp; resLck[0] &amp;amp;&amp;amp; resLck[0].locked === &#039;&#039;) {&lt;br /&gt;
									const resLgev = res.query.logevents;&lt;br /&gt;
									// $1: Locking steward, $2: &amp;quot;Since&amp;quot; timestamp, $3: Reason&lt;br /&gt;
									// Note: logs can be revdeled or suppressed occasionally&lt;br /&gt;
									const titleVars = [&#039;??&#039;, &#039;??&#039;,&#039;??&#039;];&lt;br /&gt;
									if (resLgev &amp;amp;&amp;amp; resLgev.length) {&lt;br /&gt;
										/**&lt;br /&gt;
										 * The `params` property is an object with either the `added` and `removed` keys, or&lt;br /&gt;
										 * the `0` and `1` numeral keys (in the case of an old log entry):&lt;br /&gt;
										 * ```&lt;br /&gt;
										 * &amp;quot;params&amp;quot;: {&lt;br /&gt;
										 *		&amp;quot;added&amp;quot;: [&lt;br /&gt;
										 *			&amp;quot;locked&amp;quot;&lt;br /&gt;
										 *		],&lt;br /&gt;
										 *		&amp;quot;removed&amp;quot;: []&lt;br /&gt;
										 *	}&lt;br /&gt;
										 * ```&lt;br /&gt;
										 * ```&lt;br /&gt;
										 * &amp;quot;params&amp;quot;: {&lt;br /&gt;
										 *		&amp;quot;0&amp;quot;: &amp;quot;locked&amp;quot;,&lt;br /&gt;
										 *		&amp;quot;1&amp;quot;: &amp;quot;(none)&amp;quot;&lt;br /&gt;
										 *	}&lt;br /&gt;
										 * ```&lt;br /&gt;
										 */&lt;br /&gt;
										for (const {params, user, timestamp, comment} of resLgev) {&lt;br /&gt;
											if (!params) {&lt;br /&gt;
												// If the &amp;quot;params&amp;quot; property is missing, can&#039;t fetch the details of the lock&lt;br /&gt;
												break;&lt;br /&gt;
											} else if (&lt;br /&gt;
												// If &amp;quot;params&amp;quot; has an &amp;quot;added&amp;quot; array and a &amp;quot;removed&amp;quot; array, the former should&lt;br /&gt;
												// contain &amp;quot;locked&amp;quot; and the latter shouldn&#039;t&lt;br /&gt;
												(&lt;br /&gt;
													params.added &amp;amp;&amp;amp; params.removed &amp;amp;&amp;amp; (&lt;br /&gt;
														params.added.indexOf(&#039;locked&#039;) === -1 ||&lt;br /&gt;
														params.removed.indexOf(&#039;locked&#039;) !== -1&lt;br /&gt;
													)&lt;br /&gt;
												) ||&lt;br /&gt;
												// In the case of an old log entry, the numeral keys should have fixed values&lt;br /&gt;
												(&lt;br /&gt;
													params[&#039;0&#039;] &amp;amp;&amp;amp; params[&#039;0&#039;] !== &#039;locked&#039; ||&lt;br /&gt;
													params[&#039;1&#039;] &amp;amp;&amp;amp; params[&#039;1&#039;] !== &#039;(none)&#039;&lt;br /&gt;
												)&lt;br /&gt;
											) {&lt;br /&gt;
												continue;&lt;br /&gt;
											}&lt;br /&gt;
											if (user) {&lt;br /&gt;
												titleVars[0] = user;&lt;br /&gt;
											}&lt;br /&gt;
											if (timestamp) {&lt;br /&gt;
												titleVars[1] = timestamp;&lt;br /&gt;
											}&lt;br /&gt;
											if (typeof comment === &#039;string&#039;) {&lt;br /&gt;
												titleVars[2] = comment || &#039;&amp;quot;&amp;quot;&#039;;&lt;br /&gt;
											}&lt;br /&gt;
											break;&lt;br /&gt;
										}&lt;br /&gt;
									}&lt;br /&gt;
									const tooltip = mw.format(this.getMessage(&#039;title-locked&#039;), ...titleVars);&lt;br /&gt;
									MarkBLocked.addClass(userLinks, user, &#039;mbl-globally-locked&#039;, tooltip);&lt;br /&gt;
								}&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
					});&lt;br /&gt;
				});&lt;br /&gt;
			}&lt;br /&gt;
			if (this.options.g_rangeblocks &amp;amp;&amp;amp; (remainingIps = ips.filter((ip) =&amp;gt; g_markedUsers.indexOf(ip) === -1)).length) {&lt;br /&gt;
				remainingIps.forEach((ip) =&amp;gt; {&lt;br /&gt;
					batchArray.push({&lt;br /&gt;
						username: ip,&lt;br /&gt;
						params: {&lt;br /&gt;
							list: &#039;globalblocks&#039;,&lt;br /&gt;
							bgip: ip,&lt;br /&gt;
							bgprop: &#039;target|by|expiry|reason&#039;&lt;br /&gt;
						},&lt;br /&gt;
						callback: (res) =&amp;gt; {&lt;br /&gt;
							const resGblk = res &amp;amp;&amp;amp; res.query &amp;amp;&amp;amp; res.query.globalblocks || [];&lt;br /&gt;
							const resObj = resGblk.reduce(/** @param {ApiResponseQueryListGlobalblocks?} acc */ (acc, obj, i) =&amp;gt; {&lt;br /&gt;
								if (i === 0) {&lt;br /&gt;
									acc = obj;&lt;br /&gt;
								} else {&lt;br /&gt;
									let m;&lt;br /&gt;
									const lastRange = acc &amp;amp;&amp;amp; (m = acc.target.match(/\/(\d+)$/)) ? parseInt(m[1]) : 128;&lt;br /&gt;
									const thisRange = (m = obj.target.match(/\/(\d+)$/)) !== null ? parseInt(m[1]) : 128;&lt;br /&gt;
									if (thisRange &amp;gt; lastRange) {&lt;br /&gt;
										acc = obj;&lt;br /&gt;
									}&lt;br /&gt;
								}&lt;br /&gt;
								return acc;&lt;br /&gt;
							}, null);&lt;br /&gt;
							if (resObj) {&lt;br /&gt;
								const {target, by, expiry, reason} = resObj;&lt;br /&gt;
								let clss;&lt;br /&gt;
								const range = (target.match(/\/(\d+)$/) || [&#039;&#039;, &#039;??&#039;])[1];&lt;br /&gt;
								// $1: Domain, $2: CIDR range, $3: Expiry, $4: Blocking admin, $5: Reason&lt;br /&gt;
								const titleVars = [this.getMessage(&#039;title-domain-global&#039;), range, &#039;&#039;, by, reason];&lt;br /&gt;
								if (/^in/.test(expiry)) {&lt;br /&gt;
									clss = &#039;mbl-globally-blocked-indef&#039;;&lt;br /&gt;
									titleVars[2] = this.getMessage(&#039;title-expiry-indefinite&#039;);&lt;br /&gt;
								} else {&lt;br /&gt;
									clss = &#039;mbl-globally-blocked-temp&#039;;&lt;br /&gt;
									titleVars[2] = this.getMessage(&#039;title-expiry-temporary&#039;).replace(&#039;$1&#039;, expiry);&lt;br /&gt;
								}&lt;br /&gt;
								const tooltip = mw.format(this.getMessage(&#039;title-rangeblocked&#039;), ...titleVars);&lt;br /&gt;
								MarkBLocked.addClass(userLinks, ip, clss, tooltip);&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
					});&lt;br /&gt;
				});&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			if (batchArray.length) {&lt;br /&gt;
				this.batchRequest(batchArray);&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Object that stores collected user links, keyed by usernames and valued by an array of anchors.&lt;br /&gt;
	 * @typedef {Record&amp;lt;string, HTMLAnchorElement[]&amp;gt;} UserLinks&lt;br /&gt;
	 */&lt;br /&gt;
	/**&lt;br /&gt;
	 * @typedef {{userLinks: UserLinks; users: string[]; ips: string[];}} LinkObject&lt;br /&gt;
	 */&lt;br /&gt;
	/**&lt;br /&gt;
	 * Collect user links to mark up.&lt;br /&gt;
	 * @param {JQuery&amp;lt;HTMLElement&amp;gt;} $content&lt;br /&gt;
	 * @returns {LinkObject}&lt;br /&gt;
	 * @requires mediawiki.util&lt;br /&gt;
	 */&lt;br /&gt;
	collectLinks($content) {&lt;br /&gt;
&lt;br /&gt;
		// Get all anchors in the content&lt;br /&gt;
		let $anchors = $content.find(&#039;a&#039;);&lt;br /&gt;
		const $pNamespaces = $(&#039;#p-associated-pages, #p-namespaces, .skin-monobook #ca-nstab-user, .skin-monobook #ca-talk&#039;);&lt;br /&gt;
		if ($pNamespaces.length &amp;amp;&amp;amp; !$content.find($pNamespaces).length &amp;amp;&amp;amp; [2, 3].indexOf(mw.config.get(&#039;wgNamespaceNumber&#039;)) !== -1) {&lt;br /&gt;
			$anchors = $anchors.add($pNamespaces.find(&#039;a&#039;));&lt;br /&gt;
		}&lt;br /&gt;
		const $contribsTools = $(&#039;.mw-special-Contributions, .mw-special-DeletedContributions&#039;).find(&#039;#mw-content-subtitle&#039;);&lt;br /&gt;
		if ($contribsTools.length &amp;amp;&amp;amp; !$content.find($contribsTools).length) {&lt;br /&gt;
			$anchors = $anchors.add($contribsTools.find(&#039;a&#039;));&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		// Find user links&lt;br /&gt;
		/** @type {LinkObject} */&lt;br /&gt;
		const ret = {&lt;br /&gt;
			userLinks: Object.create(null),&lt;br /&gt;
			users: [],&lt;br /&gt;
			ips: []&lt;br /&gt;
		};&lt;br /&gt;
		const prIgnore = /(^|\s)(twg?-rollback-\S+|autocomment|cd-commentLink-\S+)($|\s)/;&lt;br /&gt;
		return Array.from($anchors).reduce((acc, a) =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
			// Ignore some anchors&lt;br /&gt;
			const href = a.href;&lt;br /&gt;
			const pr = a.parentElement;&lt;br /&gt;
			if (&lt;br /&gt;
				!href ||&lt;br /&gt;
				(a.getAttribute(&#039;href&#039;) || &#039;&#039;)[0] === &#039;#&#039; ||&lt;br /&gt;
				a.role === &#039;button&#039; ||&lt;br /&gt;
				a.classList.contains(&#039;ext-discussiontools-init-timestamplink&#039;) ||&lt;br /&gt;
				pr &amp;amp;&amp;amp; prIgnore.test(pr.className) ||&lt;br /&gt;
				mw.util.getParamValue(&#039;action&#039;, href) &amp;amp;&amp;amp; !mw.util.getParamValue(&#039;redlink&#039;, href) ||&lt;br /&gt;
				mw.util.getParamValue(&#039;diff&#039;, href) ||&lt;br /&gt;
				mw.util.getParamValue(&#039;oldid&#039;, href)&lt;br /&gt;
			) {&lt;br /&gt;
				return acc;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			const url = new URL(href)&lt;br /&gt;
			const pagetitle = decodeURIComponent(url.pathname.split(&amp;quot;/&amp;quot;)[1]).replace(/ /g, &#039;_&#039;);&lt;br /&gt;
&lt;br /&gt;
			// Extract a username from the pagetitle&lt;br /&gt;
			let tar, username, m;&lt;br /&gt;
			if (this.regex.contribsCA.test(pagetitle) &amp;amp;&amp;amp; (tar = mw.util.getParamValue(&#039;target&#039;, href))) {&lt;br /&gt;
				// If the parsing title is one for a special page, check whether there&#039;s a valid &amp;amp;target= query parameter.&lt;br /&gt;
				// This parameter&#039;s value is prioritized than the subpage name, if any, hence &amp;quot;Special:CA/Foo?target=Bar&amp;quot;&lt;br /&gt;
				// shows CentralAuth for User:Bar, not User:Foo.&lt;br /&gt;
				username = tar;&lt;br /&gt;
			} else if ((m = this.regex.user.exec(pagetitle))) {&lt;br /&gt;
				// If the condition above isn&#039;t met, just parse out a username from the pagetitle&lt;br /&gt;
				username = m[1];&lt;br /&gt;
			} else {&lt;br /&gt;
				return acc;&lt;br /&gt;
			}&lt;br /&gt;
			username = username.replace(/_/g, &#039; &#039;).replace(/@global$/, &#039;&#039;).trim();&lt;br /&gt;
			let /** @type {string[]} */ arr;&lt;br /&gt;
			if (mw.util.isIPAddress(username, true)) {&lt;br /&gt;
				username = mw.util.sanitizeIP(username) || username; // The right operand is never reached&lt;br /&gt;
				arr = acc.ips;&lt;br /&gt;
			} else if (/[/@#&amp;lt;&amp;gt;[\]|{}:]|^(\d{1,3}\.){3}\d{1,3}$/.test(username)) {&lt;br /&gt;
				// Ensure the username doesn&#039;t contain characters that can&#039;t be used for usernames (do this here or block status query might fail)&lt;br /&gt;
				console.log(&#039;MarkBLocked: Unprocessable username: &#039; + username);&lt;br /&gt;
				return acc;&lt;br /&gt;
			} else {&lt;br /&gt;
				arr = acc.users;&lt;br /&gt;
				if (!/^[\u10A0-\u10FF]/.test(username)) { // ucFirst, except for Georgean letters&lt;br /&gt;
					username = username.charAt(0).toUpperCase() + username.slice(1);&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			if (arr.indexOf(username) === -1) {&lt;br /&gt;
				arr.push(username);&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			a.classList.add(&#039;mbl-userlink&#039;);&lt;br /&gt;
			if (acc.userLinks[username]) {&lt;br /&gt;
				acc.userLinks[username].push(a);&lt;br /&gt;
			} else {&lt;br /&gt;
				acc.userLinks[username] = [a];&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			return acc;&lt;br /&gt;
		}, ret);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Mark up registered users and single IPs locally or globally blocked in bulk. This method does not&lt;br /&gt;
	 * deal with indirect range blocks.&lt;br /&gt;
	 * @param {&amp;quot;local&amp;quot;|&amp;quot;global&amp;quot;} domain&lt;br /&gt;
	 * @param {UserLinks} userLinks&lt;br /&gt;
	 * @param {string[]} usersArr&lt;br /&gt;
	 * @returns {JQueryPromise&amp;lt;string[]?&amp;gt;} Usernames whose links are marked up, or `null` if aborted&lt;br /&gt;
	 * @requires mediawiki.api&lt;br /&gt;
	 */&lt;br /&gt;
	bulkMarkup(domain, userLinks, usersArr) {&lt;br /&gt;
&lt;br /&gt;
		if (!usersArr.length) {&lt;br /&gt;
			return $.Deferred().resolve([]);&lt;br /&gt;
		}&lt;br /&gt;
		usersArr = usersArr.slice();&lt;br /&gt;
&lt;br /&gt;
		// API calls&lt;br /&gt;
		const /** @type {JQueryPromise&amp;lt;string[]?&amp;gt;[]} */ deferreds = [];&lt;br /&gt;
		while (usersArr.length) {&lt;br /&gt;
			if (domain === &#039;local&#039;) {&lt;br /&gt;
				deferreds.push(this.bulkMarkupLocal(userLinks, usersArr.splice(0, this.apilimit)));&lt;br /&gt;
			} else {&lt;br /&gt;
				deferreds.push(this.bulkMarkupGlobal(userLinks, usersArr.splice(0, this.apilimit)));&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		return $.when(...deferreds).then((...args) =&amp;gt; {&lt;br /&gt;
			const ret = [];&lt;br /&gt;
			for (let i = 0; i &amp;lt; args.length; i++) {&lt;br /&gt;
				const marked = args[i];&lt;br /&gt;
				if (marked !== null) {&lt;br /&gt;
					ret.push(...marked);&lt;br /&gt;
				} else {&lt;br /&gt;
					return null;&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
			return ret;&lt;br /&gt;
		});&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * @param {UserLinks} userLinks&lt;br /&gt;
	 * @param {string[]} users&lt;br /&gt;
	 * @returns {JQueryPromise&amp;lt;string[]?&amp;gt;} An array of marked users&#039; names or `null` if aborted&lt;br /&gt;
	 * @private&lt;br /&gt;
	 */&lt;br /&gt;
	bulkMarkupLocal(userLinks, users) {&lt;br /&gt;
		return this.readApi.post({ // This MUST be a POST request because the parameters can exceed the word count limit of URI&lt;br /&gt;
			list: &#039;blocks&#039;,&lt;br /&gt;
			bklimit: &#039;max&#039;,&lt;br /&gt;
			bkusers: users.join(&#039;|&#039;),&lt;br /&gt;
			bkprop: &#039;user|by|expiry|reason|restrictions&#039;&lt;br /&gt;
		}).then(/** @param {ApiResponse} res */ (res) =&amp;gt; {&lt;br /&gt;
			const resBlk = res &amp;amp;&amp;amp; res.query &amp;amp;&amp;amp; res.query.blocks || [];&lt;br /&gt;
			return resBlk.reduce(/** @param {string[]} acc */ (acc, {user, by, expiry, reason, restrictions}) =&amp;gt; {&lt;br /&gt;
				const partialBlk = restrictions &amp;amp;&amp;amp; !Array.isArray(restrictions); // Boolean: True if partial block&lt;br /&gt;
				let clss;&lt;br /&gt;
				// $1: Domain, $2: Expiry, $3: Blocking admin, $4: Reason&lt;br /&gt;
				const titleVars = [this.getMessage(&#039;title-domain-local&#039;), &#039;&#039;, by, reason];&lt;br /&gt;
				if (/^in/.test(expiry)) {&lt;br /&gt;
					clss = partialBlk ? &#039;mbl-blocked-partial&#039; : &#039;mbl-blocked-indef&#039;;&lt;br /&gt;
					titleVars[1] = this.getMessage(&#039;title-expiry-indefinite&#039;);&lt;br /&gt;
				} else {&lt;br /&gt;
					clss = partialBlk ? &#039;mbl-blocked-partial&#039; : &#039;mbl-blocked-temp&#039;;&lt;br /&gt;
					titleVars[1] = this.getMessage(&#039;title-expiry-temporary&#039;).replace(&#039;$1&#039;, expiry);&lt;br /&gt;
				}&lt;br /&gt;
				const tooltip = mw.format(this.getMessage(&#039;title-blocked&#039;), ...titleVars);&lt;br /&gt;
				const markedUser = MarkBLocked.addClass(userLinks, user, clss, tooltip);&lt;br /&gt;
				if (markedUser) {&lt;br /&gt;
					acc.push(markedUser);&lt;br /&gt;
				}&lt;br /&gt;
				return acc;&lt;br /&gt;
			}, []);&lt;br /&gt;
		}).catch(/** @param {object} err */ (_, err) =&amp;gt; {&lt;br /&gt;
			if (err.exception === &#039;abort&#039;) {&lt;br /&gt;
				return null;&lt;br /&gt;
			} else {&lt;br /&gt;
				console.error(err);&lt;br /&gt;
				return [];&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * @param {UserLinks} userLinks&lt;br /&gt;
	 * @param {string[]} users&lt;br /&gt;
	 * @returns {JQueryPromise&amp;lt;string[]?&amp;gt;} An array of marked users&#039; names or `null` if aborted&lt;br /&gt;
	 * @private&lt;br /&gt;
	 */&lt;br /&gt;
	bulkMarkupGlobal(userLinks, users) {&lt;br /&gt;
		return this.readApi.post({&lt;br /&gt;
			list: &#039;globalblocks&#039;,&lt;br /&gt;
			bgtargets: users.join(&#039;|&#039;),&lt;br /&gt;
			bgprop: &#039;target|by|expiry|reason&#039;&lt;br /&gt;
		}).then(/** @param {ApiResponse} res */ (res) =&amp;gt; {&lt;br /&gt;
			const resGblk = res &amp;amp;&amp;amp; res.query &amp;amp;&amp;amp; res.query.globalblocks || [];&lt;br /&gt;
			return resGblk.reduce(/** @param {string[]} acc */ (acc, {target, by, expiry, reason}) =&amp;gt; {&lt;br /&gt;
				let clss;&lt;br /&gt;
				// $1: Domain, $2: Expiry, $3: Blocking admin, $4: Reason&lt;br /&gt;
				const titleVars = [this.getMessage(&#039;title-domain-global&#039;), &#039;&#039;, by, reason];&lt;br /&gt;
				if (/^in/.test(expiry)) {&lt;br /&gt;
					clss = &#039;mbl-globally-blocked-indef&#039;;&lt;br /&gt;
					titleVars[1] = this.getMessage(&#039;title-expiry-indefinite&#039;);&lt;br /&gt;
				} else {&lt;br /&gt;
					clss = &#039;mbl-globally-blocked-temp&#039;;&lt;br /&gt;
					titleVars[1] = this.getMessage(&#039;title-expiry-temporary&#039;).replace(&#039;$1&#039;, expiry);&lt;br /&gt;
				}&lt;br /&gt;
				const tooltip = mw.format(this.getMessage(&#039;title-blocked&#039;), ...titleVars);&lt;br /&gt;
				const markedUser = MarkBLocked.addClass(userLinks, target, clss, tooltip);&lt;br /&gt;
				if (markedUser) {&lt;br /&gt;
					acc.push(markedUser);&lt;br /&gt;
				}&lt;br /&gt;
				return acc;&lt;br /&gt;
			}, []);&lt;br /&gt;
		}).catch(/** @param {object} err */ (_, err) =&amp;gt; {&lt;br /&gt;
			if (err.exception === &#039;abort&#039;) {&lt;br /&gt;
				return null;&lt;br /&gt;
			} else {&lt;br /&gt;
				console.error(err);&lt;br /&gt;
				return [];&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Add a class to all anchors associated with a certain username.&lt;br /&gt;
	 * @param {UserLinks} userLinks&lt;br /&gt;
	 * @param {string} userName&lt;br /&gt;
	 * @param {string} className&lt;br /&gt;
	 * @param {string} tooltip&lt;br /&gt;
	 * @returns {string?} The username if any link is marked up, or else `null`.&lt;br /&gt;
	 */&lt;br /&gt;
	static addClass(userLinks, userName, className, tooltip) {&lt;br /&gt;
		const links = userLinks[userName]; // Get all links related to the user&lt;br /&gt;
		if (links) {&lt;br /&gt;
			tooltip = this.truncateWikilinks(tooltip).trim().replace(/\n/g, &#039; &#039;);&lt;br /&gt;
			for (let i = 0; i &amp;lt; links.length; i++) {&lt;br /&gt;
				links[i].classList.add(className);&lt;br /&gt;
				this.addTooltip(links[i], tooltip);&lt;br /&gt;
			}&lt;br /&gt;
			return userName;&lt;br /&gt;
		} else {&lt;br /&gt;
			console.error(&#039;MarkBLocked: There\&#039;s no link for User:&#039; + userName);&lt;br /&gt;
			return null;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Truncate [[wikilink]]s in a string by extracting their display texts.&lt;br /&gt;
	 * @param {string} str&lt;br /&gt;
	 * @returns {string}&lt;br /&gt;
	 */&lt;br /&gt;
	static truncateWikilinks(str) {&lt;br /&gt;
		const regex = /\[\[([^|\]]+)(?:\|([^\]]+))?\]\]/g;&lt;br /&gt;
		let ret = str;&lt;br /&gt;
		let m;&lt;br /&gt;
		while ((m = regex.exec(str))) {&lt;br /&gt;
			ret = ret.replace(m[0], m[2] || m[1]);&lt;br /&gt;
		}&lt;br /&gt;
		return ret;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * Add a tooltip to a user link.&lt;br /&gt;
	 * @param {HTMLAnchorElement} anchor&lt;br /&gt;
	 * @param {string} text&lt;br /&gt;
	 */&lt;br /&gt;
	static addTooltip(anchor, text) {&lt;br /&gt;
		if (typeof anchor.dataset.mblTooltip === &#039;string&#039;) {&lt;br /&gt;
			anchor.dataset.mblTooltip += &#039;\n&#039; + text;&lt;br /&gt;
		} else {&lt;br /&gt;
			$(anchor)&lt;br /&gt;
				.attr(&#039;data-mbl-tooltip&#039;, text)&lt;br /&gt;
				.tooltip({&lt;br /&gt;
					tooltipClass: &#039;mbl-tooltip&#039;,&lt;br /&gt;
					content: /** @this {HTMLAnchorElement} */ function() {&lt;br /&gt;
						const tt = this.dataset.mblTooltip;&lt;br /&gt;
						if (tt) {&lt;br /&gt;
							return $(&#039;&amp;lt;ul&amp;gt;&#039;).append(&lt;br /&gt;
								tt.split(&#039;\n&#039;).map((line) =&amp;gt; $(&#039;&amp;lt;li&amp;gt;&#039;).text(line))&lt;br /&gt;
							);&lt;br /&gt;
						}&lt;br /&gt;
					},&lt;br /&gt;
					position: {&lt;br /&gt;
						my: &#039;left bottom&#039;,&lt;br /&gt;
						at: &#039;left top&#039;&lt;br /&gt;
					}&lt;br /&gt;
				});&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
	 * @typedef {object} BatchObject&lt;br /&gt;
	 * @property {string} username&lt;br /&gt;
	 * @property {mw.Api} [api]&lt;br /&gt;
	 * @property {Record&amp;lt;string, any&amp;gt;} params&lt;br /&gt;
	 * @property {(res?: ApiResponse) =&amp;gt; void} callback&lt;br /&gt;
	 */&lt;br /&gt;
	/**&lt;br /&gt;
	 * Send batched API requests.&lt;br /&gt;
	 *&lt;br /&gt;
	 * MarkBLocked has to send quite a few API requests when additional markup functionalities are enabled,&lt;br /&gt;
	 * and this can lead to an `net::ERR_INSUFFICIENT_RESOURCES` error if too many requests are sent all&lt;br /&gt;
	 * at once. This (private) function sends API requests by creating batches of 1000, where each batch is&lt;br /&gt;
	 * processed sequentially after the older batch is resolved.&lt;br /&gt;
	 * @param {BatchObject[]} batchArray&lt;br /&gt;
	 * @returns {JQueryPromise&amp;lt;void&amp;gt;}&lt;br /&gt;
	 * @requires mediawiki.api&lt;br /&gt;
	 */&lt;br /&gt;
	batchRequest(batchArray) {&lt;br /&gt;
&lt;br /&gt;
		// Unflatten the array of objects to an array of arrays of objects&lt;br /&gt;
		const unflattened = batchArray.reduce(/** @param {BatchObject[][]} acc */ (acc, obj) =&amp;gt; {&lt;br /&gt;
			const len = acc.length - 1;&lt;br /&gt;
			if (Array.isArray(acc[len]) &amp;amp;&amp;amp; acc[len].length &amp;lt; 1000) {&lt;br /&gt;
				acc[len].push(obj);&lt;br /&gt;
			} else {&lt;br /&gt;
				acc[len + 1] = [obj];&lt;br /&gt;
			}&lt;br /&gt;
			return acc;&lt;br /&gt;
		}, [[]]);&lt;br /&gt;
&lt;br /&gt;
		let aborted = false;&lt;br /&gt;
		/**&lt;br /&gt;
		 * Send an API request.&lt;br /&gt;
		 * @param {BatchObject} batchObj&lt;br /&gt;
		 * @returns {JQueryPromise&amp;lt;void&amp;gt;}&lt;br /&gt;
		 */&lt;br /&gt;
		const req = (batchObj) =&amp;gt; {&lt;br /&gt;
			return (batchObj.api || this.api).get(batchObj.params)&lt;br /&gt;
				.then(batchObj.callback)&lt;br /&gt;
				.catch(/** @param {object} err */ (_, err) =&amp;gt; {&lt;br /&gt;
					if (err.exception === &#039;abort&#039;) {&lt;br /&gt;
						aborted = true;&lt;br /&gt;
					} else {&lt;br /&gt;
						console.error(batchObj.username, err);&lt;br /&gt;
					}&lt;br /&gt;
				});&lt;br /&gt;
		};&lt;br /&gt;
		/**&lt;br /&gt;
		 * Send batched API requests.&lt;br /&gt;
		 * @param {number} index&lt;br /&gt;
		 * @returns {JQueryPromise&amp;lt;void&amp;gt;}&lt;br /&gt;
		 */&lt;br /&gt;
		const batch = (index) =&amp;gt; {&lt;br /&gt;
			return $.when(...unflattened[index].map(req)).then((...args) =&amp;gt; {&lt;br /&gt;
				console.log(&#039;MarkBLocked batch count: &#039; + args.length);&lt;br /&gt;
				if (!aborted &amp;amp;&amp;amp; unflattened[++index]) {&lt;br /&gt;
					return batch(index);&lt;br /&gt;
				}&lt;br /&gt;
			});&lt;br /&gt;
		};&lt;br /&gt;
&lt;br /&gt;
		return batch(0);&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * @type {Record&amp;lt;string, Lang&amp;gt;}&lt;br /&gt;
 */&lt;br /&gt;
MarkBLocked.i18n = {&lt;br /&gt;
	en: {&lt;br /&gt;
		&#039;config-label-heading&#039;: &#039;MarkBLocked configurations&#039;,&lt;br /&gt;
		&#039;config-label-fsgeneral&#039;: &#039;General settings&#039;,&lt;br /&gt;
		&#039;config-label-genportlet&#039;: &#039;Generate a portlet link to the config page&#039;,&lt;br /&gt;
		&#039;config-label-fsmarkup&#039;: &#039;Markup settings&#039;,&lt;br /&gt;
		&#039;config-help-resources&#039;: &#039;Features with an exclamation mark may consume server resources.&#039;,&lt;br /&gt;
		&#039;config-label-rangeblocks&#039;: &#039;Mark up IPs in locally blocked IP ranges&#039;,&lt;br /&gt;
		&#039;config-label-g_locks&#039;: &#039;Mark up globally locked users&#039;,&lt;br /&gt;
		&#039;config-label-g_blocks&#039;: &#039;Mark up globally blocked users and IPs&#039;,&lt;br /&gt;
		&#039;config-label-g_rangeblocks&#039;: &#039;Mark up IPs in globally blocked IP ranges&#039;,&lt;br /&gt;
		&#039;config-help-g_rangeblocks&#039;: &#039;This option can be configured only when markup for global blocks is enabled.&#039;,&lt;br /&gt;
		&#039;config-label-save&#039;: &#039;Save settings&#039;,&lt;br /&gt;
		&#039;config-label-saving&#039;: &#039;Saving settings...&#039;,&lt;br /&gt;
		&#039;config-notify-notloaded&#039;: &#039;Failed to load the interface.&#039;,&lt;br /&gt;
		&#039;config-notify-savedone&#039;: &#039;Settings have been saved successfully.&#039;,&lt;br /&gt;
		&#039;config-notify-savefailed&#039;: &#039;Failed to save the settings. &#039;,&lt;br /&gt;
		&#039;portlet-text&#039;: &#039;MBL config&#039;,&lt;br /&gt;
		&#039;portlet-title&#039;: &#039;Open [[Special:MarkBLockedConfig]]&#039;,&lt;br /&gt;
		&#039;toggle-title-enabled&#039;: &#039;MarkBLocked is enabled. Click to disable it temporarily.&#039;,&lt;br /&gt;
		&#039;toggle-title-disabled&#039;: &#039;MarkBLocked is temporarily disabled. Click to enable it again.&#039;,&lt;br /&gt;
		&#039;toggle-notify-enabled&#039;: &#039;Enabled MarkBLocked.&#039;,&lt;br /&gt;
		&#039;toggle-notify-disabled&#039;: &#039;Temporarily disabled MarkBLocked.&#039;,&lt;br /&gt;
		&#039;title-domain-local&#039;: &#039;Locally&#039;,&lt;br /&gt;
		&#039;title-domain-global&#039;: &#039;Globally&#039;,&lt;br /&gt;
		&#039;title-expiry-indefinite&#039;: &#039;indefinitely&#039;,&lt;br /&gt;
		&#039;title-expiry-temporary&#039;: &#039;until $1&#039;,&lt;br /&gt;
		&#039;title-blocked&#039;: &#039;$1 blocked $2 by $3: $4&#039;,&lt;br /&gt;
		&#039;title-rangeblocked&#039;: &#039;$1 range-blocked in /$2 $3 by $4: $5&#039;,&lt;br /&gt;
		&#039;title-locked&#039;: &#039;Globally locked by $1 since $2: $3&#039;&lt;br /&gt;
	},&lt;br /&gt;
	ja: {&lt;br /&gt;
		&#039;config-label-heading&#039;: &#039;MarkBLockedの設定&#039;,&lt;br /&gt;
		&#039;config-label-fsgeneral&#039;: &#039;一般設定&#039;,&lt;br /&gt;
		&#039;config-label-genportlet&#039;: &#039;設定ページへのポートレットリンクを生成&#039;,&lt;br /&gt;
		&#039;config-label-fsmarkup&#039;: &#039;マークアップ設定&#039;,&lt;br /&gt;
		&#039;config-help-resources&#039;: &#039;感嘆符の付いた機能はサーバーリソースを消費します。&#039;,&lt;br /&gt;
		&#039;config-label-rangeblocks&#039;: &#039;ブロックされたIPレンジに含まれるIPをマークアップ&#039;,&lt;br /&gt;
		&#039;config-label-g_locks&#039;: &#039;グローバルロックされた利用者をマークアップ&#039;,&lt;br /&gt;
		&#039;config-label-g_blocks&#039;: &#039;グローバルブロックされた利用者およびIPをマークアップ&#039;,&lt;br /&gt;
		&#039;config-label-g_rangeblocks&#039;: &#039;グローバルブロックされたIPレンジに含まれるIPをマークアップ&#039;,&lt;br /&gt;
		&#039;config-help-g_rangeblocks&#039;: &#039;この設定はグローバルブロックのマークアップが有効化されている場合のみ変更可能です。&#039;,&lt;br /&gt;
		&#039;config-label-save&#039;: &#039;設定を保存&#039;,&lt;br /&gt;
		&#039;config-label-saving&#039;: &#039;設定を保存中...&#039;,&lt;br /&gt;
		&#039;config-notify-notloaded&#039;: &#039;インターフェースの読み込みに失敗しました。&#039;,&lt;br /&gt;
		&#039;config-notify-savedone&#039;: &#039;設定の保存に成功しました。&#039;,&lt;br /&gt;
		&#039;config-notify-savefailed&#039;: &#039;設定の保存に失敗しました。&#039;,&lt;br /&gt;
		&#039;portlet-text&#039;: &#039;MarkBLockedの設定&#039;,&lt;br /&gt;
		&#039;portlet-title&#039;: &#039;[[特別:MarkBLockedConfig]]を開く&#039;,&lt;br /&gt;
		&#039;toggle-title-enabled&#039;: &#039;MarkBLockedが有効化されています。クリックすると一時的に無効化します。&#039;,&lt;br /&gt;
		&#039;toggle-title-disabled&#039;: &#039;MarkBLockedが一時的に無効化されています。クリックすると再有効化します。&#039;,&lt;br /&gt;
		&#039;toggle-notify-enabled&#039;: &#039;MarkBLockedを有効化しました。&#039;,&lt;br /&gt;
		&#039;toggle-notify-disabled&#039;: &#039;MarkBLockedを一時的に無効化しました。&#039;,&lt;br /&gt;
		&#039;title-domain-local&#039;: &#039;ローカル&#039;,&lt;br /&gt;
		&#039;title-domain-global&#039;: &#039;グローバル&#039;,&lt;br /&gt;
		&#039;title-expiry-indefinite&#039;: &#039;無期限&#039;,&lt;br /&gt;
		&#039;title-expiry-temporary&#039;: &#039;$1まで&#039;,&lt;br /&gt;
		&#039;title-blocked&#039;: &#039;$3により$2$1ブロック中: $4&#039;,&lt;br /&gt;
		&#039;title-rangeblocked&#039;: &#039;$4により/$2で$3$1レンジブロック中: $5&#039;,&lt;br /&gt;
		&#039;title-locked&#039;: &#039;$1により$2からグローバルロック中: $3&#039;&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
MarkBLocked.defaultOptionKey = &#039;userjs-markblocked-config&#039;;&lt;br /&gt;
&lt;br /&gt;
return MarkBLocked;&lt;br /&gt;
})();&lt;br /&gt;
//&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked-core.css&amp;diff=965</id>
		<title>MediaWiki:Gadget-MarkBLocked-core.css</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked-core.css&amp;diff=965"/>
		<updated>2025-04-13T16:34:37Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「/* Config */ #mblc-container { 	position: relative; } #mblc-container-overlay { 	width: 100%; 	height: 100%; 	position: absolute; 	top: 0; 	left: 0; 	z-index: 10; } #mblc-optionfield { 	padding: 1em; 	margin: 0; 	border: 1px solid var(--border-color-subtle, #c8ccd1); } .mblc-exclamation { 	display: inline-block; 	width: 0.5em; 	text-align: center; 	color: var(--color-destructive, red); } #mblc-save { 	margin-top: 0.5em; }  /* Block tooltips */ .mbl-tooltip { 	backgr…」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Config */&lt;br /&gt;
#mblc-container {&lt;br /&gt;
	position: relative;&lt;br /&gt;
}&lt;br /&gt;
#mblc-container-overlay {&lt;br /&gt;
	width: 100%;&lt;br /&gt;
	height: 100%;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	top: 0;&lt;br /&gt;
	left: 0;&lt;br /&gt;
	z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
#mblc-optionfield {&lt;br /&gt;
	padding: 1em;&lt;br /&gt;
	margin: 0;&lt;br /&gt;
	border: 1px solid var(--border-color-subtle, #c8ccd1);&lt;br /&gt;
}&lt;br /&gt;
.mblc-exclamation {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	width: 0.5em;&lt;br /&gt;
	text-align: center;&lt;br /&gt;
	color: var(--color-destructive, red);&lt;br /&gt;
}&lt;br /&gt;
#mblc-save {&lt;br /&gt;
	margin-top: 0.5em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Block tooltips */&lt;br /&gt;
.mbl-tooltip {&lt;br /&gt;
	background: var(--background-color-base, #fff);&lt;br /&gt;
	border: 1px solid var(--border-color-base, #a2a9b1);&lt;br /&gt;
	border-width: 1px !important;&lt;br /&gt;
	border-radius: 0;&lt;br /&gt;
	color: var(--color-base, #202122);&lt;br /&gt;
	box-shadow: 0 3px 8px rgba(50, 50, 50, 0.35);&lt;br /&gt;
	font-size: 11px;&lt;br /&gt;
	padding: 4px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* General */&lt;br /&gt;
.mbl-userlink {&lt;br /&gt;
	opacity: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Classes for locally blocked users. These classes are mutually exclusive.&lt;br /&gt;
 */&lt;br /&gt;
.mbl-blocked-indef {&lt;br /&gt;
	opacity: 0.6;&lt;br /&gt;
	text-decoration: line-through;&lt;br /&gt;
	/**&lt;br /&gt;
	 * Below might not be supported by the user&#039;s browser, hence defined separately.&lt;br /&gt;
	 * This ensures that the user link is at least struck through.&lt;br /&gt;
	 */&lt;br /&gt;
	text-decoration-style: double;&lt;br /&gt;
}&lt;br /&gt;
.mbl-blocked-temp {&lt;br /&gt;
	text-decoration: line-through;&lt;br /&gt;
}&lt;br /&gt;
.mbl-blocked-partial {&lt;br /&gt;
	text-decoration: underline;&lt;br /&gt;
	text-decoration-style: dotted;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Classes for globally (b)locked users. The classes for global block can&lt;br /&gt;
 * overlap with the class for global lock.&lt;br /&gt;
 */&lt;br /&gt;
.mbl-globally-locked {&lt;br /&gt;
	opacity: 0.6;&lt;br /&gt;
	border-bottom: red double;&lt;br /&gt;
}&lt;br /&gt;
.mbl-globally-blocked-indef:not(.mbl-globally-locked) {&lt;br /&gt;
	opacity: 0.6;&lt;br /&gt;
	border-bottom: 2px red dashed;&lt;br /&gt;
}&lt;br /&gt;
.mbl-globally-blocked-temp:not(.mbl-globally-locked) {&lt;br /&gt;
	border-bottom: 2px red dashed;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Increase opacity on dark mode for better readability */&lt;br /&gt;
@media screen {&lt;br /&gt;
	html.skin-theme-clientpref-night .mbl-blocked-indef,&lt;br /&gt;
	html.skin-theme-clientpref-night .mbl-globally-locked,&lt;br /&gt;
	html.skin-theme-clientpref-night .mbl-globally-blocked-indef:not(.mbl-globally-locked) {&lt;br /&gt;
		opacity: 0.8;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
@media screen and (prefers-color-scheme: dark) {&lt;br /&gt;
	html.skin-theme-clientpref-os .mbl-blocked-indef,&lt;br /&gt;
	html.skin-theme-clientpref-os .mbl-globally-locked,&lt;br /&gt;
	html.skin-theme-clientpref-os .mbl-globally-blocked-indef:not(.mbl-globally-locked) {&lt;br /&gt;
		opacity: 0.8;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked&amp;diff=964</id>
		<title>MediaWiki:Gadget-MarkBLocked</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadget-MarkBLocked&amp;diff=964"/>
		<updated>2025-04-13T16:33:51Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「MediaWiki:Gadget-MarkBLocked: 投稿ブロックされた利用者のリンクを取り消し線表示する（&amp;lt;span class=&amp;quot;plainlinks&amp;quot;&amp;gt;[{{fullurl:特別:ログ/block|withgadget=MarkBLocked}} 試用]&amp;lt;/span&amp;gt;）」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[MediaWiki:Gadget-MarkBLocked]]: 投稿ブロックされた利用者のリンクを取り消し線表示する（&amp;lt;span class=&amp;quot;plainlinks&amp;quot;&amp;gt;[{{fullurl:特別:ログ/block|withgadget=MarkBLocked}} 試用]&amp;lt;/span&amp;gt;）&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadgets-definition&amp;diff=963</id>
		<title>MediaWiki:Gadgets-definition</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=MediaWiki:Gadgets-definition&amp;diff=963"/>
		<updated>2025-04-13T16:32:48Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: MarkBLockedガジェットを追加&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* MarkBLocked-core[ResourceLoader|hidden|dependencies=mediawiki.user,mediawiki.api,mediawiki.ForeignApi,mediawiki.util,oojs-ui,oojs-ui.styles.icons-moderation]|MarkBLocked-core.js|MarkBLocked-core.css&lt;br /&gt;
* MarkBLocked[ResourceLoader|default|supportsUrlLoad|dependencies=ext.gadget.MarkBLocked-core]|MarkBLocked.js&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E3%83%97%E3%83%A9%E3%82%A4%E3%83%90%E3%82%B7%E3%83%BC%E3%83%BB%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC&amp;diff=958</id>
		<title>人工言語学Wiki:プライバシー・ポリシー</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E3%83%97%E3%83%A9%E3%82%A4%E3%83%90%E3%82%B7%E3%83%BC%E3%83%BB%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC&amp;diff=958"/>
		<updated>2025-04-13T06:39:52Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: アカウントの「実名」フィールドに関する記述を追加&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 個人情報の収集項目およびそれらの目的 ==&lt;br /&gt;
&lt;br /&gt;
人工言語学Wikiのシステムが収集する個人情報は、Wikiを正常に機能させるために必要な最小限の情報に限定されます。人工言語学Wikiは、広告配信、販売、その他の営利目的などのために個人情報を利用することはなく、アカウント管理と記事保全のためにのみ利用します。&lt;br /&gt;
&lt;br /&gt;
=== 収集される個人情報 ===&lt;br /&gt;
&lt;br /&gt;
収集される個人情報は以下のとおりです。これらのうち「全閲覧者に対して公開」される情報が、匿名の利用者によって何らかの目的で利用されることは妨げられません。インターネット上の無数のアーカイブ装置や、バックアップ処理によって、これらの公開情報が運営者の管理の及ばない外部の情報媒体に無期限に保持される可能性もあります。&lt;br /&gt;
&lt;br /&gt;
==== アカウント情報 ====&lt;br /&gt;
&lt;br /&gt;
人工言語学Wikiでは、スパム対策の一環として、記事投稿を行う際にはアカウント登録およびログインが求められます。アカウント登録の際、以下の情報の入力が求められます。&lt;br /&gt;
&lt;br /&gt;
* 利用者名（表示用およびアカウント識別用、全閲覧者に対して公開）&lt;br /&gt;
* 実名（表示用、任意、全閲覧者に対して公開）（[[特別:利用者ページ|利用者ページ]]が存在する場合のみ、利用者名の代わりに表示されます）&lt;br /&gt;
* メールアドレス（スパム対策用および連絡用、非公開）&lt;br /&gt;
* パスワード（認証用、非公開）&lt;br /&gt;
&lt;br /&gt;
これらの情報は登録されるアカウントに紐づけられ、なんらかの理由で変更または削除されない限り、人工言語学Wikiのサーバーが無期限に保持し続けます。&lt;br /&gt;
&lt;br /&gt;
メールアドレス情報は、主として投稿者の適格性を疑似的に確認する手段として利用されます。アカウントの登録時に、確認用のリンクが記載されたメールが送信され、このリンク先にアクセスしてアカウントを確認することで、アカウントに投稿権限が与えられます。また、利用者が意図的にパスワード再設定の操作を開始した場合に、パスワード再設定用のリンクがこのメールアドレスに送信されます。ここに挙げた状況以外で人工言語学Wikiからメールが送信されるのは、セキュリティー侵害などの有事の連絡のみです。&lt;br /&gt;
&lt;br /&gt;
==== 投稿記録 ====&lt;br /&gt;
&lt;br /&gt;
記事の改訂によってウェブ上の情報の連関や整合性が損なわれないようにするために、人工言語学Wikiは、投稿された記事の全ての変更履歴を保持しており、これを投稿記録と呼びます。投稿記録には、以下の情報が含まれます。&lt;br /&gt;
&lt;br /&gt;
* 投稿内容を反映した直後の記事のスナップショット&lt;br /&gt;
* 投稿者情報&lt;br /&gt;
* 投稿日時&lt;br /&gt;
* 投稿の要約&lt;br /&gt;
&lt;br /&gt;
全てのアカウントの各投稿記録とその一覧、および全ての記事の各投稿記録とその一覧は、全閲覧者に対して公開される情報であり、なんらかの理由で変更または削除されない限り、人工言語学Wikiのサーバーが無期限に保持し続けます。&lt;br /&gt;
&lt;br /&gt;
もし、記事の内容や要約に書き込まれた個人情報が、投稿者もしくは当該個人の意思、または人工言語学の主旨および人工言語コミュニティーの維持に反すると考えられる場合、状況を総合的に判断して、運営者が当該部分の投稿記録を含めた削除対応を行うことがあります。また、利用者が運営者に対してそのような申し立てを行うこともできますので、お問い合わせください。&lt;br /&gt;
&lt;br /&gt;
== 免責事項 ==&lt;br /&gt;
&lt;br /&gt;
運営者は、投稿者の個人情報の保護のために最善を尽くしますが、絶対に安全なセキュリティー対策というものは存在しないため、上に挙げた非公開情報が漏洩する可能性はゼロではありません。漏洩した場合の当ウェブサイト上での被害（例えば、アカウント乗っ取り後のスパム投稿など）に関しては運営者が適宜対応できますが、二次被害（例えば、他のウェブサービスで同じパスワードを用いていたことによる、そのサービス上で起こる損害など）について、運営者は一切責任を負うことはできません。&lt;br /&gt;
&lt;br /&gt;
人工言語学Wikiは、MediaWikiというフレームワークを利用して構築されています。運営者は、MediaWikiおよびその内部で利用されている他のソフトウェアや、インストールされている拡張機能の挙動に関して、全てを把握しているわけではありません。そのため、運営者の意図しないところで、上記に挙げた項目以外の個人情報の収集や目的外利用などが暗黙的に行われている可能性を否定できません。しかし、そのような部分を見つけ次第、可能な限りその機能性を無効化し、記録された余分な個人情報を消去することを約束します。&lt;br /&gt;
&lt;br /&gt;
== お問い合わせ ==&lt;br /&gt;
&lt;br /&gt;
[mailto:contact@conlinguistics.jp contact@conlinguistics.jp]&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E5%88%A9%E7%94%A8%E8%80%85:Yuhr&amp;diff=957</id>
		<title>利用者:Yuhr</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E5%88%A9%E7%94%A8%E8%80%85:Yuhr&amp;diff=957"/>
		<updated>2025-04-13T06:27:11Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「* https://github.com/yuhr * https://yuhr.org/.well-known/nostr.json * https://x.com/exograph」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* https://github.com/yuhr&lt;br /&gt;
* https://yuhr.org/.well-known/nostr.json&lt;br /&gt;
* https://x.com/exograph&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6&amp;diff=469</id>
		<title>人工言語学</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6&amp;diff=469"/>
		<updated>2024-04-03T16:12:50Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: 段落を調整&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;人工言語学は、人工言語だけでなく、およそ言語と呼ばれるあらゆるものを、人工言語という創造的な観点から研究します。&lt;br /&gt;
&lt;br /&gt;
人工言語においては、すべてが認められます。どんな屈折変化も、どんな品詞も、どんな文法範疇も可能といえば可能であり、既存の言語学の範疇を完全に逸脱することもあるものです。人工言語は明らかに言語学の手に余ります。そのような理由から、人工言語学は、基本的に既存の言語学とは無関係な分野であり、特別な理由がない限り、言語学をただ前提として言語研究にあたることは推奨されません。言語学においては当然の事実であっても、研究に即して再検討されるべきです。&lt;br /&gt;
&lt;br /&gt;
==背景==&lt;br /&gt;
&lt;br /&gt;
セレン・アルバザード氏の立ちあげた人工言語学研究会の活動主旨は、人工言語を言語学の観点から分析研究しようというものでした。その理由から、研究の対象とされる人工言語は、言語学の対象となりうるだけの深遠さと運用実績を持ちあわせていなければなりませんでした。日々新しく作られる人工言語にそのようなことを求めることはできませんし、作られてからある程度時が経った言語も、往々にしてそこまでの発展は見られません。実際、人工言語学研究会が取りあつかったのはほとんどアルカだけでした。&lt;br /&gt;
&lt;br /&gt;
人工言語には「どんなものでも作れる」という、途方もなくとりとめのない性質があるために、ある一定の基準を設けて研究対象を選りすぐろうとするのは理解できることです。ただ、それでは人工言語全体を研究しているとは言えません。そして、言語学という、ある意味 (人工言語にとっては) 恣意的に決定された基準による敷居の高さがあったこともまた事実です。人工言語学は、そのような基準を排して、人工言語のもつ限りない自由度に沿ったかたちで、開かれた研究を可能とします。&lt;br /&gt;
&lt;br /&gt;
[[カテゴリ:総論]]&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E3%83%90%E3%83%99%E3%82%8B&amp;diff=348</id>
		<title>バベる</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E3%83%90%E3%83%99%E3%82%8B&amp;diff=348"/>
		<updated>2024-03-29T07:09:28Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: 漢字を開いた&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;バベる&#039;&#039;&#039;とは、以下のような意味をもつ語である。&lt;br /&gt;
#互いに言葉が通じていないこと。話の噛み合わないこと。&lt;br /&gt;
#互いに別々の言語を使わせることで、言葉を通じないようにすること。&lt;br /&gt;
#言語学や語学に関してあれこれ話すこと。&lt;br /&gt;
&lt;br /&gt;
==外部リンク==&lt;br /&gt;
*[http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10108960165 バベるってなんですか？どういう意味ですか？ - Yahoo!知恵袋]&lt;br /&gt;
*[http://conlang.echo.jp/arka/images/babel.pdf 『言語学少女とバベルの塔』seren arbazard] 53pに用例がある。&lt;br /&gt;
[[category:ユーモア]]&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E5%9F%B7%E7%AD%86%E3%82%AC%E3%82%A4%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3&amp;diff=347</id>
		<title>執筆ガイドライン</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E5%9F%B7%E7%AD%86%E3%82%AC%E3%82%A4%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3&amp;diff=347"/>
		<updated>2024-03-28T15:56:26Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: 一般記事とブログ記事の区別や、コメント機能に関する記述を削除&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ここでは、記事を執筆される方へのガイドラインを示します。&lt;br /&gt;
&lt;br /&gt;
== どのように書くか ==&lt;br /&gt;
記事を作成するつもりなら、&#039;&#039;&#039;とにかくシンプルに書いてみてください&#039;&#039;&#039;。その上で執筆に行き詰まったり、いまいちパッとしない気がする場合や、書きたいことを書き終わったと思った場合には、以下の方針を参考にしながらあなたの記事を何度も読み返してみてください。一時的に保存したい場合は、その旨を要約に書いてください。&lt;br /&gt;
&lt;br /&gt;
既存の記事を編集する場合には、記事の読みやすさを維持するためにこの方針に従ってください。&lt;br /&gt;
* &#039;&#039;&#039;記事のタイトルはできるだけ一般的に認められている名前にしてください&#039;&#039;&#039;。既に知れ渡った名前の存在している概念に独自の名前を付けることは、いたずらに混乱を招きかねません。基本的にWikipediaにあるものと同じ記事名にしてください。&lt;br /&gt;
* &#039;&#039;&#039;常体で書いてください&#039;&#039;&#039;。Wikiの全体的な運営に関わる記事（例えばこのガイドライン）が敬体なのは、&#039;&#039;運営者として&#039;&#039;書いているからです。執筆者の立場を限定すべきでない一般の記事では、常体を使った方が適切です。&lt;br /&gt;
* &#039;&#039;&#039;中立的な観点から記述してください&#039;&#039;&#039;。&amp;lt;span&amp;gt;特定の主義や流派、立場を攻撃したり、Wikiの利用者が迷惑する記述をすることは避けてください。また逆に、特定の立場へと読者を誘導するような記述も避けるべきです。無用な争いを避けるため、何らかの考えを「&#039;&#039;良い。&#039;&#039;」「&#039;&#039;悪い。&#039;&#039;」と断言しないよう留意し、「&#039;&#039;一考に値する。&#039;&#039;」などの表現に置き換えられないか検討してください。置き換えられない場合、それはおそらく書くべきではないことです。&amp;lt;/span&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;一人称的記述を避けてください&#039;&#039;&#039;。一般の記事は、「（私は）&#039;&#039;どこで何々をどうした。&#039;&#039;」ではなく、「&#039;&#039;〇〇はどこで何々をこうした。&#039;&#039;」「&#039;&#039;何々とは〇〇によってこうされたものである。&#039;&#039;」というふうに記述する場です。読者にとって、あなたと執筆者とは別の存在です。あなたが執筆者であることを推測しながら読む必要のある記述は、そのことを知らない読者を排除します。例えば「（私は）&#039;&#039;何々と考えてほしい。&#039;&#039;」「（私は）&#039;&#039;何々ということを期待する。&#039;&#039;」のような&#039;&#039;&#039;表明&#039;&#039;&#039;は、代わりに「&#039;&#039;何々と考えるべきである。&#039;&#039;」「&#039;&#039;何々ということが期待されている。&#039;&#039;」という&#039;&#039;&#039;叙述&#039;&#039;&#039;に変えるべきです。しかし「&#039;&#039;これを何々と定義する。&#039;&#039;」「&#039;&#039;これを何々と記述する。&#039;&#039;」などはそのままで構いません。なぜならこれらは、あなたと無関係の議論であり、隣接する記述の意味を明確にするだけのものであるからです。&lt;br /&gt;
* &#039;&#039;&#039;記事や見出し、段落などの論理構造を適切に使ってください&#039;&#039;&#039;。あるトピックについての説明が、関連トピックの記事や見出しの下に置かれているような事態は不条理です。それらは本来の場に書いて、関連トピックから誘導してください（リンクや「&#039;&#039;前述&#039;&#039;」「&#039;&#039;後述&#039;&#039;」などによって）。また、あまりに書くべきことが少ないトピックは他のトピックと統合できないか確認してください。ほとんどの場合「&#039;&#039;特徴&#039;&#039;」「&#039;&#039;性質&#039;&#039;」「&#039;&#039;概要&#039;&#039;」「&#039;&#039;解説&#039;&#039;」「&#039;&#039;意味&#039;&#039;」といった見出しは無意味であり、単なる段落であるべきです。それらは上の階層に開いてください。&lt;br /&gt;
* &#039;&#039;&#039;冗長な記述は避けてください&#039;&#039;&#039;。記事の保守性を著しく損なうため、記述をコピーしたりせず、また見つけた場合はどちらかを削除できるように記事の流れを再構成してください。「読者には考えが及ばないかもしれない関連性」や「読者には無関係と考えられてしまっているかもしれない関連性」といった[[特筆性|特筆的]]な説明は推奨されますが、それ以外で、似たような表現が近い場所に何度も出現している場合は、読者を混乱させない限りで代名詞に置き換えるか、削除してください。「&#039;&#039;何々概念とはこういう概念である。&#039;&#039;」よりも「&#039;&#039;何々概念とはこういうものである。&#039;&#039;」の方が好ましいです。「&#039;&#039;一つだけではない&#039;&#039;」「&#039;&#039;複数ある&#039;&#039;」「&#039;&#039;二つ以上ある&#039;&#039;」というような記述はどれか一つを残せば充分です。&lt;br /&gt;
* &#039;&#039;&#039;当たり前のことを書く必要はありません&#039;&#039;&#039;。例えば、ある言語Lの記事おいて、「&#039;&#039;言語LにはP詞という独自の品詞がある。&#039;&#039;」と一度述べたのに、「&#039;&#039;&#039;&#039;&#039;言語Lにおいて&#039;&#039;&#039;P詞とはこういうものである。&#039;&#039;」と書くべきではありません。なぜなら、この文脈では「&#039;&#039;言語Lにおいて&#039;&#039;」ということは当たり前であり、あえてそう書くのは、「他の言語にもP詞という概念があるのではないか」「他の言語ではその意味が異なるのではないか」などと、記事内の他の記述と矛盾する推論を読者に強いることになるからです。しかし、当たり前でないことを書くことによって、それまで当たり前だった考え方が脅かされうるのであれば、躊躇わずに言及してください、「&#039;&#039;一般的にはどうであるが、このトピックに関して言えばこうである。&#039;&#039;」。すなわちP詞の例で言えば「&#039;&#039;P詞はどうであると上述したが、Q詞句においてはこのようにやや振舞いが異なる。&#039;&#039;」などのように。&lt;br /&gt;
* &#039;&#039;&#039;厳密に記述してください&#039;&#039;&#039;。別の概念を指す表現は区別してください。読者は基本的に、同じ表現ならば同じものを指していると考えます。紛らわしい表現は避け、その単語が何を意味しているのかを別の言葉で明らかにしてください。ただし厳密たろうとするあまり、読者にとってあまりに難解な、馴染みのない表現で埋め尽くされていないか常に確認し、それらの一部は平易な言葉に置き換えてください。たまには惹句を挿んで読者の興味を維持するのも良いでしょう。&lt;br /&gt;
* &#039;&#039;&#039;術語の選択は基本的に既存の慣習に従ってください&#039;&#039;&#039;。記事のタイトルと同じ理由です。自信がない場合には注釈を入れることを躊躇わないでください。すなわち括弧などで意味を限定しておけば、もし術語が不適切でも、慣習に親しみのある人が直してくれます。GoogleやWikipedia、そしてもちろん人工言語学Wikiはあなたの友達です。&lt;br /&gt;
* &#039;&#039;&#039;考察や研究の成果を示す場合には、必ずその意義を明記してください&#039;&#039;&#039;。結論だけを羅列するのは、端的に言って不親切です。まず読者は基本的にあなたの書く記事の内容に何の意義も感じていないと考えながら書くべきです。あなたの伝えたい考えを読者が導入するきっかけを与えるようにしてください。&lt;br /&gt;
* &#039;&#039;&#039;矛盾する記述をしていないか常に確認してください&#039;&#039;&#039;。もしそれが意味のある、もしくは見かけ上の矛盾なのであれば、それについてより詳しい説明を追加するべきです。一貫性のない論理は読者を混乱させます。&lt;br /&gt;
* &#039;&#039;&#039;出典や外部情報があればリンクしてください&#039;&#039;&#039;。これは読者がそのトピックについてより深く知ることができるようにするためです。たとえその外部媒体の永続性が確保できない場合でも、無いよりはましです。&lt;br /&gt;
&lt;br /&gt;
__節編集非表示__&lt;br /&gt;
[[カテゴリ:総論]]&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6&amp;diff=344</id>
		<title>人工言語学Wiki:人工言語学Wikiについて</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6&amp;diff=344"/>
		<updated>2024-03-28T06:43:20Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: 人工言語学への転送ページ&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[人工言語学]]&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E3%83%97%E3%83%A9%E3%82%A4%E3%83%90%E3%82%B7%E3%83%BC%E3%83%BB%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC&amp;diff=339</id>
		<title>人工言語学Wiki:プライバシー・ポリシー</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E3%83%97%E3%83%A9%E3%82%A4%E3%83%90%E3%82%B7%E3%83%BC%E3%83%BB%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC&amp;diff=339"/>
		<updated>2024-03-27T12:54:08Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「== 個人情報の収集項目およびそれらの目的 ==  人工言語学Wikiのシステムが収集する個人情報は、Wikiを正常に機能させるために必要な最小限の情報に限定されます。人工言語学Wikiは、広告配信、販売、その他の営利目的などのために個人情報を利用することはなく、アカウント管理と記事保全のためにのみ利用します。  === 収集される個人情報 ===  収…」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 個人情報の収集項目およびそれらの目的 ==&lt;br /&gt;
&lt;br /&gt;
人工言語学Wikiのシステムが収集する個人情報は、Wikiを正常に機能させるために必要な最小限の情報に限定されます。人工言語学Wikiは、広告配信、販売、その他の営利目的などのために個人情報を利用することはなく、アカウント管理と記事保全のためにのみ利用します。&lt;br /&gt;
&lt;br /&gt;
=== 収集される個人情報 ===&lt;br /&gt;
&lt;br /&gt;
収集される個人情報は以下のとおりです。これらのうち「全閲覧者に対して公開」される情報が、匿名の利用者によって何らかの目的で利用されることは妨げられません。インターネット上の無数のアーカイブ装置や、バックアップ処理によって、これらの公開情報が運営者の管理の及ばない外部の情報媒体に無期限に保持される可能性もあります。&lt;br /&gt;
&lt;br /&gt;
==== アカウント情報 ====&lt;br /&gt;
&lt;br /&gt;
人工言語学Wikiでは、スパム対策の一環として、記事投稿を行う際にはアカウント登録およびログインが求められます。アカウント登録の際、以下の情報の入力が求められます。&lt;br /&gt;
&lt;br /&gt;
* 利用者名（表示用、全閲覧者に対して公開）&lt;br /&gt;
* メールアドレス（スパム対策用および連絡用、非公開）&lt;br /&gt;
* パスワード（認証用、非公開）&lt;br /&gt;
&lt;br /&gt;
これらの情報は登録されるアカウントに紐づけられ、なんらかの理由で変更または削除されない限り、人工言語学Wikiのサーバーが無期限に保持し続けます。&lt;br /&gt;
&lt;br /&gt;
メールアドレス情報は、主として投稿者の適格性を疑似的に確認する手段として利用されます。アカウントの登録時に、確認用のリンクが記載されたメールが送信され、このリンク先にアクセスしてアカウントを確認することで、アカウントに投稿権限が与えられます。また、利用者が意図的にパスワード再設定の操作を開始した場合に、パスワード再設定用のリンクがこのメールアドレスに送信されます。ここに挙げた状況以外で人工言語学Wikiからメールが送信されるのは、セキュリティー侵害などの有事の連絡のみです。&lt;br /&gt;
&lt;br /&gt;
==== 投稿記録 ====&lt;br /&gt;
&lt;br /&gt;
記事の改訂によってウェブ上の情報の連関や整合性が損なわれないようにするために、人工言語学Wikiは、投稿された記事の全ての変更履歴を保持しており、これを投稿記録と呼びます。投稿記録には、以下の情報が含まれます。&lt;br /&gt;
&lt;br /&gt;
* 投稿内容を反映した直後の記事のスナップショット&lt;br /&gt;
* 投稿者情報&lt;br /&gt;
* 投稿日時&lt;br /&gt;
* 投稿の要約&lt;br /&gt;
&lt;br /&gt;
全てのアカウントの各投稿記録とその一覧、および全ての記事の各投稿記録とその一覧は、全閲覧者に対して公開される情報であり、なんらかの理由で変更または削除されない限り、人工言語学Wikiのサーバーが無期限に保持し続けます。&lt;br /&gt;
&lt;br /&gt;
もし、記事の内容や要約に書き込まれた個人情報が、投稿者もしくは当該個人の意思、または人工言語学の主旨および人工言語コミュニティーの維持に反すると考えられる場合、状況を総合的に判断して、運営者が当該部分の投稿記録を含めた削除対応を行うことがあります。また、利用者が運営者に対してそのような申し立てを行うこともできますので、お問い合わせください。&lt;br /&gt;
&lt;br /&gt;
== 免責事項 ==&lt;br /&gt;
&lt;br /&gt;
運営者は、投稿者の個人情報の保護のために最善を尽くしますが、絶対に安全なセキュリティー対策というものは存在しないため、上に挙げた非公開情報が漏洩する可能性はゼロではありません。漏洩した場合の当ウェブサイト上での被害（例えば、アカウント乗っ取り後のスパム投稿など）に関しては運営者が適宜対応できますが、二次被害（例えば、他のウェブサービスで同じパスワードを用いていたことによる、そのサービス上で起こる損害など）について、運営者は一切責任を負うことはできません。&lt;br /&gt;
&lt;br /&gt;
人工言語学Wikiは、MediaWikiというフレームワークを利用して構築されています。運営者は、MediaWikiおよびその内部で利用されている他のソフトウェアや、インストールされている拡張機能の挙動に関して、全てを把握しているわけではありません。そのため、運営者の意図しないところで、上記に挙げた項目以外の個人情報の収集や目的外利用などが暗黙的に行われている可能性を否定できません。しかし、そのような部分を見つけ次第、可能な限りその機能性を無効化し、記録された余分な個人情報を消去することを約束します。&lt;br /&gt;
&lt;br /&gt;
== お問い合わせ ==&lt;br /&gt;
&lt;br /&gt;
[mailto:contact@conlinguistics.jp contact@conlinguistics.jp]&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E5%85%8D%E8%B2%AC%E4%BA%8B%E9%A0%85&amp;diff=265</id>
		<title>人工言語学Wiki:免責事項</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E4%BA%BA%E5%B7%A5%E8%A8%80%E8%AA%9E%E5%AD%A6Wiki:%E5%85%8D%E8%B2%AC%E4%BA%8B%E9%A0%85&amp;diff=265"/>
		<updated>2024-01-05T13:49:28Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: ページの作成:「当Wikiの全ての記事は、特に断りがない限り、&amp;#039;&amp;#039;&amp;#039;[https://creativecommons.org/licenses/by-sa/4.0/deed.ja CC BY-SA 4.0]&amp;#039;&amp;#039;&amp;#039;のもとで許諾されています。許諾内容について詳しくはクリエイティブ・コモンズのウェブサイトをお読みください。  CC BY-SA 4.0に基づき、当Wikiの記事に関して、明示的か暗黙的かに関わらず、その有用性、真実性や非侵害性などについていかなる…」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;当Wikiの全ての記事は、特に断りがない限り、&#039;&#039;&#039;[https://creativecommons.org/licenses/by-sa/4.0/deed.ja CC BY-SA 4.0]&#039;&#039;&#039;のもとで許諾されています。許諾内容について詳しくはクリエイティブ・コモンズのウェブサイトをお読みください。&lt;br /&gt;
&lt;br /&gt;
CC BY-SA 4.0に基づき、当Wikiの記事に関して、明示的か暗黙的かに関わらず、その有用性、真実性や非侵害性などについていかなる保証もありません。特に、投稿された内容が何らかの知的財産権等を侵害していないという保証はありません。もしあなたが当Wikiに記事を投稿される場合、あなたはその投稿内容をCC BY-SA 4.0の元で他のユーザーに対して許諾することに同意することになりますが、それが有効なのは、その内容があなたが書いたものである場合またはCC BY-SA 4.0の元で再配布可能な何らかの許諾を権利者から得ている場合に限ります。それぞれの記事の投稿行為およびその内容に関して、当Wikiの運営者は何ら責任を負うことができません。&lt;br /&gt;
&lt;br /&gt;
一般にそれぞれの記事には著者が複数存在し、匿名である場合もあるため、記事内容の再配布および翻案にあたって著者名を列挙することが常に可能とは限らず、またしばしば無意味です。したがって、CC BY-SA 4.0の許諾条件のうち「表示（Attribution）」を達成するための妥当な方法は、利用者にとって現実的に到達可能な箇所に、当該記事へのハイパーリンクを貼る（電子媒体の場合）もしくはURIを付録する（物理媒体の場合）ことです。&lt;br /&gt;
&lt;br /&gt;
なお、基本的な著作物としての記事の取り扱い方、例えば公正な範囲での引用などに関して、本許諾がそれを妨げることはないはずです。&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:fax.jpg&amp;diff=22</id>
		<title>ファイル:fax.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:fax.jpg&amp;diff=22"/>
		<updated>2023-12-25T14:11:21Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
	<entry>
		<id>https://wiki.conlinguistics.jp/index.php?title=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:o_df9141c8.png&amp;diff=21</id>
		<title>ファイル:o df9141c8.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.conlinguistics.jp/index.php?title=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:o_df9141c8.png&amp;diff=21"/>
		<updated>2023-12-25T13:58:00Z</updated>

		<summary type="html">&lt;p&gt;Yuhr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Yuhr</name></author>
	</entry>
</feed>