From Wikipedia, the free encyclopedia

	---                                        ---

	---     LOCAL ENVIRONMENT                  ---

	---    ________________________________    ---

	---                                        ---







	--[[ Abstract utilities ]]--

	----------------------------





-- Helper function for `string.gsub()` (for managing zero-padded numbers)

function zero_padded(str)

	return ("%03d%s"):format(#str, str)

end





-- Helper function for `table.sort()` (for natural sorting)

function natural_sort(var1, var2)

	return tostring(var1):gsub("%d+", zero_padded) <

		tostring(var2):gsub("%d+", zero_padded)

end





-- Return a copy or a reference to a table

local function copy_or_ref_table(src, refonly)

	if refonly then return src end

	newtab = {}

	for key, val in pairs(src) do newtabkey = val end

	return newtab

end





-- Remove numerical elements from a table, shifting everything to the left

function remove_numerical_keys(tbl, idx, len)

	local cache = {}

	local tmp = idx + len - 1

	for key, val in pairs(tbl) do

		if type(key) == 'number' and key >= idx then

			if key > tmp then cachekey - len = val end

			tblkey = nil

		end

	end

	for key, val in pairs(cache) do tblkey = val end

end





-- Make a reduced copy of a table (shifting in both directions if necessary)

function copy_table_reduced(tbl, idx, len)

	local ret = {}

	local tmp = idx + len - 1

	if idx > 0 then

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key < idx then

				retkey = val

			elseif key > tmp then retkey - len = val end

		end

	elseif tmp > 0 then

		local nshift = 1 - idx

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' then retkey = val

			elseif key > tmp then retkey - tmp = val

			elseif key < idx then retkey + nshift = val end

		end

	else

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key > tmp then

				retkey = val

			elseif key < idx then retkey + len = val end

		end

	end

	return ret

end





-- Make an expanded copy of a table (shifting in both directions if necessary)

function copy_table_expanded(tbl, idx, len)

	local ret = {}

	local tmp = idx + len - 1

	if idx > 0 then

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key < idx then

				retkey = val

			else retkey + len = val end

		end

	elseif tmp > 0 then

		local nshift = idx - 1

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' then retkey = val

			elseif key > 0 then retkey + tmp = val

			elseif key < 1 then retkey + nshift = val end

		end

	else

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key > tmp then

				retkey = val

			else retkey - len = val end

		end

	end

	return ret

end





-- Move a key from a table to another, but only if under a different name and

-- always parsing numerical strings as numbers

function steal_if_renamed(val, src, skey, dest, dkey)

	local realkey = tonumber(dkey) or dkey:match'^%s*(.-)%s*$'

	if skey ~= realkey then

		destrealkey = val

		srcskey = nil

	end

end







	--[[ Public strings ]]--

	------------------------





-- Special match keywords (functions and modifiers MUST avoid these names)

local mkeywords = {

	'or' = 0,

	--pattern = 1, -- Simply uncommenting enables the option

	plain = 2,

	strict = 3

}





-- Sort functions (functions and modifiers MUST avoid these names)

local sortfunctions = {

	--alphabetically = false, -- Simply uncommenting enables the option

	naturally = natural_sort

}





-- Callback styles for the `mapping_*` and `renaming_*` class of modifiers

-- (functions and modifiers MUST avoid these names)

--[[



Meanings of the columns:



  col[1] = Loop type (0-3)

  col[2] = Number of module arguments that the style requires (1-3)

  col[3] = Minimum number of sequential parameters passed to the callback

  col[4] = Name of the callback parameter where to place each parameter name

  col[5] = Name of the callback parameter where to place each parameter value

  col[6] = Argument in the modifier's invocation that will override `col[4]`

  col[7] = Argument in the modifier's invocation that will override `col[5]`



A value of `-1` indicates that no meaningful value is stored (i.e. `nil`)



]]--

local mapping_styles = {

	names_and_values = { 3, 2, 2, 1, 2, -1, -1 },

	values_and_names = { 3, 2, 2, 2, 1, -1, -1 },

	values_only = { 1, 2, 1, -1, 1, -1, -1 },

	names_only = { 2, 2, 1, 1, -1, -1, -1 },

	names_and_values_as = { 3, 4, 0, -1, -1, 2, 3 },

	names_only_as = { 2, 3, 0, -1, -1, 2, -1 },

	values_only_as = { 1, 3, 0, -1, -1, -1, 2 },

	blindly = { 0, 2, 0, -1, -1, -1, -1 }

}





-- Memory slots (functions and modifiers MUST avoid these names)

local memoryslots = {

	i = 'itersep',

	l = 'lastsep',

	p = 'pairsep',

	h = 'header',

	f = 'footer',

	n = 'ifngiven'

}





-- Functions and modifiers MUST avoid these names too: `let`







	--[[ Module's private environment ]]--

	--------------------------------------





-- Maximum number of numerical parameters that can be filled, if missing (we

-- chose an arbitrary number for this constant; you can discuss about its

-- optimal value at Module talk:Params)

local maxfill = 1024





-- The private table of functions

local library = {}





-- Functions that can only be invoked in first position

local static_iface = {}





-- Create a new context

local function context_new()

	local ctx = {}

	ctx.luaname = 'Module:Params'	--[[ or `frame:getTitle()` ]]--

	ctx.iterfunc = pairs

	ctx.firstposonly = static_iface

	ctx.n_available = maxfill

	return ctx

end





-- Move to the next action within the user-given list

local function context_iterate(ctx, n_forward)

	local nextfn

	if ctx.pipen_forward ~= nil then

		nextfn = ctx.pipen_forward]:match'^%s*(.*%S)'

	end

	if nextfn == nil then error(ctx.luaname ..

		': You must specify a function to call', 0) end

	if librarynextfn == nil then

		if ctx.firstposonlynextfn == nil then error(ctx.luaname ..

			': The function ‘' .. nextfn .. '’ does not exist', 0)

		else error(ctx.luaname .. ': The ‘' .. nextfn ..

			'’ directive can only appear in first position', 0)

		end

	end

	remove_numerical_keys(ctx.pipe, 1, n_forward)

	return librarynextfn

end





-- Main loop

local function main_loop(ctx, start_with)

	local fn = start_with

	repeat fn = fn(ctx) until not fn

end





-- Parse the arguments of the `mapping_*` and `renaming_*` class of modifiers

function parse_child_args(dest, src, n_skip, default_style)

	local style

	local shf

	local tmp = srcn_skip + 1

	if tmp ~= nil then style = mapping_stylestmp:match'^%s*(.-)%s*$' end

	if style == nil then

		style = default_style

		shf = n_skip - 1

	else shf = n_skip end

	local names

	local nargs

	local pin = style2 + shf

	local n_exist = style3

	local karg = style4

	local varg = style5

	tmp = style6

	if tmp > -1 then

		tmp = srctmp + shf

		karg = tonumber(tmp)

		if karg == nil then karg = tmp:match'^%s*(.-)%s*$'

		else n_exist = math.max(n_exist, karg) end

	end

	tmp = style7

	if tmp > -1 then

		tmp = srctmp + shf

		varg = tonumber(tmp)

		if varg == nil then varg = tmp:match'^%s*(.-)%s*$'

		else n_exist = math.max(n_exist, varg) end

	end

	if srcpin ~= nil and srcpin]:match'^%s*let%s*$' then

		names = {}

		repeat

			tmp = srcpin + 1 or ''

			namestonumber(tmp) or tmp:match'^%s*(.-)%s*$' or '' =

				srcpin + 2

			pin = pin + 3

		until srcpin == nil or not srcpin]:match'^%s*let%s*$'

	end

	tmp = tonumber(srcpin])

	if tmp ~= nil then

		if tmp < 0 then tmp = -1 end

		shf = n_exist - pin

		for idx = pin + 1, pin + tmp do destidx + shf = srcidx end

		nargs = pin + tmp + 1

	else nargs = pin end

	if names ~= nil then

		for key, val in pairs(names) do destkey = val end

	end

	tmp = style1

	if (tmp == 3 or tmp == 2) and destkarg ~= nil then

		tmp = tmp - 2 end

	if (tmp == 3 or tmp == 1) and destvarg ~= nil then

		tmp = tmp - 1 end

	return nargs, tmp, karg, varg

end





-- Parse the arguments of the `with_*_matching` class of modifiers

local function parse_pattern_args(ctx, ptns, fname)

	local state = 0

	local cnt = 1

	local keyw

	local nptns = 0

	for _, val in ipairs(ctx.pipe) do

		if state == 0 then

			nptns = nptns + 1

			ptnsnptns = { val, false, false }

			state = -1

		else

			keyw = val:match'^%s*(.*%S)'

			if keyw == nil or mkeywordskeyw == nil or (

				state > 0 and mkeywordskeyw > 0

			) then break

			else

				state = mkeywordskeyw

				if state > 1 then ptnsnptns][2 = true end

				if state == 3 then ptnsnptns][3 = true end

			end

		end

		cnt = cnt + 1

	end

	if state == 0 then error(ctx.luaname .. ', ‘' .. fname ..

		'’: No pattern was given', 0) end

	return cnt

end





-- Map parameters' values using a custom callback and a referenced table

function map_values(tbl, margs, karg, varg, looptype, fn)

	if looptype == 1 then

		for key, val in pairs(tbl) do

			margsvarg = val

			tblkey = fn()

		end

	elseif looptype == 3 then

		for key, val in pairs(tbl) do

			margskarg = key

			margsvarg = val

			tblkey = fn()

		end

	elseif looptype == 2 then

		for key in pairs(tbl) do

			margskarg = key

			tblkey = fn()

		end

	elseif looptype == 0 then

		for key in pairs(tbl) do

			tblkey = fn()

		end

	end

end





-- Map parameters' names using a custom callback and a referenced table

function map_names(tbl, rargs, karg, varg, looptype, fn)

	local cache = {}

	if looptype == 2 then

		for key, val in pairs(tbl) do

			rargskarg = key

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	elseif looptype == 3 then

		for key, val in pairs(tbl) do

			rargskarg = key

			rargsvarg = val

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	elseif looptype == 1 then

		for key, val in pairs(tbl) do

			rargsvarg = val

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	elseif looptype == 0 then

		for key, val in pairs(tbl) do

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	end

	for key, val in pairs(cache) do tblkey = val end

end





-- Concatenate the numerical keys from the table of parameters to the numerical

-- keys from the table of options; non-numerical keys from the table of options

-- will prevail over colliding non-numerical keys from the table of parameters

local function concat_params(ctx)

	local tbl = ctx.params

	local size = table.maxn(ctx.pipe)

	local retval = {}

	if ctx.subset == 1 then

		-- We need only the sequence

		for key, val in ipairs(tbl) do retvalkey + size = val end

	else

		if ctx.subset == -1 then

			for key, val in ipairs(tbl) do tblkey = nil end

		end

		for key, val in pairs(tbl) do

			if type(key) == 'number' then retvalkey + size = val

			else retvalkey = val end

		end

	end

	for key, val in pairs(ctx.pipe) do retvalkey = val end

	return retval

end





-- Flush the parameters by calling a custom function for each value (after this

-- function has been invoked `ctx.params` will be no longer usable)

local function flush_params(ctx, fn)

	local tbl = ctx.params

	if ctx.subset == 1 then

		for key, val in ipairs(tbl) do fn(key, val) end

		return

	end

	if ctx.subset == -1 then

		for key, val in ipairs(tbl) do tblkey = nil end

	end

	if ctx.dosort then

		local nums = {}

		local words = {}

		local nlen = 0

		local wlen = 0

		for key, val in pairs(tbl) do

			if type(key) == 'number' then

				nlen = nlen + 1

				numsnlen = key

			else

				wlen = wlen + 1

				wordswlen = key

			end

		end

		table.sort(nums)

		table.sort(words, natural_sort)

		for idx = 1, nlen do fn(numsidx], tblnumsidx]]) end

		for idx = 1, wlen do fn(wordsidx], tblwordsidx]]) end

		return

	end

	if ctx.subset ~= -1 then

		for key, val in ipairs(tbl) do

			fn(key, val)

			tblkey = nil

		end

	end

	for key, val in pairs(tbl) do fn(key, val) end

end







	--[[ Modifiers ]]--

	-----------------------------





-- Syntax:  #invoke:params|sequential|pipe to

library.sequential = function(ctx)

	if ctx.subset == -1 then error(ctx.luaname ..

		': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end

	if ctx.dosort then error(ctx.luaname ..

		': The ‘all_sorted’ directive is redundant when followed by ‘sequential’', 0) end

	ctx.iterfunc = ipairs

	ctx.subset = 1

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|non-sequential|pipe to

library'non-sequential' = function(ctx)

	if ctx.subset == 1 then error(ctx.luaname ..

		': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end

	ctx.iterfunc = pairs

	ctx.subset = -1

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|sort|pipe to

library.all_sorted = function(ctx)

	if ctx.subset == 1 then error(ctx.luaname ..

		': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end

	ctx.dosort = true

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|setting|directives|...|pipe to

library.setting = function(ctx)

	local opts = ctx.pipe

	local cmd = opts1

	if cmd ~= nil then

		cmd = cmd:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'

	end

	if cmd == nil then error(ctx.luaname ..

		', ‘setting’: No directive was given', 0) end

	local sep = string.byte('/')

	local argc = 2

	local dest = {}

	local vname

	local chr

	for idx = 1, #cmd do

		chr = cmd:byte(idx)

		if chr == sep then

			for key, val in ipairs(dest) do

				ctxval = optsargc

				destkey = nil

			end

			argc = argc + 1

		else

			vname = memoryslotsstring.char(chr)]

			if vname == nil then error(ctx.luaname ..

				', ‘setting’: Unknown slot "' ..

				string.char(chr) .. '"', 0) end

			table.insert(dest, vname)

		end

	end

	for key, val in ipairs(dest) do ctxval = optsargc end

	return context_iterate(ctx, argc + 1)

end





-- Syntax:  #invoke:params|squeezing|pipe to

library.squeezing = function(ctx)

	local tbl = ctx.params

	local store = {}

	local indices = {}

	local newlen = 0

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			newlen = newlen + 1

			indicesnewlen = key

			storekey = val

			tblkey = nil

		end

	end

	table.sort(indices)

	for idx = 1, newlen do tblidx = storeindicesidx]] end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|filling_the_gaps|pipe to

library.filling_the_gaps = function(ctx)

	local tbl = ctx.params

	local nmin = 1

	local nmax = nil

	local nnums = -1

	local tmp = {}

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			if nmax == nil then

				if key < nmin then nmin = key end

				nmax = key

			elseif key > nmax then nmax = key

			elseif key < nmin then nmin = key end

			nnums = nnums + 1

			tmpkey = val

		end

	end

	if nmax ~= nil and nmax - nmin > nnums then

		ctx.n_available = ctx.n_available + nmin + nnums - nmax

		if ctx.n_available < 0 then error(ctx.luaname ..

			', ‘filling_the_gaps’: It is possible to fill at most ' ..

			tostring(maxfill) .. ' parameters', 0) end

		for idx = nmin, nmax, 1 do tblidx = '' end

		for key, val in pairs(tmp) do tblkey = val end

	end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|clearing|pipe to

library.clearing = function(ctx)

	local tbl = ctx.params

	local numericals = {}

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericalskey = val

			tblkey = nil

		end

	end

	for key, val in ipairs(numericals) do tblkey = val end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|cutting|left cut|right cut|pipe to

library.cutting = function(ctx)

	local lcut = tonumber(ctx.pipe1])

	if lcut == nil then error(ctx.luaname ..

		', ‘cutting’: Left cut must be a number', 0) end

	local rcut = tonumber(ctx.pipe2])

	if rcut == nil then error(ctx.luaname ..

		', ‘cutting’: Right cut must be a number', 0) end

	local tbl = ctx.params

	local len = #tbl

	if lcut < 0 then lcut = len + lcut end

	if rcut < 0 then rcut = len + rcut end

	local tot = lcut + rcut

	if tot > 0 then

		local cache = {}

		if tot >= len then

			for key in ipairs(tbl) do tblkey = nil end

			tot = len

		else

			for idx = len - rcut + 1, len, 1 do tblidx = nil end

			for idx = 1, lcut, 1 do tblidx = nil end

		end

		for key, val in pairs(tbl) do

			if type(key) == 'number' and key > 0 then

				if key > len then cachekey - tot = val

				else cachekey - lcut = val end

				tblkey = nil

			end

		end

		for key, val in pairs(cache) do tblkey = val end

	end

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|cropping|left crop|right crop|pipe to

library.cropping = function(ctx)

	local lcut = tonumber(ctx.pipe1])

	if lcut == nil then error(ctx.luaname ..

		', ‘cropping’: Left crop must be a number', 0) end

	local rcut = tonumber(ctx.pipe2])

	if rcut == nil then error(ctx.luaname ..

		', ‘cropping’: Right crop must be a number', 0) end

	local tbl = ctx.params

	local nmin

	local nmax

	for key in pairs(tbl) do

		if type(key) == 'number' then

			if nmin == nil then

				nmin = key

				nmax = key

			elseif key > nmax then nmax = key

			elseif key < nmin then nmin = key end

		end

	end

	if nmin ~= nil then

		local len = nmax - nmin + 1

		if lcut < 0 then lcut = len + lcut end

		if rcut < 0 then rcut = len + rcut end

		if lcut + rcut - len > -1 then

			for key in pairs(tbl) do

				if type(key) == 'number' then tblkey = nil end

			end

		elseif lcut + rcut > 0 then

			for idx = nmax - rcut + 1, nmax do tblidx = nil end

			for idx = nmin, nmin + lcut - 1 do tblidx = nil end

			local lshift = nmin + lcut - 1

			if lshift > 0 then

				for idx = lshift + 1, nmax, 1 do

					tblidx - lshift = tblidx

					tblidx = nil

				end

			end

		end

	end

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|purging|start offset|length|pipe to

library.purging = function(ctx)

	local idx = tonumber(ctx.pipe1])

	if idx == nil then error(ctx.luaname ..

		', ‘purging’: Start offset must be a number', 0) end

	local len = tonumber(ctx.pipe2])

	if len == nil then error(ctx.luaname ..

		', ‘purging’: Length must be a number', 0) end

	local tbl = ctx.params

	if len < 1 then

		len = len + table.maxn(tbl)

		if idx > len then return context_iterate(ctx, 3) end

		len = len - idx + 1

	end

	ctx.params = copy_table_reduced(tbl, idx, len)

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|backpurging|start offset|length|pipe to

library.backpurging = function(ctx)

	local last = tonumber(ctx.pipe1])

	if last == nil then error(ctx.luaname ..

		', ‘backpurging’: Start offset must be a number', 0) end

	local len = tonumber(ctx.pipe2])

	if len == nil then error(ctx.luaname ..

		', ‘backpurging’: Length must be a number', 0) end

	local idx

	local tbl = ctx.params

	if len > 0 then

		idx = last - len + 1

	else

		for key in pairs(tbl) do

			if type(key) == 'number' and (idx == nil or

				key < idx) then idx = key end

		end

		if idx == nil then return context_iterate(ctx, 3) end

		idx = idx - len

		if last < idx then return context_iterate(ctx, 3) end

		len = last - idx + 1

	end

	ctx.params = copy_table_reduced(ctx.params, idx, len)

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|rotating|pipe to

library.rotating = function(ctx)

	local tbl = ctx.params

	local numericals = {}

	local nmax = 0

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericalskey = val

			tblkey = nil

			if key > nmax then nmax = key end

		end

	end

	for key, val in pairs(numericals) do tblnmax - key + 1 = val end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|pivoting|pipe to

--[[

library.pivoting = function(ctx)

	local tbl = ctx.params

	local shift = #tbl + 1

	if shift < 2 then return library.rotating(ctx) end

	local numericals = {}

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericals[key] = val

			tbl[key] = nil

		end

	end

	for key, val in pairs(numericals) do tbl[shift - key] = val end

	return context_iterate(ctx, 1)

end

]]--





-- Syntax:  #invoke:params|mirroring|pipe to

--[[

library.mirroring = function(ctx)

	local tbl = ctx.params

	local numericals = {}

	local nmax

	local nmin

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericals[key] = val

			tbl[key] = nil

			if nmax == nil then

				nmax = key

				nmin = key

			elseif key > nmax then nmax = key

			elseif key < nmin then nmin = key end

		end

	end

	for key, val in pairs(numericals) do tbl[nmax + nmin - key] = val end

	return context_iterate(ctx, 1)

end

]]--





-- Syntax:  #invoke:params|swapping|pipe to

--[[

library.swapping = function(ctx)

	local tbl = ctx.params

	local cache = {}

	local nsize = 0

	local tmp

	for key in pairs(tbl) do

		if type(key) == 'number' then

			nsize = nsize + 1

			cache[nsize] = key

		end

	end

	table.sort(cache)

	for idx = math.floor(nsize / 2), 1, -1 do

		tmp = tbl[cache[idx] ]

		tbl[cache[idx] ] = tbl[cache[nsize - idx + 1] ]

		tbl[cache[nsize - idx + 1] ] = tmp

	end

	return context_iterate(ctx, 1)

end

]]--





-- Syntax:  #invoke:params|sorting_sequential_values|[criterion]|pipe to

library.sorting_sequential_values = function(ctx)

	local sortfn

	if ctx.pipe1 ~= nil then sortfn = sortfunctionsctx.pipe1]] end

	if sortfn then table.sort(ctx.params, sortfn)

	else table.sort(ctx.params) end -- i.e. either `false` or `nil`

	if sortfn == nil then return context_iterate(ctx, 1) end

	return context_iterate(ctx, 2)

end





-- Syntax:  #invoke:params|inserting|position|how many|...|pipe to

--[[

library.inserting = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable! As a modifier,

	-- this function MUST create a copy of it before returning

	local idx = tonumber(ctx.pipe[1])

	if idx == nil then error(ctx.luaname ..

		', ‘inserting’: Position must be a number', 0) end

	local len = tonumber(ctx.pipe[2])

	if len == nil or len < 1 then error(ctx.luaname ..

		', ‘inserting’: The amount must be a number greater than zero', 0) end

	local opts = ctx.pipe

	local tbl = copy_table_expanded(ctx.params, idx, len)

	for key = idx, idx + len - 1 do tbl[key] = opts[key - idx + 3] end

	ctx.params = tbl

	return context_iterate(ctx, len + 3)

end

]]--





-- Syntax:  #invoke:params|imposing|name|value|pipe to

library.imposing = function(ctx)

	if ctx.pipe1 == nil then error(ctx.luaname ..

		', ‘imposing’: Missing parameter name to impose', 0) end

	local key = ctx.pipe1]:match'^%s*(.-)%s*$'

	ctx.paramstonumber(key) or key = ctx.pipe2

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|discarding|name|[how many]|pipe to

library.discarding = function(ctx)

	if ctx.pipe1 == nil then error(ctx.luaname ..

		', ‘discarding’: Missing parameter name to discard', 0) end

	local key = ctx.pipe1

	local len = tonumber(ctx.pipe2])

	if len == nil then

		ctx.paramstonumber(key) or key:match'^%s*(.-)%s*$' = nil

		return context_iterate(ctx, 2)

	end

	key = tonumber(key)

	if key == nil then error(ctx.luaname ..

		', ‘discarding’: A range was provided, but the initial parameter name is not numerical', 0) end

	if len < 1 then error(ctx.luaname ..

		', ‘discarding’: A range can only be a number greater than zero', 0) end

	for idx = key, key + len - 1 do ctx.paramsidx = nil end

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or]

--            |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag

--            N]|pipe to

library.with_name_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns, 'with_name_matching')

	local nomatch

	for key in pairs(tbl) do

		nomatch = true

		for _, ptn in ipairs(patterns) do

			if not ptn3 then

				if string.find(key, ptn1], 1, ptn2]) then

					nomatch = false

					break

				end

			elseif key == ptn1 then

				nomatch = false

				break

			end

		end

		if nomatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|with_name_not_matching|pattern 1|[plain flag 1]

--            |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain

--            flag N]|pipe to

library.with_name_not_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns,

		'with_name_not_matching')

	local yesmatch

	for key in pairs(tbl) do

		yesmatch = true

		for _, ptn in ipairs(patterns) do

			if ptn3 then

				if key ~= ptn1 then

					yesmatch = false

					break

				end

			elseif not string.find(key, ptn1], 1, ptn2]) then

				yesmatch = false

				break

			end

		end

		if yesmatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or]

--            |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag

--            N]|pipe to

library.with_value_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns, 'with_value_matching')

	local nomatch

	for key, val in pairs(tbl) do

		nomatch = true

		for _, ptn in ipairs(patterns) do

			if ptn3 then

				if val == ptn1 then

					nomatch = false

					break

				end

			elseif string.find(val, ptn1], 1, ptn2]) then

				nomatch = false

				break

			end

		end

		if nomatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|with_value_not_matching|pattern 1|[plain flag 1]

--            |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain

--            flag N]|pipe to

library.with_value_not_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns,

		'with_value_not_matching')

	local yesmatch

	for key, val in pairs(tbl) do

		yesmatch = true

		for _, ptn in ipairs(patterns) do

			if ptn3 then

				if val ~= ptn1 then

					yesmatch = false

					break

				end

			elseif not string.find(val, ptn1], 1, ptn2]) then

				yesmatch = false

				break

			end

		end

		if yesmatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|trimming_values|pipe to

library.trimming_values = function(ctx)

	local tbl = ctx.params

	for key, val in pairs(tbl) do tblkey = val:match'^%s*(.-)%s*$' end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|mapping_by_calling|template name|[call

--            style]|[let]|[...][number of additional parameters]|[parameter

--            1]|[parameter 2]|[...]|[parameter N]|pipe to

library.mapping_by_calling = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘mapping_by_calling’: No template name was provided', 0) end

	local margs = {}

	local argc, looptype, karg, varg = parse_child_args(margs, opts, 1,

		mapping_styles.values_only)

	local model = { title = tname, args = margs }

	map_values(ctx.params, margs, karg, varg, looptype, function()

		return ctx.frame:expandTemplate(model)

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|mapping_by_invoking|module name|function

--            name|[call style]|[let]|[...]|[number of additional

--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to

library.mapping_by_invoking = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘mapping_by_invoking’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘mapping_by_invoking’: No function name was provided', 0) end

	local margs = {}

	local argc, looptype, karg, varg = parse_child_args(margs, opts, 2,

		mapping_styles.values_only)

	local model = { title = 'Module:' .. mname, args = margs }

	local mfunc = require(model.title)[fname

	if mfunc == nil then error(ctx.luaname ..

		', ‘mapping_by_invoking’: The function ‘' .. fname ..

		'’ does not exist', 0) end

	map_values(ctx.params, margs, karg, varg, looptype, function()

		return mfunc(ctx.frame:newChild(model))

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|mapping_by_magic|parser function|[call

--            style]|[let]|[...][number of additional arguments]|[argument

--            1]|[argument 2]|[...]|[argument N]|pipe to

library.mapping_by_magic = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘mapping_by_magic’: No parser function was provided', 0) end

	local margs = {}

	local argc, looptype, karg, varg = parse_child_args(margs, opts, 1,

		mapping_styles.values_only)

	map_values(ctx.params, margs, karg, varg, looptype, function()

		return ctx.frame:callParserFunction(magic, margs)

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|renaming_by_calling|template name|[call

--            style]|[let]|[...][number of additional parameters]|[parameter

--            1]|[parameter 2]|[...]|[parameter N]|pipe to

library.renaming_by_calling = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘renaming_by_calling’: No template name was provided', 0) end

	local rargs = {}

	local argc, looptype, karg, varg = parse_child_args(rargs, opts, 1,

		mapping_styles.names_only)

	local model = { title = tname, args = rargs }

	map_names(ctx.params, rargs, karg, varg, looptype, function()

		return ctx.frame:expandTemplate(model)

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|renaming_by_invoking|module name|function

--            name|[call style]|[let]|[...]|[number of additional

--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to

library.renaming_by_invoking = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘renaming_by_invoking’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘renaming_by_invoking’: No function name was provided', 0) end

	local rargs = {}

	local argc, looptype, karg, varg = parse_child_args(rargs, opts, 2,

		mapping_styles.names_only)

	local model = { title = 'Module:' .. mname, args = rargs }

	local mfunc = require(model.title)[fname

	if mfunc == nil then error(ctx.luaname ..

		', ‘renaming_by_invoking’: The function ‘' .. fname ..

		'’ does not exist', 0) end

	map_names(ctx.params, rargs, karg, varg, looptype, function()

		return mfunc(ctx.frame:newChild(model))

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|renaming_by_magic|parser function|[call

--            style]|[let]|[...][number of additional arguments]|[argument

--            1]|[argument 2]|[...]|[argument N]|pipe to

library.renaming_by_magic = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘renaming_by_magic’: No parser function was provided', 0) end

	local rargs = {}

	local argc, looptype, karg, varg = parse_child_args(rargs, opts, 1,

		mapping_styles.names_only)

	map_names(ctx.params, rargs, karg, varg, looptype, function()

		return ctx.frame:callParserFunction(magic, rargs)

	end)

	return context_iterate(ctx, argc)

end







	--[[ Functions ]]--

	-----------------------------





-- Syntax:  #invoke:params|count

library.count = function(ctx)

	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!

	local retval = 0

	for _ in ctx.iterfunc(ctx.params) do retval = retval + 1 end

	if ctx.subset == -1 then retval = retval - #ctx.params end

	ctx.text = retval

	return false

end





-- Syntax:  #invoke:args|concat_and_call|template name|[prepend 1]|[prepend 2]

--            |[...]|[item n]|[named item 1=value 1]|[...]|[named item n=value

--            n]|[...]

library.concat_and_call = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable!

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘concat_and_call’: No template name was provided', 0) end

	remove_numerical_keys(opts, 1, 1)

	ctx.text = ctx.frame:expandTemplate{

		title = tname,

		args = concat_params(ctx)

	}

	return false

end





-- Syntax:  #invoke:args|concat_and_invoke|module name|function name|[prepend

--            1]|[prepend 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named

--            item n=value n]|[...]

library.concat_and_invoke = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable!

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘concat_and_invoke’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘concat_and_invoke’: No function name was provided', 0) end

	remove_numerical_keys(opts, 1, 2)

	local mfunc = require('Module:' .. mname)[fname

	if mfunc == nil then error(ctx.luaname ..

		', ‘concat_and_invoke’: The function ‘' .. fname ..

		'’ does not exist', 0) end

	ctx.text = mfunc(ctx.frame:newChild{

		title = 'Module:' .. fname,

		args = concat_params(ctx)

	})

	return false

end





-- Syntax:  #invoke:args|concat_and_magic|parser function|[prepend 1]|[prepend

--            2]|[...]|[item n]|[named item 1=value 1]|[...]|[named item n=

--            value n]|[...]

library.concat_and_magic = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable!

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘concat_and_magic’: No parser function was provided', 0) end

	remove_numerical_keys(opts, 1, 1)

	ctx.text = ctx.frame:callParserFunction(magic, concat_params(ctx))

	return false

end





-- Syntax:  #invoke:params|value_of|parameter name

library.value_of = function(ctx)

	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!

	local opts = ctx.pipe

	local kstr

	if opts1 ~= nil then kstr = opts1]:match'^%s*(.*%S)' end

	if kstr == nil then error(ctx.luaname ..

		', ‘value_of’: No parameter name was provided', 0) end

	local knum = tonumber(kstr)

	local len = #ctx.params

	local val = ctx.paramsknum or kstr

	if val ~= nil and (

		ctx.subset ~= -1 or knum == nil or knum > len or knum < 1

	) and (

		ctx.subset ~= 1 or (knum ~= nil and knum <= len and knum > 0)

	) then

		ctx.text = (ctx.header or '') .. val .. (ctx.footer or '')

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|list

library.list = function(ctx)

	-- NOTE: `ctx.pipe` might be the original metatable!

	local kvs = ctx.pairsep or ''

	local pps = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			retnss + 1 = pps

			retnss + 2 = key

			retnss + 3 = kvs

			retnss + 4 = val

			nss = nss + 4

		end

	)

	if nss > 0 then

		if nss > 4 and ctx.lastsep ~= nil then

			retnss - 3 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|list_values

library.list_values = function(ctx)

	-- NOTE: `ctx.pipe` might be the original metatable!

	local pps = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			retnss + 1 = pps

			retnss + 2 = val

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|for_each|wikitext

library.for_each = function(ctx)

	-- NOTE: `ctx.pipe` might be the original metatable!

	local txt = ctx.pipe1 or ''

	local pps = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			retnss + 1 = pps

			retnss + 2 = txt:gsub('%$#', key):gsub('%$@', val)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|call_for_each|template name|[append 1]|[append 2]

--            |[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.call_for_each = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘call_for_each’: No template name was provided', 0) end

	local model = { title = tname, args = opts }

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	table.insert(opts, 1, true)

	flush_params(

		ctx,

		function(key, val)

			opts1 = key

			opts2 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:expandTemplate(model)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|invoke_for_each|module name|module function|[append

--            1]|[append 2]|[...]|[append n]|[named param 1=value 1]|[...]

--            |[named param n=value n]|[...]

library.invoke_for_each = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘invoke_for_each’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘invoke_for_each’: No function name was provided', 0) end

	local model = { title = 'Module:' .. mname, args = opts }

	local mfunc = require(model.title)[fname

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			opts1 = key

			opts2 = val

			retnss + 1 = ccs

			retnss + 2 = mfunc(ctx.frame:newChild(model))

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|magic_for_each|parser function|[append 1]|[append 2]

--            |[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.magic_for_each = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘magic_for_each’: No parser function was provided', 0) end

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	table.insert(opts, 1, true)

	flush_params(

		ctx,

		function(key, val)

			opts1 = key

			opts2 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:callParserFunction(magic,

				opts)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|call_for_each_value|template name|[append 1]|[append

--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.call_for_each_value = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘call_for_each_value’: No template name was provided', 0) end

	local model = { title = tname, args = opts }

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			opts1 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:expandTemplate(model)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|invoke_for_each_value|module name|[append 1]|[append

--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.invoke_for_each_value = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘invoke_for_each_value’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘invoke_for_each_value’: No function name was provided', 0) end

	local model = { title = 'Module:' .. mname, args = opts }

	local mfunc = require(model.title)[fname

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	remove_numerical_keys(opts, 1, 1)

	flush_params(

		ctx,

		function(key, val)

			opts1 = val

			retnss + 1 = ccs

			retnss + 2 = mfunc(ctx.frame:newChild(model))

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|magic_for_each_value|parser function|[append 1]

--            |[append 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named

--            param n=value n]|[...]

library.magic_for_each_value = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘magic_for_each_value’: No parser function was provided', 0) end

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			opts1 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:callParserFunction(magic,

				opts)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|call_for_each_group|template name|[append 1]|[append

--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.call_for_each_group = function(ctx)

	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!

	local opts = ctx.pipe

	local tmp

	if opts1 ~= nil then tmp = opts1]:match'^%s*(.*%S)' end

	if tmp == nil then error(ctx.luaname ..

		', ‘call_for_each_group’: No template name was provided', 0) end

	local model = { title = tmp }

	local ccs = ctx.itersep or ''

	local nss = 0

	local prefix

	local gid

	local groups = {}

	local ret = {}

	opts = {}

	for key, val in pairs(ctx.pipe) do

		if type(key) == 'number' then optskey - 1 = val

		else optskey = val end

	end

	ctx.pipe = opts

	for key, val in pairs(ctx.params) do

		prefix, gid = tostring(key):match'^%s*(.-)%s*(%-?%d*)%s*$'

		gid = tonumber(gid) or ''

		if groupsgid == nil then groupsgid = {} end

		tmp = tonumber(prefix)

		if tmp ~= nil then

			if tmp < 1 then prefix = tmp - 1 else prefix = tmp end

		end

		groupsgid][prefix = val

	end

	ctx.params = groups

	flush_params(

		ctx,

		function(gid, group)

			for key, val in pairs(opts) do groupkey = val end

			group0 = gid

			model.args = group

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:expandTemplate(model)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end







	---                                        ---

	---     PUBLIC ENVIRONMENT                 ---

	---    ________________________________    ---

	---                                        ---







	--[[ First-position-only modifiers ]]--

	---------------------------------------





-- Syntax:  #invoke:params|new|pipe to

--[[

static_iface.new = function(frame)

	local ctx = context_new()

	ctx.frame = frame:getParent()

	ctx.pipe = copy_or_ref_table(frame.args, false)

	ctx.params = {}

	main_loop(ctx, context_iterate(ctx, 1))

	return ctx.text

end

]]--







	--[[ First-position-only functions ]]--

	---------------------------------------







-- Syntax:  #invoke:params|self

static_iface.self = function(frame)

	return frame:getParent():getTitle()

end







	--[[ Public metatable of functions ]]--

	---------------------------------------







return setmetatable(static_iface, {

	__index = function(iface, _fname_)

		local ctx = context_new()

		local fname = _fname_:match'^%s*(.*%S)'

		if fname == nil then error(ctx.luaname ..

			': You must specify a function to call', 0) end

		if libraryfname == nil then error(ctx.luaname ..

			': The function ‘' .. fname .. '’ does not exist', 0) end

		return function(frame)

			local func = libraryfname

			local refpipe = {

				count = true,

				value_of = true,

				list = true,

				list_values = true,

				for_each = true,

				call_for_each_group = true

			}

			local refparams = {

				--inserting = true,

				count = true,

				concat_and_call = true,

				concat_and_invoke = true,

				concat_and_magic = true,

				value_of = true,

				call_for_each_group = true

			}

			ctx.frame = frame:getParent()

			ctx.pipe = copy_or_ref_table(frame.args, refpipefname])

			ctx.params = copy_or_ref_table(ctx.frame.args, refparamsfname])

			main_loop(ctx, func)

			return ctx.text

		end

	end

})
From Wikipedia, the free encyclopedia

	---                                        ---

	---     LOCAL ENVIRONMENT                  ---

	---    ________________________________    ---

	---                                        ---







	--[[ Abstract utilities ]]--

	----------------------------





-- Helper function for `string.gsub()` (for managing zero-padded numbers)

function zero_padded(str)

	return ("%03d%s"):format(#str, str)

end





-- Helper function for `table.sort()` (for natural sorting)

function natural_sort(var1, var2)

	return tostring(var1):gsub("%d+", zero_padded) <

		tostring(var2):gsub("%d+", zero_padded)

end





-- Return a copy or a reference to a table

local function copy_or_ref_table(src, refonly)

	if refonly then return src end

	newtab = {}

	for key, val in pairs(src) do newtabkey = val end

	return newtab

end





-- Remove numerical elements from a table, shifting everything to the left

function remove_numerical_keys(tbl, idx, len)

	local cache = {}

	local tmp = idx + len - 1

	for key, val in pairs(tbl) do

		if type(key) == 'number' and key >= idx then

			if key > tmp then cachekey - len = val end

			tblkey = nil

		end

	end

	for key, val in pairs(cache) do tblkey = val end

end





-- Make a reduced copy of a table (shifting in both directions if necessary)

function copy_table_reduced(tbl, idx, len)

	local ret = {}

	local tmp = idx + len - 1

	if idx > 0 then

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key < idx then

				retkey = val

			elseif key > tmp then retkey - len = val end

		end

	elseif tmp > 0 then

		local nshift = 1 - idx

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' then retkey = val

			elseif key > tmp then retkey - tmp = val

			elseif key < idx then retkey + nshift = val end

		end

	else

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key > tmp then

				retkey = val

			elseif key < idx then retkey + len = val end

		end

	end

	return ret

end





-- Make an expanded copy of a table (shifting in both directions if necessary)

function copy_table_expanded(tbl, idx, len)

	local ret = {}

	local tmp = idx + len - 1

	if idx > 0 then

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key < idx then

				retkey = val

			else retkey + len = val end

		end

	elseif tmp > 0 then

		local nshift = idx - 1

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' then retkey = val

			elseif key > 0 then retkey + tmp = val

			elseif key < 1 then retkey + nshift = val end

		end

	else

		for key, val in pairs(tbl) do

			if type(key) ~= 'number' or key > tmp then

				retkey = val

			else retkey - len = val end

		end

	end

	return ret

end





-- Move a key from a table to another, but only if under a different name and

-- always parsing numerical strings as numbers

function steal_if_renamed(val, src, skey, dest, dkey)

	local realkey = tonumber(dkey) or dkey:match'^%s*(.-)%s*$'

	if skey ~= realkey then

		destrealkey = val

		srcskey = nil

	end

end







	--[[ Public strings ]]--

	------------------------





-- Special match keywords (functions and modifiers MUST avoid these names)

local mkeywords = {

	'or' = 0,

	--pattern = 1, -- Simply uncommenting enables the option

	plain = 2,

	strict = 3

}





-- Sort functions (functions and modifiers MUST avoid these names)

local sortfunctions = {

	--alphabetically = false, -- Simply uncommenting enables the option

	naturally = natural_sort

}





-- Callback styles for the `mapping_*` and `renaming_*` class of modifiers

-- (functions and modifiers MUST avoid these names)

--[[



Meanings of the columns:



  col[1] = Loop type (0-3)

  col[2] = Number of module arguments that the style requires (1-3)

  col[3] = Minimum number of sequential parameters passed to the callback

  col[4] = Name of the callback parameter where to place each parameter name

  col[5] = Name of the callback parameter where to place each parameter value

  col[6] = Argument in the modifier's invocation that will override `col[4]`

  col[7] = Argument in the modifier's invocation that will override `col[5]`



A value of `-1` indicates that no meaningful value is stored (i.e. `nil`)



]]--

local mapping_styles = {

	names_and_values = { 3, 2, 2, 1, 2, -1, -1 },

	values_and_names = { 3, 2, 2, 2, 1, -1, -1 },

	values_only = { 1, 2, 1, -1, 1, -1, -1 },

	names_only = { 2, 2, 1, 1, -1, -1, -1 },

	names_and_values_as = { 3, 4, 0, -1, -1, 2, 3 },

	names_only_as = { 2, 3, 0, -1, -1, 2, -1 },

	values_only_as = { 1, 3, 0, -1, -1, -1, 2 },

	blindly = { 0, 2, 0, -1, -1, -1, -1 }

}





-- Memory slots (functions and modifiers MUST avoid these names)

local memoryslots = {

	i = 'itersep',

	l = 'lastsep',

	p = 'pairsep',

	h = 'header',

	f = 'footer',

	n = 'ifngiven'

}





-- Functions and modifiers MUST avoid these names too: `let`







	--[[ Module's private environment ]]--

	--------------------------------------





-- Maximum number of numerical parameters that can be filled, if missing (we

-- chose an arbitrary number for this constant; you can discuss about its

-- optimal value at Module talk:Params)

local maxfill = 1024





-- The private table of functions

local library = {}





-- Functions that can only be invoked in first position

local static_iface = {}





-- Create a new context

local function context_new()

	local ctx = {}

	ctx.luaname = 'Module:Params'	--[[ or `frame:getTitle()` ]]--

	ctx.iterfunc = pairs

	ctx.firstposonly = static_iface

	ctx.n_available = maxfill

	return ctx

end





-- Move to the next action within the user-given list

local function context_iterate(ctx, n_forward)

	local nextfn

	if ctx.pipen_forward ~= nil then

		nextfn = ctx.pipen_forward]:match'^%s*(.*%S)'

	end

	if nextfn == nil then error(ctx.luaname ..

		': You must specify a function to call', 0) end

	if librarynextfn == nil then

		if ctx.firstposonlynextfn == nil then error(ctx.luaname ..

			': The function ‘' .. nextfn .. '’ does not exist', 0)

		else error(ctx.luaname .. ': The ‘' .. nextfn ..

			'’ directive can only appear in first position', 0)

		end

	end

	remove_numerical_keys(ctx.pipe, 1, n_forward)

	return librarynextfn

end





-- Main loop

local function main_loop(ctx, start_with)

	local fn = start_with

	repeat fn = fn(ctx) until not fn

end





-- Parse the arguments of the `mapping_*` and `renaming_*` class of modifiers

function parse_child_args(dest, src, n_skip, default_style)

	local style

	local shf

	local tmp = srcn_skip + 1

	if tmp ~= nil then style = mapping_stylestmp:match'^%s*(.-)%s*$' end

	if style == nil then

		style = default_style

		shf = n_skip - 1

	else shf = n_skip end

	local names

	local nargs

	local pin = style2 + shf

	local n_exist = style3

	local karg = style4

	local varg = style5

	tmp = style6

	if tmp > -1 then

		tmp = srctmp + shf

		karg = tonumber(tmp)

		if karg == nil then karg = tmp:match'^%s*(.-)%s*$'

		else n_exist = math.max(n_exist, karg) end

	end

	tmp = style7

	if tmp > -1 then

		tmp = srctmp + shf

		varg = tonumber(tmp)

		if varg == nil then varg = tmp:match'^%s*(.-)%s*$'

		else n_exist = math.max(n_exist, varg) end

	end

	if srcpin ~= nil and srcpin]:match'^%s*let%s*$' then

		names = {}

		repeat

			tmp = srcpin + 1 or ''

			namestonumber(tmp) or tmp:match'^%s*(.-)%s*$' or '' =

				srcpin + 2

			pin = pin + 3

		until srcpin == nil or not srcpin]:match'^%s*let%s*$'

	end

	tmp = tonumber(srcpin])

	if tmp ~= nil then

		if tmp < 0 then tmp = -1 end

		shf = n_exist - pin

		for idx = pin + 1, pin + tmp do destidx + shf = srcidx end

		nargs = pin + tmp + 1

	else nargs = pin end

	if names ~= nil then

		for key, val in pairs(names) do destkey = val end

	end

	tmp = style1

	if (tmp == 3 or tmp == 2) and destkarg ~= nil then

		tmp = tmp - 2 end

	if (tmp == 3 or tmp == 1) and destvarg ~= nil then

		tmp = tmp - 1 end

	return nargs, tmp, karg, varg

end





-- Parse the arguments of the `with_*_matching` class of modifiers

local function parse_pattern_args(ctx, ptns, fname)

	local state = 0

	local cnt = 1

	local keyw

	local nptns = 0

	for _, val in ipairs(ctx.pipe) do

		if state == 0 then

			nptns = nptns + 1

			ptnsnptns = { val, false, false }

			state = -1

		else

			keyw = val:match'^%s*(.*%S)'

			if keyw == nil or mkeywordskeyw == nil or (

				state > 0 and mkeywordskeyw > 0

			) then break

			else

				state = mkeywordskeyw

				if state > 1 then ptnsnptns][2 = true end

				if state == 3 then ptnsnptns][3 = true end

			end

		end

		cnt = cnt + 1

	end

	if state == 0 then error(ctx.luaname .. ', ‘' .. fname ..

		'’: No pattern was given', 0) end

	return cnt

end





-- Map parameters' values using a custom callback and a referenced table

function map_values(tbl, margs, karg, varg, looptype, fn)

	if looptype == 1 then

		for key, val in pairs(tbl) do

			margsvarg = val

			tblkey = fn()

		end

	elseif looptype == 3 then

		for key, val in pairs(tbl) do

			margskarg = key

			margsvarg = val

			tblkey = fn()

		end

	elseif looptype == 2 then

		for key in pairs(tbl) do

			margskarg = key

			tblkey = fn()

		end

	elseif looptype == 0 then

		for key in pairs(tbl) do

			tblkey = fn()

		end

	end

end





-- Map parameters' names using a custom callback and a referenced table

function map_names(tbl, rargs, karg, varg, looptype, fn)

	local cache = {}

	if looptype == 2 then

		for key, val in pairs(tbl) do

			rargskarg = key

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	elseif looptype == 3 then

		for key, val in pairs(tbl) do

			rargskarg = key

			rargsvarg = val

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	elseif looptype == 1 then

		for key, val in pairs(tbl) do

			rargsvarg = val

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	elseif looptype == 0 then

		for key, val in pairs(tbl) do

			steal_if_renamed(val, tbl, key, cache, fn())

		end

	end

	for key, val in pairs(cache) do tblkey = val end

end





-- Concatenate the numerical keys from the table of parameters to the numerical

-- keys from the table of options; non-numerical keys from the table of options

-- will prevail over colliding non-numerical keys from the table of parameters

local function concat_params(ctx)

	local tbl = ctx.params

	local size = table.maxn(ctx.pipe)

	local retval = {}

	if ctx.subset == 1 then

		-- We need only the sequence

		for key, val in ipairs(tbl) do retvalkey + size = val end

	else

		if ctx.subset == -1 then

			for key, val in ipairs(tbl) do tblkey = nil end

		end

		for key, val in pairs(tbl) do

			if type(key) == 'number' then retvalkey + size = val

			else retvalkey = val end

		end

	end

	for key, val in pairs(ctx.pipe) do retvalkey = val end

	return retval

end





-- Flush the parameters by calling a custom function for each value (after this

-- function has been invoked `ctx.params` will be no longer usable)

local function flush_params(ctx, fn)

	local tbl = ctx.params

	if ctx.subset == 1 then

		for key, val in ipairs(tbl) do fn(key, val) end

		return

	end

	if ctx.subset == -1 then

		for key, val in ipairs(tbl) do tblkey = nil end

	end

	if ctx.dosort then

		local nums = {}

		local words = {}

		local nlen = 0

		local wlen = 0

		for key, val in pairs(tbl) do

			if type(key) == 'number' then

				nlen = nlen + 1

				numsnlen = key

			else

				wlen = wlen + 1

				wordswlen = key

			end

		end

		table.sort(nums)

		table.sort(words, natural_sort)

		for idx = 1, nlen do fn(numsidx], tblnumsidx]]) end

		for idx = 1, wlen do fn(wordsidx], tblwordsidx]]) end

		return

	end

	if ctx.subset ~= -1 then

		for key, val in ipairs(tbl) do

			fn(key, val)

			tblkey = nil

		end

	end

	for key, val in pairs(tbl) do fn(key, val) end

end







	--[[ Modifiers ]]--

	-----------------------------





-- Syntax:  #invoke:params|sequential|pipe to

library.sequential = function(ctx)

	if ctx.subset == -1 then error(ctx.luaname ..

		': The two directives ‘non-sequential’ and ‘sequential’ are in contradiction with each other', 0) end

	if ctx.dosort then error(ctx.luaname ..

		': The ‘all_sorted’ directive is redundant when followed by ‘sequential’', 0) end

	ctx.iterfunc = ipairs

	ctx.subset = 1

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|non-sequential|pipe to

library'non-sequential' = function(ctx)

	if ctx.subset == 1 then error(ctx.luaname ..

		': The two directives ‘sequential’ and ‘non-sequential’ are in contradiction with each other', 0) end

	ctx.iterfunc = pairs

	ctx.subset = -1

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|sort|pipe to

library.all_sorted = function(ctx)

	if ctx.subset == 1 then error(ctx.luaname ..

		': The ‘all_sorted’ directive is redundant after ‘sequential’', 0) end

	ctx.dosort = true

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|setting|directives|...|pipe to

library.setting = function(ctx)

	local opts = ctx.pipe

	local cmd = opts1

	if cmd ~= nil then

		cmd = cmd:gsub('%s+', ''):gsub('/+', '/'):match'^/*(.*[^/])'

	end

	if cmd == nil then error(ctx.luaname ..

		', ‘setting’: No directive was given', 0) end

	local sep = string.byte('/')

	local argc = 2

	local dest = {}

	local vname

	local chr

	for idx = 1, #cmd do

		chr = cmd:byte(idx)

		if chr == sep then

			for key, val in ipairs(dest) do

				ctxval = optsargc

				destkey = nil

			end

			argc = argc + 1

		else

			vname = memoryslotsstring.char(chr)]

			if vname == nil then error(ctx.luaname ..

				', ‘setting’: Unknown slot "' ..

				string.char(chr) .. '"', 0) end

			table.insert(dest, vname)

		end

	end

	for key, val in ipairs(dest) do ctxval = optsargc end

	return context_iterate(ctx, argc + 1)

end





-- Syntax:  #invoke:params|squeezing|pipe to

library.squeezing = function(ctx)

	local tbl = ctx.params

	local store = {}

	local indices = {}

	local newlen = 0

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			newlen = newlen + 1

			indicesnewlen = key

			storekey = val

			tblkey = nil

		end

	end

	table.sort(indices)

	for idx = 1, newlen do tblidx = storeindicesidx]] end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|filling_the_gaps|pipe to

library.filling_the_gaps = function(ctx)

	local tbl = ctx.params

	local nmin = 1

	local nmax = nil

	local nnums = -1

	local tmp = {}

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			if nmax == nil then

				if key < nmin then nmin = key end

				nmax = key

			elseif key > nmax then nmax = key

			elseif key < nmin then nmin = key end

			nnums = nnums + 1

			tmpkey = val

		end

	end

	if nmax ~= nil and nmax - nmin > nnums then

		ctx.n_available = ctx.n_available + nmin + nnums - nmax

		if ctx.n_available < 0 then error(ctx.luaname ..

			', ‘filling_the_gaps’: It is possible to fill at most ' ..

			tostring(maxfill) .. ' parameters', 0) end

		for idx = nmin, nmax, 1 do tblidx = '' end

		for key, val in pairs(tmp) do tblkey = val end

	end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|clearing|pipe to

library.clearing = function(ctx)

	local tbl = ctx.params

	local numericals = {}

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericalskey = val

			tblkey = nil

		end

	end

	for key, val in ipairs(numericals) do tblkey = val end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|cutting|left cut|right cut|pipe to

library.cutting = function(ctx)

	local lcut = tonumber(ctx.pipe1])

	if lcut == nil then error(ctx.luaname ..

		', ‘cutting’: Left cut must be a number', 0) end

	local rcut = tonumber(ctx.pipe2])

	if rcut == nil then error(ctx.luaname ..

		', ‘cutting’: Right cut must be a number', 0) end

	local tbl = ctx.params

	local len = #tbl

	if lcut < 0 then lcut = len + lcut end

	if rcut < 0 then rcut = len + rcut end

	local tot = lcut + rcut

	if tot > 0 then

		local cache = {}

		if tot >= len then

			for key in ipairs(tbl) do tblkey = nil end

			tot = len

		else

			for idx = len - rcut + 1, len, 1 do tblidx = nil end

			for idx = 1, lcut, 1 do tblidx = nil end

		end

		for key, val in pairs(tbl) do

			if type(key) == 'number' and key > 0 then

				if key > len then cachekey - tot = val

				else cachekey - lcut = val end

				tblkey = nil

			end

		end

		for key, val in pairs(cache) do tblkey = val end

	end

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|cropping|left crop|right crop|pipe to

library.cropping = function(ctx)

	local lcut = tonumber(ctx.pipe1])

	if lcut == nil then error(ctx.luaname ..

		', ‘cropping’: Left crop must be a number', 0) end

	local rcut = tonumber(ctx.pipe2])

	if rcut == nil then error(ctx.luaname ..

		', ‘cropping’: Right crop must be a number', 0) end

	local tbl = ctx.params

	local nmin

	local nmax

	for key in pairs(tbl) do

		if type(key) == 'number' then

			if nmin == nil then

				nmin = key

				nmax = key

			elseif key > nmax then nmax = key

			elseif key < nmin then nmin = key end

		end

	end

	if nmin ~= nil then

		local len = nmax - nmin + 1

		if lcut < 0 then lcut = len + lcut end

		if rcut < 0 then rcut = len + rcut end

		if lcut + rcut - len > -1 then

			for key in pairs(tbl) do

				if type(key) == 'number' then tblkey = nil end

			end

		elseif lcut + rcut > 0 then

			for idx = nmax - rcut + 1, nmax do tblidx = nil end

			for idx = nmin, nmin + lcut - 1 do tblidx = nil end

			local lshift = nmin + lcut - 1

			if lshift > 0 then

				for idx = lshift + 1, nmax, 1 do

					tblidx - lshift = tblidx

					tblidx = nil

				end

			end

		end

	end

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|purging|start offset|length|pipe to

library.purging = function(ctx)

	local idx = tonumber(ctx.pipe1])

	if idx == nil then error(ctx.luaname ..

		', ‘purging’: Start offset must be a number', 0) end

	local len = tonumber(ctx.pipe2])

	if len == nil then error(ctx.luaname ..

		', ‘purging’: Length must be a number', 0) end

	local tbl = ctx.params

	if len < 1 then

		len = len + table.maxn(tbl)

		if idx > len then return context_iterate(ctx, 3) end

		len = len - idx + 1

	end

	ctx.params = copy_table_reduced(tbl, idx, len)

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|backpurging|start offset|length|pipe to

library.backpurging = function(ctx)

	local last = tonumber(ctx.pipe1])

	if last == nil then error(ctx.luaname ..

		', ‘backpurging’: Start offset must be a number', 0) end

	local len = tonumber(ctx.pipe2])

	if len == nil then error(ctx.luaname ..

		', ‘backpurging’: Length must be a number', 0) end

	local idx

	local tbl = ctx.params

	if len > 0 then

		idx = last - len + 1

	else

		for key in pairs(tbl) do

			if type(key) == 'number' and (idx == nil or

				key < idx) then idx = key end

		end

		if idx == nil then return context_iterate(ctx, 3) end

		idx = idx - len

		if last < idx then return context_iterate(ctx, 3) end

		len = last - idx + 1

	end

	ctx.params = copy_table_reduced(ctx.params, idx, len)

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|rotating|pipe to

library.rotating = function(ctx)

	local tbl = ctx.params

	local numericals = {}

	local nmax = 0

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericalskey = val

			tblkey = nil

			if key > nmax then nmax = key end

		end

	end

	for key, val in pairs(numericals) do tblnmax - key + 1 = val end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|pivoting|pipe to

--[[

library.pivoting = function(ctx)

	local tbl = ctx.params

	local shift = #tbl + 1

	if shift < 2 then return library.rotating(ctx) end

	local numericals = {}

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericals[key] = val

			tbl[key] = nil

		end

	end

	for key, val in pairs(numericals) do tbl[shift - key] = val end

	return context_iterate(ctx, 1)

end

]]--





-- Syntax:  #invoke:params|mirroring|pipe to

--[[

library.mirroring = function(ctx)

	local tbl = ctx.params

	local numericals = {}

	local nmax

	local nmin

	for key, val in pairs(tbl) do

		if type(key) == 'number' then

			numericals[key] = val

			tbl[key] = nil

			if nmax == nil then

				nmax = key

				nmin = key

			elseif key > nmax then nmax = key

			elseif key < nmin then nmin = key end

		end

	end

	for key, val in pairs(numericals) do tbl[nmax + nmin - key] = val end

	return context_iterate(ctx, 1)

end

]]--





-- Syntax:  #invoke:params|swapping|pipe to

--[[

library.swapping = function(ctx)

	local tbl = ctx.params

	local cache = {}

	local nsize = 0

	local tmp

	for key in pairs(tbl) do

		if type(key) == 'number' then

			nsize = nsize + 1

			cache[nsize] = key

		end

	end

	table.sort(cache)

	for idx = math.floor(nsize / 2), 1, -1 do

		tmp = tbl[cache[idx] ]

		tbl[cache[idx] ] = tbl[cache[nsize - idx + 1] ]

		tbl[cache[nsize - idx + 1] ] = tmp

	end

	return context_iterate(ctx, 1)

end

]]--





-- Syntax:  #invoke:params|sorting_sequential_values|[criterion]|pipe to

library.sorting_sequential_values = function(ctx)

	local sortfn

	if ctx.pipe1 ~= nil then sortfn = sortfunctionsctx.pipe1]] end

	if sortfn then table.sort(ctx.params, sortfn)

	else table.sort(ctx.params) end -- i.e. either `false` or `nil`

	if sortfn == nil then return context_iterate(ctx, 1) end

	return context_iterate(ctx, 2)

end





-- Syntax:  #invoke:params|inserting|position|how many|...|pipe to

--[[

library.inserting = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable! As a modifier,

	-- this function MUST create a copy of it before returning

	local idx = tonumber(ctx.pipe[1])

	if idx == nil then error(ctx.luaname ..

		', ‘inserting’: Position must be a number', 0) end

	local len = tonumber(ctx.pipe[2])

	if len == nil or len < 1 then error(ctx.luaname ..

		', ‘inserting’: The amount must be a number greater than zero', 0) end

	local opts = ctx.pipe

	local tbl = copy_table_expanded(ctx.params, idx, len)

	for key = idx, idx + len - 1 do tbl[key] = opts[key - idx + 3] end

	ctx.params = tbl

	return context_iterate(ctx, len + 3)

end

]]--





-- Syntax:  #invoke:params|imposing|name|value|pipe to

library.imposing = function(ctx)

	if ctx.pipe1 == nil then error(ctx.luaname ..

		', ‘imposing’: Missing parameter name to impose', 0) end

	local key = ctx.pipe1]:match'^%s*(.-)%s*$'

	ctx.paramstonumber(key) or key = ctx.pipe2

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|discarding|name|[how many]|pipe to

library.discarding = function(ctx)

	if ctx.pipe1 == nil then error(ctx.luaname ..

		', ‘discarding’: Missing parameter name to discard', 0) end

	local key = ctx.pipe1

	local len = tonumber(ctx.pipe2])

	if len == nil then

		ctx.paramstonumber(key) or key:match'^%s*(.-)%s*$' = nil

		return context_iterate(ctx, 2)

	end

	key = tonumber(key)

	if key == nil then error(ctx.luaname ..

		', ‘discarding’: A range was provided, but the initial parameter name is not numerical', 0) end

	if len < 1 then error(ctx.luaname ..

		', ‘discarding’: A range can only be a number greater than zero', 0) end

	for idx = key, key + len - 1 do ctx.paramsidx = nil end

	return context_iterate(ctx, 3)

end





-- Syntax:  #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or]

--            |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag

--            N]|pipe to

library.with_name_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns, 'with_name_matching')

	local nomatch

	for key in pairs(tbl) do

		nomatch = true

		for _, ptn in ipairs(patterns) do

			if not ptn3 then

				if string.find(key, ptn1], 1, ptn2]) then

					nomatch = false

					break

				end

			elseif key == ptn1 then

				nomatch = false

				break

			end

		end

		if nomatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|with_name_not_matching|pattern 1|[plain flag 1]

--            |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain

--            flag N]|pipe to

library.with_name_not_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns,

		'with_name_not_matching')

	local yesmatch

	for key in pairs(tbl) do

		yesmatch = true

		for _, ptn in ipairs(patterns) do

			if ptn3 then

				if key ~= ptn1 then

					yesmatch = false

					break

				end

			elseif not string.find(key, ptn1], 1, ptn2]) then

				yesmatch = false

				break

			end

		end

		if yesmatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or]

--            |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag

--            N]|pipe to

library.with_value_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns, 'with_value_matching')

	local nomatch

	for key, val in pairs(tbl) do

		nomatch = true

		for _, ptn in ipairs(patterns) do

			if ptn3 then

				if val == ptn1 then

					nomatch = false

					break

				end

			elseif string.find(val, ptn1], 1, ptn2]) then

				nomatch = false

				break

			end

		end

		if nomatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|with_value_not_matching|pattern 1|[plain flag 1]

--            |[and]|[pattern 2]|[plain flag 2]|[and]|[...]|[pattern N]|[plain

--            flag N]|pipe to

library.with_value_not_matching = function(ctx)

	local tbl = ctx.params

	local patterns = {}

	local argc = parse_pattern_args(ctx, patterns,

		'with_value_not_matching')

	local yesmatch

	for key, val in pairs(tbl) do

		yesmatch = true

		for _, ptn in ipairs(patterns) do

			if ptn3 then

				if val ~= ptn1 then

					yesmatch = false

					break

				end

			elseif not string.find(val, ptn1], 1, ptn2]) then

				yesmatch = false

				break

			end

		end

		if yesmatch then tblkey = nil end

	end

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|trimming_values|pipe to

library.trimming_values = function(ctx)

	local tbl = ctx.params

	for key, val in pairs(tbl) do tblkey = val:match'^%s*(.-)%s*$' end

	return context_iterate(ctx, 1)

end





-- Syntax:  #invoke:params|mapping_by_calling|template name|[call

--            style]|[let]|[...][number of additional parameters]|[parameter

--            1]|[parameter 2]|[...]|[parameter N]|pipe to

library.mapping_by_calling = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘mapping_by_calling’: No template name was provided', 0) end

	local margs = {}

	local argc, looptype, karg, varg = parse_child_args(margs, opts, 1,

		mapping_styles.values_only)

	local model = { title = tname, args = margs }

	map_values(ctx.params, margs, karg, varg, looptype, function()

		return ctx.frame:expandTemplate(model)

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|mapping_by_invoking|module name|function

--            name|[call style]|[let]|[...]|[number of additional

--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to

library.mapping_by_invoking = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘mapping_by_invoking’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘mapping_by_invoking’: No function name was provided', 0) end

	local margs = {}

	local argc, looptype, karg, varg = parse_child_args(margs, opts, 2,

		mapping_styles.values_only)

	local model = { title = 'Module:' .. mname, args = margs }

	local mfunc = require(model.title)[fname

	if mfunc == nil then error(ctx.luaname ..

		', ‘mapping_by_invoking’: The function ‘' .. fname ..

		'’ does not exist', 0) end

	map_values(ctx.params, margs, karg, varg, looptype, function()

		return mfunc(ctx.frame:newChild(model))

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|mapping_by_magic|parser function|[call

--            style]|[let]|[...][number of additional arguments]|[argument

--            1]|[argument 2]|[...]|[argument N]|pipe to

library.mapping_by_magic = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘mapping_by_magic’: No parser function was provided', 0) end

	local margs = {}

	local argc, looptype, karg, varg = parse_child_args(margs, opts, 1,

		mapping_styles.values_only)

	map_values(ctx.params, margs, karg, varg, looptype, function()

		return ctx.frame:callParserFunction(magic, margs)

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|renaming_by_calling|template name|[call

--            style]|[let]|[...][number of additional parameters]|[parameter

--            1]|[parameter 2]|[...]|[parameter N]|pipe to

library.renaming_by_calling = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘renaming_by_calling’: No template name was provided', 0) end

	local rargs = {}

	local argc, looptype, karg, varg = parse_child_args(rargs, opts, 1,

		mapping_styles.names_only)

	local model = { title = tname, args = rargs }

	map_names(ctx.params, rargs, karg, varg, looptype, function()

		return ctx.frame:expandTemplate(model)

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|renaming_by_invoking|module name|function

--            name|[call style]|[let]|[...]|[number of additional

--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|pipe to

library.renaming_by_invoking = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘renaming_by_invoking’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘renaming_by_invoking’: No function name was provided', 0) end

	local rargs = {}

	local argc, looptype, karg, varg = parse_child_args(rargs, opts, 2,

		mapping_styles.names_only)

	local model = { title = 'Module:' .. mname, args = rargs }

	local mfunc = require(model.title)[fname

	if mfunc == nil then error(ctx.luaname ..

		', ‘renaming_by_invoking’: The function ‘' .. fname ..

		'’ does not exist', 0) end

	map_names(ctx.params, rargs, karg, varg, looptype, function()

		return mfunc(ctx.frame:newChild(model))

	end)

	return context_iterate(ctx, argc)

end





-- Syntax:  #invoke:params|renaming_by_magic|parser function|[call

--            style]|[let]|[...][number of additional arguments]|[argument

--            1]|[argument 2]|[...]|[argument N]|pipe to

library.renaming_by_magic = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘renaming_by_magic’: No parser function was provided', 0) end

	local rargs = {}

	local argc, looptype, karg, varg = parse_child_args(rargs, opts, 1,

		mapping_styles.names_only)

	map_names(ctx.params, rargs, karg, varg, looptype, function()

		return ctx.frame:callParserFunction(magic, rargs)

	end)

	return context_iterate(ctx, argc)

end







	--[[ Functions ]]--

	-----------------------------





-- Syntax:  #invoke:params|count

library.count = function(ctx)

	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!

	local retval = 0

	for _ in ctx.iterfunc(ctx.params) do retval = retval + 1 end

	if ctx.subset == -1 then retval = retval - #ctx.params end

	ctx.text = retval

	return false

end





-- Syntax:  #invoke:args|concat_and_call|template name|[prepend 1]|[prepend 2]

--            |[...]|[item n]|[named item 1=value 1]|[...]|[named item n=value

--            n]|[...]

library.concat_and_call = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable!

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘concat_and_call’: No template name was provided', 0) end

	remove_numerical_keys(opts, 1, 1)

	ctx.text = ctx.frame:expandTemplate{

		title = tname,

		args = concat_params(ctx)

	}

	return false

end





-- Syntax:  #invoke:args|concat_and_invoke|module name|function name|[prepend

--            1]|[prepend 2]|[...]|[item n]|[named item 1=value 1]|[...]|[named

--            item n=value n]|[...]

library.concat_and_invoke = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable!

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘concat_and_invoke’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘concat_and_invoke’: No function name was provided', 0) end

	remove_numerical_keys(opts, 1, 2)

	local mfunc = require('Module:' .. mname)[fname

	if mfunc == nil then error(ctx.luaname ..

		', ‘concat_and_invoke’: The function ‘' .. fname ..

		'’ does not exist', 0) end

	ctx.text = mfunc(ctx.frame:newChild{

		title = 'Module:' .. fname,

		args = concat_params(ctx)

	})

	return false

end





-- Syntax:  #invoke:args|concat_and_magic|parser function|[prepend 1]|[prepend

--            2]|[...]|[item n]|[named item 1=value 1]|[...]|[named item n=

--            value n]|[...]

library.concat_and_magic = function(ctx)

	-- NOTE: `ctx.params` might be the original metatable!

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘concat_and_magic’: No parser function was provided', 0) end

	remove_numerical_keys(opts, 1, 1)

	ctx.text = ctx.frame:callParserFunction(magic, concat_params(ctx))

	return false

end





-- Syntax:  #invoke:params|value_of|parameter name

library.value_of = function(ctx)

	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!

	local opts = ctx.pipe

	local kstr

	if opts1 ~= nil then kstr = opts1]:match'^%s*(.*%S)' end

	if kstr == nil then error(ctx.luaname ..

		', ‘value_of’: No parameter name was provided', 0) end

	local knum = tonumber(kstr)

	local len = #ctx.params

	local val = ctx.paramsknum or kstr

	if val ~= nil and (

		ctx.subset ~= -1 or knum == nil or knum > len or knum < 1

	) and (

		ctx.subset ~= 1 or (knum ~= nil and knum <= len and knum > 0)

	) then

		ctx.text = (ctx.header or '') .. val .. (ctx.footer or '')

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|list

library.list = function(ctx)

	-- NOTE: `ctx.pipe` might be the original metatable!

	local kvs = ctx.pairsep or ''

	local pps = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			retnss + 1 = pps

			retnss + 2 = key

			retnss + 3 = kvs

			retnss + 4 = val

			nss = nss + 4

		end

	)

	if nss > 0 then

		if nss > 4 and ctx.lastsep ~= nil then

			retnss - 3 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|list_values

library.list_values = function(ctx)

	-- NOTE: `ctx.pipe` might be the original metatable!

	local pps = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			retnss + 1 = pps

			retnss + 2 = val

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|for_each|wikitext

library.for_each = function(ctx)

	-- NOTE: `ctx.pipe` might be the original metatable!

	local txt = ctx.pipe1 or ''

	local pps = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			retnss + 1 = pps

			retnss + 2 = txt:gsub('%$#', key):gsub('%$@', val)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|call_for_each|template name|[append 1]|[append 2]

--            |[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.call_for_each = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘call_for_each’: No template name was provided', 0) end

	local model = { title = tname, args = opts }

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	table.insert(opts, 1, true)

	flush_params(

		ctx,

		function(key, val)

			opts1 = key

			opts2 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:expandTemplate(model)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|invoke_for_each|module name|module function|[append

--            1]|[append 2]|[...]|[append n]|[named param 1=value 1]|[...]

--            |[named param n=value n]|[...]

library.invoke_for_each = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘invoke_for_each’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘invoke_for_each’: No function name was provided', 0) end

	local model = { title = 'Module:' .. mname, args = opts }

	local mfunc = require(model.title)[fname

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			opts1 = key

			opts2 = val

			retnss + 1 = ccs

			retnss + 2 = mfunc(ctx.frame:newChild(model))

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|magic_for_each|parser function|[append 1]|[append 2]

--            |[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.magic_for_each = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘magic_for_each’: No parser function was provided', 0) end

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	table.insert(opts, 1, true)

	flush_params(

		ctx,

		function(key, val)

			opts1 = key

			opts2 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:callParserFunction(magic,

				opts)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|call_for_each_value|template name|[append 1]|[append

--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.call_for_each_value = function(ctx)

	local opts = ctx.pipe

	local tname

	if opts1 ~= nil then tname = opts1]:match'^%s*(.*%S)' end

	if tname == nil then error(ctx.luaname ..

		', ‘call_for_each_value’: No template name was provided', 0) end

	local model = { title = tname, args = opts }

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			opts1 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:expandTemplate(model)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|invoke_for_each_value|module name|[append 1]|[append

--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.invoke_for_each_value = function(ctx)

	local opts = ctx.pipe

	local mname

	local fname

	if opts1 ~= nil then mname = opts1]:match'^%s*(.*%S)' end

	if mname == nil then error(ctx.luaname ..

		', ‘invoke_for_each_value’: No module name was provided', 0) end

	if opts2 ~= nil then fname = opts2]:match'^%s*(.*%S)' end

	if fname == nil then error(ctx.luaname ..

		', ‘invoke_for_each_value’: No function name was provided', 0) end

	local model = { title = 'Module:' .. mname, args = opts }

	local mfunc = require(model.title)[fname

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	remove_numerical_keys(opts, 1, 1)

	flush_params(

		ctx,

		function(key, val)

			opts1 = val

			retnss + 1 = ccs

			retnss + 2 = mfunc(ctx.frame:newChild(model))

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|magic_for_each_value|parser function|[append 1]

--            |[append 2]|[...]|[append n]|[named param 1=value 1]|[...]|[named

--            param n=value n]|[...]

library.magic_for_each_value = function(ctx)

	local opts = ctx.pipe

	local magic

	if opts1 ~= nil then magic = opts1]:match'^%s*(.*%S)' end

	if magic == nil then error(ctx.luaname ..

		', ‘magic_for_each_value’: No parser function was provided', 0) end

	local ccs = ctx.itersep or ''

	local ret = {}

	local nss = 0

	flush_params(

		ctx,

		function(key, val)

			opts1 = val

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:callParserFunction(magic,

				opts)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end





-- Syntax:  #invoke:params|call_for_each_group|template name|[append 1]|[append

--            2]|[...]|[append n]|[named param 1=value 1]|[...]|[named param

--            n=value n]|[...]

library.call_for_each_group = function(ctx)

	-- NOTE: `ctx.pipe` and `ctx.params` might be the original metatables!

	local opts = ctx.pipe

	local tmp

	if opts1 ~= nil then tmp = opts1]:match'^%s*(.*%S)' end

	if tmp == nil then error(ctx.luaname ..

		', ‘call_for_each_group’: No template name was provided', 0) end

	local model = { title = tmp }

	local ccs = ctx.itersep or ''

	local nss = 0

	local prefix

	local gid

	local groups = {}

	local ret = {}

	opts = {}

	for key, val in pairs(ctx.pipe) do

		if type(key) == 'number' then optskey - 1 = val

		else optskey = val end

	end

	ctx.pipe = opts

	for key, val in pairs(ctx.params) do

		prefix, gid = tostring(key):match'^%s*(.-)%s*(%-?%d*)%s*$'

		gid = tonumber(gid) or ''

		if groupsgid == nil then groupsgid = {} end

		tmp = tonumber(prefix)

		if tmp ~= nil then

			if tmp < 1 then prefix = tmp - 1 else prefix = tmp end

		end

		groupsgid][prefix = val

	end

	ctx.params = groups

	flush_params(

		ctx,

		function(gid, group)

			for key, val in pairs(opts) do groupkey = val end

			group0 = gid

			model.args = group

			retnss + 1 = ccs

			retnss + 2 = ctx.frame:expandTemplate(model)

			nss = nss + 2

		end

	)

	if nss > 0 then

		if nss > 2 and ctx.lastsep ~= nil then

			retnss - 1 = ctx.lastsep

		end

		ret1 = ctx.header or ''

		if ctx.footer ~= nil then retnss + 1 = ctx.footer end

		ctx.text = table.concat(ret)

		return false

	end

	ctx.text = ctx.ifngiven or ''

	return false

end







	---                                        ---

	---     PUBLIC ENVIRONMENT                 ---

	---    ________________________________    ---

	---                                        ---







	--[[ First-position-only modifiers ]]--

	---------------------------------------





-- Syntax:  #invoke:params|new|pipe to

--[[

static_iface.new = function(frame)

	local ctx = context_new()

	ctx.frame = frame:getParent()

	ctx.pipe = copy_or_ref_table(frame.args, false)

	ctx.params = {}

	main_loop(ctx, context_iterate(ctx, 1))

	return ctx.text

end

]]--







	--[[ First-position-only functions ]]--

	---------------------------------------







-- Syntax:  #invoke:params|self

static_iface.self = function(frame)

	return frame:getParent():getTitle()

end







	--[[ Public metatable of functions ]]--

	---------------------------------------







return setmetatable(static_iface, {

	__index = function(iface, _fname_)

		local ctx = context_new()

		local fname = _fname_:match'^%s*(.*%S)'

		if fname == nil then error(ctx.luaname ..

			': You must specify a function to call', 0) end

		if libraryfname == nil then error(ctx.luaname ..

			': The function ‘' .. fname .. '’ does not exist', 0) end

		return function(frame)

			local func = libraryfname

			local refpipe = {

				count = true,

				value_of = true,

				list = true,

				list_values = true,

				for_each = true,

				call_for_each_group = true

			}

			local refparams = {

				--inserting = true,

				count = true,

				concat_and_call = true,

				concat_and_invoke = true,

				concat_and_magic = true,

				value_of = true,

				call_for_each_group = true

			}

			ctx.frame = frame:getParent()

			ctx.pipe = copy_or_ref_table(frame.args, refpipefname])

			ctx.params = copy_or_ref_table(ctx.frame.args, refparamsfname])

			main_loop(ctx, func)

			return ctx.text

		end

	end

})

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook