<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.cultopedia.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AExcerpt</id>
	<title>Module:Excerpt - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.cultopedia.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AExcerpt"/>
	<link rel="alternate" type="text/html" href="https://www.cultopedia.org/index.php?title=Module:Excerpt&amp;action=history"/>
	<updated>2026-04-06T05:46:52Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.5</generator>
	<entry>
		<id>https://www.cultopedia.org/index.php?title=Module:Excerpt&amp;diff=152&amp;oldid=prev</id>
		<title>imported&gt;Sophivorus: Add option to only get the filename of the first file, see Module talk:Excerpt#Feature request for file excerpts</title>
		<link rel="alternate" type="text/html" href="https://www.cultopedia.org/index.php?title=Module:Excerpt&amp;diff=152&amp;oldid=prev"/>
		<updated>2026-03-06T12:56:17Z</updated>

		<summary type="html">&lt;p&gt;Add option to only get the filename of the first file, see &lt;a href=&quot;/index.php?title=Module_talk:Excerpt&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Module talk:Excerpt (page does not exist)&quot;&gt;Module talk:Excerpt#Feature request for file excerpts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Module:Excerpt implements the Excerpt template&lt;br /&gt;
-- Documentation and master version: https://en.wikipedia.org/wiki/Module:Excerpt&lt;br /&gt;
-- Authors: User:Sophivorus, User:Certes, User:Aidan9382 &amp;amp; others&lt;br /&gt;
-- License: CC-BY-SA-3.0&lt;br /&gt;
&lt;br /&gt;
local parser = require( &amp;#039;Module:WikitextParser&amp;#039; )&lt;br /&gt;
local yesno = require( &amp;#039;Module:Yesno&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
local ok, config = pcall( require, &amp;#039;Module:Excerpt/config&amp;#039; )&lt;br /&gt;
if not ok then config = {} end&lt;br /&gt;
&lt;br /&gt;
local Excerpt = {}&lt;br /&gt;
&lt;br /&gt;
-- Main entry point for templates&lt;br /&gt;
function Excerpt.main( frame )&lt;br /&gt;
&lt;br /&gt;
	-- Make sure the requested page exists and get the wikitext&lt;br /&gt;
	local page = Excerpt.getArg( 1 )&lt;br /&gt;
	if not page or page == &amp;#039;{{{1}}}&amp;#039; then return Excerpt.getError( &amp;#039;no-page&amp;#039; ) end&lt;br /&gt;
	local title = mw.title.new( page )&lt;br /&gt;
	if not title then return Excerpt.getError( &amp;#039;invalid-title&amp;#039;, page ) end&lt;br /&gt;
	local fragment = title.fragment -- save for later&lt;br /&gt;
	if title.isRedirect then&lt;br /&gt;
		title = title.redirectTarget&lt;br /&gt;
		if fragment == &amp;quot;&amp;quot; then&lt;br /&gt;
			fragment = title.fragment -- page merge potential	&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not title.exists then return Excerpt.getError( &amp;#039;page-not-found&amp;#039;, page ) end&lt;br /&gt;
	page = title.prefixedText&lt;br /&gt;
	local wikitext = title:getContent()&lt;br /&gt;
&lt;br /&gt;
	-- Get the template params and process them&lt;br /&gt;
	local params = {&lt;br /&gt;
		hat = yesno( Excerpt.getArg( &amp;#039;hat&amp;#039;, true ) ),&lt;br /&gt;
		this = Excerpt.getArg( &amp;#039;this&amp;#039; ),&lt;br /&gt;
		only = Excerpt.getArg( &amp;#039;only&amp;#039; ),&lt;br /&gt;
		files = Excerpt.getArg( &amp;#039;files&amp;#039;, Excerpt.getArg( &amp;#039;file&amp;#039; ) ),&lt;br /&gt;
		lists = Excerpt.getArg( &amp;#039;lists&amp;#039;, Excerpt.getArg( &amp;#039;list&amp;#039; ) ),&lt;br /&gt;
		tables = Excerpt.getArg( &amp;#039;tables&amp;#039;, Excerpt.getArg( &amp;#039;table&amp;#039; ) ),&lt;br /&gt;
		templates = Excerpt.getArg( &amp;#039;templates&amp;#039;, Excerpt.getArg( &amp;#039;template&amp;#039; ) ),&lt;br /&gt;
		paragraphs = Excerpt.getArg( &amp;#039;paragraphs&amp;#039;, Excerpt.getArg( &amp;#039;paragraph&amp;#039; ) ),&lt;br /&gt;
		references = yesno( Excerpt.getArg( &amp;#039;references&amp;#039;, true ) ),&lt;br /&gt;
		subsections = yesno( Excerpt.getArg( &amp;#039;subsections&amp;#039;, false ) ),&lt;br /&gt;
		links = yesno( Excerpt.getArg( &amp;#039;links&amp;#039;, true ) ),&lt;br /&gt;
		bold = yesno( Excerpt.getArg( &amp;#039;bold&amp;#039;, false ) ),&lt;br /&gt;
		briefDates = yesno( Excerpt.getArg( &amp;#039;briefdates&amp;#039;, false ) ),&lt;br /&gt;
		inline = yesno( Excerpt.getArg( &amp;#039;inline&amp;#039; ) ),&lt;br /&gt;
		quote = yesno( Excerpt.getArg( &amp;#039;quote&amp;#039; ) ),&lt;br /&gt;
		more = yesno( Excerpt.getArg( &amp;#039;more&amp;#039; ) ),&lt;br /&gt;
		class = Excerpt.getArg( &amp;#039;class&amp;#039; ),&lt;br /&gt;
		track = yesno( Excerpt.getArg( &amp;#039;track&amp;#039;, true ) ),&lt;br /&gt;
		displayTitle = Excerpt.getArg( &amp;#039;displaytitle&amp;#039;, page ),&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	-- Make sure the requested section exists and get the excerpt&lt;br /&gt;
	local excerpt&lt;br /&gt;
	local section = Excerpt.getArg( 2, fragment )&lt;br /&gt;
	section = mw.text.trim( section )&lt;br /&gt;
	if section == &amp;#039;&amp;#039; then section = nil end&lt;br /&gt;
	if section then&lt;br /&gt;
		excerpt = parser.getSectionTag( wikitext, section )&lt;br /&gt;
		if not excerpt then&lt;br /&gt;
			if params.subsections then&lt;br /&gt;
				excerpt = parser.getSection( wikitext, section )&lt;br /&gt;
			else&lt;br /&gt;
				local sections = parser.getSections( wikitext )&lt;br /&gt;
				excerpt = sections[ section ]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if not excerpt then return Excerpt.getError( &amp;#039;section-not-found&amp;#039;, section ) end&lt;br /&gt;
		if excerpt == &amp;#039;&amp;#039; then return Excerpt.getError( &amp;#039;section-empty&amp;#039;, section ) end&lt;br /&gt;
	else&lt;br /&gt;
		excerpt = parser.getLead( wikitext )&lt;br /&gt;
		if excerpt == &amp;#039;&amp;#039; then return Excerpt.getError( &amp;#039;lead-empty&amp;#039; ) end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove noinclude bits&lt;br /&gt;
	excerpt = excerpt:gsub( &amp;#039;&amp;lt;[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]&amp;gt;.-&amp;lt;/[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]&amp;gt;&amp;#039;, &amp;#039;&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
	-- Filter various elements from the excerpt&lt;br /&gt;
	excerpt = Excerpt.filterFiles( excerpt, params.files )&lt;br /&gt;
	excerpt = Excerpt.filterLists( excerpt, params.lists )&lt;br /&gt;
	excerpt = Excerpt.filterTables( excerpt, params.tables )&lt;br /&gt;
	excerpt = Excerpt.filterParagraphs( excerpt, params.paragraphs )&lt;br /&gt;
&lt;br /&gt;
	-- If no file is found, try to get one from the infobox&lt;br /&gt;
	if ( params.only == &amp;#039;file&amp;#039; or params.only == &amp;#039;files&amp;#039; or params.only == &amp;#039;filename&amp;#039; or not params.only and ( not params.files or params.files ~= &amp;#039;0&amp;#039; ) ) -- caller asked for files&lt;br /&gt;
		and not section -- and we&amp;#039;re in the lead section&lt;br /&gt;
		and config.captions -- and we have the config option required to try finding files in infoboxes&lt;br /&gt;
		and #parser.getFiles( excerpt ) == 0 -- and there&amp;#039;re no files in the excerpt&lt;br /&gt;
	then&lt;br /&gt;
		excerpt = Excerpt.addInfoboxFile( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Filter the templates by appending the templates blacklist to the templates filter&lt;br /&gt;
	if config.blacklist then&lt;br /&gt;
		local blacklist = table.concat( config.blacklist, &amp;#039;,&amp;#039; )&lt;br /&gt;
		if params.templates then&lt;br /&gt;
			if string.sub( params.templates, 1, 1 ) == &amp;#039;-&amp;#039; then&lt;br /&gt;
				params.templates = params.templates .. &amp;#039;,&amp;#039; .. blacklist&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			params.templates = &amp;#039;-&amp;#039; .. blacklist&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	excerpt = Excerpt.filterTemplates( excerpt, params.templates )&lt;br /&gt;
&lt;br /&gt;
	-- Leave only the requested elements&lt;br /&gt;
	if params.only == &amp;#039;file&amp;#039; or params.only == &amp;#039;files&amp;#039; then&lt;br /&gt;
		local files = parser.getFiles( excerpt )&lt;br /&gt;
		excerpt = params.only == &amp;#039;file&amp;#039; and files[1] or table.concat( files, &amp;#039;\n\n&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if params.only == &amp;#039;list&amp;#039; or params.only == &amp;#039;lists&amp;#039; then&lt;br /&gt;
		local lists = parser.getLists( excerpt )&lt;br /&gt;
		excerpt = params.only == &amp;#039;list&amp;#039; and lists[1] or table.concat( lists, &amp;#039;\n\n&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if params.only == &amp;#039;table&amp;#039; or params.only == &amp;#039;tables&amp;#039; then&lt;br /&gt;
		local tables = parser.getTables( excerpt )&lt;br /&gt;
		excerpt = params.only == &amp;#039;table&amp;#039; and tables[1] or table.concat( tables, &amp;#039;\n\n&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if params.only == &amp;#039;paragraph&amp;#039; or params.only == &amp;#039;paragraphs&amp;#039; then&lt;br /&gt;
		local paragraphs = parser.getParagraphs( excerpt )&lt;br /&gt;
		excerpt = params.only == &amp;#039;paragraph&amp;#039; and paragraphs[1] or table.concat( paragraphs, &amp;#039;\n\n&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if params.only == &amp;#039;template&amp;#039; or params.only == &amp;#039;templates&amp;#039; then&lt;br /&gt;
		local templates = parser.getTemplates( excerpt )&lt;br /&gt;
		excerpt = params.only == &amp;#039;template&amp;#039; and templates[1] or table.concat( templates, &amp;#039;\n\n&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if params.only == &amp;#039;filename&amp;#039; then&lt;br /&gt;
		local files = parser.getFiles( excerpt )&lt;br /&gt;
		local file = files[1]&lt;br /&gt;
		excerpt = file and parser.getFileName( file ) or &amp;#039;Noimage.png&amp;#039;&lt;br /&gt;
		params.inline = true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- @todo Make more robust and move downwards&lt;br /&gt;
	if params.briefDates then&lt;br /&gt;
		excerpt = Excerpt.fixDates( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove unwanted elements&lt;br /&gt;
	excerpt = Excerpt.removeComments( excerpt )&lt;br /&gt;
	excerpt = Excerpt.removeSelfLinks( excerpt )&lt;br /&gt;
	excerpt = Excerpt.removeNonFreeFiles( excerpt )&lt;br /&gt;
	excerpt = Excerpt.removeBehaviorSwitches( excerpt )&lt;br /&gt;
&lt;br /&gt;
	-- Fix or remove the references&lt;br /&gt;
	if params.references then&lt;br /&gt;
		excerpt = Excerpt.fixReferences( excerpt, page, wikitext )&lt;br /&gt;
	else&lt;br /&gt;
		excerpt = Excerpt.removeReferences( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove wikilinks&lt;br /&gt;
	if not params.links then&lt;br /&gt;
		excerpt = Excerpt.removeLinks( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Link the bold text near the start of most leads and then remove it&lt;br /&gt;
	if not section then&lt;br /&gt;
		excerpt = Excerpt.linkBold( excerpt, page )&lt;br /&gt;
	end&lt;br /&gt;
	if not params.bold then&lt;br /&gt;
		excerpt = Excerpt.removeBold( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove extra line breaks but leave one before and after so the parser interprets lists, tables, etc. correctly&lt;br /&gt;
	excerpt = excerpt:gsub( &amp;#039;\n\n\n+&amp;#039;, &amp;#039;\n\n&amp;#039; )&lt;br /&gt;
	excerpt = mw.text.trim( excerpt )&lt;br /&gt;
	excerpt = &amp;#039;\n&amp;#039; .. excerpt .. &amp;#039;\n&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	-- Remove nested categories&lt;br /&gt;
	excerpt = frame:preprocess( excerpt )&lt;br /&gt;
	excerpt = Excerpt.removeCategories( excerpt )&lt;br /&gt;
&lt;br /&gt;
	-- Add tracking categories&lt;br /&gt;
	if params.track and config.categories then&lt;br /&gt;
		excerpt = Excerpt.addTrackingCategories( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Build the final output&lt;br /&gt;
	if params.inline then&lt;br /&gt;
		return mw.text.trim( excerpt )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tag = params.quote and &amp;#039;blockquote&amp;#039; or &amp;#039;div&amp;#039;&lt;br /&gt;
	local block = mw.html.create( tag ):addClass( &amp;#039;excerpt-block&amp;#039; ):addClass( params.class )&lt;br /&gt;
&lt;br /&gt;
	if config.styles then&lt;br /&gt;
		local styles = frame:extensionTag( &amp;#039;templatestyles&amp;#039;, &amp;#039;&amp;#039;, { src = config.styles } )&lt;br /&gt;
		block:node( styles )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if params.hat then&lt;br /&gt;
		local hat = Excerpt.getHat( page, section, params )&lt;br /&gt;
		block:node( hat )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	excerpt = mw.html.create( &amp;#039;div&amp;#039; ):addClass( &amp;#039;excerpt&amp;#039; ):wikitext( excerpt )&lt;br /&gt;
	block:node( excerpt )&lt;br /&gt;
&lt;br /&gt;
	if params.more then&lt;br /&gt;
		local more = Excerpt.getReadMore( page, section )&lt;br /&gt;
		block:node( more )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return block&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Filter the files in the given wikitext against the given filter&lt;br /&gt;
function Excerpt.filterFiles( wikitext, filter )&lt;br /&gt;
	if not filter then return wikitext end&lt;br /&gt;
	local filters, isBlacklist = Excerpt.parseFilter( filter )&lt;br /&gt;
	local files = parser.getFiles( wikitext )&lt;br /&gt;
	for index, file in pairs( files ) do&lt;br /&gt;
		local name = parser.getFileName( file )&lt;br /&gt;
		if isBlacklist and ( Excerpt.matchFilter( index, filters ) or Excerpt.matchFilter( name, filters ) )&lt;br /&gt;
		or not isBlacklist and ( not Excerpt.matchFilter( index, filters ) and not Excerpt.matchFilter( name, filters ) ) then &lt;br /&gt;
			wikitext = Excerpt.removeString( wikitext, file )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Filter the lists in the given wikitext against the given filter&lt;br /&gt;
function Excerpt.filterLists( wikitext, filter )&lt;br /&gt;
	if not filter then return wikitext end&lt;br /&gt;
	local filters, isBlacklist = Excerpt.parseFilter( filter )&lt;br /&gt;
	local lists = parser.getLists( wikitext )&lt;br /&gt;
	for index, list in pairs( lists ) do&lt;br /&gt;
		if isBlacklist and Excerpt.matchFilter( index, filters )&lt;br /&gt;
		or not isBlacklist and not Excerpt.matchFilter( index, filters ) then &lt;br /&gt;
			wikitext = Excerpt.removeString( wikitext, list )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Filter the tables in the given wikitext against the given filter&lt;br /&gt;
function Excerpt.filterTables( wikitext, filter )&lt;br /&gt;
	if not filter then return wikitext end&lt;br /&gt;
	local filters, isBlacklist = Excerpt.parseFilter( filter )&lt;br /&gt;
	local tables = parser.getTables( wikitext )&lt;br /&gt;
	for index, tableWikitext in pairs( tables ) do&lt;br /&gt;
		local id = parser.getTableAttribute( tableWikitext, &amp;#039;id&amp;#039; )&lt;br /&gt;
		if isBlacklist and ( Excerpt.matchFilter( index, filters ) or Excerpt.matchFilter( id, filters ) )&lt;br /&gt;
		or not isBlacklist and ( not Excerpt.matchFilter( index, filters ) and not Excerpt.matchFilter( id, filters ) ) then &lt;br /&gt;
			wikitext = Excerpt.removeString( wikitext, tableWikitext )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Filter the paragraphs in the given wikitext against the given filter&lt;br /&gt;
function Excerpt.filterParagraphs( wikitext, filter )&lt;br /&gt;
	if not filter then return wikitext end&lt;br /&gt;
	local filters, isBlacklist = Excerpt.parseFilter( filter )&lt;br /&gt;
	local paragraphs = parser.getParagraphs( wikitext )&lt;br /&gt;
	for index, paragraph in pairs( paragraphs ) do&lt;br /&gt;
		if isBlacklist and Excerpt.matchFilter( index, filters )&lt;br /&gt;
		or not isBlacklist and not Excerpt.matchFilter( index, filters ) then &lt;br /&gt;
			wikitext = Excerpt.removeString( wikitext, paragraph )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Filter the templates in the given wikitext against the given filter&lt;br /&gt;
function Excerpt.filterTemplates( wikitext, filter )&lt;br /&gt;
	if not filter then return wikitext end&lt;br /&gt;
	local filters, isBlacklist = Excerpt.parseFilter( filter )&lt;br /&gt;
	local templates = parser.getTemplates( wikitext )&lt;br /&gt;
	for index, template in pairs( templates ) do&lt;br /&gt;
		local name = parser.getTemplateName( template )&lt;br /&gt;
		if isBlacklist and ( Excerpt.matchFilter( index, filters ) or Excerpt.matchFilter( name, filters ) )&lt;br /&gt;
		or not isBlacklist and ( not Excerpt.matchFilter( index, filters ) and not Excerpt.matchFilter( name, filters ) ) then &lt;br /&gt;
			wikitext = Excerpt.removeString( wikitext, template )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.addInfoboxFile( excerpt )&lt;br /&gt;
	-- We cannot distinguish the infobox from the other templates, so we search them all&lt;br /&gt;
	local templates = parser.getTemplates( excerpt )&lt;br /&gt;
	for _, template in pairs( templates ) do&lt;br /&gt;
		local parameters = parser.getTemplateParameters( template )&lt;br /&gt;
		local file, captions, caption, cssClasses, cssClass&lt;br /&gt;
		for _, pair in pairs( config.captions ) do&lt;br /&gt;
			file = pair[1]&lt;br /&gt;
			file = parameters[file]&lt;br /&gt;
			if file and Excerpt.matchAny( file, &amp;#039;^.*%.&amp;#039;, { &amp;#039;[Jj][Pp][Ee]?[Gg]&amp;#039;, &amp;#039;[Pp][Nn][Gg]&amp;#039;, &amp;#039;[Gg][Ii][Ff]&amp;#039;, &amp;#039;[Ss][Vv][Gg]&amp;#039; }, &amp;#039;.*&amp;#039; ) then&lt;br /&gt;
				file = string.match( file, &amp;#039;%[?%[?.-:([^{|]+)%]?%]?&amp;#039; ) or file -- [[File:Example.jpg{{!}}upright=1.5]] to Example.jpg&lt;br /&gt;
				captions = pair[2]&lt;br /&gt;
				for _, p in pairs( captions ) do&lt;br /&gt;
					if parameters[ p ] then caption = parameters[ p ] break end&lt;br /&gt;
				end&lt;br /&gt;
				-- Check for CSS classes&lt;br /&gt;
				-- We opt to use skin-invert-image instead of skin-invert&lt;br /&gt;
				-- in all other cases, the CSS provided in the infobox is used&lt;br /&gt;
				if pair[3] then&lt;br /&gt;
					cssClasses = pair[3]&lt;br /&gt;
					for _, p in pairs( cssClasses ) do&lt;br /&gt;
						if parameters[ p ] then&lt;br /&gt;
							cssClass = ( parameters[ p ] == &amp;#039;skin-invert&amp;#039; ) and &amp;#039;skin-invert-image&amp;#039; or parameters[ p ]&lt;br /&gt;
							break&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				local class = cssClass and ( &amp;#039;|class=&amp;#039; .. cssClass ) or &amp;#039;&amp;#039;&lt;br /&gt;
				return &amp;#039;[[File:&amp;#039; .. file .. class .. &amp;#039;|thumb|&amp;#039; .. ( caption or &amp;#039;&amp;#039; ) .. &amp;#039;]]\n&amp;#039; .. excerpt&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeNonFreeFiles( wikitext )&lt;br /&gt;
	local files = parser.getFiles( wikitext )&lt;br /&gt;
	for _, file in pairs( files ) do&lt;br /&gt;
		local fileName = &amp;#039;File:&amp;#039; .. parser.getFileName( file )&lt;br /&gt;
		local fileTitle = mw.title.new( fileName )&lt;br /&gt;
		if fileTitle then&lt;br /&gt;
			local fileDescription = fileTitle:getContent()&lt;br /&gt;
			if not fileDescription or fileDescription == &amp;#039;&amp;#039; then&lt;br /&gt;
				local frame = mw.getCurrentFrame()&lt;br /&gt;
				fileDescription = frame:preprocess( &amp;#039;{{&amp;#039; .. fileName .. &amp;#039;}}&amp;#039; ) -- try Commons&lt;br /&gt;
			end&lt;br /&gt;
			if fileDescription and string.match( fileDescription, &amp;#039;[Nn]on%-free&amp;#039; ) then&lt;br /&gt;
				wikitext = Excerpt.removeString( wikitext, file )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.getHat( page, section, params )&lt;br /&gt;
	local hat&lt;br /&gt;
&lt;br /&gt;
	-- Build the text&lt;br /&gt;
	if params.this then&lt;br /&gt;
		hat = params.this&lt;br /&gt;
	elseif params.quote then&lt;br /&gt;
		hat = Excerpt.getMessage( &amp;#039;this&amp;#039; )&lt;br /&gt;
	elseif params.only then&lt;br /&gt;
		hat = Excerpt.getMessage( params.only )&lt;br /&gt;
	else&lt;br /&gt;
		hat = Excerpt.getMessage( &amp;#039;section&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	hat = hat .. &amp;#039; &amp;#039; .. Excerpt.getMessage( &amp;#039;excerpt&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
	-- Build the link&lt;br /&gt;
	if section then&lt;br /&gt;
		hat = hat .. &amp;#039; [[:&amp;#039; .. page .. &amp;#039;#&amp;#039; .. mw.uri.anchorEncode( section ) .. &amp;#039;|&amp;#039; .. params.displayTitle&lt;br /&gt;
			.. &amp;#039; § &amp;#039; .. section:gsub( &amp;#039;%[%[([^]|]+)|?[^]]*%]%]&amp;#039;, &amp;#039;%1&amp;#039; ) .. &amp;#039;]].&amp;#039; -- remove nested links&lt;br /&gt;
	else&lt;br /&gt;
		hat = hat .. &amp;#039; [[:&amp;#039; .. page .. &amp;#039;|&amp;#039; .. params.displayTitle .. &amp;#039;]].&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Build the edit link&lt;br /&gt;
	local title = mw.title.new( page )&lt;br /&gt;
	local editUrl = title:fullUrl( &amp;#039;action=edit&amp;#039; )&lt;br /&gt;
	hat = hat .. &amp;#039;&amp;lt;span class=&amp;quot;mw-editsection-like plainlinks&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;mw-editsection-bracket&amp;quot;&amp;gt;[&amp;lt;/span&amp;gt;[&amp;#039;&lt;br /&gt;
	hat = hat .. editUrl .. &amp;#039; &amp;#039; .. mw.message.new( &amp;#039;editsection&amp;#039; ):plain()&lt;br /&gt;
	hat = hat .. &amp;#039;]&amp;lt;span class=&amp;quot;mw-editsection-bracket&amp;quot;&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	if config.hat then&lt;br /&gt;
		local frame = mw.getCurrentFrame()&lt;br /&gt;
		hat = config.hat .. hat .. &amp;#039;}}&amp;#039;&lt;br /&gt;
		hat = frame:preprocess( hat )&lt;br /&gt;
	else&lt;br /&gt;
		hat = mw.html.create( &amp;#039;div&amp;#039; ):addClass( &amp;#039;dablink excerpt-hat&amp;#039; ):wikitext( hat )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return hat&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.getReadMore( page, section )&lt;br /&gt;
	local link = &amp;quot;&amp;#039;&amp;#039;&amp;#039;[[&amp;quot; .. page&lt;br /&gt;
	if section then&lt;br /&gt;
		link = link .. &amp;#039;#&amp;#039; .. section&lt;br /&gt;
	end&lt;br /&gt;
	local text = Excerpt.getMessage( &amp;#039;more&amp;#039; )&lt;br /&gt;
	link = link .. &amp;#039;|&amp;#039; .. text .. &amp;quot;]]&amp;#039;&amp;#039;&amp;#039;&amp;quot;&lt;br /&gt;
	link = mw.html.create( &amp;#039;div&amp;#039; ):addClass( &amp;#039;noprint excerpt-more&amp;#039; ):wikitext( link )&lt;br /&gt;
	return link&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Fix birth and death dates, but only in the first paragraph&lt;br /&gt;
-- @todo Use parser.getParagraphs() to get the first paragraph&lt;br /&gt;
function Excerpt.fixDates( excerpt )&lt;br /&gt;
	local start&lt;br /&gt;
	local s&lt;br /&gt;
	local e = 0&lt;br /&gt;
	repeat&lt;br /&gt;
		start = e + 1&lt;br /&gt;
		s, e = mw.ustring.find( excerpt, &amp;#039;%s*%b{}%s*&amp;#039;, start )&lt;br /&gt;
	until not s or s &amp;gt; start&lt;br /&gt;
	s, e = mw.ustring.find( excerpt, &amp;#039;%b()&amp;#039;, start ) -- get (...), which may be (year–year)&lt;br /&gt;
	if s and s &amp;lt; start + 100 then -- look only near the start&lt;br /&gt;
		local excerptStart = mw.ustring.sub( excerpt, s, e )&lt;br /&gt;
		local year1, conjunction, year2 = string.match( excerptStart, &amp;#039;(%d%d%d+)(.-)(%d%d%d+)&amp;#039; )&lt;br /&gt;
		if year1 and year2 and ( string.match( conjunction, &amp;#039;[%-–—]&amp;#039; ) or string.match( conjunction, &amp;#039;{{%s*[sS]nd%s*}}&amp;#039; ) ) then&lt;br /&gt;
			local y1 = tonumber( year1 )&lt;br /&gt;
			local y2 = tonumber( year2 )&lt;br /&gt;
			if y2 &amp;gt; y1 and y2 &amp;lt; y1 + 125 and y1 &amp;lt;= tonumber( os.date( &amp;#039;%Y&amp;#039; ) ) then&lt;br /&gt;
				excerpt = mw.ustring.sub( excerpt, 1, s ) .. year1 .. &amp;#039;–&amp;#039; .. year2 .. mw.ustring.sub( excerpt, e )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Replace the first call to each reference defined outside of the excerpt for the full reference, to prevent undefined references&lt;br /&gt;
-- Then prefix the page title to the reference names to prevent conflicts&lt;br /&gt;
-- that is, replace &amp;lt;ref name=&amp;quot;Foo&amp;quot;&amp;gt; for &amp;lt;ref name=&amp;quot;Title of the article Foo&amp;quot;&amp;gt;&lt;br /&gt;
-- and also &amp;lt;ref name=&amp;quot;Foo&amp;quot; /&amp;gt; for &amp;lt;ref name=&amp;quot;Title of the article Foo&amp;quot; /&amp;gt;&lt;br /&gt;
-- also remove reference groups: &amp;lt;ref name=&amp;quot;Foo&amp;quot; group=&amp;quot;Bar&amp;quot;&amp;gt; for &amp;lt;ref name=&amp;quot;Title of the article Foo&amp;quot;&amp;gt;&lt;br /&gt;
-- and &amp;lt;ref group=&amp;quot;Bar&amp;quot;&amp;gt; for &amp;lt;ref&amp;gt;&lt;br /&gt;
-- @todo The current regex may fail in cases with both kinds of quotes, like &amp;lt;ref name=&amp;quot;Darwin&amp;#039;s book&amp;quot;&amp;gt;&lt;br /&gt;
function Excerpt.fixReferences( excerpt, page, wikitext )&lt;br /&gt;
	local references = parser.getReferences( excerpt )&lt;br /&gt;
	local fixed = {}&lt;br /&gt;
	for _, reference in pairs( references ) do&lt;br /&gt;
		local name = parser.getTagAttribute( reference, &amp;#039;name&amp;#039; )&lt;br /&gt;
		if not fixed[ name ] then -- fix each reference only once&lt;br /&gt;
			local content = parser.getTagContent( reference )&lt;br /&gt;
			if not content then -- reference is self-closing&lt;br /&gt;
				local full = parser.getReference( excerpt, name )&lt;br /&gt;
				if not full then -- the reference is not defined in the excerpt&lt;br /&gt;
					full = parser.getReference( wikitext, name )&lt;br /&gt;
					if full then&lt;br /&gt;
						excerpt = excerpt:gsub( Excerpt.escapeString( reference ), Excerpt.escapeString( full ), 1 )&lt;br /&gt;
					end&lt;br /&gt;
					table.insert( fixed, name )&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- Prepend the page title to the reference names to prevent conflicts with other references in the transcluding page&lt;br /&gt;
	excerpt = excerpt:gsub( &amp;#039;&amp;lt; *[Rr][Ee][Ff][^&amp;gt;]*name *= *[&amp;quot;\&amp;#039;]?([^&amp;quot;\&amp;#039;&amp;gt;/]+)[&amp;quot;\&amp;#039;]?[^&amp;gt;/]*(/?) *&amp;gt;&amp;#039;, &amp;#039;&amp;lt;ref name=&amp;quot;&amp;#039; .. page:gsub( &amp;#039;&amp;quot;&amp;#039;, &amp;#039;&amp;#039; ) .. &amp;#039; %1&amp;quot;%2&amp;gt;&amp;#039; )&lt;br /&gt;
	-- Remove reference groups because they don&amp;#039;t apply to the transcluding page&lt;br /&gt;
	excerpt = excerpt:gsub( &amp;#039;&amp;lt; *[Rr][Ee][Ff] *group *= *[&amp;quot;\&amp;#039;]?[^&amp;quot;\&amp;#039;&amp;gt;/]+[&amp;quot;\&amp;#039;] *&amp;gt;&amp;#039;, &amp;#039;&amp;lt;ref&amp;gt;&amp;#039; )&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeReferences( excerpt )&lt;br /&gt;
	local references = parser.getReferences( excerpt )&lt;br /&gt;
	for _, reference in pairs( references ) do&lt;br /&gt;
		excerpt = Excerpt.removeString( excerpt, reference )&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeCategories( excerpt )&lt;br /&gt;
	local categories = parser.getCategories( excerpt )&lt;br /&gt;
	for _, category in pairs( categories ) do&lt;br /&gt;
		excerpt = Excerpt.removeString( excerpt, category )&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeBehaviorSwitches( excerpt )&lt;br /&gt;
	return excerpt:gsub( &amp;#039;__[A-Z]+__&amp;#039;, &amp;#039;&amp;#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeComments( excerpt )&lt;br /&gt;
	return excerpt:gsub( &amp;#039;&amp;lt;!%-%-.-%-%-&amp;gt;&amp;#039;, &amp;#039;&amp;#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeBold( excerpt )&lt;br /&gt;
	return excerpt:gsub( &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;quot;, &amp;#039;&amp;#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.removeLinks( excerpt )&lt;br /&gt;
	local links = parser.getLinks( excerpt )&lt;br /&gt;
	for _, link in pairs( links ) do&lt;br /&gt;
		excerpt = Excerpt.removeString( excerpt, link )&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- @todo Use parser.getLinks&lt;br /&gt;
function Excerpt.removeSelfLinks( excerpt )&lt;br /&gt;
	local lang = mw.language.getContentLanguage()&lt;br /&gt;
	local page = Excerpt.escapeString( mw.title.getCurrentTitle().prefixedText )&lt;br /&gt;
	local ucpage = lang:ucfirst( page )&lt;br /&gt;
	local lcpage = lang:lcfirst( page )&lt;br /&gt;
	excerpt = excerpt&lt;br /&gt;
		:gsub( &amp;#039;%[%[(&amp;#039; .. ucpage .. &amp;#039;)%]%]&amp;#039;, &amp;#039;%1&amp;#039; )&lt;br /&gt;
		:gsub( &amp;#039;%[%[(&amp;#039; .. lcpage .. &amp;#039;)%]%]&amp;#039;, &amp;#039;%1&amp;#039; )&lt;br /&gt;
		:gsub( &amp;#039;%[%[&amp;#039; .. ucpage .. &amp;#039;|([^]]+)%]%]&amp;#039;, &amp;#039;%1&amp;#039; )&lt;br /&gt;
		:gsub( &amp;#039;%[%[&amp;#039; .. lcpage .. &amp;#039;|([^]]+)%]%]&amp;#039;, &amp;#039;%1&amp;#039; )&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Replace the bold title or synonym near the start of the page by a link to the page&lt;br /&gt;
function Excerpt.linkBold( excerpt, page )&lt;br /&gt;
	local lang = mw.language.getContentLanguage()&lt;br /&gt;
	local position = mw.ustring.find( excerpt, &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;quot; .. lang:ucfirst( page ) .. &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;quot;, 1, true ) -- look for &amp;quot;&amp;#039;&amp;#039;&amp;#039;Foo&amp;#039;&amp;#039;&amp;#039; is...&amp;quot; (uc) or &amp;quot;A &amp;#039;&amp;#039;&amp;#039;foo&amp;#039;&amp;#039;&amp;#039; is...&amp;quot; (lc)&lt;br /&gt;
		or mw.ustring.find( excerpt, &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;quot; .. lang:lcfirst( page ) .. &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;quot;, 1, true ) -- plain search: special characters in page represent themselves&lt;br /&gt;
	if position then&lt;br /&gt;
		local length = mw.ustring.len( page )&lt;br /&gt;
		excerpt = mw.ustring.sub( excerpt, 1, position + 2 ) .. &amp;#039;[[&amp;#039; .. mw.ustring.sub( excerpt, position + 3, position + length + 2 ) .. &amp;#039;]]&amp;#039; .. mw.ustring.sub( excerpt, position + length + 3, -1 ) -- link it&lt;br /&gt;
	else -- look for anything unlinked in bold, assumed to be a synonym of the title (e.g. a person&amp;#039;s birth name)&lt;br /&gt;
		excerpt = mw.ustring.gsub( excerpt, &amp;quot;&amp;#039;&amp;#039;&amp;#039;(.-&amp;#039;*)&amp;#039;&amp;#039;&amp;#039;&amp;quot;, function ( text )&lt;br /&gt;
			if not string.find( text, &amp;#039;%[&amp;#039; ) and not string.find( text, &amp;#039;%{&amp;#039; ) then -- if not wikilinked or some weird template&lt;br /&gt;
				return &amp;quot;&amp;#039;&amp;#039;&amp;#039;[[&amp;quot; .. page .. &amp;#039;|&amp;#039; .. text .. &amp;quot;]]&amp;#039;&amp;#039;&amp;#039;&amp;quot; -- replace &amp;#039;&amp;#039;&amp;#039;Foo&amp;#039;&amp;#039;&amp;#039; by &amp;#039;&amp;#039;&amp;#039;[[page|Foo]]&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
			else&lt;br /&gt;
				return nil -- instruct gsub to make no change&lt;br /&gt;
			end&lt;br /&gt;
		end, 1 ) -- terminates the anonymous replacement function passed to gsub&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Excerpt.addTrackingCategories( excerpt )&lt;br /&gt;
	local currentTitle = mw.title.getCurrentTitle()&lt;br /&gt;
	local addedCategories = false&lt;br /&gt;
	local contentCategory = config.categories.content&lt;br /&gt;
	if contentCategory and currentTitle.isContentPage then&lt;br /&gt;
		addedCategories = true&lt;br /&gt;
		excerpt = excerpt .. &amp;#039;[[Category:&amp;#039; .. contentCategory .. &amp;#039;]]&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local namespaceCategory = config.categories[ currentTitle.namespace ]&lt;br /&gt;
	if namespaceCategory then&lt;br /&gt;
		addedCategories = true&lt;br /&gt;
		excerpt = excerpt .. &amp;#039;[[Category:&amp;#039; .. namespaceCategory .. &amp;#039;]]&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	if addedCategories then&lt;br /&gt;
		excerpt = excerpt .. &amp;#039;\n&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return excerpt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper method to match from a list of regular expressions&lt;br /&gt;
-- Like so: match pre..list[1]..post or pre..list[2]..post or ...&lt;br /&gt;
function Excerpt.matchAny( text, pre, list, post, init )&lt;br /&gt;
	for i = 1, #list do&lt;br /&gt;
		local match = { mw.ustring.match( text, pre .. list[ i ] .. post, init ) }&lt;br /&gt;
		if match[1] then return unpack( match ) end&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper function to get arguments&lt;br /&gt;
-- args from Lua calls have priority over parent args from template&lt;br /&gt;
function Excerpt.getArg( key, default )&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	for k, value in pairs( frame:getParent().args ) do&lt;br /&gt;
		if k == key and mw.text.trim( value ) ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			return value&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for k, value in pairs( frame.args ) do&lt;br /&gt;
		if k == key and mw.text.trim( value ) ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			return value&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return default&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper method to get an error message&lt;br /&gt;
-- This method also categorizes the current page in one of the configured error categories&lt;br /&gt;
function Excerpt.getError( key, value )&lt;br /&gt;
	local message = Excerpt.getMessage( &amp;#039;error-&amp;#039; .. key, value )&lt;br /&gt;
	local markup = mw.html.create( &amp;#039;div&amp;#039; ):addClass( &amp;#039;error&amp;#039; ):wikitext( message )&lt;br /&gt;
	if config.categories and config.categories.errors and mw.title.getCurrentTitle().isContentPage then&lt;br /&gt;
		markup:node( &amp;#039;[[Category:&amp;#039; .. config.categories.errors .. &amp;#039;]]&amp;#039; )&lt;br /&gt;
	end&lt;br /&gt;
	return markup&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper method to get a localized message&lt;br /&gt;
-- This method uses Module:TNT to get localized messages from https://commons.wikimedia.org/wiki/Data:I18n/Module:Excerpt.tab&lt;br /&gt;
-- If Module:TNT is not available or the localized message does not exist, the key is returned instead&lt;br /&gt;
function Excerpt.getMessage( key, value )&lt;br /&gt;
	local ok2, TNT = pcall( require, &amp;#039;Module:TNT&amp;#039; )&lt;br /&gt;
	if not ok2 then return key end&lt;br /&gt;
	local ok3, message = pcall( TNT.format, &amp;#039;I18n/Module:Excerpt.tab&amp;#039;, key, value )&lt;br /&gt;
	if not ok3 then return key end&lt;br /&gt;
	return message&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper method to escape a string for use in regexes&lt;br /&gt;
function Excerpt.escapeString( str )&lt;br /&gt;
	return str:gsub( &amp;#039;[%^%$%(%)%.%[%]%*%+%-%?%%]&amp;#039;, &amp;#039;%%%0&amp;#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper method to remove a string from a text&lt;br /&gt;
-- @param text Text from where to remove the string&lt;br /&gt;
-- @param str String to remove&lt;br /&gt;
-- @return The given text with the string removed&lt;br /&gt;
function Excerpt.removeString( text, str )&lt;br /&gt;
	local pattern = Excerpt.escapeString( str )&lt;br /&gt;
	if #pattern &amp;gt; 9999 then -- strings longer than 10000 bytes can&amp;#039;t be put into regexes&lt;br /&gt;
		pattern = Excerpt.escapeString( mw.ustring.sub( str, 1, 999 ) ) .. &amp;#039;.-&amp;#039; .. Excerpt.escapeString( mw.ustring.sub( str, -999 ) )&lt;br /&gt;
	end&lt;br /&gt;
	return text:gsub( pattern, &amp;#039;&amp;#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper method to convert a comma-separated list of numbers or min-max ranges into a list of booleans&lt;br /&gt;
-- @param filter Required. Comma-separated list of numbers or min-max ranges, for example &amp;#039;1,3-5&amp;#039;&lt;br /&gt;
-- @return Map from integers to booleans, for example {1=true,2=false,3=true,4=true,5=true}&lt;br /&gt;
-- @return Boolean indicating whether the filters should be treated as a blacklist or not&lt;br /&gt;
-- @note Merging this into matchFilter is possible, but way too inefficient&lt;br /&gt;
function Excerpt.parseFilter( filter )&lt;br /&gt;
	local filters = {}&lt;br /&gt;
	local isBlacklist = false&lt;br /&gt;
	if string.sub( filter, 1, 1 ) == &amp;#039;-&amp;#039; then&lt;br /&gt;
		isBlacklist = true&lt;br /&gt;
		filter = string.sub( filter, 2 )&lt;br /&gt;
	end&lt;br /&gt;
	local values = mw.text.split( filter, &amp;#039;,&amp;#039; ) -- split values: &amp;#039;1,3-5&amp;#039; to {&amp;#039;1&amp;#039;,&amp;#039;3-5&amp;#039;}&lt;br /&gt;
	for _, value in pairs( values ) do&lt;br /&gt;
		value = mw.text.trim( value )&lt;br /&gt;
		local min, max = mw.ustring.match( value, &amp;#039;^(%d+)%s*[-–—]%s*(%d+)$&amp;#039; ) -- &amp;#039;3-5&amp;#039; to min=3 max=5&lt;br /&gt;
		if not max then min, max = string.match( value, &amp;#039;^((%d+))$&amp;#039; ) end -- &amp;#039;1&amp;#039; to min=1 max=1&lt;br /&gt;
		if max then&lt;br /&gt;
			for i = min, max do filters[ i ] = true end&lt;br /&gt;
		else&lt;br /&gt;
			filters[ value ] = true -- if we reach this point, the string had the form &amp;#039;a,b,c&amp;#039; rather than &amp;#039;1,2,3&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	filter = { cache = {}, terms = filters }&lt;br /&gt;
	return filter, isBlacklist&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Helper function to see if a value matches any of the given filters&lt;br /&gt;
function Excerpt.matchFilter( value, filter )&lt;br /&gt;
	if value == nil then&lt;br /&gt;
		return false&lt;br /&gt;
	elseif type(value) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		return filter.terms[value]&lt;br /&gt;
	else&lt;br /&gt;
		local cached = filter.cache[value]&lt;br /&gt;
		if cached ~= nil then&lt;br /&gt;
			return cached&lt;br /&gt;
		end&lt;br /&gt;
		local lang = mw.language.getContentLanguage()&lt;br /&gt;
		local lcvalue = lang:lcfirst(value)&lt;br /&gt;
		local ucvalue = lang:ucfirst(value)&lt;br /&gt;
		for term in pairs( filter.terms ) do&lt;br /&gt;
			if value == tostring(term)&lt;br /&gt;
			or type(term) == &amp;quot;string&amp;quot; and (&lt;br /&gt;
				lcvalue == term&lt;br /&gt;
				or ucvalue == term&lt;br /&gt;
				or mw.ustring.match( value, term )&lt;br /&gt;
			) then&lt;br /&gt;
				filter.cache[value] = true&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		filter.cache[value] = false&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return Excerpt&lt;/div&gt;</summary>
		<author><name>imported&gt;Sophivorus</name></author>
	</entry>
</feed>