<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.you107657.duckdns.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AExclusive</id>
	<title>Module:Exclusive - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.you107657.duckdns.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AExclusive"/>
	<link rel="alternate" type="text/html" href="https://wiki.you107657.duckdns.org/index.php?title=Module:Exclusive&amp;action=history"/>
	<updated>2026-09-27T23:45:58Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://wiki.you107657.duckdns.org/index.php?title=Module:Exclusive&amp;diff=13150&amp;oldid=prev</id>
		<title>imported&gt;Merge: merge.py</title>
		<link rel="alternate" type="text/html" href="https://wiki.you107657.duckdns.org/index.php?title=Module:Exclusive&amp;diff=13150&amp;oldid=prev"/>
		<updated>2026-09-25T10:55:52Z</updated>

		<summary type="html">&lt;p&gt;merge.py&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:55, 25 September 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key tensura:diff:1.41:old-5333:rev-13150 --&gt;
&lt;/table&gt;</summary>
		<author><name>imported&gt;Merge</name></author>
	</entry>
	<entry>
		<id>https://wiki.you107657.duckdns.org/index.php?title=Module:Exclusive&amp;diff=5333&amp;oldid=prev</id>
		<title>imported&gt;Merge: merge.py</title>
		<link rel="alternate" type="text/html" href="https://wiki.you107657.duckdns.org/index.php?title=Module:Exclusive&amp;diff=5333&amp;oldid=prev"/>
		<updated>2026-09-25T10:55:52Z</updated>

		<summary type="html">&lt;p&gt;merge.py&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;---Holds the tables with the l10n information for the different languages, taken from the l10n submodule.&lt;br /&gt;
local l10n_data = mw.loadData(&amp;#039;Module:Exclusive/l10n&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
---Database with exclusivity info.&lt;br /&gt;
---luacache.get() is relative slow, therefore we load data from luacache only once per page.&lt;br /&gt;
local exclusive_info = mw.loadData(&amp;#039;Module:Exclusive/loaddata&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local bit32 = require(&amp;#039;bit32&amp;#039;)&lt;br /&gt;
local trim = mw.text.trim&lt;br /&gt;
&lt;br /&gt;
---Default content language of the wiki (i.e. `$wgLanguageCode`, not the value of the&lt;br /&gt;
---`uselang` URL parameter, and not the user&amp;#039;s language preference setting).&lt;br /&gt;
local contentLanguage = mw.getContentLanguage()&lt;br /&gt;
&lt;br /&gt;
---Holds the arguments from the template call.&lt;br /&gt;
local args_table&lt;br /&gt;
&lt;br /&gt;
---The current language. Determines which l10n table to use.&lt;br /&gt;
local lang&lt;br /&gt;
&lt;br /&gt;
---Return the l10n string associated with the `key`.&lt;br /&gt;
---@param key string&lt;br /&gt;
---@return string&lt;br /&gt;
local function l10n(key)&lt;br /&gt;
	if l10n_data[lang] then&lt;br /&gt;
		return l10n_data[lang][key] or l10n_data[&amp;#039;en&amp;#039;][key]&lt;br /&gt;
	else&lt;br /&gt;
		return l10n_data[&amp;#039;en&amp;#039;][key]&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Return a trimmed version of the value of the template parameter with the specified `key`.&lt;br /&gt;
---Return `nil` if the parameter is empty or unset.&lt;br /&gt;
---@param key string|number&lt;br /&gt;
---@return string|nil&lt;br /&gt;
local function getArg(key)&lt;br /&gt;
	local value = trim(args_table[key] or &amp;#039;&amp;#039;)&lt;br /&gt;
	return (value ~= &amp;#039;&amp;#039;) and value or nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Convert a string of parameters in a `@param1:value^@param2:value^` format to a table.&lt;br /&gt;
---@param paramstr string&lt;br /&gt;
---@return table&lt;br /&gt;
local function parse(paramstr)&lt;br /&gt;
	local args = {}&lt;br /&gt;
	for s in string.gmatch(paramstr, &amp;#039;%b@^&amp;#039;) do&lt;br /&gt;
		local k,v = string.match(s, &amp;#039;^@(.-):(.*)^$&amp;#039;)&lt;br /&gt;
		args[k] = v&lt;br /&gt;
	end&lt;br /&gt;
	return args&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Split the `str` on each `div` in it and return the result as a table.&lt;br /&gt;
---This is much much faster then `mw.text.split`.&lt;br /&gt;
---Credit: http://richard.warburton.it.&lt;br /&gt;
---@param div string&lt;br /&gt;
---@param str string&lt;br /&gt;
---@return table|boolean&lt;br /&gt;
local function explode(div,str)&lt;br /&gt;
	if (div==&amp;#039;&amp;#039;) then return false end&lt;br /&gt;
	local pos,arr = 0,{}&lt;br /&gt;
	-- for each divider found&lt;br /&gt;
	for st,sp in function() return string.find(str,div,pos,true) end do&lt;br /&gt;
		arr[#arr + 1] = string.sub(str,pos,st-1) -- Attach chars left of current divider&lt;br /&gt;
		pos = sp + 1 -- Jump past current divider&lt;br /&gt;
	end&lt;br /&gt;
	arr[#arr + 1] = string.sub(str,pos) -- Attach chars right of last divider&lt;br /&gt;
	return arr&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Return the integer defined in the database for the specified `page`.&lt;br /&gt;
---Perform some standardization on the `page` for that first.&lt;br /&gt;
---@param page string&lt;br /&gt;
---@return number&lt;br /&gt;
local function readFromDb(page)&lt;br /&gt;
	-- standardize pagename: remove section parts (&amp;#039;x#section&amp;#039; -&amp;gt; &amp;#039;x&amp;#039;) and replace underscores with spaces&lt;br /&gt;
	page = contentLanguage:ucfirst(string.gsub(string.gsub(page or &amp;#039;&amp;#039;, &amp;#039;#.*&amp;#039;, &amp;#039;&amp;#039;), &amp;#039;_&amp;#039;, &amp;#039; &amp;#039;))&lt;br /&gt;
	return exclusive_info[page] or 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Override the exclusivity information in `info`&lt;br /&gt;
---with the content of `jdcom3`.&lt;br /&gt;
---@param info number&lt;br /&gt;
---@param jdcom3 string Expected format: `&amp;lt;j&amp;gt;:&amp;lt;d&amp;gt;:&amp;lt;c&amp;gt;:&amp;lt;o&amp;gt;:&amp;lt;m&amp;gt;:&amp;lt;3&amp;gt;`, with each platform either a Boolean string (&amp;quot;y&amp;quot;, &amp;quot;0&amp;quot;, etc.) or an empty string&lt;br /&gt;
---@return number&lt;br /&gt;
local function override(info, jdcom3)&lt;br /&gt;
	for k, v in pairs(explode(&amp;#039;:&amp;#039;, jdcom3)) do&lt;br /&gt;
		if v ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			if v == &amp;#039;1&amp;#039; or v == &amp;#039;y&amp;#039; or v == &amp;#039;yes&amp;#039; then&lt;br /&gt;
				info = bit32.replace(info, 1, k-1)&lt;br /&gt;
			elseif v == &amp;#039;0&amp;#039; or v == &amp;#039;n&amp;#039; or v == &amp;#039;no&amp;#039; then&lt;br /&gt;
				info = bit32.replace(info, 0, k-1)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return info&lt;br /&gt;
&lt;br /&gt;
	-- Example to demonstrate the behavior of this function:&lt;br /&gt;
	-- Goal: Change &amp;quot;dcom&amp;quot; to &amp;quot;dco3&amp;quot;.&lt;br /&gt;
	-- info = 30 (&amp;quot;dcom&amp;quot;), jdcom3 = &amp;quot;::::no:yes&amp;quot;&lt;br /&gt;
	-- decimal 30 = binary 011110&lt;br /&gt;
	-- The first &amp;quot;no&amp;quot; is at index 4 in the jdcom3 string, so&lt;br /&gt;
	-- replace the corresponding bit with a 0: 011110 -&amp;gt; 001110.&lt;br /&gt;
	-- The &amp;quot;yes&amp;quot; is at index 5, so replace the bit at index 5&lt;br /&gt;
	-- with a 1: 001110 -&amp;gt; 101110.&lt;br /&gt;
	-- The result is info = 46 (&amp;quot;dco3&amp;quot;).&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Main function to retrieve exclusivity information.&lt;br /&gt;
---@param page string The entity to get the info about.&lt;br /&gt;
---@param invert boolean Whether to invert the exclusivity info.&lt;br /&gt;
---@param pagenot string The entity whose exclusivity info to subtract from the main one&amp;#039;s.&lt;br /&gt;
---@param jdcom3 string Manual exclusivity info to override the fetched one with.&lt;br /&gt;
---@return number info An integer that holds the exclusivity information.&lt;br /&gt;
local function getInfo(page, invert, pagenot, jdcom3)&lt;br /&gt;
	local info = 0&lt;br /&gt;
&lt;br /&gt;
	-- A piece of exclusivity information is a set of Boolean values, one&lt;br /&gt;
	-- for each platform. This is represented as bits of the `info` integer.&lt;br /&gt;
	-- Each platform (Japanese console, Desktop, Console, Old-gen console,&lt;br /&gt;
	-- Mobile, and 3DS – &amp;quot;jdcom3&amp;quot;) is assigned one bit, in this order.&lt;br /&gt;
	-- This means that, for instance, an `info` value of 2 would represent&lt;br /&gt;
	-- Desktop-only exclusivity (&amp;quot;d&amp;quot;):&lt;br /&gt;
	-- decimal  2 = binary 000010&lt;br /&gt;
	--                     3mocdj  -&amp;gt; &amp;quot;d&amp;quot;&lt;br /&gt;
	-- Similarly, an `info` value of 40 would represent Old-gen and 3DS exclusivity (&amp;quot;o3&amp;quot;):&lt;br /&gt;
	-- decimal 40 = binary 101000&lt;br /&gt;
	--                     3mocdj -&amp;gt; &amp;quot;o3&amp;quot;&lt;br /&gt;
	-- See Module:Exclusive/data for a quick overview of all values.&lt;br /&gt;
&lt;br /&gt;
	-- This system allows using bitwise operations (https://en.wikipedia.org/wiki/Bitwise_operation)&lt;br /&gt;
	-- instead of the historically used string processing, resulting in much lower script execution times.&lt;br /&gt;
&lt;br /&gt;
	-- get info about page&lt;br /&gt;
	if page then&lt;br /&gt;
		info = readFromDb(page)&lt;br /&gt;
		if invert then&lt;br /&gt;
			-- invert jdcom3 and set j=0 (always force-off Japanese console when inverting)&lt;br /&gt;
			-- (3E in hexadecimal is 111110 in binary, i.e. &amp;quot;dcom3&amp;quot;)&lt;br /&gt;
			info = bit32.band(bit32.bnot(info), 0x3E)&lt;br /&gt;
		end&lt;br /&gt;
		if pagenot then&lt;br /&gt;
			-- exclude some versions, depending on pagenot&lt;br /&gt;
			local info_not = readFromDb(pagenot)&lt;br /&gt;
			info = bit32.band(info, bit32.bnot(info_not))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- The &amp;quot;invert&amp;quot; and &amp;quot;pagenot&amp;quot; functionalities above utilize&lt;br /&gt;
		-- bit masking (https://en.wikipedia.org/wiki/Mask_(computing)).&lt;br /&gt;
		-- The following example demonstrates the operations:&lt;br /&gt;
		-- 1. assume info=22 (&amp;quot;dcm&amp;quot;, binary 010110)&lt;br /&gt;
		-- 2. invert:&lt;br /&gt;
		--    2a. not(010110) = 101001 (&amp;quot;jo3&amp;quot;, the inverse of &amp;quot;dcm&amp;quot;)&lt;br /&gt;
		--    2b. and(101001, 111110) = 101000 (&amp;quot;o3&amp;quot;, forced-off &amp;quot;j&amp;quot;)&lt;br /&gt;
		-- 3. assume info_not=8 (&amp;quot;o&amp;quot;, binary 001000)&lt;br /&gt;
		--    3a. not(001000) = 110111&lt;br /&gt;
		--    3b. and(101000, 110111) = 100000 (&amp;quot;3&amp;quot;)&lt;br /&gt;
		-- An initial exclusivity info of &amp;quot;dcm&amp;quot; was inverted to &amp;quot;o3&amp;quot;,&lt;br /&gt;
		-- then &amp;quot;o&amp;quot; was subtracted from it, resulting in the final&lt;br /&gt;
		-- exclusivity information of &amp;quot;3&amp;quot;.&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- override if needed&lt;br /&gt;
	if jdcom3 == nil or jdcom3 == &amp;#039;:::::&amp;#039; then&lt;br /&gt;
		return info&lt;br /&gt;
	else&lt;br /&gt;
		return override(info, jdcom3)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Return an HTML span tag whose `class` attribute is set&lt;br /&gt;
---according to the exclusivity `info`.&lt;br /&gt;
---@param info number&lt;br /&gt;
---@param _small boolean Whether to add the &amp;quot;s&amp;quot; class, for small icons&lt;br /&gt;
---@return string&lt;br /&gt;
local function eicons(info, _small)&lt;br /&gt;
	local class = _small and &amp;#039;eico s&amp;#039; or &amp;#039;eico&amp;#039;&lt;br /&gt;
	local hovertext&lt;br /&gt;
&lt;br /&gt;
	if bit32.btest(info, 0x01) then&lt;br /&gt;
		-- Japanese console is set, so simply display that&lt;br /&gt;
		-- (&amp;quot;j&amp;quot; is always alone or not set at all – &amp;quot;dcj&amp;quot;, for instance, doesn&amp;#039;t exist)&lt;br /&gt;
		return &amp;#039;&amp;lt;span class=&amp;quot;&amp;#039;..class..&amp;#039; j&amp;quot; title=&amp;quot;&amp;#039;..l10n(&amp;#039;text_j&amp;#039;)..&amp;#039;&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- for each platform of dcom3, add the class and load the hovertext if the platform if set&lt;br /&gt;
	-- (e.g. for info=50 (&amp;quot;dm3&amp;quot;), append &amp;quot;i1 i4 i5&amp;quot; to the class and load the&lt;br /&gt;
	-- &amp;quot;text_1&amp;quot;, &amp;quot;text_4&amp;quot;, and &amp;quot;text_5&amp;quot; l10n strings)&lt;br /&gt;
	local v = {}&lt;br /&gt;
	for i = 1, 5 do -- 0 is &amp;quot;j&amp;quot;&lt;br /&gt;
		if bit32.btest(info, 2^i) then&lt;br /&gt;
			class = class .. &amp;quot; i&amp;quot; .. i&lt;br /&gt;
			v[#v+1] = l10n(&amp;#039;text_&amp;#039; .. i)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local hovertext = mw.text.listToText(v, l10n(&amp;#039;list_separator&amp;#039;), l10n(&amp;#039;list_conjunction&amp;#039;))&lt;br /&gt;
	hovertext = string.format(contentLanguage:convertPlural(#v, l10n(&amp;#039;version_plural_forms&amp;#039;)), hovertext)&lt;br /&gt;
	return &amp;#039;&amp;lt;span class=&amp;quot;&amp;#039;..class..&amp;#039;&amp;quot; title=&amp;quot;&amp;#039;..hovertext..&amp;#039;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;i&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;span&amp;gt;(&amp;#039;..hovertext..&amp;#039;)&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Check if the `infoToCheck` integer is a valid number for output.&lt;br /&gt;
---It is considered invalid if it represents an empty exclusivity (&amp;quot;&amp;quot;)&lt;br /&gt;
---or a &amp;quot;full&amp;quot; exclusivity, i.e. all platforms being set (&amp;quot;dcom3&amp;quot; or &amp;quot;jdcom3&amp;quot;).&lt;br /&gt;
---@param infoToCheck number&lt;br /&gt;
---@return boolean&lt;br /&gt;
local function infoIsInvalid(infoToCheck)&lt;br /&gt;
	return infoToCheck == 0x00 or infoToCheck == 0x3E or infoToCheck == 0x3F&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-----------------------------------------------------------------&lt;br /&gt;
-- main return object&lt;br /&gt;
return {&lt;br /&gt;
&lt;br /&gt;
-- for templates; get all exclusive info and set it in dplvars.&lt;br /&gt;
-- parameters: $1 = pagename&lt;br /&gt;
getInfo = function(frame)&lt;br /&gt;
	args_table = frame.args -- cache&lt;br /&gt;
&lt;br /&gt;
	local info = getInfo(getArg(1), getArg(&amp;#039;invert&amp;#039;), getArg(&amp;#039;pagenot&amp;#039;))&lt;br /&gt;
	if infoIsInvalid(info) then&lt;br /&gt;
		frame:callParserFunction{ name = &amp;#039;#dplvar:set&amp;#039;, args = {&lt;br /&gt;
			&amp;#039;ex_j&amp;#039;, &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_d&amp;#039;, &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_c&amp;#039;, &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_o&amp;#039;, &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_m&amp;#039;, &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_3&amp;#039;, &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_cached&amp;#039;, &amp;#039;y&amp;#039;&lt;br /&gt;
		} }&lt;br /&gt;
	else&lt;br /&gt;
		frame:callParserFunction{ name = &amp;#039;#dplvar:set&amp;#039;, args = {&lt;br /&gt;
			&amp;#039;ex_j&amp;#039;, bit32.btest(info, 2^0) and &amp;#039;y&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_d&amp;#039;, bit32.btest(info, 2^1) and &amp;#039;y&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_c&amp;#039;, bit32.btest(info, 2^2) and &amp;#039;y&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_o&amp;#039;, bit32.btest(info, 2^3) and &amp;#039;y&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_m&amp;#039;, bit32.btest(info, 2^4) and &amp;#039;y&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_3&amp;#039;, bit32.btest(info, 2^5) and &amp;#039;y&amp;#039; or &amp;#039;&amp;#039;,&lt;br /&gt;
			&amp;#039;ex_cached&amp;#039;, &amp;#039;y&amp;#039;&lt;br /&gt;
		} }&lt;br /&gt;
	end&lt;br /&gt;
end,&lt;br /&gt;
&lt;br /&gt;
-- for {{eicons}}&lt;br /&gt;
eicons = function(frame)&lt;br /&gt;
	args_table = parse(frame.args[1])-- cache&lt;br /&gt;
	lang = getArg(&amp;#039;lang&amp;#039;) -- set lang for l10n&lt;br /&gt;
	local info = getInfo(getArg(&amp;#039;page&amp;#039;), getArg(&amp;#039;invert&amp;#039;), getArg(&amp;#039;pagenot&amp;#039;), getArg(&amp;#039;jdcom3&amp;#039;))&lt;br /&gt;
	if infoIsInvalid(info) then&lt;br /&gt;
		return frame:expandTemplate{ title = &amp;#039;error&amp;#039;, args = { l10n(&amp;#039;eicons_error_text&amp;#039;), l10n(&amp;#039;eicons_error_cate&amp;#039;), from = &amp;#039;Eicons&amp;#039; } }&lt;br /&gt;
	end&lt;br /&gt;
	return eicons(info, getArg(&amp;#039;small&amp;#039;))&lt;br /&gt;
end,&lt;br /&gt;
&lt;br /&gt;
-- simplified version of the eicons function above, for other modules such as Module:Item&lt;br /&gt;
simpleEicons = function(page, language, small)&lt;br /&gt;
	local info = getInfo(page)&lt;br /&gt;
	if infoIsInvalid(info) then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	lang = language -- set lang for l10n&lt;br /&gt;
	return eicons(info, small)&lt;br /&gt;
end,&lt;br /&gt;
&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>imported&gt;Merge</name></author>
	</entry>
</feed>