Module:BiologyList/sandbox

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 used by {{Subspecies/sandbox}}, {{Species/sandbox}}, {{Species2/sandbox}}, {{Genera/sandbox}}, {{Genera2/sandbox}}, {{Taxa/sandbox}}, {{SimpleTaxa/sandbox}}
which are the sandbox template (to test new developments) of {{Subspecies}}, {{Species}}, {{Species2}}, {{Genera}}, {{Genera2}}, {{Taxa}}, {{SimpleTaxa}}
The final module is Module:BiologyList
How to improve and test this module
  1. developp your modification in BiologyList/sandbox, the sandbox of this module (to test new developments)
    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 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 BiologyList/testcases
  8. if needed improve the testcases BiologyList/testcases

Code

local _common=require('Module:Biology/sandbox')

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=='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 '[http://www.bucknell.edu/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 .. ' '
	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