Модуль:Sources

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация

Используемые параметры Викиданных

Свойство Комментарий
автор (P50)
краткое имя автора (P2093)
язык произведения или названия (P407)
язык оригинала (P364)
раздел, стих или параграф (P958) используется для указания названия статьи в энциклопедии
название (P1476) если требуется переопределить название из метки элемента
подзаголовок (P1680)
доступен по URL (P953)
архивный URL (P1065)
URL-ссылка на источник (P854)
опубликовано в (P1433)
номер издания (P393)
издатель (P123)
место публикации (P291)
редактор (P98)
страницы (P304)
количество страниц (P1104)
том (P478)
выпуск (P433)
дата основания/создания/возникновения (P571)
дата публикации (P577)
ISBN-13 (P212)
ISBN-10 (P957)
ISSN (P236)
порядковый номер (P1545)
идентификатор arXiv (P818)
JSTOR (P888)

Тесты [ править ]

5 tests failed.

test_Sources:

Text Expected Actual
N {{#invoke:Sources | renderSource | Q20750516}} Указ Президента Российской Федерации от 15 января 1992 г. № 23 «О Генеральном директоре Агентства федеральной безопасности Российской Федерации и Министре внутренних дел Российской Федерации» — 1992. президент Российской Федерации Указ Президента Российской Федерации от 15 января 1992 г. № 23 «О Генеральном директоре Агентства федеральной безопасности Российской Федерации и Министре внутренних дел Российской Федерации» — 1992.
N {{#invoke:Sources | renderSource | Q21683979}} Advances in Cryptology — EUROCRYPT 2004: International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004. Proceedings / C. Cachin, J. L. CamenischInterlaken: Springer-Verlag Berlin Heidelberg, 2004. — 630 p. — (Lecture Notes in Computer Science; Vol. 3027) — ISBN 978-3-540-21935-4 — ISSN 0302-9743doi:10.1007/b97182 Advances in Cryptology — EUROCRYPT 2004: International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004. Proceedings // Lecture Notes in Computer Science / C. Cachin, J. L. CamenischInterlaken: Springer Science+Business Media, 2004. — 630 p. — (Lecture Notes in Computer Science; Vol. 3027) — ISBN 978-3-540-21935-4 — ISSN 0302-9743doi:10.1007/B97182
N {{#invoke:Sources | renderSource | Q21683981}} Nguyen P. Q. Can We Trust Cryptographic Software? Cryptographic Flaws in GNU Privacy Guard v1.2.3 // Advances in Cryptology — EUROCRYPT 2004: International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004. Proceedings / C. Cachin, J. L. CamenischInterlaken: Springer-Verlag Berlin Heidelberg, 2004. — P. 555–570. — 630 p. — (Lecture Notes in Computer Science; Vol. 3027) — ISBN 978-3-540-21935-4 — ISSN 0302-9743doi:10.1007/978-3-540-24676-3_33 Nguyen P. Q. Can We Trust Cryptographic Software? Cryptographic Flaws in GNU Privacy Guard v1.2.3 // Advances in Cryptology — EUROCRYPT 2004: International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004. Proceedings / C. Cachin, J. L. CamenischInterlaken: Springer Science+Business Media, 2004. — P. 555–570. — 630 p. — (Lecture Notes in Computer Science; Vol. 3027) — ISBN 978-3-540-21935-4 — ISSN 0302-9743doi:10.1007/978-3-540-24676-3_33
✔ {{#invoke:Sources | renderSource | Q21725400}} Eichenauer J., Lehn J. A non-linear congruential pseudo random number generator // Statistische HefteSpringer Berlin Heidelberg, 1986. — Vol. 27, Iss. 1. — P. 315–326. — ISSN 0932-5026doi:10.1007/BF02932576 Eichenauer J., Lehn J. A non-linear congruential pseudo random number generator // Statistische HefteSpringer Berlin Heidelberg, 1986. — Vol. 27, Iss. 1. — P. 315–326. — ISSN 0932-5026doi:10.1007/BF02932576
N {{#invoke:Sources | renderSource | Q21725116}} Menezes A. J., Oorschot P. v., Vanstone S. A. Handbook of Applied CryptographyCRC Press, 1996. — 816 p. — (Discrete Mathematics and Its Applications) — ISBN 0-8493-8523-7 Menezes A. J., Oorschot P. v., Vanstone S. A. Handbook of Applied CryptographyCRC Press, 1996. — 816 p. — (Discrete Mathematics and Its Applications) — ISBN 978-0-8493-8523-0
N {{#invoke:Sources | renderSource | Q27450585}} Введение в криптографию / под ред. В. В. ЯщенкоМ.: МЦНМО, 2000. — 271 с. — ISBN 5-900916-26-X Введение в криптографию / под ред. В. В. ЯщенкоМ.: МЦНМО, 2000. — 271 с. — ISBN 978-5-900916-26-2


Генерирует сноски и ссылки на источники.


local p = {};
local u = require('Module:Sources-utils')

local i18nDefaultLanguage = 'ru';

local i18nEtAlDefault = ' et al.';
local i18nEtAl = {
	ru	= ' и др.',
}

local i18nEditors = {
	fr	= '',
	de	= 'Hrsg.: ',
	es	= '',
	en	= '',
	it	= '',
	ru	= 'под ред. ',
}

local i18nVolume = {
    de  = 'Vol.',
	fr	= 'Vol.',
	es	= 'Vol.',
	en	= 'Vol.',
	it	= 'Vol.',
	ru	= 'Т.',
}

local i18nIssue = {
	en	= 'Iss.',
	ru	= 'вып.',
}

local i18nPages = {
	fr = 'P.',
	de = 'S.',
	es = 'P.',
	en = 'P.',
	it = 'P.',
	ru = 'С.',
}

local i18nNumberOfPages = {
	en = 'p.',
	ru = 'с.',
}

local i18nTirage = {
	en	= 'ed. size: %d',
	ru	= '%d экз.',
}


local monthg = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', "сентября", "октября", "ноября", "декабря"};

local PREFIX_CITEREF = "CITEREF_";

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 };

local options_commas_authors = { separator = ', ', conjunction = ', ', format = personNameToAuthorName, nolinks = false, preferids = false };
local options_commas_responsible = { separator = ', ', conjunction = ', ', format = personNameToResponsibleName, nolinks = false, preferids = false };

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_pmid = { separator = '; ', conjunction = '; ', format = function( pmid ) return '[https://www.ncbi.nlm.nih.gov/pubmed/?term=' .. pmid .. ' PMID:' .. pmid .. ']' end, nolinks = true, preferids = false };

function renderSource( context, src )
	options_commas_authors.format = personNameToAuthorName;
	options_commas_responsible.format = personNameToResponsibleName;

	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 = getPeopleAsWikitext( context, src.author, options_commas_authors );
	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 .. getPeopleAsWikitext( context, src.editor, options_commas_responsible );
	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 ];
		local strPages = toString( context, src.pages, options_commas );
		strPages = mw.ustring.gsub( strPages, '[-—]', '–' );
		result = result .. ' — ' .. letter .. '&nbsp;' .. strPages .. '.';
	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.tirage ) then
		local tirageTemplate = i18nTirage[ context.lang ] or i18nTirage[ i18nDefaultLanguage ];
		result = result .. ' — ' .. toString( context, src.tirage, { separator = '; ', conjunction = ';', format = function( data ) return mw.ustring.format(tirageTemplate, data) end } );
	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.pmid ) then
		result = result .. ' — ' .. toString( context, src.pmid, options_pmid );
	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 .. '<a href="https://wikidata.org' ..  mw.uri.localUrl('Track:' .. key).path .. '"></a>';
	end
    result = result ..'</div>'

	return {text = result, code = src.code};
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 getPeopleAsWikitext( 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 ( options.preferids ) then
				return value.id;
			else
				if ( options.nolinks ) then
					return getPersonNameAsLabel( context, value.id, value.label, options );
				else
					return getPersonNameAsWikitext( context, value.id, value.label, options );
				end
			end
		end

		local resultList = {};
		for i, tableValue in pairs( value ) do
			local nextWikitext = getPeopleAsWikitext( 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 getPersonNameAsWikitext( context, entityId, customLabel, options )
	local personName = getPersonNameAsLabel( context, entityId, customLabel, options);
	if ( personName == nil ) then
		return nil;
	end

	local link = getElementLink( context, entityId, nil );
	return wrapInUrl( link, personName );
end

function getPersonNameAsLabel( 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 options.format( providedLabel );
	end

	local entity = getEntity( context, entityId );
	if ( not entity ) then return '\'\'(entity ' .. entityId .. ' is missing)\'\'' 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 ( not isInstanceOf( entity, 'Q5' ) ) then
		mw.log( 'Entity ' .. entityId .. ' is not a person' );
		return personName;
	end

	if ( isEmpty( personName ) ) then
		return '\'\'(not translated to ' .. context.lang .. ')\'\'';
	else
		return options.format( 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 i1, i2, i3, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a)\.%s(%a)\.%s(%a[%a\-]*)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im I. I. Fa» match' );
		return f .. '&nbsp;' .. mw.ustring.sub( i1, 1, 1 ) .. '.&nbsp;' .. i2 .. '.&nbsp;' .. i3 .. '.';
	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 i1, i2, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]+)%s(%a[%a\-]+)%s+de%s+(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I1 I2 de Fa» match' );
		return f .. '&nbsp;' .. mw.ustring.sub( i1, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( i2, 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

function personNameToResponsibleName( 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( 'personNameToResponsibleName: «' .. fullName .. '»: have «Fa, I. O.» match' );
		return mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( o, 1, 1 ) .. '.&nbsp;' .. f;
	end

	local f1, f2, i = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a[%a\-]*)\,%s(%a[%a\-]*)%s*$' );
	if ( f1 ) then
		mw.log( 'personNameToResponsibleName: «' .. fullName .. '»: have «Fa Fa, I» match' );
		return  mw.ustring.sub( i, 1, 1 ) .. '&nbsp;' .. f1 .. '&nbsp;' .. f2;
	end

	local i, o, f = mw.ustring.match( fullName, '^%s*(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
	if ( f ) then
		mw.log( 'v: «' .. fullName .. '»: have «I. O. Fa» match' );
		return i .. '.&nbsp;' .. o .. '.&nbsp;' .. f;
	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( 'personNameToResponsibleName: «' .. fullName .. '»: have «I. O. ?. Fa» match' );
		return  i1 .. '.&nbsp;' .. i2 .. '.&nbsp;' .. i3 .. '.&nbsp;' .. f;
	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( 'personNameToResponsibleName: «' .. fullName .. '»: have «I. O. ?. Fa» match' );
		return  i1 .. '.&nbsp;' .. i2 .. '.&nbsp;' .. i3 .. '.&nbsp;' .. i4 .. '.&nbsp;' .. f;
	end

	local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a)\.%s(%a[%a\-]*)%s*$');
	if ( f ) then
		mw.log( 'personNameToResponsibleName: «' .. fullName .. '»: have «Im O. Fa» match' );
		return mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. o .. '.&nbsp;' .. f;
	end

	local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a[%a\-]*)%s(%a[%a\-]*)%s*$');
	if ( f ) then
		mw.log( 'personNameToResponsibleName: «' .. fullName .. '»: have «Im Ot Fa» match' );
		return mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( o, 1, 1 ) .. '.&nbsp;' .. f;
	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( 'personNameToResponsibleName: «' .. fullName .. '»: have «Im Ot оглы Fa» match' );
		return  mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. mw.ustring.sub( o, 1, 1 ) .. '.&nbsp;' .. f;
	end

	local i, f = mw.ustring.match( fullName, '^%s*(%a[%a\-\']+)%s(%a[%a\-\']+)%s*$');
	if ( f ) then
		mw.log( 'personNameToResponsibleName: «' .. fullName .. '»: have «Im Fa» match' );
		return  mw.ustring.sub( i, 1, 1 ) .. '.&nbsp;' .. f;
	end

	mw.log( 'Unmatched any pattern: «' .. fullName .. '»' );
	return fullName;
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.part = frame.args['part'];
	args.parturl = frame.args['parturl'];
	args.pages = frame.args['pages'];
	args.refAnchor = frame.args['ref'];
	args.refAnchorYear = frame.args['ref-year'];
	args.url = frame.args['url'];

	return p.renderSourceImpl( mw.text.trim( arg ), args );
end

function p.renderSourceImpl( entityId, args )
	args = args or {};

	local snaks = {};
	snaks.P248 = { toWikibaseEntityIdSnak( 'P248', entityId ) };
	snaks.P805 = { toWikibaseEntityIdSnak( 'P805', 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] ) };
			snaks.P805 = { toWikibaseEntityIdSnak( "P805", 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;
	-- Про выбор алгоритма хеширования см. [[Модуль:Hash]]. Знак подчёркивания в начале позволяет
	-- исключить ошибку, когда имя сноски — чисто числовое значение, каковыми иногда бывают хеши.
	result = frame:extensionTag( 'ref', rendered.text, { name = '_' .. mw.hash.hashValue('fnv164', code) } ) .. '[[Category:Википедия:Статьи с источниками из Викиданных]]';

	return result;
end

function renderReferenceImpl( currentEntity, reference, refAnchor, refAnchorYear )
	if ( not reference.snaks ) then
		return nil;
	end

	-- контекст, содержит также кеш элементов
	local context = {
		cache = {},
	}

	-- данные в простом формате, согласованном с модулями формирования библиографического описания
	local data = {};

    -- забрать данные из reference
    populateDataFromClaims( context, 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( context, currentEntity, reference, data );

	local sourceEntity = nil;
	if ( data.sourceId ) then
		sourceEntity = getEntity( context, data.sourceId );
		if ( sourceEntity ) then
			populateSourceDataImpl( context, sourceEntity, data );
		end
	end

	if ( data.publication ) then
		expandPublication( context, sourceEntity, data );
	end

	expandBookSeries( context, data );

	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

return p;