Модуль:Sources/песочница
Поделись знанием:
Документация
Внимание! Это один из самых используемых модулей. Каждое его изменение создаёт дополнительную нагрузку на серверы проекта. Пожалуйста, убедитесь в адекватности и правильности ваших изменений, проверьте их на тестовых страницах. |
Прежде, чем вносить какие-либо изменения в данный модуль, просьба оттестировать их в /песочнице и проверить результат на странице с /контрольными примерами. Изменения могут быть внесены после этого в данный модуль всего одной правкой. |
Тесты
6 tests failed.
test_Sources:
Text | Expected | Actual | |
---|---|---|---|
{{#invoke:Sources | renderSource | Q20750516}} | Указ Президента Российской Федерации от 15 января 1992 г. № 23 «О Генеральном директоре Агентства федеральной безопасности Российской Федерации и Министре внутренних дел Российской Федерации» — 1992. | Ошибка Lua : attempt to index local 'entity' (a nil value). | |
{{#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. Camenisch — Interlaken: Springer Science+Business Media, 2004. — 628 p. — (Lecture Notes in Computer Science; Vol. 3027) — ISBN 978-3-540-21935-4 — ISSN [www.worldcat.org/issn/0302-9743 0302-9743] | Ошибка Lua : attempt to index local 'entity' (a nil value). | |
{{#invoke:Sources | renderSource | Q21683981}} | Nguyen P. Q. [www.di.ens.fr/~pnguyen/pub_Ng04.htm 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. Camenisch — Interlaken: Springer Science+Business Media, 2004. — P. 555—570. — 628 p. — (Lecture Notes in Computer Science; Vol. 3027) — ISBN 978-3-540-21935-4 — ISSN [www.worldcat.org/issn/0302-9743 0302-9743] — [dx.doi.org/10.1007/978-3-540-24676-3_33 doi:10.1007/978-3-540-24676-3_33] | Ошибка Lua : attempt to index local 'entity' (a nil value). | |
{{#invoke:Sources | renderSource | Q21725400}} | Eichenauer J., Lehn J. A non-linear congruential pseudo random number generator // Statistische Hefte — Springer Berlin Heidelberg, 1986. — Vol. 27, Iss. 1. — P. 315—326. — ISSN [www.worldcat.org/issn/0932-5026 0932-5026] — [dx.doi.org/10.1007/BF02932576 doi:10.1007/BF02932576] | Ошибка Lua : attempt to index local 'entity' (a nil value). | |
{{#invoke:Sources | renderSource | Q21725116}} | Menezes A. J., Oorschot P. v., Vanstone S. A. [www.cacr.math.uwaterloo.ca/hac/ Handbook of Applied Cryptography] — CRC Press, 1996. — 816 p. — (Discrete Mathematics and Its Applications) — ISBN 0-8493-8523-7 | Ошибка Lua : attempt to index local 'entity' (a nil value). | |
{{#invoke:Sources | renderSource | Q27450585}} | Введение в криптографию / под ред. В. В. Ященко — М.: МЦНМО, 2000. — 271 с. — ISBN 5-900916-26-X | Ошибка Lua : attempt to index local 'entity' (a nil value). |
Ошибка Lua на строке 151: attempt to index local 'entity' (a nil value).
Ошибка Lua на строке 151: attempt to index local 'entity' (a nil value).
[1]
Генерирует сноски и ссылки на источники.
Во избежание поломок страниц, использующих данный модуль, желательно экспериментировать в Песочнице для модулей.
local p = {}; local i18nDefaultLanguage = 'ru'; local i18nEditors = { fr = '', de = 'Hrsg.: ', es = '', en = '', it = '', ru = 'под ред. ', } local i18nEtAlDefault = ' et al.'; local i18nEtAl = { ru = ' и др.', } local i18nVolume = { 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 NORMATIVE_DOCUMENTS = { Q20754888 = 'Закон Российской Федерации', Q20754884 = 'Закон РСФСР', Q20873831 = 'Распоряжение Президента Российской Федерации', Q20873834 = 'Указ исполняющего обязанности Президента Российской Федерации', Q2061228 = 'Указ Президента Российской Федерации', } local monthg = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', "сентября", "октября", "ноября", "декабря"}; local PREFIX_CITEREF = "CITEREF_"; local options_arxiv = { separator = '; ', conjunction = '; ', format = function( id ) return '[arxiv.org/abs/' .. id .. ' arXiv:' .. id .. ']' end, nolinks = true, preferids = false }; local options_doi = { separator = '; ', conjunction = '; ', format = function( doi ) return '[dx.doi.org/' .. doi .. ' doi:' .. doi .. ']' 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_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 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( src ) mw.logObject( src ); local context = { cache = {}, lang = getLangCode( getSingle( src.lang ) ) or i18nDefaultLanguage, } preprocessPlaces( src, context.lang ); src.title = src.title or getSingle( src.url ) or '\'\'(unspecified title)\'\'' if ( src.entityId and not src.url ) then local entity = mw.wikibase.getEntity( src.entityId ); 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 = '\'\'' .. result .. '\'\' '; 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 ); if ( src.publication.subtitle ) then result = result .. ': ' .. toString( context, src.publication.subtitle, options_commas_it ); end end if ( src.editor ) then local prefix = i18nEditors[ context.lang ] or i18nEditors[ i18nDefaultLanguage ]; result = result .. ' / ' .. prefix .. toString( context, src.editor, 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 if ( src.publisher_stated_as ) then result = result .. toString( context, src.publisher_stated_as, options_commas ); else result = result .. toString( context, src.publisher, options_commas ); end 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 .. ' ' .. toString( context, src.volume, options_commas ); if ( src.issue ) then local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ]; result = result .. ', ' .. letter .. ' ' .. toString( context, src.issue, options_commas ) .. '.'; else result = result .. '.'; end else local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ]; result = result .. letter .. ' ' .. toString( context, src.issue, options_commas ) .. '.'; end end if ( src.pages ) then local letter = i18nPages[ context.lang ] or i18nPages[ i18nDefaultLanguage ]; result = result .. ' — ' .. letter .. ' ' .. 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 ) .. ' ' .. letter; end if ( src.issn ) then result = result .. ' — ISSN ' .. toString( context, src.issn, options_commas ); else if ( src.isbn ) then result = result .. ' — ISBN ' .. toString( context, src.isbn, options_commas ); end 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.entityId ) then if ( src.type and src.entityId ) then -- wrap into span to target from JS result = '<span class="wikidata_cite ' .. toString( context, src.type, options_citetypes ) .. '" data-entity-id="' .. getSingle( src.entityId ) .. '">' .. result .. '</span>' else result = '<span class="wikidata_cite citetype_unknown" data-entity-id="' .. getSingle( src.entityId ) .. '">' .. 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 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 .. ' ' .. toString( context, src.volume, options_commas ) .. '.'; end if ( src.issue ) then local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ]; result = result .. ' — ' .. letter .. ' ' .. toString( context, src.issue, options_commas ) .. '.'; end if ( src.pages ) then local letter = i18nPages[ context.lang ] or i18nPages[ i18nDefaultLanguage ]; result = result .. ' — ' .. letter .. ' ' .. 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 ); -- 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; 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 '[[' .. 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; 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 '[[' .. 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( customLabel ) ) then mw.log( 'Custom label provided for ' .. entityId ); return personNameToAuthorName( customLabel ); 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 .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. mw.ustring.sub( o, 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 .. ' ' .. i .. '. ' .. 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 .. ' ' .. i1 .. '. ' .. i2 .. '. ' .. 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 .. ' ' .. i1 .. '. ' .. i2 .. '. ' .. i3 .. '. ' .. 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 .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. 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 .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. 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 .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. 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 .. ' ' .. 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"]; -- Gemeinsame Normdatei -- specified by P227 if ( sourceId == 'Q36578' ) then appendSnaks( currentEntity.claims, 'P227', data, 'title', { format = function( gnd ) return 'Record #' .. gnd; end } ); appendSnaks( currentEntity.claims, 'P227', data, 'url', { format = function( gnd ) return 'd-nb.info/gnd/' .. gnd .. '/'; end } ); data.publication = { id = 'Q36578', label = 'Gemeinsame Normdatei' } data.year = '2012—2015' end -- BNF -- specified by P268 if ( sourceId == 'Q15222191' ) then appendSnaks( currentEntity.claims, 'P268', data, 'title', { format = function( id ) return 'Record #' .. id; end } ); appendSnaks( currentEntity.claims, 'P268', data, 'url', { format = function( id ) return 'catalogue.bnf.fr/ark:/12148/cb' .. id; end } ); expandSpecialsQualifiers( currentEntity, 'P268', data ); end -- Find a Grave -- specified by P535 if ( sourceId == 'Q63056' ) then appendSnaks( currentEntity.claims, 'P535', data, 'url', { format = function( id ) return 'www.findagrave.com/cgi-bin/fg.cgi?page=gr&GRid=' .. id; end } ); expandSpecialsQualifiers( currentEntity, 'P535', 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 'www.treccani.it/enciclopedia/' .. id .. '_%28Dizionario_Biografico%29/' end } ); expandSpecialsQualifiers( currentEntity, 'P1986', data ); end -- Union List of Artist Names -- specified by P245 if ( sourceId == 'Q2494649' ) then appendSnaks( currentEntity.claims, 'P245', data, 'url', { format = function( id ) return 'www.getty.edu/vow/ULANFullDisplay?find=&role=&nation=&subjectid=' .. id end } ); expandSpecialsQualifiers( currentEntity, 'P245', data ); end -- Gran Enciclopèdia Catalana -- specified by P1296 if ( sourceId == 'Q2664168' ) then appendSnaks( currentEntity.claims, 'P1296', data, 'url', { format = function( id ) return '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 'global.britannica.com/EBchecked/topic/' .. id .. '/'; end } ); expandSpecialsQualifiers( currentEntity, 'P1417', data ); end -- Electronic Jewish Encyclopedia (Elektronnaja Evrejskaja Entsiklopedia) -- specified by P1438 if ( sourceId == 'Q1967250' ) then appendSnaks( currentEntity.claims, 'P1438', data, 'url', { format = function( id ) return '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 'www.sports-reference.com/olympics/athletes/' .. id .. '.html'; end } ); expandSpecialsQualifiers( currentEntity, 'P1447', data ); end -- do we have appropriate record in P1343 ? local claims = findClaimsByValue( currentEntity, 'P1343', sourceId ); if ( claims and #claims ~= 0 ) then appendQualifiers( claims, 'P958', data, 'part', {} ); appendQualifiers( claims, 'P50', data, 'author', {} ); appendQualifiers( claims, 'P953', data, 'url', {} ); appendQualifiers( claims, 'P1065', data, 'url', {} ); appendQualifiers( claims, 'P854', data, 'url', {} ); appendQualifiers( claims, 'P357', data, 'title', {} ); -- obsolete appendQualifiers( claims, 'P1476', data, 'title', {} ); appendQualifiers( claims, 'P478', data, 'volume', {} ); end end end function expandSpecialsQualifiers( entity, propertyId, result ) if ( entity.claims ~= nil and entity.claims[propertyId] ~= nil ) then local claims = entity.claims[propertyId]; appendQualifiers( claims, 'P958', result, 'part', {} ); appendQualifiers( claims, 'P953', result, 'url', {} ); appendQualifiers( claims, 'P1065', result, 'url', {} ); appendQualifiers( claims, 'P854', result, 'url', {} ); appendQualifiers( claims, 'P357', result, 'title', {} ); -- obsolete appendQualifiers( claims, 'P1476', result, 'title', {} ); appendQualifiers( claims, 'P478', result, 'volume', {} ); appendQualifiers( claims, 'P433', result, 'issue', {} ); 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 ( allSnaks and allSnaks[ snakPropertyId ] ) then local hasPreferred = false; for k, snak in pairs( allSnaks[ snakPropertyId ] ) do if ( snak and snak.mainsnak and snak.mainsnak.datavalue and snak.rank == 'preferred' ) then --it's a preferred claim appendImpl( snak.mainsnak.datavalue, result, property, options ); hasPreferred = true; end end if ( hasPreferred ) then return; end for k, snak in pairs( allSnaks[ snakPropertyId ] ) do if ( snak and snak.mainsnak and snak.mainsnak.datavalue and snak.rank ~= 'deprecated' ) then --it's a claim appendImpl( snak.mainsnak.datavalue, result, property, options ); elseif ( snak and snak.datavalue ) then -- it's a snak appendImpl( snak.datavalue, result, property, options ); end end end end function appendQualifiers( claims, qualifierPropertyId, result, property, options ) -- do not populate twice if ( result[property] ) 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, result, property, options ); end end end end end function appendImpl( datavalue, result, property, options ) if ( datavalue.type == 'string' ) then local value = datavalue.value; if ( options.format ) then value = options.format( value ); end if ( not result[property] ) then result[property] = {}; elseif ( type( result[property] ) == 'string' or ( type( result[property] ) == 'table' and type( result[property].id ) == 'string' ) ) then result[property] = { result[property] }; end table.insert( result[property], value); elseif ( datavalue.type == 'monolingualtext' ) then local value = datavalue.value.text; if ( options.format ) then value = options.format( value ); end if ( not result[property] ) then result[property] = {}; elseif ( type( result[property] ) == 'string' or ( type( result[property] ) == 'table' and type( result[property].id ) == 'string' ) ) then result[property] = { result[property] }; end 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 if ( not result[property] ) then result[property] = {}; elseif ( type( result[property] ) == 'string' or ( type( result[property] ) == 'table' and type( result[property].id ) == 'string' ) ) then result[property] = { result[property] }; end table.insert( result[property], value); elseif ( datavalue.type == 'wikibase-entityid' ) then local value = datavalue.value; if ( not result[property] ) then result[property] = {}; elseif ( type( result[property] ) == 'string' or ( type( result[property] ) == 'table' and type( result[property].id ) == 'string' ) ) then result[property] = { result[property] }; end table.insert( result[property], { id = 'Q' .. value["numeric-id"] }); elseif datavalue.type == 'time' then local value = datavalue.value; if ( options.format ) then value = options.format( value ); end if ( not result[property] ) then result[property] = {}; elseif ( type( result[property] ) == 'string' or ( type( result[property] ) == 'table' and type( result[property].id ) == 'string' ) ) then result[property] = { result[property] }; end table.insert( result[property], tostring( value.time )); end end function expandDescribed ( sourceEntity, data ) local described = data.described; -- use only first one if ( type( described ) == 'table' and described[1] and described[1].id ) then data.described = described[1]; described = data.described; end data.publication = data.described; if ( described and described.id ) then if ( sourceEntity ) then -- do we have appropriate record in P1433 ? local claims = findClaimsByValue( sourceEntity, 'P1343', described.id ); if ( claims and #claims ~= 0 ) then appendQualifiers( claims, 'P958', data, 'part', {} ); appendQualifiers( claims, 'P50', data, 'author', {} ); appendQualifiers( claims, 'P953', data, 'url', {} ); appendQualifiers( claims, 'P1065', data, 'url', {} ); appendQualifiers( claims, 'P854', data, 'url', {} ); appendQualifiers( claims, 'P357', data, 'title', {} ); -- obsolete appendQualifiers( claims, 'P1476', data, 'title', {} ); appendQualifiers( claims, 'P478', data, 'volume', {} ); end end local titleWerePresent = not (not data.title); local desEntity = mw.wikibase.getEntity( described.id ); if ( desEntity ) then populateSourceDataImpl( desEntity, data ); if ( titleWerePresent ) then appendSnaks( desEntity.claims, 'P357', data, 'publication-title', {} ); -- obsolete appendSnaks( desEntity.claims, 'P1476', data, 'publication-label', {} ); appendSnaks( desEntity.claims, 'P1680', data, 'publication-subtitle', {} ); data.publication.label = getSingle( data['publication-title'] ); data.publication.label = getSingle( data['publication-label'] ); data.publication.subtitle = getSingle( data['publication-subtitle'] ); end end end end function expandPublication( 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 ( publication and publication.id ) then if ( sourceEntity ) then -- do we have appropriate record in P1433 ? local claims = findClaimsByValue( sourceEntity, 'P1433', publication.id ); if ( claims and #claims ~= 0 ) then appendQualifiers( claims, 'P958', data, 'part', {} ); appendQualifiers( claims, 'P953', data, 'url', {} ); appendQualifiers( claims, 'P1065', data, 'url', {} ); appendQualifiers( claims, 'P854', data, 'url', {} ); appendQualifiers( claims, 'P856', data, 'url', {} ); appendQualifiers( claims, 'P123', data, 'publisher', {} ); appendQualifiers( claims, 'P291', data, 'place', {} ); appendQualifiers( claims, 'P304', data, 'pages', {} ); appendQualifiers( claims, 'P1104', data, 'numberOfPages', {} ); appendQualifiers( claims, 'P478', data, 'volume', {} ); appendQualifiers( claims, 'P433', data, 'issue', {} ); appendQualifiers( claims, 'P571', data, 'dateOfCreation', {} ); appendQualifiers( claims, 'P577', data, 'dateOfPublication', {} ); appendQualifiers( claims, 'P212', data, 'isbn', {} ); -- ISBN-13 appendQualifiers( claims, 'P957', data, 'isbn', {} ); -- ISBN-10 end end local titleWerePresent = not (not data.title); local pubEntity = mw.wikibase.getEntity( publication.id ); populateSourceDataImpl( pubEntity, data ); if ( titleWerePresent ) then appendSnaks( pubEntity.claims, 'P357', data, 'publication-title', {} ); -- obsolete appendSnaks( pubEntity.claims, 'P1476', data, 'publication-label', {} ); appendSnaks( pubEntity.claims, 'P1680', data, 'publication-subtitle', {} ); data.publication.label = getSingle( data['publication-title'] ); data.publication.label = getSingle( data['publication-label'] ); data.publication.subtitle = getSingle( data['publication-subtitle'] ); end end end function expandPublisher( sourceEntity, data ) local publisher = data.publisher; -- use only first one if ( type( publisher ) == 'table' and publisher[1] and publisher[1].id ) then data.publisher = publisher[1]; publisher = data.publisher; end if ( data.publication and data.publication.id ) then local pubEntity = mw.wikibase.getEntity( data.publication.id ); if ( data.publisher and data.publisher.id and pubEntity ) then populateSourceDataImpl( pubEntity, data ); local claims = findClaimsByValue( pubEntity, 'P123', data.publisher.id ); if (claims and #claims ~=0 ) then appendQualifiers( claims, 'P1932', data, 'publisher_stated_as', {} ); end end else if ( data.publisher and data.publisher.id and sourceEntity ) then local claims = findClaimsByValue( sourceEntity, 'P123', data.publisher.id ); if (claims and #claims ~=0 ) then appendQualifiers( claims, 'P1932', data, 'publisher_stated_as', {} ); end end end 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='ru' }, plainData.title, options_commas_nolinks ); plainData.title = { normativeTitle .. " от " .. tostring(d) .. " " .. monthg[m] .. " " .. tostring(y) .. " г. № " .. getSingle( plainData.docNumber ) .. ' «' .. title.. '»' } end if ( not plainData.title ) then if ( entity.labels and entity.labels.ru and entity.labels.ru.value ) then -- plainData.title = { entity.P1343 }; plainData.title = { entity.labels.ru.value }; end end return plainData; end function populateDataFromClaims( entityId, claims, data ) appendSnaks( claims, 'P50', 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', {} ); appendSnaks( claims, 'P856', data, 'url', {} ); appendSnaks( claims, 'P1343', data, 'described', {} ); appendSnaks( claims, 'P1433', data, 'publication', {} ); 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 'www.jstor.org/stable/' .. id end } ); return src; end function updateWithRef( reference, src ) -- specified if ( reference.snaks.P662 ) then local cid = reference.snaks.P662[1].datavalue.value; src.code = src.code .. '-cid:' .. cid; src.title = 'Compound Summary for: CID ' .. cid; src.url = 'pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?cid=' .. cid; src.publication = { id = 'Q278487', label = 'PubChem' }; end populateDataFromClaims( nil, reference.snaks, src); return src; end function p.renderSource( frame ) local arg = frame.args[1]; local refAnchor = frame.args['ref']; local args = {}; args.refAnchor = frame.args['ref']; 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 ); if ( rendered ) then return rendered.text end; end function p.renderReference( frame, currentEntity, reference ) -- 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 mw.text.encode( rendered.text ); result = frame:extensionTag( 'ref', rendered.text, {name = code} ) .. '[[К:Википедия:Статьи с источниками из Викиданных]]'; return result; end function renderReferenceImpl( currentEntity, reference, refAnchor ) if ( not reference.snaks ) then return nil; end -- данные в простом формате, согласованном с модулями формирования библиографического описания local data = {}; local entityId, sourceEntity; if ( reference and reference.snaks and reference.snaks.P248 ) then for _, snak in pairs ( reference.snaks.P248 ) do if ( snak.datavalue ) then entityId = 'Q' .. snak.datavalue.value["numeric-id"]; sourceEntity = mw.wikibase.getEntity( entityId ); data.code = entityId; data.entityId = entityId; break; end end end updateWithRef( reference, 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 ); if ( sourceEntity ) then populateSourceDataImpl( sourceEntity, data ); end if ( not data.publication and data.described ) then expandDescribed( sourceEntity, data ); else if ( data.publication ) then expandPublication( sourceEntity, data ); end end expandPublisher ( sourceEntity, 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( data ); if ( mw.ustring.len( rendered.text ) == 0 ) then return nil; end if ( refAnchor ) then local anchorValue = 'CITEREF' .. refAnchor; if ( data.year ) then anchorValue = anchorValue .. data.year; end 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 = NORMATIVE_DOCUMENTS[ classId ]; if ( title ) then return title; end end end return; end local LANG_CACHE = { Q150 = 'fr', Q188 = 'de', Q1321 = 'es', Q1860 = 'en', Q652 = 'it', Q7737 = 'ru', } 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 ) -- ГОСТ Р 7.0.12—2011 if ( lang == 'ru' ) then if ( placeId == 'Q649' ) then return toTextWithTip('М.', 'Москва'); end if ( placeId == 'Q656' ) then return toTextWithTip('СПб.', 'Санкт-Петербург'); end if ( placeId == 'Q891' ) then return toTextWithTip('Н. Новгород', 'Нижний Новгород'); end if ( placeId == 'Q908' ) then return toTextWithTip('Ростов н/Д.', 'Ростов-на-Дону'); end end 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;