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(frame, 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(frame, 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 		 	            .. '"' .. genus .. '+' .. species .. '"' 		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.species = function(genus, species) 	-- new url = https://www.mammaldiversity.org/explore.html#genus=Dipodomys&species=deserti&id=1001892     local title = "" .. genus .. " " .. species .. "" 		--https://mammaldiversity.org/species-account.php?genus=ursus&species=arctos 	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']     	--local title = "Species-id=" .. 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']     	local url = data.asm.customArgs['baseURL'] .. "explore.html#genus=&species=&id=" .. id -- templateArgs['id']     	local title = "Species-id=" .. id     	return title, url end data.asm.genus  = function(genus)  return data.asm.taxon(genus, "TITLE_ITALICS") end data.asm.family = function(family) return data.asm.taxon(family) end data.asm.order  = function(order)  return data.asm.taxon(order) end data.asm.taxon  = function(taxon, 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']                .. '#' .. 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 = ' 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 WoRMS - World Register of Marine Species - Heterobranchia     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  --[[ Catalgue 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", 	    publisher = "Species 2000: Naturalis, 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 = 'none', 		postscript = " 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 (frame, 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 (frame, 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 = 'none', 	}, 	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 (frame, 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 'Requires id and one of title, family, genus or species parameters' 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 = 'none', 	}, 	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 (frame, 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 = 'none', 	}, 	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 (frame, 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 = 'none', 	}, 	customArgs = { exclude = "id,authority,family,genus,species,1", 	               baseURL = "https://www.ipni.org", 	               searchStr ="/n/", 	               defaultSuffix = "", 	               defaultTitle = "IPNI" 	} 	--id = function(id) return p.genericIdCitation (frame, 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 = 'none', 	}, 	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 = 'none', 	}, 	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 = 'none', 	}, 	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 (frame, 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 = 'none', 		            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 (frame, 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 (frame, 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(frame.args) do 		--check content 		if v and v ~= "" then 			args[k]=v  		end 	end end local function initialise(frame, sourceDB) 	 	target=sourceDB 	templateArgs = sourceDB.citationArgs -- get custom arguments for target (fishbase, cof etc      	getArgs(frame, templateArgs) -- get template arguments from parent frame 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(frame, 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 frame: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(frame, 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  		    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 frame: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(frame)  	local msw = require('Module:FishRef/MSW') 	initialise(frame, msw.MSW3) 	return msw.MSW3.main(frame,templateArgs) end p.MSW3merged = function(frame)  	local data = require('Module:FishRef/MSW') 	return p._main(frame, data.MSW3) end p.MSW3_standalone = function(frame)  	 	local data = require('Module:FishRef/MSW') 	initialise(frame, 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 frame:expandTemplate{ title = 'cite book', args = templateArgs  } end  --########################### Functions for access (using invoke) ##############################################  --================ Fishbase, Catalog of Fishes (cof) ================ p.fishbase    = function(frame) return p._main(frame, data.fishbase) end p.cof         = function(frame) return p._main(frame, data.cof) end  p.fotw5       = function(frame) return p._main(frame, data.fotw5) end  --=================== ASW6, AmphibiaWeb, ReptileDB p.reptileDB   = function(frame) return p._main(frame, data.reptileDB) end p.ASW6        = function(frame) return p._main(frame, data.ASW6) end p.amphibiaweb = function(frame) return p._main(frame, data.amphibiaweb) end --=========== Birds p.HBWa        = function(frame) return p._main(frame, data.HBWalive) end p.HBWalive    = function(frame) return p._main(frame, data.HBWalive)  end p.IOC         = function(frame) return p._main(frame, data.IOC) end --======= Mammals p.asm         = function(frame) return p._main(frame, data.asm) end -- MSW3 has custom handling (see above) --=========== Other p.fossilworks = function(frame) return p._main(frame, data.fossilworks) end p.worms       = function(frame) return p._main(frame, data.WoRMS) end p.WoRMS       = function(frame) return p._main(frame, data.WoRMS) end p.col         = function(frame) return p._main(frame, data.col) end  --fallback = function() return "hello" end --######################################################### p.main = function(frame)  	local source = mw.text.trim(frame.args[1]) 	 	if source == "MSW3" then return p.MSW3(frame) end 	 	if source == "ref" or source == "reference" then source = "Reference" end   -- aliases 	if source == "Reference" then return p.Reference(frame) end          if source == "HBWa" then source = "HBWalive" end   -- aliases     if source == "powo" then source = "POWO" end   -- aliases 	--return p[source]['test'] 	if source == "fishbase"  		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 == "AlgaeBase" 		-- and so on 	    then return p._main(frame,data[source]) 	else 		--  		-- is there a point in the default if it needs the named object/table? 		return p._main(frame,data[source]) 	end end p._main = function(frame, source)       --TODO in modular version source will be provided in frame 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(frame, 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(frame, title, url, chapterParams)     end 	return p.citeWeb(frame, title, url) 	 end  -- End the function.  p.Reference = function(frame) 	 	local refs = require('Module:FishRef/refs') 	getArgs(frame, 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['expand'] and templateArgs['expand']=='no' or templateArgs['raw']  then    				return refs[reference]    			else    				return frame: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