Mô đun:Cite Q

-- Version: 2021-02-21
local p = {}
require('strict')
local wdib = require('Module:WikidataIB')
local getValue = wdib._getValue
local getPropOfProp = wdib._getPropOfProp
local followQid = wdib._followQid
local getPropertyIDs = wdib._getPropertyIDs
local i18n = {
	"unknown-author" = mw.wikibase.getLabel("Q4233718"):gsub("^%l", mw.ustring.upper),
	"unknown-author-trackingcat" = "Thể loại:Chú thích Q - tác giả không rõ",
}
-------------------------------------------------------------------------------
-- takes cardinal number as a numeric and returns the ordinal as a string
-------------------------------------------------------------------------------
p.makeOrdinal = function(cardinal)
	return card
end
-- Table of simple properties that can be fetched in roughly the same way:
-- id = PXXX
-- maxvals = maximum number of multiple values (0 for all)
-- linked = "no" suppresses linking
-- populate_from_journal = true/false determines whether to look in a journal where the source is published
-- rank = "best", "preferred", normal, etc. determines how Wikidata ranks are treated
-- others = true - the value for the property goes to "others" section
local simple_properties = {
	publisher = {id = "P123", maxvals = 1},
	oclc = {id = "P243", maxvals = 1},
	'publication-place' = {id = "P291", maxvals = 0, linked = 'no'}, -- publication place (don't put into |place=; is treated specially in  if both are given)
	doi = {id = "P356", maxvals = 1}, -- take care of |doi-broken-date= (WD "reason for deprecation"/"stated as") and |doi-access= (WD "access status")?
	issue = {id = "P433", maxvals = 0, populate_from_journal = true}, -- distinguish from |number= ("P1545"?) if both are given (still blocked by , but will be supported in the future)
	pmid = {id = "P698", maxvals = 1},
--	gbooks = {id = "P675", maxvals = 1}, -- to be added to 
--	ia = {id = "P724", maxvals = 1}, -- to be added to 
	arxiv = {id = "P818", maxvals = 1},
	bibcode = {id = "P819", maxvals = 1}, -- take care of |bibcode-access=?
	jstor = {id = "P888", maxvals = 1}, -- take care of |jstor-access=?
	mr = {id = "P889", maxvals = 1},
	rfc = {id = "P892", maxvals = 1},
	zbl = {id = "P894", maxvals = 1},
	ssrn = {id = "P893", maxvals = 1},
	place = {id = "P1071", maxvals = 0, linked = 'no'}, -- written-at place
--	'total-pages' = {id = "P1104", maxvals = 0, linked = 'no'}, -- to be added to  / COinS &rft.tpages=
--	coden = {id = "P1159", maxvals = 1}, -- to be added to  / COinS &rft.coden=
	s2cid = {id = "P8299", maxvals = 1}, -- take care of |s2cid-access=?
	pmc = {id = "P932", maxvals = 1}, -- take care of |pmc-embargo-date= (WD "reason for deprecation")?
	lccn = {id = "P1144", maxvals = 1},
	hdl = {id = "P1184", maxvals = 1}, -- take care of |hdl-access=?
	ismn = {id = "P1208", maxvals = 1},
	journal = {id = "P1433", maxvals = 1},
	citeseerx = {id = "P3784", maxvals = 1},
	osti = {id = "P3894", maxvals = 1}, -- take care of |osti-access=?
	biorxiv = {id = "P3951", maxvals = 1},
	asin = {id = "P5749", maxvals = 1}, -- What about |asin-tld=? (WD examples resolve to .com at present, but may change)
--	'catalog-number' = {id = "P528", maxvals = 0}, -- to be added to  / COinS &rft.artnum=
	isbn = {id = "P212", maxvals = 1, populate_from_journal = true}, -- ISBN 13
	issn = {id = "P236", maxvals = 1, populate_from_journal = true}, -- distinguish from |eissn= for electronic issues?
--	jfm = {id = "P?", maxvals = 1}, -- Jahrbuch über die Fortschritte der Mathematik (not Zbl)
--	sbn = {id = "P?", maxvals = 1}, -- Standard Book Number (predecessor of ISBN, not ICCU)
--	message-id = {id = "P?", maxvals = 1}, -- Usenet message ID
	chapter = {id = "P792", maxvals = 1},
	'publication-date' = {id = "P577", maxvals = 1, populate_from_journal = true}, -- publication date (don't use |date=; is treated specially in  if both are given.)
	series = {id = "P179", maxvals = 1, populate_from_journal = true},
	version = {id = "P348", maxvals = 0},
	edition = {id = "P393", maxvals = 0},
	volume = {id = "P478", maxvals = 0, populate_from_journal = true},
--	part = {id = "P1545"?, maxvals = 0}, --  to be added to  / COinS &rft.part=
	title = {id = "P1476", rank="p n"},
--	url = {id = "P953", maxvals = 1}, -- deal with this along with archive-url
	pages = {id = "P304", maxvals = 0, populate_from_journal = true},
	at = {id = "P958", maxvals = 0, populate_from_journal = true}, -- also incorporate lines (P7421) and columns (P3903) into this (cite map also supports |section=)
--	sheets = {id = "P7416", maxvals = 0, populate_from_journal = true},
--	interviewer = {id = "P?", maxvals = 0}, -- does **not** go to "others" section! Multiple interviewers should be n-enumerated
	illustrator = {id = "P110", maxvals = 10, others = true}, -- goes to "others" section
-- foreword and afterword, when contributions to another author's work, are contributions so belong in |contribution=;
-- the writer's name goes in |contributor=; requires |title= and |author=
-- However, this might need to add support for multiple contributors and their roles to , see Help_talk:Citation_Style_1#Others
--	foreword = {id = "P2679", maxvals = 10, others = true}, -- goes to "others" section
--	afterword = {id = "P2680", maxvals = 10, others = true}, -- goes to "others" section
	composer = {id = "P86", maxvals = 10, others = true}, -- goes to "others" section
	animator = {id = "P6942", maxvals = 10, others = true}, -- goes to "others" section
	director = {id = "P57", maxvals = 10, others = true}, -- goes to "others" section
	screenwriter = {id = "P58", maxvals = 10, others = true}, -- goes to "others" section
	signatory = {id = "P1891", maxvals = 10, others = true}, -- goes to "others" section
	presenter = {id = "P371", maxvals = 10, others = true}, -- goes to "others" section
	performer = {id = "P175", maxvals = 10, others = true}, -- goes to "others" section
}
------------------------------------------------------------------------------------------
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.
local function is_set( var )
	return not (var == nil or var == )
end
------------------------------------------------------------------------------------------
Whether needle is in haystack (taken from Module:Citation/CS1/Utilities)
local function in_array( needle, haystack )
	if needle == nil then
		return false
	end
	for n, v in ipairs( haystack ) do
		if v == needle then
			return n
		end
	end
	return false
end
-----------------------------------------------------------------------------------
Accept WD value by framing in ((...)) if param_val is equal to keyword; else pass-through WD value as is.
local function accept_value( param_val, wd_val )
	local val = param_val
	if val then
		if in_array (val, {'accept', '))((', ':d:'}) then
			val = '((' .. wd_val .. '))'
		elseif '((accept))' == val then
			val = 'accept'
		elseif '(())(())' == val then
			val = '))(('
		elseif '((:d:))' == val then
			val = ':d:'
		else
			val = wd_val
		end
	end
	return val
end
-- function to fetch a value to display
local function makelink(v, out, link, maxpos, wdl)
	local label
	if v.mainsnak.snaktype == "value" then
		if v.mainsnak.datatype == "wikibase-item" then
			local qnumber = v.mainsnak.datavalue.value.id
			local sitelink = mw.wikibase.getSitelink(qnumber)
			if qnumber == "Q2818964" then sitelink = nil end -- suppress link to "Various authors"
			if v.qualifiers and v.qualifiers.P1932 then
				label = v.qualifiers.P19321.datavalue.value
			elseif v.qualifiers and v.qualifiers.P1810 then
				label = v.qualifiers.P18101.datavalue.value
			else
				label = mw.wikibase.getLabel(qnumber)
				if label then
					label = mw.text.nowiki(label)
				else
					label = qnumber -- should add tracking category
				end
			end
			local position = maxpos + 1 -- Default to 'next' author.
			-- use P1545 (series ordinal) instead of default position.
			if v"qualifiers" and v.qualifiers"P1545" and v.qualifiers"P1545"1 then
				position = tonumber(v.qualifiers"P1545"1.datavalue.value)
			end
			maxpos = math.max(maxpos, position)
			if sitelink then
				-- just the plain name,
				-- but keep a record of the links, using the same index
				outposition = label
				linkposition = sitelink
			else
				if wdl then
					-- show that there's a Wikidata entry available
					outposition = ":d:Q" .. v.mainsnak.datavalue.value"numeric-id" .. "|" .. label .. " link="
				else
					-- no Wikidata links wanted, so just give the plain label
					outposition = label
				end
			end
		elseif v.mainsnak.datatype == "string" then
			local position = maxpos + 1 -- Default to 'next' author.
			-- use P1545 (series ordinal) instead of default position.
			if v"qualifiers" and v.qualifiers"P1545" and v.qualifiers"P1545"1 then
				position = tonumber(v.qualifiers"P1545"1.datavalue.value)
			end
			maxpos = math.max(maxpos, position)
			outposition = v.mainsnak.datavalue.value
		else
			-- not a wikibase-item or a string!
		end
	else
		-- code here if we want to return something when author is "unknown"
		if v.qualifiers and v.qualifiers.P1932 then
			label = v.qualifiers.P19321.datavalue.value
		elseif v.qualifiers and v.qualifiers.P1810 then
			label = v.qualifiers.P18101.datavalue.value
		else
			label = i18n"unknown-author" .. (i18n"unknown-author-trackingcat" or "")
		end
		maxpos = maxpos + 1
		outmaxpos = label
	end
	return maxpos
end
--=wdl= parameter; a Boolean passed to enable links to Wikidata when no article exists
returns nothing; modifies the args table
**
local function get_name_list (nl_type, args, qid, wdl)
	local propertyID = "P50"
	local fallbackID = "P2093" -- author name string
	if nl_type =="author" then
		propertyID = 'P50'		-- for authors
		fallbackID = 'P2093'	-- author-string
	elseif nl_type =="editor" then
		propertyID = 'P5769'	-- "editor-in-chief"
		fallbackID = 'P98'		-- for editors - So-called "fallbacks" are actually a second set of properties processed
		-- TBD. Take book series editors into account as well (if they have a separate P code as well)?
	elseif nl_type == "translator" then
		propertyID = 'P655'		-- for translators
		fallbackID = nil
--	elseif 'contributor' == nl_type then
--		f.e. author of forewords (P2679) and afterwords (P2680); requires |contribution=, |title= and |author=
--		propertyID = 'P'		-- for contributors
--		fallbackID = nil
	else
		return					-- not specified so return
	end
	-- wdl is a Boolean passed to enable links to Wikidata when no article exists
	-- if "false" or "no" or "0" is passed set it false
	-- if nothing or an empty string is passed set it false
	if wdl and (#wdl > 0) then
		wdl = wdl:lower()
		wdl = in_array (wdl, {"false", "no", "0"})
	else
		-- wdl is empty, so
		wdl = false
	end
	local props = nil
	local fallback = nil
	if mw.wikibase.entityExists(qid) then
		props = mw.wikibase.getAllStatements(qid, propertyID)
		if props and fallbackID then
			fallback = mw.wikibase.getAllStatements(qid, fallbackID)
		end
	end
	-- Make sure it actually has at least one of the properties requested
	if not (props and props1) and not (fallback and fallback1) then
		return nil
	end
	-- So now we have something to return:
	-- table 'out' is going to store the names(s):
	-- and table 'link' will store any links to the name's article
	local out = {}
	local link = {}
	local maxpos = 0
	if props and props1 then
		for k, v in pairs(props) do
			maxpos = makelink(v, out, link, maxpos, wdl)
		end
	end
	if fallback and fallback1 then
		-- second properties
		for k, v in pairs(fallback) do
			maxpos = makelink(v, out, link, maxpos, wdl)
		end
	end
	-- if there's anything to return, then insert the additions in the template arguments table
	-- in the form |author1=firstname secondname |author2= ...
	-- Renumber, in case we have inconsistent numbering
	local keys = {}
	for k, v in pairs(out) do
		keys#keys + 1 = k
	end
	table.sort(keys) -- as they might be out of order
	for i, k in ipairs(keys) do
		mw.log(i .. " " .. k .. " " .. (outk))
		if argsnl_type .. i then -- name gets overwritten
			-- pull corresponding -link only if overwritten name is same as WD name
			if linkk and (argsnl_type .. i == outk) then
				argsnl_type .. '-link' .. i = argsnl_type .. '-link' .. i or linkk -- author-linkn or editor-linkn
			end
		else -- name does not get overwritten, so pull name from WD
			argsnl_type .. i = outk
			if linkk then
				argsnl_type .. '-link' .. i = argsnl_type .. '-link' .. i or linkk -- author-linkn or editor-linkn
			end
		end
	end
end
-- gets language codes used for a monolingual text property as a table
function p._getLangOfProp(qid, pid)
	if not pid then return {} end
	local out = {}
	local props = mw.wikibase.getAllStatements(qid, pid)
	for i, v in ipairs(props) do
		if v.mainsnak.datatype == "monolingualtext" and v.mainsnak.datavalue then
			out#out + 1 = v.mainsnak.datavalue.value.language
		end
	end
	return out
end
function p.getLangOfProp(frame)
	local pid = frame.args.pid or mw.text.trim(frame.args1 or "")
	if pid == "" then return end
	local qid = frame.args.qid
	if qid == "" then qid = nil end
	return table.concat(p._getLangOfProp(qid, pid), ", ")
end
-- gets the language codes of a Wikidata entry as a table
local function _lang_code(qid)
	local lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P424", ps = 1} )
	if lc then return mw.text.split( lc, ", +" ) end
	lc = getPropOfProp( {qid = qid, prop1 = "P407", prop2 = "P218", ps = 1} )
	if lc then return mw.text.split( lc, ", +" ) end
	return p._getLangOfProp(qid, "P1476")
end
function p.lang_code(frame)
	return table.concat(_lang_code(frame.args.qid or mw.text.trim(frame.args1 or "")), ", ")
end
-- export for debug
function p.getPropOfProp(frame)
	return getPropOfProp(frame.args)
end
-- wraps a string in nowiki unless disable flag is set
local function wrap_nowiki(str, disable)
	if disable then return str or  end
	return mw.text.nowiki(str or )
end
-- sort sequence table whose values are key-value pairs by key
local function comp_key(a, b)
	return a1 ------------------------------------------------------------------
Takes standard CS1|2 template parameters and passes all to .  If neither of |author= and |author1=
are set, calls get_authors() to try to get an author name-list from Wikidata.  The result is passed to
for rendering.
--
function p._cite_q (citeq_args)
	local frame = mw.getCurrentFrame()
	-- parameters that don't get passed to Citation
	local expand = citeq_args.expand -- when set to anything, causes  to render 
	local qid = citeq_args1 or citeq_args.qid
	local wdl = citeq_args.wdl
	local template = citeq_args.template
	citeq_args.expand = nil
	citeq_args1 = nil
	citeq_args.qid = nil
	citeq_args.wdl = nil
	citeq_args.template = nil
	-- if title supplied, flag to not read html title
	local titleforced = (citeq_args.title ~= nil)
	local oth = {}
	-- put the language codes into a sequential table langcodes
	local langcodes = {}
	if citeq_args.language then
		-- check these are a supported language codes
		for lc in mw.text.gsplit( citeq_args.language, ", +", false ) do
			langcodes#langcodes+1 = mw.language.isSupportedLanguage(citeq_args.language) and citeq_args.language
		end
	end
	if not langcodes1 then
		-- try to find language of work
		langcodes = _lang_code(qid)
	end
	if not langcodes1 then
		-- try fallback to journal's language
		local journal_qid = followQid({qid = qid, props = "P1433"})
		langcodes = journal_qid and _lang_code(journal_qid)
	end
	citeq_args.language = citeq_args.language or table.concat(langcodes, ", ")
	-- loop through list of simple properties and get their values in citeq_args
	for name, data in pairs(simple_properties) do
		citeq_argsname = getValue( {data.id, fwd = "ALL", osd = "no", noicon = "true", qid = qid, maxvals = data.maxvals, linked = data.linked, rank = data.rank or "best", citeq_argsname } )
		if data.populate_from_journal then
			local publishedin = getValue( {"P1433", ps = 1, qid = qid, maxvals = 0, citeq_argsname, qual = data.id, qualsonly = 'yes'} )
			citeq_argsname = publishedin or getPropOfProp({qid = qid, prop1 = "P1433", prop2 = data.id, maxvals = data.maxvals, ps = 1})
		end
		if citeq_argsname and citeq_argsname:find(, 1, true) then
			-- try fallback to work's native language
			citeq_argsname = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = langcodes1 } )
			if citeq_argsname:find('^Q%d+$') then -- qid was returned
				-- try fallback to qid's native language
				local qid_languages = _lang_code(citeq_argsname)
				citeq_argsname = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = qid_languages1 } )
				if citeq_argsname:find('^Q%d+$') then -- qid was returned again
					citeq_argsname = nil
				else
					-- record the language found if no lang specified
					citeq_args.language = citeq_args.language or qid_languages1
				end
			end
		end
		if data.others then
			oth#oth + 1 = citeq_argsname and (name:gsub("^%l", string.upper) .. ": " .. citeq_argsname)
			citeq_argsname = nil
		end
	end
	citeq_args.others = citeq_args.others or table.concat(oth, ". ")
	if citeq_args.others == "" then
		citeq_args.others = nil
	end
	citeq_args.journal = citeq_args.journal and citeq_args.journal:gsub("^", ""):gsub("$", ""):gsub("|", "|"):gsub("", "")
	citeq_args.ol = (getValue( {"P648", ps = 1, qid = qid, maxvals = 1, citeq_args.ol } ) or ):gsub("^OL(.+)$", "%1")
	if citeq_args.ol == "" then
		citeq_args.ol = nil
	end
	-- TBD. Take care of |ol-access=?
	citeq_args.biorxiv = citeq_args.biorxiv and ("10.1101/" .. citeq_args.biorxiv)
	citeq_args.isbn = getValue( {"P957", ps = 1, qid = qid, maxvals = 1, rank="best", citeq_args.isbn } ) -- try ISBN 10 (only one value accepted)
	-- if url then see if there's an archive: citeq_args.url
	local url
	if not citeq_args.url then
		for i, pr in ipairs( {"P953", "P856", "P2699"} ) do
			url = getValue( {pr, ps = 1, qid = qid, maxvals = 1, qual="P1065" } )
			if url then
				citeq_args.url = mw.text.split( url, " (", true )1
				local arcurl = mw.ustring.match( url, "%((.*)%)" )
				if arcurl then
					local arcy, arcm, arcd = arcurl:match("(20%d%d)%p?(%d%d)%p?(%d%d)")
					if arcy and arcm and arcd then
						citeq_args"archive-url" = arcurl
						citeq_args"archive-date" = "ngày " .. tonumber(arcd) .. " tháng " .. tonumber(arcm) .. " năm " .. arcy
					end
				end
				break
			end
		end
	end
	if citeq_args.publisher == "Unknown" then -- look for "stated as" (P1932)
		local stated_as = getValue( {"P123", ps = 1, qid = qid, maxvals = 1, qual="P1932", qo="y"} )
		if stated_as then citeq_args.publisher = stated_as end
	end
	if not titleforced then
		local htmltitle = getValue( {"P1476", qual = "P6833", ps = 1, qid = qid, maxvals = 1, qo = "y"} )
		if htmltitle then
			citeq_args.title = htmltitle:gsub("", "")
		else
			local title_display = citeq_args.title
				or mw.wikibase.getLabel(qid)
				or (langcodes1 and mw.wikibase.getLabelByLang(qid, langcodes1))
				or ("No label or title -- debug: " .. qid)
			if citeq_args.url then
				citeq_args.title = wrap_nowiki(title_display)
			else
				local slink = mw.wikibase.getSitelink(qid)
				local slink_flag = false
				local wrap_title = 
				local wslink = false
				if not slink then
					-- See if we have wikisource
					if not citeq_args.url then
						local wikisource_sitelink = mw.wikibase.getSitelink(qid, "enwikisource") or nil
						if wikisource_sitelink then
							slink = ':s:'..wikisource_sitelink
							wslink = true
						end
					end
				end
				if citeq_args.title then
					if slink then
						wrap_title = wrap_nowiki(citeq_args.title)
						slink_flag = true
					else
						citeq_args.title = wrap_nowiki(citeq_args.title)
					end
				else
					if slink and not wslink then
						if slink:lower() == title_display:lower() then
							citeq_args.title =  .. slink .. 
						else
							wrap_title = wrap_nowiki(slink:gsub("%s%(.+%)$", ""):gsub(",.+$", ""))
							slink_flag = true
						end
					elseif wslink then
						wrap_title = wrap_nowiki(title_display)
						slink_flag = true
					else
						citeq_args.title = wrap_nowiki(title_display)
					end
				end
				if slink_flag then
					if slink == wrap_title and not wslink then -- direct link
						citeq_args.title =  .. slink .. 
					else -- piped link
						citeq_args.title =  .. wrap_title .. 
					end
				end
			end
		end
	end
	-- TBD: incorporate |at, |sheets= and |sheet= here as well
	-- Sort out what should happen if several of them are given at the same time
	if citeq_args.page or citeq_args.p then -- let single take precedence over multiple
		citeq_args.pages = nil
		citeq_args.pp = nil
	end
	if citeq_args.pages then
		local _, count = string.gsub(citeq_args.pages, ",;%s%d+", "")
		if count == 1 then
			citeq_args.page = citeq_args.pages
			citeq_args.pages = nil
		end
	end
	if is_set (qid) then
		if not is_set (citeq_args.author) and not is_set (citeq_args.author1)
			and not is_set (citeq_args.subject) and not is_set (citeq_args.subject1)
			and not is_set (citeq_args.host) and not is_set (citeq_args.host1)
			and not is_set (citeq_args.last) and not is_set (citeq_args.last1)
			and not is_set (citeq_args.surname) and not is_set (citeq_args.surname1)
			and not is_set (citeq_args'author-last') and not is_set (citeq_args'author-last1') and not is_set (citeq_args'author1-last')
			and not is_set (citeq_args'author-surname') and not is_set (citeq_args'author-surname1') and not is_set (citeq_args'author1-surname1') then	-- if neither are set, try to get authors from Wikidata
			get_name_list ('author', citeq_args, qid, wdl)				-- modify citeq_args table with authors from Wikidata
		end
		if not is_set (citeq_args.editor) and not is_set (citeq_args.editor1)
			and not is_set (citeq_args'editor-last') and not is_set (citeq_args'editor-last1') and not is_set (citeq_args'editor1-last')
			and not is_set (citeq_args'editor-surname') and not is_set (citeq_args'editor-surname1') and not is_set (citeq_args'editor1-surname') then	-- if neither are set, try to get editors from Wikidata
			get_name_list ('editor', citeq_args, qid, wdl)				-- modify citeq_args table with editors from Wikidata
		end
		if not is_set (citeq_args.translator) and not is_set (citeq_args.translator1)
			and not is_set (citeq_args'translator-last') and not is_set (citeq_args'translator-last1') and not is_set (citeq_args'translator1-last')
			and not is_set (citeq_args'translator-surname') and not is_set (citeq_args'translator-surname1') and not is_set (citeq_args'translator1-surname') then	-- if neither are set, try to get translators from Wikidata
			get_name_list ('translator', citeq_args, qid, wdl)			-- modify citeq_args table with translators from Wikidata
		end
	end
	for k, v in pairs(citeq_args) do
		if in_array (v, {'(())', 'unset', 'ignore'}) or 'string' ~= type(k) then -- empty accept-as-is-written (()) markup to indicate an empty/unused parameter value, other ((...)) markups are deliberately passed down to 
			citeq_argsk = nil
		elseif in_array (v, {'((unset))', '((ignore))'}) then -- strip off markup for free-text values clashing with local keywords
			citeq_argsk = 'unset'
		end
	end
	local author_count = 0
	for k, v in pairs(citeq_args) do
		if k:find("^author%d+$") then
			author_count = author_count + 1
		end
	end
	if author_count > 8 then -- convention in astronomy journals, optional mode for this?
		citeq_args'display-authors' = citeq_args'display-authors' or 3
	end
	local editor_count = 0
	for k, v in pairs(citeq_args) do
		if k:find("^editor%d+$") then
			editor_count = editor_count + 1
		end
	end
	if editor_count > 8 then -- convention in astronomy journals, optional mode for this?
		citeq_args'display-editors' = citeq_args'display-editors' or 3
	end
	-- change edition to ordinal if it's set and numeric
	citeq_args.edition = citeq_args.edition and p.makeOrdinal(citeq_args.edition)
	-- code to make a guess what template to use from the supplied parameters
	-- (first draft for proof-of-concept)
	if citeq_args.isbn then
		template = template or "book"
		citeq_args.asin = nil -- suppress ASIN if ISBN exists
	elseif citeq_args.journal then
		template = template or "journal"
	elseif citeq_args.website then
		template = template or "web"
	end
	-- template is CS1 designator: journal, web, news, etc.
	if template then
		citeq_args.mode = citeq_args.mode or "cs1"
		template = "Cite " .. template
	else
		citeq_args.mode = citeq_args.mode or "cs2"
		template = "Citation"
	end
	-- |id= could hold more than one identifier pulled from Wikidata not supported by , right now only add our qid to the list
	local list_sep = '. '
	if citeq_args.mode ~= 'cs1' then
		list_sep = ', '
	end
	local id = 'Wikidata ' .. qid ..  -- go through "WDQ (identifier)" redirect to reduce clutter in "What links here" and improve reverse lookup. Keep in sync with .
	local old_id = citeq_args.id
	if wdl then -- show WD logo
		id = id .. 'link=' -- possibly replace by WD edit icon?
	end
	if is_set (old_id) then
		citeq_args.id = old_id .. list_sep .. id -- append to user-specified contents
	else
		citeq_args.id = id
	end
	-- clean up any blank parameters
	for k, v in pairs(citeq_args) do
		if v == "" then citeq_argsk = nil end
	end
	-- if |expand=, write a nowiki'd version to see what the  template call looks like
	if expand then
		local expand_args = { "