<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ADump</id>
	<title>Module:Dump - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ADump"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Dump&amp;action=history"/>
	<updated>2026-05-28T10:34:12Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Dump&amp;diff=136018&amp;oldid=prev</id>
		<title>imported&gt;Johnuniq: args: need nowiki to show strip marker</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Dump&amp;diff=136018&amp;oldid=prev"/>
		<updated>2021-06-07T07:35:17Z</updated>

		<summary type="html">&lt;p&gt;args: need nowiki to show strip marker&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Dump a table to help develop other modules.&lt;br /&gt;
-- It is also possible to use mw.dumpObject() but the result from this&lt;br /&gt;
-- module is clearer and is close to valid Lua source.&lt;br /&gt;
-- The main purpose is to allow easy inspection of Wikidata items.&lt;br /&gt;
-- Preview the following in a sandbox to see entity Q833639 as a Lua table:&lt;br /&gt;
--   {{#invoke:dump|wikidata|Q833639}}&lt;br /&gt;
-- Preview the following to dump a built-in table:&lt;br /&gt;
--   {{#invoke:dump|testcase}}&lt;br /&gt;
&lt;br /&gt;
local Collection  -- a table to hold items&lt;br /&gt;
Collection = {&lt;br /&gt;
	add = function (self, item)&lt;br /&gt;
		if item ~= nil then&lt;br /&gt;
			self.n = self.n + 1&lt;br /&gt;
			self[self.n] = item&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
	join = function (self, sep)&lt;br /&gt;
		return table.concat(self, sep)&lt;br /&gt;
	end,&lt;br /&gt;
	remove = function (self, pos)&lt;br /&gt;
		if self.n &amp;gt; 0 and (pos == nil or (0 &amp;lt; pos and pos &amp;lt;= self.n)) then&lt;br /&gt;
			self.n = self.n - 1&lt;br /&gt;
			return table.remove(self, pos)&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
	sort = function (self, comp)&lt;br /&gt;
		table.sort(self, comp)&lt;br /&gt;
	end,&lt;br /&gt;
	new = function ()&lt;br /&gt;
		return setmetatable({n = 0}, Collection)&lt;br /&gt;
	end&lt;br /&gt;
}&lt;br /&gt;
Collection.__index = Collection&lt;br /&gt;
&lt;br /&gt;
local function pre_block(text)&lt;br /&gt;
	-- Pre tags returned by a module do not act like wikitext &amp;lt;pre&amp;gt;...&amp;lt;/pre&amp;gt;.&lt;br /&gt;
	return &amp;#039;&amp;lt;pre&amp;gt;\n&amp;#039; ..&lt;br /&gt;
		mw.text.nowiki(text) ..&lt;br /&gt;
		(text:sub(-1) == &amp;#039;\n&amp;#039; and &amp;#039;&amp;#039; or &amp;#039;\n&amp;#039;) ..&lt;br /&gt;
		&amp;#039;&amp;lt;/pre&amp;gt;\n&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function make_tabstr(indent)&lt;br /&gt;
	-- Return a string to generate one level of indent.&lt;br /&gt;
	if indent == &amp;#039;tab&amp;#039; then&lt;br /&gt;
		-- Tabs do not work well in a browser edit window, but can force them.&lt;br /&gt;
		return &amp;#039;\t&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	indent = tonumber(indent)&lt;br /&gt;
	if not (type(indent) == &amp;#039;number&amp;#039; and 1 &amp;lt;= indent and indent &amp;lt;= 32) then&lt;br /&gt;
		indent = 4&lt;br /&gt;
	end&lt;br /&gt;
	return string.rep(&amp;#039; &amp;#039;, indent)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _dumphtml(html, tabwidth)&lt;br /&gt;
	-- Return a pretty-text formatted dump of an html string.&lt;br /&gt;
	-- This assumes clean html, for example, tag &amp;quot;&amp;lt;table&amp;gt;&amp;quot; not &amp;quot;&amp;lt; table &amp;gt;&amp;quot;.&lt;br /&gt;
	if type(html) ~= &amp;#039;string&amp;#039; then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local selfClosingTags = {  -- from mw.html.lua&lt;br /&gt;
		area = true,&lt;br /&gt;
		base = true,&lt;br /&gt;
		br = true,&lt;br /&gt;
		col = true,&lt;br /&gt;
		command = true,&lt;br /&gt;
		embed = true,&lt;br /&gt;
		hr = true,&lt;br /&gt;
		img = true,&lt;br /&gt;
		input = true,&lt;br /&gt;
		keygen = true,&lt;br /&gt;
		link = true,&lt;br /&gt;
		meta = true,&lt;br /&gt;
		param = true,&lt;br /&gt;
		source = true,&lt;br /&gt;
		track = true,&lt;br /&gt;
		wbr = true,&lt;br /&gt;
	}&lt;br /&gt;
	local tabstr = make_tabstr(tabwidth)&lt;br /&gt;
	local function indent_pad(depth, isfirst)&lt;br /&gt;
		-- Return a string with an indent to match depth.&lt;br /&gt;
		if depth &amp;gt; 0 then&lt;br /&gt;
			return &amp;#039;\n&amp;#039; .. string.rep(tabstr, depth)&lt;br /&gt;
		end&lt;br /&gt;
		return isfirst and &amp;#039;&amp;#039; or &amp;#039;\n&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local function extract(result, html, pos, len, depth, currenttag)&lt;br /&gt;
		-- Dump more of html into table result and return new pos.&lt;br /&gt;
		local has_child&lt;br /&gt;
		while pos &amp;lt;= len do&lt;br /&gt;
			local s, e = html:find(&amp;#039;&amp;lt;[^&amp;lt;&amp;gt;]*&amp;gt;&amp;#039;, pos)&lt;br /&gt;
			if s then&lt;br /&gt;
				if s &amp;gt; pos then&lt;br /&gt;
					table.insert(result, html:sub(pos, s-1))&lt;br /&gt;
				end&lt;br /&gt;
				if html:sub(s+1, s+1) == &amp;#039;/&amp;#039; then&lt;br /&gt;
					-- A closing tag.&lt;br /&gt;
					local tag = html:match(&amp;#039;^([a-zA-Z0-9]+)&amp;gt;&amp;#039;, s+2) or &amp;#039;NOTAG&amp;#039;&lt;br /&gt;
					if tag == currenttag then&lt;br /&gt;
						local indent = has_child and indent_pad(depth - 1) or &amp;#039;&amp;#039;&lt;br /&gt;
						table.insert(result, indent .. &amp;#039;&amp;lt;/&amp;#039; .. tag .. &amp;#039;&amp;gt;&amp;#039;)&lt;br /&gt;
					else&lt;br /&gt;
						-- Should never happen.&lt;br /&gt;
						table.insert(result, &amp;#039;\n&amp;lt;/&amp;#039; .. tag .. &amp;#039;&amp;gt;&amp;#039;)&lt;br /&gt;
					end&lt;br /&gt;
					return e + 1&lt;br /&gt;
				end&lt;br /&gt;
				local tag = html:match(&amp;#039;^[a-zA-Z0-9]+&amp;#039;, s+1) or &amp;#039;NOTAG&amp;#039;&lt;br /&gt;
				if html:sub(e-1, e-1) == &amp;#039;/&amp;#039; or selfClosingTags[tag] then&lt;br /&gt;
					-- A self-closing tag.&lt;br /&gt;
					table.insert(result, html:sub(s, e))&lt;br /&gt;
					pos = e + 1&lt;br /&gt;
				else&lt;br /&gt;
					-- An opening tag.&lt;br /&gt;
					table.insert(result, indent_pad(depth, pos == 1) .. html:sub(s, e))&lt;br /&gt;
					pos = extract(result, html, e+1, len, depth+1, tag)&lt;br /&gt;
					has_child = true&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				table.insert(result, html:sub(pos))&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return len + 1&lt;br /&gt;
	end&lt;br /&gt;
	local result = {}&lt;br /&gt;
	html = html:gsub(&amp;#039;&amp;gt;%s+&amp;lt;&amp;#039;, &amp;#039;&amp;gt;&amp;lt;&amp;#039;):gsub(&amp;#039;\n%s*&amp;#039;, &amp;#039; &amp;#039;)&lt;br /&gt;
	extract(result, html, 1, #html, 0)&lt;br /&gt;
	return pre_block(table.concat(result))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dumphtml(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	local pargs = frame:getParent().args&lt;br /&gt;
	local text = args[1] or pargs[1]&lt;br /&gt;
	local indent = args.indent or pargs.indent&lt;br /&gt;
	return _dumphtml(text, indent)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function quoted(str)&lt;br /&gt;
	return (string.format(&amp;#039;%q&amp;#039;, str):gsub(&amp;#039;\\\n&amp;#039;, &amp;#039;\\n&amp;#039;))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function iterkeys(var, control)&lt;br /&gt;
	-- Return an iterator over the keys of var (which should be a table).&lt;br /&gt;
	-- The keys are sorted with numbered keys first, then other types.&lt;br /&gt;
	-- The iterator returns key, repr where key is the actual key, and&lt;br /&gt;
	-- repr is its representation: a number for the ipairs keys, or&lt;br /&gt;
	-- a string, including for number keys above the table length.&lt;br /&gt;
	if type(var) ~= &amp;#039;table&amp;#039; then&lt;br /&gt;
		return function () return nil end&lt;br /&gt;
	end&lt;br /&gt;
	local nums = {}&lt;br /&gt;
	local results = Collection.new()&lt;br /&gt;
	for i, _ in ipairs(var) do&lt;br /&gt;
		nums[i] = true&lt;br /&gt;
		results:add({ i, i })&lt;br /&gt;
	end&lt;br /&gt;
	local keys = Collection.new()&lt;br /&gt;
	for k, _ in pairs(var) do&lt;br /&gt;
		if not nums[k] then&lt;br /&gt;
			keys:add(k)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local autoname = control.autoname&lt;br /&gt;
	keys:sort(function (a, b)&lt;br /&gt;
			local ta, tb = type(a), type(b)&lt;br /&gt;
			if ta == tb then&lt;br /&gt;
				if ta == &amp;#039;number&amp;#039; or ta == &amp;#039;string&amp;#039; then&lt;br /&gt;
					return a &amp;lt; b&lt;br /&gt;
				end&lt;br /&gt;
				if ta == &amp;#039;boolean&amp;#039; then&lt;br /&gt;
					return b and not a&lt;br /&gt;
				end&lt;br /&gt;
				return autoname(a) &amp;lt; autoname(b)&lt;br /&gt;
			end&lt;br /&gt;
			if ta == &amp;#039;number&amp;#039; then&lt;br /&gt;
				return true&lt;br /&gt;
			elseif tb == &amp;#039;number&amp;#039; then&lt;br /&gt;
				return false&lt;br /&gt;
			else&lt;br /&gt;
				return ta &amp;lt; tb&lt;br /&gt;
			end&lt;br /&gt;
		end)&lt;br /&gt;
	for _, k in ipairs(keys) do&lt;br /&gt;
		local repr&lt;br /&gt;
		local tk = type(k)&lt;br /&gt;
		if tk == &amp;#039;number&amp;#039; then&lt;br /&gt;
			repr = &amp;#039;[&amp;#039; .. k .. &amp;#039;]&amp;#039;&lt;br /&gt;
		elseif tk == &amp;#039;string&amp;#039; then&lt;br /&gt;
			if k:match(&amp;#039;^[%a_][%w_]*$&amp;#039;) then&lt;br /&gt;
				repr = k&lt;br /&gt;
			else&lt;br /&gt;
				repr = &amp;#039;[&amp;#039; .. quoted(k) .. &amp;#039;]&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		elseif tk == &amp;#039;boolean&amp;#039; then&lt;br /&gt;
			repr = &amp;#039;[&amp;#039; .. tostring(k) .. &amp;#039;]&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			repr = autoname(k)&lt;br /&gt;
			control.needed[repr] = true&lt;br /&gt;
		end&lt;br /&gt;
		results:add({ k, repr })&lt;br /&gt;
	end&lt;br /&gt;
	local last = 0&lt;br /&gt;
	return function ()&lt;br /&gt;
		if last &amp;lt; results.n then&lt;br /&gt;
			last = last + 1&lt;br /&gt;
			return unpack(results[last])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function vardump(var, vname, depth, control, self, parents)&lt;br /&gt;
	-- Update items in control with results from dumping a variable.&lt;br /&gt;
	local function put(value, options)&lt;br /&gt;
		options = options or {}&lt;br /&gt;
		local indent = options.indent or depth&lt;br /&gt;
		local comma = (options.kind == &amp;#039;open&amp;#039; or indent == 0) and &amp;#039;&amp;#039; or &amp;#039;,&amp;#039;&lt;br /&gt;
		control.items:add({&lt;br /&gt;
			key = (type(vname) == &amp;#039;string&amp;#039; and options.kind ~= &amp;#039;close&amp;#039;) and vname or nil,&lt;br /&gt;
			value = value .. comma,&lt;br /&gt;
			depth = indent,&lt;br /&gt;
			note = options.note&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
	if var == nil then&lt;br /&gt;
		put(&amp;#039;nil&amp;#039;)&lt;br /&gt;
	elseif type(var) == &amp;#039;string&amp;#039; then&lt;br /&gt;
		put(quoted(var))&lt;br /&gt;
	elseif type(var) == &amp;#039;table&amp;#039; then&lt;br /&gt;
		local this = control.autoname(var)&lt;br /&gt;
		if depth &amp;gt;= control.limitdepth then&lt;br /&gt;
			put(this)&lt;br /&gt;
		elseif parents and parents[this] then&lt;br /&gt;
			control.needed[this] = true&lt;br /&gt;
			if self == this then&lt;br /&gt;
				put(this, {note = &amp;#039;self&amp;#039;})&lt;br /&gt;
				control.needed[&amp;#039;self&amp;#039;] = true&lt;br /&gt;
			else&lt;br /&gt;
				put(this, {note = &amp;#039;repeat&amp;#039;})&lt;br /&gt;
				control.needed[&amp;#039;repeat&amp;#039;] = true&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			parents = parents or {}&lt;br /&gt;
			parents[this] = true&lt;br /&gt;
			self = this&lt;br /&gt;
			put(&amp;#039;{&amp;#039;, {kind = &amp;#039;open&amp;#039;, note = this})&lt;br /&gt;
			local mt = getmetatable(var)&lt;br /&gt;
			if mt then&lt;br /&gt;
				vardump(mt, &amp;#039;__metatable&amp;#039;, depth + 1, control, self, parents)&lt;br /&gt;
			end&lt;br /&gt;
			local maxsize = control.items.n + control.limititems&lt;br /&gt;
			for key, keyrep in iterkeys(var, control) do&lt;br /&gt;
				if control.items.n &amp;gt; maxsize then&lt;br /&gt;
					put(&amp;#039;...more...&amp;#039;)&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
				vardump(var[key], keyrep, depth + 1, control, self, parents)&lt;br /&gt;
			end&lt;br /&gt;
			put(&amp;#039;}&amp;#039;, { kind = &amp;#039;close&amp;#039; })&lt;br /&gt;
		end&lt;br /&gt;
	elseif type(var) == &amp;#039;boolean&amp;#039; or type(var) == &amp;#039;number&amp;#039; then&lt;br /&gt;
		put(tostring(var))&lt;br /&gt;
	else  -- function (or userdata or thread)&lt;br /&gt;
		put(control.autoname(var))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dumper(var, vname, tabwidth, wantraw, limititems, limitdepth)&lt;br /&gt;
	-- Return a string representing var in almost-correct Lua syntax.&lt;br /&gt;
	-- There is no newline at the end of the result.&lt;br /&gt;
	local onames = {}&lt;br /&gt;
	local tcounts = {}&lt;br /&gt;
	local function autoname(var)&lt;br /&gt;
		-- Return a string that is a unique name for var, given it is not&lt;br /&gt;
		-- a number or string.&lt;br /&gt;
		if not onames[var] then&lt;br /&gt;
			local name = type(var)&lt;br /&gt;
			tcounts[name] = (tcounts[name] or 0) + 1&lt;br /&gt;
			onames[var] = name .. &amp;#039;_&amp;#039; .. tcounts[name]&lt;br /&gt;
		end&lt;br /&gt;
		return onames[var]&lt;br /&gt;
	end&lt;br /&gt;
	local control = {&lt;br /&gt;
		autoname = autoname,&lt;br /&gt;
		limititems = limititems or 10000,&lt;br /&gt;
		limitdepth = limitdepth or 50,&lt;br /&gt;
		items = Collection.new(),&lt;br /&gt;
		needed = {},&lt;br /&gt;
	}&lt;br /&gt;
	vardump(var, tostring(vname or &amp;#039;variable&amp;#039;), 0, control)&lt;br /&gt;
	local tabstr = make_tabstr(tabwidth)&lt;br /&gt;
	local lines = Collection.new()&lt;br /&gt;
	for i, v in ipairs(control.items) do&lt;br /&gt;
		local indent = string.rep(tabstr, v.depth)&lt;br /&gt;
		local note = v.note&lt;br /&gt;
		if note and control.needed[note] then&lt;br /&gt;
			note = &amp;#039;  -- &amp;#039; .. note&lt;br /&gt;
		else&lt;br /&gt;
			note = &amp;#039;&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		local k = v.key and (v.key .. &amp;#039; = &amp;#039;) or &amp;#039;&amp;#039;&lt;br /&gt;
		lines:add(indent .. k .. v.value .. note)&lt;br /&gt;
	end&lt;br /&gt;
	local raw = lines:join(&amp;#039;\n&amp;#039;)&lt;br /&gt;
	return wantraw and raw or pre_block(raw)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dump_testcase(frame)&lt;br /&gt;
	local item&lt;br /&gt;
	if type(frame) == &amp;#039;table&amp;#039; then&lt;br /&gt;
		item = frame.args[1]&lt;br /&gt;
	else&lt;br /&gt;
		item = frame&lt;br /&gt;
	end&lt;br /&gt;
	if item == &amp;#039;G&amp;#039; or item == &amp;#039;_G&amp;#039; then&lt;br /&gt;
		return dumper(_G, &amp;#039;_G&amp;#039;, frame.args.indent)&lt;br /&gt;
	end&lt;br /&gt;
	local fruit = { &amp;#039;apple&amp;#039;, &amp;#039;banana&amp;#039;, [0] = &amp;#039;zero&amp;#039;, [{&amp;#039;anon&amp;#039;}] = &amp;#039;anon&amp;#039; }&lt;br /&gt;
	local testcase = {&lt;br /&gt;
		[100] = &amp;#039;one hundred&amp;#039;,&lt;br /&gt;
		[99] = &amp;#039;ninety nine&amp;#039;,&lt;br /&gt;
		[0.5] = &amp;#039;one half&amp;#039;,&lt;br /&gt;
		[-1] = &amp;#039;negative one&amp;#039;,&lt;br /&gt;
		&amp;#039;one&amp;#039;,&lt;br /&gt;
		&amp;#039;two&amp;#039;,&lt;br /&gt;
		[&amp;#039; &amp;#039;] = &amp;#039;space&amp;#039;,&lt;br /&gt;
		[&amp;#039;1 –◆— z&amp;#039;] = &amp;#039;unicode&amp;#039;,&lt;br /&gt;
		alpha = &amp;#039;aaa&amp;#039;,&lt;br /&gt;
		beta = &amp;#039;bbb&amp;#039;,&lt;br /&gt;
		c = 123,&lt;br /&gt;
		data = {&lt;br /&gt;
			dumper = dumper,&lt;br /&gt;
			[dumper] = &amp;#039;dumper&amp;#039;,&lt;br /&gt;
			&amp;#039;three&amp;#039;,&lt;br /&gt;
			&amp;#039;four&amp;#039;,&lt;br /&gt;
			T = true,&lt;br /&gt;
			[true] = &amp;#039;T&amp;#039;,&lt;br /&gt;
			alpha2 = &amp;#039;aaa2&amp;#039;,&lt;br /&gt;
			beta2 = &amp;#039;bbb2&amp;#039;,&lt;br /&gt;
			F = false,&lt;br /&gt;
			[false] = &amp;#039;F&amp;#039;,&lt;br /&gt;
			c2 = 1234,&lt;br /&gt;
			data2 = {&lt;br /&gt;
				&amp;#039;five&amp;#039;,&lt;br /&gt;
				&amp;#039;six&amp;#039;,&lt;br /&gt;
				alpha3 = &amp;#039;aaa3&amp;#039;,&lt;br /&gt;
				beta3 = &amp;#039;bbb3&amp;#039;,&lt;br /&gt;
				c3 = 12345,&lt;br /&gt;
				fruit = fruit,&lt;br /&gt;
				[fruit] = &amp;#039;fruit&amp;#039;,&lt;br /&gt;
			},&lt;br /&gt;
		},&lt;br /&gt;
		z = &amp;#039;zoo&amp;#039;,&lt;br /&gt;
	}&lt;br /&gt;
	testcase.testcase = testcase&lt;br /&gt;
	testcase.data.me = testcase.data&lt;br /&gt;
	testcase.data.data2.me = testcase&lt;br /&gt;
	testcase.data.data2.fruit.back = testcase.data&lt;br /&gt;
	setmetatable(testcase.data, {&lt;br /&gt;
		__index = function (self, key) return type(key) == &amp;#039;string&amp;#039; and #key or nil end,&lt;br /&gt;
		__tostring = function (self) return tostring(#self) end,&lt;br /&gt;
	})&lt;br /&gt;
	if item == &amp;#039;return table&amp;#039; then&lt;br /&gt;
		return testcase&lt;br /&gt;
	end&lt;br /&gt;
	return dumper(testcase, &amp;#039;testcase&amp;#039;, frame.args.indent)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function execute(frame)&lt;br /&gt;
	-- Return a dump of the result from executing {{#invoke:dump|execute|EXPRESSION}}.&lt;br /&gt;
	-- In general that is not possible in Scribunto so this has built-in code&lt;br /&gt;
	-- to parse some expressions of interest.&lt;br /&gt;
	-- The primary aim is to test the result of calling a Wikidata function&lt;br /&gt;
	-- while previewing an edit in an article.&lt;br /&gt;
	-- Examples of EXPRESSION:&lt;br /&gt;
	--   mw.wikibase.getEntityIdForCurrentPage()&lt;br /&gt;
	--   mw.wikibase.getBestStatements(&amp;#039;Q868&amp;#039;, &amp;#039;P214&amp;#039;)&lt;br /&gt;
	--   mw.wikibase.getBestStatements(Q868, P214)       -- also accepted&lt;br /&gt;
	--   mw.wikibase.getEntity():getDescription(&amp;#039;de&amp;#039;)&lt;br /&gt;
	--   mw.wikibase.getEntity(&amp;#039;Q868&amp;#039;):getDescription(&amp;#039;de&amp;#039;)&lt;br /&gt;
	-- getEntityObject is an alias for getEntity.&lt;br /&gt;
	-- Using the following gives an &amp;quot;out of memory&amp;quot; error presumably because&lt;br /&gt;
	-- the result is a table with a metatable that dump repeatedly expands.&lt;br /&gt;
	--   mw.title.getCurrentTitle()&lt;br /&gt;
	local function params(ptext, first)&lt;br /&gt;
		local p = { first }&lt;br /&gt;
		for item in (ptext .. &amp;#039;,&amp;#039;):gmatch(&amp;#039;(%S.-)%s*,&amp;#039;) do&lt;br /&gt;
			-- Remove any quotes around each parameter because it is already a string.&lt;br /&gt;
			local _, s = item:match([[^%s*([&amp;#039;&amp;quot;])(.*)%1%s*$]])&lt;br /&gt;
			table.insert(p, s or tonumber(item) or item)&lt;br /&gt;
		end&lt;br /&gt;
		return unpack(p)&lt;br /&gt;
	end&lt;br /&gt;
	local expression = frame.args[1] or &amp;#039;&amp;#039;&lt;br /&gt;
	local text = expression:match(&amp;#039;^%s*mw(%..-)%s*$&amp;#039;)&lt;br /&gt;
	if not text then&lt;br /&gt;
		return &amp;#039;Expression not recognized: &amp;quot;&amp;#039; .. expression .. &amp;#039;&amp;quot;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	-- Look for a supported expression of form &amp;#039;mw.a.b(c):d.e(f)&amp;#039;.&lt;br /&gt;
	local entity&lt;br /&gt;
	local object = mw&lt;br /&gt;
	local item, ptext, rest = text:match(&amp;#039;^%.wikibase%.(%w+)%s*%((.*)%):(.*)$&amp;#039;)&lt;br /&gt;
	if item == &amp;#039;getEntity&amp;#039; or item == &amp;#039;getEntityObject&amp;#039; then&lt;br /&gt;
		entity = mw.wikibase.getEntity(params(ptext))&lt;br /&gt;
		if not entity then&lt;br /&gt;
			return &amp;#039;No entity found for (&amp;#039; .. ptext .. &amp;#039;)&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		object = entity&lt;br /&gt;
		text = &amp;#039;.&amp;#039; .. rest  -- treat &amp;#039;:&amp;#039; as &amp;#039;.&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local upto = 1&lt;br /&gt;
	for i1, item, i2 in text:gmatch(&amp;#039;()%.(%w+)()&amp;#039;) do&lt;br /&gt;
		if i1 == upto and type(object) == &amp;#039;table&amp;#039; then&lt;br /&gt;
			object = object[item]&lt;br /&gt;
		else&lt;br /&gt;
			object = nil&lt;br /&gt;
		end&lt;br /&gt;
		if object == nil then&lt;br /&gt;
			return &amp;#039;Invalid item &amp;quot;&amp;#039; .. item .. &amp;#039;&amp;quot;&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		if type(object) == &amp;#039;function&amp;#039; then&lt;br /&gt;
			if text:sub(i2, i2 + 1) == &amp;#039;()&amp;#039; then&lt;br /&gt;
				object = object()&lt;br /&gt;
				i2 = i2 + 2&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		upto = i2&lt;br /&gt;
	end&lt;br /&gt;
	local parm = text:sub(upto):match(&amp;#039;^%((.*)%)%s*$&amp;#039;)&lt;br /&gt;
	if parm then&lt;br /&gt;
		object = object(params(parm, entity))&lt;br /&gt;
	end&lt;br /&gt;
	return dumper(object, expression)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dumpargs(frame)&lt;br /&gt;
	-- Return text dump of frame.args.&lt;br /&gt;
	-- {{#invoke:dump|args|&amp;lt;ref&amp;gt;Example&amp;lt;/ref&amp;gt;}} → display ref strip marker&lt;br /&gt;
	local control = {&lt;br /&gt;
		autoname = function (var) return tostring(var) end,  -- should not be called since keys should be numbers or strings&lt;br /&gt;
	}&lt;br /&gt;
	local lines = Collection.new()&lt;br /&gt;
	for key, keyrep in iterkeys(frame.args, control) do&lt;br /&gt;
		lines:add(keyrep .. &amp;#039; = &amp;lt;code&amp;gt;&amp;#039; .. mw.text.nowiki(frame.args[key]) .. &amp;#039;&amp;lt;/code&amp;gt;&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return lines:join(&amp;#039;&amp;lt;br&amp;gt;\n&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function parameters(frame)&lt;br /&gt;
	-- Return text dump of args and parent args from frame.&lt;br /&gt;
	-- This is for debugging a module to show what parameters it received.&lt;br /&gt;
	local control = {&lt;br /&gt;
		autoname = function (var) return tostring(var) end,  -- should not be called since keys should be numbers or strings&lt;br /&gt;
	}&lt;br /&gt;
	local lines = Collection.new()&lt;br /&gt;
	lines:add(&amp;#039;&amp;#039;)&lt;br /&gt;
	for _, f in ipairs({ frame, frame:getParent() }) do&lt;br /&gt;
		lines:add(&amp;#039;[[&amp;#039; .. f:getTitle() .. &amp;#039;]]&amp;#039;)&lt;br /&gt;
		for key, keyrep in iterkeys(f.args, control) do&lt;br /&gt;
			lines:add(&amp;#039;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#039; .. mw.text.nowiki(keyrep .. &amp;#039;=&amp;#039; .. f.args[key]))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	lines:add(&amp;#039;&amp;#039;)&lt;br /&gt;
	return lines:join(&amp;#039;&amp;lt;br&amp;gt;\n&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function wikidata(frame)&lt;br /&gt;
	local item = frame.args[1]&lt;br /&gt;
	if item then&lt;br /&gt;
		local id = item:match(&amp;#039;^%s*([PQ]%d+)%s*$&amp;#039;)&lt;br /&gt;
		if id then&lt;br /&gt;
			local entity = mw.wikibase.getEntity(id)&lt;br /&gt;
			return dumper(entity, id, frame.args.indent)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;Parameter should be a Wikidata identifier such as P2386 or Q833639&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local builtins = {&lt;br /&gt;
	-- Handle preview of wikitext like {{#invoke|dump|TEXT}}&lt;br /&gt;
	-- where TEXT is a built-in value that can be dumped.&lt;br /&gt;
	__index = function (self, key)&lt;br /&gt;
		local result&lt;br /&gt;
		local function caller()&lt;br /&gt;
			return result&lt;br /&gt;
		end&lt;br /&gt;
		if type(key) == &amp;#039;string&amp;#039; then&lt;br /&gt;
			local title = key:match(&amp;#039;^%s*[\&amp;#039;&amp;quot;]?(.*%.tab)[\&amp;#039;&amp;quot;]?%s*$&amp;#039;)&lt;br /&gt;
			if title then&lt;br /&gt;
				-- Assume structured data from Commons at [[c:Data:&amp;lt;title&amp;gt;]].&lt;br /&gt;
				if title:match(&amp;#039;^[Dd]ata:&amp;#039;) then&lt;br /&gt;
					title = title:sub(6)&lt;br /&gt;
				end&lt;br /&gt;
				local data = mw.ext.data.get(title)  -- false if page does not exist&lt;br /&gt;
				result = dumper(data, &amp;#039;[[c:Data:&amp;#039; .. title .. &amp;#039;]]&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		result = result or (&amp;#039;UNKNOWN: &amp;#039; .. tostring(key))&lt;br /&gt;
		return caller&lt;br /&gt;
	end&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
return setmetatable({&lt;br /&gt;
	args = dumpargs,&lt;br /&gt;
	_dump = dumper,&lt;br /&gt;
	_dumphtml = _dumphtml,&lt;br /&gt;
	dumphtml = dumphtml,&lt;br /&gt;
	execute = execute,&lt;br /&gt;
	parameters = parameters,&lt;br /&gt;
	testcase = dump_testcase,&lt;br /&gt;
	wikidata = wikidata,&lt;br /&gt;
}, builtins)&lt;/div&gt;</summary>
		<author><name>imported&gt;Johnuniq</name></author>
	</entry>
</feed>