-- Module:Excerpt implements the Excerpt template -- Documentation and master version: https://en.wikipedia.org/wiki/Module:Excerpt -- Authors: User:Sophivorus, User:Certes, User:Aidan9382 & others -- License: CC-BY-SA-3.0  local Transcluder = require( 'Module:Transcluder' )  local yesno = require( 'Module:Yesno' )  local ok, config = pcall( require, 'মডিউল:অনুচ্ছেদ উদ্ধৃতি/কনফিগ' ) if not ok then config = {} end  local p = {}  -- Helper function to get arguments local args local function getArg( key, default ) 	local value = args[ key ] 	if value and mw.text.trim( value ) ~=  then 		return value 	end 	return default end  -- Helper function to handle errors local function getError( message, value ) 	if type( message ) == 'string' then 		message = Transcluder.getError( message, value ) 	end 	if config.categories and config.categories.errors and mw.title.getCurrentTitle().isContentPage then 		message:node( 'Category:' .. config.categories.errors .. '' ) 	end 	return message end  -- Helper function to get localized messages local function getMessage( key ) 	local ok, TNT = pcall( require, 'Module:TNT' ) 	if not ok then return key end 	return TNT.format( 'I18n/Module:Excerpt.tab', key ) end  -- Main entry point for templates function p.main( frame ) 	args = Transcluder.parseArgs( frame )  	-- Make sure the requested page exists 	local page = getArg( 1 ) 	if not page or page == '' then return getError( 'no-page' ) end 	local title = mw.title.new(page) 	if not title then return getError( 'invalid-title', page ) end 	if title.isRedirect then title = title.redirectTarget end 	if not title.exists then return getError( 'page-not-found', page ) end 	page = title.prefixedText  	-- Set variables from the template parameters 	local section = getArg( 2, mw.ustring.match( getArg( 1 ), '[^#]+#(.+)' ) ) 	local hat = yesno( getArg( 'hat', true ) ) 	local edit = yesno( getArg( 'edit', true ) ) 	local this = getArg( 'this' ) 	local only = getArg( 'only' ) 	local files = getArg( 'files', getArg( 'file', ( only == 'file' and 1 ) ) ) 	local lists = getArg( 'lists', getArg( 'list', ( only == 'list' and 1 ) ) ) 	local tables = getArg( 'tables', getArg( 'table', ( only == 'table' and 1 ) ) ) 	local templates = getArg( 'templates', getArg( 'template', ( only == 'template' and 1 ) ) ) 	local paragraphs = getArg( 'paragraphs', getArg( 'paragraph', ( only == 'paragraph' and 1 ) ) ) 	local references = getArg( 'references' ) 	local subsections = not yesno( getArg( 'subsections' ) ) 	local noLinks = not yesno( getArg( 'links', true ) ) 	local noBold = not yesno( getArg( 'bold' ) ) 	local onlyFreeFiles = yesno( getArg( 'onlyfreefiles', true ) ) 	local briefDates = yesno( getArg( 'briefdates', false ) ) 	local inline = yesno( getArg( 'inline' ) ) 	local quote = yesno( getArg( 'quote' ) ) 	local more = yesno( getArg( 'more' ) ) 	local class = getArg( 'class' ) 	local displaytitle = getArg( 'displaytitle' ) or page  	-- Build the hatnote 	if hat and not inline then 		if this then 			hat = this 		elseif quote then 			hat = getMessage( 'this' ) 		elseif only then 			hat = getMessage( only ) 		else 			hat = getMessage( 'section' ) 		end 		hat = hat .. ' ' .. getMessage( 'excerpt' ) .. ' ' 		if section then 			hat = hat .. '' .. displaytitle 				.. ' § ' .. mw.ustring.gsub( section, '%[%[([^]|]+)|?[^*%]%]', '%1' ) .. ']].' -- remove nested links 		else 			hat = hat .. '' .. displaytitle .. '.' 		end 		if edit then 			hat = hat .. '[[' 			hat = hat .. title:fullUrl( 'action=edit' ) .. ' ' .. mw.message.new( 'editsection' ):plain() 			hat = hat .. ']]' 		end 		if config.hat then 			hat = config.hat .. hat .. '}}' 			hat = frame:preprocess( hat ) 		else 			hat = mw.html.create( 'div' ):addClass( 'dablink excerpt-hat' ):wikitext( hat ) 		end 	else 		hat = nil 	end  	-- Build the "Read more" link 	if more and not inline then 		more = "'''[[" .. page .. '#' .. ( section or  ) .. "|" .. getMessage( 'more' ) .. "]]'" 		more = mw.html.create( 'div' ):addClass( 'noprint excerpt-more' ):wikitext( more ) 	else 		more = nil 	end  	-- Build the options for Module:Transcluder out of the template parameters and the desired defaults 	local options = { 		files = files, 		lists = lists, 		tables = tables, 		paragraphs = paragraphs, 		sections = subsections, 		categories = 0, 		references = references, 		only = only and mw.text.trim( only, 's' ) .. 's', 		noLinks = noLinks, 		noBold = noBold, 		noSelfLinks = true, 		noNonFreeFiles = onlyFreeFiles, 		noBehaviorSwitches = true, 		fixReferences = true, 		linkBold = true, 	}  	-- Get the excerpt itself 	local title = page .. '#' .. ( section or  ) 	local ok, excerpt = pcall( Transcluder.get, title, options ) 	if not ok then return getError( excerpt ) end 	if mw.text.trim( excerpt ) ==  and not only then 		if section then return getError( 'section-empty', section ) else return getError( 'lead-empty' ) end 	end  	-- Fix birth and death dates, but only in the first paragraph 	if briefDates then 		local startpos = 1 -- skip initial templates 		local s 		local e = 0 		repeat 			startpos = e + 1 			s, e = mw.ustring.find( excerpt, "%s*%b{}%s*", startpos ) 		until not s or s > startpos 		s, e = mw.ustring.find( excerpt, "%b()", startpos ) -- get (...), which may be (year–year) 		if s and s < startpos + 100 then -- look only near the start 			local year1, conjunction, year2 = mw.ustring.match( mw.ustring.sub( excerpt, s, e ), '(%d%d%d+)(.-)(%d%d%d+)' ) 			if year1 and year2 and (mw.ustring.match( conjunction, '[%-–—]' ) or mw.ustring.match( conjunction, '{{%s*[sS]nd%s*}}' )) then 				local y1 = tonumber(year1) 				local y2 = tonumber(year2) 				if y2 > y1 and y2 < y1 + 125 and y1 <= tonumber( os.date( "%Y" )) then 					excerpt = mw.ustring.sub( excerpt, 1, s ) .. year1 .. "–" .. year2 .. mw.ustring.sub( excerpt, e ) 				end 			end 		end 	end  	-- If no file was found, try to get one from the infobox 	local fileNamespaces = Transcluder.getNamespaces( 'চিত্র' ) 	if ( ( only == 'file' or only == 'files' ) or ( not only and ( files ~= '0' or not files ) ) ) and -- caller asked for files 		not Transcluder.matchAny( excerpt, '%[%[', fileNamespaces, ':' ) and -- and there are no files in Transcluder's output 		config.captions -- and we have the config option required to try finding files in templates 	then 		-- We cannot distinguish the infobox from the other templates so we search them all 		local infobox = Transcluder.getTemplates( excerpt ); 		infobox = table.concat( infobox ) 		local parameters = Transcluder.getParameters( infobox ) 		local file, captions, caption 		for _, pair in pairs( config.captions ) do 			file = pair[1] 			file = parameters[file] 			if file and Transcluder.matchAny( file, '^.*%.', { '[Jj][Pp][Ee]?[Gg]', '[Pp][Nn][Gg]', '[Gg][Ii][Ff]', '[Ss][Vv][Gg]' }, '.*' ) then 				file = mw.ustring.match( file, '%[?%[?.-:([^{|]+)%]?%]?' ) or file -- File:Example.jpgupright=1.5 to Example.jpg 				captions = pair[2] 				for _, p in pairs( captions ) do 					if parameters[ p ] then caption = parameters[ p ] break end 				end 				excerpt = '[[চিত্র:' .. file .. '|thumb|' .. ( caption or  ) .. ']]' .. excerpt 				if ( onlyFreeFiles ) then 					excerpt = Transcluder.removeNonFreeFiles( excerpt ) 				end 				break 			end 		end 	end  	-- Unlike other elements, templates are filtered here 	-- because we had to search the infoboxes for files 	local trash 	if only and ( only == 'template' or only == 'templates' ) then 		trash, excerpt = Transcluder.getTemplates( excerpt, templates ); 	else -- Remove blacklisted templates 		local blacklist = config.blacklist and table.concat( config.blacklist, ',' ) or 		if templates then 			if string.sub( templates, 1, 1 ) == '-' then --Unwanted templates. Append to blacklist 				blacklist = templates .. ',' .. blacklist 			else --Wanted templates. Replaces blacklist and acts as whitelist 				blacklist = templates 			end 		else 			blacklist = '-' .. blacklist 		end 		trash, excerpt = Transcluder.getTemplates( excerpt, blacklist ); 	end  	-- Remove extra line breaks but leave one before and after so the parser interprets lists, tables, etc. correctly 	excerpt = mw.text.trim( excerpt ) 	excerpt = string.gsub( excerpt, '\n\n\n+', '\n\n' ) 	excerpt = '\n' .. excerpt .. '\n'  	-- Remove nested categories 	excerpt = frame:preprocess( excerpt ) 	local categories, excerpt = Transcluder.getCategories( excerpt, options.categories )  	-- Add tracking categories 	if config.categories then 		local contentCategory = config.categories.content 		if contentCategory and mw.title.getCurrentTitle().isContentPage then 			excerpt = excerpt .. 'Category:' .. contentCategory .. '' 		end 		local namespaceCategory = config.categories[ mw.title.getCurrentTitle().namespace ] 		if namespaceCategory then 			excerpt = excerpt .. 'Category:' .. namespaceCategory .. '' 		end 	end  	-- Load the styles 	local styles 	if config.styles then 		styles = frame:extensionTag( 'templatestyles', , { src = config.styles } ) 	end  	-- Combine and return the elements 	if inline then 		return mw.text.trim( excerpt ) 	end 	local tag = 'div' 	if quote then 		tag = 'blockquote' 	end 	excerpt = mw.html.create( 'div' ):addClass( 'excerpt' ):wikitext( excerpt ) 	local block = mw.html.create( tag ):addClass( 'excerpt-block' ):addClass( class ) 	return block:node( styles ):node( hat ):node( excerpt ):node( more ) end  -- Entry points for backwards compatibility function p.lead( frame ) return p.main( frame ) end function p.excerpt( frame ) return p.main( frame ) end  return p