Bước tới nội dung

Mô đun:Cite Q

Bách khoa toàn thư mở Wikipedia
-- Version: 2021-02-21local p = {}require('strict')local wdib = require('Module:WikidataIB')local getValue = wdib._getValuelocal getPropOfProp = wdib._getPropOfProplocal followQid = wdib._followQidlocal getPropertyIDs = wdib._getPropertyIDslocal 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 cardend-- 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" sectionlocal 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 {{citation}} 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 {{citation}}, but will be supported in the future)	pmid = {id = "P698", maxvals = 1},--	gbooks = {id = "P675", maxvals = 1}, -- to be added to {{citation}}--	ia = {id = "P724", maxvals = 1}, -- to be added to {{citation}}	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 {{citation}} / COinS &rft.tpages=--	coden = {id = "P1159", maxvals = 1}, -- to be added to {{citation}} / 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 {{citation}} / 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 {{citation}} 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 {{citation}} / 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 {{citation}}, 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}--[[--------------------------< I S _ S E T >--------------------------------------------------------------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--[[--------------------------< I N _ A R R A Y >--------------------------------------------------------------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 falseend--[[--------------------------< A C C E P T _ V A L U E >-------------------------------------------------------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 valend-- function to fetch a value to displaylocal 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.P1932[1].datavalue.value			elseif v.qualifiers and v.qualifiers.P1810 then				label = v.qualifiers.P1810[1].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				out[position] = label				link[position] = sitelink			else				if wdl then					-- show that there's a Wikidata entry available					out[position] = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]&nbsp;<span title='" .. i18n["errors"]["local-article-not-found"] .. "'>[[File:Wikidata-logo.svg|16px|alt=|link=]]</span>"				else					-- no Wikidata links wanted, so just give the plain label					out[position] = 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)			out[position] = 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.P1932[1].datavalue.value		elseif v.qualifiers and v.qualifiers.P1810 then			label = v.qualifiers.P1810[1].datavalue.value		else			label = i18n["unknown-author"] .. (i18n["unknown-author-trackingcat"] or "")		end		maxpos = maxpos + 1		out[maxpos] = label	end	return maxposend--[=[-------------------------< G E T _ N A M E _ L I S T >----------------------------------------------------get_name_list -- adapted from getAuthors code taken from Module:RexxSarguments:	nl_type - type of name list to fetch: nl_type = 'author' for authors; 'editor' for editors; 'translator' for translators	args - pointer to the parameter arguments table from the template call	qid - value from |qid= parameter; the Q-id of the source (book, etc.) in qid	wdl - value from the |wdl= parameter; a Boolean passed to enable links to Wikidata when no article existsreturns 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 props[1]) and not (fallback and fallback[1]) 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 props[1] then		for k, v in pairs(props) do			maxpos = makelink(v, out, link, maxpos, wdl)		end	end	if fallback and fallback[1] 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 .. " " .. (out[k]))		if args[nl_type .. i] then -- name gets overwritten			-- pull corresponding -link only if overwritten name is same as WD name			if link[k] and (args[nl_type .. i] == out[k]) then				args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn			end		else -- name does not get overwritten, so pull name from WD			args[nl_type .. i] = out[k]			if link[k] then				args[nl_type .. '-link' .. i] = args[nl_type .. '-link' .. i] or link[k] -- author-linkn or editor-linkn			end		end	endend-- gets language codes used for a monolingual text property as a tablefunction 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 outendfunction p.getLangOfProp(frame)	local pid = frame.args.pid or mw.text.trim(frame.args[1] 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 tablelocal 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")endfunction p.lang_code(frame)	return table.concat(_lang_code(frame.args.qid or mw.text.trim(frame.args[1] or "")), ", ")end-- export for debugfunction p.getPropOfProp(frame)	return getPropOfProp(frame.args)end-- wraps a string in nowiki unless disable flag is setlocal 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 keylocal function comp_key(a, b)	return a[1] < b[1]end-- sort sequence table whose values are key-value pairs by valuelocal function comp_val(a, b)	return a[2] < b[2]end--[[-------------------------< C I T E _ Q >------------------------------------------------------------------Takes standard CS1|2 template parameters and passes all to {{citation}}.  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{{citation}} 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 {{cite q}} to render <code><nowiki>{{citation|...}}</nowiki></code>	local qid = citeq_args[1] or citeq_args.qid	local wdl = citeq_args.wdl	local template = citeq_args.template	citeq_args.expand = nil	citeq_args[1] = 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 langcodes[1] then		-- try to find language of work		langcodes = _lang_code(qid)	end	if not langcodes[1] 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_args[name] = getValue( {data.id, fwd = "ALL", osd = "no", noicon = "true", qid = qid, maxvals = data.maxvals, linked = data.linked, rank = data.rank or "best", citeq_args[name] } )		if data.populate_from_journal then			local publishedin = getValue( {"P1433", ps = 1, qid = qid, maxvals = 0, citeq_args[name], qual = data.id, qualsonly = 'yes'} )			citeq_args[name] = publishedin or getPropOfProp({qid = qid, prop1 = "P1433", prop2 = data.id, maxvals = data.maxvals, ps = 1})		end		if citeq_args[name] and citeq_args[name]:find('[[Category:Articles with missing Wikidata information]]', 1, true) then			-- try fallback to work's native language			citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = langcodes[1] } )			if citeq_args[name]:find('^Q%d+$') then -- qid was returned				-- try fallback to qid's native language				local qid_languages = _lang_code(citeq_args[name])				citeq_args[name] = getValue( {data.id, ps = 1, qid = qid, maxvals = data.maxvals, linked = "no", lang = qid_languages[1] } )				if citeq_args[name]:find('^Q%d+$') then -- qid was returned again					citeq_args[name] = nil				else					-- record the language found if no lang specified					citeq_args.language = citeq_args.language or qid_languages[1]				end			end		end		if data.others then			oth[#oth + 1] = citeq_args[name] and (name:gsub("^%l", string.upper) .. ": " .. citeq_args[name])			citeq_args[name] = 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("</?i>", "''")		else			local title_display = citeq_args.title				or mw.wikibase.getLabel(qid)				or (langcodes[1] and mw.wikibase.getLabelByLang(qid, langcodes[1]))				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 = '[[' .. slink .. '|' .. 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 {{citation}}			citeq_args[k] = nil		elseif in_array (v, {'((unset))', '((ignore))'}) then -- strip off markup for free-text values clashing with local keywords			citeq_args[k] = '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 {{citation}}, right now only add our qid to the list	local list_sep = '. '	if citeq_args.mode ~= 'cs1' then		list_sep = ', '	end	local id = '[[WDQ (định danh)|Wikidata]]&nbsp;[[:d:' .. qid .. '|' .. qid .. ']]' -- go through "WDQ (identifier)" redirect to reduce clutter in "What links here" and improve reverse lookup. Keep in sync with {{QID}}.	local old_id = citeq_args.id	if wdl then -- show WD logo		id = id .. '[[File:Wikidata-logo.svg|16px|alt=|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_args[k] = nil end	end	-- if |expand=<anything>, write a nowiki'd version to see what the {{citation}} template call looks like	if expand then		local expand_args = { "{{" .. template }		-- init with citation template		if expand == "self" then			citeq_args.id = old_id -- restore original |id= parameter			expand_args = { "{{cite Q|" .. qid } -- expand to itself		end		-- make a sortable table and sort it by param name		local sorttable = {}		for param, val in pairs (citeq_args) do			table.insert(sorttable, {param, val})		end		table.sort(sorttable, comp_key)		-- add contents to expand_args		for idx, val in ipairs(sorttable) do			table.insert(expand_args, val[1] .. '=' .. val[2])		end		-- make the nowiki'd string and done		return "<code>" .. table.concat (expand_args, ' |') .. "}}</code>"	end	local erratumid = getPropertyIDs( { "P2507", qid = qid, fwd = "ALL", osd = "no", rank = "best", maxvals = 1 } )	if erratumid then		erratumid = " [[d:" .. erratumid .. "|(bản đính chính)]]" .. "[[Thể loại:Chú thích Q - dẫn nguồn có bản đính chính]]"	else		erratumid = ""	end	local opt_cat = ''	if getValue( {"P5824", ps = 1, qid = qid} ) then		opt_cat = '[[Thể loại:Chú thích Q - dẫn nguồn bị rút]]<!-- retracted -->'	end	if getValue( {"P1366", ps = 1, qid = qid} ) then		opt_cat = opt_cat .. '[[Thể loại:Chú thích Q - dẫn nguồn được thay thế]]<!-- replaced -->'	end	return frame:expandTemplate{title = template, args = citeq_args} .. erratumid .. opt_cat -- render the templateendfunction p.cite_q (frame)	local args = {}	for k, v in pairs(frame:getParent().args) do		if v ~= "" then args[k] = v end	end	for k, v in pairs(frame.args) do		if v ~= "" then args[k] = v end	end	args.qid = args.qid or args[1] or ""	if args.qid == "" then return nil end	args[1] = nil	local citesep = (args.citesep or "")	if citesep == "" then citesep = ", " end	citesep = citesep:gsub('"', '') -- strip double quotes after setting default to allow |citesep="" as a blank separator	args.citesep = nil	local tag = args.tag or ""	if tag == "" then tag = nil end	args.tag = nil	local list = args.list or ""	if list == "" then list = nil end	args.list = nil	args.language = args.language or args.lang	args.lang = nil	local cites = {}	for q in args.qid:gmatch("Q%d+") do		-- make a new copy of the arguments		local newargs = {}		for k, v in pairs(args) do			if k ~= "qid" then				newargs[k] = v			end		end		newargs.qid = q		if tag == "ref" then			cites[#cites + 1] = frame:callParserFunction{ name = "#tag:ref", args = { p._cite_q(newargs), name = q } }			-- expand like this: args = { p._cite_q(newargs), name = 'foo', group = 'bar' }		else			cites[#cites + 1] = p._cite_q(newargs)		end	end	if list then		return frame:expandTemplate{ title = list, args = cites }	else		return table.concat(cites, citesep)	endendreturn p