Zum Inhalt springen

Modul:European and national party data

aus Wikipedia, der freien Enzyklopädie
Vorlagenprogrammierung Diskussionen Lua Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus

Diese Seite ist eine lokale Kopie aus en.wikipedia.org und von dort zu aktualisieren.

This module is currently in pre-alpha version on this Wiki. It seeks to adapt the European and national party data module, and work and translations are on-going. This module should not be used in its current form. For more information on the status of this work, see the dedicated roadmap.

{{#invoke:European and national party data|main|<party_type>|<data_type>|<party>|<institution>|extra parameters}}

Parameter Description
1 The type of party under consideration; can be either:

This parameter is mandatory.

2 The type of data requested and pulled from Wikidata, from the following list:
  • seats: the number of seats of one or more entities in one or more institutions (P1410);
  • seat share: the share of seats of one or more entities in one or more institutions (based on P1410);
  • seat composition bar: a composition bar showing the seats of one or more entities in one or more institutions (based on P1410);
  • acronym: the short name of the entity (P1813);
  • color: the official colour of the entity as a hex code (P465);
  • country: the country in which the entity is registered (P17);
  • foundation date: the date on which the entity was founded (P571);
  • individual members: the number of individual members of the entity (P2124);
  • individual members date: the reference date for the number of individual members of the entity (based on P2124);
  • label: the name of the entity;
  • official name: the official long-form name of the entity (P1448);
  • parliamentary group: the parliamentary group the entity belongs to (P4100);
  • public funding: the amount of public funding received by the entity (P12919); or
  • website: the official website of the entity (P856), stripped from "https", "http" and "www" prefixes.

This parameter is mandatory.

3 The name of the entity, from the following list:
  • in all cases, the name can be omitted when the module is called from the Wikipedia page of the entity (alternatively, thisparty can be used to refer to the entity in question;
  • for European entities: the acronym of the entity (see list below) or its Wikidata qID; and
  • for national parties: the Wikidata qID of the party.

This parameter is optional when called from the page of the entity in question.

The following acronyms are used for European parties:

In addition, the following European political alliances are covered:

In addition, four special parameters can be used instead of European parties (so not when |party_type=national_party):

  • all: for the seats of all European parties combined;
  • none: for the seats not occupied by members of European parties (not for lower and upper houses); and
  • ind: for independent politicians on the European Council (only).

Notes:

  • the capitalisation of parameters does not matter;
  • given the cost of calling Wikidata when using a specific qID (i.e., not calling Wikidata from a linked Wikipedia page), the special parameter "thisparty" should be used whenever this module is called from the page of a European party; and
  • since the listed European political alliances are not European political parties, they do not count towards to sum of seats occupied by European political parties, nor the seats not occupied by European political parties.
4 The name of the institution, from the following list:

Notes:

  • For lower and upper houses for national parties, the module will automatically determine the relevant body, using this table;
  • For lower and upper houses for European parties, the module will sum the number of seats of their member parties across member states; and
  • For the European Parliament for national parties, the module will automatically use the member state's number of seats in the Parliament.

This parameter is mandatory when data_type is seat, seat share, or seat composition bar.

extra parameters The following extra parameters can also be used, depending on the requested data_type:
  • all data_types:
    • reference will display the reference when |reference=yes (this parameter is ignored for the seats of lower or upper houses of European entities, as many national figures are summed);
  • seat share:
    • constituency will override the institution's number of seats (for instance when the party is part of a special constituency);
  • seat composition bar:
    • constituency will override the institution's number of seats (for instance when the party is part of a special constituency);
    • width will specify the width of the bar and can have the following formats: "80" (default unit is pixel), "80px", "80em", or "80%" (without spaces);
    • percent will display the percentage when |percent=yes;
    • bar-color, background-color, and border will override default colours when provided an hexadecimal value (e.g."#123ABC", including the pound sign) or a recognised colour (e.g. "red").
  • all other data_types:
    • verbose: will display an error message when no value exists on Wikidata, as well as a relevant link, when |verbose=yes (otherwise the field is empty).

These parameters are optional.

[Quelltext bearbeiten]

The module is directly implemented by two templates:

The module has two testcase pages:

Updating the module

[Quelltext bearbeiten]

The module draws its data from two sources:

Data type seats

[Quelltext bearbeiten]
Code Result Output
{{#invoke:European and national party data|main|european_entity|seats|EPP|EP}} Q208242 (property) number of seats of the European People's Party in the European Parliament
{{#invoke:European and national party data|main|european_entity|seats|PES|EC|reference=yes}} Q220945 (property)Q220945 (references) number of seats of the Party of European Socialists in the European Commission, with reference
{{#invoke:European and national party data|main|european_entity|seats|ind|EUCO}} Q327591 (property) number of seats of independent politicians in the European Council
{{#invoke:European and national party data|main|european_entity|seats|ALDE|ms-lower-house}} Lua-Fehler in Zeile 600: attempt to perform arithmetic on a string value number of seats of the Alliance of Liberals and Democrats for Europe in member states' lower houses
{{#invoke:European and national party data|main|european_entity|seats|EGP|ms-upper-house|reference=yes}} Lua-Fehler in Zeile 600: attempt to perform arithmetic on a string value number of seats of the European Green Party in member states' upper houses, without reference (see table above)
{{#invoke:European and national party data|main|european_entity|seats|Q208242|EC}} Q208242 (property) number of seats of the European People's Party (called by its Wikidata qID) in the European Commission
{{#invoke:European and national party data|main|european_entity|seats|Q208242|ms-upper-house}} Lua-Fehler in Zeile 596: attempt to perform arithmetic on a string value number of seats of the European People's Party (called by its Wikidata qID) in member states' upper houses
{{#invoke:European and national party data|main|national_party|seats|Q13564543|ms-lower-house|reference=yes}} Q13564543 (property)Q13564543 (references) number of seats of Austria's NEOS (called by its Wikidata qID) in the National Council, with reference
{{#invoke:European and national party data|main|national_party|seats|Q138198|ms-upper-house}} Q138198 (property) number of seats of the Spanish Socialist Workers' Party (called by its Wikidata qID) in the Senate
{{#invoke:European and national party data|main|national_party|seats|Q49768|EP}} Q49768 (property) number of seats of the Social Democratic Party of Germany (called by its Wikidata qID) in the European Parliament
{{#invoke:European and national party data|main|european_entity|seats|all|EP}} Lua-Fehler in Zeile 463: attempt to perform arithmetic on a string value number of seats of all European parties combined in the European Parliament
{{#invoke:European and national party data|main|european_entity|seats|none|EP}} Lua-Fehler in Zeile 463: attempt to perform arithmetic on a string value number of seats not occupied by European parties in the European Parliament

Data type seat share

[Quelltext bearbeiten]
Code Result Output
{{#invoke:European and national party data|main|european_entity|seat share|EPP|EP|reference=yes}} Q208242 (property) share of seats of the European People's Party in the European Parliament, with reference
{{#invoke:European and national party data|main|european_entity|seat share|ind|EUCO}} Q327591 (property) share of seats of independent politicians in the European Council
{{#invoke:European and national party data|main|european_entity|seat share|ALDE|ms-lower-house}} Lua-Fehler in Zeile 600: attempt to perform arithmetic on a string value share of seats of the Alliance of Liberals and Democrats for Europe in member states' lower houses
{{#invoke:European and national party data|main|european_entity|seat share|Q208242|EC}} Q208242 (property) share of seats of the European People's Party (called by its Wikidata qID) in the European Commission
{{#invoke:European and national party data|main|national_party|seat share|Q13564543|ms-lower-house}} Lua-Fehler in Zeile 659: attempt to perform arithmetic on local 'npp_seats' (a string value) share of seats of Austria's NEOS (called by its Wikidata qID) in the National Council
{{#invoke:European and national party data|main|national_party|seat share|Q655611|ms-lower-house|constituency=61}} Lua-Fehler in Zeile 657: attempt to perform arithmetic on local 'npp_seats' (a string value) share of seats of Belgium's Écolo (called by its Wikidata qID) in the French-speaking seats of the Chamber of Representatives
{{#invoke:European and national party data|main|national_party|seat share|Q49768|EP|reference=yes}} Q49768 (property) share of seats of the Social Democratic Party of Germany (called by its Wikidata qID) in the European Parliament, with reference
{{#invoke:European and national party data|main|european_entity|seat share|all|EP}} Lua-Fehler in Zeile 463: attempt to perform arithmetic on a string value share of seats of all European parties combined in the European Parliament

Data type seat composition bar

[Quelltext bearbeiten]
Code Result Output
{{#invoke:European and national party data|main|european_entity|seat composition bar|EPP|EP|reference=yes}} Lua-Fehler: expandTemplate: template "Composition bar" does not exist composition bar of seats of the European People's Party in the European Parliament, with reference
{{#invoke:European and national party data|main|european_entity|seat composition bar|ind|EUCO|percent=yes}} Lua-Fehler: expandTemplate: template "Composition bar" does not exist composition bar of seats of independent politicians in the European Council, with reference
{{#invoke:European and national party data|main|european_entity|seat composition bar|ALDE|ms-lower-house}} Lua-Fehler in Zeile 600: attempt to perform arithmetic on a string value composition bar of seats of the Alliance of Liberals and Democrats for Europe in member states' lower houses
{{#invoke:European and national party data|main|european_entity|seat composition bar|Q208242|EC|percent=yes|reference=yes}} Lua-Fehler: expandTemplate: template "Composition bar" does not exist composition bar of seats of the European People's Party (called by its Wikidata qID) in the European Commission, with reference
{{#invoke:European and national party data|main|national_party|seat composition bar|Q655611|ms-lower-house|constituency=61}} Lua-Fehler: expandTemplate: template "Composition bar" does not exist composition bar of seats of Belgium's Écolo (called by its Wikidata qID) in the French-speaking seats of the Chamber of Representatives
{{#invoke:European and national party data|main|national_party|seat composition bar|Q49768|EP|width=80%|background-color=blue|border=green|bar-color=red}} Lua-Fehler: expandTemplate: template "Composition bar" does not exist composition bar of seats of the Social Democratic Party of Germany (called by its Wikidata qID) in the European Parliament, with special parameters
{{#invoke:European and national party data|main|european_entity|seat composition bar|all|EP|width=80%|background-color=#FFFF00|border=#008080|bar-color=#A020F0}} Lua-Fehler in Zeile 463: attempt to perform arithmetic on a string value composition bar of seats of all European parties combined in the European Parliament, with special parameters

Other data types

[Quelltext bearbeiten]
Code Result Output
{{#invoke:European and national party data|main|european_entity|acronym|EPP}} (property) acronym of the European People's Party
{{#invoke:European and national party data|main|european_entity|color|PES}} # (property) colour of the Party of European Socialists
{{#invoke:European and national party data|main|european_entity|color|PES}} (property) country of Levice (called by its Wikidata qID)
{{#invoke:European and national party data|main|european_entity|foundation date|PES}} (property) foundation date of the Party of European Socialists
{{#invoke:European and national party data|main|european_entity|individual members|EPP|reference=yes}} references (property) individual members of the European People's Party, with reference
{{#invoke:European and national party data|main|european_entity|label|ALDE}} Q25079 (label) label of the Alliance of Liberals and Democrats for Europe
{{#invoke:European and national party data|main|european_entity|official name|EGP}} (property) official name of the European Green Party
{{#invoke:European and national party data|main|european_entity|parliamentary group|EFA}} (property) parliamentary group of the European Free Alliance
{{#invoke:European and national party data|main|european_entity|public funding|EGP}} (property) public funding of the European Green Party, with reference
{{#invoke:European and national party data|main|national_party|website|Q667680}} [[[d:property| (property)]] (property)] website of the Netherlands' GroenLinks
{{#invoke:European and national party data|main|national_party|official name|Q22748|verbose=yes}} (property) official name of Germany Die PARTEI, showing verbose error message

Vorlage:Sandbox other



require ('strict');
local get_args = require ('Module:Arguments').getArgs;							-- function to fetch frame and parent frame arguments
local cfg = mw.loadData ('Module:European and national party data/config');		-- defines, configuration data, and i18n support
local namespace = mw.title.getCurrentTitle().namespace;							-- used for categorization


--[[==========================< S E C T I O N _ 1 : F U N C T I O N A L _ F U N C T I O N S >=======================

These are generic functions to accomplish specific, non-party-related tasks.

]]

--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------

substitutes $1, $2, etc in <message> with data from <data_t>. Returns plain-text substituted string when
<data_t> not nil; returns <message> else.

]]

local function substitute (message, data_t)
	return data_t and mw.message.newRawMessage (message, data_t):plain() or message;
end


--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------

assembles an error message from template name, message text, help link, and error category.

]]

local function make_error_msg (msg, template_name, nocat)
	local category;

	local category_link = ((0 == namespace) and not nocat) and substitute ('[[Category:$1]]', {cfg.settings_t.err_category}) or '';
	return substitute ('<span style="color:#d33">Error: &#x7B;{$1}}: $2 ([[:Template:$1|$3]])</span>$4',
		{
		template_name or cfg.settings_t.template_name or frame:getParent():getTitle(),	-- the template name without namespace
		msg,																	-- the error message
		cfg.settings_t.help,													-- help wikilink display text
		category_link															-- link to error category (main namespace only)
		})
end
	

--[[--------------------------< R O U N D >--------------------------------------------------------------------

return the rounded value of the arguments with two decimals

]]

local function round (n)
  return math.floor(100 * n + 0.5) / 100										-- round argument to two decimals
end


--[[--------------------------< S T R I P _ U R L >--------------------------------------------------------------------

return the stripped down URL with a hyperlink

]]

local function strip_URL (URL)
	local new_URL = URL;
	local patterns_t = {'^https://www.', '^http://www.', '^https://', '^http://', '/$'};				-- valid <width> patterns
	for i, pattern in ipairs (patterns_t) do									-- loop through the patterns in <patterns_t>
		new_URL = new_URL.gsub(new_URL, pattern, "");
	end
	return "[" .. URL .. " " .. new_URL .. "]"
end



--[[==========================< S E C T I O N _ 2 : V A L I D A T I O N _ F U N C T I O N S >=======================

These are functions to ensure data validation and return error messages when relevant.

]]

--[[--------------------------< V A L I D A T E _ W I D T H >--------------------------------------------------

validates data format for the width parameter of composition bars; returns boolean true when valid; nil else

]]

local function validate_width (width)
	local patterns_t = {'^%d+$', '^%d+px$', '^%d+%%$', '^%d+em$'};				-- valid <width> patterns
	for i, pattern in ipairs (patterns_t) do									-- loop through the patterns in <patterns_t>
		if width:match (pattern) then											-- is there a match?
			return true;														-- yes, done
		end
	end
end


--[[--------------------------< H A R M O N I S E _ H O U S E _ T Y P E >----------------------------------------------

harmonises house type input (for calls relating to lower and upper houses)

]]

local function harmonise_lower_upper_house_name (house_type)
	if house_type == "LOWER-HOUSE" or house_type == "LOWER" or house_type == "MS-LOWER-HOUSE"then	-- the three accepted formats for input
		return "LOWER_HOUSE";													-- format actually used in the code
	elseif house_type == "UPPER-HOUSE" or house_type == "UPPER" or house_type == "MS-UPPER-HOUSE" then	-- the three accepted formats for input
		return "UPPER_HOUSE";													-- format actually used in the code
	else
		return house_type;
	end
end


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

when institution parameter exists, checkes that it is correct; returns boolean true when valid; error message else

]]

local function validate_institution (institution, template_name)
	
	if institution and not cfg.institutions_t[institution] and not cfg.national_institutions_t[institution] then	-- if institution is present, it must be known
		return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution}), template_name);
	end

	return true;
end



--[[==========================< S E C T I O N _ 3 : G E T _ F U N C T I O N S >=======================

These are functions to grab data from Wikidata

]]

--[[--------------------------< G E T _ D A T A >----------------------------------------------------------

general function to return data for the requested property for a party; <frame> required to expand {{wikidata}} template

]]

local function allpp_get_data (frame, party, property_id, option)
	local args_t = get_args (frame);
	local reference = args_t.reference and args_t.reference:lower();
	local template_name = frame:getParent():getTitle();

	local data = "";
	local verbose = args_t.verbose and args_t.verbose:lower();					-- verbose parameter will provide an error message if no data, nil otherwise
	verbose = 'yes' == verbose;													-- make a boolean
	
	if reference == 'yes' and option ~= "raw-noref" then						-- if reference is true, then the call will return a reference
		reference = 'references';
	else
		reference = '';
	end
	
	local party_qid = "";														-- init party_qid
	
	if not party then															-- party is required
		return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
	elseif cfg.parties_t[party] then											-- if party is a European party
		party_qid = cfg.parties_t[party];
	elseif cfg.alliances_t[party] then											-- if party is a European alliance
		party_qid = cfg.alliances_t[party];
	elseif party:match ('^Q%d+$') then											-- if party is a qID
		party_qid = party;
	elseif property_id == 'P465' and (party == "ALL" or party == "IND" or party == "NONE") then -- default colour for special parameters
		return '#BBB';
	elseif party ~= "THISPARTY" then											-- error message if no party is provided
		return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
	end
	
	if property_id == "label" then												-- if the label of the Wikidata element is requested
		if not party then
			data = frame:expandTemplate ({title='wikidata', args = {'label'}});
		else
			data = frame:expandTemplate ({title='wikidata', args = {'label', party_qid}});
		end
	elseif property_id == "individual members date" then						-- special case
		if not party then
			data = frame:expandTemplate ({title='wikidata', args = {'qualifier', 'preferred', 'P2124', 'P585'}});
		else
			data = frame:expandTemplate ({title='wikidata', args = {'qualifier', 'preferred', party_qid, 'P2124', 'P585'}});
		end
	else																		-- for all other cases
		if not party then														-- direct call when no party is specified
			if option == "raw" or option == "raw-noref" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'raw', property_id}});
			elseif option == "linked" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'linked', property_id}});
			else
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, property_id}});
			end
		else																	-- otherwise we add the qID
			if option == "raw" or option == "raw-noref" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'raw', party_qid, property_id}});
			elseif option == "linked" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'linked', party_qid, property_id}});
			else
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, party_qid, property_id}});
			end
		end
	end
	
	if property_id == cfg.data_prop_t.colour then								-- if no colour, then default colour
		if '' == data then
			data = '#BBB';
		else
			data = '&#35;' .. data;
		end
	elseif property_id == cfg.data_prop_t.website then							-- if no website, then empty string
		if '' == data then
			data = "";
		else
			data = strip_URL (data);
		end
	end

	if '' == data and verbose then												-- if verbose, then error message
		return make_error_msg (substitute (cfg.error_messages_t.no_data, {party_qid, property_id}));
	end

	return data;
end


--[[--------------------------< H O U S E _ Q I D _ F R O M _ M E M B E R _ S T A T E >----------------------------------------------------------

return the qID of a house based on its name (lower house or upper house) and its member state; <frame> required to expand {{wikidata}} template

]]

local function house_qid_from_member_state_qid (house_type, member_state_qid)
	local house_qid = "";
	for row, _ in ipairs (cfg.ms_data_t) do										-- loop on table with lower/upper houses per member state
		if member_state_qid == cfg.ms_data_t[row].member_state_qid then
			if house_type == "LOWER_HOUSE" then
				house_qid = cfg.ms_data_t[row].lower_house_qid;					-- get the lower house qid
			elseif house_type == "UPPER_HOUSE" then
				house_qid = cfg.ms_data_t[row].upper_house_qid;					-- get the upper house qid
			end
		end
	end
	return house_qid;
end


--[[--------------------------< I N S T I T U T I O N _ S I Z E >----------------------------------------------------------

return the size of an institution; <frame> required to expand {{wikidata}} template

]]

local function institution_size (frame, institution)
	local institution_size = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});	-- get the institution size
	if '' == institution_size then												-- if no institution size
		return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution}));
	end
	return institution_size;
end


--[[--------------------------< M E M B E R _ S T A T E _ D E L E G A T I O N _ S I Z E >----------------------------------------------------------

return the size of a member state's delegation in the European Parliament; <frame> required to expand {{wikidata}} template

]]

local function member_state_delegation_size (frame, member_state_qid)
	local delegation_size = frame:expandTemplate ({title='wikidata', args = {'property', member_state_qid, 'P1410', P194 = 'Q8889'}});		-- get the delegation size
	if '' == delegation_size then												-- if no delegation size
		return make_error_msg (substitute (cfg.error_messages_t.not_member_state, {member_state_qid}));
	end
	return delegation_size;
end


--[[--------------------------< S I N G L E _ H O U S E _ S E A T S >------------------------------------------------

returns the number of seats in a given lower or upper house (identified by a row in the master table) from
wikidata.  When <house_type> not recognized or when <ms_data_t> does not have 'that' house, returns 0

]]

local function single_house_seats (frame, row, house_type)
	local house_qid;

	if house_type == "LOWER_HOUSE" then
		house_qid = cfg.ms_data_t[row].lower_house_qid;							-- get the lower house qid
	elseif house_type == "UPPER_HOUSE" then
		house_qid = cfg.ms_data_t[row].upper_house_qid;							-- get the upper house qid
	end

	return house_qid and frame:expandTemplate ({title='wikidata', args = {'property', house_qid, 'P1342'}}) or 0;	-- house_qid is nil when no upper or lower house 
end


--[[--------------------------< T O T A L _ H O U S E _ S E A T S >------------------------------------------------

returns the total number of seats of all lower or upper houses in all member states.

]]

local function total_house_seats (frame, house_type)
	local sum_seats = 0;														-- init sum of seats of European party's member parties in house_type

	for row, _ in ipairs (cfg.ms_data_t) do										-- for all member states
		sum_seats = sum_seats + single_house_seats (frame, row, house_type);		-- increase sum_seats
	end

	return sum_seats;
end


--[[--------------------------< A L L P P _ S E A T S _  R E F >---------------------------------------------------------------

return the reference for a seat claim; <frame> required to expand {{wikidata}} template

]]

local function allpp_seats_ref (frame, party, institution)
	local args_t = get_args (frame);
	local party_type = args_t[1] and args_t[1]:lower();							-- force to lower case
	
	if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
		if party_type == 'european_entity' then
			return '';
		elseif party_type == 'national_party' then
			if party == "THISPARTY" then
				local member_state_qid = allpp_get_data (frame, mw.wikibase.getEntityIdForCurrentPage(), cfg.data_prop_t.country, 'raw-noref');
				local house_qid = house_qid_from_member_state_qid (institution, member_state_qid)
				return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = house_qid}});
			elseif party:match ('^Q%d+$') then
				local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
				local house_qid = house_qid_from_member_state_qid (institution, member_state_qid)
				return frame:expandTemplate ({title='wikidata', args = {'references', party, 'P1410', P194 = house_qid}});
			end
		end
	elseif institution == 'EC' or institution == 'EUCO' then
		if party == "THISPARTY" then
			return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P208 = cfg.institutions_t[institution]}});
		elseif cfg.parties_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.parties_t[party], 'P1410', P208 = cfg.institutions_t[institution]}});
		elseif cfg.alliances_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.alliances_t[party], 'P1410', P208 = cfg.institutions_t[institution]}});
		elseif party:match ('^Q%d+$') then
			return frame:expandTemplate ({title='wikidata', args = {'references', party, 'P1410', P208 = cfg.institutions_t[institution]}});
		end
	else
		if party == "THISPARTY" then
			return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = cfg.institutions_t[institution]}});
		elseif cfg.parties_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.parties_t[party], 'P1410', P194 = cfg.institutions_t[institution]}});
		elseif cfg.alliances_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.alliances_t[party], 'P1410', P194 = cfg.institutions_t[institution]}});
		elseif party:match ('^Q%d+$') then
			return frame:expandTemplate ({title='wikidata', args = {'references', party, 'P1410', P194 = cfg.institutions_t[institution]}});
		end
	end
end

local function allpp_get_seats_ref_qid (frame, institution_qid)
	return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = institution_qid}});
end



--[[==========================< S E C T I O N _ 4 : S U M _ F U N C T I O N S >=======================

These functions are the ones providing seat numbers for European or national parties, in European institutions or national lower/upper houses
* functions starting with eupp apply to European parties;
* functions starting with npp apply to national political parties; and
* functions starting with allpp apply to all political parties.

]]

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

return the share of a party's seats relative to the total size of a given institution listed in <cfg.parties_t> or <cfg.alliances_t> (so not including lower and upper houses)

<frame> required to expand {{wikidata}} template 

Note: P1342 is the property "number of seats", used to record an institution's number of seats

]]

local function allpp_make_share_in_eu_institutions (frame, party_seats, institution)
	local args_t = get_args (frame);
	local constituency = args_t['constituency'];								-- argument overriding the house's number of seats
	local party_type = args_t[1] and args_t[1]:lower();							-- force to lower case
	local party = args_t[3] and args_t[3]:upper();								-- force to lower case
	
	if constituency then
		return tonumber (party_seats) and round (100 * party_seats / constituency) or party_seats;
	elseif party_type == "national_party" and institution == "EP" then
		local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
		return tonumber (party_seats) and round (100 * party_seats / member_state_delegation_size (frame, member_state_qid)) or party_seats;
	else
		return tonumber (party_seats) and round (100 * party_seats / frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}})) or party_seats;
	end
end


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

return the number of seats occupied by a political party in an <institution> listed in <cfg.parties_t> or in <cfg.alliances_t> (so not including lower and upper houses). <body_prop> is the wikidata property:
	P194: legislative body
	P208: executive body

<frame> required to expand {{wikidata}} template 

Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies

]]

local function allpp_seats_in_eu_institutions (frame, party, institution, body_prop)
	local args_t = {};	
	if party == "THISPARTY" then												-- flag used when module is called from the page of a European party; less expensive
		args_t = {'property', 'P1410'};											-- init some of the {{wikidata}} parameters with THISPARTY (only when called from the page of a European party)
	elseif cfg.alliances_t[party] then
		args_t = {'property', cfg.alliances_t[party], 'P1410'};					-- init some of the {{wikidata}} parameters
	elseif cfg.parties_t[party] then
		args_t = {'property', cfg.parties_t[party], 'P1410'};					-- init some of the {{wikidata}} parameters
	elseif party:match ('^Q%d+$') then
		args_t = {'property', party, 'P1410'};					-- init some of the {{wikidata}} parameters
	end
	args_t[body_prop] = cfg.institutions_t[institution];

	local retval = frame:expandTemplate ({title='wikidata', args = args_t})
	if '' == retval then														-- {{wikidata}} returns empty string when <party> not known to <institution>
		if party == "THISPARTY" then											-- specific error message if the module was called with THISPARTY from the wrong page
			return make_error_msg (cfg.error_messages_t.thisparty);
		elseif not party then
			return	make_error_msg (substitute (cfg.error_messages_t.party_req_share));
		else
			return  make_error_msg (substitute (cfg.error_messages_t.inst_unknown_party, {institution, party}));
		end
	end
	return retval;
end


--[[--------------------------< E U P P _ S U M _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >------------------------------------------------------------------------

return the sum of seats for all European parties combined in an <institution> listed in <cfg.parties_t> (so not including lower and upper houses).  <body_prop> is the wikidata
property:
	P194: legislative body
	P208: executive body

<frame> required to expand {{wikidata}} template 

Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies

]]

local function eupp_sum_seats_in_eu_institutions (frame, institution, body_prop)
	local sum = 0;																-- init

	local args_t = {[1]='property', [3]='P1410'};								-- init some of the {{wikidata}} parameters
	args_t[body_prop] = cfg.institutions_t[institution];

	for _, qid in pairs (cfg.parties_t) do										-- loop through all parties in <cfg.parties_t>
		args_t[2] = qid;														-- set the last {{wikidata}} parameter
		sum = sum + frame:expandTemplate ({title='wikidata', args = args_t});	-- expand and tally
	end

	return sum;
end


--[[--------------------------< E U P P _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------------------

return a number of seats of a European party (or special parameter) in an <institution> (so not including lower and upper houses).

<frame> required to expand {{wikidata}} template 

Note: 
* P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
* P1342 is the property "number of seats", used to record an institution's number of seats
* P208 is the property "executive body"
* P194 is the property "legislative body"

]]

local function eupp_seats_in_eu_institutions (frame, party, institution)
	if party == "IND" and institution == "EUCO" then						-- special case of independent politicians on European Council
		return frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}});

	elseif party == "NONE" then													-- returns seats not occupied by European parties
		local retval = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});	-- get number of seats in the institution

		if institution == "EUCO" then											-- if EUCO, use P208 and separate case to account for independent politicians
			local ind = frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}});
			return retval - (eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]) + ind);

		else																	-- COR, EC, EP
			return retval - eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]);
		end

	elseif party == "ALL" then													-- returns seats occupied by all European parties combined
		return eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]);

	elseif party:match ('^Q%d+$') then
		local party_name = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];
		return allpp_seats_in_eu_institutions (frame, party_name, institution, cfg.body_prop_t[institution]);
	else																		-- returns the number of seats occupied by one party in one institution
		return allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
	end
end


--[[--------------------------< E U P P _ S E A T _ S H A R E _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------

return a share of seats of a European party (or special parameter) in an <institution> (so not including lower and upper houses).

<frame> required to expand {{wikidata}} template 

Note: 
* P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
* P1342 is the property "number of seats", used to record an institution's number of seats
* P208 is the property "executive body"
* P194 is the property "legislative body"

]]

local function eupp_seat_share_in_eu_institutions (frame, party, institution)
	if party == "IND" and institution == "EUCO" then							-- special case of independent politicians on European Council
		return allpp_make_share_in_eu_institutions (frame, frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}}), institution);

	elseif party == "NONE" then													-- returns seats not occupied by European parties
		local retval = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});

		if institution == "EUCO" then											-- if EUCO, use P208 and separate case to account for independent politicians
			local ind = frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}})
			return allpp_make_share_in_eu_institutions (frame, retval - (eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]) + ind), institution);

		else																	-- for COR, EC, EP
			return allpp_make_share_in_eu_institutions (frame, retval - eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]), institution);
		end

	elseif party == "ALL" then													-- returns seats occupied by all European parties combined
		return allpp_make_share_in_eu_institutions (frame, eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]), institution);

	elseif party:match ('^Q%d+$') then
		party = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];
		return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);
	else																		-- returns the number of seats occupied by one party in one institution
		return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);
	end
end


--[[--------------------------< N P P _ S E A T S _ P E R _ R O W >------------------------------

returns the number of seats occupied by a given party (identified by a given row in the master table) in the
lower or upper house of its member state from wikidata.  When <house_type> not recognized or when <tab_data_t>
does not have 'that' house, returns 0

]]

local function npp_seats_per_row (frame, row, house_type)
	local house_qid = "";
	local national_party_qid = cfg.tab_data_t[row].national_party_qid;

	if house_type == "LOWER_HOUSE" then
		house_qid = cfg.tab_data_t[row].lower_house_qid;						-- get the qID of a lower house
	elseif house_type == "UPPER_HOUSE" then
		house_qid = cfg.tab_data_t[row].upper_house_qid;						-- get the qID of an upper house
	end
	
	return house_qid and frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = house_qid}}) or 0;
end


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

returns the sum of seats occupied by all national parties members of a given European party in the lower or upper house of its member state.

]]

local function eupp_seats_in_national_institutions (frame, party, house_type)
	local sum_seats = 0;														-- init sum of seats of European party's member parties in house_type

	for row, _ in ipairs (cfg.tab_data_t) do
		if party == "THISPARTY" then											-- if called from the page of a European party
			local thisparty_qid = mw.wikibase.getEntityIdForCurrentPage();		-- get party qiD

			if thisparty_qid == cfg.tab_data_t[row]['european_party_qid'] then
				sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type);	-- increase sum_seats
			end
		elseif party == "ALL" or party == "NONE" then							-- not accepted parameters
			return make_error_msg (substitute (cfg.error_messages_t.all_none_unavailable, {party}));
		elseif party == "IND" then												-- not accepted parameter
			return make_error_msg (substitute (cfg.error_messages_t.ind_only_euco));
		elseif party:match ('^Q%d+$') then										-- if party name is a qID
			if party == cfg.tab_data_t[row]['european_party_qid'] then
				sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type);	-- increase sum_seats
			end
		else																	--for any other party name (already approved via party_type validation)
			if party == cfg.tab_data_t[row]['european_party'] then
				sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type);	-- increase sum_seats
			end
		end
	end

	return sum_seats;
end


--[[--------------------------< E U P P _ S E A T _ S H A R E _ I N _ N A T I O N A L _ I N S T I T U T I O N S >--------------------------------------------------------

return a share of seats occupied by one or more entities listed in <cfg.parties_t> or <cfg.alliances_t>, or by none of them, in an <institution> (so not including lower and upper houses).

<frame> required to expand {{wikidata}} template 

]]

local function eupp_seat_share_in_national_institutions (frame, party, institution)
	return round (100 * eupp_seats_in_national_institutions (frame, party, institution) / total_house_seats (frame, institution));	-- return share of seats by calling seat_share()
end


--[[--------------------------< N P P _ S E A T S _ A N D _ S E A T _ S H A R E _ I N _ N A T I O N A L _ I N S T I T U T I O N S >------------------------------------------------

returns the sum or share of seats occupied by a national party in the lower or upper house of its member state.

]]

local function npp_seats_and_seat_share_in_national_institutions (frame, party, house_type, data)
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	local party_qid = "";
	local constituency = args_t['constituency'];								-- argument overriding the house's number of seats
	
	if party == "THISPARTY" then
		party_qid = mw.wikibase.getEntityIdForCurrentPage();
	elseif party:match ('^Q%d+$') then
		party_qid = party;
	end
	
--[=[ data validation for party_qid ]=]	

	if party_qid == '' then
		return make_error_msg (cfg.error_messages_t.no_qid, template_name);		-- yep, abandon with error message
	end

--[=[ get house_qid from party qid and house_seats ]=]	
	
	local member_state_qid = allpp_get_data (frame, party_qid, cfg.data_prop_t.country, 'raw-noref');
	local house_qid = house_qid_from_member_state_qid (house_type, member_state_qid)
	
	local npp_seats = house_qid and frame:expandTemplate ({title='wikidata', args = {'property', party_qid, 'P1410', P194 = house_qid}}) or 0;
	local house_seats = house_qid and frame:expandTemplate ({title='wikidata', args = {'property', house_qid, 'P1342'}}) or 0;
	
	if data == "seats" then
		return npp_seats;
	elseif data == "seat share" then
		if constituency then
			return round (100 * npp_seats / constituency);
		else
			return round (100 * npp_seats / house_seats);
		end
	elseif data == "house seats" then
		return house_seats;
	end
end


--[[--------------------------< A L L P P _ C O M P O S I T I O N _ B A R >------------------------------------------------

this function does whatever it is that {{composition bar}} does

implements {{EUPP composition bar}}

	{{EUPP composition bar|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}
	
]]

local function allpp_composition_bar (frame, party, institution, party_type)
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil

	local width = args_t.width;													-- must be a number, or number with unit suffix: 'px', '%', 'em'; whitespace not allowed
	local percentage = args_t.percent and args_t.percent:lower();											-- 
	percentage = 'yes' == percentage;											-- make a boolean
	local reference = args_t.reference and args_t.reference:lower();			
	reference = 'yes' == reference;												-- make a boolean
	local constituency = args_t['constituency'];								-- argument overriding the house's number of seats
	
	local institution_seats = 0;
	local party_seats = 0;
	
	local background_color = args_t['background-color'];
	local border = args_t.border;
	
	if width and not validate_width (width) then
		return make_error_msg (substitute (cfg.error_messages_t.parameter_invalid, {width}), template_name);	-- yep, abandon with error message
	end

--[=[ prepare arguments for composition bar ]=]	

	if party_type == "european_entity" then
		if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
			party_seats = eupp_seats_in_national_institutions (frame, party, institution);	-- get sum of seats occupied by members of a European party
			institution_seats = total_house_seats(frame, institution);			-- get total seats of lower or upper houses
		else
			party_seats = eupp_seats_in_eu_institutions (frame, party, institution);	-- get total seats in <institution> occupied by <party>
			institution_seats = institution_size (frame, institution);			-- get total seats in <institution>
		end
	elseif party_type == "national_party" then
		if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
			party_seats = npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seats");
			institution_seats = constituency or npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "house seats")
		elseif institution == "EP" then
			local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
			party_seats = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
			institution_seats = constituency or member_state_delegation_size (frame, member_state_qid);	-- get total seats in <institution>
		else
			party_seats = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
			institution_seats = constituency or institution_size (frame, institution);	-- get total seats in <institution>
		end
	end
		
	local color = args_t['bar-color'] or allpp_get_data (frame, party, cfg.data_prop_t.colour);	-- get color associated with <party>; |bar-color= overrides wikidata

	local comp_bar_args_t = {
		party_seats,
		institution_seats, 
		color,
		width=width,
		per=percentage,
		['background-color'] = background_color,
		border = border,
	}
	
	if party_type == "european_entity" and (institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE") then
		return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t});
	else
		return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t}) .. ((reference and allpp_seats_ref (frame, party, institution)) or '');
	end
end


--[[==========================< S E C T I O N _ 5 : M A I N _ & _ T E S T _ F U N C T I O N S >=======================]]

--[[--------------------------< M A I N >----------------------------------------------------------------------

implements {{EUPP data}} and {{political party data}} (the templates hard-code the <party_type> information)

carries out input error detection, reporting, and function dispatching

Module called by as follows:

{{EUPP data|<data_type>|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}

{{Political party data|<data_type>|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}

where <data_type> is:
* seats
* seat share
* seat composition bar
* colour
* individual members
* acronym
* country
* name
* public funding
* website
* foundation date

]]

local function main(frame)
	local template_name = frame:getParent():getTitle()
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	local party_type = args_t[1] and args_t[1]:lower();							-- force to lower case
	local data_type = args_t[2] and args_t[2]:lower();							-- force to lower case
	local party = args_t[3] and args_t[3]:upper();								-- force to upper case
	local institution = args_t[4] and args_t[4]:upper();						-- force to upper case
	local party_qid = "";
	local reference = args_t.reference and args_t.reference:lower();			
	reference = 'yes' == reference;												-- make a boolean
	local ref = "";
	
	institution = harmonise_lower_upper_house_name (institution);				-- "ms-lower-house" and "lower" are turned to "lower_house" (same for upper house)
	party = harmonise_lower_upper_house_name (party);							-- in case institution is entered as party
	
	if cfg.institutions_t[party] or party == "LOWER_HOUSE" or party == "UPPER_HOUSE" then -- if the name of the party is actually the institution, then party is "thisparty"
		institution = party;
		party = "THISPARTY";
	end	
	
	if not party then															-- if party is missing, then it is "thisparty"
		party = "THISPARTY";
	end

--[=[ data validation party type ]=]	
	
	if party_type == "european_entity" and not (cfg.parties_t[party] or cfg.alliances_t[party] or cfg.rev_parties_t[party] or cfg.rev_alliances_t[party] or party == "ALL" or party == "NONE" or party == "IND" or party == "THISPARTY") then
		return make_error_msg (substitute (cfg.error_messages_t.not_valid_eupp_parameter, {party}), template_name);
	elseif party_type == "european_entity" and party == "THISPARTY" and not (cfg.rev_parties_t[mw.wikibase.getEntityIdForCurrentPage()] or cfg.rev_alliances_t[mw.wikibase.getEntityIdForCurrentPage()]) then
		return make_error_msg (substitute (cfg.error_messages_t.thisparty), template_name);
	elseif party_type == "national_party" and (cfg.parties_t[party] or cfg.alliances_t[party] or cfg.rev_parties_t[party] or cfg.rev_alliances_t[party] or party == "ALL" or party == "NONE" or party == "IND" or (party == "THISPARTY" and not mw.wikibase.getEntityIdForCurrentPage())) then
		return make_error_msg (substitute (cfg.error_messages_t.not_valid_npp, {party}), template_name);
	end
	
--[=[ data validation institution ]=]	

	local is_valid = false;
	
	is_valid = validate_institution (institution, template_name);
	
	if true ~= is_valid then													-- boolean true when valid; error message else
		return is_valid;														-- yep, abandon with error message
	end

--[=[ function dispatching ]=]

	--[=[ send to seat functions ]=]
	
	if data_type == "seats" then												-- we look for a seat number
		if not institution then													-- institution is required
			return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
		end
		
		if reference then
			ref = allpp_seats_ref (frame, party, institution);
		end
		
		if party_type == "european_entity" then									-- the party is a European party or European alliance (specified by the calling template, not by the user)
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then	-- we look for seats aross lower or upper houses
				return eupp_seats_in_national_institutions (frame, party, institution) .. ref;	-- return the number of seats by calling eupp_seats_in_national_institutions
			else																-- we look for seats in a European institution
				return eupp_seats_in_eu_institutions (frame, party, institution) .. ref;	-- return the number of seats by calling eupp_seats_in_eu_institutions
			end
		elseif party_type == "national_party" then								-- the party is a national party
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then	-- we look for seats in a lower or upper house
				return npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seats") .. ref;	-- return the number of seats by calling ...
			else																-- we look for seats in a European institution
				return allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]) .. ref;	-- return the number of seats by calling allpp_seats_in_eu_institutions
			end
		else
			return make_error_msg (substitute (cfg.error_messages_t.unknown_party_type, {party_type}), template_name);
		end
		
	--[=[ send to seat share functions ]=]
	
	elseif data_type == "seat share" then
		if not institution then													-- institution is required
			return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
		end
		
		if party_type == "european_entity" then
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
				return eupp_seat_share_in_national_institutions (frame, party, institution);
			else 
				return eupp_seat_share_in_eu_institutions (frame, party, institution);
			end
		
		elseif party_type == "national_party" then
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
				return npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seat share");
			else 
				return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);	-- return share of seats by calling seat_share()
			end			
		
		else
			return make_error_msg (substitute (cfg.error_messages_t.unknown_party_type, {party_type}), template_name);
		end
		
	--[=[ send to composition bar functions ]=]
	
	elseif data_type == "seat composition bar" then
		if not institution then													-- institution is required
			return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
		end
		
		return allpp_composition_bar (frame, party, institution, party_type);
		
	--[=[ send to get_data functions ]=]
		
	elseif data_type == "acronym" then
		return allpp_get_data (frame, party, cfg.data_prop_t.acronym);
	elseif data_type == "color" then
		return allpp_get_data (frame, party, cfg.data_prop_t.colour);
	elseif data_type == "country" then
		return allpp_get_data (frame, party, cfg.data_prop_t.country, 'linked');
	elseif data_type == "foundation date" then
		return allpp_get_data (frame, party, cfg.data_prop_t.foundation_date);
	elseif data_type == "individual members" then
		return allpp_get_data (frame, party, cfg.data_prop_t.individual_members);
	elseif data_type == "individual members date" then
		return allpp_get_data (frame, party, 'individual members date');
	elseif data_type == "label" then
		return allpp_get_data (frame, party, 'label');	
	elseif data_type == "official name" then
		return allpp_get_data (frame, party, cfg.data_prop_t.official_name);
	elseif data_type == "parliamentary group" then
		return allpp_get_data (frame, party, cfg.data_prop_t.parliamentary_group, 'linked');
	elseif data_type == "public funding" then
		return allpp_get_data (frame, party, cfg.data_prop_t.public_funding);
	elseif data_type == "website" then
		return allpp_get_data (frame, party, cfg.data_prop_t.website);


	else
		return make_error_msg (substitute (cfg.error_messages_t.unknown_data_type, {data_type}), template_name);
	end
end


--[[--------------------------< E U _ I N S T I T U T I O N _ S E A T S >----------------------------------------------------------------------
]]

local function eu_institution_seats (frame)

	local template_name = frame:getParent():getTitle()
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	local institution = args_t[1] and args_t[1]:upper();						-- force to upper case
	
	institution = harmonise_lower_upper_house_name (institution);				-- "ms-lower-house" and "lower" are turned to "lower_house" (same for upper house)
	
--[=[ data validation institution ]=]	

	local is_valid = false;
	
	is_valid = validate_institution (institution, template_name);
	
	if true ~= is_valid then													-- boolean true when valid; error message else
		return is_valid;														-- yep, abandon with error message
	end
	
--[=[ return value ]=]

	if institution == 'LOWER_HOUSE' or institution == 'UPPER_HOUSE' then
		return total_house_seats (frame, institution);
	else
		return institution_size (frame, institution);
	end
	
end


--[[--------------------------< T E S T _ W I K I D A T A _ E N T R I E S >----------------------------------------------------------------------
]]

local function test_wikidata_entries (frame)														-- to test calls and functions, for verification purposes
	local wikidata_error = "Wikidata entries error(s):";
	
	for row, _ in ipairs (cfg.tab_data_t) do
		local national_party_qid = cfg.tab_data_t[row].national_party_qid;
		local national_party_name = "";
		
		if not cfg.tab_data_t[row].national_party then
			national_party_name = cfg.tab_data_t[row].national_party_english;
		else
			national_party_name = cfg.tab_data_t[row].national_party;
		end
		
		local lower_house_qid = cfg.tab_data_t[row].lower_house_qid;
		local lower_house_name = cfg.tab_data_t[row].lower_house;
		local upper_house_qid = cfg.tab_data_t[row].upper_house_qid;
		local upper_house_name = cfg.tab_data_t[row].upper_house;
		local retval_lower = frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = lower_house_qid}})
		local retval_upper = frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = upper_house_qid}})
		
		if '' == retval_lower then
			wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. lower_house_name .. ")";
		end
		
		if '' == retval_upper then
			wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. upper_house_name .. ")";
		end
	end
	
	if wikidata_error == "Wikidata entries error(s):" then
		wikidata_error = "Wikidata entries: all good!";
	end
	
	return wikidata_error;
end


--[[--------------------------< T E S T >----------------------------------------------------------------------
]]

local function test (frame)													-- to test calls and functions, for verification purposes
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	--local house_type = args_t[1] and args_t[1]:upper();
	
	--house_type = harmonise_lower_upper_house_name (house_type);
	--local member_state_qid = args_t[1];
	--local party_qid = args_t[1] and args_t[1]:upper();						-- force to upper case
	--local party = args_t[2] and args_t[2]:upper();
	-- local share = args_t[3] and args_t[3]:upper();
	
	local member_state_qid_check = "";
	
	for row, _ in ipairs (cfg.ms_data_t) do										-- loop on table with lower/upper houses per member state
		local member_state_check = frame:expandTemplate ({title='wikidata', args = {'label', 'linked', cfg.ms_data_t[row].member_state_qid}});
		member_state_qid_check = member_state_qid_check .. row .. ": " .. cfg.ms_data_t[row].member_state .. ", " .. member_state_check .. " -- ";					-- get the lower house qid
	end
	
	return member_state_qid_check;
	
	--local member_state_qid = allpp_get_data (frame, mw.wikibase.getEntityIdForCurrentPage(), cfg.data_prop_t.country, 'raw-noref');
	--local house_qid = house_qid_from_member_state_qid (house_type, member_state_qid);
	--return allpp_get_data (frame, party_qid, cfg.data_prop_t.country, "raw") .. ": " .. allpp_get_data (frame, party_qid, cfg.data_prop_t.country, "linked");
	--return allpp_get_data (frame, party_qid, cfg.data_prop_t.colour);
	--return member_state_delegation_size (frame, member_state_qid)
	--return cfg.institutions_t.COR .. " " .. cfg.parties_t.ALDE .. " " .. cfg.alliances_t.VOLT .. " " .. cfg.body_prop_t.COR .. " " .. cfg.data_prop_t.COLOUR;

	--institution = strip_house_type (institution);								-- here, testing strip_house_type
	--return house_type .. " - " .. member_state_qid .. " - " .. cfg.ms_data_t[1].member_state .. " - " .. cfg.ms_data_t[1].member_state_qid .. " - " .. house_qid;
	--return institution;
end


--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]

return {
	main = main,
	eu_institution_seats = eu_institution_seats,
	test = test,
	test_wikidata_entries = test_wikidata_entries,
	}