Jump to content

Module:European and national party data/sandbox

From Wikipedia, the free encyclopedia
  1. ^ "PES in the EU institutions". Retrieved 7 February 2025.
  2. ^ "Sitzplan & Mandatsverteilung". Retrieved 9 April 2025.
  3. ^ "European People's Party". Authority for European Political Parties and European Political Foundations. Retrieved 4 November 2024.
  4. ^ "Parties and partners". Retrieved 7 February 2025.
  5. ^ "List of members as per Article 32(2) of Regulation 1141/2014 (English)". Retrieved 26 January 2025.
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://', '^www.', '/$'};	-- 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
	if 'fr' == cfg.this_project_language then
		return new_URL;
	else
		return "[" .. URL .. " " .. new_URL .. "]";
	end
end


--[[--------------------------< T R A N S L A T E >--------------------------------------------------------------------

translate a term based on the project language

]]

local function xlate (term)
	if term then
		--local new_term = string.gsub(term, " ", "_");
		if 'en' == cfg.this_project_language then
			return term;
		elseif not cfg.xlate_t[cfg.this_project_language] then
			return term;
		elseif cfg.xlate_t[cfg.this_project_language][term] then
			return cfg.xlate_t[cfg.this_project_language][term];
		else 
			return term;
		end
	end
end


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

translate a parameter based on the project language

]]

local function xlate_param (parameter)
	if 'en' == cfg.this_project_language then
		return parameter;
	elseif not cfg.xlate_param_t[cfg.this_project_language] then
		return parameter;
	elseif cfg.xlate_param_t[cfg.this_project_language][parameter] then
		return cfg.xlate_param_t[cfg.this_project_language][parameter];
	else 
		return parameter;
	end
end


--[[--------------------------< L O C A L _ P A R A M E T E R _ T O _ V A L U E _ O R _ B O O L E A N  >--------------------------------------------------------------------

turns a given parameter into its local form and into a boolean

]]

local function local_parameter_to_value_or_boolean (frame, parameter, outcome)	-- 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 localised_parameter = xlate_param (parameter);						-- translate given parameter from English into local language
	local argument = (args_t[tostring(localised_parameter)] and args_t[tostring(localised_parameter)]:lower()) or (args_t[parameter] and args_t[parameter]:lower());	-- get argument (in local language) matching parameter in local language
	
	if outcome == 'boolean' then
		if nil == argument then													-- if no argument, return no
			argument = false;
		else
			argument = xlate (argument);										-- translate argument into English
			argument = 'yes' == argument;										-- turn argument into boolean
		end
	elseif nil ~= argument and argument:match ('^#') then
		argument = argument.gsub(argument, "#", "&#35;");
	end
	
	return argument;
end


--[[--------------------------< X L A T E _ W I K I D A T A >--------------------------------------------------------------------

call the {{wd}} or {{wikidata}} template based on language

arguments are as follows:
* data_requested: the type of data sought -- 'qualifier', 'property', 'references', 'label' -- compulsory
* qid: the Wikidata item on which data is sought -- e.g. Q208242 for the European People's Party -- not compulsory
* property_id: the property for which data is sought -- e.g. P1410 for number of seats in assembly -- compulsory
* qualifier_id: qualifier for property -- e.g. P194 for legislative body -- not compulsory
* value_of_qualifier: value of the qualifier -- e.g. P8889 for the European Parliament -- only compulsory if qualifier_id is provided
* reference: whether a reference should be displayed -- e.g. reference=yes to display the reference, anything else (preferably reference=no) otherwise; adding an "s" will display several references
* preferred: whether the preferred value should be displayed -- e.g. preferred=yes to display the preferred value, anything else (preferably preferred=no) otherwise
* raw: whether the qID should be displayed -- e.g. raw=yes to display the qID, anything else (preferably raw=no) otherwise
* linked: whether the value should be linked -- e.g. linked=yes to display the link, anything else (preferably linked=no) otherwise

]]

local function xlate_wikidata (data_requested, qid, property_id, qualifier_id, value_of_qualifier, reference, preferred, raw, linked)
	local local_reference = reference;
	local local_preferred = preferred;
	local local_raw = raw;
	local local_linked = linked;
	local Wd = require('Module:European_and_national_party_data/Wd')

	if local_reference == 'reference=yes' then local_reference = 'reference' elseif local_reference == 'references=yes' then local_reference = 'references' else local_reference = '' end;
	if local_preferred == 'preferred=yes' then local_preferred = 'preferred' else local_preferred = '' end;
	if local_raw == 'raw=yes' then local_raw = 'raw' else local_raw = '' end;
	if local_linked == 'linked=yes' then local_linked = 'linked' else local_linked = '' end;
	
	local wdargs = {local_reference, local_preferred, local_raw, local_linked, property_id}
	
	if qid then
		table.insert(wdargs, 5, qid)
	end
	if qualifier_id and '' ~= value_of_qualifier then
		wdargs[qualifier_id] = value_of_qualifier;
	end
	
	return Wd['_' .. data_requested](wdargs);
end


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

call the {{composition bar}} template based on language

arguments are as follows:
* seats: the number of seats to be displayed;
* total_seats: the total number of seats of the institution in question; 
* color: the color of the bar;
* width: the width of the bar;
* percentage: whether or not to display the percentage value;
* background_color: the background color of the bar;
* border: the color of the border;

]]

local function xlate_composition_bar (frame, seats, total_seats, color, width, percentage, background_color, border)
	if 'en' == cfg.this_project_language or 'pt' == cfg.this_project_language then
		local comp_bar_args_t = {
			seats,
			total_seats, 
			color,
			width=width,
			per=percentage,
			['background-color'] = background_color,
			border = border,
		};
		return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t});
	elseif 'fr' == cfg.this_project_language then
		return frame:expandTemplate ({title='Infobox Parti politique/Sièges', args = {seats, total_seats, ['hex'] = color}});
	end
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 template_name = frame:getParent():getTitle();
	local args_t = get_args (frame);

	local data = "";
	
	local reference = local_parameter_to_value_or_boolean (frame, 'reference', 'boolean');	-- check verbose and make boolean
	local verbose = local_parameter_to_value_or_boolean (frame, 'verbose', 'boolean');	-- check verbose and make boolean
	
	if reference and option ~= "raw-noref" then									-- if reference is true, then the call will return a reference
		reference = 'references=yes';
	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 '&#35;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 = xlate_wikidata ('label', '', '', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		else
			data = xlate_wikidata ('label', party_qid, '', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		end
	elseif property_id == "individual members date" then						-- special case
		if not party then
			data = xlate_wikidata ('qualifier', '', P2124, '', P585, 'reference=no', 'preferred=yes', 'raw=no', 'linked=no');
		else
			data = xlate_wikidata ('qualifier', party_qid, 'P2124', '', 'P585', 'reference=no', 'preferred=yes', 'raw=no', 'linked=no');
		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 = xlate_wikidata ('property', '', property_id, '', '', reference, 'preferred=no', 'raw=yes', 'linked=no');
			elseif option == "linked" then
				data = xlate_wikidata ('property', '', property_id, '', '', reference, 'preferred=no', 'raw=no', 'linked=yes');
			else
				xlate_wikidata ('property', '', property_id, '', '', reference, 'preferred=no', 'raw=no', 'linked=no');
			end
		else																	-- otherwise we add the qID
			if option == "raw" or option == "raw-noref" then
				data = xlate_wikidata ('property', party_qid, property_id, '', '', reference, 'preferred=no', 'raw=yes', 'linked=no');
			elseif option == "linked" then
				data = xlate_wikidata ('property', party_qid, property_id, '', '', reference, 'preferred=no', 'raw=no', 'linked=yes');
			else
				data = xlate_wikidata ('property', party_qid, property_id, '', '', reference, 'preferred=no', 'raw=no', 'linked=no');
			end
		end
	end
	
	if property_id == cfg.data_prop_t.colour then								-- if no colour, then default colour
		if '' == data then
			data = '&#35;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 = xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no');	-- 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 = xlate_wikidata ('property', member_state_qid, 'P1410', 'P194', 'Q8889', 'reference=no', 'preferred=no', 'raw=no', 'linked=no');		-- 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 xlate_wikidata ('property', house_qid, 'P1342', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no') 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
	
	party_type = xlate (party_type);
	
	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 xlate_wikidata ('references', '', 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
			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 xlate_wikidata ('references', party, 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
			end
		end
	elseif institution == 'EC' or institution == 'EUCO' then
		if party == "THISPARTY" then
			return xlate_wikidata ('references', '', 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		elseif cfg.parties_t[party] then
			return xlate_wikidata ('references', cfg.parties_t[party], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		elseif cfg.alliances_t[party] then
			return xlate_wikidata ('references', cfg.alliances_t[party], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		elseif party:match ('^Q%d+$') then
			return xlate_wikidata ('references', party, 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		end
	else
		if party == "THISPARTY" then
			return xlate_wikidata ('references', '', 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		elseif cfg.parties_t[party] then
			return xlate_wikidata ('references', cfg.parties_t[party], 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		elseif cfg.alliances_t[party] then
			return xlate_wikidata ('references', cfg.alliances_t[party], 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		elseif party:match ('^Q%d+$') then
			return xlate_wikidata ('references', party, 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		end
	end
end

local function allpp_get_seats_ref_qid (frame, institution_qid)
	return xlate_wikidata ('references', '', 'P1410', 'P194', institution_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
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 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
	
	local constituency = local_parameter_to_value_or_boolean (frame, 'constituency');	-- argument overriding the house's number of seats
	
	party_type = xlate (party_type);
	party = xlate (party);
	
	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 / xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no')) 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_input_t = get_args (frame);
	local verbose = local_parameter_to_value_or_boolean (frame, 'verbose', 'boolean');	-- check verbose and make boolean
	
	local args_t = {};	
	local retval = "";
	if party == "THISPARTY" then												-- flag used when module is called from the page of a European party; less expensive
		retval = xlate_wikidata ('property', '', 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');				-- init some of the {{wikidata}} parameters with THISPARTY (only when called from the page of a European party)
	elseif cfg.alliances_t[party] then
		retval = xlate_wikidata ('property', cfg.alliances_t[party], 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');	-- init some of the {{wikidata}} parameters
	elseif cfg.parties_t[party] then
		retval = xlate_wikidata ('property', cfg.parties_t[party], 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');	-- init some of the {{wikidata}} parameters
	elseif party:match ('^Q%d+$') then
		retval = xlate_wikidata ('property', party, 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');			-- init some of the {{wikidata}} parameters
	end

	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 "";
		elseif not party then
			return	make_error_msg (substitute (cfg.error_messages_t.party_req_share)), true;
		else
			return  make_error_msg (substitute (cfg.error_messages_t.inst_unknown_party, {institution, party})), true;
		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

	for _, qid in pairs (cfg.parties_t) do										-- loop through all parties in <cfg.parties_t>
		local local_qid = qid;														-- set the last {{wikidata}} parameter
		sum = sum + xlate_wikidata ('property', local_qid, 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');	-- 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 xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');

	elseif party == "NONE" then													-- returns seats not occupied by European parties
		local retval = xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no');	-- 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 = xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
			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, xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'), institution);

	elseif party == "NONE" then													-- returns seats not occupied by European parties
		local retval = xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no');

		if institution == "EUCO" then											-- if EUCO, use P208 and separate case to account for independent politicians
			local ind = xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
			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 xlate_wikidata ('property', national_party_qid, 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no') 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 = local_parameter_to_value_or_boolean (frame, '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 xlate_wikidata ('property', party_qid, 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no') or 0;
	local house_seats = house_qid and xlate_wikidata ('property', house_qid, 'P1342', '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no') 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 verbose = local_parameter_to_value_or_boolean (frame, 'verbose', 'boolean');	-- check verbose and make boolean
	local percentage = local_parameter_to_value_or_boolean (frame, 'percent', 'boolean');	-- check percent and make boolean
	local reference = local_parameter_to_value_or_boolean (frame, 'reference', 'boolean');	-- check reference and make boolean
	local width = local_parameter_to_value_or_boolean (frame, 'width');			-- must be a number, or number with unit suffix: 'px', '%', 'em'; whitespace not allowed
	local constituency = local_parameter_to_value_or_boolean (frame, 'constituency');	-- argument overriding the house's number of seats
	
	local institution_seats = 0;
	local party_seats = 0;
	
	local background_color = local_parameter_to_value_or_boolean (frame, 'background-color');
	local border = local_parameter_to_value_or_boolean (frame, '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
	
	if 'fr' == cfg.this_project_language then									-- the French version of the wikidata template does not allow only grabbing the reference (it is always attached to the value, which breaks the composition bar)
		reference = false;
	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');
			local has_error;
			party_seats, has_error = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
			if has_error then
				return party_seats;												-- <party_seats> has an error message
			end
			institution_seats = constituency or member_state_delegation_size (frame, member_state_qid);	-- get total seats in <institution>
		else
			local has_error;
			party_seats, has_error = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
			if has_error then
				return party_seats;												-- <party_seats> has an error message
			end
			institution_seats = constituency or institution_size (frame, institution);	-- get total seats in <institution>
		end
	end
		
	local color = local_parameter_to_value_or_boolean (frame, 'bar-color') or allpp_get_data (frame, party, cfg.data_prop_t.colour);	-- get color associated with <party>; |bar-color= overrides wikidata
	
	if '' == party_seats or ''== institution_seats then
		if verbose then
			return make_error_msg (substitute (cfg.error_messages_t.no_data_short));
		else
			return "";
		end
	elseif party_type == "european_entity" and (institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE") then
		return xlate_composition_bar (frame, party_seats, institution_seats, color, width, percentage, background_color, border);
	else
		return xlate_composition_bar (frame, party_seats, institution_seats, color, width, percentage, background_color, border) .. ((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 ref = "";
	
--[=[ translate arguments ]=]	
	
	party_type = xlate (party_type);
	data_type = xlate (data_type);
	party = xlate (party);
	institution = xlate (institution);
	
--[=[ prepare arguments ]=]	
	
	local reference = local_parameter_to_value_or_boolean (frame, 'reference', 'boolean');	-- make a boolean
	
	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 true == 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 = xlate (institution);
	
	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 = xlate_wikidata ('property', national_party_qid, 'P1410', 'P194', lower_house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		local retval_upper = xlate_wikidata ('property', national_party_qid, 'P1410', 'P194', upper_house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
		
		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 parameter = args_t['parameter'] and args_t['parameter']:lower();		-- force to upper case
	local outcome = args_t['outcome'] and args_t['outcome']:lower();			-- force to upper case
	
	local localised_parameter = xlate_param (parameter); -- translate given parameter from English into local language
	local argument = (args_t[tostring(localised_parameter)] and args_t[tostring(localised_parameter)]:lower()) or (args_t[parameter] and args_t[parameter]:lower());	-- get argument (in local language) matching parameter in local language
	
	if outcome == 'boolean' then
		if nil == argument then													-- if no argument, return no
			argument = false;
		else
			argument = xlate (argument);										-- translate argument into English
			argument = 'yes' == argument;										-- turn argument into boolean
		end
	elseif argument:match ('^#') then
		argument = argument.gsub(argument, "#", "&#35;");
	end
	
	return argument;
	--return "parameter: " .. parameter .. " - outcome: " .. tostring(outcome) .. " - localised parameter: " .. localised_parameter .. " - argument: " .. tostring(argument);
end


local function test2 (frame)
	local args_t = get_args (frame);
	local party = args_t[1] and args_t[1]:upper();								-- force to upper case
	--if local_reference == 'reference=yes' then local_reference = 'reference' elseif local_reference == 'references=yes' then local_reference = 'references' else local_reference = '' end;
	--if local_preferred == 'preferred=yes' then local_preferred = 'preferred' else local_preferred = '' end;
	local local_raw = '';
	local local_linked = '-';
	--local qid = args_t[1];
	--local property = args_t[2];
	--return allpp_get_data (frame, party_qid, cfg.data_prop_t.country, 'raw-noref');
	--return tostring(xlate_wikidata ('property', party, cfg.data_prop_t.website, '', '', 'reference=no', 'preferred=no', 'raw=no', 'linked=no'));
	return frame:expandTemplate ({title='wikidata', args = {["entity"] = party, cfg.data_prop_t.website, ['link'] = "-", ['numval'] = 1}});
end

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

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