Modul:Zitation

Aus Genealogen im Hinterland
Zur Navigation springenZur Suche springen

local Serial = "2016-07-05" --[=[ Zitation ]=]


Zitation = Zitation or { extern = false } Zitation.serial = Serial -- local globals local Selbst = "Modul:Zitation" local FehlerTypen = { Intern = { s = "Interner Fehler",

                                   k = "Intern" },
                     Entfernen = { s = "Veraltet, bitte entfernen" },
                     Format    = { s = "Parameterformat" },
                     Konflikt  = { s = "Parameterkonflikt",
                                   k = "Parameter" },
                     Modul     = { s = "Modul-Seite fehlt",
                                   k = "Intern" },
                     Name      = { s = "Schreibweise falsch",
                                   k = "Name" },
                     Pflicht   = { s = "Pflichtparameter fehlt",
                                   k = "Parameter" },
                     Vorlage   = { s = "Vorlagen-Seite fehlt",
                                   k = "Intern" },
                     Wert      = { s = "Ungültig",
                                   k = "Parameter" }
                   }

local KategorieBeginn = "Wikipedia:Vorlagenfehler" local Kategorien = { Intern = { s = "/Interner Fehler" },

                          Name       = { s = "/Parameterfehler" },
                          Parameter  = { s = "/Parameterfehler" },
                          arXiv      = { s = "Parameter:arXiv" },
                          bibcode    = { s = "Parameter:bibcode" },
                          Datum      = { s = "Parameter:Datum" },
                          DNB        = { s = "Parameter:DNB" },
                          DOI        = { s = "Parameter:DOI" },
                          ISBN       = { s = "Parameter:ISBN" },
                          ISSN       = { s = "Parameter:ISSN" },
                          JSTOR      = { s = "Parameter:JSTOR" },
                          LCCN       = { s = "Parameter:LCCN" },
                          OCLC       = { s = "Parameter:OCLC" },
                          PMID       = { s = "Parameter:PMID" },
                          Sprachcode = { s = "Parameter:Sprachcode" },
                          URN        = { s = "Parameter:URN" },
                          ZDB        = { s = "Parameter:ZDB" }
                        }

local DocTypes =

         { csv          = "CSV",
           djvu         = "DjVu",
           flash        = "Flash",
           gzip         = "gzip",
           mp3          = MP3,
           mpeg         = "MPEG",
           mpeg4        = "MPEG-4",
           msexcel      = "MS Excel",
           mspowerpoint = "MS PowerPoint",
           msword       = "MS Word",
           pdf          = "PDF",
           postscript   = "PostScript",
           rtf          = "Rich Text Format",
           zip          = "ZIP" }

local Fehler = false local Fun = { } local Resultat


-- Allgemeine Hilfsfunktionen ===========================================


local function faraway( assign, alien )

   -- Sprache zuweisen
   -- Parameter:
   --     assign  -- mw.html-Element
   --     alien   -- string mit Sprachcode, oder nil
   if alien  and  alien ~= "de" then
       assign:addClass( "lang" )
             :attr( { dir  = "auto",
                      lang = alien } )
   end

end -- faraway()


local function feed( area, access, about )

   -- Zugriff auf Parameterkomponente
   -- Parameter:
   --     area    -- string, mit Name der Parametergruppe
   --     access  -- string, mit Name der Komponente, oder nil
   --     about   -- true, for returning original parameter name
   -- Rückgabewert: Parameterwert, oder nil
   local e, r
   if not Zitation.o then
       Zitation.o = { }
   end
   e = Zitation.o[ area ]
   if e then
       if access then
           r = e[ access ]
           if type( r ) == "table" then
               if about then
                   r = r.s or "???????"
               else
                   r = r.v
               end
           end
       else
           r = e
       end
   end
   return r

end -- feed()


local function fehler( art, anzeige )

   -- Ein Fehler ist aufgetreten
   -- Parameter:
   --     art      -- string mit Schlüsselwort zum Typ
   --     anzeige  -- string mit Einzelheiten, oder nil
   local t
   if not Fehler then
       Fehler = FehlerTypen
   end
   t = Fehler[ art ]
   if t then
       if anzeige then
           local s = mw.text.nowiki( anzeige )
           if t.e then
               t.e = string.format( "%s; %s", t.e, s )
           else
               t.e = s
           end
       end
       if t.k then
           local wk = Kategorien[ t.k ]
           if wk then
               wk.e = true
           else
               Fehler.Intern.e     = "Wartungskat " .. wk
               Kategorien.Intern.e = true
           end
       end
   else
       Fehler.Intern.e     = string.format( "fehler(%s) %s",
                                            art, anzeige )
       Kategorien.Intern.e = true
   end

end -- fehler()


local function fehlerliste()

   -- Auflistung aller Fehlermeldungen und Kategorien
   -- Rückgabewert: string mit formatiertem Ergebnis
   local r = ""
   local s
   local t = mw.title.getCurrentTitle()
   if Fehler then
       local sep = ""
       for k, v in pairs( Fehler ) do
            if v.e then
               if v.s then
                   s = v.s .. ":"
               else
                   s = ""
               end
               r = string.format( "%s%s*** %s %s", r, sep, s, v.e )
               sep = " "
           end
       end -- for k, v
       r = "
" .. r end if t.namespace == 0 or ( t.namespace == 4 and t.text:sub( 1, 4 ) == "Lua/" ) then Selbst = feed( "leise", "Vorlage" ) or Selbst for k, v in pairs( Kategorien ) do if v.e then if v.s:sub( 1, 1 ) == "/" then s = Selbst else s = "" end r = string.format( "%s", r, KategorieBeginn, s, v.s ) end end -- for k, v end return r

end -- fehlerliste()


local function fein( abtrennung, anhang )

   -- Ergänze Resultat um fertig formatierten Block
   -- Parameter:
   --     abtrennung  -- string mit vorangestelltem Separator
   --     anhang      -- string mit Textelement
   if anhang then
       Resultat = string.format( "%s%s%s",
                                 Resultat, abtrennung, anhang )
   end

end -- fein()


local function figures( a )

   -- Formatierte Aufzählung von Zahlen
   return a:gsub( "(%d)-(%d)", "%1–%2" )
           :gsub( "(%d)%s*(ff?)%.?", "%1 %2." )
           :gsub( "  +", " " )
           :gsub( " ", " " )

end -- figures()


local function findbar( assigned, about )

   -- Unauffindbare Namen (Personen) melden
   -- Parameter:
   --     assigned  -- Wert; zwei lateinische Buchstaben oder ein CJK
   --     about     -- Name des Parameters
   if not  mw.ustring.find( assigned, "%a.*%a" ) then
       local Text = Zitation.fetch( "Text" )
       if not Text.containsCJK then
           fehler( "Wert",  string.format( "'%s' zu kurz", about ) )
       end
   end

end -- findbar()


local function fire( art )

   -- Melde Kategorie an
   -- Parameter:
   --     art  -- string mit Schlagwort zum Typ
   local t = Kategorien[ art ]
   if t then
       t.e  =  true
   else
       fehler( "Intern",  "Kategorie:" .. art )
   end

end -- fire()


local function flat( adjust, anzahl, ascii )

   -- Komma-separierte Aufzählung begrenzen
   -- Parameter:
   --     adjust  -- string, mit Aufzählung
   --     anzahl  -- number, mit Anzahl erlaubter Elemente
   --     ascii   -- true, für ASCII-Auslassung
   -- Rückgabewert: string mit gleichem oder gekürztem Ergebnis
   local i = 1
   local n = 0
   local r = adjust
   while i do
       i = r:find( ",", i, true )
       if i then
           n = n + 1
           if n == anzahl then
               r = r:sub( 1, i )
               if ascii then
                   r = r .. " ..."
               else
                   r = r .. " …"   -- nbsp hellip
               end
               break -- while
           end
           i = i + 1
       end
   end    -- while i
   return r

end -- flat()


local function foreign( area, access )

   -- Sprachcodes zuweisen
   -- Parameter:
   --     area    -- string, mit Name der Parametergruppe
   --     access  -- string, mit Name der Komponente
   local r = feed( area, access )
   if r then
       local Multilingual = Zitation.fetch( "Multilingual" )
       local s            = Multilingual.format( r, "-",
                                                 false, false, false,
                                                 Zitation.frame,
                                                 "[, ]", " " )
       local parts        = mw.text.split( s or "", " " )
       local lapsus
       for i = 1, #parts do
           if not Multilingual.getName( parts[ i ] ) then
               lapsus = true
               break -- for i
           end
       end -- for i
       if lapsus then
           fehler( "Wert",  "Sprachcode=" .. r )
           fire( "Sprachcode" )
           s = r:lower():match( "^(%l%l%l?)-" )
           if s then
               Zitation.fill( area, access, s )
           end
       elseif s ~= r then
           Zitation.fill( area, access, s )
           s = string.format( "%s: '%s' statt '%s' verwenden",
                              "Sprachcode", s, r )
           fehler( "Format", s )
           r = s
       end
   end
   return r

end -- foreign()


local function framedTemplate( access, args )

   -- Vorlage einbinden
   -- Parameter:
   --     access  -- Name der Vorlage
   --     args    -- table mit Parameterliste
   -- Rückgabewert: string mit expandierter Vorlage
   if not Zitation.frame then
       Zitation.frame = mw.getCurrentFrame()
   end
   return Zitation.frame:expandTemplate{ title = access, args = args }

end -- framedTemplate()


local function future( ask )

   -- Liegt Datum in der Zukunft?
   -- Parameter:
   --     ask  -- table oder string, mit Datum
   -- Rückgabewert: true, wenn ask ungültig oder in der Zukunft
   local r = true
   local DateTime, datum
   if not Zitation.heute then
       DateTime       = Zitation.fetch( "DateTime" )
       Zitation.heute = DateTime()
   end
   if type( ask ) == "string" then
       DateTime = Zitation.fetch( "DateTime" )
       datum    = DateTime( ask )
   else
       datum = ask
   end
   if type( datum ) == "table" then
       r = ( Zitation.heute < datum )
   end
   return r

end -- future()


-- Spezielle Werte ======================================================


local function Abrufdatum( abruf )

   -- Gib behauptetes Abrufdatum zurück
   -- Parameter:
   --     abruf  -- table oder string, mit Datum
   local o = abruf
   local r
   if type( o ) == "string" then
       local DateTime = Zitation.fetch( "DateTime" )
       o = DateTime( o )
   end
   if type( o ) == "table" then
       if not future( o ) then
           local s = o:format( "ISO" )
           r = o:format( "T._Monat JJJJ", "de" )
           if abruf ~= s then
               fehler( "Format",
                       string.format( "'%s'=%s soll sein: %s",
                                      feed( "www", "Abruf", true ),
                                      abruf,
                                      s ) )
               fire( "Datum" )
           end
       end
   end
   if not r then
       r = abruf
       fehler( "Wert",
               string.format( "'%s'=%s",
                              feed( "www", "Abruf", true ),
                              abruf ) )
       fire( "Datum" )
   end
   return "abgerufen am " .. r

end -- Abrufdatum()


local function Herausgeber( apply, above, ahead )

   -- Analysiere Herausgeber und formatiere ihn, mit Klammerzusatz
   -- Parameter:
   --     access  -- string mit Herausgeber
   --     above   -- true: innerhalb Klammerebene
   --     ahead   -- true: vorangestellt statt Klammerzusatz
   -- Rückgabewerte:  -- string
   local pat  = "^([^%(%[]+)[%(%[]((%w+)%.?)[%)%]](.*)$"
   local scan = apply
   local seek = "|hg|hsg|hrsg|hrsgg|herausgeber|ed|eds|editor|editors|"
   local story = ""
   local r, s, start, sub, suffix
   while true do
       start, sub, s, suffix = mw.ustring.match( scan, pat )
       if s then
           if seek:find( string.format( "|%s|", s:lower() ) ) then
               story = story .. mw.text.trim( start )
           elseif suffix:sub( 1, 1 ) == "|"   and
               sub:sub( 1, -1 ) == ")" then
               story = string.format( "%s%s%s",
                                      story, start, sub )
           else
               story = string.format( "%s%s[%s]",
                                      story, start, s )
           end
           scan = suffix
       else
           break -- while
       end
   end -- while
   r = story .. scan
   sub, suffix = mw.ustring.match( r, "^(%w+%.?)%s*(.+)$" )
   if sub == "Hg." then
       -- (Verwechslungsgefahr bei abgekürztem Vornamen)
       r = mw.text.trim( suffix )
   elseif sub then
       seek = "|hrsg|hrsgg|herausgegeben|"
       if seek:find( string.format( "|%s|", sub:lower() ) ) then
           r = mw.text.trim( suffix )
           sub, suffix = mw.ustring.match( r, "^(vo?n?.?)%s*(.+)$" )
           if sub == "von"  or  sub == "v." then
               r = mw.text.trim( suffix )
           end
       end
   end
   if r ~= apply then
       fehler( "Wert", "Herausgeber mit unnötigem Zusatz" )
   end
   findbar( r, "Hrsg" )
   if ahead then
       r = "Hrsg.: " .. r
   else
       if above then
           r = r .. " [Hrsg.]"
       else
           r = r .. " (Hrsg.)"
       end
   end
   return r

end -- Herausgeber()


Fun.arXiv = function ( access )

   -- Analysiere arXiv-ID und gib sie als formatierten Link zurück
   local arXiv   = Zitation.fetch( "arXiv", "Vorlage:arXiv" )
   local details = arXiv.fair( access )
   if not details.legal then
       fehler( "Wert", "'arXiv'" )
       fire( "arXiv" )
   end
   arXiv.features( { showArticle = "arXiv" } )
   return arXiv.format( details )

end -- Fun.arXiv()


Fun.bibcode = function ( access )

   -- Analysiere bibcode-ID und gib sie als formatierten Link zurück
   local bibcode = Zitation.fetch( "bibcode", "Vorlage:bibcode" )
   local r       = bibcode.format{ access }
   if not r:find( "//", 1, true ) then
       fehler( "Wert",  "'bibcode' =" .. access )
       fire( "bibcode" )
   end
   return r

end -- Fun.bibcode()


Fun.DOI = function ( access )

   -- Analysiere DOI und gib sie als formatierten Link zurück
   local URIutil = Zitation.fetch( "URIutil" )
   local r       = URIutil.linkDOI( access )
   local s       = "Digital Object Identifier"
   if r then
       r = string.format( "doi:%s", s, r )
   else
       r = string.format( "DOI:%s%s",
                          s,  access,  Zitation.fault( "(?!)", true ))
       fehler( "Wert", "'DOI'" )
       fire( "DOI" )
   end
   return r

end -- Fun.DOI()


Fun.DNB = function ( access )

   -- Analysiere DNB und gib sie formatiert zurück
   local URIutil = Zitation.fetch( "URIutil" )
   local r
   if URIutil.isDNBvalid( access ) then
       r = URIutil.linkDNBopac( access, false, true, true )
   else
       local s = "Deutsche Nationalbibliothek"
       fehler( "Wert", "'DNB'" )
       fire( "DNB" )
       r = string.format( "DNB %s%s",
                          s,  access,  Zitation.fault( "(?!)", true ))
   end
   return r

end -- Fun.DNB()


Fun.ISSN = function ( access, allow )

   -- Analysiere ISSN und gib sie formatiert zurück
   --     allow    -- true: permit invalid check digit
   local URIutil = Zitation.fetch( "URIutil" )
   if allow or URIutil.isISSNvalid( access ) then
       r = URIutil.linkISSN( access, allow, true, true )
   else
       local s = "International Standard Serial Number"
       fehler( "Wert", "'ISSN'" )
       fire( "ISSN" )
       r = string.format( "ISSN %s%s",
                          s,  access,  Zitation.fault( "(?!)", true ))
   end
   return r

end -- Fun.ISSN()


Fun.ISSNfalsch = function ( access )

   -- Analysiere formal falsche ISSN und gib sie formatiert zurück
   return Fun.ISSN( access, true )

end -- Fun.ISSNfalsch()


Fun.JSTOR = function ( access )

   -- Analysiere JSTOR (stable) und gib sie formatiert zurück
   -- i: Volume
   local legal
   if access:find( "/", 1, true ) then
       local URIutil = Zitation.fetch( "URIutil" )
       legal = URIutil.isDOI( access )
   else
       legal = access:match( "^i?[1-9][0-9]*$" )
   end
   if not legal then
       fehler( "Wert", "'JSTOR'" )
       fire( "JSTOR" )
   end
   return framedTemplate( "JSTOR", { access } )

end -- Fun.JSTOR()


Fun.LCCN = function ( access )

   -- Analysiere LCCN und gib sie formatiert zurück
   local URIutil = Zitation.fetch( "URIutil" )
   local see = "Library of Congress Control Number"
   local r = string.format( "LCCN ", see )
   if URIutil.isLCCN( access ) then
       r = r .. URIutil.linkLCCN( access, "-" )
   else
       fehler( "Wert", "'LCCN'" )
       fire( "LCCN" )
       r = string.format( "%s%s%s",
                          r,  access,  Zitation.fault( "(?!)", true ))
   end
   return r

end -- Fun.LCCN()


Fun.Lizenznummer = function ( access )

   -- Gib DDR-Lizenznummer formatiert zurück
   return "Lizenznummer " .. access

end -- Fun.Lizenznummer()


Fun.OCLC = function ( access )

   -- Analysiere OCLC und gib sie formatiert zurück
   local r
   if access:match( "^[1-9][0-9]*$" ) then
       r = framedTemplate( "OCLC", { access } )
   else
       fehler( "Wert", "'OCLC'" )
       fire( "OCLC" )
       r = string.format( "OCLC %s", access )
   end
   return r

end -- Fun.OCLC()


Fun.PMC = function ( access )

   -- Analysiere PMC und gib sie formatiert zurück
   local r
   if access:match( "^[1-9][0-9]*$" ) then
       r = framedTemplate( "PMC", { access } )
   else
       fehler( "Wert", "'PMC'" )
       fire( "PMID" )    -- Ja, PMID-Experte betreut auch PMC
       r = string.format( "PMC %s", access )
   end
   return r

end -- Fun.PMC()


Fun.PMID = function ( access )

   -- Analysiere PMID und gib sie formatiert zurück
   if not access:match( "^[1-9][0-9]*$" ) then
       fehler( "Wert", "'PMID'" )
       fire( "PMID" )
   end
   return string.format( "PMID %s", access )

end -- Fun.PMID()


Fun.URN = function ( access )

   -- Analysiere URN und gib sie formatiert zurück
   local URIutil = Zitation.fetch( "URIutil" )
   local r = URIutil.uriURN( "urn:" .. access )
   if not r:find( "//", 1, true ) then
       fehler( "Wert",  "'URN'=" .. access )
       fire( "URN" )
   end
   return r

end -- Fun.URN()


Fun.ZDB = function ( access )

   -- Analysiere ZDB und gib sie formatiert zurück
   local URIutil = Zitation.fetch( "URIutil" )
   if URIutil.isDNBvalid( access )  or
      URIutil.isDNBvalid( access:gsub( "-", "" ) ) then
       r = framedTemplate( "ZDB", { access:upper() } )
   else
       local s = "Zeitschriftendatenbank"
       fehler( "Wert", "'ZDB'" )
       fire( "ZDB" )
       r = string.format( "ZDB %s%s",
                          s,  access, Zitation.fault( "(?!)", true ))
   end
   return r

end -- Fun.ZDB()


local function redundanz( analyse )

   -- Prüfe Angabe auf Redundanz mit anderen Parametern
   -- Parameter:
   --     analyse  -- string
   local urlPats = { arXiv   = "//arxiv%.org/abs/",
                     bibcode = "//adsabs%.harvard%.edu/",
                     DNB     = "//portal%.dnb%.de/opac.+query=%d+X?$",
                     DOI     = "//dx%.doi%.org/10%.",
                     JSTOR   = "jstor%.org/stable/",
                     PMC     = "ncbi%.nlm%.nih%.gov/pmc/articles/PMC%d",
                     PMID    = "ncbi%.nlm%.nih%.gov/pubmed/%d",
                     URN     = "//nbn-resolving%.de/urn:" }
   for k, v in pairs( urlPats ) do
       if analyse:match( v ) then
           local s = string.format( "%s '%s=' %s",
                                    "Statt URL sollte etwas wie",
                                    k,
                                    "angegeben werden" )
           fehler( "Konflikt", s )
       end
   end -- for k, v
   if analyse:find( "title=\"ctx_ver=Z39.88-2004", 1 , true ) then
       fehler( "Konflikt", "Verschachtelte Zitationsvorlagen" )
   end

end -- redundanz()


local function bandNummer( area )

   -- Formatiere Angaben von Band und/oder Nummer
   -- Parameter:
   --     area  -- string, mit Name der Parametergruppe print/serie
   -- Rückgabewert: string mit Inhalt, oder nil
   local sB = feed( area, "Band" )
   local sN = feed( area, "Nummer" )
   local r
   if sB then
       if sB:match( "^%d+$" ) then
           r = "Band " .. sB
       else
           r = sB
       end
   end
   if sN then
       if r then
           r = r .. ", "
       else
           r = ""
       end
       if not mw.ustring.find( sN, "%a" ) then
           sN = "Nr. " .. sN
       end
       r = r .. sN
   end
   return r

end -- bandNummer()


local function Kapitel( a )

   -- Formatiere Kapitelangabe
   local r = a
   if a:match( "^%d+$" ) then
       r = "Kap. " .. a
   end
   return r

end -- Kapitel()


local function ArtikelNr( aN, aS )

   -- Analysiere ArtikelNr
   if aS then
       fehler( "Konflikt", "Seitenzahl redundant wenn ArtikelNr" )
   end
   if not aN:match( "^%d+$" ) then
       fehler( "Wert", "'ArtikelNr'=" .. aN )
   end

end -- ArtikelNr()


local function Seiten( a )

   -- Analysiere Seitenzahl und formatiere
   local s, seiten = a:match( "^(%w+%.?)%s*(.+)$" )
   if s then
       local seek = "|s.|ss.|seite|seiten|page|pages|p.|pp.|"
       if seek:find( string.format( "|%s|", s:lower() ) ) then
           fehler( "Wert", "Seitenzahl mit unnötigem Zusatz" )
           seiten = mw.text.trim( seiten )
       else
           seiten = a
       end
   else
       seiten = a
   end
   return "S. " .. figures( seiten )

end -- Seiten()


local function Spalten( a )

   -- Analysiere Spaltenangabe und formatiere
   local s, sp = a:match( "^(%w+%.?)%s*(.+)$" )
   if s then
       local seek = "|sp.|spalte|spalten|"
       if seek:find( string.format( "|%s|", s:lower() ) ) then
           fehler( "Wert", "Spaltenangabe mit unnötigem Zusatz" )
           sp = mw.text.trim( sp )
       else
           sp = a
       end
   else
       sp = a
   end
   return "Sp. " .. figures( sp )

end -- Spalten()


local function Werktitel( a, amend, alien, abschluss )

   -- Formatiere einen Werktitel, das Sammelwerk, ggf. Reihe
   -- Parameter:
   --     a          -- string
   --     amend      -- string mit Ergänzung, oder nil
   --     alien      -- string mit Sprachcode, oder nil
   --     abschluss  -- true: Satzendezeichen sicherstellen
   -- Rückgabewert: string mit formatiertem Werktitel
   local Text  = Zitation.fetch( "Text" )
   local cite = mw.html.create( "cite" )
   local sep
   local r
   cite:css( "font-style", "italic" )
   cite:wikitext( Text.uprightNonlatin( a ) )
   faraway( cite, alien )
   r = tostring( cite )
   if amend then
       local s
       if Text.sentenceTerminated( a ) then
           sep = ""
       else
           sep = "."
       end
       r = string.format( "%s%s %s", r, sep, amend )
   end
   if abschluss  and
      ( ( not amend  and  not Text.sentenceTerminated( a ) )
        or   ( amend  and  not Text.sentenceTerminated( amend ) ) ) then
       r = r .. "."
   end
   return r

end -- Werktitel()


-- Einzelblöcke der Darstellung =========================================


local function resourceMeta( anfang )

   -- Ergänze Resultat um für einen Online-Abruf wichtigen Informationen
   --     anfang  -- boolean
   --                * true   -- runde Klammern
   --                            um .Format und .KBytes gesetzt
   --                * false  -- eckige Klammern
   --                            um .Format und .KBytes und .Abruf
   -- Rückgabewert: string mit führendem " " und Inhalt, oder ""
   local r = ""
   if feed( "www" ) then
       local sURL     = feed( "www", "URL" )
       local sWeblink = feed( "www", "Weblink" )
       local some     = ( sURL or sWeblink )
       local sAbruf   = feed( "www", "Abruf" )
       local sFormat  = feed( "www", "Format" )
       local sKBytes  = feed( "www", "KBytes" )
       if some then
           local sep = ""
           some = some:lower() .. " "
           if sFormat then
               local s = sFormat:upper()
               if s ~= "HTML" then
                   if s:find( "PDF%-?" ) then
                       r = "pdf"
                   else
                       r = sFormat
                   end
               end
           elseif some:find( "%Wpdf%W" ) then
               r = "pdf"
           end
           if r:lower() == "pdf"  and
              sWeblink  and
              some:find( " .*pdf" ) then
               r = ""
           end
           if r == "" then
               sKBytes = false
           else
               r   = DocTypes[ r:lower() ]  or  r
               sep = "; "
           end
           if sKBytes then
               local scan = "^(%d+[,%.]?%d*)%s*(%a*)$"
               local size, suffix
               sKBytes = sKBytes:gsub( " ", " " )
                                :gsub( " ", " " )
                                :gsub( " ", " " )
               size, suffix = sKBytes:match( scan )
               if size then
                   local n
                   size = size:gsub( "%.", "" )
                   if size:find( "," ) then
                       n    = tonumber( size:gsub( ",", "." ), 10 )
                       size = string.format( "%1.1d", n )
                   else
                       n = tonumber( size )
                   end
                   if suffix  and
                      suffix:lower():match( "^mi?b$" ) then
                       n      = n * 1000
                       suffix = "kb"
                   end
                   if not suffix   or   suffix == ""   or
                      ( suffix  and
                        suffix:lower():match( "^ki?b%l*$" ) ) then
                       if n > 1000 then
                           n      = math.ceil( n * 0.01 ) * 0.1
                           size   = string.format( "%.1f", n )
                           suffix = "MB"
                       else
                           suffix = "kB"
                       end
                   end
                   sKBytes = string.format( "%s %s",
                                            size:gsub( "%.", "," ),
                                            suffix )
               end
               r = string.format( "%s%s%s", r, sep, sKBytes )
               sep = "; "
           end
           if not anfang and sAbruf and sWeblink then
               r = string.format( "%s%s%s",
                                  r, sep, Abrufdatum( sAbruf ) )
           end
           if r ~= "" then
               if anfang then
                   sep = " (%s)"
               else
                   sep = " [%s]"
               end
               r = string.format( sep, r )
           end
           redundanz( some )
       elseif sFormat or sKBytes or sAbruf then
           fehler( "Konflikt",
                   "Dateiformat/Größe/Abrufdatum nur wenn Weblink" )
       end
   end
   return r

end -- resourceMeta()


local function autorHrsg()

   -- Ergänze Resultat um Personen zu Beginn der Zitation
   local sAutor = feed( "bas", "Autor" )
   local sHrsg  = feed( "bas", "Hrsg" )
   local sTyp   = feed( "leise", "Typ" )
   local lead
   if sTyp  and  sTyp ~= "wl" then
       fehler( "Wert",
               "'Typ' zurzeit nur 'Typ=wl' (Werkliste) unterstützt" )
       r = "wl"
   end
   if sHrsg then
       lead = ( not feed( "bas", "Werk" ) )
       findbar( sHrsg, "Hrsg" )
   end
   if sAutor or lead then
       local list = false
       if sAutor then
           if sTyp ~= "wl" then
               fein( "", sAutor )
               list = true
           end
           if type( sAutor ) == "table" then
               sAutor = Zitation.citePerson( sAutor, false )
           end
           findbar( sAutor, "Autor" )
           if sHrsg  and  not feed( "bas", "Titel" ) then
               fehler( "Konflikt",
                       "Gleichzeitig 'Autor' und 'Herausgeber' nur wenn auch 'Titel'" )
           end
       else
           fein( "",  Herausgeber( sHrsg ) )
           list = true
       end
       if list then
           fein( ": ", "" )
       end
   end

end -- autorHrsg()


local function erstAusgabe()

   -- Erstausgabe
   -- Rückgabewert: string
   local sJahr   = feed( "ed1", "Jahr" )
   local sOrt    = feed( "ed1", "Ort" )
   local sVerlag = feed( "ed1", "Verlag" )
   local r       = "Erstausgabe: "
   local sep
   if sVerlag then
       r   = r .. sVerlag
       sep = ","
       if feed( "bas", "Verlag" ) == sVerlag then
           fehler( "Konflikt",
                   string.format( "'%s' hat gleichen Wert wie '%s'",
                                  feed( "ed1", "Verlag", true ),
                                  feed( "bas", "Verlag", true ) ) )
       end
   else
       sep = ""
   end
   if sOrt then
       r   = string.format( "%s%s %s", r, sep, sOrt )
       sep = " "
       -- bas.Verlag und ed1.Verlag dürfen in derselben Stadt sein
   end
   if sJahr then
       local jahr
       if sJahr:match( "^%d%d%d%d$" ) then
           if not future( sJahr ) then
               jahr = tonumber( sJahr )
           end
       end
       if jahr then
           local datum = feed( "bas", "Datum" )
           r = string.format( "%s%s %s", r, sep, sJahr )
           if type( datum ) == "table"   and
              datum.year   and   datum.year < jahr then
               fehler( "Konflikt",
                       string.format( "'%s' nach Neuausgabe",
                                      feed( "ed1", "Jahr", true ) ) )
           end
       else
           fehler( "Wert",
                   string.format( "'%s'=%s",
                                  feed( "ed1", "Jahr", true ),
                                  sJahr ) )
           fire( "Datum" )
       end
   end
   return r

end -- erstAusgabe()


local function originalPublikation()

   -- Originalpublikation; zulässige Parameterlogik noch unklar
   -- Rückgabewert: string mit Inhalt, oder false
   local r
   if feed( "orig" ) then
       local sTitel      = feed( "orig", "Titel" )
       local sTranslator = feed( "orig", "Translator" )
       if sTitel then
           local sprache = foreign( "orig", "Sprache" )
           local sOrt    = feed( "orig", "Ort" )
           local sJahr   = feed( "orig", "Jahr" )
           r = Werktitel( sTitel, false, sprache, true )
           if sOrt then
               r = string.format( "%s %s", r, sOrt )
           end
           if sJahr then
               r = string.format( "%s %s", r, sJahr )
               if sJahr:match( "^%d%d%d%d$" ) then
                   if future( sJahr ) then
                       fehler( "Wert", "Originaljahr in der Zukunft" )
                   else
                       local jahr = tonumber( sJahr )
                       local datum = feed( "bas", "Datum" )
                       if type( datum ) == "table"   and
                          datum.year   and   datum.year < jahr then
                           fehler( "Konflikt",
                                   "Originaljahr nach Neuausgabe" )
                       end
                   end
               else
                   fehler( "Wert", "Originaljahr ist keine Jahreszahl" )
               end
           end
           if sOrt or sJahr then
               r = r .. "."
           end
           if sprache then
               local Multilingual = Zitation.fetch( "Multilingual" )
               local s = Multilingual.format( sprache, "de", "m",
                                              false, false,
                                              Zitation.frame,
                                              " ", ", " )
               if s then
                   sprache = s
               elseif sprache:match( "^%l%l%l?$" ) then
                   fehler( "Wert",
                           "Unbekannter Sprachcode=" .. sprache )
                   fire( "Sprachcode" )
                   sprache = string.format( "%s", sprache )

-- elseif sprache:match( "^%l.+[ ,;/]" ) then -- fehler( "Wert", -- "Original-Sprachcode seltsam: " .. sprache )

               end
           else
               sprache = "Originaltitel"
           end
           r = string.format( "%s: %s", sprache, r )
           if sTranslator then
               r = string.format( "%s Übersetzt von %s",
                                  r, sTranslator )
           end
       elseif not sTranslator then
           fehler( "Pflicht", "Originaltitel fehlt" )
       end
   end
   return r

end -- originalPublikation()


local function titel()

   -- Ergänze Resultat um Titel
   local sTitel = feed( "bas", "Titel" )
   local sWerk  = feed( "bas", "Werk" )
   if sTitel then
       local stop = ""
       local sReihe    = feed( "serie", "Reihe" )
       local sTitelErg = feed( "bas",   "TitelErg" )
       local sURL      = feed( "www",   "URL" )
       local s = Werktitel( sTitel,
                            false,
                            feed( "bas", "Sprache" ),
                            sWerk  or  not sReihe  or  sTitelErg )
       local Text
       if sURL then
           local URLutil = Zitation.fetch( "URLutil" )
           if URLutil.isResourceURL( sURL ) then
               s    = s:gsub( "%[", "[" )
                       :gsub( "%]", "]" )
               sURL = sURL:gsub( "%[", "%5B" )
                          :gsub( "%]", "%5D" )
               s    = string.format( "[%s %s]%s",
                                     sURL, s, resourceMeta( true ) )
           else
               fehler( "Wert", "URL" )
           end
       end
       if sTitelErg then
           Text = Zitation.fetch( "Text" )
           if ( sWerk  or  not sReihe )   and
              not Text.sentenceTerminated( sTitelErg ) then
               stop = "."
           end
           s = string.format( "%s %s%s", s, sTitelErg, stop )
       end
       fein( "", s )
       if not sWerk then
           local sAutor = feed( "bas", "Autor" )
           local sHrsg  = feed( "bas", "Hrsg" )
           if sAutor and sHrsg then
               if stop == "" then
                   Text = Zitation.fetch( "Text" )
                   if not Text.sentenceTerminated( Resultat ) then
                       stop = "."
                   end
               elseif sTitelErg then
                   stop = ""
               end
               stop = stop .. " "
               fein( stop,  Herausgeber( sHrsg, false, true ) .. "." )
           end
       end
   else
       if sWerk then
           fehler( "Pflicht", "Kein 'Titel'" )
       else
           fehler( "Pflicht", "Weder 'Titel' noch sonstiges Werk" )
       end
   end

end -- titel()


local function werk()

   -- Ergänze Resultat um Sammelwerk usw.
   local sWerk = feed( "bas", "Werk" )
   if sWerk then
       local start = " In: "
       local sHrsg = feed( "bas", "Hrsg" )
       local s     = Werktitel( sWerk,
                                feed( "bas", "WerkErg" ),
                                feed( "bas", "Sprache" ),
                                not feed( "serie", "Reihe" ) )
       if sHrsg then
           s = string.format( "%s: %s",  Herausgeber( sHrsg ),  s )
       end
       if Resultat == "" then
           start = "In: "
       end
       fein( start, s )
   end

end -- werk()


local function auflage()

   -- Ergänze Resultat um Auflage
   local sAuflage = feed( "print", "Auflage" )
   if sAuflage then
       local s = sAuflage:gsub( "Auflage$",   "Auflage")
                         :gsub( "[eE]d%.?$",  "ed." )
                         :gsub( "[eE]dition", "ed." )
                         :gsub( "[éÉ]d%.?$",  "éd." )
                         :gsub( "[éÉ]dition", "éd." )
       if s:match( "^%d+$" ) then
           s = s .. "."
       end
       if not ( s:find( "Aufl", 1, true )  or
                s:find( "[eé]d" ) ) then
           s = s .. " Auflage"
       end
       if not s:match( "%.$" ) then
           s = s .. "."
       end
       fein( " ", s )
   end

end -- auflage()


local function reihe()

   -- Ergänze Resultat um Angaben zur Reihe
   if feed( "serie" ) then
       local sReihe = feed( "serie", "Reihe" )
       if sReihe then
           local sBN   = bandNummer( "serie" )
           local sHrsg = feed( "serie", "Hrsg" )
           local s     = Werktitel( sReihe,
                                    false,
                                    feed( "bas", "Sprache" ),
                                    sBN )
           if sHrsg then
               s = string.format( "%s: %s",
                                  Herausgeber( sHrsg, true ),  s )
           end
           if sBN then
               s = string.format( "%s %s", s, sBN )
           end
           fein( " ",  string.format( "(= %s).", s ) )
       else
           local scream
           local flop = function ( au )
                            if feed( "serie", au ) then
                                local s = feed( "serie", au, true )
                                if scream then
                                    scream = scream .. ", "
                                else
                                    scream = ""
                                end
                                scream = string.format( "%s'%s'",
                                                        scream, s )
                            end
                        end -- flop()
           flop( "Hrsg" )
           flop( "Band" )
           flop( "Nummer" )
           if scream then
               -- Muss in dieser Konstellation eigentlich immer sein
               fehler( "Pflicht",
                       scream .. " nur wenn Reihe angegeben" )
           end
       end
   end

end -- reihe()


local function bibliografischeAngaben()

   -- Ermittle die Aufzählung bibliografische Angaben
   -- Rückgabewert: string mit Inhalt, oder false
   local r       = ""
   local sep     = ""
   local datum   = feed( "bas", "Datum" )
   local sVerlag = feed( "bas", "Verlag" )
   local s, sOrt
   if feed( "print" ) then
       sOrt = feed( "print", "Ort" )
       s    = bandNummer( "print" )
       if s then
           r = s
           if s:find( "%.$" ) then
               sep = " "
           elseif sVerlag or sOrt then
               sep = ". "
           else
               sep = ", "
           end
       end
   end
   if sVerlag then
       r = string.format( "%s%s%s", r, sep, sVerlag )
       sep = ", "
   end
   if sOrt  and
      not ( feed( "id", "ISSN" )  or  feed( "id", "ZDB" ) ) then
       s = sOrt:gsub( "[,/; ]+$", "" )
       r = string.format( "%s%s%s", r, sep, s )
       if s ~= sOrt then
           Zitation.fill( "print", "Ort", s )
       end
       sep = ", "
   end
   if datum then
       local o = datum
       if type( datum ) == "string" then
           local DateTime = Zitation.fetch( "DateTime" )
           o = DateTime( datum )
       end
       if type( o ) == "table"  and  o.year then
           Zitation.fill( "bas", "Datum", o )
           if future( o ) then
               o = false
           elseif feed( "id", "ISBN" ) then
               s = tostring( o.year )
           else
               s = o:format( "T._Monat JJJJ" )
           end
       else
           o = false
       end
       if not o then
           if type( datum ) == "string" then
           --  s = "Datum: " .. datum    -- LEGACY
               s = datum
           else
               s = "Datum??"
           end
           fehler( "Wert", s )
           fire( "Datum" )
       end
       if sOrt then
           sep = " "
       end
       r = string.format( "%s%s%s", r, sep, s )
       sep = ", "
   end
   if feed( "id" ) then
       local lazy        = false    -- gültige ISBN bekannt
       local sID         = feed( "id", "ID" )
       local sISBN       = feed( "id", "ISBN" )
       local sISBNfalsch = feed( "id", "ISBNfalsch" )
       local sISBNdefekt = feed( "id", "ISBNdefekt" )
       local fiddler     =
                 function( at )
                     local s = feed( "id", at )
                     if s then
                         if lazy  and
                            not  ( at == "ISSN"  or
                                   at == "ISSNfalsch" ) then
                             s = "redundant, da ISBN gegeben"
                             s = string.format( "'%s' %s",
                                                feed( "id", at, true ),
                                                s )
                             fehler( "Konflikt", s )
                         else
                             s   = Fun[ at ]( s )
                             r   = string.format( "%s%s%s",
                                                  r, sep, s )
                             sep = ", "
                         end
                     end
                 end
       if sISBN and sISBNfalsch then
           s = string.format( "'%s' und '%s' %s",
                              feed( "id", "ISBN", true ),
                              feed( "id", "ISBNfalsch", true ),
                              "nicht gleichzeitig angeben" )
           fehler( "Konflikt", s )
       elseif sISBN or sISBNfalsch then
           local mode
           if sISBNfalsch then
               mode = -1
           end
           s, lazy = Zitation.ISBN( sISBN or sISBNfalsch,  mode )
           r = string.format( "%s%s%s", r, sep, s )
           sep = ", "
       end
       if sISBNdefekt then
           s = Zitation.ISBN( sISBNdefekt, #sISBNdefekt )
           r = string.format( "%s%s%s", r, sep, s )
           sep = ", "
       end
       fiddler( "ISSN" )
       fiddler( "ISSNfalsch" )
       fiddler( "DNB" )
       fiddler( "LCCN" )
       fiddler( "Lizenznummer" )
       fiddler( "OCLC" )
       fiddler( "ZDB" )
       if sID then
           r = string.format( "%s%s%s", r, sep, sID )
           sep = ", "
           redundanz( sID )
       end
   end
   if feed( "fragment" ) then
       local sArtikelNr  = feed( "fragment", "ArtikelNr" )
       local sFundstelle = feed( "fragment", "Fundstelle" )
       local sKapitel    = feed( "fragment", "Kapitel" )
       local sSeiten     = feed( "fragment", "Seiten" )
       local sSpalten    = feed( "fragment", "Spalten" )
       if sKapitel then
           r = string.format( "%s%s%s", r, sep, Kapitel( sKapitel ) )
           sep = ", "
       end
       if sSeiten then
           r = string.format( "%s%s%s", r, sep, Seiten( sSeiten ) )
           sep = ", "
       end
       if sSpalten then
           r = string.format( "%s%s%s", r, sep, Spalten( sSpalten ) )
           sep = ", "
       end
       if sArtikelNr then
           ArtikelNr( sArtikelNr, sSeiten )
           r = string.format( "%s%s%s", r, sep, sArtikelNr )
           sep = ", "
       end
       if sFundstelle then
           r = string.format( "%s%s%s",
                              r,
                              sep, "white-space:nowrap", sFundstelle )
           sep = ", "
       end
   end
   if feed( "id" ) then
       local docCodes   = { "DOI",
                            "PMID",
                            "PMC",
                            "arXiv",
                            "bibcode",
                            "JSTOR",
                            "URN" }
       local sign
       for i = 1, #docCodes do
           s    = docCodes[ i ]
           sign = feed( "id", s )
           if sign then
               r   = string.format( "%s%s%s", r, sep, Fun[ s ]( sign ) )
               sep = ", "
           end
       end -- for i
   end
   if r == "" then
       r = false
   end
   return r

end -- bibliografischeAngaben()


local function klammerInhalt()

   -- Inhalt der Klammer am Ende der bibliografischen Angaben
   -- Rückgabewert: string mit Inhalt, oder false
   local r          = ""
   local sep        = ""
   local sKommentar = feed( "bas",   "Kommentar" )
   local sOrig      = originalPublikation()
   local sprache    = feed( "bas",   "Sprache" )
   local sUmfang    = feed( "print", "Umfang" )
   if sprache  and  sprache ~= "de" then
       local Multilingual = Zitation.fetch( "Multilingual" )
       sprache = Multilingual.format( sprache, "de", "m",
                                      false, false,
                                      Zitation.frame,
                                      " ", ", " )
       if sprache:find( "^%a+er " ) then
           -- Rechtschreibduden, K90
           sprache = mw.ustring.lower( mw.ustring.sub( sprache, 1, 1 ) )
                     .. mw.ustring.sub( sprache, 2 )
       end
       r   = string.format( "%s%s%s", r, sep, sprache )
       sep = ", "
   end
   if sUmfang then
       if not mw.ustring.find( sUmfang, "%a" ) then
           -- "14, 234"
           sUmfang = string.format( "%s S.", sUmfang )
       end
       r   = string.format( "%s%s%s", r, sep, sUmfang )
       sep = ", "
   end
   if feed( "www" ) then
       local sWeblink = feed( "www", "Weblink" )
       if sWeblink then
           local WLink = Zitation.fetch( "WLink" )
           local show  = WLink.getWeblink( sWeblink )
           r   = string.format( "%s%s%s%s",
                                r,
                                sep,
                                show:gsub( " www%d*%.", " " ),
                                resourceMeta( false ) )
           sep = " "
           if sWeblink:find( "", 1, true )   or
              sWeblink:find( "class=\"cite\"", 1, true ) then
               fehler( "Konflikt",
                       "Zitationsvorlage rekursiv eingebunden" )
               fire( "Parameter" )
               -- Langfristig wirkungslos; greift nur vorübergehend
               -- wenn IQ noch reine Vorlage,
               -- oder cite als reine Vorlage.
               -- Nach vollständiger Umsetzung
               -- sperrt sich aber das System,
               -- weil Modul:Zitation
               -- dann rekursiv aufgerufen werden würde.
           end
       elseif feed( "www", "URL" ) then
           local sAbruf = feed( "www", "Abruf" )
           if sAbruf then
               r   = string.format( "%s%s%s",
                                    r, sep, Abrufdatum( sAbruf ) )
               sep = ", "
           end
       else
           -- ERROR  URL ./. Weblink   "Konflikt"
       end
   end
   if sOrig then
       r = string.format( "%s%s%s", r, sep, sOrig )
       if feed( "orig", "Translator" ) then
           sep = ", "
       else
           sep = " "
       end
   end
   if feed( "ed1" ) then
       r   = string.format( "%s%s%s", r, sep, erstAusgabe() )
       sep = ", "
   end
   if sKommentar then
       r = string.format( "%s%s%s", r, sep, sKommentar )
       redundanz( sKommentar )
   end
   if r == "" then
       r = false
   end
   return r

end -- klammerInhalt()


local function endBlock()

   -- Ergänze Resultat um bibliografische Angaben, Klammer sowie Zitat.
   -- Komma-getrennte Aufzählung, die mit Punkt abgeschlossen wird,
   -- oder Zitat wird nachgestellt.
   local sZitat = feed( "bas", "Zitat" )
   local sep    = ""
   local s      = bibliografischeAngaben()
   if s then
       fein( " ", s )
       sep = "."
   end
   s = klammerInhalt()
   if s then
       if Resultat:find( "%)$" ) then
           -- Irgendwas zuvor endet auf eine runde Klammer.
           sep = " – ("
       else
           sep = " ("
       end
       fein( sep,  s .. ")" )
       sep = "."
   end
   if sep ~= "" then
       -- Aufzählung enthält zumindest ein Element
       if sZitat then
           fein( ":", "" )
       elseif not Resultat:match( "%.$" ) then
           fein( ".", "" )
       end
   end
   if sZitat then
       local sprache = feed( "bas", "Sprache" )
       local Text    = Zitation.fetch( "Text" )
       local story   = Text.quoteUnquoted( sZitat, sprache )
       if sprache  and  sprache ~= "de" then
           local q = mw.html.create( "span" )
           faraway( q, sprache )
           q:wikitext( story )
           story = tostring( q )
       end
       fein( " ", story )
   end

end -- endBlock()


local function coins()

   -- Ergänze Resultat um COinS, wenn gewünscht
   local COinS = feed( "coins" )
   if COinS then
       local std = "book"
       local pars
       if type( COinS ) == "table" then
           pars = COinS
       elseif feed( "bas" ) then
           local datum    = feed( "bas",      "Datum" )
           local sAutor   = feed( "bas",      "Autor" )
           local sKapitel = feed( "fragment", "Kapitel" )
           local sTitel   = feed( "bas",      "Titel" )
           local sWerk    = feed( "bas",      "Werk" )
           local stick
           pars = { }
           if sWerk then
               if feed( "print",    "Nummer" )  or
                  feed( "id",       "ISSN" )  or
                  feed( "id",       "ISSNfalsch" )  or
                  feed( "id",       "ZDB" )  or
                  feed( "fragment", "ArtikelNr" ) then
                   pars.genre  = "journal"
                   pars.jtitle = sWerk
                   std         = "journal"
               else
                   pars.genre  = "book"
                   pars.btitle = sWerk
               end
               pars.atitle = sTitel
           elseif sKapitel then
               pars.genre  = "bookitem"
               pars.btitle = sTitel
               pars.atitle = sKapitel
           else
               pars.genre  = "book"
               pars.btitle = sTitel
           end
           if type( datum ) == "table" then
               pars.date = datum:format( "ISO" )
           end
           if sAutor then
               if type( sAutor ) == "table" then
                   stick = Zitation.citePerson( sAutor, true )
               else
                   pars.au = flat( sAutor, 3, true )
               end
           end
           pars.pub   = feed( "bas",      "Verlag" )
           pars.pages = feed( "fragment", "Seiten" )
           if feed( "id" ) then
               pars.isbn = feed( "id", "ISBN" )  or
                           feed( "id", "ISBNfalsch" )
                           feed( "id", "ISBNfalsch" )
               pars.issn = feed( "id", "ISSN" )  or
                           feed( "id", "ISSNfalsch" )
               pars.oclc = feed( "id", "OCLC" )
               pars.doi  = feed( "id", "DOI" )
               pars.pmc  = feed( "id", "PMC" )
               pars.pmid = feed( "id", "PMID" )
           end
           if feed( "print" ) then
               pars.edition = feed( "print", "Auflage" )
               pars.issue   = feed( "print", "Nummer" )
               pars.place   = feed( "print", "Ort" )
               pars.volume  = feed( "print", "Band" )
           end
           pars.series = feed( "serie", "Reihe" )
       end
       if pars then
           fein( "",  Zitation.COinS( pars, false, stick ),  std )
       end
   end

end -- coins()


-- Exportierte Funktionen ===============================================


Zitation.fault = function ( a, always )

   -- Formatiere Fehler mit class=error; teils ausgeblendet
   -- Parameter:
   --     a       -- string, mit Fehlermeldung
   --     always  -- true, wenn nicht zu unterdrücken
   -- Rückgabewert:
   --     HTML-Element
   local e = mw.html.create( "span" )
   e:addClass( "error" )
    :wikitext( a )
   if not always  and
      feed( "leise", "leiser" )  and
      mw.site.server == "//de.wikipedia.org" then
       if not Zitation.frame then
           Zitation.frame = mw.getCurrentFrame()
       end
       if Zitation.frame:preprocess( "11096" ) ~= "" then
           e:addClass( "Zitationsfehler" )
            :css( "display", "none" )
       end
   end
   return tostring( e )

end -- Zitation.fault()


Zitation.fetch = function ( assigned, acquire )

   -- Binde Modul ein
   -- Parameter:
   --     assigned  -- string mit Name
   --                  "arXiv"
   --                  "bibcode"
   --                  "DateTime"
   --                  "Multilingual"
   --                  "Text"
   --                  "URIutil"
   --                  "URLutil"
   --                  "WLink"
   --     acquire   -- string mit abweichendem Modulnamen, oder false
   -- Rückgabewert: table des Moduls
   -- error: Modul nicht gefunden
   local r
   if Zitation.extern then
       r = Zitation.extern[ assigned ]
   else
       Zitation.extern = { }
   end
   if not r then
       local s = assigned
       if acquire then
           s = acquire
       end
       local lucky, g = pcall( require, "Module:" .. s )
       if type( g ) == "table" then
           r = g[ assigned ]()
           Zitation.extern[ assigned ] = r
       else
           fehler( "Modul", g )
           error( string.format( "Zitation.fetch(%s) %s", s, g ) )
       end
   end
   return r

end -- Zitation.fetch()


Zitation.figure = function ( adjust )

   -- Bilde Zahlenwert
   -- Parameter:
   --     adjust  -- Wert beliebigen Typs
   -- Rückgabewert:
   --     Numerischer Wert, notfalls 0
   local r
   local s = type( adjust )
   if s == "string" then
       r = tonumber( adjust ) or 0
   elseif s == "number" then
       r = adjust
   else
       r = 0
   end
   return r

end -- Zitation.figure()


Zitation.fill = function ( area, access, assign, alias )

   -- Parameterkomponente zuweisen
   -- Parameter:
   --     area    -- string, mit Name der Parametergruppe
   --     access  -- string, mit Name der Komponente
   --     assign  -- Parameterwert
   --     alias   -- string, mit Name des Benutzerparameters, oder nil
   if not Zitation.o then
       Zitation.o = { }
   end
   if type( Zitation.o[ area ] ) ~= "table" then
       Zitation.o[ area ] = { }
   end
   Zitation.o[ area ][ access ] = { s = alias    or
                                        string.format( "%s.%s",
                                                       area, access ),
                                    v = assign }

end -- Zitation.fill()


Zitation.filler = function ( args, assign )

   -- Parameterkomponenten zuweisen
   -- Parameter:
   --     args    -- Zfilter.object,
   --                mit Zuweisungen nach Vorlagenparametername
   --     assign  -- table, mit Transformation in neutrales Datenmodell
   local g, r, value
   if not Zitation.o then
       Zitation.o = { }
   end
   for k, v in pairs( assign ) do
       value = args{ k }
       if value then
           g = v[ 1 ]
           if not Zitation.o[ g ] then
               Zitation.o[ g ] = { }
           end
           Zitation.o[ g ][ v[ 2 ] ] = value
       end
   end -- for k, v

end -- Zitation.filler()


Zitation.filter = function ( args, allowed )

   -- Analysiere Argumentenliste und gleiche mit erlaubten Namen ab
   -- Parameter:
   --     args     -- table, mit aktuellen Werten
   --     allowed  -- table, mit erlaubten Namen, zugewiesen:
   --                        true   -- Nur diese Namensvariante bekannt
   --                        table  -- Namensvariationen
   --                                  Jeder Wert:
   --                                  true   -- unerwünscht, Meldung
   --                                  table  -- Details
   --                                  table  -- low=true: Keine Meldung
   -- Rückgabewerte:
   --     table, mit gefilterten Werten, nach Parametername
   --            Zfilter object
   --            Jede Komponente:
   --                 index-Zugriff:
   --                     string, mit Parameterwert, kein leerer string
   --                 get-Zugriff:
   --                     table, mit
   --                            s=Orginal-Parametername
   --                            v=Parameterwert, nicht leer
   local signatur = "__Zfilter"
   local meta     = { }
   local r        = { [ signatur ] = { } }
   local discard  = false
   local doubled  = false
   local un       = false
   local d, lapsus
   meta.__call     = function ( self, arglist )
                         -- Antwort auf:  Tabelle{ ... }
                         return self[ signatur ][ arglist[ 1 ] ]
                     end
   meta.__index    = function ( self, access )
                         -- Antwort auf:  ... = Tabelle[x]
                         local e = self[ signatur ][ access ]
                         if type( e ) == "table" then
                             e = e.v
                         end
                         return e
                     end
   meta.__newindex = function ( self, access, assign )
                      -- Antwort auf:  Tabelle[x] = ...
                         local put = assign
                         if assign  and
                            ( type( assign ) ~= "table"   or
                              not assign.v ) then
                             put = { s=access, v=assign }
                         end
                         self[ signatur ][ access ] = put
                         return
                     end
   setmetatable( r, meta )
   for s, v in pairs( args ) do
       d = allowed[ s ]
       if d then
           lapsus = false
           if type( d ) == "table" then
               for dk, dv in pairs( d ) do
                   if args[ dk ] then
                       if not doubled then
                           doubled = { }
                       end
                       if not doubled[ dk ] then
                           doubled[ tostring( s ) ] = dk
                       end
                   end
               end
           else
               d = false
           end
       elseif type( s ) == "string" then
           if d == false then
               if not discard then
                   discard = { }
               end
               table.insert( discard, s )
           else
               lapsus = true
           end
       else
           lapsus = true
           if v then
               if mw.text.trim( v ) == "" then
                   fehler( "Format", "Pipe '|' zu viel" )
               end
               v = false
           end
           s = tostring( s )
       end
       if lapsus then
           if not un then
               un = { }
           end
           un[ s ] = true
       end
       if v == "" then
           v = false
       end
       if v then
           r[ s ] = v
           if v:find( "", 1, true )   and
              type( s ) == "string" then
               fehler( "Wert",
                       string.format( "'%s' mit Wikisyntax", s ) )
           end
       end
   end -- for s, v
   if un then
       local down      = { }
       local scream    = false
       local undesired = false
       local unknown   = false
       local light, s, sa
       for k, v in pairs( allowed ) do
           s = mw.ustring.lower( k )
           down[ s ] = { standard=k }
           if type( v ) == "table" then
               for ka, va in pairs( v ) do
                   sa = mw.ustring.lower( ka )
                   if type( va ) == "table" then
                       va.standard = k
                   else
                       va = { standard=k }
                   end
                   down[ sa ] = va
               end
           end
       end -- for k, v
       for k, v in pairs( un ) do
           if type( k ) == "string" then
               s = mw.ustring.lower( k )
               d = down[ s ]
           else
               d = false
           end
           if d then
               if type( d ) == "table" then
                   light = d.low
                   s     = d.standard
               else
                   light = false
               end
               if r[ s ] then
                   if not doubled then
                       doubled = { }
                   end
                   if not doubled[ s ] then
                       doubled[ k ] = s
                   end
               else
                   r[ s ] = r{ k }
                   r[ k ] = nil
                   if not light then
                       if not undesired then
                           undesired = { }
                       end
                       undesired[ k ] = s
                   end
               end
           else
               if not unknown then
                   unknown = { }
               end
               unknown[ k ] = true
           end
       end -- for k, v
       if unknown then
           down = { }
           for k, v in pairs( allowed ) do
               if type( v ) == "table" then
                   sa = mw.ustring.lower( k )
                   for ka, va in pairs( v ) do
                       sa = mw.ustring.lower( ka )
                       if type( va ) == "table" then
                           va.standard = k
                       else
                           va = { standard=k }
                       end
                       down[ sa ] = va
                   end
               end
           end -- for k, v
           for k, v in pairs( unknown ) do
               if type( k ) == "string" then
                   s = mw.ustring.lower( k )
                   d = down[ s ]
                   if d then
                       if type( d ) == "table" then
                           light = d.low
                       else
                           light = false
                       end
                       s = d.standard
                       if r[ s ] then
                           if not doubled then
                               doubled = { }
                           end
                           doubled[ k ] = s
                       else
                           r[ s ] = r{ k }
                           r[ k ] = nil
                           if not light then
                               if not undesired then
                                   undesired = { }
                               end
                               undesired[ k ] = d.standard
                           end
                       end
                   else
                       if scream then
                           scream = scream .. ", "
                       else
                           scream = "Unbekannte Parameter: "
                       end
                       scream = scream .. k
                   end
               end
           end -- for k, v
           fehler( "Konflikt", scream )
           scream = false
       end
       if undesired then
           for k, v in pairs( undesired ) do
               if scream then
                   scream = scream .. ", "
               else
                   scream = ""
               end
               scream = string.format( "%s '%s' ist '%s'",
                                       scream, k, v )
           end -- for k, v
           fehler( "Name", scream )
           scream = false
       end
   end
   if doubled then
       for k, v in pairs( doubled ) do
           if scream then
               scream = scream .. ","
           else
               scream = "Parameterwerte gedoppelt: "
           end
           scream = string.format( "%s '%s' ./. '%s'",
                                   scream, k, v )
       end -- for k, v
       fehler( "Konflikt", scream )
       scream = false
   end
   if discard then
       for k, v in pairs( discard ) do
           fehler( "Entfernen",  v .. "=" )
       end -- for k, v
   end
   return r

end -- Zitation.filter()


Zitation.format = function ()

   -- Generiere Zitation
   -- Rückgabewert:
   --     1  -- string mit Vorlagenresultat
   --     2  -- string mit Fehlermeldung(en) und -kategorien, oder false
   local s
   Resultat = ""
   foreign( "bas", "Sprache" )
   autorHrsg()
   titel()       -- Schließt mit Punkt etc.
   werk()        -- Schließt mit Punkt etc.
   reihe()
   auflage()     -- Schließt mit Punkt
   endBlock()    -- Schließt mit Punkt
   Resultat = Resultat:gsub( " ",
                             " ")
   coins()
   s = fehlerliste()
   if s == "" then
       s = false
   end
   return Resultat, s

end -- Zitation.format()


Zitation.COinS = function ( args, assign, already )

   -- Create string with COinS 
   -- Parameter:
   --     args     -- table, with COinS components
   --     assign   -- optional string, with ID
   --     already  -- optional string, with preformatted &sequence
   -- Returns HTML element string
   local Text  = Zitation.fetch( "Text" )
   local WLink = Zitation.fetch( "WLink" )
   local rft   = { }
   local site  = mw.site.server:gsub( "^%l*:?//", "" )
   local s, sub, v
   if assign then
       sub = assign
   else
       if args.genre then
           sub = args.genre
       else
           sub = "book"
       end
   end
   if args.isbn then
       args.isbn = args.isbn:gsub( "-", "" ):upper()
   end
   s = string.format( "%s%s%s",
                      "ctx_ver=Z39.88-2004",
                      "&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3A",
                      sub )
   if not args.genre then
       s = s .. "&rft.genre=book"
   end
   if type( assign ) == "string" then
       sub = assign
   else
       sub = mw.title.getCurrentTitle().fullText
   end
   s = string.format( "%s&rfr_id=info:sid/%s:%s",
                      s,
                      site,
                      mw.uri.encode( sub ) )
   if already then
       s = s .. already
   end
   for k, v in pairs( args ) do
      table.insert( rft, k )
   end -- for k, v
   table.sort( rft )
   for i = 1, #rft do
       sub = rft[ i ]
       v   = args[ sub ]
       if type( v ) == "table" then
           if type( v.tostring ) == "function" then
               v = v.tostring()
           end
       end
       if type( v ) == "string" then
           v = mw.uri.encode( WLink.getPlain( Text.getPlain( v ) ) )
                            :gsub( "%%E2%%80%%93", "-" )
           s = string.format( "%s&rft.%s=%s", s, sub, v )
       end
   end -- for i
   s = string.format( "%s",
                      s,
                      "style='display:none'",
                      " " )
   return s

end -- Zitation.COinS()


Zitation.ISBN = function ( access, accept, alert )

   -- Create string with formatted ISBN
   -- Parameter:
   --     access   -- string, with presumable ISBN
   --     accept   -- optional number, whether invalid data is permitted
   --                  0, nil   -- require valid ISBN
   --                 -1        -- ignore invalid check digit
   --                 other     -- other, e.g. number of digits
   --     alert    -- optional string, with maintenance category title
   -- Returns:
   --     1  -- string, for display
   --     2  -- true, if conditions not matched
   local URIutil = Zitation.fetch( "URIutil" )
   local mode  = accept or 0
   local isbn, lapsus, legal, lethal, r
   if mode == -1 then
       legal, isbn = URIutil.isISBN( access )
       if legal then
           if URIutil.isISBNvalid( access ) then
               fehler( "Wert", "'ISBN' ist nicht formal falsch" )
           else
               lapsus = true
           end
       end
   elseif mode == 0 then
       legal, isbn = URIutil.isISBNvalid( access )
   else
       legal, isbn  = URIutil.isISBN( access )
       if isbn == -1 then
           lapsus = true
           legal  = true
           lethal = true
       end
   end
   if legal then
       if lethal then
           r = URIutil.linkISBN( access, true, true, true, alert )
       else
           r = "ISBN " .. URIutil.formatISBN( access, isbn )
       end
       if lapsus then
           local plus = mw.html.create( "small" )
           local show, story
           if lethal then
               show  = "defekt"
               story = "WP:ISBNdefekt"
           else
               show  = "formal falsch"
               story = "WP:ISBNformalFalsch"
           end
           if story then
               show = string.format( "%s", story, show )
           end
           show = string.format( "(%s)", show )
           plus:addClass( "ISBN-bad-code" )
               :css( "white-space", "nowrap" )
               :wikitext( show )
           r = string.format( "%s %s", r, tostring( plus ) )
       end
   else
       r = string.format( "ISBN %s%s",
                          access,
                          Zitation.fault( "(?!)", true ) )
       fehler( "Wert", "'ISBN'" )
       fire( "ISBN" )
   end
   return r, legal

end -- Zitation.ISBN()


-- Export ===============================================================

local p = { }

p.Endpunkt = function ( frame )

   -- LEGACY für Vorlage:Internetquelle
   local r = ""
   local s = frame.args.titel
   if s then
       local Text = Zitation.fetch( "Text" )
       if Text.sentenceTerminated( s ) then
           r = ""
       else
           r = "."
       end
   end
   return r

end -- p.Endpunkt


p.TitelFormat = function ( frame )

   -- LEGACY für Vorlage:Internetquelle
   local r = ""
   local s = frame.args.titel
   if s then
       local Text = Zitation.fetch( "Text" )
       if Text.sentenceTerminated( s ) then
           r = s
       else
           r = s .. "."
       end
       r = string.format( "%s", r )
   end
   return r

end -- p.TitelFormat


p.COinS_Template = function ( frame )

   local l, r = pcall( Zitation.COinS, frame:getParent().args )
   return r

end -- p.COinS_Template


p.ISBN = function ( frame )

   local mode = frame.args[ 2 ]
   if mode then
       mode = tonumber( mode )
   end
   if frame.args.template then
       Selbst = frame.args.template
   end
   local l, r = pcall( Zitation.ISBN,
                       frame.args[ 1 ],
                       mode,
                       frame.args.link )
   return r

end -- p.ISBN


function p.failsafe()

   return Zitation.serial

end


p.Zitation = function ()

   return Zitation

end -- p.Zitation

return p