Module:BiologyList

Lua

CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules

Module:BiologyList (talk · edit · hist · links · doc · subpages · tests / results · sandbox · all modules)


Usage
This module is mainly used to display lists of taxa. It is also used by other biology templates as helper.
Functions and their usage
How to improve and test this module
  1. develop your modification in BiologyList/sandbox, the sandbox of this module
    which is used in the sandbox templates {{Subspecies/sandbox}}, {{Species/sandbox}}, {{Species2/sandbox}}, {{Genera/sandbox}}, {{Genera2/sandbox}}, {{Taxa/sandbox}}, {{SimpleTaxa/sandbox}}
  2. verify your changes in {{Subspecies/testcases}}, {{Species/testcases}}, {{Species2/testcases}}, {{Genera/testcases}}, {{Genera2/testcases}}, {{Taxa/testcases}}, {{SimpleTaxa/testcases}}
  3. verify your changes in Module talk:BiologyList/sandbox/testcases
  4. if needed improve the testcases BiologyList/sandbox/testcases
  5. report your modifications in BiologyList
  6. verify again your changes in {{Subspecies/testcases}}, {{Species/testcases}}, {{Species2/testcases}}, {{Genera/testcases}}, {{Genera2/testcases}}, {{Taxa/testcases}}, {{SimpleTaxa/testcases}}
  7. verify again your changes in Module talk:BiologyList/testcases
  8. if needed improve the testcases BiologyList/testcases
See also

Code

local _common=require('Module:Biology')

local _prefixes = {
	'Species of ',
	'Genera of ',
	'Subtribes of ',
	'Tribes of ',
	'Subfamilies of ',
	'Families of '
}

-- getTaxonNameOutOfTitle() returns 'Canistrum' out of 'Canistrum (Bromeliaceae)' and 'Bromeliaceae' out of 'Genera of Bromeliaceae'
--    parameter title can be nil  which case calling article's pagename is used
-- Warning: for this function cannot distinguish a subgenus (like 'Canistrum (subgenus)') from a disambiguated taxon 'Canistrum (Bromeliaceae)'.
--          So calling this function on a subgenus returns the genus. This behavior is not too problematic as genus are just above their subgenus.
function getTaxonNameOutOfTitle(title)
	if string.isNilOrEmpty(title) then
		-- Usage: from getTaxonNameForUrl() when {{Taxasource}} is called without param name=
		title = mw.title.getCurrentTitle().text
	else
		-- Usage: from testcase with different titles
		title = mw.text.trim(title)
	end
	title = _common.suppressDisambiguation(title)
	for index, prefix in pairs(_prefixes) do
		if string.sub(title,1,string.len(prefix))==prefix then
			title = mw.text.trim(string.sub(title,string.len(prefix)))
		end
	end
	return title
end

function getTaxonNameForUrl(taxonNameOrNilForTitle, urlFormatOrNil)
	local taxonName
	if string.isNilOrEmpty(taxonNameOrNilForTitle) then
		-- parameter name= is NOT provided to new {{Taxasource}} => use current title trunked
		taxonName = getTaxonNameOutOfTitle(Nil)
	else
		-- parameter name= is provided to new {{Taxasource}} => use it without modifications
		taxonName = taxonNameOrNilForTitle
	end
	if string.isNilOrEmpty(urlFormatOrNil) then
		-- https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual/fr#mw.uri.encode
		-- "QUERY" encodes spaces by "+"
		-- "PATH"  encodes spaces by "%20"
		-- "WIKI"  encodes spaces by "_".
		urlFormatOrNil = 'QUERY'
	end
	return mw.uri.encode(taxonName, urlFormatOrNil)
end

function getCleverLepIndex(source, taxonNameOrNil)
	local link = '[http://www.nhm.ac.uk/research-curation/research/projects/lepindex/search/ Lepidoptera Names Index]'
	local taxonName = getTaxonNameForUrl(taxonNameOrNil)

	if string.endsWith(taxonName, 'oidea') then
		-- taxonNameOrNil is a superfamily
		link = link .. ' <small>([http://www.nhm.ac.uk/api/global-lepidoptera-names-index-api/superfamily/' .. taxonName .. '/family Families])</small>'
    elseif string.endsWith(taxonName, 'dae') then
		-- taxonNameOrNil is a family
		link = link .. ' <small>([http://www.nhm.ac.uk/api/global-lepidoptera-names-index-api/family/' .. taxonName .. '/subfamily Subfamilies])</small>'
    elseif string.endsWith(taxonName, 'inae') then
		-- taxonNameOrNil is a subfamily
		link = link .. ' <small>([http://www.nhm.ac.uk/api/global-lepidoptera-names-index-api/subfamily/' .. taxonName .. '/tribe Tribes])</small>'
	end
	return link;
end

function getSourceLink(source, taxonNameOrNil)
	if source=='adw' then
		return '[http://animaldiversity.ummz.umich.edu/site/search?category=Classification&SearchableText=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' Animal Diversity Web (ADW)]'
	elseif source=='afd' then
		return '[https://biodiversity.org.au/afd/taxa/' .. getTaxonNameForUrl(taxonNameOrNil) .. '/checklist Australian Faunal Directory (AFD)]'
	elseif source=='algaebase' then
		return '[http://www.algaebase.org/ AlgaeBASE]'
	elseif source=='amphibiaweb' then
		return '[http://amphibiaweb.org/ Amphibiaweb]'
	elseif source=='animalbase' then
		return '[http://www.animalbase.uni-goettingen.de/zooweb/servlet/AnimalBase/search AnimalBase]'
	elseif source=='aou' then
		return '[http://www.aou.org/checklist/north/full.php AOU]'
	elseif source=='apg' then
		return '[[:en:APG system|APG]]'
	elseif source=='apgii' or source=='apg ii' then
		return '[[APG II|APG II]]'
	elseif source=='apgiii' or source=='apg iii' then
		return '[[APG III|APG III]]'
	elseif source=='apgiv' or source=='apg iv' then
		return '[[APG IV|APG IV]]'
	elseif source=='apni' then
		return '[http://www.anbg.gov.au/cgi-bin/apni APNI]'
	elseif source=='apwebsite' then
		return '[[APWebsite]]'
	elseif source=='asw' then
		return '[http://research.amnh.org/vz/herpetology/amphibia/index.php ASW]'
	elseif source=='avibase' then
		return '[http://avibase.bsc-eoc.org/avibase.jsp Avibase]'
	elseif source=='baltimore' then
		return '[[:en:Baltimore classification|Baltimore classification]]'
	elseif source=='betancur (2017)' or source=='betancur-r et al. (2017)' then
		return '[https://bmcevolbiol.biomedcentral.com/articles/10.1186/s12862-017-0958-3 Betancur-R et al. (2017)]'
	elseif source=='biolib' then
		return '[http://www.biolib.cz/en/main/ BioLib]'
	elseif source=='bouchet&rocroi2005' then
		return '[[:en:Taxonomy of the Gastropoda (Bouchet & Rocroi, 2005)|Bouchet & Rocroi (2005)]]'
	elseif source=='bouchet et al. (2010)' then
		return '[[:en:Taxonomy of the Bivalvia (Bouchet, Rocroi, Bieler, Carter & Coan, 2010)|Bouchet et al. (2010)]]'
	elseif source=='bugguide' then
		return '[https://bugguide.net bugguide.net]'
	elseif source=='butmoth' then
		return '[http://www.nhm.ac.uk/research-curation/research/projects/butmoth/index.html ButMoth]'
	elseif source=='catalogueoflife' then
		return '[http://www.catalogueoflife.org/col/search/all/key/' .. getTaxonNameForUrl(taxonNameOrNil) .. ' Catalogue of Life]'
	elseif source=='chase2003' then
		return '[http://www.orchids.co.in/dna-data-orchidaceae.shtm Chase (2003)]'
	elseif source=='cites' then
		return '[[:en:CITES|CITES]]'
	elseif source=='cronquist' then
		return '[[Cronquist System|Cronquist]]'
	elseif source=='de' then
		return '[[:de:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|de.wikipedia]]'
	elseif source=='discoverlife' then
		return '[http://www.discoverlife.org/mp/20q?search=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' DiscoverLife]'
	elseif source=='dmitriev' then
		return '[http://dmitriev.speciesfile.org Dmitriev Species File]'
	elseif source=='doris' then
		return '[http://doris.ffessm.fr/fiches_liste_recherche.asp?touslesmots=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' DORIS]'
	elseif source=='efloras' then
		return '[http://www.efloras.org eFloras.org]'
	elseif source=='emonocot' then
		return '[http://www.e-monocot.org/search?query=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' eMonocot]'
	elseif source=='en' then
		return '[[:en:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|en.wikipedia]]'
	elseif source=='eol' then
		return '[http://www.eol.org/ EOL]'
	elseif source=='es' then
		return '[[:en:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|es.wikipedia]]'
	elseif source=='faunaeur' then
		return '[http://www.faunaeur.org Fauna Europaea]'
	elseif source=='fishbase' then
		return '[http://www.fishBase.org FishBase]'
	elseif source=='funet' then
		return '[http://www.nic.funet.fi/cgi-bin/life/goto?taxon=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' Funet]'
	elseif source=='fungorum' then
		return '[http://www.indexfungorum.org Index Fungorum]'
	elseif source=='fr' then
		return '[[:fr:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|fr.wikipedia]]'
	elseif source=='gbif' then
		return '[http://data.gbif.org/welcome.htm GBIF]'
	elseif source=='generaorchidacearum2014' then
		return '[http://www.kew.org/science-conservation/research-data/science-directory/projects/genera-orchidacearum Genera Orchidacearum, Volume 1 - 6 (1999-2014)]'
	elseif source=='goffinet et al.' then
		return '[http://bryology.uconn.edu/classification-2/#' .. getTaxonNameForUrl(taxonNameOrNil) .. " Goffinet ''et al.'']"
	elseif source=='grin' then
		return '[http://www.ars-grin.gov/npgs/aboutgrin.html GRIN]'
	elseif source=='gymnosperm database' then
		return '[http://www.conifers.org/index.php Gymnosperm Database]'
	elseif source=='hbw' then
		return "[[:en:Handbook of the Birds of the World|''Handbook of the Birds of the World'']]"
	elseif source=='ictv' then
		return "[https://talk.ictvonline.org/taxonomy/ ICTV]"
	elseif source=='inaturalist' then
		return "[https://www.inaturalist.org/taxa/" .. getTaxonNameForUrl(taxonNameOrNil) .. " iNaturalist]"
	elseif source=='insectoid' then
		return "[http://insectoid.info Insectoid]"
	elseif source=='ioc2.2' then
		return '[[:en:International Ornithological Congress|IOC classification 2.2]]'
	elseif source=='ioc2.3' then
		return '[[:en:International Ornithological Congress|IOC classification 2.3]]'
	elseif source=='ioc2.4' then
		return '[[:en:International Ornithological Congress|IOC classification 2.4]]'
	elseif source=='ioc2.5' then
		return '[[:en:International Ornithological Congress|IOC classification 2.5]]'
	elseif source=='ioc2.6' then
		return '[[:en:International Ornithological Congress|IOC classification 2.6]]'
	elseif source=='ioc2.7' then
		return '[[:en:International Ornithological Congress|IOC classification 2.7]]'
	elseif source=='ioc2.8' then
		return '[[:en:International Ornithological Congress|IOC classification 2.8]]'
	elseif source=='ioc2.9' then
		return '[[:en:International Ornithological Congress|IOC classification 2.9]]'
	elseif source=='ioc2.10' then
		return '[[:en:International Ornithological Congress|IOC classification 2.10]]'
	elseif source=='ioc2.11' then
		return '[[:en:International Ornithological Congress|IOC classification 2.11]]'
	elseif source=='ioc3.1' then
		return '[[:en:International Ornithological Congress|IOC classification 3.1]]'
	elseif source=='ioc3.2' then
		return '[[:en:International Ornithological Congress|IOC classification 3.2]]'
	elseif source=='ioc3.3' then
		return '[[:en:International Ornithological Congress|IOC classification 3.3]]'
	elseif source=='ioc3.4' then
		return '[[:en:International Ornithological Congress|IOC classification 3.4]]'
	elseif source=='ioc3.5' then
		return '[[:en:International Ornithological Congress|IOC classification 3.5]]'
	elseif source=='ioc4.1' then
		return '[[:en:International Ornithological Congress|IOC classification 4.1]]'
	elseif source=='ioc4.2' then
		return '[[:en:International Ornithological Congress|IOC classification 4.2]]'
	elseif source=='ioc4.3' then
		return '[[:en:International Ornithological Congress|IOC classification 4.3]]'
	elseif source=='ioc4.4' then
		return '[[:en:International Ornithological Congress|IOC classification 4.4]]'
	elseif source=='ioc5.1' then
		return '[[:en:International Ornithological Congress|IOC classification 5.1]]'
	elseif source=='ioc5.2' then
		return '[[:en:International Ornithological Congress|IOC classification 5.2]]'
	elseif source=='ioc5.3' then
		return '[[:en:International Ornithological Congress|IOC classification 5.3]]'
	elseif source=='ioc5.4' then
		return '[[:en:International Ornithological Congress|IOC classification 5.4]]'
	elseif source=='ioc6.1' then
		return '[[:en:International Ornithological Congress|IOC classification 6.1]]'
	elseif source=='ioc6.2' then
		return '[[:en:International Ornithological Congress|IOC classification 6.2]]'
	elseif source=='ioc6.3' then
		return '[[:en:International Ornithological Congress|IOC classification 6.3]]'
	elseif source=='ioc6.4' then
		return '[[:en:International Ornithological Congress|IOC classification 6.4]]'
	elseif source=='ioc7.1' then
		return '[[:en:International Ornithological Congress|IOC classification 7.1]]'
	elseif source=='ioc7.2' then
		return '[[:en:International Ornithological Congress|IOC classification 7.2]]'
	elseif source=='ioc7.3' then
		return '[[:en:International Ornithological Congress|IOC classification 7.3]]'
	elseif source=='ioc8.1' then
		return '[[:en:International Ornithological Congress|IOC classification 8.1]]'
	elseif source=='ioc8.2' then
		return '[[:en:International Ornithological Congress|IOC classification 8.2]]'
	elseif source=='ioc9.1' then
		return '[[:en:International Ornithological Congress|IOC classification 9.1]]'
	elseif source=='ioc9.2' then
		return '[[:en:International Ornithological Congress|IOC classification 9.2]]'
	elseif source=='ioc10.1' then
		return '[[:en:International Ornithological Congress|IOC classification 10.1]]'
	elseif source=='ioc10.2' then
		return '[[:en:International Ornithological Congress|IOC classification 10.2]]'
	elseif source=='ioc11.1' then
		return '[[:en:International Ornithological Congress|IOC classification 11.1]]'
	elseif source=='ioc12.1' then
		return '[[:en:International Ornithological Congress|IOC classification 12.1]]'
	elseif source=='ioc12.2' then
		return '[[:en:International Ornithological Congress|IOC classification 12.2]]'
	elseif source=='ioc13.1' then
		return '[[:en:International Ornithological Congress|IOC classification 13.1]]'
	elseif source=='ioc13.2' then
		return '[[:en:International Ornithological Congress|IOC classification 13.2]]'
	elseif source=='ioc14.1' then
		return '[[:en:International Ornithological Congress|IOC classification 14.1]]'
	elseif source=='ioc' then
		return '[[:en:International Ornithological Congress|IOC classification]]'
	elseif source=='ion' then
		return '[http://www.organismnames.com/query.htm?Submit.x=10&Submit.y=9&searchType=simple&q=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' ION]'
	elseif source=='ipni' then
		return '[http://www.ipni.org/index.html IPNI]'
	elseif source=='it' then
		return '[[:it:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|it.wikipedia]]'
	elseif source=='itis' then
		return '[http://www.itis.gov ITIS]'
	elseif source=='iucn' then
		return '[http://www.iucnredlist.org/search/quick?x=0&y=0&species=true&subspecies=true&stocks=false&text=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' IUCN]'
	elseif source=='jboyd' then
		return "[http://jboyd.net/Taxo/ ''A Taxonomy in Flux'' (JBoyd.net)]"
	elseif source=='jörger et al. (2010)' then
		return "[[:en:Heterobranchia#2010_taxonomy|Jörger ''et al.'' (2010)]]"
	elseif source=='kew vascular plant' then
		return '[http://data.kew.org/cgi-bin/vpfg1992/genlist.pl?' .. getTaxonNameForUrl(taxonNameOrNil) .. " Kew Gardens 'Vascular Plant']"
	elseif source=='kew world checklist' then
		return '[http://apps.kew.org/wcsp/qsearch.do?page=quickSearch&plantName=' .. getTaxonNameForUrl(taxonNameOrNil) .. " Kew Gardens 'World Checklist']"
	elseif source=='lepindex' then
		return getCleverLepIndex(source, taxonNameOrNil)
	elseif source=='lpsn' then
		return '[http://www.bacterio.net/-classifphyla.html LPSN]'
	elseif source=='luther2008' then
		return '[[:en:Harry E. Luther|Harry E. Luther, 2008]]'
	elseif source=='nakano&ozawa2007' then
		return '[[:en:Patellogastropoda#2007_taxonomy|Nakano & Ozawa (2007)]]'
	elseif source=='malaquias et al. 2009' then
		return "[[:en:Cephalaspidea#2009 taxonomy|Malaquias ''et al.'' (2009)]]"
	elseif source=='msw' then
		return '[https://www.departments.bucknell.edu/biology/resources/msw3/search.asp?s=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' Mammal Species of the World (2005)]'
	elseif source=='mycobank' then
		return '[http://www.mycobank.org MycoBank]'
	elseif source=='nam' then
		return '[http://www.mnh.si.edu/mna North American Mammals]'
	elseif source=='ncbi' then
		return '[http://www.ncbi.nlm.nih.gov/Taxonomy NCBI]'
	elseif source=='nelson, j.s. 2006' then
		return '[[Template:Taxonavigation/Nelson, J.S. 2006 Fishes of the world|Nelson, J.S. 2006 Fishes of the world]]'
	elseif source=='nrcsplants' then
		return '[https://plants.usda.gov/java/ NRCS Plants]'
	elseif source=='nrcs plants' or source=='usdaplants' or source=='usda plants' then
		return '[https://plants.usda.gov/java/ NRCS Plants]' .. _common.incorrectBiologyTemplateUsage('Source', 'source ' .. source .. ' is incorrect. Please use nrcsplants', 'Taxasource', nil)
	elseif source=='plantsoftheworldonline' or source=='plants of the world online' then
		return '[http://www.plantsoftheworldonline.org/?q=' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. ' Plants of the world online]'
	elseif source=='reptiledb' then
		return '[http://reptile-database.reptarium.cz/ ReptileDB]'
	elseif source=='rushforth conifers' then
		return "Keith D. Rushforth ''Conifers''"
	elseif source=='sibley' then
		return '[[Template:Taxonavigation/Sibley-Ahlquist taxonomy|Sibley-Ahlquist]]' .. _common.incorrectBiologyTemplateUsage('Source', 'source sibley should not be used anymore', 'Taxasource', nil)
	elseif source=='smith' then
		return '[[Smith System]]'
	elseif source=='species' then
		return '[[:species:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|Wikispecies]]'
	elseif source=='sv' then
		return '[[:sv:' .. getTaxonNameForUrl(taxonNameOrNil, 'WIKI') .. '|sv.wikipedia]]'
-- Start TelaBotanica
	elseif source=='telaafriquen' then
		return '[http://www.tela-botanica.org/page:isfan Tela Botanica (Afrique du nord)]'
	elseif source=='telaafriquet' then
		return '[http://www.tela-botanica.org/page:apd Tela Botanica (Afrique tropicale)]'
	elseif source=='telaantilles' then
		return '[http://www.tela-botanica.org/page:isfgm Tela Botanica (Antilles)]'
	elseif source=='telametro' then
		return '[http://www.tela-botanica.org/page:eflore_bdtfx Tela Botanica (France métro.)]'
-- End TelaBotanica
-- Start SpeciesFile
	elseif source=='aphidsf' then
		return '[http://aphid.speciesfile.org Aphid Species File]'
	elseif source=='arthropodasf' then
		return '[http://arthropoda.speciesfile.org Arthropoda Species File]'
	elseif source=='blattodeasf' then
		return '[http://blattodea.speciesfile.org Blattodea Species File]'
	elseif source=='cockroachsf' then
		return '[http://cockroach.speciesfile.org Cockroach Species File]'
	elseif source=='coleorrhynchasf' then
		return '[http://coleorrhyncha.speciesfile.org Coleorrhyncha Species File]'
	elseif source=='collembolasf' then
		return '[http://collembola.speciesfile.org Collembola Species File]'
	elseif source=='coreoideasf' then
		return '[http://coreoidea.speciesfile.org Coreoidea Species File]'
	elseif source=='dermapterasf' then
		return '[http://dermaptera.speciesfile.org Dermaptera Species File]'
	elseif source=='embiopterasf' then
		return '[http://embioptera.speciesfile.org Embioptera Species File]'
	elseif source=='grylloblattodeasf' then
		return '[http://grylloblattodea.speciesfile.org Grylloblattodea Species File]'
	elseif source=='mantodeasf' then
		return '[http://mantodea.speciesfile.org Mantodea Species File]'
	elseif source=='orthopterasf' then
		return '[http://orthoptera.speciesfile.org Orthoptera Species File]'
	elseif source=='paraneopterasf' then
		return '[http://paraneoptera.speciesfile.org Paraneoptera Species File]'
	elseif source=='phasmidasf' then
		return '[http://phasmida.speciesfile.org Phasmida Species File]'
	elseif source=='plecopterasf' then
		return '[http://plecoptera.speciesfile.org Plecoptera Species File]'
	elseif source=='polyneopterasf' then
		return '[http://polyneoptera.speciesfile.org Polyneoptera Species File]'
	elseif source=='psocodeasf' then
		return '[http://psocodea.speciesfile.org Psocodea Species File]'
	elseif source=='orthopterasf' then
		return '[http://orthoptera.speciesfile.org Orthoptera Species File]'
	elseif source=='zorapterasf' then
		return '[http://zoraptera.speciesfile.org Zoraptera Species File]'
-- End SpeciesFile
	elseif source=='strasburger' then
		return '[[Strasburger]]'
	elseif source=='theastereaeworkinggroup' then
		return '[http://msb.unm.edu/divisions/herbarium/research/astereae-working-group/genera.html The Astereae Working Group]'
	elseif source=='theplantlist' then
		return '[http://www.theplantlist.org/tpl1.1/search?q=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' The Plant List]'
	elseif source=='ttdb' then
		return '[http://turbellaria.umaine.edu/turb2.php?action=5&sys=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' Turbellarian Taxonomic Database]'
	elseif source=='tolweb' then
		return '[http://tolweb.org/' .. getTaxonNameForUrl(taxonNameOrNil) .. ' TOLweb]'
	elseif source=='tpdb' then
		return '[http://paleodb.org TPDB]'
	elseif source=='tropicos' then
		return '[http://www.tropicos.org/NameSearch.aspx?exact=true&commonname=&name=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' Tropicos]'
	elseif source=='ubio' then
		return '[http://www.ubio.org/browser/search.php?search_all=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' uBIO]'
	elseif source=='weston&barker (2006)' then
		return '[http://www.rbgsyd.nsw.gov.au/__data/assets/pdf_file/0009/80856/Tel11Wes314.pdf Weston and Barker (2006)]'
	elseif source=='wrms' or source=='worms' then
		return '[http://www.marinespecies.org/aphia.php?p=taxlist&tName=' .. getTaxonNameForUrl(taxonNameOrNil) .. ' WoRMS]'
	elseif source=='wsc' then
		return '[https://wsc.nmbe.ch/search World Spider Catalog]'
	elseif source=='?' then
		return 'undetermined source'
	else
		_common.addDebug('getSourceLink', "Unknown source '" .. source .. "'")
		return source .. _common.incorrectBiologyTemplateUsage('Source', "(Unknown source '" .. source .. "')", 'Taxasource')
	end
end

function addSourceLinks(allsources, taxonNameOrNil, sources)
	if not string.isNilOrEmpty(sources) then
		sources = mw.text.split(sources, " & ", true) -- true for plaintext
		for index, source in pairs(sources) do
			source = mw.text.trim(source)
			source = string.lower(source)
			table.insert(allsources, {source, getSourceLink(source, taxonNameOrNil)})
		end
	end
end

function sourceIsBefore(t1,t2)
	local first = t1[1]
	local second = t2[1]
	if string.startsWith(first,'apg') then
		if string.startsWith(second,'apg') then
			-- latest first
			return first >= second
		end
	elseif string.startsWith(first,'ioc') then
		if string.startsWith(second,'ioc') then
			-- latest first
			return first >= second
		end
	end
	return first < second
end

-- Used by {{Taxasource}}
function getSourceLinks(args)
	local allsources = {}
	local taxonNameOrNil = args.name

	local links = ''

	for argNameOrIndex, argValue in pairs(args) do
		if type(argNameOrIndex) == 'string' then
			-- named argument pair: taxon=Amphiprion, ref=MyRef
			if string.startsWith(argNameOrIndex, 'ref') then
				table.insert(allsources, {'zzzz' .. argNameOrIndex, argValue})
			elseif argNameOrIndex == 'name' then
				-- already assigned in taxonNameOrNil
			else
				-- Not managed => error
				_common.addDebug('getSourceLinks', "Unmanaged parameter '" .. argNameOrIndex .. "' passed to Taxasource")
				links = links .. _common.incorrectBiologyTemplateUsage('Source', "Unmanaged parameter '" .. argNameOrIndex .. "' passed to Taxasource", 'Taxasource')
			end
		else
			-- normal argument pair: 1=ADW, 2=fishbase
			addSourceLinks(allsources, taxonNameOrNil, argValue)
		end
	end

	table.sort(allsources, sourceIsBefore)

	for index, sourceAndLink in pairs(allsources) do
		if string.len(links)>0 then
			links = links .. '&nbsp;&&nbsp;'
		end
		links = links .. sourceAndLink[2]
	end
	return links
end

-- Used by {{SimpleTaxa}}, {{Taxa}}, {{Genera}}, {{Genera2}}, {{Species}}, {{Species2}}, {{Subspecies}}, {{Minerals}} to display a list of taxon
function formatList(options)
	if not options then
		return "options is nul"
	end
	local italic = string.isTrue(options['italic'])

	local extinctCross = '†'
	if italic then
		extinctCross = '<span style="font-style:normal">†</span>'
	end

	local avoidFirstParamCount = options['avoidFirstParamCount']
	if avoidFirstParamCount then
		avoidFirstParamCount = tonumber(avoidFirstParamCount,10)
	end

	local link = options['link']
	if not link then
		link = 'true'
	end
	link = string.isTrue(link)
	
	local nameprefix = options['nameprefix']
	if link then
		local linkPrefix = '[[:Category:'
		if options['linkto'] and options['linkto'] == 'gallery' then
			linkPrefix = '[['
		end
		if string.isNilOrEmpty(nameprefix) then
			nameprefix = linkPrefix
		else
			nameprefix = linkPrefix .. nameprefix .. ' '
		end
	else
		nameprefix = nil
	end
	
	local displayprefix = options['displayprefix']
	if string.isNilOrEmpty(displayprefix) then
		displayprefix = ''
	else
		displayprefix = displayprefix .. ' ' -- non-breaking space
	end
	if link then
		displayprefix = '|' .. displayprefix
	else
		--displayprefix = displayprefix
	end

	local formatedList = nil
	for index = 1, 2602 do
		local indexStr = tostring(index)
		local name = string.trimOrNullify(options[indexStr])
		if not name then
			return formatedList
		end
		if name == 'STOP' then
			-- Needed by {{Invalid taxon category redirect}}
			return formatedList
		end
		if avoidFirstParamCount and index <= avoidFirstParamCount then
			-- First parameter of Template:Taxa and Template:SimpleTaxa is rank that we want to avoid
			-- First 2 parameters of Template:Species and Template:Species is genus cut in 2 that we want to avoid
			-- First 3 parameters of Template:Subspecies is species cut in 3
		else
			-- Manage extinct sign
			local namee = options['†' .. indexStr]
			local extinct = false
			if not string.isNilOrEmpty(namee) then
				-- Extinct sign 1 (deprecated + no more possible): coming from old template: |†2={{{{{{3}}}|}}}| where {{{{3}}}==Eohiodon and {{{{{{3}}}|}}}=='†'
				extinct = true
			else
				namee = options[name]
				if namee and string.find(namee,'†',1,true) then
					-- Extinct sign 2 (deprecated): coming from Module:Arguments: |Eohiodon=†|
					extinct = true
					options[name] = nil -- To avoid interpretation by Disambiguation
				elseif string.find(name,'†',1,true) then
					-- Extinct sign 3: |Eohiodon†| or |†Eohiodon|
					extinct = true
					name = string.gsub(name, '†', '', 5)
				end
			end

			-- Manage note
			local notepos = string.find(name,'note:',1,true)
			local note=''
			if notepos then
				note = ' ' .. mw.text.trim(string.sub(name,notepos+5))
				name = mw.text.trim(string.sub(name,1,notepos-1))
			end

			-- Manage disambiguation
			local displayName = name
			local disambiguated = false
			-- Disambiguation 1: '|Ibicella|Ibicella=Ibicella (Martyniaceae)|'
			local namedisamb = options[name]
			if not string.isNilOrEmpty(namedisamb) then
				if string.startsWith(string.lower(namedisamb),string.lower(name)) then
					-- Disambiguation 1: Ibicella|Ibicella=Ibicella (Martyniaceae)
				else
					-- Disambiguation 1bis: Ibicella|Ibicella=(Martyniaceae)
					namedisamb = name .. ' ' .. namedisamb
				end
				name = namedisamb
				displayName = name
				disambiguated = true
			end
			-- Disambiguation 2: '|Ibicella (Martyniaceae)|'
			-- Warning, it will manage  Disambiguation 1 if parentheses are involved
			local parenthesisStart = string.find(displayName,' (',1,true)
   	 		if parenthesisStart then
				local parenthesisEnd = string.find(displayName,')',parenthesisStart,true)
				if parenthesisEnd then
					displayName = string.sub(displayName,1,parenthesisStart-1) .. '<small>' .. string.sub(displayName,parenthesisStart,parenthesisEnd) .. '</small>' .. string.sub(displayName,parenthesisEnd+1)
					disambiguated = true
				end
			end
			-- Disambiguation 3 (deprecated): '|Ibicella|d2=(Martyniaceae)|'
			if not disambiguated then
				local named = options['d' .. indexStr]
				if not string.isNilOrEmpty(named) then
					name = name .. ' ' .. named
					displayName = displayName .. ' <small>' .. named .. '</small>'
				end
			end

            -- Manage var. and subsp.
            if italic then
            	displayName = displayName.gsub(displayName, 'var. ', '<span style="font-style:normal">var. </span>', 1)
            	displayName = displayName.gsub(displayName, 'subsp. ', '<span style="font-style:normal">subsp. </span>', 1)
            end
            
			if name == '...' then
				if formatedList then
					formatedList = formatedList .. '...<small> (incomplete list)</small>'
				else
					formatedList = '...<small> (incomplete list)</small>'
				end
			else
				if formatedList then
					formatedList = formatedList .. ', '
				else
					formatedList = ''
				end
				-- Detect too small entries
				if string.len(name) <= 1 then
					formatedList = formatedList .. _common.incorrectBiologyTemplateUsage('Taxa', "Too short taxonName/epithet '" .. name .. "' :", 'Taxa')
				elseif string.startsWith(name, 'X ') then
					formatedList = formatedList .. _common.incorrectBiologyTemplateUsage('Taxa', "Incorrect taxonName/epithet '" .. name .. "' containing X instead of ×:", 'Taxa')
				elseif string.startsWith(name, 'x ') then
					formatedList = formatedList .. _common.incorrectBiologyTemplateUsage('Taxa', "Incorrect taxonName/epithet '" .. name .. "' containing x instead of ×:", 'Taxa')
				elseif string.startsWith(name, '×') and not string.startsWith(name, '× ') then
					formatedList = formatedList .. _common.incorrectBiologyTemplateUsage('Taxa', "Incorrect taxonName/epithet '" .. name .. "' having × without space:", 'Taxa')
				end
				if extinct then
					formatedList = formatedList .. extinctCross
				end
				--displayName='<taxon> <small><disamb></small>'
				if link then
					-- nameprefix=   '[[:Category:<genus> <species> ' (ssp list) or '[[<genus> <species> ' (ssp list) or '[[:Category:<genus> ' (sp list) or '[[<genus> ' (sp list) or '[[:Category:' (taxa/genus list) or '[[' (taxa/genus list)
					-- displayprefix='|<G>. <S>.'                     (ssp list)                                      or '|<G>. '               (sp list)                           or '|'            (taxa/genus list)
					formatedList = formatedList .. nameprefix .. name .. displayprefix .. displayName .. ']]'
				else
					-- displayprefix='<G>. <S>. '                     (ssp list)                                      or '<G>. '                (sp list)                           or ''             (taxa/genus list)
					formatedList = formatedList .. displayprefix .. displayName
				end
				formatedList = formatedList .. note
			end
		end
	end
	return formatedList
end

-- Used by {{IPNI}} and {{Kew list}} to transform "Cattleya × ballantiniana" in "Cattleya ballantiniana"
function suppressNothospeciesX(text)
	if not text then
		return ''
	end
	text = string.gsub(text, '×', ' ', 5)
	text = string.gsub(text, '  ', ' ', 5)
	text = string.gsub(text, '  ', ' ', 5)
	text = string.gsub(text, '  ', ' ', 5)
	return mw.text.trim(text)
end

-- Used by {{IPNI}} if first parameter is empty or a year number
-- returns '1' for true, '' for false to be used with {{#if:
function isEmptyOrNumeric(text)
	if not text then
		return true
	end
	if string.len(text) == 0 then
		return true
	end
	if tonumber(text,10) == nil then
		return false
	else
		return true
	end
end

-- checkDate() verifies that the passed date is in the format 'YYYY-MM-DD' like '2012-12-31'
-- return '' if yes
-- return error message + category if not in correct format
function internalCheckDate(mydate)
	local pattern = '(%d+)%-(%d+)%-(%d+)'
	local format = ". Format: 'YYYY-MM-DD' like '2012-12-31'"
	local yearStr, monthStr, dayStr = mydate:match(pattern)
	if not yearStr or not monthStr or not dayStr then
		return 'Incorrect date ' .. mydate .. format
	end
	local year = tonumber(yearStr)
	local month = tonumber(monthStr)
	local day = tonumber(dayStr)
	if not year or not month or not day then
		return 'Incorrect date ' .. mydate .. format
	end
	if year < 2005 or year > 2050 then 
		return 'Incorrect year ' .. year .. ' in date ' .. mydate .. format
	end
	if month < 1 or month > 12 then 
		return 'Incorrect month ' .. month .. ' in date ' .. mydate .. format
	end
	if day < 0 or day > 31 then 
		return 'Incorrect day ' .. day .. ' in date ' .. mydate .. format
	end
	_common.addDebug('checkDate', 'Perfect date: year=' .. year .. ' month=' .. month .. ' day=' .. day)
	return nil
end

-- checkDate() verifies that the passed date is in the format 'YYYY-MM-DD' like '2012-12-31'
-- return '' if yes
-- return error message + category if not in correct format
function checkDate(mydate, templateNameForDoc, ignoreNamespace)
	local error = internalCheckDate(mydate)
	if error then
		return _common.incorrectBiologyTemplateUsage('Date', error, templateNameForDoc, ignoreNamespace)
	else
		return ''
	end
end


----------------------------------------------------------------------------------------------------
---------- PUBLIC FUNCTIONS ------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

local p = {}
local getArgs = require('Module:Arguments').getArgs

-- public version of getSourceLinks()
-- Used by {{Taxasource}}
function p.getSourceLinks(frame)
	local args = getArgs(frame)
	return getSourceLinks(args) .. _common.getDebug('<BR/>Debug:<BR/>')
end

-- public version of formatList()
-- Used by {{SimpleTaxa}}, {{Taxa}}, {{Genera}}, {{Genera2}}, {{Species}}, {{Species2}}, {{Subspecies}}, {{Minerals}}
function p.formatList(frame)
	local args = getArgs(frame)

	if not string.isNilOrEmpty(args['accessdate']) then
		_common.addDebug('formatList', 'accessdate=' .. args['accessdate'])
	end
	local formatedList = formatList(args)
	if formatedList then
		local italic = string.isTrue(frame.args['italic'])
		if italic then
			formatedList = "<i>" .. formatedList .. "</i>"
		end
	else
		formatedList = ''
	end
	-- Now add debug traces if activated
	formatedList = formatedList .. _common.getDebug('\n<BR/>Debug:<BR/>')
	return formatedList
end

-- public version of suppressNothospeciesX()
-- Used by {{IPNI}}, {{Kew list}}
function p.suppressNothospeciesX(frame)
	return suppressNothospeciesX(frame.args['1'])
end

-- public version of isEmptyOrNumeric().
-- Used by {{IPNI}}
function p.isEmptyOrNumeric(frame)
	if isEmptyOrNumeric(frame.args['1']) then
		return '1'
	else
		return ''
	end
end

-- public version of checkDate()
-- Used by {{TaxasourceAndDate/CheckDate}}
function p.checkDate(frame)
	local mydate = frame.args['1']
	if string.isNilOrEmpty(mydate) then
		 return ''
	end
	local templateNameForDoc = frame.args.templateNameForDoc
	local ignoreNamespace = frame.args.ignoreNamespace
	if string.isNilOrEmpty(templateNameForDoc) then
		 templateNameForDoc = 'TaxasourceAndDate'
	end
	return checkDate(mydate, templateNameForDoc, ignoreNamespace)
end

----------------------------------------------------------------------------------------------------
---------- Testcase public functions (return string) -----------------------------------------------
----------------------------------------------------------------------------------------------------

function p.testcase_getTaxonNameOutOfTitle(frame)
	return getTaxonNameOutOfTitle(frame.args['1']) .. _common.getDebug('Debug: ')
end

function p.testcase_getSourceLink(frame)
	-- testcase (return nowiki string when normal function returns wiki syntax)
	return mw.text.nowiki(getSourceLink(frame.args['1'], frame.args['2'])) .. _common.getDebug('Debug: ')
end

function p.testcase_getSourceLinks(frame)
	-- testcase (return nowiki string when normal function returns wiki syntax)
	return mw.text.nowiki(getSourceLinks(frame.args)) .. _common.getDebug('Debug: ')
end

function p.testcase_formatList(frame)
	-- testcase (return nowiki string when normal function returns wiki syntax)
	return mw.text.nowiki(p.formatList(frame)) .. _common.getDebug('Debug: ')
end

function p.testcase_checkDate(frame)
	-- testcase (return nowiki string when normal function returns wiki syntax)
	return mw.text.nowiki(p.checkDate(frame)) .. _common.getDebug('Debug: ')
end

return p