Module:Institution

    From Commons

    Documentation for this module may be created at Module:Institution/doc

    --[[  
      __  __           _       _        ___           _   _ _         _   _             
     |  \/  | ___   __| |_   _| | ___ _|_ _|_ __  ___| |_(_) |_ _   _| |_(_) ___  _ __  
     | |\/| |/ _ \ / _` | | | | |/ _ (_)| || '_ \/ __| __| | __| | | | __| |/ _ \| '_ \ 
     | |  | | (_) | (_| | |_| | |  __/_ | || | | \__ \ |_| | |_| |_| | |_| | (_) | | | |
     |_|  |_|\___/ \__,_|\__,_|_|\___(_)___|_| |_|___/\__|_|\__|\__,_|\__|_|\___/|_| |_|
                                                                                        
    
    This module is intended to be the engine behind "Template:Institution".
    
    Please do not modify this code without applying the changes first at 
    "Module:Institution/sandbox" and testing at "Module:Institution/testcases".
    
    Authors and maintainers:
    * User:Jarekt - original version 
    
    ]]
    require('Module:No globals') -- used for debugging purposes as it detects cases of unintended global variables
    local Wikidata2        = require("Module:Wikidata label")                      -- used for creation of name based on wikidata
    local getDate          = require("Module:Wikidata date")._date                 -- used for processing of date properties
    local authorityControl = require("Module:Authority control")._authorityControl -- used for formatting of Authority control row
    local City             = require("Module:City")                                -- used to add wikidata bases links to names of places
    local Coordinates      = require("Module:Coordinates")
    local labels           = require("Module:I18n/institution")
    local ISOdate          = require("Module:ISOdate")                             -- used for internationalization of dates
    local LanguageCodes    = require("Module:LanguageCodes")                       
    
    -- ==================================================
    -- === Internal functions ===========================
    -- ==================================================
    local function langSwitch(list,lang)
    	local langList = mw.language.getFallbacksFor(lang)
    	table.insert(langList,1,lang)
    	for _,language in ipairs(langList) do
    		if list[language] then
    			return list[language]
    		end
    	end
    	return nil
    end
    
    local function info_box(text, lang, qCode)
    	return string.format('<table class="messagebox plainlinks layouttemplate" style="border-collapse:collapse; border-width:2px; border-style:solid; width:100%%; clear: both; '..
    		'border-color:#f28500; background:#ffe;direction:ltr; border-left-width: 8px; ">'..
    		'<tr>'..
    		'<td class="mbox-image" style="padding-left:.9em;">'..
    		' [[File:Commons-emblem-issue.svg|class=noviewer|45px]]</td>'..
    		'<td class="mbox-text" style="">%s</td>'..
    		'</tr></table>', string.format(langSwitch(labels[text],lang), qCode))
    end
    
    -- ====================================================================
    -- This function is responsible for producing HTML of a single row of the template
    -- At this stage all the fields are already filed. There is either one or two fields
    -- INPUTS:
    -- * param - structures for 2 fields containing fields:
    --    - field    - field name
    --    - wrapper  - some fields need a <span class=...> wrapper around the field content 
    -- * args - table with all the parameters
    -- ====================================================================
    local function Build_html_row(param, args)
    	local field = args[param.field]
    	if field=='' then field=nul; end
    	if not (field or args.demo) then 
    		return nil
    	end
    	local tag = labels[param.field]
    	if type(tag)=='string' and string.match(tag, "^Q%d+$") then
    		tag = Wikidata2._getLabel(tag, args.lang, "-", "ucfirst")
    	else
    		tag = langSwitch(tag, args.lang)
    	end
    	local cell1 = string.format('<td style="%s">%s</td>\n', args.style2, tag)
    	local cell2 = string.format('<td colspan="2" style="%s">'.. param.wrapper ..'</td>', args.style1, field or '')
    	return string.format('<tr valign="top">\n%s%s</tr>\n', cell1, cell2)
    end
    
    -- ====================================================================
    -- === This function is just responsible for producing HTML of the  ===
    -- === template. At this stage all the fields are already filed     ===
    -- ====================================================================
    local function Build_html(args, cats)
    	local field
    	args.style1 = 'border:1px solid #aaa;'
    	args.style2 = 'background-color:#e0e0ee; font-weight:bold; ' .. args.style1
    	args.style3 = 'min-width:130px; ' .. args.style1
    	
    	-- get text direction
    	local dir, text_align, odir
    	if mw.language.new( args.lang ):isRTL() then
    		dir, text_align, odir = 'rtl', 'right', 'left'
    	else
    		dir, text_align, odir = 'ltr', 'left', 'right'
    	end 
    	
    	-- Top line with Creator name, lifespan and link icons -
    	local top = {}
    	table.insert(top, string.format('<span class="fn" id="creator"><bdi>%s\n</bdi></span>', args.name or 'missing name') )
    	table.insert(top, string.format('[[File:Blue pencil.svg|15px|link=Institution:%s]]', args.linkback or '') )
    	if args.wikidata then -- Wikidata Link
    		table.insert(top, string.format('[[File:Wikidata-logo.svg|20px|wikidata:%s|link=wikidata:%s]]', args.wikidata, args.wikidata) )
    	end
    	if args.QS then -- quick_statement link to upload missing info to wikidata
    		table.insert(top, string.format('%s', args.QS) )
    	end
    	if args.inventory then
    		local formatStr = "<span style='float:%s; font-size:80%%; margin-%s:20px;'> ([[%s|%s]])</span>"
    		table.insert(top, string.format(formatStr, odir, odir, args.inventory, langSwitch(labels.inventory, args.lang)  ))
    	end
    	
    	local line = string.format('<th colspan="4" style="%s">%s</th>', args.style2, table.concat(top, '&nbsp;')) 
    	local results = {}
    	table.insert(results, string.format('<tr valign="top">\n%s\n</tr>\n', line))
    	
    	-- add other fields
    	local param = {
    		{field='native_name' 	, wrapper='%s'},
    		{field='parent'       , wrapper='%s'},
    		{field='location' 		, wrapper='<span class="locality">%s</span>'},
    		{field='coordinates'	, wrapper='%s'},
    		{field='established' 	, wrapper='%s'},
    		{field='website'      , wrapper='%s'},
    		{field='authority'		, wrapper='%s'},
    	}
    	for i=1,#param do
    		table.insert(results, Build_html_row(param[i], args))
    	end
    
    	-- Image on the Left
    	if not args.image and args.demo then
    		args.image = 'MarksburgSilhouette.svg'
    	end
    	if args.image then --Wikiquote link
    		field = string.format('[[File:%s|200x140px|alt=%s|class=photo]]', args.image, args.name or '') 
    		local n = #results -- number of rows below 
    		line  = string.format('<td rowspan="%i" style="width:120px" id="fileinfotpl_creator_image"><span class="wpImageAnnotatorControl wpImageAnnotatorOff">%s</span></td>', n, field) 
    		table.insert(results, 2, string.format('<tr valign="top">\n%s\n</tr>\n', line)	)
    	end
    	results = table.concat(results)
    
    	-- build table
    	local collapsed = ''
    	if args.collapse or args.namespace == 6 then
    		collapsed = 'collapsed'
    	end
    	local style = string.format('class="toccolours collapsible %s" cellpadding="2" cellspacing="0" style="direction:%s; text-align:%s; border-collapse:collapse; background:#f0f0ff; border:1px solid #aaa;" lang="%s"',
    		collapsed, dir, text_align, args.lang)
    	results = string.format('<table %s>\n%s\n</table>\n', style, results)
    	results = string.format('<div class="vcard">\n%s\n</div>\n', results)
    	
    	-- add references and documentation which are only visible in creator namespace
    	if args.namespace==106 then
    		local box =''
    		if args.wikidata and string.match(cats,'missing linkback') then
    			box = info_box('missing_linkback', args.lang, args.wikidata)
    		elseif args.wikidata and string.match(cats,'without home category') then
    			box = info_box('missing_homecat', args.lang, args.wikidata)
    		end
    		local doc = mw.getCurrentFrame():expandTemplate{ title ='documentation', args = { 'Template:Institution/documentation' } }
    		results = results .. box .. doc -- add documentation to pages in creator namespace
    	end
    	return results
    end
    
    -- ===========================================================================
    -- === Create coordinate link                                              ===
    -- === INPUTS:                                                             ===
    -- ===  * lat - latitude of the institution                                ===
    -- ===  * lon - longitude of the institution                               ===
    -- ===  * osm - "waypoint" ID gives better www.openstreetmap.org link      ===
    -- ===  * geopoly - not woring at the moment                               ===
    -- ===  * lang  - language id of the desired language                      ===
    -- ===  * namespace - namespace number of the page calling the module      ===
    -- ===========================================================================
    local function coords(lat, lon, osm, geopoly, namespace, lang)
    	if not lat or not lon then
    		return nil
    	end
    
    	-- add OSM polygon, title etc.
    	local str, prec
    	if namespace == 6 then -- in files
    		str = Coordinates._lat_lon(lat, lon, prec, lang)
    	else
    		local args = { lat=lat, lon=lon, lang=lang, prec="50", mode="institution"}
    		str = Coordinates._GeoHack_link(args)
    	end
    	-- OSM link
    	local osmlink = string.format('//www.openstreetmap.org/index.html?mlat=%s&mlon=%s&zoom=17', lat, lon)
    	if osm then
    		osmlink = string.format('//www.openstreetmap.org/?way=%s', osm)
    	end
    	osmlink = string.format('<span class="wpImageAnnotatorControl wpImageAnnotatorOff">[[File:Openstreetmap logo.svg|20px|Link to OpenStreetMap|link=%s]]</span>', osmlink)
    	-- Google maps link
    	local gmaplink = string.format('//maps.google.com/maps?hl=%s&q=%s,%s&tab=wl', lang, lat, lon)
    	if geopoly then
    		--gmaplink = string.format('//tools.wmflabs.org/dschwenbot/geo_poly/?t=unnamed&p=%s', mw.text.encode(geopoly)) -- not working at the moment
    	end
    	gmaplink = string.format('<span class="wpImageAnnotatorControl wpImageAnnotatorOff">[[File:Google favicon.svg|16px|Link to Google Maps|link=%s]]</span>', gmaplink)
    	return str .. ' ' .. osmlink .. ' ' .. gmaplink
    end
    
    -- ===========================================================================
    -- === This function is responsible for adding maintenance categories      ===
    -- === which are not related to wikidata                                   ===
    -- === INPUTS:                                                             ===
    -- ===  * args  - merged data from the local arguments and Wikidata        ===
    -- ===========================================================================
    local function add_maintenance_categories(args)
    	local cats = '' -- categories 
    	
    	-- if home category than
    	if args.namespace==14 and args.homecat and mw.title.new('Category:' .. args.homecat):localUrl() == mw.title.getCurrentTitle():localUrl() then
    	
    		cats = cats .. '\n[[Category:Institution template home categories]]'
    		--cats = cats .. string.format('\n[[Category:namespace %i]]',args.namespace)
    		-- check for wikidata q-code
    		if not args.wikidata then
    			cats = cats .. '\n[[Category:Institution template home categories without Wikidata link]]'
    		end
    	end
    		
    	-- ===============================================================
    	-- === automatic categorization of pages in Institution: namespace === 
    	-- ===============================================================
    	if args.namespace~=106 then
    		return cats
    	end
    	
    	-- add [[Category:Institution templates]] category
    	cats = cats .. string.format('\n[[Category:Institution templates]]')
    	
    	-- check for key information
    	if not args.linkback and not args.wikidata then
    		cats = cats .. '\n[[Category:Institution templates without linkback]]'
    	end	
    	if not args.name then
    		cats = cats .. '\n[[Category:Institution templates without name]]'
    	end	
    	
    	-- add homecat category
    	if args.homecat then
    		cats = cats .. string.format('\n[[Category:%s]]',args.homecat)
    	end
    	
    	-- check for image
    	if not args.image then
    		cats = cats .. '\n[[Category:Institution templates without images]]'
    	end
    	-- check for wikidata q-code
    	if not args.wikidata then
    		cats = cats .. '\n[[Category:Institution templates without Wikidata link]]'
    	end
    	-- check for homecat
    	if not args.homecat then
    		cats = cats .. '\n[[Category:Institution templates without home category]]'
    	else
    		local hc = mw.title.new('Category:'..args.homecat)
    		if not hc or not hc.exists then
    			cats = cats .. '\n[[Category:Institution templates without home category]]'
    		end 
    	end
    
    	return cats
    end
    
    -- ===========================================================================
    -- === This function is responsible for adding maintenance categories      ===
    -- === to pages in Institution namespace which are related to wikidata     ===
    -- === INPUTS:                                                             ===
    -- ===  * args0 - local inputs from the Institution template page          ===
    -- ===  * args1 - merge of local and wikidata metadata                     ===
    -- ===  * data  - data pulled from Wikidata                                ===
    -- ===========================================================================
    local function add_categories_to_institution_namespace(args0, args1, data)
    	local cats = ''     -- categories 
    	local qsTable = {}  -- table to store QuickStatements 
    	local comp    = {}  -- outcome of argument vs. wikidata comparison
    	local today = '+' .. os.date('!%F') .. 'T00:00:00Z/11' -- today's date in QS format
    	-- two forms of QuickStatements command with and without quotes
    	local qsCommand = {'%s|%s|%s|S143|Q48552277|S813|' .. today, '%s|%s|"%s"|S143|Q48552277|S813|' .. today}
    
    	-- compare Linkback to the actual page name. Many "Linkbacks" are created with 
    	-- tool which produces &#38; and &#39;  instead of "&" and "'"
    	if args0.linkback then
    		local linkback = args0.linkback
    		linkback = mw.ustring.gsub(linkback, '&#39;', "'")
    		linkback = mw.ustring.gsub(linkback, '&#38;', "&")
    		if linkback~=args0.pagename then
    			cats = cats .. '\n[[Category:Institution templates with mismatching linkback]]'
    		end
    	end
    	
    	-- add [[Category:Institution templates with unknown parameter]] category, if some parameter not on the following list is used
    	local fields = {'name', 'native_name', 'inventory', 'parent', 'location', 'latitude', 'longitude', 'osm', 'geopoly', 
    									'image', 'homecat', 'established', 'website', 'authority', 'stub', 'demo',
    									'namespace', 'linkback', 'wikidata', 'lang', 'pagename', 'option', 'collapse' }
    	local set = {}
    	for _, field in ipairs(fields) do set[field] = true end
    	for field, _ in pairs( args0 ) do 
    		if not set[field] then
    			cats = string.format('%s\n[[Category:Institution templates with unknown parameter|%s]]', cats, field)
    		end
    	end
    	
    	-- skip the rest if no q-code
    	if not args0.wikidata then
    		return cats, args1
    	end	
    	
    	-- add [[Category:Wikidata based Institution templates]] and [[Category:Institution templates with Wikidata link: local linkback]]
    	local val = {wikidata=1, linkback=0, lang=0, namespace=0, pagename=0 }
    	local hash = 0;
    	for field, _ in pairs( args0 ) do 
    		hash = hash + (val[field] or 10)
    	end
    	if hash==1 then
    		cats = string.format('%s\n[[Category:Institution templates based only on Wikidata]]', cats)
    	end
    	
    	-- mark parameters as "local" if they are present in Institution template
    	local fields = {'name', 'native_name', 'parent', 'location', 'image', 'homecat', 'established', 'website', 'authority', 'linkback'}
    	for _, field in ipairs( fields ) do
    		if args0[field] then
    			comp[field] = 'local'
    		end
    	end
    	
    	-- redundant if commons Institution template and wikidata have those fields and they are the same
    	local fields = {'established', 'native name‎'}
    	for _, field in ipairs( fields ) do
    		if args0[field] and data[field] and args0[field]==data[field] then
    			comp[field] = 'redundant'
    		end
    	end
    
    	-- redundant name if wikidata has at least English label
    	if args0.name and data.name_ and not string.match(data.name_, "^%[%[d:Q%d+%|.+%]%]")  then
    		comp.name = 'redundant'
    	end
    	
    	-- redundant if commons Institution template and wikidata have those fields, without checking values
    	if args0.location and data.location then
    		--comp.location = 'redundant'
    	end
    	
    	-- ==================================================
    	-- === coordinates  ================================= 
    	-- ==================================================
    	-- calculate distance
    	local lat1, lat2, lon1, lon2 = args0.latitude, data.latitude, args0.longitude, data.longitude
    	if lat1 and lat2 then
    		comp.coordinates = 'local'
    	end
    	if lat1 and lat2 and lon1 and lon2 then
    		local dLat = math.rad(lat1-lat2)
    		local dLon = math.rad(lon1-lon2)
    		local d = math.pow(math.sin(dLat/2),2) + math.pow(math.sin(dLon/2),2) * math.cos(math.rad(lat1)) * math.cos(math.rad(lat2))
    		d = 2 * math.atan2(math.sqrt(d), math.sqrt(1-d))  -- angular distance in radians
    		d = 6371000 * d       -- radians to meters conversion
    		if d<100 then
    			comp.coordinates = 'redundant'
    		else
    			comp.coordinates = 'mismatching'
    		end
    	elseif lat1 and not lat2 and lon1 and not lon2 then
    		comp.coordinates = 'item missing'
    		table.insert( qsTable, string.format(qsCommand[1], args0.wikidata, 'P625', string.format('@%09.5f/%09.5f', lat1, lon1)) )
    	end
    
      -- ==================================================
    	-- === website  ===================================== 
    	-- ==================================================	
    	args0.website_ = args0.website
    	if args0.website then
    		local str = string.match(args0.website, "%[([^ %]]+)[ %]]")
    		if str then -- strip off [] brackets if detected
    		  args0.website_ = str
    		end
    	end
    	local a1 = args0.website_    -- creator template value  
    	local d1 = data.website      -- wikidata q-code
    	if a1 and d1 and a1==d1 then 
    		comp.website = 'redundant'	
    	elseif a1 and not d1 then
    		comp.website = 'item missing'
    		table.insert( qsTable, string.format(qsCommand[2], args0.wikidata, 'P856', a1) )
    	end	
    	
    	-- ==================================================
    	-- === odds and ends  =============================== 
    	-- ==================================================	
    	if args0.image then 
    		args0.image_ = mw.uri.decode( args0.image, "WIKI" )
    	end
    	args0.linkback_ = args0.pagename;
    	args0.homecat_  = args0.homecat;	
    	
    	local fields = {image='P18', linkback='P1612', homecat='P373'}
    	for field, prop in pairs( fields ) do
    		a1 = args0[field..'_'] -- creator template value  
    		d1 = data[field]       -- wikidata q-code
    		if a1 and d1 and a1~=d1 then 
    			comp[field] = 'mismatching'
    		elseif a1 and d1 and a1==d1 then 
    			comp[field] = 'redundant'	
    		elseif a1 and not d1 then
    			comp[field] = 'item missing'
    			table.insert( qsTable, string.format(qsCommand[2], args0.wikidata, prop, a1) )
    		end	
    	end
    	if comp.linkback == 'redundant' and (hash~=1 or not args0.linkback) then
    		comp.linkback = nil
    	end
    
    	-- ==================================================
    	-- === Create categories and QuickStatement codes === 
    	-- ==================================================
    	-- create categories based on comp structure
    	for field, outcome in pairs( comp ) do
    		cats = string.format('%s\n[[Category:Institution templates with Wikidata link: %s %s]]', cats, outcome, field)
    	end
    	
    	-- convert QS table to a string
    	local QS   = ''     -- quick_statements final string
    	if #qsTable>0 then
    		local qsHeader  = 'https://tools.wmflabs.org/quickstatements/index_old.html#v1='
    		local qsWrapper = '&nbsp;[[File:Commons_to_Wikidata_QuickStatements.svg|15px|link=%s]]'
    		QS = table.concat( qsTable, '%0A')
    		QS = mw.ustring.gsub(QS, '|', "%%09")
    		QS = mw.ustring.gsub(QS, '"', "%%22")
    		QS = mw.ustring.gsub(QS, ' ', "%%20")
    		QS = string.format(qsWrapper, qsHeader .. QS)
    		cats = cats .. '\n[[Category:Institution templates with Wikidata link: quick statements]]'
    	end
    	args1.QS = QS;
    	return cats, args1
    end
    
    -- ===========================================================================
    -- === Harvest wikidata properties matching creator template fields        ===
    -- === INPUTS:                                                             ===
    -- ===  * qCode - item id or a q-code                                      ===
    -- ===  * lang  - language id of the desired language                      ===
    -- ===  * namespace - namespace number of the page calling the module      ===
    -- ===========================================================================
    local function harvest_wikidata(qCode, lang, namespace)
    -- INPUTS:
    -- * qCode - item id or a q-code
    -- * lang  - language id of the desired language
    -- * namespace - namespace number of the page calling the module
    	local str, d, v
    	local data = {} -- structure similar to "args" but filled with wikidata data
    	local cats = ''
    	local entity = nil
    	if mw.wikibase and qCode then
    		entity = mw.wikibase.getEntity(qCode)
    		if not entity then
    			 cats = '[[Category:Institution templates with bad Wikidata link|invalid]]' 
    		elseif entity.id~=qCode then
    			 cats = '[[Category:Institution templates with redirected Wikidata link]]'
    		end
    	end
    	if not entity then
    		return data, cats
    	end
    
    	-- ===========================================================================
    	-- === Step 1: time properties
    	-- ===========================================================================	
    	-- harvest time properties: translated date and year number
    	local d = getDate(entity, 'P1619' , lang)  -- date of official opening
    	if not d.str or d.str=='' then
    		d = getDate(entity, 'P571' , lang) -- inception date
    	end
    	data.established, data.established_ = d.str, d.iso
    	
    	-- ===========================================================================
    	-- === Step 1a: website
    	-- ===========================================================================	
    	-- look for multiple values each with a language code
    	local website = {}
    	local val
    	for _, statement in pairs( entity:getBestStatements( 'P856' )) do
    		if (statement.mainsnak.snaktype == "value") then 
    			val = statement.mainsnak.datavalue.value
    			local lng = nil
    			if statement.qualifiers and statement.qualifiers.P407 then
    				lng = statement.qualifiers.P407[1].datavalue.value.id
    				lng = LanguageCodes[lng]
    		  end
    			--cats = cats .. "[[Category:".. lng .. " : " ..val .."]]"
    			website[lng or 'en'] = val
    		end
    	end
    	data.website = langSwitch(website, lang)
    	if not data.website and val then
    		data.website = val 
    	end
    		
    	-- ===========================================================================
    	-- === Step 2: simple string and Q-code properties
    	-- ===========================================================================	
    	-- harvest string and Q-code properties
    	local property = {P18='image', P154='logo_image', P373='homecat', P1612='linkback', P1448='official_name', 
    										P1705='native_name', P131='city', P276='location', P159='HQ_location', P749='parent', P361='partOf', P17='country'}
    	for prop, field in pairs( property ) do
    		if entity.claims and entity.claims[prop] then -- if we have wikidata item and item has the property
    			-- capture single "best" Wikidata value
    			for _, statement in pairs( entity:getBestStatements( prop )) do
    				if (statement.mainsnak.snaktype == "value") then 
    					local v = statement.mainsnak.datavalue.value
    					if v.id then 
    						v = Wikidata2._getLabel(v.id, lang, "wikipedia")
    					elseif v.text then
    						v = v.text
    					end
    					data[field] = v
    				end
    			end
    		end
    	end
    	data.native_name = data.official_name or data.native_name
    	data.image       = data.logo_image or data.image
    	data.location    = data.city or data.HQ_location or data.location
    	data.parent      = data.parent or data.partOf
    	if data.location and data.country then
    		data.location = mw.text.listToText( {data.location, data.country}, ', ', ', ')
    	end
    	-- trim website name
    	if data.website then
    		local website    = mw.ustring.gsub(data.website , '^https?\:\/\/', "")   -- remove "http://" or "https://" at the beginning
    		website          = mw.ustring.gsub(website , '\/$', "")                 -- "/" at the end
    		data.website     = string.format("[%s %s]", data.website, website)
    	end
    	
    	-- ===========================================================================
    	-- === Step 3: geographic coordinates
    	-- ===========================================================================	
    	local P625 = entity:getBestStatements( 'P625' ) --  coordinate location
    	v = nil
    	if P625[1] and P625[1].mainsnak.datavalue.value.latitude then 
    		v = P625[1].mainsnak.datavalue.value
    	end
    	if not v then -- check for location of  headquarters location (P159) 
    		local P159 = entity:getBestStatements( 'P159' ) 
    		if P159[1] and P159[1].qualifiers and P159[1].qualifiers.P625 then
    			v = P159[1].qualifiers.P625[1].datavalue.value
    		end
    	end
    	if v and v.globe == 'http://www.wikidata.org/entity/Q2' then
    		data.latitude, data.longitude = v.latitude, v.longitude
    	end
    
    	-- =================================================================================
    	-- === Step 4: name and authority control
    	-- =================================================================================	
    	-- get name field
    	data.name  = Wikidata2._getLabel(entity, lang, "wikipedia") -- create name based on wikidata label
    	data.name_ = Wikidata2._getLabel(entity, 'en', "wikipedia") -- try english label label
    
    	-- get authority control template		
    	local AC_cats
    	data.authority, AC_cats = authorityControl(entity, {wikidata = qCode}, lang, 5) 
    	if not (namespace == 2 or namespace == 6 or namespace == 828 or math.fmod(namespace,2)==1) then
    		cats = cats .. AC_cats -- lets not add authorityControl categories to user pages, files, modules or talk pages and concentrate on templates and categories instead
    	end
    	
    	return data, cats
    end
    
    -- ==================================================
    -- === External functions ===========================
    -- ==================================================
    local p = {}
    
    -- ===========================================================================
    -- === Version of the function to be called from other LUA codes
    -- ===========================================================================
    function p._institution(args0)
    	local lang = args0.lang  -- user's language
    	local cats = ''         -- categories 
    	local str, data
    	
    	-- look up title info
    	args0.namespace  = mw.title.getCurrentTitle().namespace   -- get page namespace
    	args0.pagename   = mw.title.getCurrentTitle().text        -- get {{PAGENAME}}
    
    	-- ===========================================================================
    	-- === Step 1: clean up of template arguments "args0"
    	-- ===========================================================================
    	if args0.linkback then
    		args0.linkback = string.sub(args0.linkback,13)
    	end
    	if args0.established then
    			args0.established = ISOdate._ISOdate(args0.established, lang)
    	end
    	if not tonumber(args0.latitude) or not tonumber(args0.longitude) then
    		args0.longitude = nil
    		args0.latitude  = nil
    	end
    	
    	-- ===========================================================================
    	-- === Step 2: one by one merge wikidata and creator data
    	-- ===========================================================================
    	data, cats = harvest_wikidata(args0.wikidata, lang, args0.namespace)
    	
    	-- mass merge (prioritize local values)
    	local args = {}
    	local fields = {'native_name', 'inventory', 'parent', 'location', 'latitude', 'longitude', 'demo', 'image', 'homecat', 
    					'established', 'website', 'authority', 'linkback', 'wikidata', 'lang', 'namespace', 'collapse' }
    	for _, field in ipairs( fields ) do 
    		args[field] = args0[field] or data[field]
    	end
    	args.name = data.name
    	if not args.name or string.match(args.name or '', "^%[%[d:Q%d+%|Q.+%]%]") then 
    		args.name = args0.name -- no name on Wikidata
    	end
    	--args.name = data.name or args0.name
    
    	args.location = City._city(args.location, lang) 
    	args.coordinates = coords(args.latitude, args.longitude, args0.osm, args0.geopoly, args0.namespace, lang)
    
    	-- convert all empty strings to nils
    	for _, field in ipairs( fields ) do 
    		if args[field] == '' then 
    			args[field] = nil; 
    		end
    	end
    	
    	-- ===========================================================================
    	-- === Step 3: create maintenance categories and render html of the table
    	-- ===========================================================================
    	cats = cats .. add_maintenance_categories(args)
    	-- If institution namespace than add maintenance categories
    	args.QS = nil;
    	if args.namespace==106  then
    		str, args = add_categories_to_institution_namespace(args0, args, data)
    		cats = cats .. str
    	end
    	local results = Build_html(args, cats)
    	return results, cats
    end
    
    -- ===========================================================================
    -- === Version of the function to be called from template namespace
    -- ===========================================================================
    function p.institution(frame)
    	-- switch to lowercase parameters to make them case independent
    	local args = {}
    	for name, value in pairs( frame:getParent().args ) do 
    		if value ~= '' then -- nuke empty strings
    			local name1 = string.gsub( string.lower(name), ' ', '_')
    			args[name1] = value
    		end
    	end
    	for name, value in pairs( frame.args ) do 
    		if value ~= '' then -- nuke empty strings
    			local name1 = string.gsub( string.lower(name), ' ', '_')
    			args[name1] = value
    		end
    	end
    	
    	if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then 
    		args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
    	end
    
    	if args.option == 'collapse' then
    		args.collapse = 1 -- some "options" are to modify the name and some are commands to do things
    		args.option  = nil
    	end
    	local QS = ''
    	if args.wikidata and string.match(args.wikidata or '', "^Q%d+$") then -- invisible language independent marking
    		QS = string.format('<div style="display: none;">institution QS:P195,%s</div>\n', args.wikidata)
    	end
    	
    	-- call the inner "core" function
    	local results, cats = p._institution(args)	
    	return results .. QS .. cats
    end
    
    return p