"मोड्युल:Article history/config" का संशोधनहरू बिचको अन्तर

विकिपिडिया, एक स्वतन्त्र विश्वकोशबाट
Content deleted Content added
convert DGA status to FFA automatically for any articles that have been delisted at FAR
add tracking categories for small banners, for gacat parameters, and for BP actions
पङ्क्ति १,१०२: पङ्क्ति १,१०२:
aliases = {'pass', 'promoted', 'nom'}
aliases = {'pass', 'promoted', 'nom'}
}
}
}
},
categories = function ()
return {Category.new('Article history templates with BP actions')}
end
},
},
RBP = {
RBP = {
पङ्क्ति २,००१: पङ्क्ति २,००४:
end
end
return ret
return ret
end
end,

-- Track the gacat parameter
function (articleHistoryObj)
local ret = {}
if articleHistoryObj.args.gacat then
table.insert(ret, Category.new('Article history templates with deprecated parameters'))
end
return ret
end,

-- Track small banners
function (articleHistoryObj)
local ret = {}
if articleHistoryObj.isSmall then
table.insert(ret, Category.new('Small article history templates'))
end
return ret
end,
},
},



१८:२८, १३ फेब्रुअरी २०१५ जस्तै गरी पुनरावलोकन

-------------------------------------------------------------------------------
--              Configuration data for [[Module:Article history]]
-------------------------------------------------------------------------------

local lang = mw.language.getContentLanguage()
local Category = require('Module:Article history/Category')

-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------

-- Makes a link to a template page surrounded by double curly braces. A
-- workalike for the {{tl}} template.
local function makeTemplateLink(s)
	local openb = mw.text.nowiki('{{')
	local closeb = mw.text.nowiki('}}')
	return string.format('%s[[Template:%s|%s]]%s', openb, s, s, closeb)
end

-- Gets the Good Article topic for the given key. Uses
-- [[Module:Good article topics]].
local function getGoodArticleTopic(key)
	if not key then
		return nil
	end
	return require('Module:Good article topics')._main(key)
end

-- Returns the Good Article page link and display value for a given Good Article
-- key. If the key wasn't valid, the default Good Article page and display value
-- is returned instead.
local function getGoodArticleTopicLink(key)
	local topic = getGoodArticleTopic(key)
	local link, display
	if topic then
		link = 'Wikipedia:Good articles/' .. topic
		display = topic .. ' good articles'
	else
		link = 'Wikipedia:Good articles'
		display = 'good articles'
	end
	return link, display
end

-- Wrapper function for mw.language:formatDate, going through pcall to catch
-- invalid input errors.
local function getDate(format, date)
	local success, result = pcall(lang.formatDate, lang, format, date)
	if success then
		return result
	end
end

-- Gets the date in the format YYYYMMDD, as a number. Months and dates are
-- zero-padded. Results from this function are intended to be used in date
-- calculations.
local function getYmdDate(date)
	return tonumber(getDate('Ymd', date))
end

-- Gets the date in the format Month d, YYYY.
local function getLongDate(date)
	return getDate('F j, Y', date)
end

-- Returns true if the given page is an existing title, and false or nil
-- otherwise
local function titleExists(page)
	local success, title = pcall(mw.title.new, page)
	return success and title.exists
end

-- Returns a truthy value if a date parameter for the given prefix has been
-- provided by the user.
local function isActiveDatedObject(articleHistoryObj, prefix)
	local args = articleHistoryObj.args
	local prefixArgs = articleHistoryObj.prefixArgs
	return args[prefix .. 'date'] or args[prefix .. 'date2'] or prefixArgs[prefix]
end

-- Returns a date as formatted by getLongDate. If the date is invalid, it raises
-- an error using param as the parameter name containing the invalid date.
local function validateDate(param, date, articleHistoryObj)
	local longDate = getLongDate(date)
	if longDate then
		return longDate
	else
		articleHistoryObj:raiseError(
			string.format(
				"invalid date '%s' detected in parameter '%s'",
				tostring(date),
				param
			),
			'Template:Article history#Invalid date'
		)
	end
end

-- Generates a data table for a date-related notice such as DYK and ITN. prefix
-- is the parameter prefix for that notice type (e.g. "dyk"), and suffixes is
-- an array of parameter suffixes in addition to "date" that is used by that
-- notice type (e.g. "entry" for the "dykentry" and "dyk2entry" parameters).
local function makeDateData(articleHistoryObj, prefix, suffixes)
	local args = articleHistoryObj.args
	local prefixArgs = articleHistoryObj.prefixArgs

	-- Sanity checks
	if prefixArgs[prefix] then
		for _, t in ipairs(prefixArgs[prefix]) do
			if not t.date then
				articleHistoryObj:raiseError(
					string.format(
						"an argument starting with '%s%d' was detected, " ..
							"but no '%s%ddate' parameter was specified",
						prefix, t[1],
						prefix, t[1]
					),
					'Template:Article history#No date parameter'
				)
			end
		end
	end

	local data = {}

	-- Organise the input
	if args[prefix .. 'date'] then
		local t = {}
		do
			local key = prefix .. 'date'
			t.date = validateDate(key, args[key], articleHistoryObj)
		end
		for _, suffix in ipairs(suffixes) do
			local key = prefix .. suffix
			t[suffix] = args[key]
		end
		data[#data + 1] = t
	end
	if prefixArgs[prefix] then
		for _, prefixData in ipairs(prefixArgs[prefix]) do
			local t = {}
			do
				local key = prefix .. tostring(prefixData[1]) .. 'date'
				t.date = validateDate(key, args[key], articleHistoryObj)
			end
			for i, suffix in ipairs(suffixes) do
				local key = prefix .. tostring(prefixData[1]) .. suffix
				t[suffix] = args[key]
			end
			data[#data + 1] = t
		end
	end
	if #data < 1 then
		error(string.format(
			"no data items found for prefix '%s' and parameter checks failed'",
			tostring(prefix)
		))
	end

	return data
end

-- This makes the text for Main Page features such as DYKs and ITNs for the
-- dates contained in dateData (made with the makeDateData function).
-- The parameter $1 in the blurb will be replaced with the list of dates.
local function makeDateText(dateData, blurb)
	local dates = {}
	for i, t in ipairs(dateData) do
		if t.link then
			dates[i] = string.format('on [[%s|%s]]', t.link, t.date)
		else
			dates[i] = string.format('on %s', t.date)
		end
	end
	local dateList = mw.text.listToText(dates, ', ', ', and ')
	return mw.message.newRawMessage(blurb, dateList):plain()
end

return {
	
-------------------------------------------------------------------------------
--                             CONFIG TABLE START
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Statuses
-- Configuration for possible current statuses of the article.
-------------------------------------------------------------------------------

-- The statuses table contain configuration tables for possible current statuses
-- of the article.
-- Each table can have the following fields:
--
-- id: the main ID for the status. This should be the same as the configuration
--    table key.
-- aliases: a table of ID aliases that can be used to access the config table.
-- icon: The status icon.
-- iconSize: The icon size, including "px" suffix. The default is defined in
--    defaultStatusIconSize.
-- iconSmallSize: The icon size if we are outputting a small template. The
--    default is defined in defaultSmallStatusIconSize.
-- iconMultiSize: The icon size if we are outputting multiple status rows. The
--    default is defaultSmallStatusIconSize.
-- text: The status text. This may be a string or a function. If it is a
--    function, it takes an article history object as input, and should return
--    the text string. If it is a string, it can have the following parameters:
--    $1 - The full page name of the article or subject page
--    $2 - The page name without the namespace name
-- categories: The categories set by the status. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter, and the current status object as
--    the second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. The status
--    name is used by default. This can be a string or a function. If it is a
--    function, it takes an article history object as its first parameter, and
--    should return the caption text. If this is absent, the icon caption is
--    used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

statuses = {
	FA = {
		id = 'FA',
		name = 'Featured article',
		icon = 'Featured article star.svg',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local actions = articleHistoryObj:getActionObjects()
			local link
			for i = #actions, 1, -1 do
				local actionObj = actions[i]
				if actionObj.id == 'FAC' then
					link = actionObj.link
					break
				end
			end
			link = link or 'Wikipedia:Featured article candidates/' .. articlePage
			local text = "'''%s''' is a [[Wikipedia:Featured articles|featured article]]; " ..
				"it (or a previous version of it) has been '''''[[%s|identified]]''''' " ..
				"as one of the best articles produced by the [[Wikipedia:Wikipedians|Wikipedia community]]. " ..
				"Even so, if you can update or improve it, [[Wikipedia:Be bold|please do so]]."
			return string.format(text, articlePage, link)
		end,
		categories = {'Wikipedia featured articles'}
	},
	FFA = {
		id = 'FFA',
		name = 'Former featured article',
		icon = 'Featured article star - cross.svg',
		iconSize = '48px',
		text = "'''$1''' is a [[Wikipedia:Former featured articles|former featured article]]. " ..
			"Please see the links under Article milestones below for its original nomination page " ..
			"(for older articles, check [[Wikipedia:Featured article candidates/Archived nominations/Index|the nomination archive]]) " ..
			"and why it was removed.",
		categories = {'Wikipedia former featured articles'}
	},
	FFAC = {
		id = 'FFAC',
		name = 'Former featured article candidate',
		aliases = {'FACFAILED'},
		icon = 'Cscr-former.svg',
		text = "'''$1''' is a former [[Wikipedia:Featured article candidates|featured article candidate]]. " ..
			"Please view the links under Article milestones below to see why " ..
			"the nomination failed. For older candidates, please check the " ..
			"[[Wikipedia:Featured article candidates/Archived nominations/Index|archive]]."
	},
	FL = {
		id = 'FL',
		name = 'Featured list',
		icon = 'Featured article star.svg',
		iconSize = '48px',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local actions = articleHistoryObj:getActionObjects()
			local link
			for i = #actions, 1, -1 do
				local actionObj = actions[i]
				if actionObj.id == 'FLC' then
					link = actionObj.link
					break
				end
			end
			link = link or 'Wikipedia:Featured list candidates/' .. articlePage
			local text = "'''%s''' is a [[Wikipedia:Featured lists|featured list]], " ..
				"which means it has been '''''[[%s|identified]]''''' as one of the best " ..
				"[[Wikipedia:Lists|lists]] produced by the [[Wikipedia:Wikipedians|Wikipedia community]]. " ..
				"If you can update or improve it, [[Wikipedia:Be bold|please do so]]."
			return string.format(text, articlePage, link)
		end,
		categories = {'Wikipedia featured lists'}
	},
	FFL = {
		id = 'FFL',
		name = 'Former featured list',
		icon = 'Cscr-featured-strike.svg',
		text = "'''$1''' is a [[Wikipedia:Former featured lists|former featured list]]. " ..
			"Please see the links under Article milestones below for its original " ..
			"nomination page and why it was removed. If it has improved again to " ..
			"[[Wikipedia:Featured list criteria|featured list standard]], you may " ..
			"[[Wikipedia:Featured list candidates|renominate]] the article to " ..
			"become a [[Wikipedia:Featured list|featured list]]."
	},
	FFLC = {
		id = 'FFLC',
		name = 'Former featured list candidate',
		icon = 'Cscr-former.svg',
		iconCaption = 'Former FLC',
		text = "'''$1''' is a former [[Wikipedia:Featured list candidates|featured list candidate]]. " ..
			"Please view the link under Article milestones below to see why the nomination failed. " ..
			"Once the objections have been addressed you may " ..
			"[[Wikipedia:Featured list candidates#Resubmitting nominations|resubmit]] " ..
			"the article for featured list status.",
		categories = {'Wikipedia featured list candidates (contested)'}
	},
	['FFA/GA'] = {
		id = 'FFA/GA',
		name = 'Former featured article, current good article',
		isMulti = true,
		statuses = {'FFA', 'GA'}
	},
	GA = {
		id = 'GA',
		name = 'Good article',
		icon = 'Symbol support vote.svg',
		iconSize = '40px',
		iconMultiSize = '25px',
		text = function (articleHistoryObj)
			local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local text = "'''%s''' has been listed as one of the '''''[[%s|%s]]''''' " ..
				"under the [[Wikipedia:Good article criteria|good article criteria]]. " ..
				"If you can improve it further, [[Wikipedia:Be bold|please do so]]. " ..
				"<small>''If it no longer meets these criteria, you can " ..
				"'''[[Wikipedia:Good article reassessment|reassess]]''' it''.</small>"
			return string.format(text, articlePage, link, display)
		end,
		categories = function (articleHistoryObj)
			local ret = {}
			local title = articleHistoryObj.currentTitle
			if title.namespace == 1 then
				ret[#ret + 1] = Category.new('Wikipedia good articles')
				ret[#ret + 1] = Category.new('Wikipedia CD Selection-GAs')
				ret[#ret + 1] = Category.new('GA-Class Good articles')
				local topic = getGoodArticleTopic(articleHistoryObj.args.topic)
				if topic then
					ret[#ret + 1] = Category.new(
						topic .. ' good articles',
						title.text
					)
				else
					ret[#ret + 1] = Category.new(
						'Good articles without topic parameter',
						title.text
					)
				end
			end

			-- GA categories
			local gacat = articleHistoryObj.args.gacat
			if gacat then
				local cdSelectionCat = 'Wikipedia CD Selection - People'
				if gacat == 'actors' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on actors, models and celebrities')
					ret[#ret + 1] = Category.new(cdSelectionCat)
				elseif gacat == 'bands' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on performers and composers')
				elseif gacat == 'hist figures' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on historical figures')
					ret[#ret + 1] = Category.new(cdSelectionCat)
				elseif gacat == 'musicians' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on performers and composers')
					ret[#ret + 1] = Category.new(cdSelectionCat)
				elseif gacat == 'politicians' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on politicians')
					ret[#ret + 1] = Category.new(cdSelectionCat)
				elseif gacat == 'royalty' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on royalty')
					ret[#ret + 1] = Category.new(cdSelectionCat)
				elseif gacat == 'writers' then
					ret[#ret + 1] = Category.new('Wikipedia good articles on writers and critics')
					ret[#ret + 1] = Category.new(cdSelectionCat)
				else
					articleHistoryObj:addWarning(
						string.format(
							"invalid value '%s' detected in the 'gacat' parameter",
							tostring(gacat)
						),
						"Template:Article history#Invalid value in 'gacat'"
					)
				end
			end

			return ret
		end
	},
	FGAN = {
		id = 'FGAN',
		name = 'Former good article nominee',
		aliases = {'FAILEDGA'},
		icon = 'Symbol unsupport vote.svg',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
			local text = "'''%s''' was a '''''[[%s|%s]]''''' nominee, " ..
				"but did not meet the [[Wikipedia:Good article criteria|good article criteria]] " ..
				"at the time. There are suggestions below for improving the article. " ..
				"Once these issues have been addressed, the article can be " ..
				"[[Wikipedia:Good article nominations|renominated]]. " ..
				"Editors may also seek a '''[[Wikipedia:Good article reassessment|reassessment]]''' " ..
				"of the decision if they believe there was a mistake."
			return string.format(text, articlePage, link, display)
		end,
		categories = {'Former good article nominees'}
	},
	DGA = {
		id = 'DGA',
		name = 'Delisted good article',
		aliases = {'DELISTEDGA'},
		icon = 'Symbol unsupport vote.svg',
		iconCaption = 'Former good article',
		text = function (articleHistoryObj)
			local articlePage = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local link, display = getGoodArticleTopicLink(articleHistoryObj.args.topic)
			local text = "'''%s''' was one of the '''''[[%s|%s]]''''', " ..
				"but it has been removed from the list. " ..
				"There are suggestions below for improving the article to meet the " ..
				"[[Wikipedia:Good article criteria|good article criteria]]. " ..
				"Once these issues have been addressed, the article can be " ..
				"[[Wikipedia:Good article nominations|renominated]]. " ..
				"Editors may also seek a '''[[Wikipedia:Good article reassessment|reassessment]]''' " ..
				"of the decision if they believe there was a mistake."
			return string.format(text, articlePage, link, display)
		end,
		categories = {'Delisted good articles'}
	},
	FFT = {
		id = 'FFT',
		name = 'Part of former featured topic',
		icon = 'Cscr-featured-strike.svg',
		iconCaption = 'Former featured topic',
		text = "This article is part of a " ..
			"''[[Wikipedia:Former featured topics|former featured topic]]'' series. " ..
			"If it has improved again to " ..
			"[[Wikipedia:Featured topic criteria|featured topic standard]], " ..
			"you may [[Wikipedia:Featured topic candidates|renominate]] " ..
			"the topic to become a [[Wikipedia:Featured topic|featured topic]]."
	},
	FFTC = {
		id = 'FFTC',
		name = 'Former featured topic candidate',
		icon = 'Cscr-former.svg',
		text = "This article is part of a ''former'' " ..
			"[[Wikipedia:Featured topic candidates|featured topic candidate]]. " ..
			"Please view the links under Article milestones below to see why " ..
			"the nomination failed."
	},
	FPO = {
		id = 'FPO',
		name = 'Featured portal',
		icon = 'Cscr-former.svg',
		text = "The '''$2 Portal''' is a [[Wikipedia:Featured portals|featured portal]], " ..
			"which means it has been " ..
			"'''''[[Wikipedia:Featured portal candidates/Portal:$2|identified]]''''' " ..
			"as one of the best portals on [[Wikipedia]]. " ..
			"If you see a way this portal can be updated or improved without " ..
			"compromising previous work, please feel free to contribute.",
		categories = function (articleHistoryObj)
			return {Category.new(
				'Wikipedia featured portals',
				articleHistoryObj.currentTitle.text
			)}
		end
	},
	FFPO = {
		id = 'FFPO',
		name = 'Former featured portal',
		icon = 'Featured article star - cross.svg',
		text = "This portal is a [[Wikipedia:Former featured portals|former featured portal]]. " ..
			"Please see the links under Portal milestones below for its " ..
			"original nomination page and why it was removed.",
		categories = function (articleHistoryObj)
			return {Category.new(
				'Wikipedia former featured portals',
				articleHistoryObj.currentTitle.text
			)}
		end
	},
	FFPOC = {
		id = 'FFPOC',
		name = 'Former featured portal candidate',
		icon = 'Cscr-former.svg',
		text = "This portal is a '''''former''''' " ..
			"[[Wikipedia:Featured portal candidates|featured portal candidate]]. " ..
			"Please see the links under Portal milestones below for its " ..
			"original nomination page and why the nomination failed.",
		categories = function (articleHistoryObj)
			return {Category.new(
				'Wikipedia featured portal candidates (contested)',
				articleHistoryObj.currentTitle.text
			)}
		end
	},
	PR = {
		-- Peer review is a valid current status, but it doesn't trigger a
		-- header row.
		id = 'PR',
		name = 'Peer reviewed',
		noticeBarIcon = 'Nuvola apps kedit.svg'
	},
	NA = {
		-- A valid current status, but doesn't trigger a header row.
		id = 'NA',
		noticeBarIcon = 'Nuvola apps kedit.svg'
	},
	-- The following are invalid statuses.
	FAC = {
		id = 'FAC',
		text = function (articleHistoryObj)
			articleHistoryObj:raiseError(
				string.format(
					'use the template %s to nominate an article for Featured article status',
					makeTemplateLink('fac')
				),
				'Template:Article history#Featured article candidates'
			)
		end
	},
	FAR = {
		id = 'FAR',
		text = function (articleHistoryObj)
			articleHistoryObj:raiseError(
				string.format(
					'use the template %s to nominate an article for Featured article review',
					makeTemplateLink('FAR')
				),
				'Template:Article history#Featured article review'
			)
		end
	},
	STUB = {
		id = 'STUB',
		aliases = {'START', 'B', 'A'},
		text = function (articleHistoryObj)
			local currentStatusParam = articleHistoryObj.cfg.currentStatusParam
			articleHistoryObj:raiseError(
				string.format(
					"do not use '%s' as value of the '%s' parameter; these " ..
						'assessments are the responsibility of individual ' ..
						'WikiProjects',
					articleHistoryObj.args[currentStatusParam],
					currentStatusParam
				),
				'Template:Article history#WikiProject assessments'
			)
		end
	},
},

-- This function allows the generation of custom status ID. It takes an
-- articleHistory object as the first parameter, and should output the status
-- ID.
getStatusIdFunction = function (articleHistoryObj)
	-- Get the status ID. The status code is the code passed in from the
	-- arguments, and the ID is the value contained in the config.
	local statuses = articleHistoryObj.cfg.statuses
	local statusCode = articleHistoryObj.args[articleHistoryObj.cfg.currentStatusParam]
	local statusId = articleHistoryObj:getStatusIdForCode(statusCode)

	-- Check for former featured articles.
	if statusId ~= 'FA'
		and statusId ~= 'FL'
		and statusId ~= 'FFA'
		and statusId ~= 'FFL'
		and statusId ~= 'FFA/GA'
	then
		local ffaObj
		local actions = articleHistoryObj:getActionObjects()
		for i = #actions, 1, -1 do
			local actionObj = actions[i]
			if actionObj.id == 'FAR' and actionObj.resultId == 'demoted' then
				ffaObj = actionObj
				break
			end
		end
		if ffaObj then
			if not statusId then
				articleHistoryObj:raiseError(
					'former featured articles should have a current status',
					'Template:Article history#Former featured articles'
				)
			elseif statusId == 'GA' then
				statusId = 'FFA/GA'
			elseif statusId == 'DGA' then
				statusId = 'FFA'
			else
				articleHistoryObj:raiseError(
					string.format(
						"'%s' is not a valid current status for former featured articles",
						tostring(statusCode)
					),
					'Template:Article history#Former featured articles'
				)
			end
		end
	end

	return statusId
end,

-------------------------------------------------------------------------------
-- Notices
-------------------------------------------------------------------------------

-- The notices table contains configuration tables for notices about the article
-- that are unrelated to its current status.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the notice. This should be the same as the configuration
--    table key.
-- isActive: a function that should return a truthy value if the notice should
--    be displayed, and a falsy value if not. (Falsy values are false and nil,
--    and truthy values are everything else.) The function takes an article
--    history object as its first parameter.
-- makeData: a function that should return a table of data to be used by other
--    functions in this notice configuration table. It can be accessed using
--    noticeObj:getData().
-- icon: the filename of the notice icon, minus the "File:" prefix.
-- iconCaption: the icon caption.
-- iconSize: The icon size, including "px" suffix. The default is defined in
--    defaultIconSize.
-- iconSmallSize: The icon size if we are outputting a small template. The
--    default is defined in defaultSmallIconSize.
-- text: The notice text. This may be a string or a function. If it is a
--    function, it takes an article history object as the first parameter, and
--    the current notice object as the second parameter, and should return the
--    text string.
-- categories: The categories set by the notice. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter, and the current notice object as
--    the second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
--    a string or a function. If it is a function, it takes an article history
--    object as its first parameter, and should return the caption text. If this
--    is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

notices = {
	{
		id = 'FT',
		isActive = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local prefixArgs = articleHistoryObj.prefixArgs
			-- ftmain is included here because it leads to better error
			-- messages than leaving it out, even though ftmain by itself is
			-- invalid.
			return args.ftname or args.ftmain or prefixArgs.ft
		end,
		makeData = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local prefixArgs = articleHistoryObj.prefixArgs
			local data = {}
			local getTopicStatus = require('Module:FeaturedTopicSum').status
			local yesno = require('Module:Yesno')

			local function makeTopicData(name, isMain, paramNum)
				if name then
					return {
						name = name,
						isMain = yesno(isMain) or false,
						status = getTopicStatus(name),
						paramNum = paramNum
					}
				elseif isMain then
					local num = paramNum and tostring(paramNum) or ''
					articleHistoryObj:raiseError(
						string.format(
							"parameter 'ft%smain' is set, but no featured " ..
								"topic name is set in parameter 'ft%sname'",
							num, num
						),
						'Template:Article history#Featured topic names'
					)
				else
					return nil
				end
			end
			data[#data + 1] = makeTopicData(args.ftname, args.ftmain)
			if prefixArgs.ft then
				for i, t in ipairs(prefixArgs.ft) do
					if t[1] > 1 then -- we use args.ftname instead of args.ft1name
						data[#data + 1] = makeTopicData(t.name, t.main, t[1])
					end
				end
			end

			-- Check for rogue ft.. parameters
			if #data < 1 then
				articleHistoryObj:raiseError(
					"a parameter starting with 'ft' was detected, but no " ..
						"featured topic names were specified; " ..
						"please check the parameter names",
					'Template:Article history#Featured topic names'
				)
			end

			-- Find if one of the topics is featured.
			local isInFeaturedTopic = false
			for _, topic in ipairs(data) do
				if topic.status == 'FT' then
					isInFeaturedTopic = true
					break
				end
			end
			data.isInFeaturedTopic = isInFeaturedTopic

			return data
		end,
		icon = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			if data.isInFeaturedTopic then
				return 'Cscr-featuredtopic.svg'
			else
				return 'Support cluster.svg'
			end
		end,
		iconCaption = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			if data.isInFeaturedTopic then
				return 'Featured topic star'
			else
				return 'Good topic star'
			end
		end,
		iconSize = '48px',
		iconSmallSize = '30px',
		text = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local article = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText

			local firstBlurb = "'''%s''' is %s the '''[[Wikipedia:Featured topics/%s|%s]] series''', %s."
			local otherBlurb = "It is also %s the '''[[Wikipedia:Featured topics/%s|%s]] series''', %s."
			local finalBlurb = "%s identified as among the best series of " ..
				"articles produced by the [[Wikipedia:Wikipedians|Wikipedia community]]. " ..
				"If you can update or improve %s, [[Wikipedia:Be bold|please do so]]."
			local main = 'the main article in'
			local notMain = 'part of'
			local featuredLink = 'a [[Wikipedia:Featured topics|featured topic]]'
			local featuredNoLink = 'a featured topic'
			local goodLink = 'a [[Wikipedia:Good topics|good topic]]'
			local goodNoLink = 'a good topic'
			local thisSingular = 'This is'
			local thisPlural = 'These are'
			local itSingular = 'it'
			local itPlural = 'them'

			local hasFeaturedLink = false
			local hasGoodLink = false
			local text = {}
			
			-- First topic
			do
				local topic = data[1]
				local link
				if topic.status == 'FT' then
					link = featuredLink
					hasFeaturedLink = true
				else
					link = goodLink
					hasGoodLink = true
				end
				text[#text + 1] = string.format(
					firstBlurb,
					article,
					topic.isMain and main or notMain,
					topic.name,
					topic.name,
					link
				)
			end

			-- Other topics
			for i = 2, #data do
				local topic = data[i]
				local link
				if topic.status == 'FT' then
					if hasFeaturedLink then
						link = featuredNoLink
					else
						link = featuredLink
						hasFeaturedLink = true
					end
				else
					if hasGoodLink then
						link = goodNoLink
					else
						link = goodLink
						hasGoodLink = true
					end
				end
				text[#text + 1] = string.format(
					otherBlurb,
					topic.isMain and main or notMain,
					topic.name,
					topic.name,
					link
				)
			end

			-- Final blurb
			do
				local isPlural = #data > 1
				text[#text + 1] = string.format(
					finalBlurb,
					isPlural and thisPlural or thisSingular,
					isPlural and itPlural or itSingular
				)
			end

			return table.concat(text, ' ')
		end,
		categories = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local status = articleHistoryObj:getStatusId()
			local article = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
			local cats = {}

			local function addCat(cat, sort)
				cats[#cats + 1] = Category.new(cat, sort)
			end

			-- Page-wide status categories
			if status == 'FA' then
				addCat('FA-Class Featured topics articles')
			elseif status == 'FL' then
				addCat('FL-Class Featured topics articles')
			elseif status == 'FFA/GA' or status == 'GA' then
				addCat('GA-Class Featured topics articles')
			else
				addCat('Unassessed Featured topics articles')
			end

			-- Topic-specific status categories
			local function addTopicCats(catFormat)
				for i, topic in ipairs(data) do
					addCat(string.format(catFormat, topic.name))
				end
			end
			if status == 'FA' or status == 'FL' then
				addTopicCats('Wikipedia featured topics %s featured content')
			elseif status == 'FFA/GA' or 'GA' then
				addTopicCats('Wikipedia featured topics %s good content')
			else
				addTopicCats('Wikipedia featured topics %s')
			end

			-- Importance categories
			local hasTop, hasHigh, hasMid, hasLow -- These check for dupes
			for i, topic in ipairs(data) do
				local cat, sort
				if topic.status == 'FT' then
					if topic.isMain and not hasTop then
						cat = 'Top-importance Featured topics articles'
						sort = topic.name .. ' ' .. article
						hasTop = true
					elseif not topic.isMain and not hasHigh then
						cat = 'High-importance Featured topics articles'
						hasHigh = true
					end
				else
					if topic.isMain and not hasMid then
						cat = 'Mid-importance Featured topics articles'
						sort = topic.name .. ' ' .. article
						hasMid = true
					elseif not topic.isMain and not hasLow then
						cat = 'Low-importance Featured topics articles'
						hasLow = true
					end
				end
				if cat then
					addCat(cat, sort)
				end
			end

			return cats
		end
	},

	-- Main page date
	{
		id = 'MAINDATE',
		isActive = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local status = articleHistoryObj:getStatusId()
			return args.maindate or status == 'FA' or status == 'FL'
		end,
		makeData = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local status = articleHistoryObj:getStatusId()
			local data = {}
			data.mainDate = args.maindate

			if not data.mainDate then
				if status == 'FA' then
					data.categoryOnly = 'Featured articles that have not appeared on the main page'
				elseif status == 'FL' then
					data.categoryOnly = 'Featured lists that have not appeared on the main page'
				end
				return data
			end

			data.mainDateTimestamp = getYmdDate(data.mainDate)
			data.currentTimestamp = getYmdDate()
			if not data.mainDateTimestamp then
				articleHistoryObj:raiseError(
					string.format(
						"invalid date '%s' detected in parameter 'maindate'",
						data.mainDate
					),
					'Template:Article history#Invalid date'
				)
			end
			-- The first Today's Featured List was on 13 June 2011.
			data.isList = (status == 'FL' or status == 'FFL') and data.mainDateTimestamp >= 20110613

			return data
		end,
		icon = 'Wikipedia-logo-v2.svg',
		iconCaption = 'Main Page trophy',
		text = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data or data.categoryOnly then
				return nil
			end

			local blurb = "This article %s on Wikipedia's [[Main Page]] as " ..
				"[[Wikipedia:Today's featured %s/%s|Today's featured %s]]%s."
			local longDate = getLongDate(data.mainDate)
			local pagetype = data.isList and 'list' or 'article'
			local tenseBlurb, dateBlurb
			if data.mainDateTimestamp < data.currentTimestamp then
				tenseBlurb = 'appeared'
				dateBlurb = ' on ' .. longDate
			elseif data.mainDateTimestamp == data.currentTimestamp then
				tenseBlurb = 'is currently on'
				dateBlurb = ''
			else
				tenseBlurb = 'will appear'
				dateBlurb = ' on ' .. longDate
			end
			return string.format(
				blurb, tenseBlurb, pagetype, longDate, pagetype, dateBlurb
			)
		end,
		categories = function (articleHistoryObj, noticeObj)
			local data = noticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local cats = {}
			if data.categoryOnly then
				cats[1] = Category.new(data.categoryOnly)
			else
				cats[1] = Category.new(string.format(
					'Featured %s that have appeared on the main page',
					data.isList and 'lists' or 'articles'
				))
			end
			return cats
		end
	}
},

-------------------------------------------------------------------------------
-- Actions
-------------------------------------------------------------------------------

-- The actions table contains configuration tables for actions such as featured
-- article candidacies and peer review, etc.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the action. This should be the same as the configuration
--    table key.
-- name: the name of the action. This can be a string or a function. If it is
--    a function, it takes an article history object as its first parameter and
--    the action object as its second parameter, and should return the name.
-- results: a table of possible results for the action. Keys in the table should
--    be a result ID, e.g. "promoted" or "kept", and values should be a subtable
--    with the following fields:
--    id: the result ID. This should be the same as the table key. It will
--        also define a possible input value for the action's result parameter.
--    text: the displayed result text. This may be a string or a function. If it
--        is a function, it takes an article history object as the first
--        parameter and the current action object as the second parameter, and
--        should return the result string.
--    aliases: an array of result ID aliases. Each of these will define a valid
--        value for the action's result parameter.
-- text: The action text. This may be a string or a function. If it is a
--    function, it takes an article history object as the first parameter and
--    the current action object as the second parameter, and should return the
--    text string.
-- categories: The categories set by the notice. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter and the current action object as the
--    second parameter, and should return an array of category objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
--    a string or a function. If it is a function, it takes an article history
--    object as its first parameter, and should return the caption text. If this
--    is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

actions = {
	FAC = {
		id = 'FAC',
		name = 'Featured article candidate',
		results = {
			promoted = {
				id = 'promoted',
				text = 'Promoted',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'Not promoted',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FAR = {
		id = 'FAR',
		name = 'Featured article review',
		aliases = {'FARC'},
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'Demoted',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			local result = actionObj.resultId
			if result == 'demoted' or result == 'merged' then
				local status = articleHistoryObj:getStatusId()
				local sortKey = articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
				if status == 'FA' or status == 'FL' then
					sortKey = '#' .. sortKey
				end
				ret[#ret + 1] = Category.new(
					'Wikipedia former featured articles',
					sortKey
				)
			end
			return ret
		end
	},
	BP = {
		id = 'BP',
		name = 'Brilliant prose',
		results = {
			nominated = {
				id = 'nominated',
				text = 'Nominated',
				aliases = {'pass', 'promoted', 'nom'}
			}
		},
		categories = function ()
			return {Category.new('Article history templates with BP actions')}
		end
	},
	RBP = {
		id = 'RBP',
		name = 'Refreshing brilliant prose',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			['not kept'] = {
				id = 'not kept',
				text = 'Not kept',
				aliases = {'fail', 'failed', 'remove', 'removed', 'demoted'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			if actionObj.resultId == 'not kept' then
				ret[#ret + 1] = Category.new(
					'Wikipedia former brilliant prose',
					articleHistoryObj.currentTitle.text
				)
			end
			return ret
		end
	},
	FLC = {
		id = 'FLC',
		name = 'Featured list candidate',
		results = {
			promoted = {
				id = 'promoted',
				text = 'Promoted',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'Not promoted',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FLR = {
		id = 'FLR',
		name = 'Featured list removal candidate',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'Demoted',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			local result = actionObj.resultId
			if result == 'demoted' or result == 'merged' then
				local sortKey
				if articleHistoryObj:getStatusId() == 'FL' then
					sortKey = '#' .. articleHistoryObj.currentTitle.subjectPageTitle.prefixedText
				else
					sortKey = articleHistoryObj.currentTitle.text
				end
				ret[#ret + 1] = Category.new(
					'Wikipedia former featured lists',
					sortKey
				)
			end
			return ret
		end
	},
	FTC = {
		id = 'FTC',
		name = 'Featured topic candidate',
		results = {
			promoted = {
				id = 'promoted',
				text = 'Promoted',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'Not promoted',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FTR = {
		id = 'FTR',
		name = 'Featured topic removal candidate',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'Demoted',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			}
		}
	},
	FPOC = {
		id = 'FPOC',
		name = 'Featured portal candidate',
		results = {
			promoted = {
				id = 'promoted',
				text = 'Promoted',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'Not promoted',
				aliases = {'fail', 'failed'}
			}
		}
	},
	FPOR = {
		id = 'FPOR',
		name = 'Featured portal review',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'Demoted',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			}
		}
	},
	GAN = {
		id = 'GAN',
		name = 'Good article nominee',
		aliases = {'GAC'},
		results = {
			listed = {
				id = 'listed',
				text = 'Listed',
				aliases = {'pass', 'passed', 'promoted'}
			},
			['not listed'] = {
				id = 'not listed',
				text = 'Not listed',
				aliases = {'fail', 'failed', 'not promoted'}
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			if actionObj.resultId == 'not listed' then
				local status = articleHistoryObj:getStatusId()
				if status ~= 'FA'
					and status ~= 'GA'
					and status ~= 'FFA'
				then
					ret[#ret + 1] = Category.new(
						'Former good article nominees',
						articleHistoryObj.currentTitle.text
					)
				end
			end
			return ret
		end
	},
	GAR = {
		id = 'GAR',
		name = 'Good article reassessment',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			delisted = {
				id = 'delisted',
				text = 'Delisted',
				aliases = {'fail', 'failed'}
			},
			listed = {
				id = 'listed',
				text = 'Listed'
			},
			['not listed'] = {
				id = 'not listed',
				text = 'Not listed'
			}
		},
		categories = function (articleHistoryObj, actionObj)
			local ret = {}
			if actionObj.resultId == 'delisted' then
				local status = articleHistoryObj:getStatusId()
				if status ~= 'FA'
					and status ~= 'GA'
				then
					ret[#ret + 1] = Category.new(
						'Delisted good articles',
						articleHistoryObj.currentTitle.text
					)
				end
			end
		end
	},
	GTC = {
		id = 'GTC',
		name = 'Good topic candidate',
		results = {
			promoted = {
				id = 'promoted',
				text = 'Promoted',
				aliases = {'pass', 'passed'}
			},
			['not promoted'] = {
				id = 'not promoted',
				text = 'Not promoted',
				aliases = {'fail', 'failed'}
			}
		}
	},
	GTR = {
		id = 'GTR',
		name = 'Good topic removal candidate',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'pass', 'passed', 'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'Demoted',
				aliases = {'fail', 'failed', 'remove', 'removed'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			}
		}
	},
	PR = {
		id = 'PR',
		name = 'Peer review',
		results = {
			reviewed = {
				id = 'reviewed',
				text = 'Reviewed',
				aliases = {'_BLANK'}
			},
			['not reviewed'] = {
				id = 'not reviewed',
				text = 'Not reviewed',
			}
		},
		categories = {'Old requests for peer review'}
	},
	WPR = {
		id = 'WPR',
		name = function (articleHistoryObj, actionObj)
			local names = {
				approved = 'WikiProject approved revision',
				copyedited = 'Guild of Copy Editors',
				collaboration = 'WikiProject collaboration',
				maindate = "Today's featured article"
			}
			local result = actionObj.resultId
			return result and names[result] or 'WikiProject peer review'
		end,
		results = {
			approved = {
				id = 'approved',
				text = function(articleHistoryObj, actionObj)
					if actionObj.oldid then
						local url = mw.uri.fullUrl(
							articleHistoryObj.currentTitle.prefixedText,
							{diff = 'cur', oldid = actionObj.oldid}
						)
						return string.format(
							'[%s %s]',
							tostring(url),
							'Diff to current version'
						)
					else
						error(string.format(
							"No oldid detected for the approved version; " ..
								"please set the 'action%doldid' parameter " ..
								"or give the 'action%dresult' parameter a " ..
								"different value.",
							actionObj.paramNum,
							actionObj.paramNum
						))
					end
				end,
				aliases = {'approved version'}
			},
			copyedited = {
				id = 'copyedited',
				text = 'Copyedited',
				aliases = {'copyedit', 'proofread'}
			},
			maindate = {
				id = 'maindate',
				text = 'Main Page'
			},
			collaborated = {
				id = 'collaborated',
				text = 'Collaborated',
				aliases = {'cotw', 'collaboration'}
			},
			reviewed = {
				id = 'reviewed',
				text = 'Reviewed',
				aliases = {'_BLANK'}
			}
		}
	},
	WAR = {
		id = 'WAR',
		name = 'WikiProject A-class review',
		results = {
			approved = {
				id = 'approved',
				text = 'Approved',
				aliases = {'pass', 'passed'}
			},
			['not approved'] = {
				id = 'not approved',
				text = 'Not approved',
				aliases = {'fail', 'failed', 'not reviewed'}
			},
			reviewed = {
				id = 'reviewed',
				text = 'Reviewed',
				aliases = {'_BLANK'}
			},
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'keep'}
			},
			demoted = {
				id = 'demoted',
				text = 'Demoted',
				aliases = {'demote'}
			}
		}
	},
	AFD = {
		id = 'AFD',
		name = 'Articles for deletion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'Speedily kept',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] ={
				id = 'speedily deleted',
				text = 'Speedily deleted',
				aliases = {'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'Redirected',
				aliases = {'redirect'}
			},
		}
	},
	MFD = {
		id = 'MFD',
		name = 'Miscellanea for deletion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'Speedily kept',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] = {
				id = 'speedily deleted',
				text = 'Speedily deleted',
				aliases = {'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'Redirected',
				aliases = {'redirect'}
			},
		}
	},
	TFD = {
		id = 'TFD',
		name = 'Templates for discussion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete'}
			},
			merged = {
				id = 'merged',
				text = 'Merged',
				aliases = {'merge'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			},
			['speedily kept'] = {
				id = 'speedily kept',
				text = 'Speedily kept',
				aliases = {'speedy keep'}
			},
			['speedily deleted'] = {
				id = 'speedily deleted',
				text = 'Speedily deleted',
				aliases = {'speedy delete'}
			},
			redirected = {
				text = 'Redirected',
				aliases = {'redirect'}
			},
		}
	},
	CSD = {
		id = 'CSD',
		name = 'Candidate for speedy deletion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete', 'speedily deleted', 'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'Redirected',
				aliases = {'redirect'}
			},
			prod = {
				id = 'prod',
				text = 'Converted to [[WP:PROD|proposed deletion]]',
				aliases = {'prodded'}
			},
			afd = {
				id = 'afd',
				text = 'Sent to [[WP:AFD|articles for deletion]]',
				aliases = {'afded'}
			},
		}
	},
	PROD = {
		id = 'PROD',
		name = 'Proposed deletion',
		results = {
			kept = {
				id = 'kept',
				text = 'Kept',
				aliases = {'withdrawn', 'keep'}
			},
			deleted = {
				id = 'deleted',
				text = 'Deleted',
				aliases = {'delete'}
			},
			['speedily deleted'] = {
				id = 'speedily deleted',
				text = 'Speedily deleted',
				aliases = {'speedy delete'}
			},
			redirected = {
				id = 'redirected',
				text = 'Redirected',
				aliases = {'redirect'}
			},
			afd = {
				id = 'afd',
				text = 'Sent to [[WP:AFD|articles for deletion]]',
				aliases = {'afded'}
			},
		}
	},
	DRV = {
		id = 'DRV',
		name = 'Deletion review',
		results = {
			endorsed = {
				id = 'endorsed',
				text = 'Endorsed',
				aliases = {'endorse'}
			},
			relisted = {
				id = 'relisted',
				text = 'Relisted',
				aliases = {'relist'}
			},
			overturned = {
				id = 'overturned',
				text = 'Overturned',
				aliases = {'overturn'}
			},
			['no consensus'] = {
				id = 'no consensus',
				text = 'No consensus'
			}
		}
	}
},

-------------------------------------------------------------------------------
-- Collapsible notices
-------------------------------------------------------------------------------

-- The collapsibleNotices table contains configuration tables for notices that
-- go in the collapsible part of the template, underneath the actions.
-- Each configuration table can have the following fields:
--
-- id: the main ID for the notice. This should be the same as the configuration
--    table key.
-- isActive: a function that should return a truthy value if the notice should
--    be displayed, and a falsy value if not. (Falsy values are false and nil,
--    and truthy values are everything else.) The function takes an article
--    history object as its first parameter.
-- makeData: a function that should return a table of data to be used by other
--    functions in this notice configuration table. It can be accessed using
--    noticeObj:getData().
-- icon: the filename of the notice icon, minus the "File:" prefix.
-- iconCaption: the icon caption.
-- iconSize: The icon size, including "px" suffix. The default is defined in
--    defaultIconSize.
-- iconSmallSize: The icon size if we are outputting a small template. The
--    default is defined in defaultSmallIconSize.
-- text: The notice text. This may be a string or a function. If it is a
--    function, it takes an article history object as the first parameter, and
--    the current collapsible notice object as the second parameter, and should
--    return the text string.
-- categories: The categories set by the notice. This may be an array of
--    category names, or a function. If it is a function, it takes an article
--    history object as the first parameter, and the current collapsible notice
--    object as the second parameter, and should return an array of category
--    objects.
-- noticeBarIcon: the icon to use for the notice bar. This can be a string, or
--    a function, or true. If it is a function it takes an article history
--    object as the first parameter, and should output the icon filename. If it
--    is true, it uses the value of icon. If it is nil then no notice bar icon
--    will be displayed.
-- noticeBarIconCaption: the caption to use for the notice bar icon. This can be
--    a string or a function. If it is a function, it takes an article history
--    object as its first parameter, and should return the caption text. If this
--    is absent, the icon caption is used instead.
-- noticeBarIconSize: the size of the notice bar icon, including "px" suffix.
--    The default is set by defaultNoticeBarIconSize.

collapsibleNotices = {
	-- DYK
	{
		id = 'DYK',
		icon = 'DYK questionmark icon.svg',
		iconCaption = 'Did You Know',
		iconSmallSize = '15px',
		noticeBarIcon = true,
		isActive = function (articleHistoryObj)
			return isActiveDatedObject(articleHistoryObj, 'dyk')
		end,
		makeData = function (articleHistoryObj)
			return makeDateData(articleHistoryObj, 'dyk', {'entry'})
		end,
		text = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local raPage = 'Wikipedia:Recent additions/' ..
				getDate('Y/F#j F Y', data[1].date)
			if not titleExists(raPage) then
				raPage = 'Wikipedia:Recent additions'
			end
			local blurb = string.format(
				"A [[%s|'''fact from this article''']] appeared on " ..
					"Wikipedia's [[Main Page]] in the " ..
					"''\"[[:Template:Did you know|Did you know?]]\"'' " ..
					"column $1.",
				raPage
			)
			return makeDateText(data, blurb)
		end,
		collapsibleText = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local ctext = {}
			if #data == 1 and data[1].entry then
				ctext[#ctext + 1] = string.format(
					"The text of the entry was: ''Did you know %s''",
					data[1].entry
				)
			else
				local entries = {}
				local lastEntryDate
				for i, t in ipairs(data) do
					entries[#entries + 1] = t.entry
					lastEntryDate = t.date
				end
				if #entries == 1 then
					ctext[#ctext + 1] = string.format(
						"The text of the entry for %s was: ''Did you know %s''",
						lastEntryDate, entries[1]
					)
				elseif #entries > 1 then
					ctext[#ctext + 1] = 'The text of the entries was:\n'
					local list = mw.html.create('ul')
					for i, t in ipairs(data) do
						if t.entry then
							list:tag('li'):wikitext(string.format(
								"%s: ''Did you know %s''",
								t.date, t.entry
							))
						end
					end
					ctext[#ctext + 1] = tostring(list)
				end
			end
			if #ctext > 0 then
				return table.concat(ctext)
			else
				return nil
			end
		end,
		categories = function (articleHistoryObj, collapsibleNoticeObj)
			local cats = {}
			local status = articleHistoryObj:getStatusId()
			local cat
			if status == 'FA' then
				cat = 'Wikipedia Did you know articles that are featured articles'
			elseif status == 'FL' then
				cat = 'Wikipedia Did you know articles that are featured lists'
			elseif status == 'GA' or status == 'FFA/GA' then
				cat = 'Wikipedia Did you know articles that are good articles'
			else
				cat = 'Wikipedia Did you know articles'
			end
			cats[1] = Category.new(cat)
			return cats
		end
	},

	-- ITN
	{
		id = 'ITN',
		isActive = function (articleHistoryObj)
			return isActiveDatedObject(articleHistoryObj, 'itn')
		end,
		makeData = function (articleHistoryObj)
			return makeDateData(articleHistoryObj, 'itn', {'link'})
		end,
		icon = 'Globe current.svg',
		iconCaption = 'In the news',
		noticeBarIcon = true,
		noticeBarIconSize = '20px',
		text = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local intro
			if #data > 1 then
				intro = 'News items involving this article were'
			else
				intro = 'A news item involving this article was'
			end
			local blurb = intro ..
				" featured on Wikipedia's [[Main Page]] in the " ..
				"''\"[[Template:In the news|In the news]]\"'' column $1."
			return makeDateText(data, blurb)
		end,
		categories = function (articleHistoryObj, collapsibleNoticeObj)
			local cats = {}
			cats[1] = Category.new('Wikipedia In the news articles')
			return cats
		end
	},

	-- On This Day
	{
		id = 'OTD',
		isActive = function (articleHistoryObj)
			return isActiveDatedObject(articleHistoryObj, 'otd')
		end,
		makeData = function (articleHistoryObj)
			return makeDateData(articleHistoryObj, 'otd', {'link'})
		end,
		icon = 'Nuvola apps date.svg',
		iconCaption = 'On this day...',
		noticeBarIcon = true,
		noticeBarIconSize = '20px',
		text = function (articleHistoryObj, collapsibleNoticeObj)
			local data = collapsibleNoticeObj:getData(articleHistoryObj)
			if not data then
				return nil
			end
			local intro
			if #data > 1 then
				intro = 'Facts from this article were'
			else
				intro = 'A fact from this article was'
			end
			local blurb = intro ..
				" featured on Wikipedia's [[Main Page]] in the " ..
				"''\"[[Wikipedia:Selected anniversaries|On this day...]]\"'' " ..
				"column $1."
			return makeDateText(data, blurb)
		end,
		categories = function (articleHistoryObj, collapsibleNoticeObj)
			local cats = {}
			cats[1] = Category.new('Selected anniversaries articles')
			return cats
		end
	},

	-- Article Collaboration and Improvement Drive
	{
		id = 'ACID',
		isActive = function (articleHistoryObj)
			return articleHistoryObj.args.aciddate
		end,
		icon = 'Article Collaboration and Improvement Drive.svg',
		iconCaption = 'Article Collaboration and Improvement Drive',
		noticeBarIcon = true,
		noticeBarIconSize = '20px',
		text = function (articleHistoryObj)
			local args = articleHistoryObj.args
			local blurb = 'This article was on the ' ..
				'[[WP:ACID|Article Collaboration and Improvement Drive]] ' ..
				'for the week of %s.'
			local date = validateDate('aciddate', args.aciddate)
			return string.format(blurb, date)
		end
	},

	-- League of Copy Editors
	{
		id = 'LOCE',
		isActive = function (articleHistoryObj)
			return articleHistoryObj.args.loceNotAnActiveOption
		end,
		icon = 'LoCiconRevised.png',
		iconCaption = 'League of Copyeditors',
		iconSize = '25px',
		noticeBarIcon = true,
		text = 'This article, or a portion of it, was copyedited by the ' ..
			'[[WP:LoCE|League of Copyeditors]].'
	}
},

-------------------------------------------------------------------------------
-- Notice bar icons
-------------------------------------------------------------------------------

-- This table holds configuration tables for notice bar icons that don't appear
-- as part of a row. Other notice bar icons are handled in the statuses,
-- notices, actions, and collapsibleNotices tables.
-- It accepts the following fields:
-- isActive: a function that should return a truthy value if the notice should
--    be displayed, and a falsy value if not. (Falsy values are false and nil,
--    and truthy values are everything else.) The function takes an article
--    history object as its first parameter.
-- icon: the filename of the notice bar icon, minus the "File:" prefix.

noticeBarIcons = {
	-- Peer review, or NA status
	{
		isActive = function (articleHistoryObj)
			local status = articleHistoryObj:getStatusId()
			-- @XXX: This is what the template does, but we should take into
			-- account peer review actions as well.
			return not status or status == 'PR' or status == 'NA'
		end,
		icon = 'Nuvola apps kedit.svg'
	},

	-- Wikipedia 1.0
	{
		isActive = function (articleHistoryObj)
			return articleHistoryObj.args['v1.0NotAnActiveOption']
		end,
		icon = 'WP1 0 Icon.svg'
	}
},

-------------------------------------------------------------------------------
-- Extra categories
-------------------------------------------------------------------------------

-- This table contains categories that don't appear as part of a row. It is an
-- array of functions; each function takes an article history object as input
-- and must return an array of category objects as output.

extraCategories = {
	-- Four award
	function (articleHistoryObj)
		local yesno = require('Module:Yesno')
		local ret = {}
		local isFour = yesno(articleHistoryObj.args.four)
		if isFour then
			ret[#ret + 1] = Category.new('Wikipedia four award articles')
		elseif isFour == false then
			ret[#ret + 1] = Category.new('Wikipedia articles rejected for Four awards')
		elseif articleHistoryObj:getStatusId() == 'FA' then
			local isPossibleFour, isDYK = false, false
			for i, obj in ipairs(articleHistoryObj:getCollapsibleNoticeObjects()) do
				if obj.id == 'DYK' then
					isDYK = true
					break
				end
			end
			if isDYK then
				for i, obj in ipairs(articleHistoryObj:getActionObjects()) do
					if obj.id == 'GAN' and obj:getResult() == 'successful' then
						isPossibleFour = true
						break
					end
				end
			end
			if isPossibleFour then
				ret[#ret + 1] = Category.new('Possible Wikipedia four award articles')
			end
		end
		return ret
	end,

	-- Track the gacat parameter
	function (articleHistoryObj)
		local ret = {}
		if articleHistoryObj.args.gacat then
			table.insert(ret, Category.new('Article history templates with deprecated parameters'))
		end
		return ret
	end,

	-- Track small banners
	function (articleHistoryObj)
		local ret = {}
		if articleHistoryObj.isSmall then
			table.insert(ret, Category.new('Small article history templates'))
		end
		return ret
	end,
},

-------------------------------------------------------------------------------
-- Parameters
-------------------------------------------------------------------------------

-- The parameter values used to generate the page actions. These are used as
-- Lua patterns, so any of the magic characters *+-.^$%[] should be escaped
-- with a preceding % symbol.
actionParamPrefix = 'action',
actionParamSuffixes = {
	[''] = 'code',
	date = 'date',
	link = 'link',
	result = 'resultCode',
	oldid = 'oldid'
},

-- The parameter used to set the current status.
currentStatusParam = 'currentstatus',

-------------------------------------------------------------------------------
-- Other settings
-------------------------------------------------------------------------------

-- If this number or fewer of collapsible rows are present (including actions
-- and collapsible notices) they will not be collapsed. If this is set to the
-- string "all", all rows will always be visible. Otherwise, the input must be
-- a number. The default is three rows.
uncollapsedRows = 3,

-- The default size for icons. The default is 30px.
defaultIconSize = '30px',

-- The default size for icons for small templates. The default is 15px.
defaultSmallIconSize = '15px',

-- The default size for status icons. The default is 50px.
defaultStatusIconSize = '50px',

-- The default size for status icons for small templates. The default is 30px.
defaultSmallStatusIconSize = '30px',

-- The default size for notice bar icons. The default is 15px.
defaultNoticeBarIconSize = '15px',

-- The default size for collapsible status icons. The default is 50px.
defaultCollapsibleNoticeIconSize = '20px',

-- The default size for collapsible status icons for small templates. The
-- default is 30px.
defaultSmallCollapsibleNoticeIconSize = '20px',

-------------------------------------------------------------------------------
-- Messages
-------------------------------------------------------------------------------

msg = {

-- The heading for the collapsible table of actions if we are in the main
-- namespace or the talk namespace.
['milestones-header'] = 'Article milestones',

-- The heading for the collapsible table of actions if we are in a different
-- namespace.
-- $1 - the subject namespace name.
['milestones-header-other-ns'] = '$1 milestones',

-- The milestones date header.
['milestones-date-header'] = 'Date',

-- The milestones process header.
['milestones-process-header'] = 'Process',

-- The milestones result header.
['milestones-result-header'] = 'Result',

-- The format to display the action dates in. The syntax is the same as the
-- #time parser function.
['action-date-format'] = 'F j, Y',

-- The category to use if any errors are detected.
['error-category'] = 'Article history templates with errors',

-- Define boilerplate text for error messages and warnings, both with and
-- without help links.
-- $1 - the error message
-- $2 - a link to a help page and section for the error
['error-message-help'] = 'Error: $1 ([[$2|help]]).',
['error-message-nohelp'] = 'Error: $1.',
['warning-help'] = 'Warning: $1 ([[$2|help]]).',
['warning-nohelp'] = 'Warning: $1.',

-- Error for row objects that should output notice bar icons but for which no
-- icon values could be found.
['row-error-missing-icon'] = "notice bar icon config set to 'true' but no " ..
	'image could be found',

-- A help link for row-error-missing-icon
['row-error-missing-icon-help'] = 'Template:Article history#Missing icon',

-- Error for action objects that aren't passed a code.
-- $1 - the parameter name for the code
['action-error-no-code'] = "no action code found in the '$1' parameter; " ..
	"please add a code or remove other parameters starting with '$1'",

-- A help link for action-error-no-code
['action-error-no-code-help'] = 'Template:Article history#Action codes',

-- Error for action objects that are passed an invalid code.
-- $1 - the code that the user input
-- $2 - the parameter name for the code
['action-error-invalid-code'] = "invalid action code '$1' passed to the '$2' parameter",

-- A help link for action-error-invalid-code
['action-error-invalid-code-help'] = 'Template:Article history#Action codes',

-- Error for action objects with blank result parameters, where result
-- parameters are required for the action's ID.
-- $1 - the action ID
-- $2 - the result parameter name
['action-error-blank-result'] = "the '$1' action requires a result code; " ..
	"please add a result code to parameter '$2'",

-- A help link for action-error-blank-result
['action-error-blank-result-help'] = 'Template:Article history#Action results',

-- Error for action objects with invalid result parameters.
-- $1 - the result code that the user input
-- $2 - the action ID
-- $3 - the result parameter name
['action-error-invalid-result'] = "invalid result '$1' for action '$2' " ..
	"detected in parameter '$3'",

-- A help link for action-error-invalid-result
['action-error-invalid-result-help'] = 'Template:Article history#Action results',

-- Warning for action objects with invalid dates.
-- $1 - the date input by the user
-- $2 - the date parameter name
['action-warning-invalid-date'] = "invalid date '$1' detected in parameter '$2'",

-- A help link for action-warning-invalid-date
['action-warning-invalid-date-help'] = 'Template:Article history#Invalid date',

-- Error for action objects with no dates.
-- $1 - the parameter number
-- $2 - the date parameter name
-- $3 - the action parameter name
['action-warning-no-date'] = "no date specified for action $1; " ..
	"please add a date to parameter '$2' or remove the other parameters " ..
	"beginning with '$3'",

-- A help link for action-warning-no-date
['action-warning-no-date-help'] = 'Template:Article history#No date',

-- The text to display in place of the action date if it is missing.
['action-date-missing'] = '?',

-- Error for action objects with invalid oldids.
-- $1 - the oldid input by the user
-- $2 - the oldid parameter name
['action-warning-invalid-oldid'] = "invalid oldid '$1' detected in parameter '$2'; " ..
	"if an oldid is specified it must be a positive integer",

-- A help link for action-warning-invalid-oldid
['action-warning-invalid-oldid-help'] = 'Template:Article history#Invalid oldid',

-- Error for invalid current status codes.
-- $1 - the code input by the user
['articlehistory-warning-invalid-status'] = "'$1' is not a valid status code",

-- A help link for articlehistory-warning-invalid-status
['articlehistory-warning-invalid-status-help'] = 'Template:Article history#Invalid status',

-- Warning for invocations that specify a current status without specifying any
-- actions.
['articlehistory-warning-status-no-actions'] = "a current status was supplied " ..
	'without any actions',

-- A help link for articlehistory-warning-status-no-actions
['articlehistory-warning-status-no-actions-help'] = 'Template:Article history#No actions',

-- The text to display the current status at the bottom of the collapsible
-- table.
-- $1 - the current status name
['status-blurb'] = "Current status: '''$1'''",

-- The text to display at the bottom of the collapsible table if the current
-- status is unknown.
['status-unknown'] = '?',

}

-------------------------------------------------------------------------------
--                              CONFIG TABLE END
-------------------------------------------------------------------------------

}