Bước tới nội dung

Mô đun:Autotaxobox

Trang mô đun bị khóa vô hạn
Bách khoa toàn thư mở Wikipedia
--[[*************************************************************************This module provides support to the automated taxobox system – the templatesAutomatic taxobox, Speciesbox, Subspeciesbox, Infraspeciesbox, etc.In particular it provides a way of traversing the taxonomic hierarchy encodedin taxonomy templates (templates with names of the form"Bản mẫu:Taxonomy/TAXON_NAME") without causing template expansion deptherrors.*****************************************************************************]]require('strict')local TaxonItalics = require('Module:TaxonItalics') -- use a function from Module:TaxonItalics to italicize a taxon namelocal TableRow = '|-\n'local TableEnd = '|}\n'local p = {} -- functions made publiclocal l = {} -- internal functions, kept separatelocal colour = '' -- colour for taxobox and taxonomy listings--[[=========================================================================Limit the maximum depth of a taxonomic hierarchy that can be traversed;avoids excessive processing time and protects against incorrectly set uphierarchies, e.g. loops.The value can be obtained externally via{{#invoke:Autotaxobox|getMaxSearchLevels}}=============================================================================]]local MaxSearchLevels = 100function p.getMaxSearchLevels()	return MaxSearchLevelsend--[[========================== taxoboxColour ================================Determines the correct colour for a taxobox, by searching up the taxonomichierarchy from the supplied taxon for the first taxon (other than'incertae sedis') that sets a taxobox colour. It is assumed that a validtaxobox colour is defined using CSS rgb() syntax.If no taxon that sets a taxobox colour is found, then 'transparent' isreturned unless the taxonomic hierarchy is too deep, when the error colour isreturned.Usage: {{#invoke:Autotaxobox|taxoboxColour|TAXON}}=============================================================================]]function p.taxoboxColour(frame)	return p.getTaxoboxColour(frame, frame.args[1] or '')endfunction p.getTaxoboxColour(frame, currTaxon)	-- note that colour is global to this function; default is empty string	local i = 1 -- count levels processed	local searching = currTaxon ~= '' -- still searching for a colour?	local foundICTaxon = false -- record whether 'incertae sedis' found	while searching and i <= MaxSearchLevels do		local plainCurrTaxon, dummy = l.stripExtra(currTaxon) -- remove trailing text after /		if string.lower(plainCurrTaxon) == 'incertae sedis' then			foundICTaxon = true		else			local possibleColour = frame:expandTemplate{ title = 'Bản mẫu:Taxobox colour', args = { plainCurrTaxon } }			if string.sub(possibleColour,1,3) == 'rgb' then				colour = possibleColour				searching = false			end		end		if searching then			local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent')			if ok and parent ~= '' then				currTaxon = parent				i = i + 1			else				searching = false -- run off the top of the hierarchy or tried to use non-existent taxonomy template			end		end	end	if colour == '' then		if foundICTaxon then			colour = frame:expandTemplate{ title = 'Bản mẫu:Taxobox colour', args = { 'incertae sedis' } }		elseif searching then			-- hierarchy exceeds MaxSearchLevels levels			colour = frame:expandTemplate{ title = 'Bản mẫu:Taxobox/Error colour', args = { } }		else			colour = 'transparent'		end	end	return colourend--[[= = = = = = = = = = = = =  topLevelTaxon  = = = = = = = = = = = = = = = = Defines the correct top level taxa, one of which should terminate everytaxonomic hierarchy encoded in taxonomy templates.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.topLevelTaxon(taxon)	return  taxon == 'Life' or taxon == 'Veterovata' or taxon == 'Ichnos'end--[[=========================== taxoboxList =================================Returns the rows of taxa in an automated taxobox, based on the taxonomichierarchy for the supplied taxon.Usage:{{#invoke:Autotaxobox|taxoboxList|TAXON|display_taxa = the number of taxa *above* TAXON to force to be displayed|authority = taxonomic authority for TAXON|parent_authority = taxonomic authority for TAXON's parent|gparent_authority = taxonomic authority for TAXON's grandparent|ggparent_authority = taxonomic authority for TAXON's greatgrandparent|ggparent_authority = taxonomic authority for TAXON's greatgreatgrandparent|bold_first = 'bold' to bold TAXON in its row|virus = 'yes' to apply virus taxa italicization standards}}=============================================================================]]function p.taxoboxList(frame)	local currTaxon = frame.args[1] or ''	if currTaxon == '' then return '' end	local displayN = (tonumber(frame.args['display_taxa']) or 1) + 1	local authTable = {}	authTable[1] = frame.args['authority'] or ''	authTable[2] = frame.args['parent_authority'] or ''	authTable[3] = frame.args['gparent_authority'] or ''	authTable[4] = frame.args['ggparent_authority'] or ''	authTable[5] = frame.args['gggparent_authority'] or ''	local boldFirst = frame.args['bold_first'] or 'link' -- values 'link' or 'bold'	local virus = frame.args['virus'] or 'no' -- values 'yes' or 'no'	local offset = tonumber(frame.args['offset'] or 0)	-- adjust the authority table if 'authority' refers to a rank lower than the target taxon	if offset ~= 0 then		for i = 1, 5 do			local j = i + offset			if j <= 5 then				authTable[i] = authTable[j]			else				authTable[i] = ''			end		end	end	local taxonTable, taxonRankTable = l.makeTable(frame, currTaxon)	local res = ''	local topTaxonN = taxonTable.n	-- display all taxa above possible greatgreatgrandparent, without authority	for i = topTaxonN, 6, -1 do		res = res .. l.showTaxon(frame, taxonTable[i], taxonRankTable[i], topTaxonN==i, '', displayN >= i, '', virus)	end	-- display all taxa above possible parent, with authority if given	for i = math.min(topTaxonN, 5), 2, -1 do		res = res .. l.showTaxon(frame, taxonTable[i], taxonRankTable[i], topTaxonN==i, authTable[i], displayN >= i, '', virus)	end	-- display target taxon, always displayed and emboldened	res = res .. l.showTaxon(frame, taxonTable[1], taxonRankTable[1], topTaxonN==1, authTable[1], true, boldFirst, virus)	return resend--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =Show one taxon row in a taxobox.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.showTaxon(frame, taxon, rank, isTopTaxon, auth, force, boldFirst, virus)	-- it's an error if this is the top taxon and it's not a top level taxon (e.g. "Life")	if isTopTaxon then		if l.topLevelTaxon(taxon) then			return '' -- don't display a top level taxon		elseif (mw.title.new('Taxonomy/'..taxon, 'Template') or {}).exists then			-- taxonomy template for this taxon has no parent specified			return frame:expandTemplate{ title = 'Bản mẫu:Create taxonomy', args = {taxon, msg='Taxonomy template does not specify a parent'} } .. '\n' .. TableRow		else			-- no taxonomy template for this taxon			return frame:expandTemplate{ title = 'Bản mẫu:Create taxonomy', args = {taxon, msg='Missing taxonomy template'} } .. '\n' .. TableRow		end	else		-- if showing is not already forced, force if it's a principal rank or an authority is specified		force = force or frame:expandTemplate{ title = 'Bản mẫu:Principal rank', args = {rank} } == 'yes' or		        auth ~= ''		if not force then			-- if showing is still not already forced, force if the taxonomy template has 'always_display' set			local ok, alwaysDisplay = p.getTaxonInfoItem(frame, taxon, 'always_display')			force = alwaysDisplay == 'yes' or  alwaysDisplay == 'true'		end		if force then			local res = l.tableCell(frame:expandTemplate{ title = 'Bản mẫu:Anglicise rank', args = {rank} } .. ':')			local bold = 'no'			if boldFirst == 'bold' then bold = 'yes' end			if auth ~= '' then				auth = '<br><small>' .. auth .. '</small>'			end			local res = res .. l.tableCell(l.getTaxonLink(frame, taxon, rank, bold, '', '', virus) .. auth) -- italic, abbreviated			return res .. TableRow		else			return ''		end	endend--[[========================== taxonomyList =================================Returns the cells of the taxonomy table displayed on the right hand side of"Bản mẫu:Taxonomy...." pages.Usage: {{#invoke:Autotaxobox|taxonomyList|TAXON}}=============================================================================]]function p.taxonomyList(frame)	local currTaxon = frame.args[1] or ''	if currTaxon == '' then		return '{|class="infobox biota"\n' .. TableRow .. l.tableCell('') .. l.tableCell('LỖI: không có taxon nào được cung cấp') .. TableEnd	end	local taxonTable, taxonRankTable = l.makeTable(frame, currTaxon)	local rankValTable = l.getRankTable()	local lastRankVal = 1000000	local orderOk = true	-- check whether the taxonomy is for viruses; use already determined taxon colour if possible	local virus = 'no'	local taxoColour = colour	if taxoColour == '' then		if  taxonTable[taxonTable.n] == 'Ichnos' or taxonTable[taxonTable.n] == 'Veterovata' then			taxoColour = frame:expandTemplate{ title = 'Bản mẫu:Taxobox colour', args = { taxonTable[taxonTable.n] } }		else			taxoColour = frame:expandTemplate{ title = 'Bản mẫu:Taxobox colour', args = { taxonTable[taxonTable.n - 1] } }		end	end	if taxoColour == frame:expandTemplate{ title = 'Bản mẫu:Taxobox colour', args = { 'virus' } } then		virus = 'yes'	end	-- add information message	local res = '<p style="float:right">Các cấp được in đậm là phân loại sẽ hiển thị trong bảng phân loại<br>vì là phân loại quan trọng hoặc <code>always_display=yes</code>.</p>\n'	-- start table	res =  res .. '{| class="infobox biota" style="text-align: left; font-size:100%"\n' .. TableRow .. '! colspan=4 style="text-align: center; color:inherit; background-color: '	            .. taxoColour .. '"|Ancestral taxa\n'	-- deal first with the top level taxon; if there are no errors, it should be Life/Veterovata/Ichnos, which are 	-- not displayed	local taxon = taxonTable[taxonTable.n]	if not l.topLevelTaxon(taxon) then		local msg = 'Taxonomy template missing'		if mw.title.new('Taxonomy/'..taxon, 'Template').exists then			msg = 'Parent taxon needed'		end		res = res .. TableRow .. l.tableCell('colspan=2', frame:expandTemplate{title = 'Bản mẫu:Create taxonomy', args = {taxon, msg = msg}})	end	-- now output the rest of the table	local currRankVal	for i = taxonTable.n-1, 1, -1 do		-- check ranks are in right order in the hierarchy		taxon = taxonTable[i]		local rank = taxonRankTable[i]		currRankVal = l.lookupRankVal(rankValTable, rank)		if currRankVal then			orderOk = currRankVal < lastRankVal			if orderOk then lastRankVal = currRankVal end		else			orderOk = true		end		-- see if the row will be displayed in a taxobox; bold the rank if so		local boldRank = false		local ok, alwaysDisplay = p.getTaxonInfoItem(frame, taxon, 'always_display')		if ok and (alwaysDisplay == 'yes' or alwaysDisplay == 'true') then			boldRank = true		else			boldRank = frame:expandTemplate{ title = 'Bản mẫu:Principal rank', args = {rank} } == 'yes'		end		-- now return a row of the taxonomy table with anomalous ranks marked		local errorStr = ''		if not orderOk then errorStr = 'yes' end		local link = l.getTaxonLink(frame, taxon, rank, '', '', '', virus) -- bold, italic, abbreviated		res = res .. l.taxonomyListRow(frame, taxon, rank, link, boldRank, errorStr)	end	-- close table	res = res .. TableEnd	-- error-tracking for taxonomy templates	-- if the last row has an anomalous rank, put the page in an error-tracking category	local errCat1 = ''	if not orderOk then		errCat1 = '[[Category:Taxonomy templates showing anomalous ranks]]\n'	end	-- if the last row has a taxon name in the page name that does not match the link text,	-- put the taxonomy template in a tracking category	local dummy, linkText = p.getTaxonInfoItem(frame, taxon, 'link_text')	local match = l.matchTaxonLink(taxon, linkText, currRankVal and currRankVal < rankValTable['genus'])	local errCat2 = ''	if not match then		errCat2 = '[[Category:Taxonomy templates with name and link text not matching|' .. taxon .. ']]\n'	end	if errCat1..errCat2 ~= '' then		res = res .. frame:expandTemplate{ title = 'Template other', args = { errCat1..errCat2} }	end	return resend--[[ = = = = = = = = = = = = = = taxonomyListRow  = = = = = = = = = = = = = = Returns a single row of the taxonomy table displayed on the right hand side of "Bản mẫu:Taxonomy...." pages.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.taxonomyListRow(frame, taxon, rank, link, boldRank, error)	local res = ''	if taxon == '' or rank == '' then return res end	local baseTaxon, qualifier = l.stripExtra(taxon)	-- if appropriate, make it clear that some taxa have been skipped via a ... row	if qualifier == '/skip' then		res = res .. TableRow .. l.tableCell('.....') .. l.tableCell('.....')	end	-- now generate a row of the table	res = res .. TableRow	local cellContent = ''	local anglicizedRank = frame:expandTemplate{ title = 'Bản mẫu:Anglicise rank', args = { rank } }	if boldRank then		cellContent = cellContent .. '<b>' .. anglicizedRank .. '</b>:'	else		cellContent = cellContent .. anglicizedRank .. ':'	end	if error == 'yes' then		cellContent = '<span style="background-color:#FDD">' .. cellContent .. '</span>'	end	res = res .. l.tableCell(cellContent)	          .. l.tableCell('<span style="white-space:nowrap;">' .. link .. '</span>')	          .. l.tableCell('<span style="font-size:smaller;white-space:nowrap;">' .. qualifier  .. '</span>')	          .. l.tableCell('<span style="white-space:nowrap;">' .. frame:expandTemplate{ title = 'Bản mẫu:Edit a taxon', args = { taxon } } .. '</span>')	return resend--[[========================= callTaxonomyKey ===============================Prepares for, and then calls, Bản mẫu:Taxonomy key to display a taxonomytemplate page. It does this by building up the information the templaterequires, following one 'same as' link, if required.Usage:{{#invoke:Autotaxobox|callTaxonomyKey|parent=|rank=|extinct=|always_display=|link_target=value of 'link' parameter in taxonomy template|link_text=value of parameter 2 in taxonomy template|same_as=}}=============================================================================]]local PARENT = 1local RANK = 2local LINK_TARGET = 3local LINK_TEXT = 4local ALWAYS_DISPLAY = 5local EXTINCT = 6local SAME_AS = 7local REFS = 8function p.callTaxonomyKey(frame)	local taxon = frame.args['taxon'] or ''	local parent = frame.args['parent'] or ''	local rank = frame.args['rank'] or ''	local extinct = string.lower(frame.args['extinct']) or ''	local alwaysDisplay = string.lower(frame.args['always_display']) or ''	local linkTarget = frame.args['link_target'] or ''	local linkText = frame.args['link_text'] or '' -- this is the "raw" link text, and can be ''	local refs = frame.args['refs'] or ''	local sameAsTaxon = frame.args['same_as'] or ''	if sameAsTaxon ~= '' then		-- try using the 'same as' taxon; it's an error if it doesn't exist		local ok, sameAsInfoStr = pcall(frame.expandTemplate, frame, { title = 'Bản mẫu:Taxonomy/' .. sameAsTaxon, args = {['machine code'] = 'all' } })		if ok then			local sameAsInfo = mw.text.split(sameAsInfoStr, '$', true)			--'same as' taxon's taxonomy template must not have a 'same as' link			if sameAsInfo[SAME_AS] == '' then				if parent == '' then parent = sameAsInfo[PARENT] end				if rank == '' then rank = sameAsInfo[RANK] end				if extinct == '' then extinct = string.lower(sameAsInfo[EXTINCT]) end				if alwaysDisplay == '' then alwaysDisplay = string.lower(sameAsInfo[ALWAYS_DISPLAY]) end				if linkTarget == '' then linkTarget = sameAsInfo[LINK_TARGET] end				if linkText == '' then linkText = sameAsInfo[LINK_TEXT] end				if refs == '' and parent == sameAsInfo[PARENT] then refs = sameAsInfo[REFS] end			else				return '<span style="color:red; font-size:1.1em">Lỗi: cố gắng theo hai liên kết "same as"</span>: <code>same_as = ' .. sameAsTaxon .. '</code>, nhưng [[Bản mẫu:Taxonomy/' .. sameAsTaxon .. ']] cũng có một tham số <code>same_as</code>.'			end		else			return frame:expandTemplate{ title = 'Bản mẫu:Taxonomy key/missing template', args = {taxon=sameAsTaxon, msg='given as the value of <code>same as</code>'} }		end	end	local link = linkTarget	if linkText ~= '' and linkText ~= linkTarget then link = link .. "|" .. linkText end	-- check consistency of extinct status; if this taxon is not extinct, parent must not be either	local extinctError = 'no'	if parent ~= '' and (extinct == '' or extinct == 'no' or extinct == 'false') then		local ok, parentExtinct = p.getTaxonInfoItem(frame, parent, 'extinct')		if ok and (parentExtinct == 'yes' or parentExtinct == 'true') then extinctError = 'yes' end	end	return frame:expandTemplate{ title = 'Bản mẫu:Taxonomy key',			args = {taxon=taxon, parent=parent, rank=rank, extinct=extinct, always_display=alwaysDisplay, link_target=linkTarget, link=link, refs=refs, same_as=sameAsTaxon, extinct_error = extinctError} }end--[[============================= showRefs ==================================Shows the refs field in a taxonomy template, handing incertae sedis taxa andusing '–' for absent refs.Usage: {{#invoke:Autotaxobox|showRefs|TAXON|REFS}}=============================================================================]]function p.showRefs(frame)	local taxonName = frame.args[1] or ''	local refs = frame.args[2] or ''	return l.doShowRefs(taxonName, refs)end--[[= = = = = = = = = = = = = = doShowRefs  = = = = = = = = = = = = = = = = =Show the refs field in a taxonomy template.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.doShowRefs(taxonName, refs)	if mw.text.split(taxonName, '/', true)[1] == 'Incertae sedis' then		refs = 'not applicable (<i>incertae sedis</i>)'	elseif refs == '' then		refs = '–'	end	return refsend--[[============================ taxonInfo ==================================Extracts and returns information from Bản mẫu:Taxonomy/TAXON, followingone 'same as' link if required.Usage: {{#invoke:Autotaxobox|taxonInfo|TAXON|ITEM}}ITEM is one of: 'parent', 'rank', 'link target', 'link text', 'extinct','always display', 'refs', 'same as' or 'all'.If ITEM is not specified, the default is 'all' – all values in a single stringseparated by '$'.=============================================================================]]function p.taxonInfo(frame)	local taxon = frame.args[1] or ''	local item = frame.args[2] or ''	if item == '' then item = 'all' end	local ok, info = p.getTaxonInfoItem(frame, taxon, item)	return infoend--[[= = = = = = = = = = = getTaxonInfoItem  = = = = = = = = = = = = = = = = =Utility function to extract an item of information from a taxonomy template, following one 'same as' link if required.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function p.getTaxonInfoItem(frame, taxon, item)	local ok, info	-- item == 'dagger' is a special case	if item == 'dagger' then		ok, info = p.getTaxonInfoItem(frame, taxon, 'extinct')		if ok then			if info == 'yes' or info == 'true' then				info = '&dagger;'			else				info = ''			end		end	-- item ~= 'dagger'	else		ok, info = pcall(frame.expandTemplate, frame, { title = 'Bản mẫu:Taxonomy/' .. taxon, args = {['machine code'] = item } })		if ok then			if info == '' then				-- try 'same as'				local sameAsTaxon = frame:expandTemplate{ title = 'Bản mẫu:Taxonomy/' .. taxon, args = {['machine code'] = 'same as' } }				if sameAsTaxon ~= '' then					ok, info = pcall(frame.expandTemplate, frame, { title = 'Bản mẫu:Taxonomy/' .. sameAsTaxon, args = {['machine code'] = item } })				end			end		end	end	if ok then		-- if item is 'link_text', trim info and check whether '(?)' needs to be added		if item == 'link_text' then			-- there is a newline at the end of linkText when taxonomy template has "|link = LINK_TARGET|LINK_TEXT"			info = mw.text.trim(info)			if string.sub(taxon, -2) == '/?' and not string.find(info, '?', 1, true) then				info = info .. '<span style="font-style:normal;font-weight:normal;">&nbsp;(?)</span>'			end		end	else		info = '[[Bản mẫu:Taxonomy/' .. taxon .. ']]' --error indicator in code before conversion to Lua	end	return ok, infoend--[[============================ taxonLink ==================================Returns a wikilink to a taxon, if required including '†' before it and' (?)' after it, and optionally italicized or bolded without a wikilink.Usage:{{#invoke:Autotaxobox|taxonLink|taxon=           : having '/?' at the end triggers the output of ' (?)'|extinct=         : 'yes' or 'true' trigger the output of '†'|bold=            : 'yes' makes the core output bold and not wikilinked|italic=          : 'yes' makes the core output italic|link_target=     : target for the wikilink|link_text=        : text of the wikilink (may be same as link_target), without †, italics, etc.}}=============================================================================]]function p.taxonLink(frame)	local taxon = frame.args['taxon'] or ''	local extinct = string.lower(frame.args['extinct'] or '')	local bold = frame.args['bold'] or ''	local italic = frame.args['italic'] or ''	local abbreviated = frame.args['abbreviated'] or ''	local linkTarget = frame.args['link_target'] or ''	local linkText = frame.args['link_text'] or frame.args['plain_link_text'] or '' --temporarily allow alternative args	return l.makeLink(taxon, extinct, bold, italic, abbreviated, linkTarget, linkText)end--[[= = = = = = = = = = = = = = getTaxonLink  = = = = = = = = = = = = = = = =Internal function to drive l.makeLink().= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.getTaxonLink(frame, taxon, rank, bold, italic, abbreviated, virus)	local ok, extinct = p.getTaxonInfoItem(frame, taxon, 'extinct')	if italic == '' then		italic = frame:expandTemplate{ title = 'Bản mẫu:Is italic taxon', args = { rank, virus = virus } }	end	local ok, linkTarget = p.getTaxonInfoItem(frame, taxon, 'link_target')	local ok, linkText = p.getTaxonInfoItem(frame, taxon, 'link_text')	return l.makeLink(taxon, extinct, bold, italic, abbreviated, linkTarget, linkText)end--[[= = = = = = = = = = = = = = makeLink  = = = = = = = = = = = = = = = = = =Actually make the link.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.makeLink(taxon, extinct, bold, italic, abbreviated, linkTarget, linkText)	local dummy	-- if link text is missing, try to find a replacement	if linkText == '' then		if string.find(taxon, 'Incertae sedis', 1, true) then			linkText = "''incertae sedis''"			linkTarget = 'Incertae sedis'		else			linkText, dummy = l.stripExtra(taxon)		end	end	if linkTarget == '' then linkTarget = linkText end	if italic == 'yes' then linkText = TaxonItalics.italicizeTaxonName(linkText, false, abbreviated=='yes') end	local link = ''	if bold == 'yes' then link = '<b>' .. linkText .. '</b>'	else		if linkTarget == linkText then link = linkText		else link = linkTarget .. '|' .. linkText		end		link = '[[' .. link .. ']]'	end	if (extinct == 'yes' or extinct == 'true') and not string.find(link, '†', 1, true) then		link = '<span style="font-style:normal;font-weight:normal;">†</span>' .. link	end	if string.sub(taxon, -2) == '/?' and not string.find(link, '?', 1, true) then		link = link .. '<span style="font-style:normal;font-weight:normal;">&nbsp;(?)</span>'	end	return linkend--[[========================== showRankTable ================================Returns a wikitable showing the ranks and their values as set up bygetRankTable().Usage: {{#invoke:Autotaxobox|showRankTable}}=============================================================================]]function p.showRankTable(frame)	local rankTable = l.getRankTable()	local res = '{| class="wikitable sortable"\n|+ Xếp hạng được chọn trong bản mẫu taxonomy\n! Xếp hạng !! Hiển thị !! Giá trị\n'	for k, v in pairs(rankTable) do		local rankShown = frame:expandTemplate{ title = 'Bản mẫu:Anglicise rank', args = { k } }		res = res .. TableRow .. l.tableCell(k) .. l.tableCell(rankShown) .. l.tableCell(v)	end	return res .. TableEndend--[[============================== find =====================================Returns the taxon above the specified taxon with a given rank.Usage: {{#invoke:Autotaxobox|find|TAXON|RANK}}=============================================================================]]function p.find(frame)	local currTaxon = frame.args[1] or ''	if currTaxon == '' then return '<span class="error">không có taxon nào được cung cấp</span>' end	local rank = frame.args[2] or ''	if rank == '' then return '<span class="error">không có xếp hạng nào được cung cấp</span>' end	local inHierarchy = true -- still in the taxonomic hierarchy or off the top?	local searching = true -- still searching	while inHierarchy and searching do		local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent')			if ok and parent ~= '' then			currTaxon = parent			local ok, currRank = p.getTaxonInfoItem(frame, currTaxon, 'rank')			if currRank == rank then				searching = false			end		else			inHierarchy = false		end	end	if inHierarchy and not searching then return currTaxon	else return '<span class="error">không tìm ra xếp hạng</span>'	endend--[[=============================== nth =====================================External utility function primarily intended for use in checking and debugging.Returns the nth level above a taxon in a taxonomic hierarchy, where the taxonitself is counted as the first level.Usage: {{#invoke:Autotaxobox|nth|TAXON|n=N}}=============================================================================]]function p.nth(frame)	local currTaxon = frame.args[1] or ''	if currTaxon == '' then return 'LỖI: không có taxon nào được cung cấp' end	local n = tonumber(frame.args['n'] or 1)	if n > MaxSearchLevels then		return 'Đã vượt quá tối đa số lượng của các cấp được phép (' .. MaxSearchLevels .. ')'	end	local i = 1	local inHierarchy = true -- still in the taxonomic hierarchy or off the top?	while i < n and inHierarchy do		local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent')			if ok and parent ~= '' then			currTaxon = parent			i = i + 1		else			inHierarchy = false		end	end	if inHierarchy then return currTaxon	else return 'Level ' .. n .. ' is past the top of the taxonomic hierarchy'	endend--[[============================= nLevels ===================================External utility function primarily intended for use in checking and debugging.Returns number of levels in a taxonomic hierarchy, starting fromthe supplied taxon as level 1.Usage: {{#invoke:Autotaxobox|nLevels|TAXON}}=============================================================================]]function p.nLevels(frame)	local currTaxon = frame.args[1] or ''	if currTaxon == '' then return 'LỖI: không có taxon nào được cung cấp' end	local i = 1	local inHierarchy = true -- still in the taxonomic hierarchy or off the top?	while inHierarchy and i < MaxSearchLevels  do		local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent')		if ok and parent ~= '' then			currTaxon = parent			i = i + 1		else			inHierarchy = false		end	end	if inHierarchy then return MaxSearchLevels .. '+'	else return i	endend--[[============================= listAll ===================================External utility function primarily intended for use in checking and debugging.Returns a comma separated list of a taxonomic hierarchy, starting fromthe supplied taxon.Usage: {{#invoke:Autotaxobox|listAll|TAXON}}=============================================================================]]function p.listAll(frame)	local currTaxon = frame.args[1] or ''	if currTaxon == '' then return 'LỖI: không có taxon nào được cung cấp' end	return l.doListAll(l.makeTable(frame, currTaxon))endfunction l.doListAll(taxonTable, taxonRankTable)	local lst = taxonTable[1] .. '-' .. tostring(taxonRankTable[1])	for i = 2, taxonTable.n, 1 do		lst = lst .. ', ' .. taxonTable[i] .. '-' .. taxonRankTable[i]	end	return lstend--[[=========================== removeQualifier ================================External utility function to remove a qualifier (any part after a "/") from a taxon name.Usage: {{#invoke:Autotaxobox|removeQualifier|TAXON}}=============================================================================]]function p.removeQualifier(frame)	local baseName, qualifier = l.stripExtra(frame.args[1])	return baseNameend--[[=========================================================================Internal functions=============================================================================]]--[[= = = = = = = = = = = = stripExtra  = = = = = = = = = = = = = = = = = = =Internal utility function to strip off any extra parts of a taxon name, i.e.anything after a '/'. Thus 'Felidae/?' would be split into 'Felidae' and '?'.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.stripExtra(taxonName)	local i = mw.ustring.find(taxonName, '/', 1, true)	if i then		return mw.ustring.sub(taxonName, 1, i-1), mw.ustring.sub(taxonName, i, -1)	else		return taxonName, ''	endend--[[= = = = = = = = = = = = splitTaxonName  = = = = = = = = = = = = = = = = =Internal utility function to split a taxon name into its parts and returnthem. Possible formats include:* taxon* taxon (disambig)* taxon (Subgenus)* taxon/qualifier* combinations, e.g. taxon (disambig)/qualifier= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.splitTaxonName(taxon)	-- get any qualifier present	local qualifier = ''	local i = mw.ustring.find(taxon, '/', 1, true)	if i then		qualifier = mw.ustring.sub(taxon, i+1, -1)		taxon = mw.ustring.sub(taxon, 1, i-1)	end	-- get any disambiguator or subgenus	local disambig = ''	local subgenus = ''	i = mw.ustring.find(taxon, ' (', 1, true)	if i then		local parenTerm = mw.ustring.sub(taxon, i+2, -2)		taxon = mw.ustring.sub(taxon, 1, i-1)		local char1 = mw.ustring.sub(parenTerm, 1, 1)		if char1 == mw.ustring.lower(char1) then			disambig = parenTerm		else			subgenus = parenTerm		end	end	return taxon, disambig, subgenus, qualifierend--[[= = = = = = = = = = = = matchTaxonLink  = = = = = = = = = = = = = = = = =Function to determine whether the taxon name derived from the name of the taxonomy template (passed in the parameter taxon) matches the link text(passed in the parameter linkText).The taxon name may have any of the formats:* baseTaxon/qualifier* baseTaxon (disambig)* baseTaxon (Subgenus) [distinguished by the capital letter]* a qualifier may be present after the previous two formats.Examples of matches (baseTaxon ~ linkText):* Pinus ~ Pinus* Pinus sect. Trifoliae ~ Pinus sect. Trifoliae* Pinus sect. Trifoliae ~ ''Pinus'' sect. ''Trifoliae'' [italic markers ignored]* Pinus sect. Trifoliae ~ P. sect. Trifoliae [abbreviated genus name matches]* Bombus (Pyrobombus) ~ Bombus (Pyrobombus)* Bombus (Pyrobombus) ~ B. (Pyrobombus)* Bombus (Pyrobombus) ~ Pyrobombus [link text may just be the subgenus]* Heteractinida ~ "Heteractinida" [double-quotes are ignored in link text]* "Heteractinida" ~ Heteractinida [double-quotes are ignored in base taxon name]* Incertae sedis ~ anything [link text is ignored for matching in this case]* Cetotheriidae with qualifier=? ~ Cetotheriidae (?)= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.matchTaxonLink(taxon, linkText, rankBelowGenus)	local dummy	linkText, dummy = mw.ustring.gsub(linkText, "''", '') -- remove any italic wikitext in the link text	linkText, dummy = mw.ustring.gsub(linkText, '<.->', '') -- strip all tags used to format the link text	linkText, dummy = mw.ustring.gsub(linkText, '"', '') -- remove any occurrences of " in the link text	local baseTaxon, disambig, subgenus, qualifier = l.splitTaxonName(taxon) -- split up the taxon name	baseTaxon, dummy = mw.ustring.gsub(linkText, '"', '') -- remove any occurrences of " in the base taxon name	local match = linkText == baseTaxon or	              linkText == subgenus or	              linkText == baseTaxon .. ' (' .. subgenus .. ')' or	              linkText ==  mw.ustring.sub(baseTaxon, 1, 1) .. '. (' .. subgenus .. ')' or	              baseTaxon == 'Incertae sedis' or	              rankBelowGenus and linkText == mw.ustring.gsub(baseTaxon, '([A-Z]).- (.*)', '%1. %2') or 	              mw.ustring.find(qualifier, '?', 1, true) and mw.ustring.find(linkText, baseTaxon, 1, true) == 1	return matchend--[[= = = = = = = = = = = = = makeTable = = = = = = = = = = = = = = = = = = =Internal utility function to return a table (array) constructed from ataxonomic hierarchy stored in "Bản mẫu:Taxonomy/..." templates.TABLE.n holds the total number of taxa; TABLE[1]..TABLE[TABLE.n] the taxonnames.The last taxon in the table will either (a) have a taxonomy template but withno parent given (e.g. 'Life') or (b) not have a taxonomy template.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.makeTable(frame, currTaxon)	local taxonTable = {}	local taxonRankTable = {}	local ok, rank, parent	local i = 1	local topReached = false -- reached the top of the taxonomic hierarchy?	repeat		taxonTable[i] = currTaxon		ok, rank = p.getTaxonInfoItem(frame, currTaxon, 'rank')		if ok then taxonRankTable[i] = string.lower(rank) else taxonRankTable[i] = '' end		ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent')		if ok and parent ~= '' then			currTaxon = parent			i = i + 1		else			topReached = true -- reached the top of the hierarchy or tried to use a non-existent taxonomy template		end	until topReached or i > MaxSearchLevels	taxonTable.n = math.min(i, MaxSearchLevels)	return taxonTable, taxonRankTableend--[[= = = = = = = = = = = = getRankTable  = = = = = = = = = = = = = = = = = =Internal utility function to set up a table of numerical values correspondingto 'Linnaean' ranks, with upper ranks having higher values. In a validtaxonomic hierarchy, a lower rank should never have a higher value than ahigher rank. The actual numerical values are arbitrary so long as they areordered.The ranks should correspond to those in Bản mẫu:Anglicise ranks.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.getRankTable()	return {		classis = 1400,		cohort = 1100,		divisio = 1500,		domain = 1700,		epifamilia =  802,		familia = 800,		forma = 100,		genus = 600,		grandordo = 1005,		['grandordo-mb'] = 1002,		hyperfamilia = 805;		infraclassis = 1397,		infralegio = 1197,		infraordo = 997,		infraphylum = 1497,		infraregnum = 1597,		infratribus = 697,		legio = 1200,		magnordo = 1006,		microphylum = 1495,		micrordo = 995,		mirordo = 1004,		['mirordo-mb'] = 1001,		nanophylum = 1494,		nanordo = 994,		ordo = 1000,		parafamilia = 800,		parvclassis = 1396; -- same as subterclassis		parvordo = 996,		phylum = 1500,		regnum = 1600,		sectio = 500,		--series = 400, used too inconsistently to check		species = 300,		subclassis = 1398,		subcohort = 1098,		subdivisio = 1498,		subfamilia = 798,		subgenus = 598,		sublegio = 1198,		subordo = 998,		subphylum = 1498,		subregnum = 1598,		subsectio = 498,		subspecies = 298,		subterclassis = 1396; -- same as parvclassis		subtribus = 698,		superclassis = 1403,		supercohort = 1103,		superdivisio = 1503,		superdomain = 1703,		superfamilia = 803,		superlegio = 1203,		superordo = 1003,		superphylum = 1503,		superregnum = 1603,		supersectio = 503,		supertribus = 703,		tribus = 700,		varietas = 200,		zoodivisio = 1300,		zoosectio = 900,		zoosubdivisio = 1298,		zoosubsectio = 898,	}end--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =Function to look up the arbitrary numerical value of a rank in a rank valuetable. "Ichno" and "oo" ranks are not stored separately, so if present theprefix is removed.= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.lookupRankVal(rankValTable, rank)	local rankVal = rankValTable[rank]	if not rankVal then		-- may be an "ichno" or "oo" rank; try removing "ichno-" or "oo-"		local baseRank = mw.ustring.gsub(mw.ustring.gsub(rank, '^ichno', ''), '^oo', '')		if baseRank == 'rdo' then baseRank = 'ordo' end		-- if an "ichno" or "oo" rank, lower rank value slightly so it is ok below the base rank		rankVal = rankValTable[baseRank]		if rankVal then			rankVal = rankVal - 0.1		end	end	return rankValend--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = == = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]function l.tableCell(arg1, arg2)	local text, style	if arg2 then		style = arg1		text = arg2	else		style = ''		text = arg1	end	local res = '|'	if style ~= '' then		res = res .. style .. '|'	end	return res .. text .. '\n'endreturn p