-- This module stores functions that are shared between Module:UserLinks -- and Module:UserLinks/extra.  -- Load data and define often-used variables local cfg = mw.loadData('Module:ব্যবহারকারী সংযোগ/কনফিগারেশন') local namespaces = mw.site.namespaces  -- Lazily initialise modules that we may or may not need local mCategoryHandler  -- Define namespaces for which links need to be escaped with the colon trick. -- See w:en:Help:Colon trick. local colonNamespaces = { 	[6] = true, -- File 	[14] = true, -- Category }  local p = {}  function p.maybeLoadModule(s) 	-- Attempts to load the module s. If it succeeds, returns the module; 	-- otherwise, returns false. 	local success, mdl = pcall(require, s) 	if success then 		return mdl 	else 		return false 	end end  function p.raiseError(message, section, level) 	-- Raises an error using the Lua error function. The error message is 	-- designed to be caught with pcall and then passed to p.makeWikitextError. 	-- The section, if specified, is the section name on a help page that gives 	-- help to users about that particular error. 	if section then 		message = message .. '|' .. section 	end 	if not level or level == 0 then 		level = 0 	else 		level = level + 1 	end 	error(message, level) end  local localBlacklist = { 	'/খেলাঘর$', -- Don't categorise sandboxes 	'/[sS]andbox$', -- Don't categorise sandboxes 	'/পরীক্ষা ?পাতা$', -- Don't categorise test case pages }  local function currentTitleMatchesLocalBlacklist() 	-- Return true if the current title matches any of the patterns in the 	-- local blacklist table. Otherwise return false. 	local title = mw.title.getCurrentTitle().prefixedText 	for i, pattern in ipairs(localBlacklist) do 		if title:find(pattern) then 			return true 		end 	end 	return false end  function p.makeWikitextError(encodedMessage, demo) 	local errorMessage, section = mw.ustring.match(encodedMessage, '^(.-)|(.*)$') 	errorMessage = errorMessage or encodedMessage 	 	-- If not a demo, get the error category link and pass it through 	-- Module:Category handler's blacklist. 	local category 	if not demo then 		category = string.format( 			'%s:%s', 			namespaces[14].name, 			p.message('error-config-category') 		) 		mCategoryHandler = p.maybeLoadModule('মডিউল:বিষয়শ্রেণী পরিচালনাকারী') 		if mCategoryHandler then 			-- Categorise all namespaces, but not blacklisted pages. 			category = mCategoryHandler.main{all = category} 		end 		if category and currentTitleMatchesLocalBlacklist() then 			category = nil 		end 	end 	category = category or 	 	-- Format the error message and the section link. 	local formattedError 	if section then 		formattedError = p.message( 			'error-config-message-help', 			errorMessage, 			section 		) 	else 		formattedError = p.message( 			'error-config-message-nohelp', 			errorMessage 		) 	end  	-- Return the error message and the category inside html error tags. 	return string.format( 		'%s%s', 		formattedError, 		category 	) end  local function formatPage(interwiki, namespace, page) 	-- Formats an interwiki, a namespace and a page into a wikilink-ready 	-- string. The interwiki and namespace are optional. If a namespace is 	-- specified, it should be a valid key to mw.site.namespaces. The page 	-- parameter is required. 	local ret = {} 	interwiki = interwiki or  	if interwiki ~=  or colonNamespaces[namespace] then 		ret[#ret + 1] = ':' 	end 	ret[#ret + 1] = interwiki 	if interwiki ~=  then 		ret[#ret + 1] = ':' 	end 	if namespace then 		local nsTable = namespaces[namespace] 		if not nsTable then 			error('"' .. tostring(namespace) .. '" কোন বৈধ নামস্থান চাবি নয়', 2) 		end 		ret[#ret + 1] = nsTable.name 		if namespace ~= 0 then 			ret[#ret + 1] = ':' 		end 	end 	ret[#ret + 1] = page 	return table.concat(ret) end  local function formatDisplay(s) 	-- Replaces spaces in a string with " " to make sure they don't wrap. 	-- Don't replace anything if we are substing, as we generally don't want 	-- to use " " in that case. 	if mw.isSubsting() then 		return s 	else 		return s:gsub(' ', ' ') 	end end  function p.makeWikilink(interwiki, namespace, page, display) 	-- Creates a wikilink. The interwiki, namespace and display parameters are 	-- optional. If a namespace parameter is specified it must be a valid key 	-- to mw.site.namespaces. 	local formattedPage = formatPage(interwiki, namespace, page) 	if display then 		display = formatDisplay(display) 		return string.format('%s', formattedPage, display) 	else 		return string.format('%s', formattedPage) 	end end  local function formatUrlLink(url, display) 	-- Formats a URL link with an optional display parameter. 	if display then 		display = formatDisplay(display) 		return string.format('[%s %s]', url, display) 	else 		return string.format('[%s]', url) 	end end  function p.makeUrlLink(s, display) 	-- Makes a URL link with an optional display parameter. The first input 	-- may be any valid input to mw.uri.new. 	local url = mw.uri.new(s) 	url = tostring(url) 	return formatUrlLink(url, display) end  function p.makeFullUrlLink(interwiki, namespace, page, query, display) 	-- Makes a link to the full URL of a page. The interwiki, namespace, query 	-- and display parameters are optional. If a namespace parameter is 	-- specified it must be a valid key to mw.site.namespaces. The query 	-- parameter can be a string or a table as specified in the mw.uri library. 	local formattedPage = formatPage(interwiki, namespace, page) 	local url = mw.uri.fullUrl(formattedPage, query) 	url = tostring(url) 	return formatUrlLink(url, display) end  function p.message(key, ...) 	-- Returns the message with the given key from Module:UserLinks/config. 	-- Extra parameters are substituted in the message for keys $1, $2, $3, etc. 	local msg = cfg[key] 	if not msg then 		p.raiseError( 			'"' .. tostring(key) .. '" চাবিসহ কোন বার্তা পাওয়া যায়নি', 			'কোন বার্তা পাওয়া যায়নি', 			2 		) 	end 	local noArgs = select('#', ...) 	if noArgs < 1 then 		return msg 	else 		local msg = mw.message.newRawMessage(msg, ...) 		return msg:plain() 	end end  return p