<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ar">
	<id>https://www.copticpedia.org/index.php?action=history&amp;feed=atom&amp;title=%D9%88%D8%AD%D8%AF%D8%A9%3ATableTools</id>
	<title>وحدة:TableTools - تاريخ المراجعة</title>
	<link rel="self" type="application/atom+xml" href="https://www.copticpedia.org/index.php?action=history&amp;feed=atom&amp;title=%D9%88%D8%AD%D8%AF%D8%A9%3ATableTools"/>
	<link rel="alternate" type="text/html" href="https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;action=history"/>
	<updated>2026-04-03T22:41:10Z</updated>
	<subtitle>تاريخ التعديل لهذه الصفحة في الويكي</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;diff=75885&amp;oldid=prev</id>
		<title>Gerges: مراجعة واحدة</title>
		<link rel="alternate" type="text/html" href="https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;diff=75885&amp;oldid=prev"/>
		<updated>2021-10-22T00:41:13Z</updated>

		<summary type="html">&lt;p&gt;مراجعة واحدة&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ar&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;→ مراجعة أقدم&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;مراجعة ٠٠:٤١، ٢٢ أكتوبر ٢٠٢١&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;ar&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(لا فرق)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Gerges</name></author>
	</entry>
	<entry>
		<id>https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;diff=1779&amp;oldid=prev</id>
		<title>Gerges: ٤ مراجعات</title>
		<link rel="alternate" type="text/html" href="https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;diff=1779&amp;oldid=prev"/>
		<updated>2021-03-14T14:11:50Z</updated>

		<summary type="html">&lt;p&gt;٤ مراجعات&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ar&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;→ مراجعة أقدم&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;مراجعة ١٤:١١، ١٤ مارس ٢٠٢١&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;ar&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(لا فرق)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Gerges</name></author>
	</entry>
	<entry>
		<id>https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;diff=75884&amp;oldid=prev</id>
		<title>كوبتيكبيديا&gt;طلال في ٠٩:٤١، ٢ نوفمبر ٢٠٢٠</title>
		<link rel="alternate" type="text/html" href="https://www.copticpedia.org/index.php?title=%D9%88%D8%AD%D8%AF%D8%A9:TableTools&amp;diff=75884&amp;oldid=prev"/>
		<updated>2020-11-02T09:41:28Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;صفحة جديدة&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--                               TableTools                                       --&lt;br /&gt;
--                                                                                --&lt;br /&gt;
-- This module includes a number of functions for dealing with Lua tables.        --&lt;br /&gt;
-- It is a meta-module, meant to be called from other Lua modules, and should     --&lt;br /&gt;
-- not be called directly from #invoke.                                           --&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
local libraryUtil = require('libraryUtil')&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- Define often-used variables and functions.&lt;br /&gt;
local floor = math.floor&lt;br /&gt;
local infinity = math.huge&lt;br /&gt;
local checkType = libraryUtil.checkType&lt;br /&gt;
local checkTypeMulti = libraryUtil.checkTypeMulti&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- isPositiveInteger&lt;br /&gt;
--&lt;br /&gt;
-- This function returns true if the given value is a positive integer, and false&lt;br /&gt;
-- if not. Although it doesn't operate on tables, it is included here as it is&lt;br /&gt;
-- useful for determining whether a given table key is in the array part or the&lt;br /&gt;
-- hash part of a table.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.isPositiveInteger(v)&lt;br /&gt;
	return type(v) == 'number' and v &amp;gt;= 1 and floor(v) == v and v &amp;lt; infinity &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- isNan&lt;br /&gt;
--&lt;br /&gt;
-- This function returns true if the given number is a NaN value, and false&lt;br /&gt;
-- if not. Although it doesn't operate on tables, it is included here as it is&lt;br /&gt;
-- useful for determining whether a value can be a valid table key. Lua will&lt;br /&gt;
-- generate an error if a NaN is used as a table key.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.isNan(v)&lt;br /&gt;
	return type(v) == 'number' and tostring(v) == '-nan'&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- shallowClone&lt;br /&gt;
--&lt;br /&gt;
-- This returns a clone of a table. The value returned is a new table, but all&lt;br /&gt;
-- subtables and functions are shared. Metamethods are respected, but the returned&lt;br /&gt;
-- table will have no metatable of its own.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.shallowClone(t)&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		ret[k] = v&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- removeDuplicates&lt;br /&gt;
--&lt;br /&gt;
-- This removes duplicate values from an array. Non-positive-integer keys are&lt;br /&gt;
-- ignored. The earliest value is kept, and all subsequent duplicate values are&lt;br /&gt;
-- removed, but otherwise the array order is unchanged.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.removeDuplicates(t)&lt;br /&gt;
	checkType('removeDuplicates', 1, t, 'table')&lt;br /&gt;
	local isNan = p.isNan&lt;br /&gt;
	local ret, exists = {}, {}&lt;br /&gt;
	for i, v in ipairs(t) do&lt;br /&gt;
		if isNan(v) then&lt;br /&gt;
			-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.&lt;br /&gt;
			ret[#ret + 1] = v&lt;br /&gt;
		else&lt;br /&gt;
			if not exists[v] then&lt;br /&gt;
				ret[#ret + 1] = v&lt;br /&gt;
				exists[v] = true&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end			&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- numKeys&lt;br /&gt;
--&lt;br /&gt;
-- This takes a table and returns an array containing the numbers of any numerical&lt;br /&gt;
-- keys that have non-nil values, sorted in numerical order.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.numKeys(t)&lt;br /&gt;
	checkType('numKeys', 1, t, 'table')&lt;br /&gt;
	local isPositiveInteger = p.isPositiveInteger&lt;br /&gt;
	local nums = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		if isPositiveInteger(k) then&lt;br /&gt;
			nums[#nums + 1] = k&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(nums)&lt;br /&gt;
	return nums&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- affixNums&lt;br /&gt;
--&lt;br /&gt;
-- This takes a table and returns an array containing the numbers of keys with the&lt;br /&gt;
-- specified prefix and suffix. For example, for the table&lt;br /&gt;
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix &amp;quot;a&amp;quot;, affixNums will&lt;br /&gt;
-- return {1, 3, 6}.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.affixNums(t, prefix, suffix)&lt;br /&gt;
	checkType('affixNums', 1, t, 'table')&lt;br /&gt;
	checkType('affixNums', 2, prefix, 'string', true)&lt;br /&gt;
	checkType('affixNums', 3, suffix, 'string', true)&lt;br /&gt;
&lt;br /&gt;
	local function cleanPattern(s)&lt;br /&gt;
		-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.&lt;br /&gt;
		return s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1')&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	prefix = prefix or ''&lt;br /&gt;
	suffix = suffix or ''&lt;br /&gt;
	prefix = cleanPattern(prefix)&lt;br /&gt;
	suffix = cleanPattern(suffix)&lt;br /&gt;
	local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'&lt;br /&gt;
&lt;br /&gt;
	local nums = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		if type(k) == 'string' then			&lt;br /&gt;
			local num = mw.ustring.match(k, pattern)&lt;br /&gt;
			if num then&lt;br /&gt;
				nums[#nums + 1] = tonumber(num)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(nums)&lt;br /&gt;
	return nums&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- numData&lt;br /&gt;
--&lt;br /&gt;
-- Given a table with keys like (&amp;quot;foo1&amp;quot;, &amp;quot;bar1&amp;quot;, &amp;quot;foo2&amp;quot;, &amp;quot;baz2&amp;quot;), returns a table&lt;br /&gt;
-- of subtables in the format &lt;br /&gt;
-- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} }&lt;br /&gt;
-- Keys that don't end with an integer are stored in a subtable named &amp;quot;other&amp;quot;.&lt;br /&gt;
-- The compress option compresses the table so that it can be iterated over with&lt;br /&gt;
-- ipairs.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.numData(t, compress)&lt;br /&gt;
	checkType('numData', 1, t, 'table')&lt;br /&gt;
	checkType('numData', 2, compress, 'boolean', true)&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$')&lt;br /&gt;
		if num then&lt;br /&gt;
			num = tonumber(num)&lt;br /&gt;
			local subtable = ret[num] or {}&lt;br /&gt;
			if prefix == '' then&lt;br /&gt;
				-- Positional parameters match the blank string; put them at the start of the subtable instead.&lt;br /&gt;
				prefix = 1&lt;br /&gt;
			end&lt;br /&gt;
			subtable[prefix] = v&lt;br /&gt;
			ret[num] = subtable&lt;br /&gt;
		else&lt;br /&gt;
			local subtable = ret.other or {}&lt;br /&gt;
			subtable[k] = v&lt;br /&gt;
			ret.other = subtable&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if compress then&lt;br /&gt;
		local other = ret.other&lt;br /&gt;
		ret = p.compressSparseArray(ret)&lt;br /&gt;
		ret.other = other&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- compressSparseArray&lt;br /&gt;
--&lt;br /&gt;
-- This takes an array with one or more nil values, and removes the nil values&lt;br /&gt;
-- while preserving the order, so that the array can be safely traversed with&lt;br /&gt;
-- ipairs.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.compressSparseArray(t)&lt;br /&gt;
	checkType('compressSparseArray', 1, t, 'table')&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	local nums = p.numKeys(t)&lt;br /&gt;
	for _, num in ipairs(nums) do&lt;br /&gt;
		ret[#ret + 1] = t[num]&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- sparseIpairs&lt;br /&gt;
--&lt;br /&gt;
-- This is an iterator for sparse arrays. It can be used like ipairs, but can&lt;br /&gt;
-- handle nil values.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.sparseIpairs(t)&lt;br /&gt;
	checkType('sparseIpairs', 1, t, 'table')&lt;br /&gt;
	local nums = p.numKeys(t)&lt;br /&gt;
	local i = 0&lt;br /&gt;
	local lim = #nums&lt;br /&gt;
	return function ()&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		if i &amp;lt;= lim then&lt;br /&gt;
			local key = nums[i]&lt;br /&gt;
			return key, t[key]&lt;br /&gt;
		else&lt;br /&gt;
			return nil, nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- size&lt;br /&gt;
--&lt;br /&gt;
-- This returns the size of a key/value pair table. It will also work on arrays,&lt;br /&gt;
-- but for arrays it is more efficient to use the # operator.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
function p.size(t)&lt;br /&gt;
	checkType('size', 1, t, 'table')&lt;br /&gt;
	local i = 0&lt;br /&gt;
	for k in pairs(t) do&lt;br /&gt;
		i = i + 1&lt;br /&gt;
	end&lt;br /&gt;
	return i&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function defaultKeySort(item1, item2)&lt;br /&gt;
	-- &amp;quot;number&amp;quot; &amp;lt; &amp;quot;string&amp;quot;, so numbers will be sorted before strings.&lt;br /&gt;
	local type1, type2 = type(item1), type(item2)&lt;br /&gt;
	if type1 ~= type2 then&lt;br /&gt;
		return type1 &amp;lt; type2&lt;br /&gt;
	else -- This will fail with table, boolean, function.&lt;br /&gt;
		return item1 &amp;lt; item2&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Returns a list of the keys in a table, sorted using either a default&lt;br /&gt;
	comparison function or a custom keySort function.&lt;br /&gt;
]]&lt;br /&gt;
function p.keysToList(t, keySort, checked)&lt;br /&gt;
	if not checked then&lt;br /&gt;
		checkType('keysToList', 1, t, 'table')&lt;br /&gt;
		checkTypeMulti('keysToList', 2, keySort, { 'function', 'boolean', 'nil' })&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local list = {}&lt;br /&gt;
	local index = 1&lt;br /&gt;
	for key, value in pairs(t) do&lt;br /&gt;
		list[index] = key&lt;br /&gt;
		index = index + 1&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if keySort ~= false then&lt;br /&gt;
		keySort = type(keySort) == 'function' and keySort or defaultKeySort&lt;br /&gt;
		&lt;br /&gt;
		table.sort(list, keySort)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return list&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Iterates through a table, with the keys sorted using the keysToList function.&lt;br /&gt;
	If there are only numerical keys, sparseIpairs is probably more efficient.&lt;br /&gt;
]]&lt;br /&gt;
function p.sortedPairs(t, keySort)&lt;br /&gt;
	checkType('sortedPairs', 1, t, 'table')&lt;br /&gt;
	checkType('sortedPairs', 2, keySort, 'function', true)&lt;br /&gt;
	&lt;br /&gt;
	local list = p.keysToList(t, keySort, true)&lt;br /&gt;
	&lt;br /&gt;
	local i = 0&lt;br /&gt;
	return function()&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		local key = list[i]&lt;br /&gt;
		if key ~= nil then&lt;br /&gt;
			return key, t[key]&lt;br /&gt;
		else&lt;br /&gt;
			return nil, nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Returns true if all keys in the table are consecutive integers starting at 1.&lt;br /&gt;
--]]&lt;br /&gt;
function p.isArray(t)&lt;br /&gt;
	checkType(&amp;quot;isArray&amp;quot;, 1, t, &amp;quot;table&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local i = 0&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		if t[i] == nil then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- { &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot; } -&amp;gt; { a = 1, b = 2, c = 3 }&lt;br /&gt;
function p.invert(array)&lt;br /&gt;
	checkType(&amp;quot;invert&amp;quot;, 1, array, &amp;quot;table&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local map = {}&lt;br /&gt;
	for i, v in ipairs(array) do&lt;br /&gt;
		map[v] = i&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return map&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	{ &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot; } -&amp;gt; { [&amp;quot;a&amp;quot;] = true, [&amp;quot;b&amp;quot;] = true, [&amp;quot;c&amp;quot;] = true }&lt;br /&gt;
--]]&lt;br /&gt;
function p.listToSet(t)&lt;br /&gt;
	checkType(&amp;quot;listToSet&amp;quot;, 1, t, &amp;quot;table&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local set = {}&lt;br /&gt;
	for _, item in ipairs(t) do&lt;br /&gt;
		set[item] = true&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return set&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Recursive deep copy function.&lt;br /&gt;
	Preserves identities of subtables.&lt;br /&gt;
	&lt;br /&gt;
]]&lt;br /&gt;
local function _deepCopy(orig, includeMetatable, already_seen)&lt;br /&gt;
	-- Stores copies of tables indexed by the original table.&lt;br /&gt;
	already_seen = already_seen or {}&lt;br /&gt;
	&lt;br /&gt;
	local copy = already_seen[orig]&lt;br /&gt;
	if copy ~= nil then&lt;br /&gt;
		return copy&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if type(orig) == 'table' then&lt;br /&gt;
		copy = {}&lt;br /&gt;
		for orig_key, orig_value in pairs(orig) do&lt;br /&gt;
			copy[deepcopy(orig_key, includeMetatable, already_seen)] = deepcopy(orig_value, includeMetatable, already_seen)&lt;br /&gt;
		end&lt;br /&gt;
		already_seen[orig] = copy&lt;br /&gt;
		&lt;br /&gt;
		if includeMetatable then&lt;br /&gt;
			local mt = getmetatable(orig)&lt;br /&gt;
			if mt ~= nil then&lt;br /&gt;
				local mt_copy = deepcopy(mt, includeMetatable, already_seen)&lt;br /&gt;
				setmetatable(copy, mt_copy)&lt;br /&gt;
				already_seen[mt] = mt_copy&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else -- number, string, boolean, etc&lt;br /&gt;
		copy = orig&lt;br /&gt;
	end&lt;br /&gt;
	return copy&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.deepCopy(orig, noMetatable, already_seen)&lt;br /&gt;
	checkType(&amp;quot;deepCopy&amp;quot;, 3, already_seen, &amp;quot;table&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	return _deepCopy(orig, not noMetatable, already_seen)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Concatenates all values in the table that are indexed by a number, in order.&lt;br /&gt;
	sparseConcat{ a, nil, c, d }  =&amp;gt;  &amp;quot;acd&amp;quot;&lt;br /&gt;
	sparseConcat{ nil, b, c, d }  =&amp;gt;  &amp;quot;bcd&amp;quot;&lt;br /&gt;
]]&lt;br /&gt;
function p.sparseConcat(t, sep, i, j)&lt;br /&gt;
	local list = {}&lt;br /&gt;
	&lt;br /&gt;
	local list_i = 0&lt;br /&gt;
	for _, v in p.sparseIpairs(t) do&lt;br /&gt;
		list_i = list_i + 1&lt;br /&gt;
		list[list_i] = v&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return table.concat(list, sep, i, j)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
-- Finds the length of an array, or of a quasi-array with keys such&lt;br /&gt;
-- as &amp;quot;data1&amp;quot;, &amp;quot;data2&amp;quot;, etc., using an exponential search algorithm. &lt;br /&gt;
-- It is similar to the operator #, but may return&lt;br /&gt;
-- a different value when there are gaps in the array portion of the table.&lt;br /&gt;
-- Intended to be used on data loaded with mw.loadData. For other tables, use #.&lt;br /&gt;
-- Note: #frame.args in frame object always be set to 0, regardless of &lt;br /&gt;
-- the number of unnamed template parameters, so use this function for&lt;br /&gt;
-- frame.args.&lt;br /&gt;
--]]&lt;br /&gt;
function p.length(t, prefix)&lt;br /&gt;
	-- requiring module inline so that [[Module:Exponential search]]&lt;br /&gt;
	-- which is only needed by this one function&lt;br /&gt;
	-- doesn't get millions of transclusions&lt;br /&gt;
	local expSearch = require(&amp;quot;Module:Exponential search&amp;quot;)&lt;br /&gt;
	checkType('length', 1, t, 'table')&lt;br /&gt;
	checkType('length', 2, prefix, 'string', true)&lt;br /&gt;
	return expSearch(function(i)&lt;br /&gt;
		local key&lt;br /&gt;
		if prefix then&lt;br /&gt;
			key = prefix .. tostring(i)&lt;br /&gt;
		else&lt;br /&gt;
			key = i&lt;br /&gt;
		end&lt;br /&gt;
		return t[key] ~= nil&lt;br /&gt;
	end) or 0&lt;br /&gt;
end&lt;br /&gt;
	&lt;br /&gt;
function p.inArray(arr, valueToFind)&lt;br /&gt;
	checkType(&amp;quot;inArray&amp;quot;, 1, arr, &amp;quot;table&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if valueToFind is nil, error?&lt;br /&gt;
	&lt;br /&gt;
	for _, v in ipairs(arr) do&lt;br /&gt;
		if v == valueToFind then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>كوبتيكبيديا&gt;طلال</name></author>
	</entry>
</feed>