local p = {} local PrepareText = require("Module:Wikitext Parsing").PrepareText  local function getTitle(title) 	local success, titleObj = pcall(mw.title.new, title) 	if success then return titleObj 	else return nil end end  --string.gmatch will check the largest block it can without re-scanning whats inside, but we need whats inside local function matchAllTemplates(str) 	local matches = {} 	for template in string.gmatch(str, "{%b{}}") do 		table.insert(matches, template) 		local innerContent = string.sub(template, 3, -3) 		for _,subtemplate in next,matchAllTemplates(innerContent) do 			table.insert(matches, subtemplate) 		end 	end 	return matches end  --Forked version of getParameters from Module:Transcluder with extra features removed local function escapeString(str) 	return string.gsub(str, '[%^%$%(%)%.%[%]%*%+%-%?%%]', '%%%0') end local function getParameters(template) 	local parameters, parameterOrder = {}, {} 	local params = string.match(template, '{{[^|}]-|(.*)}}') 	if params then 		local count = 0 		-- Temporarily replace pipes in subtemplates and wikilinks to avoid chaos 		for subtemplate in string.gmatch(params, '{%b{}}') do 			params = string.gsub(params, escapeString(subtemplate), string.gsub(subtemplate, ".", {["%"]="%%", ["|"]="@@:@@", ["="]="@@_@@"}) ) 		end 		for wikilink in string.gmatch(params, '%[%b[]%]') do 			params = string.gsub(params, escapeString(wikilink), string.gsub(wikilink, ".", {["%"]="%%", ["|"]="@@:@@", ["="]="@@_@@"}) ) 		end 		for parameter in mw.text.gsplit(params, '|') do 			local parts = mw.text.split(parameter, '=') 			local key = mw.text.trim(parts[1]) 			local value 			if #parts == 1 then 				value = key 				count = count + 1 				key = tostring(count) 			else 				value = mw.text.trim(table.concat(parts, '=', 2)) 			end 			value = string.gsub(string.gsub(value, '@@:@@', '|'), '@@_@@', '=') 			key = string.gsub(string.gsub(key, '@@:@@', '|'), '@@_@@', '=') 			table.insert(parameterOrder, key) 			parameters[key] = value 		end 	end 	return parameters, parameterOrder end  -- Returns a table containing parameters and a table with the order in which each of their values were found. -- Since this considers all subtemplates, a single parameter is expected to have multiple values. -- E.g.  -- Would return {X={"", "Value", "Yes"}, Y={"Other value", "P"}} local function getAllParameters(template, ignore_blank, only_subtemplates) 	local parameterTree = setmetatable({}, { 		__index = function(self,key) 			rawset(self,key,{}) 			return rawget(self,key) 		end 	}) 	local params, paramOrder = getParameters(template) 	for _,key in ipairs(paramOrder) do 		local value = params[key] 		if not ignore_blank or value ~= "" then 			if not only_subtemplates then 				table.insert(parameterTree[key], value) --Insert the initial value into the tree 			end 			for subtemplate in string.gmatch(value, "{%b{}}") do --And now check for subvalues 				local subparams = getAllParameters(subtemplate, ignore_blank) 				for subkey,subset in next,subparams do 					for _,subvalue in ipairs(subset) do 						table.insert(parameterTree[subkey], subvalue) --And add any we find to our tree 					end 				end 			end 		end 	end 	return parameterTree end  --Module entry point. Returns a success boolean and either the target template or why it failed function p.getTemplate(page, templates, options) 	if not templates then --Required parameters 		return false, "Missing required parameter 'templates'" 	end 	options = options or {} 	 	local template_index = tonumber(options.template_index) or 1 	local treat_as_regex = options.treat_as_regex or false 	if type(templates) == "string" then 		-- TODO: Find a good way to allow specifying multiple templates via template invocation 		-- (Modules can just provide a table so no concerns there) 		-- Comma splitting is a bad idea (lots of templates have a comma in their name) 		templates = {templates} 	end 	 	local title = getTitle(page) 	if title == nil then 		return false, "Requested title doesn't exist" 	end 	local content = PrepareText(title:getContent() or "") 	 	local foundTemplates = 0 	for _,template in next,matchAllTemplates(content) do 		for _,wantedTemplate in pairs(templates) do 			if not treat_as_regex then 				wantedTemplate = escapeString(wantedTemplate) 			end 			local firstLetter = string.sub(wantedTemplate, 1, 1) 			local firstUpper, firstLower = firstLetter:upper(), firstLetter:lower() 			if firstUpper ~= firstLower then 				wantedTemplate = "[" .. firstUpper .. firstLower .. "]" .. string.sub(wantedTemplate, 2) 			end 			if string.match(template, "^{{%s*"..wantedTemplate.."%s*[|}]") then 				foundTemplates = foundTemplates + 1 				if foundTemplates == template_index then --Found our wanted template 					return true, template 				end 			end 		end 	end 	return false, "No valid template found" end  --Module entry point. Returns a success boolean and either the target parameter's value or why it failed function p.getParameter(page, templates, parameter, options) 	if not (templates and parameter) then --Required parameters 		return false, "Missing required parameters 'templates' and 'parameter'" 	end 	parameter = tostring(parameter) --Force consistency 	options = options or {} 	 	local success, text = p.getTemplate(page, templates, options) 	if not success then 		return success, text 	else 		local parameter_index = tonumber(options.parameter_index) or 1 		local ignore_subtemplates = options.ignore_subtemplates or false 		local only_subtemplates = options.only_subtemplates or false 		local ignore_blank = options.ignore_blank or false  		local value 		if ignore_subtemplates then 			value = getParameters(text)[parameter] or "" 		else 			local params = getAllParameters(text, ignore_blank, only_subtemplates) 			value = params[parameter][parameter_index] or "" 		end  		value = string.gsub(value, "</?%a*include%a*>", "") 		value = mw.text.trim(value) --technically wrong in some cases but not a big issue 		return true, mw.text.decode(value) --decode due to PrepareText 	end end  --Template entry point. Returns either "yes" or nothing depending on if the wanted template is found --Will return error text if no template is provided function p.hasTemplate(frame) 	local args = require('Module:Arguments').getArgs(frame) 	local yesno = require("Module:Yesno") 	local page = args[1] or args.page 	local template = args[2] or args.template 	local template_index = tonumber(args[3] or args.N) or 1 	if not template or template == "" then 		return 'No template provided for hasTemplate' 	end 	local follow = yesno(args.follow) or false 	if follow then 		page = require("Module:Redirect").luaMain(page) 	end 	local options = { 		template_index = template_index, 		treat_as_regex = yesno(args.treat_as_regex) or false, 	}  	local success, _ = p.getTemplate(page, template, options) 	return success and "yes" or "" end  --Template entry point for getParameter. Returns an empty string upon failure function p.main(frame) 	local args = require('Module:Arguments').getArgs(frame, { 		wrappers = 'টেমপ্লেট:টেমপ্লেট প্যারামিটার মান' 	}) 	local yesno = require("Module:Yesno") 	local options = { 		template_index = args[3] or args.template_index, 		parameter_index = args[5] or args.parameter_index, 		ignore_subtemplates = yesno(args.ignore_subtemplates or args.ist) or false, 		only_subtemplates = yesno(args.only_subtemplates) or false, 		ignore_blank = yesno(args.ignore_blank) or false, 		treat_as_regex = yesno(args.treat_as_regex) or false, 	} 	local page = args[1] or args.page 	local template = args[2] or args.template 	local parameter = args[4] or args.parameter 	local success, result = p.getParameter(page, template, parameter, options) 	if not success then 		return "" 	else 		if args.dontprocess then 			return result 		else 			return frame:preprocess(result) 		end 	end end  --Backwards compatability p.getValue = p.getParameter --Potentially useful module entry points p.matchAllTemplates = matchAllTemplates p.getParameters = getParameters p.getAllParameters = getAllParameters  return p