بەڵگەدارکردنی مۆدیوول[دروست بکە]
-- This module counts the number of times that various reference tags and cs1|2 templates appear.
-- {{#invoke:ref_info|ref_info}}
-- {{ref info}}
-- {{ref info|aristotle}}

require('Module:No globals');
local data = mw.loadData ('Module:Ref info/data');

--mw.logObject (data.cs12_stripped_list, 'data.cs12_stripped_list')
local collapsible_tables = {
	['cs1'] = '',																-- collapsible wiki-tables of names and counts
	['cs2'] = '',
	['cs1_like'] = '',
	['vcite'] = '',
	['sfn'] = '',
	['harv'] = '',
	}


--[[--------------------------< T E M P L A T E _ N A M E _ T A B L E _ M A K E >------------------------------

makes a collapsed html table that holds a list of cs1 or cs2 template used in an article.  The list occupies a
single row of the parent table.

]]

local function template_name_table_make (name_list, group)
	local name_table = {};

	local function comp (a, b)													-- used in following table.sort()
		return a:lower() < b:lower();											-- case-insensitive ascending alpha sort
	end

	table.insert (name_table, '\n|-\n|scope="row" colspan="2" style="vertical-align:top;text-align:left" |\n');	-- create a blank row in parent table for this table
	table.insert (name_table, '{| class="mw-collapsible mw-collapsed nowrap" style="margin: 0.2em auto auto; width:100%;"\n')	-- open the collapsed list table; style aligns show/hide toggle
	table.insert (name_table, '| List of ');									-- begin simple header row always displays
	table.insert (name_table, group);											-- template group (cs1, cs2 TODO: vcite? harv?)
	table.insert (name_table, ' templates \n');									-- end of simple heading
	table.insert (name_table, '|-\n|\n<hr /><ul>\n');							-- new row, row content begins with <hr />; open unordered list
	local t = {};
	for k, v in pairs (name_list) do											-- spin through the list
		table.insert (t, string.format ('<li>%s (%s)</li>', k, v))				-- make pretty unordered list of name with count
	end
	
	if not t[1] then
		return '';																-- nothing in the list so abandon
	end

	table.sort (t, comp);														-- case-insensitive ascending alpha sort
	table.insert (t, '</ul>\n');												-- close unordered list
	table.insert (name_table, table.concat (t, '\n'));							-- make a string and add to main table
	table.insert (name_table, '\n|}');											-- close the table
	return table.concat (name_table);											-- return html table as a string
end


--[[--------------------------< C O U N T _ P A T T E R N >----------------------------------------------------

this is a general purpose function used to count occurrences of <pattern> in <text>

]]

local function count_pattern (text, pattern)
	local _;
	local count;
	_, count = mw.ustring.gsub (text, pattern, '%1');
	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ L A S T >--------------------------------------------------

makes a count of those cs1|2 templates that use |last= or |last1= (or any of the selected aliases of these).

]]

local function count_cs1_last (template, count)
	local _, tally;

	for _, param in ipairs (data.last_param_patterns) do
		_, tally = mw.ustring.gsub (template, '|%s*' .. param .. '%s*=%s*[^}|]', '%1');		-- count occurences of that pattern
		count = count + tally;													-- accumulate a total
	end

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ A U T H O R >----------------------------------------------

makes a count of those cs1|2 templates that use |author= or |author1= (or any of the selected aliases of these).

]]

local function count_cs1_author (template, count)
	local _, tally;

	for _, param in ipairs (data.author_param_patterns) do
		_, tally = mw.ustring.gsub (template, '|%s*' .. param .. '%s*=%s*[^}|]', '%1');		-- count occurences of that pattern
		count = count + tally;													-- accumulate a total
	end

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ A U T H O R S >--------------------------------------------

makes a count of those cs1|2 templates that use |authors= (or any of the selected aliases).

]]

local function count_cs1_authors (template, count)
	local _, tally;

	for _, param in ipairs (data.authors_param_patterns) do
		_, tally = mw.ustring.gsub (template, '|%s*' .. param .. '%s*=%s*[^}|]', '%1');		-- count occurences of that pattern
		count = count + tally;													-- accumulate a total
	end

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ V A U T H O R S >------------------------------------------

makes a count of those cs1|2 templates that use |vauthors=.

]]

local function count_cs1_vauthors (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*vauthors%s*=%s*[^}|]', '%1');	-- count occurences of that pattern
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ D A T E S _ D M Y >----------------------------------------

Using the lists of cs1|2 templates, make a count of just those templates that have |date=DD Month YYYY where
DD is one or two digits or a range DD-DD Month YYYY

]]

local function count_cs1_dates_dmy (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*date%s*=%s*%d?%d%s+%a+%s+%d%d%d%d', '%1');			-- dd Month yyyy
	count = count + tally;														-- accumulate a total
	_, tally = mw.ustring.gsub (template, '|%s*date%s*=%s*%d?%d[%-–]%d?%d%s+%a+%s+%d%d%d%d', '%1');	-- dd-dd Month yyyy
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ D A T E S _ M D Y >----------------------------------------

Using the lists of cs1|2 templates, make a count of just those templates that have |date=Month DD, YYYY where
DD is one or two digits or a range Month DD-DD, YYYY

]]

local function count_cs1_dates_mdy (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*date%s*=%s*%a+%s+%d?%d%s*,%s+%d%d%d%d', '%1');				-- Month dd, yyyy
	count = count + tally;														-- accumulate a total
	_, tally = mw.ustring.gsub (template, '|%s*date%s*=%s*%a+%s+%d?%d[%-–]%d?%d%s*,%s+%d%d%d%d', '%1');		-- Month dd-dd, yyyy
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ D A T E S _ Y M D >----------------------------------------

Using the lists of cs1|2 templates, make a count of just those templates that have |date=YYYY-MM-DD

]]

local function count_cs1_dates_ymd (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*date%s*=%s*%d%d%d%d%-%d%d%-%d%d', '%1');		-- yyyy-mm-dd
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ D F _ D M Y >----------------------------------------------

Using the lists of cs1|2 templates, make a count of just those templates that have |df=xxx (with a value)

]]

local function count_cs1_df_dmy (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*df%s*=%s*dmy%-?a?l?l?', '%1');	-- |df=dmy |df=dmy-all
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ D F _ M D Y >----------------------------------------------

Using the lists of cs1|2 templates, make a count of just those templates that have |df=xxx (with a value)

]]

local function count_cs1_df_mdy (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*df%s*=%s*mdy%-?a?l?l?', '%1');	-- |df=mdy |df=mdy-all
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 _ D F _ Y M D >----------------------------------------------

Using the lists of cs1|2 templates, make a count of just those templates that have |df=xxx (with a value)

]]

local function count_cs1_df_ymd (template, count)
	local _, tally;

	_, tally = mw.ustring.gsub (template, '|%s*df%s*=%s*ymd%-?a?l?l?', '%1');	-- |df=ymd |df=ymd-all
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C O U N T _ C S 1 2 _ M O D E >--------------------------------------------------

make a count of those cs1|2 templates that have |mode=cs1 or |mode=cs2

]]

local function count_cs12_mode (template, count, mode)
	local _, tally;

	mode = 1 == mode and 'cs1' or 'cs2';
	
	_, tally = mw.ustring.gsub (template, '|%s*mode%s*=%s*' .. mode, '%1');		-- |mode=cs1 or |mode=cs2
	count = count + tally;														-- accumulate a total

	return count;
end


--[[--------------------------< C S 1 _ C S 2 _I N F O _ G E T >-----------------------------------------------

Using the list of cs1|2 templates, make a count of those templates.  Make lists of cs1|2 templates used.  Count
different author-name styles, date styles.

]]

local function cs1_cs2_info_get (Article_content, pattern, template_name_list, object)
	local tstart, tend = Article_content:find (pattern);						-- find the first cs1 template
	local total = 0;
	
	while tstart do																-- nil when cs1|2 template not found
		local template = Article_content:match ('%b{}', tstart);				-- get the whole template

		if template then														-- necessary?
			local name = template:match ('{{%s*([^|}]+)');						-- get template name
			name=mw.text.trim (name);											-- trim whitespace
			if not template_name_list[name] then								-- if not already saved
				template_name_list[name] = 1;									-- save it 
			else																-- here when this name already saved
				template_name_list[name] = template_name_list[name] + 1;		-- to indicate that there are multiple same name templates
			end
			total = total + 1;													-- tally total number of cs1 templates

																				-- count various date properties
			object['cs1_dmy_dates']['count'] = count_cs1_dates_dmy (template, object['cs1_dmy_dates']['count']);	-- count of |date=dmy
			object['cs1_mdy_dates']['count'] = count_cs1_dates_mdy (template, object['cs1_mdy_dates']['count']);	-- count of |date=mdy
			object['cs1_ymd_dates']['count'] = count_cs1_dates_ymd (template, object['cs1_ymd_dates']['count']);	-- count of |date=ymd

			object['cs1_dates_df_dmy']['count'] = count_cs1_df_dmy (template, object['cs1_dates_df_dmy']['count']);	-- count of |df=dmy
			object['cs1_dates_df_mdy']['count'] = count_cs1_df_mdy (template, object['cs1_dates_df_mdy']['count']);	-- count of |df=dmy
			object['cs1_dates_df_ymd']['count'] = count_cs1_df_ymd (template, object['cs1_dates_df_ymd']['count']);	-- count of |df=dmy

																				-- count various author-name properties
			object['cs1_last']['count'] = count_cs1_last (template, object['cs1_last']['count']);					-- count of |lastn=
			object['cs1_author']['count'] = count_cs1_author (template, object['cs1_author']['count']);				-- count of |authorn=
			object['cs1_authors']['count'] = count_cs1_authors (template, object['cs1_authors']['count']);			-- count of |authors=
			object['cs1_vauthors']['count'] = count_cs1_vauthors (template, object['cs1_vauthors']['count']);		-- count of |vauthors=
		
			object['cs1_mode']['count'] = count_cs12_mode (template, object['cs1_mode']['count'], 1);				-- count of |mode=cs1
			object['cs2_mode']['count'] = count_cs12_mode (template, object['cs2_mode']['count'], 2);				-- count of |mode=cs2
		end
		tstart = tend;															-- reset the search starting index
		tstart, tend = Article_content:find (pattern, tstart);					-- search for another cs1|2 template
	end

	return total;
end


--[[--------------------------< C O U N T _ C S 1 >------------------------------------------------------------

Using the list of cs1 templates, make a count of just those templates as dictated by base_pattern.

makes a list of cs1 templates in the article

]]

local function count_cs1 (Article_content, base_pattern, object)
	local _;
	local pattern;
	local total = 0;
	local cs1_template_name_list = {};

	for i, cs1_template in ipairs (data.cs1_template_patterns) do
		pattern = string.format	(base_pattern, cs1_template);					-- make a pattern for the selected cs1 template

		total = total + cs1_cs2_info_get (Article_content, pattern, cs1_template_name_list, object);
	end

	collapsible_tables.cs1 = template_name_table_make (cs1_template_name_list, 'cs1');

--mw.logObject (cs1_template_name_list, 'cs1_template_name_list')
	return total;
end


--[[--------------------------< C O U N T _ C S 1 _ R E F S >--------------------------------------------------

Using the list of cs1 templates, make a count of just those references as dictated by base_pattern.

]]

local function count_cs1_refs (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	for i, template in ipairs (data.cs1_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cs1 template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ C S 1 _ L I K E _ T E M P L A T E S >------------------------------

make a count of cs1-like templates as dictated by <pattern>.

]]

local function count_cs1_like_templates (Article_content, pattern)
	local tstart, tend = Article_content:find (pattern);						-- find the first cs1-like template
	local total = 0;
	local template_name_list = {};

	while tstart do																-- nil when cs1-like template not found
		local template = Article_content:match ('%b{}', tstart);				-- get the template in the ref

		if template then														-- necessary?
			local name = template:match ('{{%s*([^|}]+)');						-- get template name
			name = mw.text.trim (name);											-- trim whitespace
			name = name:gsub (' +', ' ');										-- replace multiple space chars with a single char
			
			if not data.cs12_stripped_list[name] then							-- if not a cs1|2 template
				if not template_name_list[name] then							-- if not already saved
					template_name_list[name] = 1;								-- save it 
				else															-- here when this name already saved
					template_name_list[name] = template_name_list[name] + 1;	-- to indicate that there are multiple same name templates
				end
				total = total + 1;												-- tally total number of cs1-like templates
			end
		end
		tstart = tend;															-- reset the search starting index
		tstart, tend = Article_content:find (pattern, tstart);					-- search for another cs1|2 template
	end

	collapsible_tables.cs1_like = template_name_table_make (template_name_list, 'cs1-like');

	return total;
end


--[[--------------------------< C O U N T _ C S 1 _ L I K E _ R E F S >----------------------------------------

make a count of cs1-like references as dictated by <pattern>.

]]

local function count_cs1_like_refs (Article_content, pattern)
	local tstart, tend = Article_content:find (pattern);						-- find the first cs1-like template
	local total = 0;

	while tstart do																-- nil when cs1-like reference not found
		local template = Article_content:match ('%b{}', tstart);				-- get the template in the ref

		if template then														-- necessary?
			local name = template:match ('{{%s*([^|}]+)');						-- get template name
			name = mw.text.trim (name);											-- trim whitespace
			name = name:gsub (' +', ' ');										-- replace multiple space chars with a single char
			
			if not data.cs12_stripped_list[name] then							-- if not a cs1|2 template
				total = total + 1;												-- tally total number of cs1-like references
			end
		end
		tstart = tend;															-- reset the search starting index
		tstart, tend = Article_content:find (pattern, tstart);					-- search for another cs1|2 template
	end
	return total;
end


--[[--------------------------< C O U N T _ C S 2 >------------------------------------------------------------

Using the list of cs2 templates, make a count of those templates as dictated by base_pattern.

make a list of cs2 templates in the article

]]

local function count_cs2 (Article_content, base_pattern, object)
	local _;
	local pattern;
	local count, total = 0, 0;
	local cs2_template_name_list = {};

	for i, cs2_template in ipairs (data.cs2_template_patterns) do
		pattern = string.format	(base_pattern, cs2_template);					-- make a pattern for the selected cs2 template

		total = total + cs1_cs2_info_get (Article_content, pattern, cs2_template_name_list, object);
	end

	collapsible_tables.cs2 = template_name_table_make (cs2_template_name_list, 'cs2');

--mw.logObject (cs2_template_name_list, 'cs2_template_name_list')
	return total;
end


--[[--------------------------< C O U N T _ C S 2 _ R E F S >--------------------------------------------------

Using the list of cs2 templates, make a count of those references as dictated by base_pattern.

]]

local function count_cs2_refs (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;

	for i, template in ipairs (data.cs2_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cs1 template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ V C I T E >--------------------------------------------------------

Using the list of vcite templates, make a count of just those templates as dictated by base_pattern.

makes a list of vcite templates in the article

]]

local function count_vcite (Article_content, base_pattern, object)
	local _;
	local pattern;
	local total = 0;
	local vcite_template_name_list = {};

	for i, vcite_template in ipairs (data.vcite_template_patterns) do
		pattern = string.format	(base_pattern, vcite_template);					-- make a pattern for the selected vcite template

		local tstart, tend = Article_content:find (pattern);						-- find the first vcite template

		while tstart do																-- nil when vcite template not found
			local template = Article_content:match ('%b{}', tstart);				-- get the whole template
	
			if template then														-- necessary?
				local name = template:match ('{{%s*([^|}]+)');						-- get template name
				name=mw.text.trim (name);											-- trim whitespace
				if not vcite_template_name_list[name] then								-- if not already saved
					vcite_template_name_list[name] = 1;									-- save it 
				else																-- here when this name already saved
					vcite_template_name_list[name] = vcite_template_name_list[name] + 1;		-- to indicate that there are multiple same name templates
				end
				total = total + 1;													-- tally total number of vcite templates
			end
			tstart = tend;															-- reset the search starting index
			tstart, tend = Article_content:find (pattern, tstart);					-- search for another vcite template
		end
	end

	collapsible_tables.vcite = template_name_table_make (vcite_template_name_list, 'vcite');

--mw.logObject (vcite_template_name_list, 'vcite_template_name_list')
	return total;
end


--[[--------------------------< C O U N T _ V C I T E _ R E F S >----------------------------------------------

Using the list of cs1 templates, make a count of just those references as dictated by base_pattern.

]]

local function count_vcite_refs (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	for i, template in ipairs (data.vcite_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected vcite template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< S F N _ H A R V _I N F O _ G E T >---------------------------------------------

Using the list of sfn and harv templates, make a count of those templates.  Make lists of sfn and harv templates
used.

]]

local function sfn_harv_info_get (Article_content, pattern, template_name_list, object)
	local tstart, tend = Article_content:find (pattern);						-- find the first cs1 template
	local total = 0;
	
	while tstart do																-- nil when the template not found
		local template = Article_content:match ('%b{}', tstart);				-- get the whole template

		if template then														-- necessary?
			local name = template:match ('{{%s*([^|}]+)');						-- get template name
			name=mw.text.trim (name);											-- trim whitespace
			if not template_name_list[name] then								-- if not already saved
				template_name_list[name] = 1;									-- save it 
			else																-- here when this name already saved
				template_name_list[name] = template_name_list[name] + 1;		-- to indicate that there are multiple same name templates
			end
			total = total + 1;													-- tally total number of templates
		end
		tstart = tend;															-- reset the search starting index
		tstart, tend = Article_content:find (pattern, tstart);					-- search for another template
	end

	return total;
end


--[[--------------------------< C O U N T _ S F N >------------------------------------------------------------

Using the list of sfn templates, make a count of just those templates as dictated by base_pattern.

makes a list of sfn templates in the article

]]

local function count_sfn (Article_content, base_pattern, object)
	local _;
	local pattern;
	local total = 0;
	local sfn_template_name_list = {};

	for i, sfn_template in ipairs (data.sfn_template_patterns) do
		pattern = string.format	(base_pattern, sfn_template);					-- make a pattern for the selected template

		total = total + sfn_harv_info_get (Article_content, pattern, sfn_template_name_list, object);
	end

	collapsible_tables.sfn = template_name_table_make (sfn_template_name_list, 'sfn');

--mw.logObject (sfn_template_name_list, 'sfn_template_name_list')
	return total;
end


--[[--------------------------< C O U N T _ H A R V >----------------------------------------------------------

Using the list of harv templates, make a count of just those templates as dictated by base_pattern.

makes a list of harv templates in the article

]]

local function count_harv (Article_content, base_pattern, object)
	local _;
	local pattern;
	local total = 0;
	local harv_template_name_list = {};

	for i, harv_template in ipairs (data.harv_template_patterns) do
		pattern = string.format	(base_pattern, harv_template);					-- make a pattern for the selected template

		total = total + sfn_harv_info_get (Article_content, pattern, harv_template_name_list, object);
	end

	collapsible_tables.harv = template_name_table_make (harv_template_name_list, 'harv');

--mw.logObject (harv_template_name_list, 'harv_template_name_list')
	return total;
end


--[[--------------------------< C O U N T _ H A R V _ R E F S >------------------------------------------------

Using the list of harv templates, make a count of those references as dictated by base_pattern.

]]

local function count_harv_refs (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;

	for i, template in ipairs (data.harv_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cs1 template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ R E F B E G I N >--------------------------------------------------

Using the list of cleanup templates, make a count of those templates as dictated by base_pattern.

]]

local function count_refbegin (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	
	for i, template in ipairs (data.refbegin_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cleanup template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ R P >--------------------------------------------------------------

Using the list of cleanup templates, make a count of those templates as dictated by base_pattern.

]]

local function count_rp (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	
	for i, template in ipairs (data.rp_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cleanup template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ C L E A N U P >----------------------------------------------------

Using the list of cleanup templates, make a count of those templates as dictated by base_pattern.

]]

local function count_cleanup (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	
	for i, template in ipairs (data.cleanup_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cleanup template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ D E A D _ L I N K S >----------------------------------------------

Using the list of dead link templates, make a count of those templates as dictated by base_pattern.

]]

local function count_dead_links (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	
	for i, template in ipairs (data.dead_link_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected cleanup template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< C O U N T _ W E B A R C H I V E >----------------------------------------------

Using the list of webarchive aliases, make a count of those templates as dictated by base_pattern.

]]

local function count_webarchive (text, base_pattern)
	local _;
	local pattern;
	local count, total = 0, 0;
	
	for i, template in ipairs (data.webarchive_template_patterns) do
		pattern = string.format	(base_pattern, template);						-- make a pattern for the selected webarchive template
		_, count = mw.ustring.gsub (text, pattern, '%1');						-- count occurences of that pattern
		total = total + count;													-- accumulate a total
	end
	return total;
end


--[[--------------------------< H A S _ L D R >----------------------------------------------------------------

returns a string set to 'yes' if the article uses list defined references.  ldr uses {{reflist |refs=...}} or
<references>...</references>.  Here we do simple 'find's to make the determination.

It is also possible to do ldr with {{refbegin}} ... {{refend}} 

the pattern value is passed to this function but ignored
]]

local function has_ldr (text)
	local pattern;

	for i, template in ipairs (data.reflist_template_patterns) do
		pattern = string.format	('{{%%s*%s[^}]*|%%s*refs%%s*=%%s*[^}|]+', template);	-- make a pattern using the selected reflist template

		if mw.ustring.find (text, '{{%s*[Rr]eflist[^}]*|%s*refs%s*=%s*[^}|]+') then	-- does page use {{Reflist |refs=...}}?
			return 'yes'
		end
	end

	if mw.ustring.find (text, '<references>[^<]+') then							-- no reflist template, does page use <references>...</references>?
		return 'yes'
	else
		return 'no';
	end
end


--[[--------------------------< H A S _ U S E _ X X X _ D A T E S >--------------------------------------------

returns string set to either of 'dmy' or 'mdy'

TODO: needs companion |cs1-dates= support somehow ... 2 separate tests? one detects {{use xxx dates |cs1-dates=xx}} the other detects {{use xxx dates}}?
Also, detect conflicting |df= parameters?

]]

local global_df;

local function has_use_xxx_dates (text, pattern)
	local ret_val = 'no';														-- presume not found
	local df_template_patterns = {												-- table of redirects to {{Use dmy dates}} and {{Use mdy dates}}
		'{{ *[Uu]se (dmy) dates *[|}]',		-- 915k								-- sorted by approximate transclusion count
		'{{ *[Uu]se *(mdy) *dates *[|}]',	-- 161k
		'{{ *[Uu]se (DMY) dates *[|}]',		-- 2929
		'{{ *[Uu]se *(dmy) *[|}]',			-- 250 + 34
		'{{ *([Dd]my) *[|}]',				-- 272
		'{{ *[Uu]se (MDY) dates *[|}]',		-- 173
		'{{ *[Uu]se *(mdy) *[|}]',			-- 59 + 12
		'{{ *([Mm]dy) *[|}]',				-- 9
		'{{ *[Uu]se (MDY) *[|}]',			-- 3
		'{{ *([Dd]MY) *[|}]',				-- 2
		'{{ *([Mm]DY) *[|}]',				-- 0
--		'{{ *[Uu]se(mdy) *[|}]',
--		'{{ *[Uu]se(mdy)dates *[|}]',
--		'{{ *[Uu]se(dmy) *[|}]',
		}

	for _, pattern in ipairs (df_template_patterns) do							-- loop through the patterns looking for {{Use dmy dates}} or {{Use mdy dates}} or any of their redirects
		local start, _, match = text:find(pattern);								-- match is the three letters indicating desired date format

		if match then
			ret_val = match;													-- set return value to the global date format
			global_df = match;													-- save for |df= tests
			text = text:match ('%b{}', start);									-- get the whole use xxx dates template
			if text:match ('| *cs1%-dates *= *[lsy][sy]?') then					-- look for |cs1-dates=publication date length access-/archive-date length
				ret_val = ret_val .. ' [' .. text:match ('| *cs1%-dates *= *([lsy][sy]?)') .. ']';
			end
			break;																-- loop escape
		end
	end

	return ret_val;
end


--[[--------------------------< O B J E C T S   T A B L E >----------------------------------------------------

Here we define various properties and values necessary to the counting of referencing objects

]]

local objects = {
	['unnamed_refs'] = {														-- count unnamed ref tags
		['func'] = count_pattern,												-- the function that does the work for this object
		['pattern'] = '(<ref>)',												-- a pattern that the function uses to find and count this object
		['count'] = 0,															-- the returned result (called count because that is the most common but can be 'yes' or 'no' etc
		['label'] = 'unnamed refs'												-- a label and markup for displaying the result; used with string.format()
		},
	['named_refs'] = {															-- count named ref tags
		['func'] = count_pattern,
		['pattern'] = '(<ref%s+name%s*=%s*[%a%d%p ]+>)',
		['count'] = 0,
		['label'] = 'named refs'
		},
	['self_closed_refs'] = {													-- count self closed ref tags
		['func'] = count_pattern,
		['pattern'] = '(<ref%s*name%s*=%s*["%a%d%p ]+/>)',
		['count'] = 0,
		['label'] = 'self closed'
		},
	['r_templates'] = {															-- count R templates (wrapper for self closed refs)
		['func'] = count_pattern,
		['pattern'] = '({{%s*[Rr]%s*|)',
		['count'] = 0,
		['label'] = 'R templates'
		},
	['refn_templates'] = {														-- count Refn templates
		['func'] = count_pattern,
		['pattern'] = '({{%s*[Rr]efn%s*|)',
		['count'] = 0,
		['label'] = 'Refn templates'
		},
	['bare_url_refs'] = {														-- count bare url refs
		['func'] = count_pattern,												-- TODO: separate function to detect protocol relative urls?
		['pattern'] = '(<ref[^>]*>%s*http[^<%s]+%s*</ref>)',
		['count'] = 0,
		['label'] = '<span style="font-size:inherit" class="error">bare url refs</span>'
		},
	['ext_link_refs'] = {														-- count unlabeled external link refs
		['func'] = count_pattern,												-- TODO: separate function to detect protocol relative urls?
		['pattern'] = '(<ref[^>]*>%[%s*http[^%]<%s]+%][^<]*</ref>)',
		['count'] = 0,
		['label'] = '<span style="font-size:inherit" class="error">bare ext link refs</span>'
		},
	['cs1_like_refs'] = {														-- count cs1 refs and refs that look like cs1 (cite something)
		['func'] = count_cs1_like_refs,
		['pattern'] = '(<ref[^>]*>[^<{]*{{%s*[Cc]ite%s+[^|]+)',
		['count'] = 0,
		['label'] = 'cs1-like refs'
		},
	['cs1_refs'] = {															-- count cs1 refs only
		['func'] = count_cs1_refs,
		['pattern'] = '(<ref[^>]*>[^<{]*{{%%s*%s%%s*|)',						-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'cs1 refs'
		},
	['cs1_like_templates'] = {													-- count templates that look like cs1
		['func'] = count_cs1_like_templates,
		['pattern'] = '({{%s*[Cc]ite%s+[^|]+)',
		['count'] = 0,
		['label'] = 'cs1-like templates'
		},
	['cs1_templates'] = {														-- count cs1 templates only
		['func'] = count_cs1,
		['pattern'] = '({{%%s*%s%%s*|)',										-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'cs1 templates'
		},
	['cs2_refs'] = {															-- count cs2 refs
		['func'] = count_cs2_refs,
		['pattern'] = '(<ref[^>]*>[^<{]*{{%%s*%s%%s*|)',						-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'cs2 refs'
		},
	['cs2_templates'] = {														-- count cs2 templates
		['func'] = count_cs2,
		['pattern'] = '{{%%s*%s%%s*|',
		['count'] = 0,
		['label'] = 'cs2 templates'
		},
	['vcite_refs'] = {															-- count vancite, vcite, and vcite2 refs
--		['func'] = count_pattern,
--		['pattern'] = '(<ref[^>]*>[^<{]*{{%s*[Vv]a?n?cite2?%s+[^|]+)',
		['func'] = count_vcite_refs,
		['pattern'] = '(<ref[^>]*>[^<{]*{{%%s*%s%%s*|)',
		['count'] = 0,
		['label'] = 'vcite refs'
		},
	['vcite_templates'] = {														-- count vancite templates
		['func'] = count_vcite,
		['pattern'] = '{{%%s*%s%%s*|',
--		['func'] = count_pattern,
--		['pattern'] = '({{%s*[Vv]a?n?cite2?%s+[^|]+)',
		['count'] = 0,
		['label'] = 'vcite templates'
		},
	['wikicite_templates'] = {													-- count wikicite templates
		['func'] = count_pattern,
		['pattern'] = '({{%s*[Ww]ikicite%s*|)',
		['count'] = 0,
		['label'] = 'wikicite templates'
		},
	['harv_refs'] = {															-- count harv refs
		['func'] = count_harv_refs,
		['pattern'] = '(<ref[^>]*>[^<{]*{{%%s*%s%%s*|)',						-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'harv refs'
		},
	['harv_templates'] = {														-- count harv templates
		['func'] = count_harv,
		['pattern'] = '({{%%s*%s%%s*|)',
		['count'] = 0,
		['label'] = 'harv templates'
		},
	['sfn_templates'] = {														-- count sfn templates
		['func'] = count_sfn,
		['pattern'] = '({{%%s*%s%%s*|)',
		['count'] = 15,
		['label'] = 'sfn templates'
		},
	['rp_templates'] = {														-- count rp templates
		['func'] = count_rp,
		['pattern'] = '({{%%s*%s%%s*[|}])',
		['count'] = 0,
		['label'] = 'rp templates'
		},
	['ldr'] = {																	-- does this article use list defined references?
		['func'] = has_ldr,
		['pattern'] = '',														-- uses multiple patterns which are defined in the function
		['count'] = 'no',
		['label'] = 'uses ldr'
		},
	['refbegin_templates'] = {													-- count refbegin templates - bibliography lists
		['func'] = count_refbegin,
		['pattern'] = '({{%%s*%s%%s*[|}])',
		['count'] = 0,
		['label'] = 'refbegin templates'
		},
	['cleanup_templates'] = {													-- count cleanup templates
		['func'] = count_cleanup,
		['pattern'] = '({{%%s*%s%%s*[|}])',										-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'cleanup templates'
		},
	['dead_link_templates'] = {													-- count deadlink templates (includes redirects)
		['func'] = count_dead_links,
		['pattern'] = '({{%%s*%s%%s*[|}])',										-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'dead link templates'
		},
	['webarchive_templates'] = {												-- count webarchive templates (includes redirects)
		['func'] = count_webarchive,
		['pattern'] = '({{%%s*%s%%s*|)',										-- will be modified in the func by string.format()
		['count'] = 0,
		['label'] = 'webarchive templates'
		},
	['use_xxx_dates'] = {														-- does this article use list defined references?
		['func'] = has_use_xxx_dates,
		['pattern'] = nil,														-- uses multiple patterns that are defined in the function
		['count'] = 'no',
		['label'] = 'use xxx dates'
		},

	['cs1_dates_df_dmy'] = {													-- count 
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 df dmy'
		},
	['cs1_dates_df_mdy'] = {													-- count 
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 df mdy'
		},
	['cs1_dates_df_ymd'] = {													-- count 
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 df ymd'
		},

	['cs1_dmy_dates'] = {														-- count cs1 templates only
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 dmy dates'
		},
	['cs1_mdy_dates'] = {														-- count cs1 templates only
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 mdy dates'
		},
	['cs1_ymd_dates'] = {														-- count cs1 templates only
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 ymd dates'
		},
	['cs1_last'] = {															-- count cs1 templates only
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 last/first'
		},
	['cs1_author'] = {															-- count cs1 templates only
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 author'
		},
	['cs1_authors'] = {															-- count cs1 templates only
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 authors'
		},
	['cs1_vauthors'] = {
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1|2 vauthors'
		},
	['cs1_mode'] = {
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs1 mode'
		},
	['cs2_mode'] = {
		['func'] = nil,															-- handled by cs1_cs2_info_get()
		['pattern'] = nil,
		['count'] = 0,
		['label'] = 'cs2 mode'
		},
	}
																				-- here we set the order in which the objects are processed
local order = {'unnamed_refs', 'named_refs', 'self_closed_refs',				-- these three are always output
	'r_templates',																-- this and the others only produce output when ...
	'refn_templates',															-- ... their count is not 0 or not 'no'
	'bare_url_refs',
	'ext_link_refs',
	'cs1_refs',
	'cs1_templates',
	'cs1_like_refs',
	'cs1_like_templates',
	'cs2_refs',
	'cs2_templates',
	'vcite_refs', 'vcite_templates',
	'wikicite_templates',
	'harv_refs', 'harv_templates',
	'sfn_templates',
	'rp_templates',
	'ldr',
	'refbegin_templates',
	'cleanup_templates',
	'dead_link_templates',
	'webarchive_templates',
	'use_xxx_dates',
	'cs1_dates_df_dmy',
	'cs1_dates_df_mdy',
	'cs1_dates_df_ymd',
	'cs1_dmy_dates',
	'cs1_mdy_dates',
	'cs1_ymd_dates',
	'cs1_last',
	'cs1_author',
	'cs1_authors',
	'cs1_vauthors',
	'cs1_mode',
	'cs2_mode',
	};


--[[--------------------------< R E F _ I N F O >--------------------------------------------------------------

the working part of Template:Ref info

]]


local function ref_info (frame)
	local text;																	-- unparsed page content
	local title;																-- page title without namespace or interwiki references
	local nstitle;																-- page title with namespace and interwiki references
	local page_title_object;													-- 
	local output = {};
	local i=1;
	local style = frame.args.style or '';										-- styling css for output table
	
	if frame.args[1] then
		page_title_object = mw.title.new(frame.args[1]);						-- title object for the page specified in the template call
	else
		page_title_object = mw.title.getCurrentTitle();							-- title object for the current page
	end

	text = page_title_object:getContent();										-- the unparsed content of the selected page
	text = text:gsub ('<nowiki>.-</nowiki>', '');								-- remove nowiki tags and their content; less constrained
	text = text:gsub ('<!%-%-.-%-%->', '');										-- remove html comments and their content
	text = text:gsub ('<pre>.-</pre>', '');										-- remove pre tags and their content

	nstitle = page_title_object.prefixedText;									-- the title of the page (with namespace)
	title = page_title_object.text;												-- the title of the page (without namespace)

	if nil == text then
		return string.format ('<span style="font-size:100%%" class="error">{{ref info}} – page is empty or does not exist: %s</span>', frame.args[1] or 'no page');
	end

	for i, object in ipairs (order) do											-- loop through order and search for the related objects
		if objects[object].func then
			objects[object].count = objects[object].func (text, objects[object].pattern, objects)	-- do the search and store the result
		end
	end
																				-- for those that count duplicates remove the duplicates from the counts
	objects['named_refs'].count = objects['named_refs'].count - objects['self_closed_refs'].count;

	table.insert (output, string.format ('{| class="wikitable" style="text-align:right; %s"\n|+reference info for [[%s|%s]]', style, nstitle, title));	-- output table header

	for i, object in ipairs (order) do											-- loop through order and search for the related objects
		if i<=3 then															-- first three (reference tags) are always output
			table.insert (output, string.format ('%s\n|%s', objects[object].label, objects[object].count));
		elseif 'string' == type (objects[object].count) then					-- objects[object].count can be a string or a number
			if 'no' ~= objects[object].count then								-- if a string and not 'no' ...
				table.insert (output, string.format ('%s\n|%s', objects[object].label, objects[object].count));	-- output the result
			end
		elseif 'number' == type (objects[object].count) then					-- if a number ...
		 	if 0 < objects[object].count then									-- ... and count is greater than zero ...
				table.insert (output, string.format ('%s\n|%s', objects[object].label, objects[object].count));	-- ... output the result
			end
		end
	end

	output = {table.concat (output,'\n|-\n! scope="row" | ')};					-- concat an intermediate result
	table.insert (output, collapsible_tables.cs1);								-- add the collapsible tables
	table.insert (output, collapsible_tables.cs2);
	table.insert (output, collapsible_tables.cs1_like);
	table.insert (output, collapsible_tables.vcite);
	table.insert (output, collapsible_tables.sfn);
	table.insert (output, collapsible_tables.harv);
	table.insert (output, '\n|-\n|scope="row" colspan="2" style="text-align:center"|[[Template:Ref_info#Output_meanings|explanations]]\n|-\n|}');

	return table.concat (output);
end


--[[--------------------------< E X P O R T E D   F U N C T I O N S >------------------------------------------
]]

return {
	ref_info = ref_info,
	}