Nemo hanc paginam annexam adhuc scripsit. Interea, si alias linguas intellegis, eandem paginam sermone barbaro legere potes. Vel, si tibi placet, hanc paginam alio sermone scripta ad lingua Latinam vertere potes!


	---                                        ---
	---     LOCAL ENVIRONMENT                  ---
	---    ________________________________    ---
	---                                        ---


-- Special user-given keywords (functions and modifiers MUST avoid these names)
local mkeywords = {
--	['pattern'] = false,
	['plain'] = true,
	['or'] = 0
}


-- Set directives
local memoryslots = {
	i = 'itersep',
	l = 'lastsep',
	p = 'pairsep',
	h = 'header',
	f = 'footer',
	n = 'ifngiven'
}


-- The private table of functions
local library = {}


-- 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 newtab[key] = val end
	return newtab
end


-- Prepare the context
local function context_init(frame, funcname, refpipe, refparams)
	local ctx = {}
	ctx.luaname = 'Module:Params'	--[[ or `frame:getTitle()` ]]--
	ctx.iterfunc = pairs
	ctx.pipe = copy_or_ref_table(frame.args, refpipe)
	ctx.frame = frame:getParent()
	ctx.params = copy_or_ref_table(ctx.frame.args, refparams)
	return funcname(ctx)
end


-- Move to the next action within the user-given list
local function context_iterate(ctx, n_forward)
	local nextfn
	if ctx.pipe[n_forward] ~= nil then
		nextfn = ctx.pipe[n_forward]:match'^%s*(.*%S)'
	end
	if nextfn == nil then
		error(ctx.luaname .. ': You must specify a function to call', 0)
	end
	if library[nextfn] == nil then
		error(ctx.luaname .. ': The function ‘' .. nextfn .. '’ does not exist', 0)
	end
	for idx = n_forward, 1, -1 do table.remove(ctx.pipe, idx) end
	return library[nextfn](ctx)
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 shift = table.maxn(ctx.pipe) 
	local newargs = {}
	if ctx.subset == 1 then
		-- We need only the sequence
		for key, val in ipairs(ctx.params) do
			newargs[key + shift] = val
		end
	else
		if ctx.subset == -1 then
			for key, val in ipairs(ctx.params) do
				ctx.params[key] = nil
			end
		end
		for key, val in pairs(ctx.params) do
			if type(key) == 'number' then
				newargs[key + shift] = val
			else
				newargs[key] = val
			end
		end
	end
	for key, val in pairs(ctx.pipe) do newargs[key] = val end
	return newargs
end


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 tbl[key] = 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
				nums[nlen] = key
			else
				wlen = wlen + 1
				words[wlen] = key
			end

		end
		table.sort(nums)
		table.sort(words)
		for idx = 1, nlen do fn(nums[idx], tbl[nums[idx]]) end
		for idx = 1, wlen do fn(words[idx], tbl[words[idx]]) end
		return
	end
	if ctx.subset ~= -1 then
		for key, val in ipairs(tbl) do
			fn(key, val)
			tbl[key] = nil
		end
	end
	for key, val in pairs(tbl) do fn(key, val) end
end


-- Parse the arguments of the `with_*_matching` class of modifiers
local function parse_match_args(opts, ptns, fname)
	local state = 0
	local cnt = 1
	local keyw
	local nptns = 0
	for _, val in ipairs(opts) do
		if state == 0 then
			nptns = nptns + 1
			ptns[nptns] = { val, false }
			state = -1
		else
			keyw = val:match'^%s*(.*%S)'
			if keyw == nil or mkeywords[keyw] == nil then break
			else
				state = mkeywords[keyw]
				if state ~= 0 then ptns[nptns][2] = state end
			end
		end
		cnt = cnt + 1
	end
	if state == 0 then error(ctx.luaname .. ', ‘' .. fname .. '’: No pattern was given', 0) end
	return cnt
end



	--[[ Library's modifiers ]]--
	--------------------------------


-- See iface.sequential()
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


-- See iface['non-sequential']()
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


-- See iface.all_sorted()
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


-- See iface.setting()
library.setting = function(ctx)
	local opts = ctx.pipe
	local cmd
	if opts[1] ~= nil then
		cmd = opts[1]: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
				ctx[val] = opts[argc]
				dest[key] = nil
			end
			argc = argc + 1
		else
			vname = memoryslots[string.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 ctx[val] = opts[argc] end
	return context_iterate(ctx, argc + 1)
end


-- See iface.squeezing()
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
			indices[newlen] = key
			store[key] = val
			tbl[key] = nil
		end
	end
	table.sort(indices)
	for idx = 1, newlen do tbl[idx] = store[indices[idx]] end
	return context_iterate(ctx, 1)
end


-- See iface.cutting()
library.cutting = function(ctx)
	local lcut = tonumber(ctx.pipe[1])
	if lcut == nil then error(ctx.luaname .. ', ‘cutting’: Left cut must be a number', 0) end
	local rcut = tonumber(ctx.pipe[2])
	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, val in ipairs(tbl) do tbl[key] = nil end
			tot = len
		else
			for idx = len - rcut + 1, len, 1 do tbl[idx] = nil end
			for idx = 1, lcut, 1 do tbl[idx] = nil end
		end
		for key, val in pairs(tbl) do
			if type(key) == 'number' and key > 0 then
				if key > len then
					cache[key - tot] = val
				else
					cache[key - lcut] = val
				end
				tbl[key] = nil
			end
		end
		for key, val in pairs(cache) do tbl[key] = val end
	end
	return context_iterate(ctx, 3)
end


-- See iface.with_name_matching()
library.with_name_matching = function(ctx)
	local tbl = ctx.params
	local patterns = {}
	local argc = parse_match_args(ctx.pipe, patterns, 'with_name_matching')
	local nomatch
	for key in pairs(tbl) do
		nomatch = true
		for _, ptn in ipairs(patterns) do
			if string.find(key, ptn[1], 1, ptn[2]) then
				nomatch = false
				break
			end
		end
		if nomatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- See iface.with_name_not_matching()
library.with_name_not_matching = function(ctx)
	local tbl = ctx.params
	local patterns = {}
	local argc = parse_match_args(ctx.pipe, patterns,
		'with_name_not_matching')
	local yesmatch
	for key in pairs(tbl) do
		yesmatch = true
		for _, ptn in ipairs(patterns) do
			if not string.find(key, ptn[1], 1, ptn[2]) then
				yesmatch = false
				break
			end
		end
		if yesmatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- See iface.with_value_matching()
library.with_value_matching = function(ctx)
	local tbl = ctx.params
	local patterns = {}
	local argc = parse_match_args(ctx.pipe, patterns,
		'with_value_matching')
	local nomatch
	for key, val in pairs(tbl) do
		nomatch = true
		for _, ptn in ipairs(patterns) do
			if string.find(val, ptn[1], 1, ptn[2]) then
				nomatch = false
				break
			end
		end
		if nomatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- See iface.with_value_not_matching()
library.with_value_not_matching = function(ctx)
	local tbl = ctx.params
	local patterns = {}
	local argc = parse_match_args(ctx.pipe, patterns,
		'with_value_not_matching')
	local yesmatch
	for key, val in pairs(tbl) do
		yesmatch = true
		for _, ptn in ipairs(patterns) do
			if not string.find(val, ptn[1], 1, ptn[2]) then
				yesmatch = false
				break
			end
		end
		if yesmatch then tbl[key] = nil end
	end
	return context_iterate(ctx, argc)
end


-- See iface.trimming_values()
library.trimming_values = function(ctx)
	local tbl = ctx.params
	for key, val in pairs(tbl) do tbl[key] = val:match'^%s*(.-)%s*$' end
	return context_iterate(ctx, 1)
end


-- See iface.mapping_values_by_calling()
library.mapping_values_by_calling = function(ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(ctx.luaname .. ', ‘mapping_values_by_calling’: No template name was provided', 0) end
	local nargs
	local margs = {}
	local tmp = tonumber(opts[2])
	if tmp == nil then
		nargs = 1
	elseif tmp < 1 then
		nargs = 2
	else
		nargs = tmp + 2
		for idx = 3, nargs do margs[idx] = opts[idx] end
	end
	local model = { title = tname, args = margs }
	local tbl = ctx.params
	if ctx.subset == 1 then
		for key, val in ipairs(tbl) do
			margs[1] = key
			margs[2] = val
			tbl[key] = ctx.frame:expandTemplate(model)
		end
	elseif ctx.subset == -1 then
		tmp = {}
		for key, val in pairs(tbl) do tmp[key] = true end
		for key, val in ipairs(tmp) do tmp[key] = nil end
		for key in pairs(tmp) do
			margs[1] = key
			margs[2] = tbl[key]
			tbl[key] = ctx.frame:expandTemplate(model)
		end
	else
		for key, val in pairs(tbl) do
			margs[1] = key
			margs[2] = val
			tbl[key] = ctx.frame:expandTemplate(model)
		end

	end
	return context_iterate(ctx, nargs + 1)
end


-- See iface.mapping_values_by_invoking()
library.mapping_values_by_invoking = function(ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(ctx.luaname .. ', ‘mapping_values_by_invoking’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(ctx.luaname .. ', ‘mapping_values_by_invoking’: No function name was provided', 0) end
	local nargs
	local margs = {}
	local tmp = tonumber(opts[3])
	if tmp == nil then
		nargs = 2
	elseif tmp < 1 then
		nargs = 3
	else
		nargs = tmp + 3
		for idx = 4, nargs do margs[idx - 1] = opts[idx] end
	end
	local model = { title = 'Module:' .. mname, args = margs }
	local mfunc = require(model.title)[fname]
	local tbl = ctx.params
	if ctx.subset == 1 then
		for key, val in ipairs(tbl) do
			margs[1] = key
			margs[2] = val
			tbl[key] = mfunc(ctx.frame:newChild(model))
		end
	elseif ctx.subset == -1 then
		tmp = {}
		for key, val in pairs(tbl) do tmp[key] = true end
		for key, val in ipairs(tmp) do tmp[key] = nil end
		for key in pairs(tmp) do
			margs[1] = key
			margs[2] = tbl[key]
			tbl[key] = mfunc(ctx.frame:newChild(model))
		end
	else
		for key, val in pairs(tbl) do
			margs[1] = key
			margs[2] = val
			tbl[key] = mfunc(ctx.frame:newChild(model))
		end

	end
	return context_iterate(ctx, nargs + 1)
end


-- See iface.mapping_values_blindly_by_calling()
library.mapping_values_blindly_by_calling = function(ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_calling’: No template name was provided', 0) end
	local nargs
	local margs = {}
	local tmp = tonumber(opts[2])
	if tmp == nil then
		nargs = 1
	elseif tmp < 1 then
		nargs = 2
	else
		nargs = tmp + 2
		for idx = 3, nargs do margs[idx - 1] = opts[idx] end
	end
	local model = { title = tname, args = margs }
	local tbl = ctx.params
	if ctx.subset == 1 then
		for key, val in ipairs(tbl) do
			margs[1] = val
			tbl[key] = ctx.frame:expandTemplate(model)
		end
	elseif ctx.subset == -1 then
		tmp = {}
		for key, val in pairs(tbl) do tmp[key] = true end
		for key, val in ipairs(tmp) do tmp[key] = nil end
		for key in pairs(tmp) do
			margs[1] = tbl[key]
			tbl[key] = ctx.frame:expandTemplate(model)
		end
	else
		for key, val in pairs(tbl) do
			margs[1] = val
			tbl[key] = ctx.frame:expandTemplate(model)
		end

	end
	return context_iterate(ctx, nargs + 1)
end


-- See iface.mapping_values_blindly_by_invoking()
library.mapping_values_blindly_by_invoking = function(ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_invoking’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(ctx.luaname .. ', ‘mapping_values_blindly_by_invoking’: No function name was provided', 0) end
	local nargs
	local margs = {}
	local tmp = tonumber(opts[3])
	if tmp == nil then
		nargs = 2
	elseif tmp < 1 then
		nargs = 3
	else
		nargs = tmp + 3
		for idx = 4, nargs do margs[idx - 2] = opts[idx] end
	end
	local model = { title = 'Module:' .. mname, args = margs }
	local mfunc = require(model.title)[fname]
	local tbl = ctx.params
	if ctx.subset == 1 then
		for key, val in ipairs(tbl) do
			margs[1] = val
			tbl[key] = mfunc(ctx.frame:newChild(model))
		end
	elseif ctx.subset == -1 then
		tmp = {}
		for key, val in pairs(tbl) do tmp[key] = true end
		for key, val in ipairs(tmp) do tmp[key] = nil end
		for key in pairs(tmp) do
			margs[1] = tbl[key]
			tbl[key] = mfunc(ctx.frame:newChild(model))
		end
	else
		for key, val in pairs(tbl) do
			margs[1] = val
			tbl[key] = mfunc(ctx.frame:newChild(model))
		end

	end
	return context_iterate(ctx, nargs + 1)
end



	--[[ Library's functions ]]--
	------------------------------------


-- See iface.count()
library.count = function(ctx)
	local count = 0
	for _ in ctx.iterfunc(ctx.params) do count = count + 1 end
	if ctx.subset == -1 then count = count - #ctx.params end
	return count
end


-- See iface.concat_and_call()
library.concat_and_call = function(ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]:match'^%s*(.*%S)' end
	if tname == nil then error(ctx.luaname .. ', ‘concat_and_call’: No template name was provided', 0) end
	table.remove(opts, 1)
	return ctx.frame:expandTemplate{
		title = tname,
		args = concat_params(ctx)
	}
end


-- See iface.concat_and_invoke()
library.concat_and_invoke = function(ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(ctx.luaname .. ', ‘concat_and_invoke’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]:match'^%s*(.*%S)' end
	if fname == nil then error(ctx.luaname .. ', ‘concat_and_invoke’: No function name was provided', 0) end
	table.remove(opts, 2)
	table.remove(opts, 1)
	return require('Module:' .. mname)[fname](ctx.frame:newChild{
		title = 'Module:' .. fname,
		args = concat_params(ctx)
	})
end


-- See iface.concat_and_magic()
library.concat_and_magic = function(ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]:match'^%s*(.*%S)' end
	if magic == nil then error(ctx.luaname .. ', ‘concat_and_magic’: No parser function was provided', 0) end
	table.remove(opts, 1)
	return ctx.frame:callParserFunction(magic, concat_params(ctx))
end


-- See iface.value_of()
library.value_of = function(ctx)
	local opts = ctx.pipe
	local keystr
	if opts[1] ~= nil then keystr = opts[1]:match'^%s*(.*%S)' end
	if keystr == nil then error(ctx.luaname .. ', ‘value_of’: No parameter name was provided', 0) end
	local keynum = tonumber(keystr)
	local len = #ctx.params
	if (
		ctx.subset == -1 and keynum ~= nil and len >= keynum
	) or (
		ctx.subset == 1 and (keynum == nil or len < keynum)
	) then return (ctx.ifngiven or '') end
	local val = ctx.params[keynum or keystr]
	if val == nil then return (ctx.ifngiven or '') end
	return (ctx.header or '') .. val .. (ctx.footer or '')
end


-- See iface.list()
library.list = function(ctx)
	local kvs = ctx.pairsep or ''
	local pps = ctx.itersep or ''
	local ret = {}
	local nss = 0
	flush_params(
		ctx,
		function(key, val)
			ret[nss + 1] = pps
			ret[nss + 2] = key
			ret[nss + 3] = kvs
			ret[nss + 4] = val
			nss = nss + 4
		end
	)
	if nss > 0 then
		if nss > 4 and ctx.lastsep ~= nil then
			ret[nss - 3] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.list_values()
library.list_values = function(ctx)
	local pps = ctx.itersep or ''
	local ret = {}
	local nss = 0
	flush_params(
		ctx,
		function(key, val)
			ret[nss + 1] = pps
			ret[nss + 2] = val
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.for_each()
library.for_each = function(ctx)
	local txt = ctx.pipe[1] or ''
	local pps = ctx.itersep or ''
	local ret = {}
	local nss = 0
	flush_params(
		ctx,
		function(key, val)
			ret[nss + 1] = pps
			ret[nss + 2] = txt:gsub('%$#', key):gsub('%$@', val)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.call_for_each()
library.call_for_each = function(ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]: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)
			opts[1] = key
			opts[2] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:expandTemplate(model)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.invoke_for_each()
library.invoke_for_each = function(ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(ctx.luaname .. ', ‘invoke_for_each’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]: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)
			opts[1] = key
			opts[2] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = mfunc(ctx.frame:newChild(model))
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.magic_for_each()
library.magic_for_each = function(ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]: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)
			opts[1] = key
			opts[2] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:callParserFunction(magic,
				opts)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.call_for_each_value()
library.call_for_each_value = function(ctx)
	local opts = ctx.pipe
	local tname
	if opts[1] ~= nil then tname = opts[1]: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)
			opts[1] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:expandTemplate(model)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.invoke_for_each_value()
library.invoke_for_each_value = function(ctx)
	local opts = ctx.pipe
	local mname
	local fname
	if opts[1] ~= nil then mname = opts[1]:match'^%s*(.*%S)' end
	if mname == nil then error(ctx.luaname .. ', ‘invoke_for_each_value’: No module name was provided', 0) end
	if opts[2] ~= nil then fname = opts[2]: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
	table.remove(opts, 1)
	flush_params(
		ctx,
		function(key, val)
			opts[1] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = mfunc(ctx.frame:newChild(model))
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''

end


-- See iface.magic_for_each_value()
library.magic_for_each_value = function(ctx)
	local opts = ctx.pipe
	local magic
	if opts[1] ~= nil then magic = opts[1]: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)
			opts[1] = val
			ret[nss + 1] = ccs
			ret[nss + 2] = ctx.frame:callParserFunction(magic,
				opts)
			nss = nss + 2
		end
	)
	if nss > 0 then
		if nss > 2 and ctx.lastsep ~= nil then
			ret[nss - 1] = ctx.lastsep
		end
		ret[1] = ctx.header or ''
		if ctx.footer ~= nil then ret[nss + 1] = ctx.footer end
		return table.concat(ret)
	end
	return ctx.ifngiven or ''
end


-- See iface.self()
library.self = function(ctx)
	return ctx.frame:getTitle()
end



	---                                        ---
	---     PUBLIC ENVIRONMENT                 ---
	---    ________________________________    ---
	---                                        ---


-- The public table of functions
local iface = {}



	--[[ Modifiers ]]--
	------------------------------------


-- Syntax:  #invoke:params|sequential|function name
iface.sequential = function(frame)
	return context_init(frame, library.sequential, false, false)
end


-- Syntax:  #invoke:params|non-sequential|function name
iface['non-sequential'] = function(frame)
	return context_init(frame, library['non-sequential'], false, false)
end


-- Syntax:  #invoke:params|sort|function name
iface.all_sorted = function(frame)
	return context_init(frame, library.all_sorted, false, false)
end


-- Syntax:  #invoke:params|setting|directives|...|function name
iface.setting = function(frame)
	return context_init(frame, library.setting, false, false)
end


-- Syntax:  #invoke:params|squeezing|function name
iface.squeezing = function(frame)
	return context_init(frame, library.squeezing, false, false)
end


-- Syntax:  #invoke:params|cutting|left cut|right cut|function name
iface.cutting = function(frame)
	return context_init(frame, library.cutting, false, false)
end


-- Syntax:  #invoke:params|with_name_matching|pattern 1|[plain flag 1]|[or]
--            |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag
--            N]|function name
iface.with_name_matching = function(frame)
	return context_init(frame, library.with_name_matching, false, false)
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]|function name
iface.with_name_not_matching = function(frame)
	return context_init(frame, library.with_name_not_matching, false,
		false)
end


-- Syntax:  #invoke:params|with_value_matching|pattern 1|[plain flag 1]|[or]
--            |[pattern 2]|[plain flag 2]|[or]|[...]|[pattern N]|[plain flag
--            N]|function name
iface.with_value_matching = function(frame)
	return context_init(frame, library.with_value_matching, false, false)
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]|function name
iface.with_value_not_matching = function(frame)
	return context_init(frame, library.with_value_not_matching, false,
		false)
end


-- Syntax:  #invoke:params|trimming_values|function name
iface.trimming_values = function(frame)
	return context_init(frame, library.trimming_values, false, false)
end


-- Syntax:  #invoke:params|mapping_values_by_calling|template name|[number of additional
--            arguments]|[argument 1]|[argument 2]|[...]|[argument N]|function
--            name
iface.mapping_values_by_calling = function(frame)
	return context_init(frame, library.mapping_values_by_calling, false, false)
end


-- Syntax:  #invoke:params|mapping_values_by_invoking|module name|function name|[number of
--            additional arguments]|[argument 1]|[argument 2]|[...]|[argument
--            N]|function name
iface.mapping_values_by_invoking = function(frame)
	return context_init(frame, library.mapping_values_by_invoking, false, false)
end


-- Syntax:  #invoke:params|mapping_values_blindly_by_calling|template name|[number of
--            additional arguments]|[argument 1]|[argument 2]|[...]|[argument
--            N]|function name
iface.mapping_values_blindly_by_calling = function(frame)
	return context_init(frame, library.mapping_values_blindly_by_calling, false,
		false)
end


-- Syntax:  #invoke:params|mapping_values_blindly_by_invoking|module name|function name
--            |[number of additional arguments]|[argument 1]|[argument 2]|[...]
--            |[argument N]|function name
iface.mapping_values_blindly_by_invoking = function(frame)
	return context_init(frame, library.mapping_values_blindly_by_invoking, false,
		false)
end




	--[[ Functions ]]--
	----------------------------------------


-- Syntax:  #invoke:params|count
iface.count = function(frame)
	return context_init(frame, library.count, true, true)
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]|[...]
iface.concat_and_call = function(frame)
	return context_init(frame, library.concat_and_call, false, true)
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]|[...]
iface.concat_and_invoke = function(frame)
	return context_init(frame, library.concat_and_invoke, false, true)
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]|[...]
iface.concat_and_magic = function(frame)
	return context_init(frame, library.concat_and_magic, false, true)
end


-- Syntax:  #invoke:params|value_of|parameter name
iface.value_of = function(frame)
	return context_init(frame, library.value_of, true, true)
end


-- Syntax:  #invoke:params|list
iface.list = function(frame)
	return context_init(frame, library.list, true, false)
end


-- Syntax:  #invoke:params|list_values
iface.list_values = function(frame)
	return context_init(frame, library.list_values, true, false)
end


-- Syntax:  #invoke:params|for_each|wikitext
iface.for_each = function(frame)
	return context_init(frame, library.for_each, true, 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]|[...]
iface.call_for_each = function(frame)
	return context_init(frame, library.call_for_each, false, 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]|[...]
iface.invoke_for_each = function(frame)
	return context_init(frame, library.invoke_for_each, false, 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]|[...]
iface.magic_for_each = function(frame)
	return context_init(frame, library.magic_for_each, false, 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]|[...]
iface.call_for_each_value = function(frame)
	return context_init(frame, library.call_for_each_value, false, 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]|[...]
iface.invoke_for_each_value = function(frame)
	return context_init(frame, library.invoke_for_each_value, false, 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]|[...]
iface.magic_for_each_value = function(frame)
	return context_init(frame, library.magic_for_each_value, false, false)
end


-- Syntax:  #invoke:params|self
iface.self = function(frame)
	return frame:getParent():getTitle()
end


return iface