local getArgs = require('Module:Arguments').getArgs  local p = {}  local function error(text) 	return '*' .. require('Module:Error').error{ text, tag = 'p' } end   local function arr_contains(array, val)     for _, value in ipairs(array) do         if value == val then             return true         end     end     return false end  local function str_split(inputstr, sep)     local t = {}     for str in string.gmatch(inputstr, "([^"..sep.."]+)") do 		table.insert(t, str)     end     return t end  local function is_integer(str)  	if str:match("%D") then  		return false 	end  	return true end  local function trim(s)    return s:match("^%s*(.-)%s*$") end  -- Called from  function p.check_syntax(frame) 	local args = getArgs(frame) 	 	-- check that required parameters are provided 	if not args.sql then 		return error('Invalid config: required parameter "sql" is missing') 	end 	 	local deprecated_params = { 		['frequency'] = 'interval' 	} 	 	-- check for invalid parameters 	for param, _ in pairs(args) do 		if arr_contains(deprecated_params, param) then 			return error(param .. ' is deprecated, please use ' .. deprecated_params[param] .. ' instead') 		end 		if not arr_contains({ 			'sql', 'wikilinks', 'excerpts', 'comments', 'widths', 'hide', 'silent', 			'table_style', 'table_class', 'remove_underscores', 'pagination', 'output_page', 			'max_pages', 'interval', 'row_template', 'skip_table', 'header_template', 			'footer_template', 'row_template_named_params', 'postprocess_js' 		}, param) then 			return -- error('Unknown parameter "' .. param.. args[param] .. '" used, ignoring') 		end 	end 	 	-- check incompatible param combinations 	if not args.row_template then 		if args.skip_table then  			return error('Invalid config: skip_table can only be used with row_template') 		end  	end 	 	if args.output_page then 		if args.pagination then  			return error('pagination and output_page cannot be used together; output_page will be ignored') 		end 		local t1 = mw.title.getCurrentTitle() 		local t2 = mw.title.new(args.output_page) 		if t1.namespace ~= t2.namespace or t2.text:find(t1.text..'/', 1, true) ~= 1 then 			return error('output_page must be a subpage of the current page') 		end 	end  	-- check wikilinks config 	if args.wikilinks then 		local configs = str_split(args.wikilinks, ',') 		for _, config in ipairs(configs) do 			local parts = str_split(trim(config), ':') 			local srcColNum = parts[1] 			if not is_integer(srcColNum) then 				return error('Invalid wikilink config: Non-numeral source column number: '..parts[1]..'. Will be ignored.') 			end 			local ns = parts[2] 			if ns and ns:match("^c?%d+$") == nil then  				return error('Invalid namespace number "'.. ns..'" in wikilinks parameter: refer to WP:NS for namespace numbers, or use "cN" to take namespace number from column number N') 			end  		end  	end 	 	-- check excerpts config 	if args.excerpts then 		local configs = str_split(args.excerpts, ',') 		for _, config in ipairs(configs) do 			local parts = str_split(trim(config), ':') 			local srcColNum = parts[1] 			if not is_integer(srcColNum) then 				return error('Invalid excerpts config: Non-numeral source column number: '..parts[1]..'. Will be ignored.') 			end 			local dstColNum = parts[2] 			if dstColNum and not is_integer(dstColNum) then 				return error('Invalid excerpts config: Non-numeral destination column number: '..parts[2]..'. Will be ignored.') 			end 			local ns = parts[3] 			if ns and ns:match("^c?%d+$") == nil then  				return error('Invalid namespace number "'.. ns..'" in excerpts parameter: refer to WP:NS for namespace numbers, or use "cN" to take namespace number from column number N') 			end  			local charLimit = parts[4] 			if charLimit and not is_integer(charLimit) then  				return error('Invalid excerpts config: Non-numeral in charLimit: '..parts[4]..'. Will be ignored.') 			end  			local hardCharLimit = parts[5] 			if hardCharLimit and not is_integer(hardCharLimit) then  				return error('Invalid excerpts config: Non-numeral in hardCharLimit: '..parts[5]..'. Will be ignored.') 			end  		end  	end 	 	-- check column numbers in widths param 	if args.widths then 		local configs = str_split(args.widths, ',') 		for _, config in ipairs(configs) do  			local parts = str_split(trim(config), ':') 			local column = parts[1] 			if not is_integer(column) then 				return error('Invalid widths config: Non-numeral column number: '..parts[1]..'. Will be ignored.') 			end 		end  	end 	 	-- check numeric configs 	if args.comments then 		local columns = str_split(args.comments, ',') 		for _, column in ipairs(columns) do 			if not is_integer(trim(column)) then 				return error('Invalid comments parameter: Non-numeral column number: '..column..'. Will be ignored.') 			end 		end 	end 	if args.remove_underscores then 		local columns = str_split(args.remove_underscores, ',') 		for _, column in ipairs(columns) do 			if not is_integer(trim(column)) then 				return error('Invalid remove_underscores parameter: Non-numeral column number: '..column..'. Will be ignored.') 			end 		end 	end 	if args.hide then 		local columns = str_split(args.hide, ',') 		for _, column in ipairs(columns) do 			if not is_integer(trim(column)) then 				return error('Invalid hide parameter: Non-numeral column number: '..column..'. Will be ignored.') 			end 		end 	end 	if args.pagination and not is_integer(args.pagination) then  		return error('pagination should be an integer. Will be ignored.') 	end  	if args.max_pages and not is_integer(args.max_pages) then 		return error('max_pages should be an integer. Will be ignored.') 	end  	if args.interval and not is_integer(args.interval) then 		return error('interval should be an integer. Will be ignored.') 	end  	if args.row_template_named_params and not args.row_template then 		return error('row_template_named_params is only applicable when row_template is used') 	end 	 	return end  -- Called from  and   function p.navlinks(frame) 	local args = getArgs(frame) 	 	if args.page then 		local page = tonumber(args.page) 		local num_pages = tonumber(args.num_pages) 		 		local title = mw.title.getCurrentTitle() 		 		local nextPage = title.nsText..':'..title.baseText..'/'..(page + 1) 		local prevPage = title.nsText..':'..title.baseText..'/'..(page - 1) 		-- page 1 has no subpage name  		if page == 1 then  			nextPage = title.nsText..':'..title.text..'/2' 		elseif page == 2 then 			prevPage = title.nsText..':'..title.baseText  		end  		 		local prevPageText = '<< Previous page' 		local nextPageText = 'Next page >>' 		 		local prevPageLink = (page == 1 or page > num_pages + 1) and ''..prevPageText..'' 			or ''..prevPageText..'' 		local nextPageLink = page >= num_pages and ''..nextPageText..'' 			or ''..nextPageText..'' 		 		return prevPageLink..' || '..nextPageLink 	end 	return  end  return p