# Module:FishRef

require('strict')  

local p = {}  
local data = {}  
local templateArgs = {} -- contains arguments passed to cite web  
local target = {} -- short cut to target table, e.g. fishbase, cof, etc  

local function firstToUpper(str)  
return (str:gsub("^%l", string.upper))  
end  
-- define citation template and custom parameters for various sources  

--####################### Default functions ##########################  
data.default = {}  
-- currently being tested on Avibase, but Fossilworks, Tropicos, FNA and a few others are candidates  
data.default.id = function (id, source)  
local title = id  
local url = source.customArgs['baseURL'] .. (source.customArgs['searchStr'] or "") .. id  
return title, url  
end  
data.default.error = function  
return "Minimal requirement is two of id, url and title parameters"  
end  
data.default.search = function (search, source)  
local title = "Search for " .. search  
local url = source.customArgs['baseURL'] .. source.customArgs['searchString'] .. search .. source.customArgs['searchSuffix']  
return title, url  
end  

--[[ handling for ID only (unused, original concept)  
p.genericIdCitation = function(, title, url)  

if not templateArgs['id'] then return "no id parameter detected" end  

templateArgs['url']= target.CustomArgs['baseURL'] .. target.CustomArgs['searchStr'] .. templateArgs['id']  

return p.citeWeb(, title, url)  
end]]  
--####################### FISH #####################################  
--======================== Fishbase =================================  
data.fishbase = {  
citationArgs = {  
['editor1-last']="Froese", ['editor1-first']="Rainer", ['editor1-link']="Rainer Froese",  
['editor2-last']="Pauly", ['editor2-first']="Daniel",  
--['last-author-amp'] ="yes",  
['website'] = "Fishbase",  
--['publisher'] = ""  
},  
customArgs = { exclude= "order, family,genus, species, subspecies, 1, 2, 3, 4",  
baseURL = "http://www.fishbase.org/",  
defaultTitle = "Search FishBase"  
},  
}  
data.fishbase.species = function(genus, species, subspecies)  

local title = genus .. " " .. species  
local url = data.fishbase.customArgs['baseURL']  
.. "summary/SpeciesSummary.php?genusname=" .. genus .. "&speciesname=" .. species  
if subspecies then  
url = url .. "+" .. subspecies  
title = title .. " " .. subspecies  
end  
title = "*" .. title .. "*"  
return title, url  
end  
data.fishbase.genus = function(genus)  
local title = "Species in genus *" .. firstToUpper(genus) .. "*"  
local url = data.fishbase.customArgs['baseURL'] .. "identification/SpeciesList.php?genus=" .. genus  
return title, url  
end  
data.fishbase.order = function(order)  
local title = "Order " .. firstToUpper(order)  
local url = data.fishbase.customArgs['baseURL'] .. "Summary/OrdersSummary.php?order=" .. order  
return title, url  
end  
data.fishbase.family = function(family)  
local title = "Family " .. firstToUpper(family)  
local url = data.fishbase.customArgs['baseURL'] .. "Summary/FamilySummary.php?family=" .. family  
return title, url  
end  
data.fishbase.error = function  
return "No recognised taxon options: order, family, genus, species, subspecies."  
end  
data.fishbase.custom = function  
--TODO decide what to do with default date  
local version = "April 2006 version" -- Should we have a default (probably not)  
if templateArgs['month'] then version = templateArgs['month'] end  
if templateArgs['year'] then version = templateArgs['year'] .. " version" end  
if templateArgs['month'] then version = templateArgs['month'] .. " " .. version end  
templateArgs['version'] = version  
end  
--================================ Catalog of Fishes ================================================  
data.cof = {  
citationArgs = {  
--baseURL = "http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatget.asp?",  
['editor1-last']="Eschmeyer", ['editor1-first']="William N.", ['editor1-link']="William N. Eschmeyer",  
['editor2-last']="Fricke", ['editor2-first']="Ron",  
['editor3-last']="van der Laan", ['editor3-first']="Richard",  
['name-list-style'] ="amp",  
['website'] = "Catalog of Fishes",  
['publisher'] = "California Academy of Sciences"  
},  
customArgs = { exclude= "family,genus,species,genid,spid,id,list,1,2,3",  
baseURL = "http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatget.asp?",  
defaultTitle = "CAS - Eschmeyer's Catalog of Fishes"  
}  
}  
data.cof.species = function(genus, species, subspecies)  
local taxon = genus .. " " .. species  
local url = data.cof.customArgs['baseURL'] .. 'tbl=species&genus=' .. genus .. '&species=' .. species  
local title = "Species related to " .. "*" .. firstToUpper(taxon) .. "*" -- .. "" species synonyms"  
return title, url  
end  
data.cof.genus = function(genus)  
local url = data.cof.customArgs['baseURL'] .. 'tbl=species&genus=' .. genus  
local title = "Species in the genus *" .. firstToUpper(genus) .. "*"  
return title, url  
end  
-- note the family works with subfamilies using &family=SUBFAMILY  
data.cof.family = function(family)  
local list = templateArgs['list'] or "genus"  
local url = data.cof.customArgs['baseURL'] .. 'tbl=' .. list .. '&family=' .. family  
local title = "Species"  
if list == "genus" then title = "Genera" end  
title = title .. ' in the family ' .. firstToUpper(family)  
return title, url  
end  
data.cof.genid = function(genid)  
local searchStr = "genid" .. '=' .. genid  
local title = searchStr  
local url = data.cof.customArgs['baseURL'] .. searchStr  
return title, url  
end  
data.cof.spid = function(spid)  
local searchStr = "spid" .. '=' .. spid  
local title = searchStr  
local url = data.cof.customArgs['baseURL'] .. searchStr  
return title, url  
end  
data.cof.error = function  
return "Error. No recognised option set by template (need one of family, genus, species (also requires genus), spid, or genid"  
end  
--======================Fishes of the World 5===============================  
data.fotw5 = {  
citeTemplate = "Cite book",  
citationArgs = {  
--['website'] = "[[]]",  
first1 = "Joseph S.", last1 = "Nelson",  
first2="Terry C.", last2="Grande",  
first3="Mark V. H.", last3="Wilson",  
--work = "Fishes of the World (work)",  
title = "Fishes of the World", edition="5th", year = 2016,  
publisher ="John Wiley and Sons", location="Hoboken",  
isbn = "978-1-118-34233-6", doi="10.1002/9781119174844" ,  
},  
customArgs = {exclude="gb-page,q,dq,1",  
baseURL = "https://onlinelibrary.wiley.com/doi/book/10.1002/9781119174844", -- online library  
defaultTitle = "Fishes of the World",  
altTitle = "Fishes of the World", -- wikilinked for when using chapter/section title  
altURL = "https://sites.google.com/site/fotw5th/", -- classification  
},  
GoogleBooks = { baseURL = "https://books.google.co.uk/books?id=",  
id = "E-MLDAAAQBAJ",  
defaultPage = "&pg=PP1"  
}  
}  
data.fotw5.default2 = function(targs)  
local title = data.fotw5.citationArgs['work']  
local url = data.fotw5.customArgs['baseURL']  
local chapterParams = { title = title,  
['chapter-url']= data.fotw5.customArgs['googleBooks']  
}  
--return title, url, chapterParams  
end  

data.BentonVP4 = {  
citeTemplate = "Cite book",  
citationArgs = {  
first1 = "Michael J.", last1 = "Benton",  
title = "Vertebrate Palaeontology", edition="4th", year = 2014,  
publisher ="John Wiley & Sons",  
isbn = "978-1-118-40764-6",  
},  
customArgs = {exclude="gb-page,q,dq,1",  
--baseURL = "",  
defaultTitle = "Vertebrate Palaeontology",  
altTitle = "Vertebrate Palaeontology" -- wikilinked for when using chapter/section title  
},  
GoogleBooks = { baseURL = "https://books.google.co.uk/books?id=",  
id = "qak-BAAAQBAJ",  
defaultPage = "&pg=PP1",  
}  
}  

--====================TODO FishWisePro==================================================  
data.fishwisepro = {  
citationArgs = {  
['website'] = "FishWisePro",  

},  
customArgs = {exclude="family,genus,species,1",  
baseURL = ""  
}  
}  

-- #################### AMPHIBIA and REPTILES ###############################  
-- ================= Amphibian Species of the World (ASW6)  
--Recommended citation: Frost, Darrel R. 2019. Amphibian Species of the World: an Online Reference. Version 6.0 (Date of access). Electronic Database accessible at http://research.amnh.org/herpetology/amphibia/index.html. American Museum of Natural History, New York, USA.  
URL for family page: http://research.amnh.org/vz/herpetology/amphibia/Amphibia/Anura/Allophrynidae  
baseURL = http://research.amnh.org/vz/herpetology/amphibia/  
suffix = Amphibia/Anura/Allophrynidae  
note: needs the whole hierarchy (except the superfamily which is optional)  
Template for main taxonomic listing:  
SEARCH http://research.amnh.org/vz/herpetology/amphibia/amphib/basic_search?basic_query=Atelopus&stree=&stree_id=  
searchSuffix = amphib/basic_search?basic_query=Atelopus&stree=&stree_id=  
SEARCH http://research.amnh.org/vz/herpetology/amphibia/content/search?taxon=Allophryn*&subtree=&subtree_id=&english_name=&author=&year=&country=  
searchSuffix = /content/search?taxon=Allophryn*&subtree=&subtree_id=&english_name=&author=&year=&country=  
minimul = /content/search?taxon=Allophryn*&subtree  

data.ASW6 ={  
citationArgs = {  
website ="Amphibian Species of the World, an Online Reference.",  
version = "Version 6.0",  
publisher = "American Museum of Natural History, New York",  
['last1']="Frost", ['first1']="Darrel R.", ['author1-link']="Darrel R. Frost",  
},  
customArgs = { exclude = "taxon,species,genus,family, superfamily,1,2,3",  
baseURL = "http://research.amnh.org/herpetology/amphibia/",  
defaultSuffix = "index.html",  
defaultTitle = "ASW Home"  
}  
}  

data.ASW6.species = function(genus, species, subspecies)  

-- search for genus+species  
local title = "Search for taxon: " .. "*" .. genus .. " " .. species .. "*"  

--local search = ""?action=names&taxon="" -- old version (pre ASW6)  
--local search = "amphib/basic_search?basic_query=" -- basic search  
local search = "content/search?taxon=" -- guided search for taxon name  

local url = data.ASW6.customArgs['baseURL'] .. search -- .. genus .. '+AND+' .. species  
.. '&quot;' .. genus .. '+' .. species .. '&quot;'  
return title, url  
end  
data.ASW6.genus = function(genus)  
return data.ASW6.taxon(genus) -- use genus as alias of taxon  
end  
data.ASW6.taxon = function(taxon)  
local title = "Search for Taxon: " .. taxon  
local url= data.ASW6.customArgs['baseURL'] .. "content/search?taxon=" .. taxon  
return title, url  
end  
data.ASW6.family = function(family)  
local order = data.ASW6.checkOrder(family)  
local url= data.ASW6.customArgs['baseURL'] .. "Amphibia/" .. order .. "/" .. firstToUpper(family)  
local title = firstToUpper(family)  
return title, url  
end  
data.ASW6.checkOrder = function(family)  

local gymnophiona={ "Caeciliidae", "Chikilidae", "Dermophiidae", "Herpelidae", "Ichthyophiidae", "Grandisoniidae", "Indotyphlidae", "Rhinatrematidae", "Scolecomorphidae", "Siphonopidae", "Typhlonectidae" }  
local caudata = { "Ambystomatidae", "Amphiumidae", "Cryptobranchidae", "Hynobiidae", "Plethodontidae", "Proteidae", "Rhyacotritonidae", "Salamandridae", "Sirenidae" }  

for k,v in pairs(caudata) do  
if v == family then return "Caudata" end  
end  
for k,v in pairs(gymnophiona) do  
if v == family then return "Gymnophiona" end  
end  

return "Anura"  
end  

--============================= AmphibiaWeb ===================================  
-- Citation: AmphibiaWeb. 2019. <https://amphibiaweb.org> University of California, Berkeley, CA, USA. Accessed 27 Sep 2019.  
Code:  
---
data.amphibiaweb = {  
citationArgs = {  
website = "AmphibiaWeb",  
publisher = "University of California, Berkeley",  
--['editor1-last']="", ['editor1-first']="", ['editor1-link']="",  
},  
customArgs = { exclude = "taxon,species,genus,family,1,2,3",  
baseURL = "https://amphibiaweb.org/",  
defaultSuffix = "taxonomy/AW_FamilyPhylogeny.html",  
defaultTitle = "AmphibiaWeb Family Taxonomy"  
}  
}  
data.amphibiaweb.species = function (genus, species, subspecies)  
local title = "*" .. genus .. " " .. species .. "*"  
--https://amphibiaweb.org/cgi/amphib_query?where-genus=Altiphrynoides&where-species=malcolmi  
local url = data.amphibiaweb.customArgs['baseURL'] .. "cgi/amphib_query?rel-genus=equals&where-genus="  
.. genus .. "&rel-species=equals&where-species=" .. species  
return title, url  
end  
data.amphibiaweb.genus = function (genus)  
local title = "*" .. genus .. "*"  
--https://amphibiaweb.org/cgi/amphib_query?where-genus=Altiphrynoides&where-species=malcolmi  
local url = data.amphibiaweb.customArgs['baseURL'] .. "cgi/amphib_query?rel-genus=equals&where-genus="  
.. genus .. "&include_synonymies=Yes&show_photos=Yes"  
return title, url  
end  
data.amphibiaweb.family = function (family) -- if family use standardised url  
local url = data.amphibiaweb.customArgs['baseURL'] .. "lists/" .. firstToUpper(templateArgs['family']) .. ".shtml"  
local title = templateArgs['family']  
return title, url  
end  

--=========================== The Reptile Database  
data.reptileDB = {  
-- http://reptile-database.reptarium.cz/species?genus=Epacrophis&species=boulengeri  
-- recommended citation: Uetz, P., Freed, P. & Hošek, J. (eds.) (2019) The Reptile Database, http://www.reptile-database.org, accessed [insert date here]  
citationArgs = {  
--website="reptile-database.org",  
website="The Reptile Database",  
['editor1-last']="Uetz", ['editor1-first']="P.", --['editor1-link']="Peter Uetz",  
['editor2-last']="Freed", ['editor2-first']="P.",  
['editor3-last']="Hošek", ['editor3-first']="J.",  
--year=2019  

},  
customArgs = { exclude = "taxon,species,genus,family,1,2,3",  
baseURL = "http://reptile-database.reptarium.cz/"  
}  
}  

data.reptileDB.species = function(genus, species)  
local title = "*" .. genus .. " " .. species .. "*"  
--http://reptile-database.reptarium.cz/species?genus=Loxocemus&species=bicolor  
local url = data.reptileDB.customArgs['baseURL'] .. "species?genus=" .. genus .. "&species=" .. species  
return title, url  
end  
data.reptileDB.genus = function(genus)  
local title = "*" .. genus .. "*"  
--http://reptile-database.reptarium.cz/advanced_search?genus=Malayopython&submit=Search  
local url = data.reptileDB.customArgs['baseURL'] .. "advanced_search?genus=" .. genus .. "&exact%5B0%5D=taxon&submit=search"  
return title, url  
end  
data.reptileDB.family = function(family)  
return data.reptileDB.taxon(family)  
end  
data.reptileDB.order = function(order)  
return data.reptileDB.taxon(order)  
end  
data.reptileDB.taxon = function(taxon)  
local title = taxon  
--http://reptile-database.reptarium.cz/advanced_search?taxon=Viperidae&exact%5B0%5D=taxon&submit=Search  
local url = data.reptileDB.customArgs['baseURL'] .. "advanced_search?taxon=" .. taxon .. "&exact%5B0%5D=taxon&submit=search"  
return title, url  
end  

--################################### BIRDS ########################################  
--====================Handbook of the Birds of the World Alive (HBW Alive)==============  
data.HBWalive = {  
citationArgs = {  
website="Handbook of the Birds of the World Alive",  
publisher="Lynx Edicions"  
},  
customArgs = { exclude="order,family,genus,species,taxon,id,1",  
baseURL = "https://www.hbw.com/",  
defaultSuffix = "family/home",  
defaultTitle = "Family | HBW Alive"  

}  
}  
--############################## HBW ALIVE #########################################  
-- family and species entries have mix of common name and taxon name so cannot be prempted;  
-- must use title + url (which uses default functions in this module)  
data.HBWalive.order = function(order)  
local title = "Order " .. firstToUpper(order)  
--https://www.hbw.com/order/struthioniformes  
local url = target.customArgs['baseURL'] .. "order/" .. order  
return title, url  
end  

--======================IOC World Bird List==========================  
Gill, F & D Donsker (Eds). 2019. IOC World Bird List (v9.2). doi : 10.14344/IOC.ML.9.2.  
Gill F, D Donsker & P Rasmussen (Eds). 2020. IOC World Bird List (v10.2). doi : 10.14344/IOC.ML.10.1.  

data.IOC = {  
citationArgs = {  
website="IOC World Bird List",  
-- version="Version 9.2", -- shouldn't default; should be hardcode so it doesn't change  
['editor1-last']="Gill", ['editor1-first']="F.", ['editor1-link']="Frank Gill (ornithologist)",  
['editor2-last']="Donsker", ['editor2-first']="D.",  
['editor3-last']="Rasmussen", ['editor3-first']="P.", -- TODO only show from version 10.1 onwards  
-- doi = "10.14344/IOC.ML.9.2", -- this changes by version number and is not a useful part of the cictation  
publisher="International Ornithological Congress"  
},  
customArgs = { exclude="order,family,genus,species,taxon,id,1",  
baseURL = "https://www.worldbirdnames.org/",  
defaultSuffix = "",  
defaultTitle = "IOC World Bird List: Welcome"  

},  
}  
data.IOC.version = function  
local version = templateArgs['version']  
local old = false  
if version then  
version = string.gsub( version, "[Vv]ersion ", "")  
local versionNumber = tonumber(version)  
if versionNumber < 10.1 then  
old = true  
end  
else  
local Date = require('Module:Date')._Date  
if Date(templateArgs['access-date']) < Date('1 January 2020') then  
old = true  
end  
end  

if old then  
data.IOC.citationArgs['editor3-last'] = nil  
data.IOC.citationArgs['editor3-first'] = nil  
end  
end  
data.IOC.order = function(order)  
data.IOC.version  
local IOCorders = {Struthioniformes='ratites',Rheiformes='ratites',Apterygiformes='ratites',Casuariiformes='ratites',Tinamiformes='ratites',Galliformes='megapodes',Anseriformes='waterfowl',Caprimulgiformes='nightjars',Apodiformes='swifts',Musophagiformes='turacos',Otidiformes='turacos',Cuculiformes='turacos',Mesitornithiformes='turacos',Pterocliformes='turacos',Columbiformes='pigeons',Gruiformes='flufftails',Podicipediformes='grebes',Phoenicopteriformes='grebes',Charadriiformes='sandpipers',Eurypygiformes='loons',Phaethontiformes='loons',Gaviiformes='loons',Sphenisciformes='loons',Procellariiformes='loons',Ciconiiformes='storks',Suliformes='storks',Pelecaniformes='pelicans',Opisthocomiformes='raptors',Accipitriformes='raptors',Strigiformes='owls',Coliiformes='mousebirds',Leptosomiformes='mousebirds',Trogoniformes='mousebirds',Bucerotiformes='mousebirds',Coraciiformes='rollers',Piciformes='woodpeckers',Cariamiformes='falcons',Falconiformes='falcons',Psittaciformes='parrots',  
Passeriformes='nz_wrens'} -- passeriformes link not very useful  

local title = "Order " .. firstToUpper(order)  
local url = data.IOC.customArgs['baseURL'] .. "/bow/" .. IOCorders[order]  
return title, url  
end  
data.IOC.family = function(family)  
data.IOC.version  
local IOCfamilies = { Struthionidae = {"ratites", 4}, Alcippeidae = {"babblers", 24989 } } -- temporary partial list for testing  

local title = "Family " .. firstToUpper(family)  
--https://www.worldbirdnames.org/Family/Struthionidae  
local url = data.IOC.customArgs['baseURL'] .. "Family/" .. family -- old version (might be resurrected by IOC)  

-- https://www.worldbirdnames.org/new/bow/babblers/#1338626516R24989  
if IOCfamilies[family] then -- test version local partial list  
url = data.IOC.customArgs['baseURL'] .. "new/bow/" .. IOCfamilies[family][1] .. "/#1338626516R" .. IOCfamilies[family][2]  
end  
return title, url  
end  
data.IOC.default = function( title, url)  
data.IOC.version  
return title, url  
end  

data.BOW = {  
citationArgs = {  
website="Birds of the World Online",  
-- doi = "",  
-- ['last1']="Winkler", ['first1']="David W.", -- are these always the authors in version 1? no, perhaps for family page  
-- ['last2']="Billerman", ['first2']="Shawn M.",  
-- ['last3']="Lovette", ['first3']="Irby J.",  
-- ['editor1-last']="Billerman", ['editor1-first']="S. M.", --['editor1-link']="",  
-- ['editor2-last']="Keeney", ['editor2-first']="B. K.",  
-- ['editor3-last']="Rodewald", ['editor3-first']="P. G.",  
-- ['editor4-last']="Schulenberg", ['editor4-first']="T. S.",  
-- ['version'] = 1, ['year'] = 2020, -- may not want to default  
publisher="Cornell Lab of Ornithology, Ithaca, NY."  
},  
customArgs = { exclude="citation,make,order,family,genus,species,taxon,id,1",  
baseURL = "https://birdsoftheworld.org/bow/species",  
defaultSuffix = "",  
defaultTitle = "Explore Taxonomy"  

},  
}  

data.BOW.default = function( title, url)  
--data.BOW.citationArgs['version'] = "Version 1"  
return title, url  
end  

-- make BOW to parse standard citation,  
vesrion 1 (family): Winkler, D. W., S. M. Billerman, and I.J. Lovette (2020). Bulbuls (Pycnonotidae), version 1.0. In Birds of the World  
(S. M. Billerman, B. K. Keeney, P. G. Rodewald, and T. S. Schulenberg, Editors). Cornell Lab of Ornithology, Ithaca, NY, USA.  
https://doi.org/10.2173/bow.pycnon4.01  
version 2 (species): Limparungpatthanakij , W. L., L. Fishpool, and J. Tobias (2020). Buff-vented Bulbul (Iole crypta), version 2.0. In Birds of the World  
(S. M. Billerman and B. K. Keeney, Editors). Cornell Lab of Ornithology, Ithaca, NY, USA.  
https://doi.org/10.2173/bow.buvbul1.02  

data.BOW.citation = function( value)  
local citation = templateArgs['citation']  

data.BOW.citationArgs['year'] = citation:match ('^%D+(%d%d%d%d)')  
data.BOW.citationArgs['doi'] = citation:match ('10%.2173/bow%..+') -- https://doi.org/10.2173/bow.pycnon4.01  
--data.BOW.citationArgs['version'] = citation:match ('version %d%.%d') -- version applies to page, not whole BOW  
local title = citation:match ('%d%d%d%d%)%.(.*, version %d%.%d)'); -- include version number in title  
local suffix = citation:match ('10%.2173/bow%.(.+%d)%.'); -- https://doi.org/10.2173/bow.pycnon4.01  
local version = "/cur/" -- for the current version  
version = citation:match ('version (%d%.%d)') -- for the cited version  
local url = data.BOW.customArgs['baseURL'] .. '/' .. suffix .. '/' .. version .. '/'  

title = title:gsub( '%((%D+) (%D+)%)' , "(*%1 %2*)")  

local authors = citation:match ('^(%D+) %(%d%d%d%d%)')  
--data.BOW.citationArgs['authors'] = citation:match ('^(%D+)%(%d%d%d%d%)')  
--data.BOW.citationArgs['editors'] = citation:match ('In Birds of the World %((.-)Editors%)' ) -- omit editors as cite web psoitioning is weird  
if authors then -- split authors with modified code from make cite iucn  
local list = {}  
authors = authors:gsub(", and ", ", ")  
--local names = author_names:gsub ('%.?,?%s+&%s+', '.|'):gsub ('%.,%s+', '.|'); -- replace 'separators' (<dot><comma><space> and <opt. dot><opt. comma><space><ampersand><space>) with <dot><pipe>  
local names = authors:gsub (',%s+', '|'); -- replace any comma  
-- :gsub ('%.?,?%s+and%s+', '|') -- replace 'separators' <opt. dot><opt. comma><space>and<space>) with <dot><pipe>  
-- :gsub ('%.,%s+', '.|'); -- replace 'separators' <dot><comma><space> with <dot><pipe>  
list = mw.text.split (names, '|'); -- split the string on the pipes into entries in list  
if #list == 0 then  
data.BOW.citationArgs['authors'] = authors -- no 'names' of the proper form; return the original as a single |author= parameter  
else  
for i, name in ipairs (list) do -- for each author in list  
data.BOW.citationArgs['author'..i-1] = name -- add |authorn= parameter names  
-- list[i] = table.concat ({'|author', (i == 1) and '' or i, '=', name}); -- add |authorn= parameter names; create |author= instead of |author1=  
end  
data.BOW.citationArgs['author1'] = data.BOW.citationArgs['author0'] .. ', ' .. data.BOW.citationArgs['author1']  
end  

end  

--if not url then url = data.BOW.customArgs['baseURL'] end  
--if not title then title = "Title parameter required" end  

return title, url  
end  

-- basic handling for Taxonomy in Flux website  
data.tif = {  
citationArgs = {  
website="Taxonomy in Flux",  
['editor1-last']="Boyd III", ['editor1-first']="John H.", --['editor1-link']="",  
},  
customArgs = { exclude="order,family,genus,species,taxon,id,1",  
baseURL = "http://jboyd.net/Taxo/",  
defaultSuffix = "List.html",  
defaultTitle = "Taxonomy in Flux"  

},  
}  
-- ------------- Avibase  
e.g. https://avibase.bsc-eoc.org/species.jsp?avibaseid=9144EF4017F2D8B1  

data.avibase = {  
citationArgs = {  
website="Avibase",  
['editor1-last']="Lepage", ['editor1-first']="Denis", --['editor1-link']="",  
},  
customArgs = { exclude="order,family,genus,species,taxon,id,1",  
baseURL = "https://avibase.bsc-eoc.org/",  
searchStr = "species.jsp?avibaseid=",  
defaultTitle = "Avibase - The World Bird Database"  
}  
}  
--[[ use default function  
data.avibase.id = function (id)  

local title = "Avibase id: " .. id  
local url = data.avibase.customArgs['baseURL'] .. data.avibase.customArgs['searchStr'] .. id  
return title, url  
end  
--]]  

-- ============================= IUCN =================================================  
-- for species in taxon; for species assessments, us  
-- https://www.iucnredlist.org/search?query=Murexia&searchType=species  
-- https://www.iucnredlist.org/search?query=aonyx&searchType=species  
data.iucn = {  
citationArgs = {  
website="IUCN Red List of Threatened Species",  
--publisher="IUCN"  
},  
customArgs = { exclude="family,genus,species,taxon,id,1",  
baseURL = "https://www.iucnredlist.org",  
searchString = "/search?query=",  
searchSuffix = "&searchType=species",  
defaultSuffix = "",  
defaultTitle="IUCN Red List of Threatened Species"  
}  
}  
data.iucn.genus = function(genus) return data.iucn.taxon(genus, "TITLE_ITALICS") end  
data.iucn.family = function(family) return data.iucn.taxon(family) end  
data.iucn.order = function(order) return data.iucn.taxon(order) end  
data.iucn.taxon = function(taxon, titleItalics)  
local title = firstToUpper(taxon)  
if titleItalics then title = "*" .. title .. "*" end  
local url = data.iucn.customArgs['baseURL'] .. data.iucn.customArgs['searchString'] .. taxon .. data.iucn.customArgs['searchSuffix']  
return title, url  
end  

-- ============================= ASM Mammal Diversity Database ========================  
data.asm = {  
citationArgs = {  
website="ASM Mammal Diversity Database",  
publisher="American Society of Mammalogists"  
},  
customArgs = { exclude="family,genus,species,taxon,id,1,2,3",  
baseURL = "https://www.mammaldiversity.org/",  
defaultTitle="ASM Mammal Diversity Database"  

}  
}  

data.asm.species2 = function(genus, species) -- use species function below  
-- old url = https://mammaldiversity.org/species-account.php?genus=ursus&species=arctos  
-- new url = https://www.mammaldiversity.org/explore.html#genus=Dipodomys&species=deserti&id=1001892 (only id required)  
local title = "*" .. genus .. " " .. species .. "*"  
local url = data.asm.customArgs['baseURL'] .. "explore.html#genus=" .. genus .. "&species=" .. species  
if templateArgs['id'] then url = url .. "&id=" .. templateArgs['id'] end  
return title, url  
end  
data.asm.id = function(id)  
--local url = data.asm.customArgs['baseURL'] .. "species-account/species-id=" .. templateArgs['id']  
-- new format https://www.mammaldiversity.org/explore.html#species-id=1006310  
--local url = data.asm.customArgs['baseURL'] .. "explore.html#species-id=" .. id -- templateArgs['id']  
-- newer format https://www.mammaldiversity.org/explore.html#genus=Leopardus&species=colocola&id=1005993 (genus and species can be blank)  

local title = "Species-id=" .. id  
local hashString = "genus=&species=&id=" .. id -- if id only, requires blank genus and species  
if templateArgs['genus'] and templateArgs['species'] then  
title = "*" .. templateArgs['genus'] .. " " .. templateArgs['species'] .. "* (id=" .. id ..")"  
hashString = "genus=" .. templateArgs['genus'] .. "&species=" .. templateArgs['species'] .. "&id=" .. id  
end  
--local url = data.asm.customArgs['baseURL'] .. "explore.html#genus=&species=&id=" .. id -- templateArgs['id']  
local url = data.asm.customArgs['baseURL'] .. "explore.html#" .. hashString  

return title, url  
end  
data.asm.species = function(genus, species)  
if templateArgs['id'] then  
return data.asm.id(templateArgs['id']) -- use the ASM explore page if ID given (as permalink)  
end  
if genus and species then -- otherwisee use the treeview page with the species info  
local title = "*" .. firstToUpper(genus) .. " " .. species .. "*"  
local url = data.asm.customArgs['baseURL'] .. "tree.html#genus=" .. genus .. "&species=" .. species  
return title, url  
end  

end  

data.asm.genus = function(genus) return data.asm.taxon(genus, "genus", "TITLE_ITALICS") end  
data.asm.family = function(family) return data.asm.taxon(family, "family") end  
data.asm.order = function(order) return data.asm.taxon(order, "order") end  
data.asm.taxon = function(taxon, rank, titleItalics)  
--https://mammaldiversity.org/#ZmVsaWRhZSZnbG9iYWxfc2VhcmNoPXRydWUmbG9vc2U9dHJ1ZQ  
-- Base64.encode(felidae&global_search=true&loose=true)  
local title = firstToUpper(taxon)  
if titleItalics then title = "*" .. title .. "*" end  
local url = data.asm.customArgs['baseURL'] .. "tree.html#" .. rank .. "=" .. taxon  
-- .. '#' .. data.asm.Base64.encode(taxon.."&global_search=true&loose=false")  
return title, url  
end  
--############################## Base64 encode and decode (used for ASM#####################  
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'  
-- encoding  
data.asm.Base64 = {}  
data.asm.Base64.encode = function(data)  
return ((data:gsub('.', function(x)  
local r,b='',x:byte  
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end  
return r;  
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)  
if (#x < 6) then return '' end  
local c=0  
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end  
return b:sub(c+1,c+1)  
end)..({ '', '==', '=' })[#data%3+1])  
end  
-- decoding  
data.asm.Base64.decode=function(data)  
data = string.gsub(data, '[^'..b..'=]', '')  
return (data:gsub('.', function(x)  
if (x == '=') then return '' end  
local r,f='',(b:find(x)-1)  
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end  
return r;  
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)  
if (#x ~= 8) then return '' end  
local c=0  
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end  
return string.char(c)  
end))  
end  
--######################## Misc ##################################  
--[[ 3 approaches to handling DB:  
1) use DB as website and use author for editors (if known)  
(a) use via to append WoRMS  
(b) use postscript to append WoRMs  
(c) use publisher for WoRMS  
2) use WoRMS as website and designate DB as author (recommended by WoRMS) CURRENT  
(option) add editors [TODO see cite WoRMS for list]  
issue: what to do about editors changing (need to use access-date)  
data.WoRMS = {  
citationArgs = {  
author = "WoRMS",  
website = "World Register of Marine Species",  
--['via'] = "World Register of Marine Species",  
--postscript = '&#32;from the World Register of Marine Species.'  

},  
customArgs = {exclude="id,db,1",  
baseURL = "http://www.marinespecies.org/aphia.php?",  
searchStr = "p=taxdetails&id=",  
defaultTitle="World Register of Marine Species"  
}  
}  
data.WoRMS.id = function(id)  
-- Two styles  
1. http://www.marinespecies.org/aphia.php?p=taxdetails&id=14712  
> WoRMS (2018). Heterobranchia. Accessed at: http://marinespecies.org/aphia.php?p=taxdetails&id=14712 on 2018-11-28  
2. http://www.marinespecies.org/aphia.php?p=taxdetails&id=1057249  
> MolluscaBase (2018). Ringipleura. Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&id=1057249 on 2018-11-28  

if not templateArgs['id'] then return "no id parameter detected" end  
local searchStr = "p=taxdetails&id=" .. templateArgs['id']  

if templateArgs['db'] then  
data.WoRMS.db (templateArgs['db'])  
--[[else -- WoRMS is primary source (note cite WoRMs uses WoRMS as publisher and the db as the work)  
templateArgs['via'] = nil  
templateArgs['postscript'] = nil]]  
end  
--templateArgs['website'] = templateArgs['db'] -- alternative (and use |postscript)  
--templateArgs['publisher'] = templateArgs['via']  

--page <title>WoRMS - World Register of Marine Species - Heterobranchia</title>  
local title = "WoRMS taxon details: AphiaID " .. id  
local url = data.WoRMS.customArgs['baseURL'] .. data.WoRMS.customArgs['searchStr'] .. id  
return title, url  

end  
data.WoRMS.default = function  
if templateArgs['db'] then  
data.WoRMS.db (templateArgs['db'])  
end  
end  
data.WoRMS.db = function(db) -- if database hosted by WoRMS  

db = string.lower( db )  
if db == "world of copepods database" or db == "copepoda" or db == "copepods" or db == "copepod" then  
templateArgs['author'] = "World of Copepods Database"  
templateArgs['editor-last1']="Walter"; templateArgs['editor-first1']="T.C."  
templateArgs['editor-last2']="Boxshall"; templateArgs['editor-first2']="G."  
-- year ? (2022).  
elseif db == "world amphipoda database" or db == "amphipoda" or db == "amphipod"then  
templateArgs['author'] = "World Amphipoda Database"  
templateArgs['editor-last1']="Horton"; templateArgs['editor-first1']="T."  
templateArgs['editor-last2']="Lowry"; templateArgs['editor-first2']="J."  
templateArgs['editor-last3']="De Broyer"; templateArgs['editor-first3']="C."  
templateArgs['display-editors']="etal"; -- full list is about 20 names  
elseif db == "world isopoda database" or db == "isopoda" or db == "isopod"then  
templateArgs['author'] = "World Marine, Freshwater and Terrestrial Isopod Crustaceans database"  
templateArgs['editor-last1']="Boyko"; templateArgs['editor-first1']="C.B."  
templateArgs['editor-last2']="Bruce"; templateArgs['editor-first2']="N.L."  
templateArgs['editor-last3']="Hadfield"; templateArgs['editor-first3']="K.A."  
templateArgs['editor-last4']="Merrin"; templateArgs['editor-first4']="K.L."  
templateArgs['editor-last5']="Ota."; templateArgs['editor-first5']="Y."  
templateArgs['editor-last6']="Poore"; templateArgs['editor-first6']="G.C.B."  
templateArgs['editor-last7']="Taiti"; templateArgs['editor-first7']="S."  
elseif db == "millibase" or db == "diplopoda" or db == "diplopod"then  
templateArgs['author'] = "MilliBase"  
templateArgs['editor-last1']="Sierwald"; templateArgs['editor-first1']="P."  
templateArgs['editor-last2']="Spelda"; templateArgs['editor-first2']="J."  
elseif db == "molluscabase" or db == "mollusca" or db == "mollusc" then  
templateArgs['author'] = "MolluscaBase"  
else  
templateArgs['author'] = templateArgs['db'] -- this is recommended by WoRMS  
end  
end  
-- ITIS - Integrated Taxonomic Information System  
https://www.itis.gov/servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=95601#null  

data.itis = {  
citationArgs = {  
website = "Integrated Taxonomic Information System",  
--publisher = "",  
},  
customArgs = {exclude="id,1,2,3,4,5",  
baseURL = "https://www.itis.gov/",  
searchStr = "servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=",  
defaultTitle="Integrated Taxonomic Information System"  
}  
}  
data.itis.id = function(id)  

local title = "ITIS id=" .. id  
local url = data.itis.customArgs['baseURL'] .. data.itis.customArgs['searchStr'] .. id  

return title, url  

end  

-- Catalogue of Life:  
Roskov Y., Ower G., Orrell T., Nicolson D., Bailly N., Kirk P.M., Bourgoin T., DeWalt R.E., Decock W., van Nieukerken E.J., Penev L. (eds.) (2020).  
Species 2000 & ITIS Catalogue of Life, 2020-12-01.  
Digital resource at www.catalogueoflife.org. Species 2000: Naturalis, Leiden, the Netherlands. ISSN 2405-8858.  
Species 2000 & ITIS Catalogue of Life, 2020-12-01. Digital resource at www.catalogueoflife.org.  
Species 2000: Naturalis, Leiden, the Netherlands. ISSN 2405-8858.  

data.col = {  
db = "col", -- need rethink this  
citationArgs = {  
--author = "Catalogue of Life",  
--['editor-last1'] = "Roskov", ['editor-first1'] = "Y.", ['editor-last2'] = "Ower", ['editor-first2'] = "G.", ['editor-last3'] = "Orrell", ['editor-first3'] = "T.", ['editor-last4'] = "Nicolson", ['editor-first4'] = "D.", ['editor-last5'] = "Bailly", ['editor-first5'] = "N.", ['editor-last6'] = "Kirk", ['editor-first6'] = "P.M.", ['editor-last7'] = "Bourgoin", ['editor-first7'] = "T.", ['editor-last8'] = "DeWalt", ['editor-first8'] = "R.E.", ['editor-last9'] = "Decock", ['editor-first9'] = "W.", ['editor-last10'] = "van Nieukerken", ['editor-first10'] = "E.J.", ['editor-last11'] = "Penev", ['editor-first11'] = "L.",  
--website = "Catalogue of Life",  
--website = "Species 2000 & ITIS Catalogue of Life",  
-- website = "Species 2000 & ITIS Catalogue of Life",  
website = "Catalogue of Life",  
publisher = "Species 2000: Leiden, the Netherlands",  
--others = "Species 2000 & ITIS"  

},  
customArgs = {exclude="id,db,1,2,3,4,5,legacy,option",  
baseURL = "https://www.catalogueoflife.org/data/",  
searchStr = "browse?taxonKey=",  
defaultTitle="Catalogue of Life"  
}  
}  
data.col.id = function(id)  

-- Catalogue of Life  
browse option: https://www.catalogueoflife.org/data/browse?taxonKey=4JQ8  
use id for taxoKey  

taxon option https://www.catalogueoflife.org/data/taxon/6HR5M  

local title = "Catalogue of Life taxonKey " .. id  
local url = data.col.customArgs['baseURL']  

-- some new CoL are numbers e.g. 64553 in https://www.catalogueoflife.org/data/taxon/64553  
if not tonumber(id) and string.find( id, "^[0-9abcdef]+$" ) then -- if old-style id  
local year = "2019" -- last old-style version available  
if templateArgs['version'] and string.find( templateArgs['version'], "^%d%d%d%d$" ) then --if version specied  
year = templateArgs['version']  
end  
if templateArgs['option'] == "browse" then  
url = "http://www.catalogueoflife.org/annual-checklist/" .. year .. "/browse/tree/id/" .. id  
else -- default to option=taxon  
url = "http://www.catalogueoflife.org/annual-checklist/" .. year .. "/details/species/id/" .. id  
end  
else -- else use current version  
if templateArgs['option'] == "browse" then  
url = url .. "browse?taxonKey=" .. id  
else -- default to option=taxon  
url = url .. "taxon/" .. id  
end  
end  

return title, url  

end  
-- current links  
https://www.catalogueoflife.org/data/search?q=" Chinchilla+chinchilla&type=EXACT  
legacy links with redirect  
Species pages: http://www.catalogueoflife.org/col/details/species/id/12dca9c49741815f82400bb7bff50553  
Species searches: http://www.catalogueoflife.org/col/search/all/key/Dracula+antonii/  
old-style links  
http://www.catalogueoflife.org/col/details/species/id/7539827da517bd6273a4a3836578cb24  
http://www.catalogueoflife.org/col/search/scientific/genus/Chinchilla/species/chinchilla/match/1/  
http://www.catalogueoflife.org/col/browse/tree/id/003e480e646d0e7647ab67efc1218197  
year specific links  
2019 http://www.catalogueoflife.org/annual-checklist/2019/details/species/id/7539827da517bd6273a4a3836578cb24  
http://www.catalogueoflife.org/annual-checklist/2019/search/all/key/Chinchilla+chinchilla/fossil/1/match/1  
http://www.catalogueoflife.org/annual-checklist/2019/search/scientific/genus/Chinchilla/species/chinchilla/match/1/  
? http://www.catalogueoflife.org/annual-checklist/2016/browse/tree?6d600f4985f19b1207d41d847424edd0  
? http://www.catalogueoflife.org/col/browse/tree/id/003e480e646d0e7647ab67efc1218197  
browse http://www.catalogueoflife.org/annual-checklist/2019/browse/tree/id/003e480e646d0e7647ab67efc1218197  

data.col.default = function(mode) -- this handles the old style template with positional parameters (mode unused?)  

local para1 = templateArgs[1]  
local para2 = templateArgs[2]  
local para3 = templateArgs[3]  
local para4 = templateArgs[4]  
if para1 then para1 = mw.text.trim(para1) end  
if para2 then para2 = mw.text.trim(para2) end  
if para3 then para3 = mw.text.trim(para3) end  
if para4 then para4 = mw.text.trim(para4) end  

local title, url  

if para1 then  
--local match = "7539827da517bd6273a4a3836578cb24"  
local match = "^[0-9abcdef]+$"  
if string.find( para1, match ) then  
url = "http://www.catalogueoflife.org/col/details/species/id/" .. para1 -- ""Old style id"  
--url ="https://www.catalogueoflife.org/data/search?q=" .. para1  
if para2 then  
title = para2  
else  
title = "Oldstyle id: " .. para1  
end  

else  

--https://www.catalogueoflife.org/data/search?q=" Chinchilla+chinchilla&type=EXACT  

if para1 ~= "" then  
url = "https://www.catalogueoflife.org/data/search?q=" .. para1  
title = "''" .. para1  
if para2 then  
url = url .. "+" .. para2  
title = title .. " " .. para2  
end  
url = url .. "&type=EXACT"  
title = title .. "''"  
end  

end  
if para3 then title = title .. " " .. para3 end -- add authority  
if para4 == "nv" then templateArgs['trans-title'] = "synonym" end -- if nv add [synonym]. Note that this parameter is not used to add COinS metadata  
else  
-- no parameter 1  
end  

return title, url  
end  

--====================== Fossilworks =======================================  

data.fossilworks = {  
citationArgs = {  
website="Fossilworks",  
--publisher="Paleobiology Database",  
--postscript = '',  
postscript = "&#32;from the Paleobiology Database.",  
--via="*fossilworks.org*" -- an alternative format to using |website=  
},  
customArgs = { exclude = "id,collection,date,1",  
baseURL = "http://www.fossilworks.org/cgi-bin/",  
searchStr ="bridge.pl?a=taxonInfo&taxon_no=",  
defaultTitle = "Fossilworks: Gateway to the Paleobiology Database"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
data.fossilworks.id = function(id)  
--[[ http://fossilworks.org/cgi-bin/bridge.pl?a=taxonInfo&taxon_no=83087  
if not templateArgs['id'] then return "no id parameter detected" end  
local searchStr = "bridge.pl?a=taxonInfo&taxon_no=" .. templateArgs['id']  
templateArgs['url']= target.CustomArgs['baseURL'] .. searchStr  
local title = "PaleoDB taxon number: " .. id  
local url = data.fossilworks.customArgs['baseURL'] .. data.fossilworks.customArgs['searchStr'] .. id  
return title, url  
end  
data.fossilworks.collection = function(collection)  
-- http://fossilworks.org/bridge.pl?a=collectionSearch&collection_no=20072  
local title = "PaleoDB collection number: " .. collection  
local url = data.fossilworks.customArgs['baseURL'] .. "bridge.pl?a=collectionSearch&collection_no=" .. collection  
return title, url  
end  
data.fossilworks.error = function  
return "Requires id and title parameters"  
end  

--====================== Paleobiology Database: paleobiodb.org =======================================  

data.paleobiodb = {  
citationArgs = {  
website="Paleobiology Database"  
},  
customArgs = { exclude = "id,collection,date,1",  
baseURL = "https://paleobiodb.org/classic/",  
searchStr ="basicTaxonInfo?taxon_no=",  
defaultTitle = "Paleobiology Database"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
data.paleobiodb.id = function(id)  
--[[ https://paleobiodb.org/classic/basicTaxonInfo?taxon_no=22786  
if not templateArgs['id'] then return "no id parameter detected" end  
local title = "PaleoDB taxon number: " .. id  
local url = data.paleobiodb.customArgs['baseURL'] .. data.paleobiodb.customArgs['searchStr'] .. id  
return title, url  
end  
data.paleobiodb.collection = function(collection)  
-- https://paleobiodb.org/classic/basicCollectionSearch?collection_no=24193  
local title = "PaleoDB collection number: " .. collection  
local url = data.paleobiodb.customArgs['baseURL'] .. "basicCollectionSearch?collection_no=" .. collection  
return title, url  
end  
data.paleobiodb.error = function  
return "Requires id and title parameters"  
end  
--======================================= PLANTS =========================  
-- Plant authorities can end in a period. This is stripped by the citation templates.  
This function encloses titles ending in such authorities in double parentheses, i.e. ((title))  

local addAuthority = function(formattedTaxonName)  
if templateArgs['authority'] then  
local title = formattedTaxonName .. " " .. templateArgs['authority']  
return string.gsub( title, "(.*%.)$", "((%1))") -- if authority ends in "." enclose ((title)) to prevent removal  
end  
return formattedTaxonName  
end  

-- Hassler, Michael (2004 - 2020): World Plants. Synonymic Checklist and Distribution of the World Flora.  
Version x.xx; last update xx.xx.xxxx. - www.worldplants.de. Last accessed dd/mm/yyyy.  
https://www.worldplants.de/world-plants-complete-list/complete-plant-list#1599996425  
Hassler, Michael (2004 - 2020): World Ferns. Synonymic Checklist and Distribution of Ferns and Lycophytes of the World.  
Version x.xx; last update xx.xx.xxxx. - www.worldplants.de/ferns/. Last accessed dd/mm/yyyy.  
https://www.worldplants.de/world-ferns/ferns-and-lycophytes-list#1599997555  

deeplinks:  
Genus: *Helosciadium*  
Species: *Helosciadium longipedunculatum*  

Genus: *Lycopodium*  
Species: *Lycopodium clavatum*  

---
data.worldplants = {  
citationArgs = {  
last1 = "Hassler", first1 = "Michael",  
website="World Plants. Synonymic Checklist and Distribution of the World Flora.",  
--publisher=""  
},  
customArgs = { exclude = "id,authority,family,genus,species,1",  
baseURL = "https://www.worldplants.de",  
searchStr ="/world-plants-complete-list/complete-plant-list#",  
defaultSuffix = "",  
defaultTitle = "World Plants"  
}  
}  
data.worldplants.genus = function(genus)  
local title = addAuthority("*" .. genus .. "*")  
local genusString = genus  
if templateArgs['authority'] then genusString = genus .. "-" .. templateArgs['authority'] end  
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. genusString  
return title, url  
end  
data.worldplants.species = function(genus, species)  
local title = addAuthority("*" .. genus .. " " .. species .. "*")  
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. genus .. "-" .. species .. " " .. (templateArgs['authority'] or "")  
return title, url  
end  
--[[ experimental, don't leave live  

data.worldplants.taxon = function(taxon)  
local title = taxon .. " " .. (templateArgs['authority'] or "")  
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. taxon  
return title, url  
end  

data.worldplants.family = function(family)  
local title = family .. " " .. (templateArgs['authority'] or "")  
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. family  
return title, url  
end  
--]]  
data.worldferns = {  
citationArgs = {  
last1 = "Hassler", first1 = "Michael",  
website="World Ferns. Synonymic Checklist and Distribution of the World Flora.",  
--publisher=""  
},  
customArgs = { exclude = "id,authority,family,genus,species,1",  
baseURL = "https://www.worldplants.de/",  
searchStr ="world-ferns/ferns-and-lycophytes-list?name=",  
defaultSuffix = "",  
defaultTitle = "World Ferns"  
}  
}  
data.worldferns.genus = function(genus)  
local title = addAuthority("*" .. genus .. "*")  
local genusString = genus  
if templateArgs['authority'] then genusString = genus .. "-" .. templateArgs['authority'] end  
local url = data.worldferns.customArgs['baseURL'] .. data.worldferns.customArgs['searchStr'] .. genusString  
return title, url  
end  
data.worldferns.species = function(genus, species)  
local title = addAuthority("*" .. genus .. " " .. species .. "*")  
local url = data.worldferns.customArgs['baseURL'] .. data.worldferns.customArgs['searchStr'] .. genus .. "-" .. species .. " " .. (templateArgs['authority'] or "")  
return title, url  
end  

--[[Plants of the World online  
http://powo.science.kew.org/taxon/urn:lsid:ipni.org:names:30003057-2 -- use id  
http://powo.science.kew.org/?q=Selaginellaceae -- use search  
http://powo.science.kew.org/?family=Selaginellaceae -- can also use family= [gets same result as q=]  
http://powo.science.kew.org/?genus=Selago -- or genus  
http://powo.science.kew.org/?genus=Selago&species=abietina -- or genus + species  
http://powo.science.kew.org/?genus=Selago&f=accepted_names -- filter for accepted names  
http://powo.science.kew.org/?genus=Selago&f=genus_f -- filter for genus (no species selected)  
http://powo.science.kew.org/?genus=Selago&f=genus_f%2Caccepted_names -- filter for genus and accepted names  
http://powo.science.kew.org/?page.size=480&f=family_f%2Caccepted_names -- list of accepted families  
-- all these searches get the search result (no apparent way to target the article when unique)  
data.POWO = {  
citationArgs = {  
website="Plants of the World Online",  
publisher="Royal Botanic Gardens, Kew",  
--postscript = '',  
},  
customArgs = { exclude = "id,authority,family,genus,species,1",  
baseURL = "http://powo.science.kew.org/taxon/",  
searchStr ="urn:lsid:ipni.org:names:",  
defaultSuffix = "",  
defaultTitle = "Plants of the World Online"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
-- http://powo.science.kew.org/taxon/urn:lsid:ipni.org:names:30003057-2  
data.POWO.id = function(id)  
local id = data.POWO.getValidID  
if not id then return data.POWO.error end  
local title = id -- as default value  
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] .. id  
return title, url  
end  
data.POWO.family = function(family)  
local title = addAuthority(family)  
local id = templateArgs['id']  
if not id then return data.POWO.error end  
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] .. id  
return title, url  
end  
data.POWO.genus = function(genus)  
local title = addAuthority("*" .. genus .. "*")  
local id = data.POWO.getValidID  
if not id then return data.POWO.error end  
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] .. id  
return title, url  
end  
data.POWO.species = function(genus,species)  
local title = addAuthority("*" .. genus .. " " .. species .. "*")  
local id = data.POWO.getValidID  
if not id then return data.POWO.error end  
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] ..id  
return title, url  
end  
data.POWO.getValidID = function  
local id = templateArgs['id']  
if id then  
return string.gsub( id, "urn:lsid:ipni.org:names:", "") -- don't want this twice  
end  
return nil  
end  
data.POWO.error = function  
return '<span>Requires id and one of title, family, genus or species parameters</span>'  
end  

--Gouda, E.J., Butcher, D. & Gouda, C.S. (cont.updated)  
Encyclopaedia of Bromeliads, Version 4. http://bromeliad.nl/encyclopedia/ Utrecht University Botanic Gardens  

data.bromeliad = {  
citationArgs = {  
last1="Gouda", first1="E.J.",  
last2="Butcher", first2="D.",  
last3="Gouda", first3="C.S",  
website="Encyclopaedia of Bromeliads",  
version="Version 4",  
publisher="Utrecht University Botanic Gardens",  
--postscript = '',  
},  
customArgs = { exclude = "id,authority,family,genus,species,list,1",  
baseURL = "https://bromeliad.nl/",  
searchStr ="encyclopedia/index.php?find=",  
defaultSuffix = "",  
defaultTitle = "Encyclopaedia of Bromeliads, Version 4"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
-- https://bromeliad.nl/encyclopedia/index.php?find=Hylaeaicum  
data.bromeliad.search = function(search)  

local title = search -- as default value  
local url = data.bromeliad.customArgs['baseURL'] .. data.bromeliad.customArgs['searchStr'] .. search  
return title, url  
end  
-- http://bromeliad.nl/species/Bromeliaceae  
data.bromeliad.taxon = function(taxon)  

local title = addAuthority(taxon) -- as default value  
local url = data.bromeliad.customArgs['baseURL'] .. "species/" .. taxon  
return title, url  
end  
-- genus  
data.bromeliad.genus = function(genus)  

local title = addAuthority("*" .. genus .. "*") -- as default value  
local url = data.bromeliad.customArgs['baseURL'] .. "species/" .. genus  
if templateArgs['list'] == "species" then  
url = data.bromeliad.customArgs['baseURL'] .. "encyclopedia/brome.php?action=showSpeciesIndex&name=" .. genus .. "&flags="  
end  
return title, url  
end  
---
data.bromeliad.species = function(genus, species)  

local title = addAuthority("*" .. genus .. " " .. species .. "*") -- as default value  
local url = data.bromeliad.customArgs['baseURL'] .. "species/" .. genus .. "/" .. species  
return title, url  
end  

-- https://bromeliad.nl/encyclopedia/brome.php?action=showTaxon&id=10093  
data.bromeliad.id = function(id)  

local title = id -- as default value  
local url = data.bromeliad.customArgs['baseURL'] .. "encyclopedia/brome.php?action=showTaxon&id=" .. id  
return title, url  
end  

--GRIN  
Cite as: USDA, Agricultural Research Service, National Plant Germplasm System. 2021. Germplasm Resources Information Network (GRIN Taxonomy). National Germplasm Resources Laboratory, Beltsville, Maryland.  
URL: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=tribe&id=1571. Accessed 27 October 2021.  
Family record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?id=440  
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=440&type=family  
Subfamily record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=subfamily&id=1507  
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=3265&type=subfamily  
Tribe record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=tribe&id=1551 (Millettieae)  
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=1551&type=tribe  
Subtribe record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=subtribe&id=1507  
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=1507&type=subtribe  
Genus record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenus?id=191 (Genus Adenodolichos Harms)  
Species list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyspecieslist?id=191&type=genus  
Species record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomydetail?id=489203 ( Adenodolichos paniculatus)  

data.GRIN = {  
citationArgs = {  
website="Germplasm Resources Information Network (GRIN)",  
publisher="Agricultural Research Service (ARS), United States Department of Agriculture (USDA)",  
--postscript = '',  
},  
customArgs = { exclude = "id,authority,family,genus,species,1",  
baseURL = "https://npgsweb.ars-grin.gov/gringlobal",  
searchStr ="/taxon/taxonomydetail?", -- for species record  
defaultSuffix = "",  
defaultTitle = "GRIN-Global"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
data.GRIN.id = function(id)  
local title = data.GRIN.customArgs['defaultTitle'] .. ' ' .. id  
local url = data.GRIN.customArgs['baseURL'] .. data.GRIN.customArgs['searchStr'] .. id  
return title, url  
end  

-- IPNI  
--→ "Meconopsis Vig." International Plant Names Index (IPNI). Royal Botanic Gardens, Kew.  
--- https://www.ipni.org/n/30149252-2  
--- as  

data.IPNI = {  
citationArgs = {  
website="International Plant Names Index (IPNI)",  
publisher="Royal Botanic Gardens, Kew",  
--postscript = '',  
},  
customArgs = { exclude = "id,authority,family,genus,species,1",  
baseURL = "https://www.ipni.org",  
searchStr ="/n/",  
defaultSuffix = "",  
defaultTitle = "IPNI"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
data.IPNI.id = function(id)  
local title = id  
local url = data.IPNI.customArgs['baseURL'] .. data.IPNI.customArgs['searchStr'] .. id  
return title, url  
end  
data.IPNI.species = function(genus, species) return data.IPNI.taxon(genus .. " " .. species, "TITLE_ITALICS") end  
data.IPNI.genus = function(genus) return data.IPNI.taxon(genus, "TITLE_ITALICS") end  
data.IPNI.taxon = function(taxon, italics)  
local title = taxon  
if italics then title = "*" .. title .. "*" end  
title = addAuthority(title)  
--[[ if templateArgs['authority'] then  
title = title .. " " .. templateArgs['authority']  
title = string.gsub( title, "(.*%.)$", "((%1))") -- if authority ends in "." enclose ((title)) to prevent removal  
end ]]  
local url = data.IPNI.customArgs['baseURL'] .. data.IPNI.customArgs['searchStr'] .. templateArgs['id']  
return title, url  
end  

--World Flora Online  
http://www.worldfloraonline.org/taxon/wfo-4000012284 -- id  

data.WFO = {  
citationArgs = {  
website="World Flora Online",  
--publisher="Missouri Botanical Gardens",  
--postscript = '',  
},  
customArgs = { exclude = "id,family,genus,species,authority,1",  
baseURL = "http://www.worldfloraonline.org",  
searchStr ="/taxon/wfo-", -- not strictly search string  
defaultSuffix = "",  
--defaultTitle = "World Flora Online"  
defaultTitle = "An Online Flora of All Known Plants"  
}  

}  
data.WFO.id = function(id)  
-- http://www.worldfloraonline.org/taxon/wfo-4000012284  

local title = id  
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. id  
return title, url  
end  
data.WFO.family = function(family)  
local title = addAuthority(family)  
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. templateArgs['id']  
return title, url  
end  
data.WFO.genus = function(genus)  
local title = addAuthority("*" .. genus .. "*")  
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. templateArgs['id']  
return title, url  
end  
data.WFO.species = function(genus,species)  
local title = addAuthority("*" .. genus .. " " .. species .. "*")  
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. templateArgs['id']  
return title, url  
end  
data.WFO.error = function  
return "Requires id and title parameters"  
end  

data.Tropicos = {  
citationArgs = {  
website="Tropicos",  
--publisher="Missouri Botanical Gardens",  
--postscript = '',  
},  
customArgs = { exclude = "id,1",  
baseURL = "http://legacy.tropicos.org/Name/",  
searchStr ="",  
defaultSuffix = "",  
defaultTitle = "Tropicos"  
}  

}  
data.Tropicos.id = function(id)  
-- hhttp://legacy.tropicos.org/Name/100444532  

local title = id  
local url = data.Tropicos.customArgs['baseURL'] .. data.Tropicos.customArgs['searchStr'] .. id  
return title, url  
end  
data.Tropicos.error = function  
return "Requires id and title parameters"  
end  

data.FNA = {  
citationArgs = {  
website="Flora of North America",  
--publisher="http://www.efloras.org",  
--postscript = '',  
},  
customArgs = { exclude = "id,1",  
baseURL = "http://www.efloras.org/florataxon.aspx",  
searchStr ="?flora_id=1&taxon_id=",  
defaultSuffix = "",  
defaultTitle = "Flora of North America"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
data.FNA.id = function(id)  
-- http://www.efloras.org/florataxon.aspx?flora_id=1&taxon_id=125683  

local title = id  
local url = data.FNA.customArgs['baseURL'] .. data.FNA.customArgs['searchStr'] .. id  
return title, url  
end  
data.FNA.error = function  
return "Requires id and title parameters"  
end  
-- ATRP: Australian Tropical Rainforest Plants  

data.ATRP = {  
citationArgs = {  
website="Australian Tropical Rainforest Plants",  
publisher="Commonwealth Scientific and Industrial Research Organisation (CSIRO)",  
version = "Edition 8",  
year = 2020,  
--postscript = '',  
last1= "Zich", first1="F. A.",  
last2= "Hyland", first2= "B. P. M.", ['author2-link']="Bernard Hyland",  
last3= "Whiffin", first3= "T.",  
last4= "Kerrigan", first4= "R.A.",  
--['display-authors']=3,  
},  
customArgs = { exclude = "genus, species,authority, id,1",  
baseURL = "https://apps.lucidcentral.org/rainforest",  
searchStr ="/text/entities/",  
defaultSuffix = ".htm",  
defaultTitle = "Australian Tropical Rainforest Plants"  
}  
--id = function(id) return p.genericIdCitation (, title, url)  
}  
data.ATRP.species = function(genus,species)  
-- https://apps.lucidcentral.org/rainforest/text/entities/buckinghamia_celsissima.htm  

local title = addAuthority("*" .. genus .. " " .. species .. "*") --"*" .. genus .. " " .. species .. "*"  
local url = data.ATRP.customArgs['baseURL'] .. data.ATRP.customArgs['searchStr'] .. genus .. "_" .. species .. data.ATRP.customArgs['defaultSuffix']  
return title, url  
end  
data.ATRP.error = function  
return "Requires genus and species parameters"  
end  

-- ============================= Mosses (Goffinet's site) =================================================-- for species in taxon; for species assessments, us  
-- https://bryology.uconn.edu/classification/#Hypnanae  
-- https://bryology.uconn.edu/classification/#Bryales  
data.goffinet = {  
citationArgs = {  
first1="B.", last1="Goffinet",  
first2="W.R.", last2="Buck",  
website="Classification of extant moss genera"  
--publisher="xxx"  
},  
customArgs = { exclude="family,genus,species,taxon,id,1",  
baseURL = "https://bryology.uconn.edu/classification/",  
searchString = "#",  
searchSuffix = "",  
defaultSuffix = "",  
defaultTitle="Classification of the Bryophyta"  
}  
}  
data.goffinet.genus = function(genus) return data.goffinet.taxon(genus, "GENUS") end  
data.goffinet.family = function(family) return data.goffinet.taxon(family, "FAMILY") end  
data.goffinet.order = function(order) return data.goffinet.taxon(order, "ORDER") end  
data.goffinet.taxon = function(taxon, rank)  
local title = firstToUpper(taxon)  
if rank == "GENUS" then title = "*" .. title .. "*" end  
if not (rank == "GENUS" or rank == "FAMILY") then -- upper case anchors for orders and above  
if taxon ~= "Bryanae" and taxon ~= "Hypnanae" and taxon ~= "Bryales" and taxon ~= "Bryidae" then -- check for exceptions (inconsistencies at website)  
taxon = taxon:upper  
end  
end  
local url = data.goffinet.customArgs['baseURL'] .. data.goffinet.customArgs['searchString'] .. taxon .. data.goffinet.customArgs['searchSuffix']  
return title, url  
end  

-- AlgaeBase  
taxonomy browser url (Volvox) = https://www.algaebase.org/browse/taxonomy/?id=6898  
genus article url (Volvox) = https://www.algaebase.org/search/genus/detail/?genus_id=43497 (different id)  
genus article url (Torodinium)= https://www.algaebase.org/search/genus/detail/?genus_id=44698  
Please cite this record as: M.D. Guiry in Guiry, M.D. & Guiry, G.M. 2020. AlgaeBase.  
World-wide electronic publication, National University of Ireland, Galway.  
http://www.algaebase.org; searched on 10 May 2020.  

data.AlgaeBase = {  
citationArgs = {  
website="AlgaeBase",  
['editor1-last']="Guiry", ['editor1-first']="M.D.",  
['editor2-last']="Guiry", ['editor2-first']="G.M.",  
publisher="National University of Ireland, Galway",  
},  
customArgs = { exclude = "id,1,genus_id,species_id,spid,genid",  
baseURL = "https://www.algaebase.org/",  
searchStr ="browse/taxonomy/?id=",  
defaultSuffix = "",  
defaultTitle = "AlgaeBase"  
}  
}  
data.AlgaeBase.id = function(id)  
-- https://www.algaebase.org/browse/taxonomy/?id=6898 (id for taxonomy page)  

local title = id  
local url = data.AlgaeBase.customArgs['baseURL'] .. data.AlgaeBase.customArgs['searchStr'] .. id  
return title, url  
end  
data.AlgaeBase.genid = function(genid)  
-- https://www.algaebase.org/search/genus/detail/?genus_id=43497 (different id for genus page)  

local title = genid  
local url = data.AlgaeBase.customArgs['baseURL'] .. "search/genus/detail/?genus_id=" .. genid  
return title, url  
end  
data.AlgaeBase.spid = function(spid)  
-- https://www.algaebase.org/search/species/detail/?species_id=52713 (id for species page)  

local title = spid  
local url = data.AlgaeBase.customArgs['baseURL'] .. "search/species/detail/?species_id=" .. spid  
return title, url  
end  
data.AlgaeBase.error = function  
return "Requires id and title parameters"  
end  
--############################## General Functions ########################################  

local function getArgs (, args)  
local parents = mw.getCurrentFrame:getParent  

for k,v in pairs(parents.args) do  
--check content  
if v and v ~= "" then  
args[k]=v --parents.args[k]  
end  
end  
for k,v in pairs(.args) do  
--check content  
if v and v ~= "" then  
args[k]=v  
end  
end  
end  
local function initialise(, sourceDB)  

target=sourceDB  
templateArgs = sourceDB.citationArgs -- get custom arguments for target (fishbase, cof etc  

getArgs(, templateArgs) -- get template arguments from parent and frane  

local url = (target.customArgs['baseURL'] or "") .. (target.customArgs['defaultSuffix'] or "")  
local title = target.customArgs['defaultTitle'] or ""  
return title, url  
end  
-- moved up top for scope  
local function firstToUpper2(str)  
return (str:gsub("^%l", string.upper))  
end  
-- clear template arguments that won't be recognised by  
local function clearCustomArgs  

local excludeTable = { 'genus', 'species', 'subspecies', 'family', 'order', 'taxon',  
'id', 'search' , 'citation', 1, 2, 3, 4 } -- add defaults ?  

if target.customArgs['exclude'] then  
local customTable = mw.text.split (target.customArgs['exclude'] , "%s*,%s*");  
for k,v in pairs(customTable) do  
table.insert (excludeTable, v )  
end  
end  
for k,v in pairs(excludeTable) do  
if tonumber (v) then  
v = tonumber (v) --convert positional parameters (numbers as string) to a number  
end  
templateArgs[v]=nil --clear content  
end  
end  

-- function handling the cite web template  
p.citeWeb = function(, title, url)  

-- set url and title if not provided (template parameters override above)  
if not templateArgs['url'] and url then  
templateArgs['url']= url  
end  
if not templateArgs['title'] and title then  
templateArgs['title'] = title  
end  

clearCustomArgs--blank template parameters not for cite web  

local citeTemplate = 'cite web' -- use Template:Cite web unless specified  
--if target.citeTemplate then citeTemplate = target.citeTemplate end  
return :expandTemplate{ title = citeTemplate, args = templateArgs }  

end  
-- p.CiteBook  
-- for reasons of consisitency within BioRef/FishRef the title parameter is the section-title of  
p.citeBook = function(, title, url, chapterParams) -- very much a msw3 function  

--if (1==1) then return templateArgs['title'] end  

-- set url and title if not provided (template parameters override above)  
if not templateArgs['url'] and url then  
templateArgs['url']= url  
if target.GoogleBooks then  
templateArgs['url'] = target.GoogleBooks['baseURL'] .. target.GoogleBooks['id']  
.. (target.GoogleBooks['defaultPage'] or "&pg=PP1")  

end  
end  
if not templateArgs['title'] and title then  
-- templateArgs['title'] = title  
end  
if templateArgs['title'] ~= title or templateArgs['taxon-title'] then -- do we have a section title provided  
templateArgs['section'] = templateArgs['title'] -- chapter/section title passed as title parameter  
templateArgs['title'] = title -- the work is the book title given in the source data  
if target.GoogleBooks then  

templateArgs['section-url'] = target.GoogleBooks['baseURL'] .. target.GoogleBooks['id']  
local pageSuffix = target.GoogleBooks['defaultPage'] or ""  
if templateArgs['page'] or templateArgs['gb-page'] then  
pageSuffix = "&pg=PT" .. (templateArgs['gb-page'] or templateArgs['page'] )  
end  
local searchStr = ""  
-- quoted search |&dq=}}}}  
if templateArgs['q'] then searchStr = "&q=" .. mw.text.encode( templateArgs['q'] ) end  
-- search #if:}}|&q=}}}}  
if templateArgs['dq'] then searchStr = "&dq=" .. mw.text.encode( templateArgs['dq'] ) end  

templateArgs['section-url'] = templateArgs['section-url'] .. pageSuffix .. searchStr  
templateArgs['url'] = nil -- no need for second link to google books  
end  

-- if the chapter/section is linked, we can link the main book chapter differently  
if target.customArgs['altTitle'] then -- if we are using a chapter/section, we can wikilink the book title  
templateArgs['title'] = target.customArgs['altTitle'] -- alternative to allow wikilink  
elseif target.customArgs['altURL'] then  
templateArgs['url'] = target.customArgs['altURL']  
end  

end -- end if using supplied title for chapter/section  

clearCustomArgs--blank template parameters not for cite web  

local citeTemplate = 'cite book' -- use Template:Cite web unless specified  
--if target.citeTemplate then citeTemplate = target.citeTemplate end  
return :expandTemplate{ title = citeTemplate, args = templateArgs }  

end  

-- common function for genus and species  
local function getGenusSpecies  
--TODO standardise genus species handling  
local genus, species, subspecies  
if (templateArgs['genus'] or templateArgs[2] ) then  
genus = templateArgs['genus'] or templateArgs[2]  
genus = firstToUpper(mw.text.trim(genus))  
end  
if (templateArgs['species'] or templateArgs[3] ) then  
species = templateArgs['species'] or templateArgs[3]  
species = mw.text.trim(species)  
end  
if (templateArgs['subspecies'] or templateArgs[4] ) then  
subspecies = templateArgs['subspecies'] or templateArgs[4]  
subspecies = mw.text.trim(subspecies)  
end  

return genus, species, subspecies  
end  

--#################### MSW3 -- uses cite book  
p.MSW3 = function  
local msw = require('Module:FishRef/MSW')  
initialise(, msw.MSW3)  
return msw.MSW3.main(,templateArgs)  
end  
p.MSW3merged = function  
local data = require('Module:FishRef/MSW')  
return p._main(, data.MSW3)  
end  
p.MSW3_standalone = function  

local data = require('Module:FishRef/MSW')  
initialise(, data.MSW3)  
local url = target.CustomArgs['baseURL']  

if templateArgs['title'] and templateArgs['id'] then  
templateArgs['chapter-url']= url .. target.CustomArgs['searchStr'] .. templateArgs['id']  
templateArgs['chapter'] = templateArgs['title']  

templateArgs['title'] = target.CustomArgs['bookTitle']  
if templateArgs['page'] then  
templateArgs['url'] = target.CustomArgs['googleBooksURL'] .. templateArgs['page']  
else  
--return "Page number for google books required"  
end  
elseif templateArgs['order'] then  
templateArgs['chapter'] = "Order " .. templateArgs['order']  
local chapter = target.chapters[templateArgs['order']]  
for k,v in pairs(chapter) do -- add chapter specific parameters  
templateArgs[k] = v  
end  
templateArgs['chapter-url']= url .. target.CustomArgs['searchStr'] .. templateArgs['id']  
templateArgs['url']= target.CustomArgs['googleBooksURL'] .. templateArgs['page']  
if templateArgs['pages'] and templateArgs['page'] then templateArgs['page'] = nil end  
else -- default output  
templateArgs['url']= target.CustomArgs['googleBooksURL'] .. "1" -- default to book  
templateArgs['url']= url  
end  
-- using cite book  
clearCustomArgs--blank template parameters not for cite web  
return :expandTemplate{ title = 'cite book', args = templateArgs }  
end  

--########################### Functions for access (using invoke) ##############################################  

--================ Fishbase, Catalog of Fishes (cof) ================  
p.fishbase = function return p._main(, data.fishbase) end  
p.cof = function return p._main(, data.cof) end  
p.fotw5 = function return p._main(, data.fotw5) end  
--=================== ASW6, AmphibiaWeb, ReptileDB  
p.reptileDB = function return p._main(, data.reptileDB) end  
p.ASW6 = function return p._main(, data.ASW6) end  
p.amphibiaweb = function return p._main(, data.amphibiaweb) end  
--=========== Birds  
p.HBWa = function return p._main(, data.HBWalive) end  
p.HBWalive = function return p._main(, data.HBWalive) end  
p.IOC = function return p._main(, data.IOC) end  
--======= Mammals  
p.asm = function return p._main(, data.asm) end  
--======= Plants  
p.WFO = function return p._main(, data.WFO) end  
p.POWO = function return p._main(, data.POWO) end  
-- MSW3 has custom handling (see above)  
--=========== Other  
p.fossilworks = function return p._main(, data.fossilworks) end  
p.worms = function return p._main(, data.WoRMS) end  
p.WoRMS = function return p._main(, data.WoRMS) end  
p.col = function return p._main(, data.col) end  
--fallback = function return "hello" end  
--#########################################################  
p.main = function  
local source = mw.text.trim(.args[1])  
--TODO force to lower case and use lower case for all functions above  

if source == "MSW3" then return p.MSW3 end  

if source == "ref" or source == "reference" then source = "Reference" end -- aliases  
if source == "Reference" then return p.Reference end  

if source == "HBWa" then source = "HBWalive" end -- aliases  
if source == "powo" then source = "POWO" end -- aliases  
if source == "wfo" then source = "WFO" end -- aliases  
if source == "mdd" then source = "asm" end -- aliases  
--return p[source]['test']  
if source == "fishbase" -- unnecessary?  
or source == "cof"  
or source == "fotw5" or source == "Fotw5"  
or source == "reptileDB"  
or source == "amphibiaweb"  
or source == "ASW6"  
or source == "asm"  
or source == "HBWalive" or source == "HBWa"  
or source == "fossilworks"  
or source == "WoRMS" or source == "worms"  
or source == "POWO" or source == "powo"  
or source == "WFO" or source == "wfo"  
or source == "AlgaeBase"  
-- and so on  
then return p._main(,data[source])  
else  
---
-- is there a point in the default if it needs the named object/table?  
return p._main(,data[source])  
end  
end  
p._main = function(, source)  

--TODO in modular version source will be provided in arguments  
--local source = mw.getCurrentFrame:getParent.args[1]  
local chapterParams = {} -- used for cite book (only MSW3 at moment)  

if not source then return "Error: unrecognised source." end  

local title, url = initialise(, source)  

--taxon related parameters  
local genus, species, subspecies  

if source.db ~= "col" then -- col legacy uses positional parameters differently  
genus, species, subspecies = getGenusSpecies  
end  

local family = templateArgs['family']  
local order = templateArgs['order']  
local taxon = templateArgs['taxon']  

local id = templateArgs['id'] --id related parameters  
local spid = templateArgs['spid'] or templateArgs['species_id']  
local genid = templateArgs['genid'] or templateArgs['genus_id']  
local citation = templateArgs['citation']  
local collection = templateArgs['collection'] or templateArgs['collection_no']  
local search = templateArgs['search']  
local mode, value  

-- the functions  
if genus and species and source.species then  
title, url = source.species(genus,species,subspecies)  
else -- functions with just their own name as parameter  

if genus then mode = "genus"; value = genus  
elseif family then mode = "family"; value = family  
elseif order then mode = "order"; value = order  
elseif taxon then mode = "taxon"; value = taxon  
elseif id then mode = "id"; value = id  
elseif spid then mode = "spid"; value = spid  
elseif genid then mode = "genid"; value = genid  
elseif search then mode = "search"; value = search  
elseif citation then mode = "citation"; value = citation  
elseif collection then mode = "collection"; value = collection  
else  
-- no suitable parameter (use default page)  
if source.default then  
title, url, chapterParams = source.default(title, url)  
end  
end  
end  
if mode then  
if source[mode] then  
title, url, chapterParams = source[mode](value)  
elseif data.default[mode] then  
title, url, chapterParams = data.default[mode](value, source)  
else  
if source.error then return source.error end -- custom error message  
return "Error: parameter not supported for this source" .. " (" .. mode .. ")"  
end  
else  
-- if no mode then use the default title and url set by initialize  
end  

if source.citeTemplate == "Cite book" then  
return p.citeBook(, title, url, chapterParams)  
end  
return p.citeWeb(, title, url)  

end -- End the function.  

p.Reference = function  

local refs = require('Module:FishRef/refs')  
getArgs(, templateArgs)  

if templateArgs[2] then  
local reference = mw.text.trim(templateArgs[2])  
if reference ~= "" and refs[reference] then  
if templateArgs['pages'] then  
refs[reference] = refs[reference]:gsub("}}", "|pages="..templateArgs['pages'].."}}")  
refs[reference] = refs[reference]:gsub("|pages=[^|{}%[%]]*(|[^|{}}%[%]]*|pages=)", "%1")  
end  
if templateArgs['reftags'] == "yes" then  
refs[reference] = ''  
end  
if templateArgs['expand'] and templateArgs['expand']=='no' or templateArgs['raw'] then  
return refs[reference]  
else  
return :preprocess(refs[reference])  
end  
else  
return 'Reference not found: "' .. templateArgs[2] .. '"'  
end  
end  
return "Reference parameter missing."  
end -- End the function.  

-- All modules end by returning the variable containing its functions to Wikipedia.  
return p