Modul:Marker utilities

Template-info.png Dokumentation für das Modul Marker utilities[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]

Anwendung

Das Modul stellt gemeinsame Funktionen für das Modul:Marker und das Modul:vCard zur Verfügung.

Versionsbezeichnung auf Wikidata: 2021-09-06 Ok!

Benötigte weitere Module

Dieses Modul benötigt folgende weitere Module: Coordinates • Marker utilities/Groups • Marker utilities/i18n • Marker utilities/Maki icons • Marker utilities/Types • UrlCheck • Wikidata utilities

Verwendung in anderen Modulen

Dieses Modul ist notwendig für die Ausführung folgender Module. Bei Anpassungen sollte die Funktionstüchtigkeit der folgenden Module geprüft werden. Benutze dazu auch diese Tracking-Kategorie um Fehler zu finden, die sich dann auf Artikel auswirken:

Wartungsfunktionen

function mu.initMaintenance( name )

Die Funktion initialisiert die Zeichenkettenverwaltung für die Ausgabe von Fehlermeldungen. name ist der zugehörige Modulname ohne die Namensraumbezeichnung. Diese Funktion setzt auch die Tabellen fehlerhafter Paramter und der Fehlermeldungen/Hinweise zurück.

function mu.addWrongParameter( param )

Diese Funktion fügt den Parameter param in die Tabelle fehlerhafter Parameter ein.

function mu.addDuplicateAlias( alias )

Diese Funktion fügt den Parameter alias in die Tabelle doppelter Aliase ein.

function mu.addMaintenance( s )

Diese Funktion fügt die Fehlermeldung s in die Tabelle der Fehlermeldungen und Hinweise ein. Ein Teil der oben genannten Funktionen befüllt ebenfalls diese Tabelle.

function mu.getMaintenance()

Dises Funktion liefert eine Zeichenkette mit allen Fehlermeldungen und Hinweisen zurück.

function mu.getCategories( formatStr )
  • Liefert eine Zeichenkette mit den Kategorie-Links aller verwendeten Wikidata-Eigenschaften zurück.

Funktionen

Im Projektnamensraum befindet sich die technische Dokumentation.

function mu.isSet( arg )

liefert true oder false, je nachdem, ob das Argument arg gesetzt ist oder nicht. arg muss existieren und einen Wert ungleich '' enthalten.

function mu.tableInsert( tab, value )

fügt den Wert value zur Tabelle tab hinzu, wenn er existiert und nicht leer ist.

function mu.textTrim( s )

entfernt Leer- und Steuerzeichen am Anfang und Ende der Zeichenkette.

function mu.textSplit( s, sep )

trennt die Zeichenkette s an Trennzeichen sep auf und legt sie in einer Tabelle ab. sep muss genau die Länge von einem Zeichen (ein Byte) haben und darf kein magisches Pattern-Zeichen sein. Die Funktion ist deutlich schneller als mw.text.split().

function mu.checkArguments( args, validKeys )

prüft, ob im Vorlagenaufruf unbekannte Parameternamen verwendet werden. Diese unbekannten Parameter werden in die Tabelle fehlerhafter Parameter eingefügt. args ist die Tabelle der Vorlagenparamter, validKeys die Tabelle der erlaubten Parameter (siehe z. B. Modul:VCard/i18n).

function mu.getArgument( args, keys )

liest den Wert aus der Vorlagenparametertabelle args mit dem Index/den Indices keys. keys kann eine Zeichenkette oder eine Tabelle mit Zeichenketten sein. Wenn ein Wert nicht existiert, wird nil zurückgeliefert. Sollten im Fall, dass keys eine Tabelle darstellt, mehrere Werte gefunden werden, wird der zuerst gefundene Wert zurückgeliefert, und der erste Parametername keys[ 1 ] wird in die Liste doppelter Aliase eingetragen.

function mu.translateGroup( group )

liefert eine Zeichenkette mit group in Übersetzung. Die Übersetzungen werden der Tabelle groups im Modul Marker utilities/Types entnommen. Ist keine Übersetzung vorhanden, so wird group unübersetzt zurückgeliefert.

function mu.addWdClass( isFromWikidata )

liefert den Klassenbezeichner wikidata-content, wenn isFromWikidata auf true gesetzt ist, ansonsten eine leere Zeichenkette.

function mu.dmsCoordinates( lat, long, name, fromWD, extraParams, withBracket )

liefert die Zeichenkette r, die eine zu den Kartenwerkzeugen verlinkte Dezimalkoordinate enthält, die wahlweise in Klammern gesetzt oder mit einem Komma eingeleitet werden kann. name ist der Name der Einrichtung, fromWD = true besagt, dass die Koordinate aus Wikidata stammt und extraParams enthält zusätzliche Parameter wird Maßstab und Region, die in den kartenwerkzeugen ausgewertet werden.

function mu.removeCtrls( s, onlyInline )

Die Funktion entfernt Steuerzeichen und die HTML-Tags für den Zeilenumbruch und Zeilenwechsel aus der Zeichenkette s. Wenn onlyInline = false, dann bleiben Zeilenumbruch und Zeilenwechsel erhalten. Deren Vorkommen wird in der Variablen descrDiv mitgeteilt. Die Funktion liefert zwei Werte zurück:

  • s bereinigte Zeichenkette.
  • descrDiv Der Container für die Beschreibung muss ein <div>-Tag sein.
function mu.addSisterIcons( sisters, name, id )

Die Funktion liefert die Zeichenkette mit Interwiki-verlinkten Symbolbildern wie Wikipedia und Wikimedia Commons zurück. sisters ist eine Tabelle mit Link-Zeichenketten zu den Wikis, name ist der Name einer Einrichtung und id die zugehörige Wikidata-Id. Es werden zwei Zeichenketten zurückgeliefert:

  • s vollständige Zeichenkette.
  • t Teilzeichenkette mit dem Wikidata-Link. Die Zeichenkette dient dazu, im Vergleich mit der ersten Zeichenkette festzustellen, ob die erste Zeichenkette nur aus dem Wikidata-Link besteht.
function mu.getWikiLink( langArray, wiki, entity, wikilang )

liefert die vollständige Zeichenkette l zu einem Artikel in Wikimedia-Projekten zurück. Die Angaben stammen aus den Sitelinks der Wikidata-Entity entity. langArray ist eine Tabelle der gewünschten Sprachen. wiki = "wiki" steht für den Einsatz in der Wikipedia.

function mu.makeSisterIcons( args, country, entity )

liefert eine Zeichenkette mit den verlinkten Schwesterprojekt-Symbolen. Die Angaben stammen meist aus den Sitelinks der Wikidata-Entity entity. args ist die Tabelle der übergebenen Vorlagenparameter. Die Tabelle country enthält länderspezifische Daten wie die Sprachangabe.

function mu.getName( name, pageTitle )

liefert die Tabelle array, die den Namen einer Einrichtung name in verschiedenen Formen enthält. Hauptaufgabe ist es, den eigentlichen Namen aus einem möglichen Link in Wikiyntax herauszulösen. pageTitle ist der mögliche Titel des zugehörigen Artikels. Enthält der Name neben einem möglichen Link in Wikisyntax weitere Textteile, so werden diese verworfen. Folgende vier Tabellenelemente werden zurückgeliefert:

  • exists: boolean, Name liegt vor.
  • name: string, nur der Name.
  • all: string, verlinkter Name oder nur der Name, falls kein Link vorliegt.
  • pageTitle: string, Artikel, auf den verlinkt wird. Der Titel kann von name verschieden sein.
function mu.checkCoordinates( lat, long )

liefert die überprüften Koordinaten lat, long. Im Fehlerfall sind lat und long leere Zeichenketten. Die Fehlermeldungstabelle enthält zusätzlich einen entsprechenden Eintrag (siehe unten).

function mu.getTypeParams( aType )

liefert den Parametersatz aus Module:Marker utilities/Types für den Typ aType zurück.

function mu.checkTypeAndGroup( aType, group )

liefert die überprüften Werte für aType, group zurück. Im Fehlerfall enthält die Fehlermeldungstabelle zusätzlich einen entsprechenden Eintrag (siehe unten).

function mu.checkImage( image, entity )

liefert den überprüften Wert für das image oder eine leere Zeichenkette zurück. Im Fehlerfall enthält die Fehlermeldungstabelle zusätzlich einen entsprechenden Eintrag (siehe unten). Die Variable mi.options.imageCheck legt fest, ob überhaupt einen rechenzeitintensive Prüfung vorgenommen wird.

function mu.checkCategory( category, catArray )

liefert den überprüften Wert für das category. Die Namenraumbezeichnung wird entfernt.

function mu.checkUrl( url )

liefert die überprüfte Internetaddresse url zurück. Im Fehlerfall enthält die Fehlermeldungstabelle zusätzlich einen entsprechenden Eintrag (siehe unten).

function mu.makeMarkerSymbol( args, title, frame )

liefert r: HTML-Quellcode des Marker-Symbols.

function mu.getColor( aType )

liefert color, aType. Die Gruupe aType wird durch error ersetzt, wenn sie nicht vorhanden ist. color ist die zur Gruppe gehörende Farbe und wird aus der Tabelle Modul:Marker utilities/Groups bezogen.

function mu.replaceBrackets( s )

liefert eine Zeichenkette, in der eckige Klammern durch XML-Zeichenreferenz ersetzt wurden. Wird benötigt, wenn die Zeichenkette in einem Link verwendet werden soll.

function mu.convertForSort( s )

Wandelt die Zeichenkette s so um, dass eine korrekte Sortierung ermöglicht wird. Die auszutauschenden Buchstaben sind in der sprachabhängigen Tabelle substitutes im Modul Marker utilities/i18n enthalten.

function mu.generateTableTypeList( frame )

liefert eine sortierbare Tabelle aller für die Vorlagen {{Marker}} und {{vCard}} einsetzbaren Typen. Die Tabelle zeigt die deutsche Übersetzung, die zugehörige Gruppe und die englische Typbezeichnung an.

function mu.data( s )

liefert die Zeichenkette s mit aufgelösten XML- und SGML-Enitäten, wenn sie existiert und nicht leer ist, ansonsten nil.

function mu.makeWrapper( result, args, country, show, list, aClass, frame )

umgibt zum Inhalt eines Markers oder einer vCard mit einem umschließenden Tag (span, div).

function mu.languageSpan( s, titleHint, args, country )

fügt den Text in ein span-Tag, in dem die Sprache und Textrichtung des des Texts s angegeben ist. titleHint ist das title-Attribut des span-Tags, args die Vorlagenparamtetertabelle und country eine Tabelle mit landesspezifischen Angaben.

function mu.split( s, convert, toValue )

liefert eine Tabelle kommaseparierter Werte der Zeichenkette s. Bei convert = true wird die Zeichenkette in Kleinbuchstaben umgewandelt, und Leerräume werden durch den Unterstrich ersetzt. Bei toValue = false, werden die Werte als Schlüssel einer assoziierten Tabelle übergeben.

function mu.splitAndCheck( s, validValues )

liefert eine Tabelle kommaseparierter Werte der Zeichenkette s und überprüft, ob diese Werte in der Tabelle validValues enthalten sind. Neben der Tabelle wird als zweiter Wert eine Zeichenkette mit den fehlerhaften Werten übergeben.

function mu.getShow( default, value, validValues )

liefert eine assoziierte Tabelle mit den übergebenen kommaseparierten show-Attributen, wobei der überschreibbare Standardwert default berücksichtigt wird. Die show-Attribute werden auf Gültigkeit hin überprüft.

function mu.getCoordinatesFromWikidata( entity )

liefert die im Wikidata-Datensatz mit der Einität entity enthaltene Koordinate zurück. Zuerst wird versucht, die Zentrumskoordinate aus der Eigenbschaft P5140 zu erhalten, danach die Koordinate aus der Eigenschaft P625.

function mu.makeSocial( args, fromWikidata, name, checkIt )

liefert die verlinkten Symbole von Social-Media-Diensten zurück. args ist die Tabelle der Vorlagenparameter, fromWikidata die Tabelle der Parameter, die aus Wikidata bezogen wurden, und name die Bezeichnung der Einrichtung. checkIt legt fest, ob eine Überprüfung der Werte erfolgen soll.

function mu.makeAirport( args, fromWikidata )

liefert den formatierten Flughafencode nach IATA oder, falls dieser fehlt, den nach ICAO. args ist die Tabelle der Vorlagenparameter und fromWikidata die Tabelle der Parameter, die aus Wikidata bezogen

function mu.typeSearch( p31 )
  • Sucht in mehreren P31-P279-Ketten nach Q-ids, deren Werte in den Tabellen Module:Wikidata2/POITypes oder Module:Marker utilities/Types enthalten sein könnten. Die Tabelle p31 enthält die vorgefunden P31-Werte. Der erste Treffer wird als Zeichenkette zurückgegeben, im Fehlerfall die Zeichenkette error. Die Maximalanzahl höherer Ebenen für die Suche ist mit mi.searchLimit vorgegeben, dies sind üblicherweise 4. Es wird nur jeweils die erste P279-Id ausgewertet, also nicht die gesamte Baumstruktur.
function mu.getMakiIconName( aType )

Die Funktion liefert den Namen einer MAKI-Ikone zum Type aType oder nil zurück, wenn es keinen gibt oder eine Abbildung für den Fließtext fehlt.

function mu.checkCommonsCategory( args )

Die Funktion löscht eine evtl. vorhandene Namensraumangabe in der Commons-Kategorie args.commonscat und fügt eine Wartungskategorie hinzu, wenn die Commons-Kategorie gesetzt wurde.

function mu.getCommonsCategory( args, entity )

Die Funktion versucht, eine Commons-Kategorie aus Wikidata über die Wikidata-Entität entity zu beziehen. Zuerst wird der Commons-Site-Link analysiert, dann die Eigenschft P373 und zuletzt die Eigenschaft P910.

function mu.getNamesFromWikidata( args, fromWikidata, country, entity )

Die Funktion befüllt die Tabelle args mit dem Namen der Einrichtung in der Wiki-Sprache und in der Landessprache mit den Angaben aus Wikidata. Die Tabelle fromWikidata enthält die Information (fromWikidata.name, fromWikidata.nameLocal), ob der Name aus Wikidata stammt.

function mu.getArticleLink( args, entity )

Die Funktion übergibt den Sitelink zum zugehörigen Arikel an args.thisWiki, außer der Vorlagenaufruf wurde in diesem Arikel vorgenommen.

function mu.formatNumber( num )
Die Funktion ersetzt in der als Zeichenkette vorliegenden Zahl das Dezimalzeichen und fügt Tausendertrennzeichen ein.
Hinweise
-- documentation
local MarkerUtilities = {
	suite  = 'Marker utilities',
	serial = '2021-09-06',
	item   = 58187612
}

-- Hint: In non-Wikivoyage projects, sister project links functions have to be
--       adapted.

-- module import
require( 'Module:No globals' )
local cd = require( 'Module:Coordinates' )
local mg = mw.loadData( 'Module:Marker utilities/Groups' )
local mi = require( 'Module:Marker utilities/i18n' )
local mm = require( 'Module:Marker utilities/Maki icons' )
local mt = require( 'Module:Marker utilities/Types' )   -- types to groups like drink, eat, go, see, sleep, ...
local uc = require( 'Module:UrlCheck' )
local wu = require( 'Module:Wikidata utilities' )

-- module variable and administration
local mu = {
	moduleInterface = MarkerUtilities
}

function mu.isSet( arg )
	return arg and arg ~= ''
end

function mu.tableInsert( tab, value )
	if mu.isSet( value ) then
		table.insert( tab, value )
	end
end

-- text manipulation
function mu.textTrim( s )
	return s:match( '^[%c%s]*(.-)[%c%s]*$' )
end

-- sep is a single character separator but no magic character
function mu.textSplit( s, sep )
	local result = {}
	for str in s:gmatch( '([^' .. sep .. ']+)' ) do
		str = mu.textTrim( str )
		if str ~= '' then
			mu.tableInsert( result, mu.textTrim( str ) )
		end
	end
	return result
end

function mu.getAliases( tab, indx )
	local result = {}
	if not tab then
		return result
	end
	local iItem
	for key, item in pairs( tab ) do
		iItem = item[ indx ]
		if iItem then
			if type( iItem ) == 'table' then
				for _, q in ipairs( iItem ) do
					result[ q ] = key
				end
			else
				result[ iItem ] = key
			end
		end
	end
	return result
end

-- maintenance tools
function mu.initMaintenance( name )
	mu.name         = name -- module name
	mu.params       = {}   -- table of unknown parameters
	mu.aliases      = {}   -- table of duplicate parameter aliases
	mu.maintenance  = {}   -- table of error strings

	mu.types = mu.getAliases( mt, 'wd' )           -- Q id to type table
	mu.typeAliases = mu.getAliases( mt, 'alias' )  -- table for type aliases
	mu.groupAliases = mu.getAliases( mg, 'alias' ) -- table for group aliases
end

function mu.addWrongParameter( param )
	table.insert( mu.params, "''" .. param .. "''" )
end

function mu.addDuplicateAlias( alias )
	table.insert( mu.aliases, "''" .. alias .. "''" )
end

function mu.addMaintenance( s )
	local function contains( new )
		for _, value in ipairs( mu.maintenance ) do
			if value == new then
				return true
			end
		end
		return false
	end
	if not contains( s ) then
		table.insert( mu.maintenance, s )
	end
end

function mu.getMaintenance()
	local s = ''
	if #mu.params > 0 then
		if #mu.params == 1 then
			s = mw.ustring.format( mi.maintenance.unknownParam, mu.params[ 1 ] )
		else
			s = mw.ustring.format( mi.maintenance.unknownParams,
				table.concat( mu.params, ', ' ) )
		end
		s = s .. mw.ustring.format( mi.maintenance.wrongParam, mu.name )
	end
	if #mu.aliases > 0 then
		s = s .. mw.ustring.format( mi.maintenance.duplicateAliases,
			table.concat( mu.aliases, ', ' ) )
	end
	return s .. table.concat( mu.maintenance, ' ' )
end

function mu.getCategories( formatStr )
	return wu.getCategories( formatStr )
end

-- args: template arguments consisting of argument name as key and a value
-- validKeys: table with argument name as key used by the script and
--    a string or a table of strings for argument names used by the local wiki
function mu.checkArguments( args, validKeys )
	if not args or not validKeys or not next( validKeys ) then
		return
	end

	for key, _ in pairs( args ) do
		local invalid = true
		for _, validKey in pairs( validKeys ) do
			if type( validKey ) == 'string' then
				validKey = { validKey }
			end
			for i = 1, #validKey, 1 do
				if key == validKey[ i ] then
					invalid = false
					break
				end
			end
		end
		if invalid then
			mu.addWrongParameter( key )
		end
	end
	return
end

-- returns an argument value from a set of keys
function mu.getArgument( args, keys )
	local value = nil
	if not args or not keys then
		return value
	end

	if type( keys ) == 'string' and keys ~= '' then
		keys = { keys }
	end
	if type( keys ) == 'table' then
		for _, key in ipairs( keys ) do
			if args[ key ] then
				if not value then
					value = args[ key ]
				else
					mu.addDuplicateAlias( keys[ 1 ] )
					break
				end
			end
		end
	end
	return value
end

-- groups translation for map legend into Wiki language
function mu.translateGroup( group )
	if not mu.isSet( group ) then
		group = mt.error.group
	end
	local t = mg[ group ]
	if t then
		t = t.map or t.label or t.alias or group
		if type( t ) == 'table' then
			t = t[ 1 ]
		end
		return t
	end
	return group
end

function mu.addWdClass( isFromWikidata )
	return isFromWikidata and ' wikidata-content' or ''
end

-- getting DMS coordinates
function mu.dmsCoordinates( lat, long, name, fromWD, extraParams, withBracket )
-- local function outputCoordinates( lat, long, name )
	local latDMS, _, latMs = cd.getDMSString( lat, 4, 'lat', '', '', mi.defaultDmsFormat )
	local longDMS, _, longMs = cd.getDMSString( long, 4, 'long', '', '', mi.defaultDmsFormat )

	local r = '[' .. mi.coordURL .. latMs .. '_' .. longMs .. '_'
		.. mw.uri.encode( extraParams )	.. '&locname=' .. mw.uri.encode( name )
		.. ' ' .. tostring( mw.html.create( 'span' )
				:addClass( 'coordStyle' )
				:attr( 'title', mi.texts.latitude )
				:wikitext( latDMS )
			)
		.. ' ' .. tostring( mw.html.create( 'span' )
				:addClass( 'coordStyle' )
				:attr( 'title', mi.texts.longitude )
				:wikitext( longDMS )
			)
		.. ']'
	if withBracket then
		r = '(' .. r .. ')'
	end
	return tostring( mw.html.create( 'span' )
		:attr( 'class', 'listing-dms-coordinates printNoLink plainlinks'
			.. mu.addWdClass( fromWD ) )
		:wikitext( r ) )
end

local function replaceWithSpace( s, pattern )
	s = s:find( pattern ) and s:gsub( pattern, ' ' ) or s
	return s
end

-- removing line breaks and controls from parameter strings
function mu.removeCtrls( s, onlyInline )
	local descrDiv = false -- div tag instead of span tag for description needed?

	-- remove controls from tags before test
	s = s:gsub( '(<[^>]+>)', function( t )
			return replaceWithSpace( t, '[%z\1-\31]' )
		end )

	local t = replaceWithSpace( s, '</br%s*>' )
	if onlyInline then
		t = replaceWithSpace( t, '<br[^/>]*/*>' )
		t = replaceWithSpace( t, '</*p[^/>]*/*>' )
		t = replaceWithSpace( t, '[%z\1-\31]' )
		-- not %c because \127 is used for Mediawiki tags (strip markers `UNIQ)
	else
		t = replaceWithSpace( t, '[%z\1-\9\11\12\14-\31]' )
		descrDiv = t:find( '[\10\13]' ) or t:find( '<br[^/>]*/*>' ) or
			t:find( '<p[^/>]*>' )
	end
	if t ~= s then
		mu.addMaintenance( mi.maintenance.illegalCtrls )
	end

	if descrDiv then
		mu.addMaintenance( mi.maintenance.descrDiv )
		-- replace line breaks by <br> in block mode
		t = t:gsub( '([^>%]\10\13])[\10\13][\10\13]+([^<%[\10\13])', '%1<br class="next-paragraph" />%2' )
	end

	return replaceWithSpace( t, '%s%s+' ), descrDiv
end

-- adding linked sister icons
function mu.addSisterIcons( sisters, name, id )
	local t = ''
	for key, value in pairs( sisters ) do
		if value ~= '' then
			t = t .. ' ' .. tostring( mw.html.create( 'span' )
				:attr( 'class', 'listing-sister-icon listing-sister-' .. key )
				:wikitext( '[' .. value .. ' '
					.. mw.ustring.format( mi.icons[ key ], name ) .. ']' )
			)
		end
	end

	local s = ''
	if mu.isSet( id ) then
		-- add Wikidata symbol
		s = tostring( mw.html.create( 'span' )
			:attr( 'class', 'listing-sister-icon listing-sister-wikidata' )
			:addClass( t == '' and 'listing-only-wikidata' or nil )
			:wikitext( '[' .. tostring( mw.uri.fullUrl( 'd:' .. id ) )
				.. ' ' .. mw.ustring.format( mi.icons.wikidata, name, id ) .. ']' )
			)
		t = t .. s
	end
	return t, s
end

local function getURL( prefix, page )
	return tostring( mw.uri.fullUrl( prefix .. mw.uri.encode( page, 'WIKI' ) ) )
end

-- getting sister project links
function mu.getWikiLink( langArray, wiki, entity, wikilang )
	local prefix = ''
	if wiki == 'wiki' then
		prefix = 'w:' -- empty in case of Wikivoyage
	end
	local link
	for _, lang in ipairs( langArray ) do
		if lang ~= '' then
			link = wu.getSitelink( entity, lang .. wiki )
			if link then
				return getURL( prefix ..
					( lang ~= wikilang and ( lang .. ':' ) or '' ), link )
			end
		end
	end
	return ''
end

-- adding Wikimedia sister project icons
function mu.makeSisterIcons( args, page, country, entity )
	local sisters = {
		wikivoyage = '', -- link to another branch, usually en, as a sister link
		commons    = '', -- link to Commons category
		wikipedia  = ''  -- link to Wikipedia
	}

	if mu.isSet( args.wikipedia ) then
		sisters.wikipedia = getURL( 'w:', args.wikipedia )
	end
	if mu.isSet( args.wikidata ) then
		if sisters.wikipedia == '' then
			sisters.wikipedia = mu.getWikiLink(
				{ page.lang, mi.langs.name, country.lang }, 'wiki', entity, page.lang
			)
		end
		if args.wikiPage == '' then
			sisters.wikivoyage = mu.getWikiLink(
				{ mi.langs.name, country.lang }, page.globalProject, entity, page.lang
			)
			if sisters.wikivoyage ~= '' then
				mu.addMaintenance( mi.maintenance.linkToOtherWV )
			end
		end
	end
	if args.commonscat ~= '' then
		sisters.commons = getURL( 'c:Category:', args.commonscat )
	end

	return mu.addSisterIcons( sisters, args.givenName.name, args.wikidata )
end

-- getting name table with linked and unlinked names
function mu.getName( name, pageTitle )
	local r = {
		exists = false,
		all = '', -- name or linked name
		name = '', -- only name
		pageTitle = '', -- if pageTitle ~= '' name is already linked
	}
	if not mu.isSet( name ) or type( name ) ~= 'string' then
		return r
	end

	r.exists = true
	local s
	local t, c = mw.ustring.gsub( name, '^(.*)%[%[(.*)%]%](.*)$', '%2' )
	if c > 0 then -- is / contains [[...]]
		t = mu.textTrim( t )
		r.all = '[[' .. t .. ']]'
		s, c = mw.ustring.gsub( t, '^(.*)|(.*)$', '%2' )
		if c > 0 then -- is [[...|...]]
			r.name = mu.textTrim( s )
			r.pageTitle = mu.textTrim( mw.ustring.gsub( t, '^(.*)|(.*)$', '%1' ) )
		else
			r.name = t
			r.pageTitle = t
		end
	else
		r.name = name
		r.all = name
		if pageTitle ~= '' then
			r.pageTitle = pageTitle
			r.all = '[[' .. pageTitle .. '|' .. name .. ']]'
		end
	end
	return r
end

-- checking coordinates
function mu.checkCoordinates( args )
	local dms = false
	local t
	if type( args.lat ) == 'boolean' then
		args.lat = ''
	end
	if type( args.long ) == 'boolean' then
		args.long = ''
	end
	if args.lat == '' and args.long == '' then
		return
	elseif args.lat ~= '' and args.long == '' then
		t = args.lat:find( ',', 1, true )
		if t then
			args.long = mu.textTrim( args.lat:sub( t + 1, #args.lat ) )
			args.lat = mu.textTrim( args.lat:sub( 1, t - 1 ) )
		end
	end
	if args.lat == '' or args.long == '' then
		args.lat = ''
		args.long = ''
		mu.addMaintenance( mi.maintenance.wrongCoord )
		return
	end

	t = tonumber( args.lat )
	if t then
		args.lat = math.abs( t ) <= 90 and t or ''
	else
		t = cd.toDec( args.lat, 'lat', 6 )
		args.lat = t.error == 0 and t.dec or ''
		dms = args.lat ~= ''
	end
	if args.lat == '' then
		args.long = ''
		mu.addMaintenance( mi.maintenance.wrongCoord )
		return
	end

	t = tonumber( args.long )
	if t then
		args.long = ( t > -180 and t <= 180 ) and t or ''
	else
		t = cd.toDec( args.long, 'long', 6 )
		args.long = t.error == 0 and t.dec or ''
		dms = dms or args.long ~= ''
	end
	if args.long == '' then
		args.lat = ''
		mu.addMaintenance( mi.maintenance.wrongCoord )
	end
	if dms then
		mu.addMaintenance( mi.maintenance.dmsCoordinate )
	end

	return
end

-- getting a set of parameters for a given type
function mu.getTypeParams( aType )
	return mt[ aType ] and mt[ aType ] or {}
end

local function encodeSpaces( s )
	if s:find( '[_%s]+' ) then
		s = s:gsub( '[_%s]+', '_' )
	end
	return s
end

-- getting marker type and group
function mu.checkTypeAndGroup( args )
	local s, t
	if mu.isSet( args.group ) then
		mu.addMaintenance( mi.maintenance.groupUsed )
		if mu.groupAliases[ args.group ] then
			args.group = mu.groupAliases[ args.group ]
		end
		s = mg[ args.group ]
		if not s then			
			mu.addMaintenance( mi.maintenance.unknownGroup )
			args.group = ''
		end
	end
	if not mu.isSet( args.type ) then
		args.type = mt.error.group
		if args.group == '' then
			args.group = mt.error.group
		end
		mu.addMaintenance( mi.maintenance.missingType )
	elseif args.type == mt.error.group then
		if args.group == '' then
			args.group = mt.error.group
		end
		mu.addMaintenance( mi.maintenance.unknownType )
	else
		-- split seperate types and analyse them
		args.typeTable = {}
		for _, t in ipairs( mu.textSplit( args.type, ',' ) ) do
			t = encodeSpaces( t:lower() )
			if next( mu.typeAliases ) then
				t = mu.typeAliases[ t ] or t
			end
			s = mu.groupAliases[ t ]
			if s then
				t = s
			end
			s = mg[ t ]
			if s then -- type is a group itself
				if s.is and s.is == 'color' then
					mu.addMaintenance( mi.maintenance.typeIsColor )
					if s.alias then
						t = s.alias
						if type( t ) == 'table' then
							t = t[ 1 ]
						end
					end
				elseif not mi.options.noTypeMsgs then
					mu.addMaintenance( mi.maintenance.typeIsGroup )
				end
				if args.group == '' then
					args.group = t
				end
			else
				s = mt[ t ]
				if s then
					if args.group == '' then
						args.group = s.group
					end
				else
					mu.addMaintenance( mi.maintenance.unknownType )
					args.group = mt.error.group
				end
			end
			table.insert( args.typeTable, t )
		end
		args.type = table.concat( args.typeTable, ',' )
	end
	return
end

local function removeNS( s, nsTable )
	s = s or ''
	if not s:find( ':', 1, true ) then
		return s
	end

	local t = s
	for _, ns in ipairs( nsTable ) do
		t = mw.ustring.gsub( t, '^' .. ns .. ':', '' )
		if s ~= t then
			break
		end
	end
	return t
end

-- image check
function mu.checkImage( image, entity )
	if type( image ) == 'boolean' or image == '' then
		return image
	end

	-- delete namespace
	image = removeNS( image, mi.texts.FileNS )

	-- formal checks
	if image:find( '^https?:' ) then
		image = ''
	else
		local extExists = false
		local im = image:lower()
		for _, ext in ipairs( mi.fileExtensions ) do
			if im:find( '%.' .. ext .. '$' ) then
				extExists = true
				break
			end
		end
		if not extExists then
			image = ''
		end
	end
	if image == '' then
		mu.addMaintenance( mi.maintenance.wrongImgName )
		return image
	end

	local alreadyChecked = false
	if mi.options.mediaCheck and image ~= '' then
		if not mi.options.WDmediaCheck and entity then
			-- check if image is stored in Wikidata
			local imgs = wu.getValues( entity, mi.properties.image, nil )
			if #imgs > 0 then
				for i = 1, #imgs, 1 do
					if imgs[ i ] == image then
						alreadyChecked = true
						break
					end
				end
			end
		end
		if not alreadyChecked then
			-- expensive function call
			local title = mw.title.new( 'Media:' .. image )
			if not title or not title.exists then
				mu.addMaintenance( mw.ustring.format( mi.maintenance.missingImg, image ) )
				image = ''
			end
		end
	end
	return image
end

-- remove namespace from category
function mu.checkCategory( category )
	return removeNS( category, mi.texts.CategoryNS )
end

-- looking for URL query which can contain a tracking parameter
local function lookForQuery( url )
	if mi.options.lookForQuery and mu.isSet( url ) and url:find( '?', 1, true ) then
		for _, p in ipairs( mi.queryExceptions ) do
			if url:find( p ) then
				return
			end
		end
		mu.addMaintenance( mi.maintenance.urlWithQuery )
	end
end

-- url check
function mu.checkUrl( url )
	local domain

	if mu.isSet( url ) then
		local c = uc.isUrl( url, mi.options.skipPathCheck ) -- getting result code
		if c > 2 then
			mu.addMaintenance( mi.maintenance.wrongUrl )
			url = ''
		elseif c == 2 then -- URL contains IP address
			mu.addMaintenance( mi.maintenance.urlWithIP )
		end
		lookForQuery( url )
	end

	if mu.isSet( url ) then
		for _, service in ipairs( mi.services ) do
			domain = service.url:gsub( 'com/.*', 'com' )
				:gsub( 'https://', '' ):gsub( 'www.', '' )
			if url:find( domain, 1, true ) then
				mu.addMaintenance( mi.maintenance.urlIsSocialMedia )
				url = ''
			end
		end
	end

	return url
end

-- making marker symbol
function mu.makeMarkerSymbol( args, title, frame )
	local lon = tonumber( args.long )
	local lat = tonumber( args.lat )
    local tagArgs = {
        zoom = tonumber( args.zoom ),
        latitude = lat,
        longitude = lon,
        show = mi.showAll,
    }
	if mu.isSet( args.text ) then
		tagArgs.text = args.text
		if not args.useIcon then
			tagArgs.class = 'no-icon'
		end
	end
	if mu.isSet( args.mapGroup ) then
		tagArgs.group = args.mapGroup
		tagArgs.show = args.mapGroup
	else
		tagArgs.group = mu.translateGroup( args.group )
	end
	if mu.isSet( args.image ) then
		tagArgs.description = '[[File:' .. args.image .. '|100x100px|' .. title .. ']]'
	end

	local geoJson = {
		type = 'Feature',
		geometry = {
			type = 'Point',
			coordinates = { lon, lat }
		},
		properties = {
			title = title,
			description = tagArgs.description,
			['marker-symbol'] = args.symbol,
			['marker-color'] = args.color,
			['marker-size'] = 'medium',
		}
	}

	return tostring( mw.html.create( 'span' )
		:attr( 'class', 'plainlinks printNoLink poi listing-map' )
		:attr( 'title', mi.texts.tooltip )
		:css( {
			[ 'background-color' ] = args.color,
			[ 'border-color' ] = args.color
		} )
		-- frame:extensionTag is expensive
		:wikitext( frame:extensionTag( 'maplink', mw.text.jsonEncode( geoJson ), tagArgs ) )
	)
end

-- getting color from group type
function mu.getColor( aType )
	local c = mg[ aType ]
	if c then
		return c.color, aType
	else
		return mg[ 'error' ].color, 'error'
	end
end

-- replace brackets in names
function mu.replaceBrackets( s )
	s, _ = s:gsub( '%[', '&#x005B;' )
		:gsub( '%]', '&#x005D;' )
	return s
end

function mu.convertForSort( s )
	s = mw.ustring.lower( s )
	for _, obj in ipairs( mi.substitutes ) do
		s = mw.ustring.gsub( s, obj.l, obj.as )
	end
	return s
end

-- generates a table with type documentation
function mu.generateTableTypeList( frame )
	local rows = {}
	local typeList = '<table class="sortable multiline" cellspacing="0">'
		.. '<tr><th>' .. mi.types.label .. '</th><th>'
		.. mi.types.group .. '</th><th>' .. mi.types.type .. '</th></tr>'
	local label
	for key, value in pairs( mt ) do
		label = value.label or value.alias or key
		if type( label ) == 'table' then
			label = label[ 1 ] or ''
		end
		label = label:gsub( '_', ' ' )
		table.insert( rows, '<tr><td>' .. label .. '</td><td>' .. value.group
			.. '</td><td>' .. key:gsub( '_', ' ' ) .. '</td></tr>' )
	end
	table.sort( rows,
		function( a, b )
			return mu.convertForSort( a ) < mu.convertForSort( b )
		end
	)
	return typeList .. table.concat( rows, '' ) .. '</table>'
end

-- prepare value data parameter to a tag
function mu.data( s )
	if not mu.isSet( s ) then
		return nil
	else
		return mw.text.decode( s, true ) -- replacing all entities by characters
	end
end

-- adding wrapper and microformats
function mu.makeWrapper( result, args, page, country, show, list, aClass, frame )
	if type( result ) == 'table' then
		result = table.concat( result, ' ' )
	end

	local wrapper = mw.html.create( show.inline and 'span' or 'div' )
		:attr( 'class', 'h-card ' .. aClass )
	if args.noGpx then
		wrapper:addClass( 'vcard-nogpx' )
	else
		wrapper:addClass( 'vcard' )
	end
	if show.outdent and not show.inline then
		wrapper:addClass( 'listing-outdent' )
	end
	if show.inlineSelected then
		wrapper:addClass( 'listing-inline' )
	end
	if args.givenName.name ~= mi.maintenance.missingName then
		wrapper:attr( 'data-name', mu.data( args.givenName.name ) )
	end
	wrapper:attr( 'data-location', mu.data( page.subpageText ) )
		:attr( 'data-location-qid', page.entityId )
		:attr( 'data-wikilang', page.lang )
		:attr( 'data-country', mu.data( country.iso_3166 ) )
		:attr( 'data-country-name', mu.data( country.country ) )
		:attr( 'data-lang', mu.data( country.lang ) )
		:attr( 'data-lang-name', mu.data( country.langName ) )
		:attr( 'data-country-calling-code', mu.data( country.cc ) )
		:attr( 'data-trunk-prefix', mu.data( country.trunkPrefix ) )
		:attr( 'data-dir', mu.data( country.isRTL and 'rtl' or 'ltr' ) )
		:attr( 'data-wiki-dir', mu.data( page.isRTL and 'rtl' or 'ltr' ) )
		:attr( 'data-currency', mu.data( country.addCurrency ) )
	local arg
	for key, value in pairs( list ) do
		arg = args[ key ]:gsub( '<[^<>]*>', '' ) -- remove html tags
		wrapper:attr( value, mu.data( arg ) )
	end
	if not show.noCoord then
		wrapper:node( mw.html.create( 'span' )
			:attr( 'class', 'p-geo geo listing-coordinates' )
			:css( 'display', 'none' )
			:node( mw.html.create( 'span' )
				:attr( 'class', 'p-latitude latitude' )
				:wikitext( args.lat )
			)
			:node( mw.html.create( 'span' )
				:attr( 'class', 'p-longitude longitude' )
				:wikitext( args.long )
			)	
		)
	end
	if not show.name then
		wrapper:node( mw.html.create( 'span' )
			:attr( 'class', 'p-name fn org listing-name' )
			:css( 'display', 'none' )
			:wikitext( args.givenName.name )
		)
	end

	wrapper = tostring( wrapper:wikitext( result ) )

	-- adding coordinates to Mediawiki database
	-- frame:callParserFunction is expensive
	if not show.noCoord and mi.options.secondaryCoords then
		wrapper = wrapper .. frame:callParserFunction{ name = '#coordinates',
			args = { args.lat, args.long, country.extra, name = args.givenName.name } }
	end

	return wrapper
end

-- bdi and bdo tags are not working properly on all browsers. Adding marks
-- (lrm, rlm) is maybe the only way for a correct output
function mu.languageSpan( s, titleHint, page, country )
	if not mu.isSet( s ) then
		return ''
	end

	local c = country.lang
	if c == '' or c == page.lang then
		return s
	end

	local dir
	if country.isRTL then
		dir = 'rtl'
	elseif page.isRTL then
		dir = 'ltr'
	end	

	local t = tostring( mw.html.create( 'span' )
		:attr( 'lang', c )
		:attr( 'dir', dir )
		:attr( 'title', mw.ustring.format( titleHint , country.langName ) )
		:wikitext( s )
	)

	if country.isRTL and not page.isRTL then
		t = '&rlm;' .. t .. '&lrm;'
	end
	if not country.isRTL and page.isRTL then
		t = '&lrm;' .. t .. '&rlm;'
	end
	return t
end

-- Splitting comma separated lists to an array
-- convert = true: conversion to lowercase characters, spaces to low lines
-- toValue = true: list items handled as array values
-- toValue = false: list items handled as array keys
function mu.split( s, convert, toValue )
	local arr = {}
	if not mu.isSet( s ) then
		return arr
	end
	for _, str in ipairs( mu.textSplit( s, ',' ) ) do
		if convert then
			str = encodeSpaces( str:lower() )
		end
		if toValue then
			table.insert( arr, str )
		else
			arr[ str ] = ''
		end
	end
	return arr
end

-- Splitting comma separated lists to an array of key items
-- checking items with allowed key values of validValues array
function mu.splitAndCheck( s, validValues, validAliases )
	local arr = {}
	local err = {}
	local at, count, item, wrong
	if not mu.isSet( s ) or not validValues then
		return arr, ''
	end
	-- error check
	for k, _ in pairs( mu.split( s, true ) ) do
		wrong = false
		count = ''
		item = k
		if validValues[ item ] and validValues[ item ].e then
			item = validValues[ item ].e
		end
		-- split subtype from count
		at = item:find( ':', 1, true )
		if at then
			count = tonumber( item:sub( at + 1, #item ) ) or ''
			item = mu.textTrim( item:sub( 1, at - 1 ) )
			if count == '' then
				wrong = true
			else
				count = math.floor( count )
				if count < 2 then
					count = ''
				end
			end
		end
		-- check subtype
		if validAliases and validAliases[ item ] then
			item = validAliases[ item ]
		end
		if validValues[ item ] then
			arr[ item ] = count
		else
			wrong = true
		end
		if wrong then
			table.insert( err, k )
		end
	end
	return arr, table.concat( err, ', ' )
end

function mu.getShow( default, value, validValues )
	local show = mu.split( default, true )
	local add, err = mu.splitAndCheck( value, validValues )
	if err ~= '' then
		mu.addMaintenance( mw.ustring.format( mi.maintenance.unknownShow, err ) )
	end
	if add.none or add.coord or add.poi or add.all then
		show.all   = nil -- overwriting defaults
		show.coord = nil
		show.poi   = nil
	end
	for key, value in pairs( add ) do
		show[ key ] = value
	end
	if show.none then
		show.none  = nil
		show.all   = nil
		show.coord = nil
		show.poi   = nil
	end
	if show.all then
		show.all   = nil
		show.coord = ''
		show.poi   = ''
	end

	return show
end

function mu.getCoordinatesFromWikidata( args, fromWikidata, entity )
	if not entity or ( args.lat ~= '' and args.long ~= '' ) then
		return
	end

	-- center coordinates from Wikidata
	local c = wu.getValue( entity, mi.properties.centerCoordinates )
	if c == '' then
		-- coordinates from Wikidata
		c = wu.getValue( entity, mi.properties.coordinates )
	end
	if c ~= '' then
		args.lat = c.latitude
		args.long = c.longitude
		fromWikidata.lat = true
	end
end

function mu.makeSocial( args, fromWikidata, name, checkIt )
	local domain, span, t
	local s = ''

	for _, service in ipairs( mi.services ) do
		-- check values first
		t = args[ service.key ] or ''
		domain = service.url:gsub( 'com/.*', 'com/' )
		if t ~= '' and checkIt then
			if t:match( '^http' ) then
				if not t:match( '^https' ) then
					t = t:gsub( '^http', 'https' )
					mu.addMaintenance( mw.ustring.format(
						mi.maintenance.wrongSocialUrl, service.key ) )
				end
				if uc.isUrl( t, mi.options.skipPathCheck ) > 1 or
					not t:match( '^' .. domain .. '.+$' ) then
					t = ''
					mu.addMaintenance( mw.ustring.format(
						mi.maintenance.wrongSocialUrl, service.key ) )
				end
				if t ~= '' and not fromWikidata[ service.key ] then
					mu.addMaintenance( mw.ustring.format(
						mi.maintenance.socialUrlUsed, service.key ) )
				end
			else
				local match = false
				local sp = service.pattern
				if type( sp ) == 'string' then
					sp = { sp }
				end
				for _, pattern in ipairs( sp ) do
					if mw.ustring.match( t, pattern ) then
						match = true
						break
					end
				end
				if not match then
					t = ''
					mu.addMaintenance( mw.ustring.format(
						mi.maintenance.wrongSocialId, service.key ) )
				end
			end
		end
		args[ service.key ] = t

		-- create symbol link
		if t ~= '' then
			if not t:find( domain, 1, true ) then
				t = mw.ustring.format( service.url, t )				
			end
			span = mw.html.create( 'span' )
				:attr( 'class', 'listing-social-media '
					.. 'listing-social-media-' .. service.key
					.. mu.addWdClass( fromWikidata[ service.key ] ) )
				:attr( 'style', mi.texts.socialStyle )
				:wikitext( '[' .. t .. ' '
					.. mw.ustring.format( mi.icons[ service.key ], name ) .. ']' )
			s = s .. tostring( span )
		end
	end
	return s
end

local function _makeAirport( code, args, fromWikidata )
	local span = mw.html.create( 'span' )
		:attr( 'class', 'listing-' .. code .. '-code'
			.. mu.addWdClass( fromWikidata[ code ] ) )
		:wikitext( args[ code ] )
	return tostring( mw.html.create( 'span' )
		:attr( 'class', 'listing-airport listing-' .. code )
		:wikitext( mw.ustring.format( mi.texts[ code ], tostring( span ) ) )
	)
end

function mu.makeAirport( args, fromWikidata )
	local airport = ''
	if mu.isSet( args.iata ) then
		airport = _makeAirport( 'iata', args, fromWikidata )
	elseif mu.isSet( args.icao ) then
		airport = _makeAirport( 'icao', args, fromWikidata )
	end
	return airport
end

local function _typeSearch( p31 )
	-- p31: array of Wikidata values
	if not p31 or #p31 == 0 then
		return ''
	end

	local firstStep = true

	local function compareLabels( ar )
		if not ar then
			return nil
		elseif type( ar ) == 'string' then
			ar = { ar }
		end
		for i, value in ipairs( ar ) do
			if mu.isSet( value ) then
				value = mw.ustring.lower( encodeSpaces( value ) )
				if mt[ value ] then
					return value
				end
			end
		end
		return nil
	end

	local function compareIds( ar )
		local id, t
		for i = 1, #ar, 1 do
			id = ar[ i ].id
			-- md: indexed array of q id - types relations
			t = mu.types[ id ]
			if t then
				return t
			end

			-- checking English label and aliases
			t = compareLabels( mw.wikibase.getLabelByLang( id, 'en' ) )
				or compareLabels( wu.getAliases( id, 'en' ) )
			if t then
				if firstStep and not mi.options.noTypeMsgs then
					firstStep = false
					mu.addMaintenance( mi.maintenance.typeFromWDchain )
				end
				return t
			end
		end
		return nil
	end

	local aType = compareIds( p31 ) -- check p31 ids first, maybe step 2 is not nessary
	if aType then
		if not mi.options.noTypeMsgs then
			mu.addMaintenance( mi.maintenance.typeFromWD )
		end
		return aType
	end

	-- now functions becomes expensive because of multiple wu.getValues calls
	local id, ids
	firstStep = false
	for i = 1, #p31, 1 do -- step 2: analyse P279 chains of first ids
		id = p31[ i ].id -- start id
		local j = 0
		repeat
			ids = wu.getValues( id, mi.properties.subclassOf, nil )
			if #ids > 0 then
				aType = compareIds( ids )
				if aType then
					if not mi.options.noTypeMsgs then
						mu.addMaintenance( mi.maintenance.typeFromWD )
						mu.addMaintenance( mi.maintenance.typeFromWDchain )
					end
					return aType
				end
				id = ids[ 1 ].id
			end
			j = j + 1

		-- limit: maximum levels to analyse
		until j >= mi.searchLimit or #ids == 0
	end

	return ''
end

function mu.typeSearch( p31, entity )
	if p31 and #p31 == 0 then
		p31 = wu.getValues( entity, mi.properties.subclassOf, mi.p31Limit )
	end
	return _typeSearch( p31 )
end

-- returns a single data set from Module:Marker utilities/Maki icons
function mu.getMaki( key )
	return mm[ key ]
end

function mu.getMakiIconName( aType )
	local mType
	if mm[ aType ] then
		mType = aType
	elseif mt[ aType ] and mt[ aType ].icon then
		mType = mt[ aType ].icon
	end
	if mType and mu.isSet( mm[ mType ].im ) then
		return mType
	end
	return nil
end

function mu.checkCommonsCategory( args )
	-- remove namespace from category
	if mu.isSet( args.commonscat ) then
		args.commonscat = mu.checkCategory( args.commonscat )
		if args.commonscat ~= '' then
			mu.addMaintenance( mi.maintenance.commonscat )
		end
	end
end

function mu.getCommonsCategory( args, entity )
	-- getting commonscat from commonswiki sitelink before P373
	-- because sitelink is checked by Wikidata
	if type( args.commonscat ) == 'boolean' then
		args.commonscat = ''
	end

	local t = wu.getSitelink( entity, 'commonswiki' ) or ''
	if t:match( '^Category:.+$' ) then
		t = t:gsub( '^Category:', '' )
	else
		t = wu.getValue( entity, mi.properties.commonsCategory )
		if t == '' then
			local id = wu.getId( entity, mi.properties.mainCategory )
			if id ~= '' then
				t = wu.getSitelink( id, 'commonswiki' ) or ''
				t = t:gsub( '^Category:', '' )
			end
		end
	end
	if t ~= '' and args.commonscat ~= '' then
		mu.addMaintenance( mi.maintenance.commonscatWD )
	end
	if args.commonscat == '' then
		args.commonscat = t
	end
end

-- getting names from Wikidata
function mu.getNamesFromWikidata( args, fromWikidata, page, country, entity )
	-- getting official names
	local officialNames =
		wu.getMonolingualValues( entity, mi.properties.officialName )

	if type( args.name ) == 'boolean' or args.name == '' then
		args.name = officialNames[ page.lang ]
			or mi.langs.name ~= '' and officialNames[ mi.langs.name ]
			or ''
		-- if failed then get labels
		if args.name == '' then
			if page.lang == mi.langs.name then
				args.name = wu.getLabel( entity ) or ''
			else
				args.name = wu.getLabel( entity )
					or mi.langs.name ~= '' and wu.getLabel( entity, mi.langs.name )
					or ''
			end
		end
		if args.name ~= '' then
			mu.addMaintenance( mi.maintenance.nameFromWD )
			fromWikidata.name = true
		end
	end

	-- get local name if no name is available
	if args.name == '' and
		not ( type( args.nameLocal ) == 'string' and args.nameLocal ~= '' ) then
		args.nameLocal = true
	-- no local name if country and wiki language are identical
	elseif args.nameLocal == true and page.lang == country.lang then
		args.nameLocal = ''	
	end

	if args.nameLocal == true then
		args.nameLocal = officialNames[ country.lang ] or ''
		if args.nameLocal == '' then
			args.nameLocal = wu.getLabel( entity, country.lang ) or ''
		end
		if args.name == '' and args.nameLocal ~= '' then
			args.name = args.nameLocal
			args.nameLocal = ''
			mu.addMaintenance( mi.maintenance.nameFromWD )
			fromWikidata.name = true
		end
		fromWikidata.nameLocal = args.nameLocal ~= ''
		-- for future use in Module:Marker
--		if fromWikidata.nameLocal then
--			mu.addMaintenance( mi.maintenance.localNameFromWD )
--		end
	end
end

-- getting link to Wikivoyage
function mu.getArticleLink( args, entity, page )
	local t = wu.getSitelinkTable( entity, page.lang .. page.globalProject )
	if t and t.title ~= page.text then  -- no link to the article itself
		local isLink = false
		for _, badge in ipairs( t.badges ) do
			if badge == mi.qualifiers.intentionalSitelink or 
				badge == mi.qualifiers.redirectSitelink then
				isLink = true
				break
			end
		end
		if not isLink then
			args.wikiPage = t.title
		end
	end
end

-- replacing decimal separator and inserting group separators
function mu.formatNumber( num )
	if mu.isSet( mi.formatnum.decimalPoint ) and mi.formatnum.decimalPoint ~= '.' then
		num = num:gsub( '%.', mi.formatnum.decimalPoint )
	end

	if mu.isSet( mi.formatnum.groupSeparator ) then
		local count
		repeat
			num, count = num:gsub( '^([-+]?%d+)(%d%d%d)',
				'%1%' .. mi.formatnum.groupSeparator .. '%2' ) 
		until count == 0
	end
    return num
end

return mu