FANDOM


local p = {};
 
local i18nDefaultLanguage = 'uk';
local i18nEditors = {
	fr	= '',
	de	= 'Hrsg.: ',
	es	= '',
	en	= '',
	it	= '',
	ru	= 'под ред. ',
	uk	= 'за ред. ',
}
local i18nEtAlDefault = ' et al.';
local i18nEtAl = {
	ru	= ' и др.',
	uk	= ' та ін.',
}
local i18nVolume = {
	fr	= 'Vol.',
	es	= 'Vol.',
	en	= 'Vol.',
	it	= 'Vol.',
	ru	= 'Т.',
	uk = 'Т.'
}
local i18nIssue = {
	en	= 'Iss.',
	ru	= 'вып.',
	uk	= 'вип.',
}
local i18nPages = {
	fr = 'P.',
	de = 'S.',
	es = 'P.',
	en = 'P.',
	it = 'P.',
	ru = 'С.',
	uk = 'С.'
}
 
local i18nNumberOfPages = {
	en = 'p.',
	ru = 'с.',
	uk = 'с.',
}
 
local monthg = {'січня', 'лютого', 'березня', 'квітня', 'травня', 'червня', 'липня', 'серпня', "вересня", "жовтня", "листопада", "грудня"};
 
local PREFIX_CITEREF = "CITEREF_";
 
local options_arxiv = { separator = '; ', conjunction = '; ', format = function( id ) return '[http://arxiv.org/abs/' .. id .. ' arXiv:' .. id .. ']' end, nolinks = true, preferids = false };
local options_doi = { separator = '; ', conjunction = '; ', format = function( doi ) return '[http://dx.doi.org/' .. doi .. ' doi:' .. doi .. ']' end, nolinks = true, preferids = false };
local options_issn = { separator = '; ', conjunction = '; ', format = function( issn ) return '[https://www.worldcat.org/issn/' .. issn .. ' ' .. issn .. ']' end, nolinks = true, preferids = false };
 
local options_commas = { separator = ', ', conjunction = ', ', format = function( src ) return src end, nolinks = false, preferids = false };
local options_commas_short = { separator = ', ', conjunction = ', ', format = function( src ) return src end, nolinks = false, preferids = false, short = true };
local options_commas_nolinks = { separator = ', ', conjunction = ', ', format = function( src ) return src end, nolinks = true, preferids = false };
local options_commas_it = { separator = ', ', conjunction = ', ', format = function( src ) return "''" .. src .. "''" end, nolinks = false, preferids = false };
local options_commas_it_short = { separator = ', ', conjunction = ', ', format = function( src ) return "''" .. src .. "''" end, nolinks = false, preferids = false, short = true };
local options_commas_it_nolinks = { separator = ', ', conjunction = ', ', format = function( src ) return "''" .. src .. "''" end, nolinks = true , preferids = false };
local options_citetypes = { separator = ' ', conjunction = ' ', format = function( src ) return 'citetype_' .. src end, nolinks = true , preferids = true };
 
function assertNotNull( argName, arg )
	if ( (not arg) or (arg == nil) ) then
		error( argName .. ' is not specified' )
	end
end
 
function coalesce( arg1, arg2, arg3, arg4 )
	if ( not isEmpty( arg1 ) ) then return arg1 end
	if ( not isEmpty( arg2 ) ) then return arg2 end
	if ( not isEmpty( arg3 ) ) then return arg3 end
	if ( not isEmpty( arg4 ) ) then return arg4 end
	return nil;
end
 
function isEmpty( str )
	return ( not str ) or ( str == nil ) or ( #str == 0 );
end
 
function isInstanceOf( entity, typeEntityId )
	if ( not entity or not entity.claims or not entity.claims.P31 ) then
		return false;
	end
 
	for _, claim in pairs( entity.claims.P31 ) do
		if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value["numeric-id"] ) then
			local actualTypeId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
			if ( actualTypeId == typeEntityId ) then
				return true;
			end
		end
	end
 
	return false;
end
 
function getEntity( context, entityId )
	assertNotNull( 'context', context );
	assertNotNull( 'entityId', entityId );
 
	local cached = context.cache[ entityId ];
	if ( cached ) then return cached; end;
 
	local result = mw.wikibase.getEntity( entityId );
	if ( result ) then
		context.cache[ entityId ] = result;
	end
 
	return result;
end
 
function toStringSnak( propertyId, strValue )
	assertNotNull('propertyId', strValue)
	assertNotNull('strValue', strValue)
 
	local snak = { snaktype = "value", property = propertyId, datatype = 'string'};
	snak["datavalue"] = { value = strValue, type = 'string' };
	return snak;
end
 
function toUrlSnak( propertyId, strValue )
	assertNotNull('propertyId', strValue)
	assertNotNull('strValue', strValue)
 
	local snak = { snaktype = "value", property = propertyId, datatype = 'string'};
	snak["datavalue"] = { value = strValue, type = 'url' };
	return snak;
end
 
function toWikibaseEntityIdSnak( propertyId, entityId )
	assertNotNull('propertyId', entityId)
	assertNotNull('entityId', entityId)
	if ( mw.ustring.sub( entityId, 1, 1 ) ~= 'Q' ) then error( 'Incorrect entity ID: «' .. entityId .. '»' ); end;
 
	local value = {};
	value["entity-type"] = 'item';
	value["numeric-id"] = mw.ustring.sub( entityId , 2);
 
	local snak = { snaktype = "value", property = propertyId, datatype = 'wikibase-item'};
	snak["datavalue"] = { value = value, type = 'wikibase-entityid' };
	return snak;
end
 
function renderSource( context, src )
	context.lang = getLangCode( getSingle( src.lang ) ) or i18nDefaultLanguage;
 
	preprocessPlaces( src, context.lang );
 
	src.title = src.title or getSingle( src.url ) or '\'\'(unspecified title)\'\''
 
	if ( src.sourceId and not src.url ) then
		local entity = getEntity( context, src.sourceId );
		if ( entity.sitelinks and entity.sitelinks[ context.lang .. 'wikisource'] ) then
			src.url = ':' .. context.lang .. ':s:' .. entity.sitelinks[ context.lang .. 'wikisource' ].title;
		end
	end
 
	if ( not src.year and src.dateOfPublication ) then
		local date = getSingle( src.dateOfPublication );
		src.year = mw.ustring.sub( date, 2, 5 );
	end
 
	if ( not src.year and src.dateOfCreation ) then
		local date = getSingle( src.dateOfCreation );
		src.year = mw.ustring.sub( date, 2, 5 );
	end
 
	local result;
	if ( src.author ) then
		result = getPeopleAsAuthorWikitext( context, src.author, options_commas );
	end
	if ( not isEmpty( result )) then
		result = '<i class="wef_low_priority_links">' .. result .. '</i> ';
	else
		result = '';
	end
 
 	if ( src.part ) then
 		if ( src.url ) then
			result = result .. wrapInUrl( src.url, toString( context, src.part, options_commas_nolinks ) );
		else
			result = result .. toString( context, src.part, options_commas );
		end
		result = result .. ' // ' .. toString( context, src.title, options_commas );
	else
		-- title only
 		if ( src.url ) then
			result = result .. wrapInUrl( src.url, toString( context, src.title, options_commas_nolinks ) );
		else
			result = result .. toString( context, src.title, options_commas );
		end
 	end
 
	if ( src.subtitle ) then
		result = result .. ": " .. toString( context, src.subtitle, options_commas );
	end
 
	if ( src.originaltitle ) then
		result = result .. ' = ' .. toString( context, src.originaltitle, options_commas );
	end
 
	if ( src.publication ) then
		if ( type( src.publication.title or '') ~= 'string' ) then error('type of src.publication.title is not string but ' .. type( src.publication.title ) ) end;
 
		result = result .. ' // ' .. toString( context, src.publication, options_commas_it_short );
		if ( src.publication.subtitle ) then
			result = result .. ': ' .. toString( context, src.publication.subtitle, options_commas_it_short );
		end
	end
 
	result = result .. '<span class="wef_low_priority_links">';
 
	if ( src.editor ) then
		local prefix = i18nEditors[ context.lang ] or i18nEditors[ i18nDefaultLanguage ];
		result = result .. ' / ' .. prefix .. toString( context, src.editor, options_commas );
	end
 
	if ( src.edition ) then
		result = result .. ' — ' .. toString( context, src.edition, options_commas );
	end
 
	if ( src.place or src.publisher or src.year ) then
		result = result .. ' — ';
		if ( src.place ) then
			result = result .. toString( context, src.place, options_commas_short );
			if ( src.publisher or src.year ) then
				result = result .. ': ';
			end
		end
		if ( src.publisher ) then
			result = result .. toString( context, src.publisher, options_commas_short );
			if ( src.year ) then
				result = result .. ', ';
			end
		end
		if ( src.year ) then
			result = result .. toString( context, src.year, options_commas );
		end
		result = result .. '.';
	end
 
 	if ( src.volume or src.issue ) then
 		result = result .. ' — ';
		if ( src.volume ) then
			local letter = i18nVolume[ context.lang ] or i18nVolume[ i18nDefaultLanguage ];
			result = result .. letter .. '&nbsp;' .. toString( context, src.volume, options_commas );
			if ( src.issue ) then
				local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
				result = result .. ', ' .. letter .. '&nbsp;' .. toString( context, src.issue, options_commas ) .. '.';
			else
				result = result .. '.';
			end
		else
			local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
			result = result .. letter .. '&nbsp;' .. toString( context, src.issue, options_commas ) .. '.';
		end
 	end
 
	if ( src.pages ) then
		local letter = i18nPages[ context.lang ] or i18nPages[ i18nDefaultLanguage ];
		result = result .. ' — ' .. letter .. '&nbsp;' .. toString( context, src.pages, options_commas )  .. '.';
	end
 
	if ( src.numberOfPages ) then
		local letter = i18nNumberOfPages[ context.lang ] or i18nNumberOfPages[ i18nDefaultLanguage ];
		result = result .. ' — ' .. toString( context, src.numberOfPages, options_commas ) .. '&nbsp;' .. letter;
	end
 
	if ( src.bookSeries ) then
		result = result .. ' — (' .. toString( context, src.bookSeries, options_commas )
 
	 	if ( src.bookSeriesVolume or src.bookSeriesIssue ) then
	 		result = result .. '; ';
			if ( src.bookSeriesVolume ) then
				local letter = i18nVolume[ context.lang ] or i18nVolume[ i18nDefaultLanguage ];
				result = result .. letter .. '&nbsp;' .. toString( context, src.bookSeriesVolume, options_commas );
				if ( src.bookSeriesIssue ) then
					local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
					result = result .. ', ' .. letter .. '&nbsp;' .. toString( context, src.bookSeriesIssue, options_commas );
				else
					result = result;
				end
			else
				local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
				result = result .. letter .. '&nbsp;' .. toString( context, src.bookSeriesIssue, options_commas );
			end
	 	end
 
		result = result .. ')';
	end
 
	if ( src.isbn ) then
		result = result .. ' — ISBN ' .. toString( context, src.isbn, options_commas );
	end
 
	if ( src.issn ) then
		result = result .. ' — ISSN ' .. toString( context, src.issn, options_issn );
	end
 
	if ( src.doi ) then
		result = result .. ' — ' .. toString( context, src.doi, options_doi );
	end
 
	if ( src.arxiv ) then
		result = result .. ' — ' .. toString( context, src.arxiv, options_arxiv );
	end
 
	if ( src.sourceId ) then
		if ( src.type and src.sourceId ) then
			-- wrap into span to target from JS
			result = '<span class="wikidata_cite ' .. toString( context, src.type, options_citetypes ) .. '" data-entity-id="' .. getSingle( src.sourceId ) .. '">' .. result .. '</span>'
		else
			result = '<span class="wikidata_cite citetype_unknown" data-entity-id="' .. getSingle( src.sourceId ) .. '">' .. result .. '</span>'
		end
	end
 
	if ( src.accessdate ) then
			local date = getSingle( src.accessdate );
			local pattern = "(%-?%d+)%-(%d+)%-(%d+)T";
			local y, m, d = mw.ustring.match( date , pattern );
			y,m,d = tonumber(y),tonumber(m),tonumber(d);
			result = result .. " <small>Проверено " .. tostring(d) .. " " .. monthg[m]  .. " " .. tostring(y) .. ".</small>";
	end
 
	result = result .. '</span>';
 
    -- append invisible links to all elements used by source for tracking purposes
    local result = result .. '<div style="display:none">';
	for key, entity in pairs( context.cache ) do
		result = result .. '[[d:Track:' .. key .. ']]';
	end
    result = result ..'</div>'
 
	return {text = result, code = src.code};
end
 
function wrapInUrl( urls, text )
	local url = getSingle( urls );
	if ( string.sub( url, 1, 1 ) == ':' ) then
		return '[[' .. url .. '|' .. text .. ']]';
	else
		return '[' .. url .. ' ' .. text .. ']';
	end
end
 
function renderShortReference( src )
	context = {
		cache = {},
		lang = getSingle( src.lang ) or i18nDefaultLanguage;
	};
	src.title = src.title or '\'\'(unspecified title)\'\''
 
	local result = '[[#' .. PREFIX_CITEREF .. src.code .. '|';
	if ( src.author ) then
		result = result .. toString( context, src.author, options_authors_nolinks );
	else
		result = result .. toString( context, src.title, options_commas_it_nolinks );
	end
	result = result .. ']]'
 
	if ( src.year ) then
		result = result .. ', ' .. toString( context, src.year, options_commas );
	end
 
	if ( src.volume ) then
		local letter = i18nVolume[ context.lang ] or i18nVolume[ i18nDefaultLanguage ];
		result = result .. ' — ' .. letter .. '&nbsp;' .. toString( context, src.volume, options_commas ) .. '.';
	end
 
	if ( src.issue ) then
		local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
		result = result .. ' — ' .. letter .. '&nbsp;' .. toString( context, src.issue, options_commas ) .. '.';
	end
 
	if ( src.pages ) then
		local letter = i18nPages[ context.lang ] or i18nPages[ i18nDefaultLanguage ];
		result = result .. ' — ' .. letter .. '&nbsp;' .. toString( context, src.pages, options_commas )  .. '.';
	end
 
end
 
function getSingle( value )
	if ( not value ) then
		return;
	end
	if ( type( value ) == 'string' ) then
		return value;
	elseif ( type( value ) == 'table' ) then
		if ( value.id ) then
			return value.id;
		end
 
		for i, tableValue in pairs( value ) do
			return getSingle( tableValue );
		end
	end
 
	return '(unknown)';
end
 
function toString( context, value, options )
	if ( type( value ) == 'string' ) then
		return options.format( value );
	elseif ( type( value ) == 'table' ) then
		if ( value.id ) then
			-- this is link
			if ( type( value.label or '' ) ~= 'string' ) then mw.logObject( value ); error('label of table value is not string but ' .. type( value.label ) ) end
 
			if ( options.preferids ) then
				return options.format( value.id );
			else
				if ( options.nolinks ) then
					return options.format( value.label or mw.wikibase.label( value.id ) or '\'\'(untranslated title)\'\'' );
				else
					return options.format( renderLink( context, value.id, value.label, options ) );
				end
			end
		end
 
		local resultList = {};
		for i, tableValue in pairs( value ) do
			table.insert( resultList, toString( context, tableValue, options ) );
		end
 
		return mw.text.listToText( resultList, options.separator, options.conjunction);
	else
		return options.format( '(unknown type)' );
	end
 
	return '';
end
 
function renderLink( context, entityId, customTitle, options )
	if ( not entityId ) then error("entityId is not specified") end
	if ( type( entityId ) ~= 'string' ) then error('entityId is not string, but ' .. type( entityId ) ) end
	if ( type( customTitle or '' ) ~= 'string' ) then error('customTitle is not string, but ' .. type( customTitle ) ) end
 
	local title = customTitle;
 
	if ( isEmpty( title ) ) then
		local entity = getEntity( context, entityId );
 
		-- ISO 4
		if ( isEmpty( title ) ) then
			if ( entity.claims and entity.claims.P1160 ) then
				for _, claim in pairs( entity.claims.P1160 ) do
					if ( claim
							and claim.mainsnak
							and claim.mainsnak.datavalue
							and claim.mainsnak.datavalue.value
							and claim.mainsnak.datavalue.value.language == context.lang ) then
						title = claim.mainsnak.datavalue.value.text;
						mw.log('Got title of ' .. entityId .. ' from ISO 4 claim: «' .. title .. '»' )
						break;
					end
				end
			end
		end
 
		-- official name P1448
		-- short name P1813
		if ( isEmpty( title ) and options.short ) then
			if ( entity.claims and entity.claims.P1813 ) then
				for _, claim in pairs( entity.claims.P1813 ) do
					if ( claim
							and claim.mainsnak
							and claim.mainsnak.datavalue
							and claim.mainsnak.datavalue.value
							and claim.mainsnak.datavalue.value.language == context.lang ) then
						title = claim.mainsnak.datavalue.value.text;
						mw.log('Got title of ' .. entityId .. ' from short name claim: «' .. title .. '»' )
						break;
					end
				end
			end
		end
		-- person name P1559
		-- labels
		if ( isEmpty( title ) and entity.labels[ context.lang ] ) then
			title = entity.labels[ context.lang ].value;
			mw.log('Got title of ' .. entityId .. ' from label: «' .. title .. '»' )
		end
	end
 
	local actualText = title or '\'\'(untranslated)\'\'';
	local link = getElementLink( context, entityId, entity);
	return wrapInUrl( link, actualText );
end
 
function getElementLink( context, entityId, entity )
	-- fast sitelink lookup, not an expensive operation
	local link = mw.wikibase.sitelink( entityId )
	if ( link ) then return ':' .. link end
 
	if ( not entity and entityId ) then
		entity = getEntity( context, entityId )
	end
 
	if ( entity ) then
		-- link to entity in source context language
		local projectToCheck = context.lang .. 'wiki';
		if ( entity.sitelinks and entity.sitelinks[ projectToCheck ] ) then
			return ':' .. context.lang .. ':' .. entity.sitelinks[ projectToCheck ].title;
		end
	end
 
	if ( entityId ) then return ':d:' .. entityId end;
	-- if ( entityId ) then return 'https://tools.wmflabs.org/reasonator/?q=' .. entityId .. '&lang=uk' end;
	return nil;
end
 
function getPeopleAsAuthorWikitext( context, value, options )
	if ( type( value ) == 'string' ) then
		return personNameToAuthorName( value );
	elseif ( type( value ) == 'table' ) then
		if ( value.id ) then
			-- this is link
			if ( options.preferids ) then
				return value.id;
			else
				if ( options.nolinks ) then
					return getPersonNameAsAuthorLabel( context, value.id, value.label, options );
				else
					return getPersonNameAsAuthorWikitext( context, value.id, value.label, options );
				end
			end
		end
 
		local resultList = {};
		for i, tableValue in pairs( value ) do
			local nextWikitext = getPeopleAsAuthorWikitext( context, tableValue, options );
			if ( not isEmpty( nextWikitext ) ) then
				table.insert( resultList, nextWikitext );
				if ( #resultList == 4 ) then
					-- even 4 is too much, but we preserve 4th to mark that "it's more than 3"
					break;
				end
			end
		end
 
		local resultWikitext = '';
		for i, wikitext in pairs( resultList ) do
			if ( i == 4 ) then
				resultWikitext = resultWikitext .. ( i18nEtAl[ context.lang ] or i18nEtAlDefault );
				break;
			end
			if ( i ~= 1 ) then
				resultWikitext = resultWikitext .. ', ';
			end
			resultWikitext = resultWikitext .. wikitext;
		end
 
		return resultWikitext;
	end
 
	return options.format( '(unknown type)' );
end
 
function getPersonNameAsAuthorWikitext( context, entityId, customLabel, options )
	local personNameAsAuthor = getPersonNameAsAuthorLabel( context, entityId, customLabel, options);
	if ( personNameAsAuthor == nil ) then
		return nil;
	end
 
	local link = getElementLink( context, entityId, nil );
	return wrapInUrl( link, personNameAsAuthor );
end
 
function getPersonNameAsAuthorLabel( context, entityId, providedLabel, options )
	-- would custom label provided we don't need to check entity at all
	if ( not isEmpty( providedLabel ) ) then
		mw.log( 'Custom label provided for ' .. entityId );
		return personNameToAuthorName( providedLabel );
	end
 
	local entity = getEntity( context, entityId );
	if ( not entity ) then return '\'\'(entity ' .. entityId .. ' is missing)\'\'' end;
	if ( not isInstanceOf( entity, 'Q5' ) ) then
		mw.log( 'Entity ' .. entityId .. ' is not a person' );
		return nil;
	end
 
	local personName = nil;
	-- support only labels so far
	if ( entity.labels[ context.lang ] ) then
		personName = entity.labels[ context.lang ].value;
		mw.log('Got person name of ' .. entityId .. ' from label: «' .. personName .. '»' )
	end
 
	if ( isEmpty( personName ) ) then
		return '\'\'(not translated to ' .. context.lang .. ')\'\'';
	else
		return personNameToAuthorName( personName );
	end
end
 
function personNameToAuthorName( fullName )
	if ( not fullName ) then return fullName; end
 
	local f, i, o = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)\,%s(%a[%a\-]*)%s(%a[%a\-]*)%s*$' );
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Fa, I. O.» match' );
		return f .. '&nbsp;'
			.. mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;'
			.. mw.ustring.sub( o, 1, 1 ) .. '.';
	end
 
	local f1, f2, i = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a[%a\-]*)\,%s(%a[%a\-]*)%s*$' );
	if ( f1 ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Fa Fa, I» match' );
		return f1 .. '&nbsp;' .. f2 .. '&nbsp;'
			.. mw.ustring.sub( i, 1, 1 ) .. '.';
	end
 
	local i, o, f = mw.ustring.match( fullName, '^%s*(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I. O. Fa» match' );
		return f .. '&nbsp;' .. i .. '.&nbsp;' .. o .. '.';
	end
 
	local i1, i2, i3, f = mw.ustring.match( fullName, '^%s*(%a)\.%s(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I. O. ?. Fa» match' );
		return f .. '&nbsp;' .. i1 .. '.&nbsp;' .. i2 .. '.&nbsp;' .. i3 .. '.';
	end
 
    -- Joel J. P. C. Rodrigues
	local i1, i2, i3, i4, f = mw.ustring.match( fullName, '^%s*(%a)[%a\-]+%s(%a)\.%s(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I. O. ?. Fa» match' );
		return f .. '&nbsp;' .. i1 .. '.&nbsp;' .. i2 .. '.&nbsp;' .. i3 .. '.&nbsp;' .. i4 .. '.';
	end
 
	local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a)\.%s(%a[%a\-]*)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im O. Fa» match' );
		return f .. '&nbsp;' .. mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. o .. '.';
	end
 
	local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a[%a\-]*)%s(%a[%a\-]*)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im Ot Fa» match' );
		return f .. '&nbsp;' .. mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( o, 1, 1 ) .. '.';
	end
 
	local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]+)%s(%a[%a\-]+)%s+оглы%s+(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im Ot оглы Fa» match' );
		return f .. '&nbsp;' .. mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( o, 1, 1 ) .. '.';
	end
 
	local i, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]+)%s(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im Fa» match' );
		return f .. '&nbsp;' .. mw.ustring.sub( i, 1, 1 ) .. '.';
	end
 
	mw.log( 'Unmatched any pattern: «' .. fullName .. '»' );
	return fullName;
end
 
-- Expand special types of references when additional data could be found in OTHER entity properties
function expandSpecials( currentEntity, reference, data )
	if ( reference.snaks.P248
			and reference.snaks.P248[1]
			and reference.snaks.P248[1].datavalue
			and reference.snaks.P248[1].datavalue.value["numeric-id"]) then
		local sourceId = "Q" .. reference.snaks.P248[1].datavalue.value["numeric-id"];
		data.sourceId = sourceId;
 
		-- Gemeinsame Normdatei -- specified by P227
		if ( sourceId == 'Q36578' ) then
			appendSnaks( currentEntity.claims, 'P227', data, 'part', { format = function( gnd ) return 'Record #' .. gnd; end } );
			appendSnaks( currentEntity.claims, 'P227', data, 'url', { format = function( gnd ) return 'http://d-nb.info/gnd/' .. gnd .. '/'; end } );
			data.year = '2012—2016'
			expandSpecialsQualifiers( currentEntity, 'P227', data );
		end
 
		-- BNF -- specified by P268
		if ( sourceId == 'Q15222191' ) then
			appendSnaks( currentEntity.claims, 'P268', data, 'part', { format = function( id ) return 'Record #' .. id; end } );
			appendSnaks( currentEntity.claims, 'P268', data, 'url', { format = function( id ) return 'http://catalogue.bnf.fr/ark:/12148/cb' .. id; end } );
			expandSpecialsQualifiers( currentEntity, 'P268', data );
		end
 
		-- Union List of Artist Names -- specified by P245
		if ( sourceId == 'Q2494649' ) then
			appendSnaks( currentEntity.claims, 'P245', data, 'url', { format = function( id ) return 'http://www.getty.edu/vow/ULANFullDisplay?find=&role=&nation=&subjectid=' .. id end } );
			expandSpecialsQualifiers( currentEntity, 'P245', data );
		end
 
		-- imdb.com -- specified by P345
		if ( sourceId == 'Q37312' ) then
			appendSnaks( currentEntity.claims, 'P345', data, 'part', { format = function( id ) return 'Person Profile' end } );
			appendSnaks( currentEntity.claims, 'P345', data, 'url', { format = function( id ) return 'http://www.imdb.com/name/' .. id .. '/' end } );
			expandSpecialsQualifiers( currentEntity, 'P345', data );
		end
 
		-- wtatennis.com -- specified by P597
		if ( sourceId == 'Q14580067' ) then
			appendSnaks( currentEntity.claims, 'P597', data, 'part', { format = function( id ) return 'Player Profile' end } );
			appendSnaks( currentEntity.claims, 'P597', data, 'url', { format = function( id ) return 'http://www.wtatennis.com/players/player/' .. id end } );
			expandSpecialsQualifiers( currentEntity, 'P597', data );
		end
 
		-- Find a Grave -- specified by P535
		if ( sourceId == 'Q63056' ) then
			appendSnaks( currentEntity.claims, 'P535', data, 'url', { format = function( id ) return 'http://www.findagrave.com/cgi-bin/fg.cgi?page=gr&GRid=' .. id; end } );
			expandSpecialsQualifiers( currentEntity, 'P535', data );
		end
 
		-- Gran Enciclopèdia Catalana -- specified by P1296
		if ( sourceId == 'Q2664168' ) then
			appendSnaks( currentEntity.claims, 'P1296', data, 'url', { format = function( id ) return 'http://www.enciclopedia.cat/enciclop%C3%A8dies/gran-enciclop%C3%A8dia-catalana/EC-GEC-' .. id .. '.xml'; end } );
			expandSpecialsQualifiers( currentEntity, 'P1296', data );
		end
 
		-- Encyclopædia Britannica online -- specified by P1417
		if ( sourceId == 'Q5375741' ) then
			appendSnaks( currentEntity.claims, 'P1417', data, 'url', { format = function( id ) return 'http://global.britannica.com/' .. id; end } );
			expandSpecialsQualifiers( currentEntity, 'P1417', data );
		end
 
		-- do we have appropriate record in P1433 ?
		local claims = findClaimsByValue( currentEntity, 'P1343', sourceId );
		if ( claims and #claims ~= 0 ) then
			for _, claim in pairs( claims ) do
				populateDataFromClaims( sourceId, claim.qualifiers, data );
			end
		end
 
		-- Electronic Jewish Encyclopedia (Elektronnaja Evrejskaja Entsiklopedia) -- specified by P1438
		if ( sourceId == 'Q1967250' ) then
			appendSnaks( currentEntity.claims, 'P1438', data, 'url', { format = function( id ) return 'http://www.eleven.co.il/article/' .. id; end } );
			expandSpecialsQualifiers( currentEntity, 'P1438', data );
		end
 
		-- sports-reference.com -- specified by P1447
		if ( sourceId == 'Q18002875' ) then
			appendSnaks( currentEntity.claims, 'P1447', data, 'url', { format = function( id ) return 'http://www.sports-reference.com/olympics/athletes/' .. id .. '.html'; end } );
			expandSpecialsQualifiers( currentEntity, 'P1447', data );
		end
 
		--  Dizionario Biografico degli Italiani -- specified by P1986
		if ( sourceId == 'Q1128537' ) then
			if ( not data.lang ) then data.lang = { id = 'Q652' } end;
			appendSnaks( currentEntity.claims, 'P1986', data, 'url', { format = function( id ) return 'http://www.treccani.it/enciclopedia/' .. id .. '_%28Dizionario_Biografico%29/' end } );
			expandSpecialsQualifiers( currentEntity, 'P1986', data );
		end
	end
end
 
function expandSpecialsQualifiers( entity, propertyId, data )
	if ( entity.claims ~= nil and entity.claims[propertyId] ~= nil ) then
		for _, claim in pairs( entity.claims[propertyId] ) do
			populateDataFromClaims( nil, claim.qualifiers, data );
		end
	end
end
 
function findClaimsByValue( entity, propertyId, value )
	local result = {};
	if ( entity and entity.claims and entity.claims[propertyId] ) then
		for i, claim in pairs( entity.claims[propertyId] ) do
			if ( claim.mainsnak and claim.mainsnak.datavalue ) then
				local datavalue = claim.mainsnak.datavalue;
				if ( datavalue.type == "string" and datavalue.value == value 
					or datavalue.type == "wikibase-entityid" and datavalue.value["entity-type"] == "item" and tostring( datavalue.value["numeric-id"] ) == mw.ustring.sub( value, 2 ) ) then
					table.insert( result, claim );
				end
			end
		end
	end
	return result;
end
 
function appendSnaks( allSnaks, snakPropertyId, result, property, options )
	-- do not populate twice
	if ( result[property] ) then return result end;
	if ( not allSnaks ) then return result; end;
 
	local selectedSnakes = allSnaks[ snakPropertyId ];
	if ( not selectedSnakes ) then return result; end;
 
	local hasPreferred = false;
	for k, snak in pairs( selectedSnakes ) do
		if ( snak and snak.mainsnak and snak.mainsnak.datavalue and snak.rank == 'preferred' ) then
			--it's a preferred claim
			appendImpl( snak.mainsnak.datavalue, snak.qualifiers, result, property, options );
			hasPreferred = true;
		end
	end
	if ( hasPreferred ) then return result; end;
 
	for k, snak in pairs( selectedSnakes ) do
		if ( snak and snak.mainsnak and snak.mainsnak.datavalue and snak.rank ~= 'deprecated' ) then
			--it's a claim
			appendImpl( snak.mainsnak.datavalue, snak.qualifiers, result, property, options );
		elseif ( snak and snak.datavalue ) then
			-- it's a snak
			appendImpl( snak.datavalue, nil, result, property, options );
		end
	end
end
 
function appendQualifiers( claims, qualifierPropertyId, result, resultProperty, options )
	-- do not populate twice
	if ( not claims ) then return result end;
	if ( result[resultProperty] ) then return result end;
 
	for i, claim in pairs( claims ) do
		if ( claim.qualifiers and claim.qualifiers[ qualifierPropertyId ] ) then
			for k, qualifier in pairs( claim.qualifiers[ qualifierPropertyId ] ) do
				if ( qualifier and qualifier.datavalue ) then
					appendImpl( qualifier.datavalue, nil, result, resultProperty, options );
				end
			end
		end
	end
end
 
function appendImpl( datavalue, qualifiers, result, property, options )
	if ( datavalue.type == 'string' ) then
		local statedAs = getSingleStringQualifierValue(qualifiers, 'P1932');
		local value;
		if ( statedAs ) then
			value = statedAs;
		else
			value = datavalue.value;
			if ( options.format ) then
				value = options.format( value );
			end
		end
		appendImpl_toTable( result, property );
		table.insert( result[property], value);
	elseif ( datavalue.type == 'monolingualtext' ) then
		local value = datavalue.value.text;
		if ( options.format ) then
			value = options.format( value );
		end
		appendImpl_toTable( result, property );
		table.insert( result[property], value);
	elseif ( datavalue.type == 'quantity' ) then
		local value = datavalue.value.amount;
		if ( mw.ustring.sub( value , 1, 1 ) == '+' ) then
			value = mw.ustring.sub( value , 2 );
		end
		if ( options.format ) then
			value = options.format( value );
		end
		appendImpl_toTable( result, property );
		table.insert( result[property], value);
	elseif ( datavalue.type == 'wikibase-entityid' ) then
		local value = datavalue.value;
		appendImpl_toTable( result, property );
		local toInsert = {
			id = 'Q' .. value["numeric-id"],
			label = getSingleStringQualifierValue(qualifiers, 'P1932') -- stated as
		};
		table.insert( result[property], toInsert );
	elseif datavalue.type == 'time' then
		local value = datavalue.value;
		if ( options.format ) then
			value = options.format( value );
		end
		appendImpl_toTable( result, property );
		table.insert( result[property], tostring( value.time ));
    end 
end
 
function appendImpl_toTable(result, resultProperty)
	if ( not result[resultProperty] ) then
		result[resultProperty] = {};
	elseif ( type( result[resultProperty] ) == 'string' or ( type( result[resultProperty] ) == 'table' and type( result[resultProperty].id ) == 'string' ) ) then
		result[resultProperty] = { result[resultProperty] };
	end
end
 
function getSingleStringQualifierValue( allQualifiers, qualifierPropertyId )
	if ( not allQualifiers ) then return end
	if ( not allQualifiers[qualifierPropertyId] ) then return end
 
	for k, qualifier in pairs( allQualifiers[qualifierPropertyId] ) do
		if ( qualifier and qualifier.datatype == 'string'
				and qualifier.datavalue and qualifier.datavalue.type == 'string' and not isEmpty( qualifier.datavalue.value ) ) then
			return qualifier.datavalue.value;
		end
	end
 
	return;
end
 
function expandPublication( context, sourceEntity, data )
	local publication = data.publication;
 
	-- use only first one
	if ( type( publication ) == 'table' and publication[1] and publication[1].id ) then
		data.publication = publication[1];
		publication = data.publication;
	end
 
	if ( not publication ) then return end;
	if ( not publication.id ) then return end;
 
	if ( sourceEntity ) then
		-- do we have appropriate record in P1433 ?
		local claims = findClaimsByValue( sourceEntity, 'P1433', publication.id );
		if ( claims and #claims ~= 0 ) then
			for _, claim in pairs( claims ) do
				populateDataFromClaims( sourceEntity, claim.qualifiers, data );
				break;
			end
		end
	end
 
	local titleWerePresent = not (not data.title);
	local pubEntity = getEntity( context, publication.id );
	populateSourceDataImpl( pubEntity, data );
	if ( titleWerePresent and isEmpty( data.publication.label ) ) then
		appendSnaks( pubEntity.claims, 'P1160', data, 'publication-title', {} ); -- obsolete
		data.publication.label = getSingle( data['publication-title'] );
	end
	if ( titleWerePresent and isEmpty( data.publication.label ) ) then
		appendSnaks( pubEntity.claims, 'P357', data, 'publication-title', {} ); -- obsolete
		appendSnaks( pubEntity.claims, 'P1476', data, 'publication-title', {} );
		appendSnaks( pubEntity.claims, 'P1680', data, 'publication-subtitle', {} );
		data.publication.label = getSingle( data['publication-title'] );
		data.publication.subtitle = getSingle( data['publication-subtitle'] );
	end
 
	if ( pubEntity.claims and pubEntity.claims.P361 ) then
		for c, claim in pairs( pubEntity.claims.P361 ) do
			if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value["numeric-id"] ) then
				local possibleBookSeriesEntityId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
				local possibleBookSeriesEntity = getEntity( context, possibleBookSeriesEntityId );
				if ( isInstanceOf( possibleBookSeriesEntity, 'Q277759' ) ) then
					appendImpl_toTable( data, 'bookSeries' );
					table.insert( data.bookSeries, { id = possibleBookSeriesEntityId } );
 
					appendQualifiers( { claim }, 'P478', data, 'bookSeriesVolume', {} );
					appendQualifiers( { claim }, 'P433', data, 'bookSeriesIssue', {} );
				end
			end
		end
	end
 
	expandBookSeries( context, data );
end
 
function expandBookSeries( context, data )
	local bookSeries = data.bookSeries;
	if ( not bookSeries ) then return end;
 
	-- use only first one
	if ( type( bookSeries ) == 'table' and bookSeries[1] and bookSeries[1].id ) then
		data.bookSeries = bookSeries[1];
		bookSeries = data.bookSeries;
	end
 
	if ( not bookSeries ) then return end;
	if ( not bookSeries.id ) then return end;
 
	local bookSeriesEntity = getEntity( context, bookSeries.id );
	appendSnaks( bookSeriesEntity.claims, 'P123', data, 'publisher', {} );
	appendSnaks( bookSeriesEntity.claims, 'P291', data, 'place', {} );
	appendSnaks( bookSeriesEntity.claims, 'P236', data, 'issn', {} );
end
 
function populateSourceDataImpl( entity, plainData )
	populateDataFromClaims( entity.id, entity.claims, plainData );
 
	local normativeTitle = getNormativeTitle( entity )
	if ( normativeTitle ) then
		local y, m, d = mw.ustring.match( getSingle( plainData.dateOfCreation ) , "(%-?%d+)%-(%d+)%-(%d+)T" );
		y,m,d = tonumber(y),tonumber(m),tonumber(d);
		local title = toString( { lang='uk' }, plainData.title, options_commas_nolinks );
		plainData.title = { normativeTitle .. " от&nbsp;" .. tostring(d) .. "&nbsp;" .. monthg[m]  .. " " .. tostring(y) .. "&nbsp;г. №&nbsp;" .. getSingle( plainData.docNumber ) .. ' «' .. title.. '»' }
	end
 
	if ( not plainData.title ) then
		if ( entity.labels and entity.labels.uk and entity.labels.uk.value ) then
			plainData.title = { entity.labels.uk.value };
		end
	end
 
	return plainData;
end
 
function populateDataFromClaims( entityId, claims, data )
	appendSnaks( claims, 'P50', data, 'author', {} );
	appendSnaks( claims, 'P2093', data, 'author', {} );
	appendSnaks( claims, 'P407', data, 'lang', {} );
	appendSnaks( claims, 'P364', data, 'lang', {} );
	appendSnaks( claims, 'P958', data, 'part', {} );
	if ( not data.title ) then
		if ( not isEmpty( entityId ) ) then
			local optionsAsLinks = { format = function( text ) return { id = entityId, label = text } end };
			appendSnaks( claims, 'P357', data, 'title', optionsAsLinks ); -- obsolete
			appendSnaks( claims, 'P1476', data, 'title', optionsAsLinks );
		else
			appendSnaks( claims, 'P357', data, 'title', {} ); -- obsolete
			appendSnaks( claims, 'P1476', data, 'title', {} );
		end
		appendSnaks( claims, 'P1680', data, 'subtitle', {} );
	end
	appendSnaks( claims, 'P953', data, 'url', {} );
	appendSnaks( claims, 'P1065', data, 'url', {} );
	appendSnaks( claims, 'P854', data, 'url', {} );
	-- temp disable, use only for current entity, see Q22338048 for example of incorrect work
	-- appendSnaks( claims, 'P856', data, 'url', {} );
	appendSnaks( claims, 'P1433', data, 'publication', {} );
	appendSnaks( claims, 'P393', data, 'edition', {} );
	appendSnaks( claims, 'P123', data, 'publisher', {} );
	appendSnaks( claims, 'P291', data, 'place', {} );
	appendSnaks( claims, 'P304', data, 'pages', {} );
	appendSnaks( claims, 'P1104', data, 'numberOfPages', {} );
	appendSnaks( claims, 'P478', data, 'volume', {} );
	appendSnaks( claims, 'P433', data, 'issue', {} );
	appendSnaks( claims, 'P571', data, 'dateOfCreation', {} );
	appendSnaks( claims, 'P577', data, 'dateOfPublication', {} );
	appendSnaks( claims, 'P212', data, 'isbn', {} ); -- ISBN-13
	appendSnaks( claims, 'P957', data, 'isbn', {} ); -- ISBN-10
	appendSnaks( claims, 'P236', data, 'issn', {} );
 
    -- web
	-- appendSnaks( claims, 'P813', data, 'accessdate', {} );
 
    -- docs
	appendSnaks( claims, 'P1545', data, 'docNumber', {} );
 
	-- other
	appendSnaks( claims, 'P31', data, 'type', {} );
 
	appendSnaks( claims, 'P818', data, 'arxiv', {} );
	appendSnaks( claims, 'P356', data, 'doi', {} );
	-- JSTOR
	appendSnaks( claims, 'P888', data, 'url', { format = function( id ) return 'http://www.jstor.org/stable/' .. id end } );
 
	return src;
end
 
function p.renderSource( frame )
	p.currentFrame = frame;
 
	local arg = frame.args[1];
	local refAnchor = frame.args['ref'];
	local refAnchorYear = frame.args['ref-year'];
	local args = {};
	args.refAnchor = frame.args['ref'];
	args.refAnchorYear = frame.args['ref-year'];
	args.part = frame.args['part'];
	args.pages = frame.args['pages'];
 
	return p.renderSourceImpl( mw.text.trim( arg ), args );
end
 
function copyArgsToSnaks( args, snaks )
	if ( not isEmpty( args.part ) ) then snaks.P958 = { toStringSnak( 'P958', tostring( args.part ) ) } end
	if ( not isEmpty( args.pages ) ) then snaks.P304 = { toStringSnak( 'P304', tostring( args.pages ) ) } end
	if ( not isEmpty( args.issue ) ) then snaks.P433 = { toStringSnak( 'P433', tostring( args.issue ) ) } end
	if ( not isEmpty( args.volume ) ) then snaks.P478 = { toStringSnak( 'P478', tostring( args.volume ) ) } end
	if ( not isEmpty( args.url ) ) then snaks.P953 = { toUrlSnak( 'P953', tostring( args.url ) ) } end
end
 
function p.renderSourceImpl( entityId, args )
	args = args or {};
 
	local snaks = {};
	snaks.P248 = { toWikibaseEntityIdSnak( 'P248', entityId ) };
	copyArgsToSnaks( args, snaks );
 
	local rendered = renderReferenceImpl( mw.wikibase.getEntity(), { snaks = snaks }, args.refAnchor, args.refAnchorYear );
	if ( rendered ) then return rendered.text end;
end
 
function p.renderReference( frame, currentEntity, reference )
	p.currentFrame = frame;
 
	-- template call
	if ( frame and not currentEntity and not reference ) then
		local args = frame.args;
		if ( #frame.args == 0 ) then
			args = frame:getParent().args;
		end
 
		local snaks = {};
 
		if ( args[1] ) then
			snaks.P248 = { toWikibaseEntityIdSnak( "P248", args[1] ) };
		end
		copyArgsToSnaks( args, snaks );
 
		currentEntity = mw.wikibase.getEntity();
		reference = { snaks = snaks };
	end
 
	local rendered = renderReferenceImpl( currentEntity, reference );
 
	if ( not rendered ) then
		return '';
	end
 
	local result;
	local code = rendered.code or rendered.text;
	result = frame:extensionTag( 'ref', rendered.text, {name = code} ) .. '[[Категорія:Статті з джерелами з Вікіданих]]';
 
	return result;
end
 
function renderReferenceImpl( currentEntity, reference, refAnchor, refAnchorYear )
	if ( not reference.snaks ) then
		return nil;
	end
 
	-- контекст, содержит также кеш элементов
	local context = {
		cache = {},
	}
 
	-- данные в простом формате, согласованном с модулями формирования библиографического описания
	local data = {};
 
    -- забрать данные из reference
    populateDataFromClaims( nil, reference.snaks, data )
 
	-- update ref name with ref-specific properties
	if ( data.code ) then
		if ( data.part ) then data.code = data.code .. '-' .. getSingle( data.part ) end
		if ( data.pages ) then data.code = data.code .. '-' .. getSingle( data.pages ) end
		if ( data.volume ) then data.code = data.code .. '-' .. getSingle( data.volume ) end
		if ( data.issue ) then data.code = data.code .. '-' .. getSingle( data.issue ) end
		if ( data.url ) then data.code = data.code .. '-' .. getSingle( data.url ) end
	end
 
	expandSpecials( currentEntity, reference, data );
 
	local sourceEntity = nil;
	if ( data.sourceId ) then
		sourceEntity = getEntity( context, data.sourceId );
		if ( sourceEntity ) then
			populateSourceDataImpl( sourceEntity, data );
		end
	end
 
	if ( data.publication ) then
		expandPublication( context, sourceEntity, data );
	end
 
	if ( next( data ) == nil ) then
		return nil;
	end
 
	local rendered;
	if ( p.short ) then
		rendered = renderShortReference( data );
		if ( mw.ustring.len( rendered.text ) == 0 ) then
			return nil;
		end
 
	else
		rendered = renderSource( context, data );
		if ( mw.ustring.len( rendered.text ) == 0 ) then
			return nil;
		end
 
		if ( refAnchor ) then
			local anchorValue = 'CITEREF' .. refAnchor .. ( coalesce( refAnchorYear, data.year ) or '' );
			rendered.text = '<span class="citation" id="' .. mw.uri.anchorEncode( anchorValue ) .. '">' .. rendered.text .. '</span>';
		end
	end
 
	return rendered;
end
 
function getNormativeTitle( entity )
	if ( not entity or not entity.claims or not entity.claims.P31 ) then
		return;
	end
 
	for _, claim in pairs( entity.claims.P31 ) do
		if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value["numeric-id"] ) then
			local classId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
			local title = nil;
			if ( title ) then
				return title;
			end
		end
	end
 
	return;
end
 
local LANG_CACHE = 	{
	Q150	= 'fr',
	Q188	= 'de',
	Q1321	= 'es',
	Q1860	= 'en',
	Q652	= 'it'
}
 
function getLangCode( langEntityId )
	if ( not langEntityId ) then
		return;
	end
 
	-- small optimization
	local cached = LANG_CACHE[ langEntityId ];
	if ( cached ) then return cached; end
 
	local langEntity = mw.wikibase.getEntity( langEntityId );
	if ( not langEntity ) then
		mw.log( '[getLangCode] Missing entity ' .. langEntityId );
	else
		if ( langEntity.claims and langEntity.claims.P424 ) then
			for _, claim in pairs( langEntity.claims.P424 ) do
				if ( claim
						and claim.mainsnak
						and claim.mainsnak.datavalue
						and claim.mainsnak.datavalue.value ) then
					return '' .. claim.mainsnak.datavalue.value;
				end
			end
		end
	end
 
	return;
end
 
function preprocessPlaces( data, lang )
	if ( not data.place ) then
		return;
	end;
 
	local newPlaces = {};
	for index, place in pairs( data.place ) do
		if ( place.id ) then
			local newPlaceStr = getPlaceName(lang, place.id)
			if ( newPlaceStr ) then
				newPlaces[index] = newPlaceStr;
			else
				newPlaces[index] = place;
			end
		else
			newPlaces[index] = place;
		end
	end
	data.place = newPlaces;
end
 
function getPlaceName( lang, placeId )
	return nil;
end
 
function toTextWithTip( text, tip )
	return '<span title="' .. tip .. '" style="border-bottom: 1px dotted; cursor: help; white-space: nowrap">' .. text .. '</span>';
end
 
return p;

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

Відвідайте інші вікіпроекти на Вікія!

Випадкова вікі