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(&quot;^%l&quot;, 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 &quot;&quot;) .. id
 	return title, url
 end
 data.default.error = function()
 	return &quot;Minimal requirement is two of id, url and title parameters&quot;
 end
 data.default.search = function (search, source)
 	local title = &quot;Search for &quot; .. 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 &quot;no id parameter detected&quot; 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']=&quot;Froese&quot;,  ['editor1-first']=&quot;Rainer&quot;, ['editor1-link']=&quot;Rainer Froese&quot;,
 	['editor2-last']=&quot;Pauly&quot;,  ['editor2-first']=&quot;Daniel&quot;,   
 	--['last-author-amp'] =&quot;yes&quot;,
     ['website'] = &quot;[[Fishbase]]&quot;,
 	--['publisher'] = &quot;&quot;
 	},
 	customArgs = { exclude= &quot;order, family,genus, species, subspecies, 1, 2, 3, 4&quot;,
 	               baseURL = &quot;http://www.fishbase.org/&quot;,
 	               defaultTitle = &quot;Search FishBase&quot;
 	},
 }
 data.fishbase.species = function(genus, species, subspecies)
 
 		local title = genus .. &quot; &quot; .. species
 		local url = data.fishbase.customArgs['baseURL'] 
 		            .. &quot;summary/SpeciesSummary.php?genusname=&quot; .. genus .. &quot;&amp;speciesname=&quot; .. species
 		if subspecies then 
 			url = url .. &quot;+&quot; .. subspecies
 			title = title .. &quot; &quot; .. subspecies
 		end               
 		title =  &quot;''&quot; .. title  .. &quot;''&quot;
 		return title, url
 end
 data.fishbase.genus = function(genus)
 		local title = &quot;Species in genus ''&quot; .. firstToUpper(genus) .. &quot;''&quot;
 		local url = data.fishbase.customArgs['baseURL'] ..  &quot;identification/SpeciesList.php?genus=&quot; .. genus   
 		return title, url
 end
 data.fishbase.order = function(order) 
 		local title =  &quot;Order &quot; .. firstToUpper(order)
 		local url = data.fishbase.customArgs['baseURL'] ..  &quot;Summary/OrdersSummary.php?order=&quot; .. order
 		return title, url
 end
 data.fishbase.family = function(family) 
 		local title = &quot;Family &quot; .. firstToUpper(family)
 		local url = data.fishbase.customArgs['baseURL'] ..  &quot;Summary/FamilySummary.php?family=&quot; .. family
 		return title, url
 end
 data.fishbase.error = function()   
 	return &quot;No recognised taxon options: order, family, genus, species, subspecies.&quot;
 end
 data.fishbase.custom = function()    
     --TODO decide what to do with default date
     local version = &quot;April 2006 version&quot;  -- Should we have a default (probably not)
     if templateArgs['month'] then version = templateArgs['month'] end
     if templateArgs['year'] then version = templateArgs['year'] .. &quot; version&quot; end
     if templateArgs['month'] then version = templateArgs['month'] .. &quot; &quot; .. version end
     templateArgs['version'] = version
 end
 --================================ Catalog of Fishes ================================================
 data.cof = {
 	citationArgs = {
 		--baseURL = &quot;http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatget.asp?&quot;,
 		['editor1-last']=&quot;Eschmeyer&quot;,  ['editor1-first']=&quot;William N.&quot;, ['editor1-link']=&quot;William N. Eschmeyer&quot;,
 		['editor2-last']=&quot;Fricke&quot;,  ['editor2-first']=&quot;Ron&quot;,   
 		['editor3-last']=&quot;van der Laan&quot;,  ['editor3-first']=&quot;Richard&quot;, 
 		['name-list-style'] =&quot;amp&quot;,
 	    ['website'] = &quot;[[Catalog of Fishes]]&quot;,
 		['publisher'] = &quot;[[California Academy of Sciences]]&quot;
 	},
 	customArgs = { exclude= &quot;family,genus,species,genid,spid,id,list,1,2,3&quot;,
 	               baseURL = &quot;http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatget.asp?&quot;,
 	               defaultTitle = &quot;CAS - Eschmeyer's Catalog of Fishes&quot;
 	}
 }
 data.cof.species = function(genus, species, subspecies)
 		local taxon = genus .. &quot; &quot; .. species
 	    local url = data.cof.customArgs['baseURL'] ..  'tbl=species&amp;genus=' .. genus .. '&amp;species=' .. species
 	    local title = &quot;Species related to &quot; .. &quot;''&quot; .. firstToUpper(taxon) .. &quot;''&quot;        -- .. &quot;&quot; species synonyms&quot;
 	    return title, url
 end
 data.cof.genus  = function(genus)
 	    local url = data.cof.customArgs['baseURL'] .. 'tbl=species&amp;genus=' .. genus
 	    local title = &quot;Species in the genus ''&quot; .. firstToUpper(genus) .. &quot;''&quot; 
 	    return title, url
 end
        -- note the family works with subfamilies using &amp;family=SUBFAMILY
 data.cof.family  = function(family)
 	    local list = templateArgs['list'] or &quot;genus&quot;
 	    local url = data.cof.customArgs['baseURL'] .. 'tbl=' .. list .. '&amp;family=' .. family
         local title = &quot;Species&quot;
         if list == &quot;genus&quot; then  title = &quot;Genera&quot; end 
         title = title .. ' in the family ' .. firstToUpper(family)  
         return title, url
 end
 data.cof.genid = function(genid)
    	    local searchStr =  &quot;genid&quot; .. '=' .. genid
         local title =  searchStr
         local url = data.cof.customArgs['baseURL'] .. searchStr
         return title, url
 end
 data.cof.spid = function(spid)
    	    local searchStr =  &quot;spid&quot; .. '=' .. spid
         local title =  searchStr
         local url = data.cof.customArgs['baseURL'] .. searchStr
         return title, url
 end
 data.cof.error = function()
     	return &quot;Error. No recognised option set by template (need one of family, genus, species (also requires genus), spid, or genid&quot;
 end
 --======================Fishes of the World 5===============================	
 data.fotw5 = {
 	citeTemplate = &quot;Cite book&quot;,
 	citationArgs = {
 	    --['website'] = &quot;[[]]&quot;,
 		first1 = &quot;Joseph S.&quot;, last1 = &quot;Nelson&quot;,
 		first2=&quot;Terry C.&quot;, last2=&quot;Grande&quot;,
 		first3=&quot;Mark V. H.&quot;, last3=&quot;Wilson&quot;, 
 		--work = &quot;Fishes of the World (work)&quot;,
 		title = &quot;Fishes of the World&quot;, edition=&quot;5th&quot;, year = 2016,
 		publisher =&quot;John Wiley and Sons&quot;, location=&quot;Hoboken&quot;,
 		isbn = &quot;978-1-118-34233-6&quot;, doi=&quot;10.1002/9781119174844&quot; ,
 	},
 	customArgs = {exclude=&quot;gb-page,q,dq,1&quot;,
 	              baseURL = &quot;https://onlinelibrary.wiley.com/doi/book/10.1002/9781119174844&quot;, -- online library
 	              defaultTitle = &quot;Fishes of the World&quot;,
 	              altTitle = &quot;[[Fishes of the World]]&quot;,               -- wikilinked for when using chapter/section title
 	              altURL = &quot;https://sites.google.com/site/fotw5th/&quot;,  -- classification
 	},
 	GoogleBooks = { baseURL = &quot;https://books.google.co.uk/books?id=&quot;,
 		            id = &quot;E-MLDAAAQBAJ&quot;,
 		            defaultPage = &quot;&amp;pg=PP1&quot;
 	}
 }
 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 = &quot;Cite book&quot;,
 	citationArgs = {
 		first1 = &quot;Michael J.&quot;, last1 = &quot;Benton&quot;,
 		title = &quot;Vertebrate Palaeontology&quot;, edition=&quot;4th&quot;, year = 2014,
 		publisher =&quot;John Wiley &amp; Sons&quot;, 
 		isbn = &quot;978-1-118-40764-6&quot;, 
 	},
 	customArgs = {exclude=&quot;gb-page,q,dq,1&quot;,
 	              --baseURL = &quot;&quot;,
 	              defaultTitle = &quot;Vertebrate Palaeontology&quot;,
 	              altTitle = &quot;[[Vertebrate Palaeontology]]&quot;  -- wikilinked for when using chapter/section title
 	},
 	GoogleBooks = { baseURL = &quot;https://books.google.co.uk/books?id=&quot;,
 		            id = &quot;qak-BAAAQBAJ&quot;,
 		            defaultPage = &quot;&amp;pg=PP1&quot;,
 	}
 }
 
 
 --====================TODO FishWisePro==================================================	
 data.fishwisepro = {
 	citationArgs = {
 	    ['website'] = &quot;[[FishWisePro]]&quot;,
 
 	},
 	customArgs = {exclude=&quot;family,genus,species,1&quot;,
 	              baseURL = &quot;&quot;
 	}
 }
 
 -- #################### 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: {{BioRef|ASW6 |title=Amphibia |year=2019 |url=http://research.amnh.org/herpetology/amphibia/index.html |access-date=27 September 2019}}
     SEARCH http://research.amnh.org/vz/herpetology/amphibia/amphib/basic_search?basic_query=Atelopus&amp;stree=&amp;stree_id=
            searchSuffix = amphib/basic_search?basic_query=Atelopus&amp;stree=&amp;stree_id=
     SEARCH http://research.amnh.org/vz/herpetology/amphibia/content/search?taxon=Allophryn*&amp;subtree=&amp;subtree_id=&amp;english_name=&amp;author=&amp;year=&amp;country=
            searchSuffix = /content/search?taxon=Allophryn*&amp;subtree=&amp;subtree_id=&amp;english_name=&amp;author=&amp;year=&amp;country=
            minimul      = /content/search?taxon=Allophryn*&amp;subtree
     ]]
 data.ASW6 ={
 	citationArgs = {
 		website  =&quot;Amphibian Species of the World, an Online Reference.&quot;,
 		version  = &quot;Version 6.0&quot;,
 		publisher = &quot;American Museum of Natural History, New York&quot;,
 		['last1']=&quot;Frost&quot;,  ['first1']=&quot;Darrel R.&quot;, ['author1-link']=&quot;Darrel R. Frost&quot;,
 	},
 	customArgs = { exclude = &quot;taxon,species,genus,family, superfamily,1,2,3&quot;,
 	               baseURL = &quot;http://research.amnh.org/herpetology/amphibia/&quot;,
 	               defaultSuffix = &quot;index.html&quot;,
 	               defaultTitle = &quot;ASW Home&quot;  
 	}
 }
 
 data.ASW6.species = function(genus, species, subspecies)
 
 		-- search for genus+species  ()
 	    local title = &quot;Search for taxon: &quot; .. &quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;
 	
 		 	--local search = &quot;&quot;?action=names&amp;taxon=&quot;&quot; -- old version (pre ASW6)
 		 	--local search =  &quot;amphib/basic_search?basic_query=&quot;  -- basic search
 	 	local search = &quot;content/search?taxon=&quot;              -- guided search for taxon name
 		 	
 		local url = data.ASW6.customArgs['baseURL'] .. search  -- .. genus .. '+AND+' .. species
 		 	            .. '&amp;quot;' .. genus .. '+' .. species .. '&amp;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 = &quot;Search for Taxon: &quot; .. taxon
 	    local url= data.ASW6.customArgs['baseURL'] .. &quot;content/search?taxon=&quot; .. taxon
 	    return title, url
 end
 data.ASW6.family = function(family) 
 		local order = data.ASW6.checkOrder(family)
 		local url= data.ASW6.customArgs['baseURL'] .. &quot;Amphibia/&quot; .. order .. &quot;/&quot; .. firstToUpper(family)
 		local title = firstToUpper(family) 
 		return title, url
 end
 data.ASW6.checkOrder = function(family)
 
 	local gymnophiona={ &quot;Caeciliidae&quot;, &quot;Chikilidae&quot;, &quot;Dermophiidae&quot;, &quot;Herpelidae&quot;, &quot;Ichthyophiidae&quot;, &quot;Grandisoniidae&quot;, &quot;Indotyphlidae&quot;, &quot;Rhinatrematidae&quot;, &quot;Scolecomorphidae&quot;, &quot;Siphonopidae&quot;, &quot;Typhlonectidae&quot; }
     local caudata = { &quot;Ambystomatidae&quot;, &quot;Amphiumidae&quot;, &quot;Cryptobranchidae&quot;, &quot;Hynobiidae&quot;, &quot;Plethodontidae&quot;, &quot;Proteidae&quot;, &quot;Rhyacotritonidae&quot;, &quot;Salamandridae&quot;, &quot;Sirenidae&quot; }
    
     for k,v in pairs(caudata) do
     	if v == family then return &quot;Caudata&quot; end
     end
     for k,v in pairs(gymnophiona) do
     	if v == family then return &quot;Gymnophiona&quot; end
     end
     
     return &quot;Anura&quot;
 end   
 
 --============================= AmphibiaWeb ===================================
 --[[   Citation: AmphibiaWeb. 2019. &lt;https://amphibiaweb.org&gt; University of California, Berkeley, CA, USA. Accessed 27 Sep 2019.
        Code:     {{BioRef|amphibiaweb |title=Amphibia |year=2019 |url=https://amphibiaweb.org/taxonomy/AW_FamilyPhylogeny.html |access-date=27 September 2019}}
 --]]
 data.amphibiaweb = {
 	citationArgs = {
 		website  = &quot;AmphibiaWeb&quot;,
 		publisher = &quot;University of California, Berkeley&quot;,
 		--['editor1-last']=&quot;&quot;,  ['editor1-first']=&quot;&quot;, ['editor1-link']=&quot;&quot;,
 	},
     customArgs = { exclude = &quot;taxon,species,genus,family,1,2,3&quot;,
 	               baseURL = &quot;https://amphibiaweb.org/&quot;,
 	               defaultSuffix = &quot;taxonomy/AW_FamilyPhylogeny.html&quot;,
 	               defaultTitle = &quot;AmphibiaWeb Family Taxonomy&quot;
 	}
 }
 data.amphibiaweb.species = function (genus, species, subspecies)
 		local title = &quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;
 		 	--https://amphibiaweb.org/cgi/amphib_query?where-genus=Altiphrynoides&amp;where-species=malcolmi
 		local url = data.amphibiaweb.customArgs['baseURL'] .. &quot;cgi/amphib_query?rel-genus=equals&amp;where-genus=&quot;
 		 	                   .. genus .. &quot;&amp;rel-species=equals&amp;where-species=&quot; .. species
 		return title, url
 end
 data.amphibiaweb.genus = function (genus)
 		local title = &quot;''&quot; .. genus ..  &quot;''&quot;
 		 	--https://amphibiaweb.org/cgi/amphib_query?where-genus=Altiphrynoides&amp;where-species=malcolmi
 		local url = data.amphibiaweb.customArgs['baseURL'] .. &quot;cgi/amphib_query?rel-genus=equals&amp;where-genus=&quot; 
 		 	                .. genus .. &quot;&amp;include_synonymies=Yes&amp;show_photos=Yes&quot;
 		return title, url
 end	
 data.amphibiaweb.family = function (family)		-- if family use standardised url
 		 local url = data.amphibiaweb.customArgs['baseURL'] .. &quot;lists/&quot; .. firstToUpper(templateArgs['family']) .. &quot;.shtml&quot;
 		 local title = templateArgs['family']
 		 return title, url
 end
 	
 
 
 --=========================== The Reptile Database
 data.reptileDB = {
 	-- http://reptile-database.reptarium.cz/species?genus=Epacrophis&amp;species=boulengeri
 	-- recommended citation: Uetz, P., Freed, P. &amp; Hošek, J. (eds.) (2019) The Reptile Database, http://www.reptile-database.org, accessed [insert date here]
 	citationArgs = {
 		--website=&quot;reptile-database.org&quot;,
 		website=&quot;[[The Reptile Database]]&quot;,
 		['editor1-last']=&quot;Uetz&quot;,  ['editor1-first']=&quot;P.&quot;, --['editor1-link']=&quot;Peter Uetz&quot;,
 		['editor2-last']=&quot;Freed&quot;,  ['editor2-first']=&quot;P.&quot;, 
 		['editor3-last']=&quot;Hošek&quot;,  ['editor3-first']=&quot;J.&quot;, 
 		--year=2019
 		
 	},
 	customArgs = { exclude = &quot;taxon,species,genus,family,1,2,3&quot;,
 	               baseURL = &quot;http://reptile-database.reptarium.cz/&quot;
 	}
 }
 
 data.reptileDB.species = function(genus, species)
 	    local title = &quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;
 	    --http://reptile-database.reptarium.cz/species?genus=Loxocemus&amp;species=bicolor
 		local url = data.reptileDB.customArgs['baseURL'] .. &quot;species?genus=&quot; .. genus .. &quot;&amp;species=&quot; .. species
 		return  title, url
 end
 data.reptileDB.genus = function(genus)
 	    local title = &quot;''&quot; .. genus .. &quot;''&quot; 
 	    --http://reptile-database.reptarium.cz/advanced_search?genus=Malayopython&amp;submit=Search
 	    local url = data.reptileDB.customArgs['baseURL'] .. &quot;advanced_search?genus=&quot; .. genus .. &quot;&amp;exact%5B0%5D=taxon&amp;submit=search&quot;
 		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&amp;exact%5B0%5D=taxon&amp;submit=Search
 		local url = data.reptileDB.customArgs['baseURL'] .. &quot;advanced_search?taxon=&quot; .. taxon .. &quot;&amp;exact%5B0%5D=taxon&amp;submit=search&quot;
 		return  title, url
 end
 	
 
    
 
 --################################### BIRDS ########################################
 --====================Handbook of the Birds of the World Alive (HBW Alive)==============
 data.HBWalive = {         
 	citationArgs = {
 		website=&quot;[[Handbook of the Birds of the World|Handbook of the Birds of the World Alive]]&quot;, 
 		publisher=&quot;Lynx Edicions&quot;
 	},
 	customArgs = { exclude=&quot;order,family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;https://www.hbw.com/&quot;,
 	               defaultSuffix = &quot;family/home&quot;,
 	               defaultTitle = &quot;Family | HBW Alive&quot;
 	               
 	}
 }
 --############################## 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 = &quot;Order &quot; .. firstToUpper(order)
     	--https://www.hbw.com/order/struthioniformes
     	local url = target.customArgs['baseURL'] .. &quot;order/&quot; .. order
     	return title, url
 end
  
 
 --[[======================IOC World Bird List==========================
 	        Gill, F &amp; D Donsker (Eds). 2019. IOC World Bird List (v9.2). doi :  10.14344/IOC.ML.9.2.
 	        Gill F, D Donsker &amp; P Rasmussen  (Eds). 2020. IOC World Bird List (v10.2). doi :  10.14344/IOC.ML.10.1.
 ]]
 data.IOC = {         
 	citationArgs = {
 		website=&quot;[[IOC World Bird List]]&quot;, 
 	--	version=&quot;Version 9.2&quot;,                               -- shouldn't default; should be hardcode so it doesn't change
 		['editor1-last']=&quot;Gill&quot;,  ['editor1-first']=&quot;F.&quot;,  ['editor1-link']=&quot;Frank Gill (ornithologist)&quot;,
 		['editor2-last']=&quot;Donsker&quot;,  ['editor2-first']=&quot;D.&quot;,
 		['editor3-last']=&quot;Rasmussen&quot;,  ['editor3-first']=&quot;P.&quot;,  -- TODO only show from version 10.1 onwards
 	--	doi = &quot;10.14344/IOC.ML.9.2&quot;,                          -- this changes by version number and is not a useful part of the cictation
 		publisher=&quot;International Ornithological Congress&quot;
 	},
 	customArgs = { exclude=&quot;order,family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;https://www.worldbirdnames.org/&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;IOC World Bird List: Welcome&quot;
 	               
 	},
 }
 data.IOC.version = function()
 	local version =  templateArgs['version'] 
 	local old = false
 	if version then
 		version = string.gsub( version, &quot;[Vv]ersion &quot;, &quot;&quot;)
      	local versionNumber = tonumber(version)
     	if versionNumber &lt; 10.1 then
 	    	old = true
 		end
 	else
 		local Date = require('Module:Date')._Date
 		if Date(templateArgs['access-date']) &lt; 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 = &quot;Order &quot; .. firstToUpper(order)
     	local url = data.IOC.customArgs['baseURL'] .. &quot;/bow/&quot; .. IOCorders[order]
     	return title, url    	
 end
 data.IOC.family = function(family)
 	    data.IOC.version()
 	    local IOCfamilies = { Struthionidae = {&quot;ratites&quot;, 4}, Alcippeidae = {&quot;babblers&quot;, 24989 } }      -- temporary partial list for testing
     	
     	local title = &quot;Family &quot; .. firstToUpper(family)
     	--https://www.worldbirdnames.org/Family/Struthionidae
     	local url = data.IOC.customArgs['baseURL'] .. &quot;Family/&quot; .. 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'] .. &quot;new/bow/&quot; ..  IOCfamilies[family][1] .. &quot;/#1338626516R&quot; .. 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=&quot;Birds of the World Online&quot;, 
 	--	doi = &quot;&quot;,                          
 	--	['last1']=&quot;Winkler&quot;,  ['first1']=&quot;David W.&quot;,              -- are these always the authors in version 1? no, perhaps for family page
 	--	['last2']=&quot;Billerman&quot;,  ['first2']=&quot;Shawn M.&quot;,
 	--	['last3']=&quot;Lovette&quot;,  ['first3']=&quot;Irby J.&quot;,  
 	--	['editor1-last']=&quot;Billerman&quot;,  ['editor1-first']=&quot;S. M.&quot;,  --['editor1-link']=&quot;&quot;,
 	--	['editor2-last']=&quot;Keeney&quot;,  ['editor2-first']=&quot;B. K.&quot;,
 	--	['editor3-last']=&quot;Rodewald&quot;,  ['editor3-first']=&quot;P. G.&quot;,  
 	--    ['editor4-last']=&quot;Schulenberg&quot;,  ['editor4-first']=&quot;T. S.&quot;,
 	--    ['version'] = 1,   ['year'] = 2020,                                             -- may not want to default
 		publisher=&quot;[[Cornell Lab of Ornithology]], Ithaca, NY.&quot;
 	},
 	customArgs = { exclude=&quot;citation,make,order,family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;https://birdsoftheworld.org/bow/species&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;Explore Taxonomy&quot;
 	               
 	},
 }
 
 data.BOW.default =  function( title, url)  
 	 --data.BOW.citationArgs['version'] = &quot;Version 1&quot;
 	 return title, url
 end
 
 --[[ make BOW to parse standard citation, {{BioRef|BOW|citation=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 = &quot;/cur/&quot;                                                                       -- 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+)%)' , &quot;(''%1 %2'')&quot;)
     
     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(&quot;, and &quot;, &quot;, &quot;)
     	--local names = author_names:gsub ('%.?,?%s+&amp;%s+', '.|'):gsub ('%.,%s+', '.|');	-- replace 'separators' (&lt;dot&gt;&lt;comma&gt;&lt;space&gt; and &lt;opt. dot&gt;&lt;opt. comma&gt;&lt;space&gt;&lt;ampersand&gt;&lt;space&gt;) with &lt;dot&gt;&lt;pipe&gt;
     	local names = authors:gsub (',%s+', '|');       -- replace any comma
     	                 --    :gsub ('%.?,?%s+and%s+', '|') -- replace 'separators' &lt;opt. dot&gt;&lt;opt. comma&gt;&lt;space&gt;and&lt;space&gt;) with &lt;dot&gt;&lt;pipe&gt;
     	                 --    :gsub ('%.,%s+', '.|');       -- replace 'separators' &lt;dot&gt;&lt;comma&gt;&lt;space&gt; with &lt;dot&gt;&lt;pipe&gt;
       	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 = &quot;Title parameter required&quot; end
 	 
 	 return title, url
 end
 
 -- basic handling for Taxonomy in Flux website
 data.tif = {         
 	citationArgs = {
 		website=&quot;Taxonomy in Flux&quot;, 
 		['editor1-last']=&quot;Boyd III&quot;,  ['editor1-first']=&quot;John H.&quot;,    --['editor1-link']=&quot;&quot;,
 	},
 	customArgs = { exclude=&quot;order,family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;http://jboyd.net/Taxo/&quot;,
 	               defaultSuffix = &quot;List.html&quot;,
 	               defaultTitle = &quot;Taxonomy in Flux&quot;
 	               
 	},
 }
 --[[ ------------- Avibase
                    e.g. https://avibase.bsc-eoc.org/species.jsp?avibaseid=9144EF4017F2D8B1
 ]]
 data.avibase = {
 		citationArgs = {
 		website=&quot;Avibase&quot;, 
 		['editor1-last']=&quot;Lepage&quot;,  ['editor1-first']=&quot;Denis&quot;,    --['editor1-link']=&quot;&quot;,
 	},
 	customArgs = { exclude=&quot;order,family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;https://avibase.bsc-eoc.org/&quot;,
 	               searchStr = &quot;species.jsp?avibaseid=&quot;,
 	               defaultTitle = &quot;Avibase - The World Bird Database&quot;
 	}
 }
 --[[ use default function
 data.avibase.id = function (id)
     
     local title = &quot;Avibase id: &quot; .. 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 {{cite iucn}}
 -- https://www.iucnredlist.org/search?query=Murexia&amp;searchType=species 
 -- https://www.iucnredlist.org/search?query=aonyx&amp;searchType=species
 data.iucn = {
 	citationArgs = {
 		website=&quot;[[IUCN Red List of Threatened Species]]&quot;, 
 		--publisher=&quot;[[IUCN]]&quot;
 	},
 	customArgs = { exclude=&quot;family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;https://www.iucnredlist.org&quot;,
 	               searchString = &quot;/search?query=&quot;,
 	               searchSuffix = &quot;&amp;searchType=species&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle=&quot;IUCN Red List of Threatened Species&quot;
 	}	
 }
 data.iucn.genus  = function(genus)  return data.iucn.taxon(genus, &quot;TITLE_ITALICS&quot;) 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 = &quot;''&quot; .. title .. &quot;''&quot; 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=&quot;ASM Mammal Diversity Database&quot;, 
 		publisher=&quot;[[American Society of Mammalogists]]&quot;
 	},
 	customArgs = { exclude=&quot;family,genus,species,taxon,id,1,2,3&quot;,
 	               baseURL = &quot;https://www.mammaldiversity.org/&quot;,
 	               defaultTitle=&quot;ASM Mammal Diversity Database&quot;
 	               
 	}
 }
 
 data.asm.species2 = function(genus, species) -- use species function below
     -- old url = https://mammaldiversity.org/species-account.php?genus=ursus&amp;species=arctos
 	-- new url = https://www.mammaldiversity.org/explore.html#genus=Dipodomys&amp;species=deserti&amp;id=1001892 (only id required)
     local title = &quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;
 	local url = data.asm.customArgs['baseURL'] .. &quot;explore.html#genus=&quot; .. genus .. &quot;&amp;species=&quot; .. species
 	if templateArgs['id'] then url = url .. &quot;&amp;id=&quot; .. templateArgs['id'] end
 	return title, url
 end	    
 data.asm.id = function(id)
     	--local url = data.asm.customArgs['baseURL'] .. &quot;species-account/species-id=&quot; .. templateArgs['id']
     	-- new format https://www.mammaldiversity.org/explore.html#species-id=1006310
     	--local url = data.asm.customArgs['baseURL'] .. &quot;explore.html#species-id=&quot; .. id -- templateArgs['id']
     	-- newer format https://www.mammaldiversity.org/explore.html#genus=Leopardus&amp;species=colocola&amp;id=1005993 (genus and species can be blank)
     	
     	local title = &quot;Species-id=&quot; .. id
     	local hashString = &quot;genus=&amp;species=&amp;id=&quot; .. id                   -- if id only, requires blank genus and species
     	if templateArgs['genus'] and templateArgs['species'] then
     		title = &quot;''&quot; .. templateArgs['genus'] .. &quot; &quot; .. templateArgs['species'] .. &quot;'' (id=&quot; .. id ..&quot;)&quot;
     		hashString = &quot;genus=&quot; .. templateArgs['genus'] .. &quot;&amp;species=&quot; .. templateArgs['species'] .. &quot;&amp;id=&quot; .. id
     	end
     	--local url = data.asm.customArgs['baseURL'] .. &quot;explore.html#genus=&amp;species=&amp;id=&quot; .. id -- templateArgs['id']
     	local url = data.asm.customArgs['baseURL'] .. &quot;explore.html#&quot; .. 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 = &quot;''&quot; .. firstToUpper(genus) .. &quot; &quot; .. species .. &quot;''&quot; 
 		local url = data.asm.customArgs['baseURL'] .. &quot;tree.html#genus=&quot; .. genus ..  &quot;&amp;species=&quot;  .. species 
 	    return title, url
 	end
 	
 end
 
 data.asm.genus  = function(genus)  return data.asm.taxon(genus, &quot;genus&quot;, &quot;TITLE_ITALICS&quot;) end
 data.asm.family = function(family) return data.asm.taxon(family, &quot;family&quot;) end
 data.asm.order  = function(order)  return data.asm.taxon(order, &quot;order&quot;) end
 data.asm.taxon  = function(taxon, rank, titleItalics)
     	--https://mammaldiversity.org/#ZmVsaWRhZSZnbG9iYWxfc2VhcmNoPXRydWUmbG9vc2U9dHJ1ZQ
     	--                             Base64.encode(felidae&amp;global_search=true&amp;loose=true)
     local title = firstToUpper(taxon)
     if titleItalics then title = &quot;''&quot; .. title .. &quot;''&quot; end
     local url = data.asm.customArgs['baseURL'] .. &quot;tree.html#&quot; .. rank .. &quot;=&quot; .. taxon 
             --  .. '#' .. data.asm.Base64.encode(taxon..&quot;&amp;global_search=true&amp;loose=false&quot;)
     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)&gt;0 and '1' or '0') end
         return r;
     end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
         if (#x &lt; 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)&gt;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 = &quot;WoRMS&quot;,
 	    website = &quot;[[World Register of Marine Species]]&quot;,
 	    --['via'] = &quot;[[World Register of Marine Species]]&quot;,
 	    --postscript = '&amp;#32;from the [[World Register of Marine Species]].'
 
 	},
 	customArgs = {exclude=&quot;id,db,1&quot;,
 	              baseURL = &quot;http://www.marinespecies.org/aphia.php?&quot;,
 	              searchStr = &quot;p=taxdetails&amp;id=&quot;,
 	              defaultTitle=&quot;World Register of Marine Species&quot;
 	}
 }
 data.WoRMS.id = function(id)
     --[[ Two styles
          1. http://www.marinespecies.org/aphia.php?p=taxdetails&amp;id=14712
             &gt;  WoRMS (2018). Heterobranchia. Accessed at: http://marinespecies.org/aphia.php?p=taxdetails&amp;id=14712 on 2018-11-28 
          2. http://www.marinespecies.org/aphia.php?p=taxdetails&amp;id=1057249
             &gt; MolluscaBase (2018). Ringipleura. Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&amp;id=1057249 on 2018-11-28 
     ]]
     if not templateArgs['id'] then return &quot;no id parameter detected&quot; end
     local searchStr = &quot;p=taxdetails&amp;id=&quot; .. 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 &lt;title&gt;WoRMS - World Register of Marine Species - Heterobranchia&lt;/title&gt;
     local title = &quot;WoRMS taxon details: AphiaID &quot; .. 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 == &quot;world of copepods database&quot; or db == &quot;copepoda&quot; or db == &quot;copepods&quot; or db == &quot;copepod&quot; then
 		templateArgs['author'] = &quot;World of Copepods Database&quot;
 		templateArgs['editor-last1']=&quot;Walter&quot;; templateArgs['editor-first1']=&quot;T.C.&quot;
 		templateArgs['editor-last2']=&quot;Boxshall&quot;; templateArgs['editor-first2']=&quot;G.&quot;
 		-- year ? (2022). 
 	elseif db == &quot;world amphipoda database&quot; or db == &quot;amphipoda&quot; or db == &quot;amphipod&quot;then
 		templateArgs['author'] = &quot;World Amphipoda Database&quot;
 		templateArgs['editor-last1']=&quot;Horton&quot;; templateArgs['editor-first1']=&quot;T.&quot;
 		templateArgs['editor-last2']=&quot;Lowry&quot;; templateArgs['editor-first2']=&quot;J.&quot;
 		templateArgs['editor-last3']=&quot;De Broyer&quot;; templateArgs['editor-first3']=&quot;C.&quot;
 		templateArgs['display-editors']=&quot;etal&quot;;  -- full list is about 20 names
 	elseif db == &quot;world isopoda database&quot; or db == &quot;isopoda&quot; or db == &quot;isopod&quot;then
 		templateArgs['author'] = &quot;World Marine, Freshwater and Terrestrial Isopod Crustaceans database&quot;
 		templateArgs['editor-last1']=&quot;Boyko&quot;; templateArgs['editor-first1']=&quot;C.B.&quot;
 		templateArgs['editor-last2']=&quot;Bruce&quot;; templateArgs['editor-first2']=&quot;N.L.&quot;
 		templateArgs['editor-last3']=&quot;Hadfield&quot;; templateArgs['editor-first3']=&quot;K.A.&quot;
 		templateArgs['editor-last4']=&quot;Merrin&quot;; templateArgs['editor-first4']=&quot;K.L.&quot;
 		templateArgs['editor-last5']=&quot;Ota.&quot;; templateArgs['editor-first5']=&quot;Y.&quot;
 		templateArgs['editor-last6']=&quot;Poore&quot;; templateArgs['editor-first6']=&quot;G.C.B.&quot;
 		templateArgs['editor-last7']=&quot;Taiti&quot;; templateArgs['editor-first7']=&quot;S.&quot;
 	elseif db == &quot;millibase&quot; or db == &quot;diplopoda&quot; or db == &quot;diplopod&quot;then
 		templateArgs['author'] = &quot;MilliBase&quot;
 		templateArgs['editor-last1']=&quot;Sierwald&quot;; templateArgs['editor-first1']=&quot;P.&quot;
 		templateArgs['editor-last2']=&quot;Spelda&quot;; templateArgs['editor-first2']=&quot;J.&quot;
 	elseif db == &quot;molluscabase&quot; or db == &quot;mollusca&quot; or db == &quot;mollusc&quot; then
 		templateArgs['author'] = &quot;MolluscaBase&quot;
 	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&amp;search_value=95601#null
 ]]
 data.itis = {
 	citationArgs = {
 	    website   = &quot;[[Integrated Taxonomic Information System]]&quot;,
 	    --publisher = &quot;&quot;,
 	},
 	customArgs = {exclude=&quot;id,1,2,3,4,5&quot;,
 	              baseURL = &quot;https://www.itis.gov/&quot;,
 	              searchStr = &quot;servlet/SingleRpt/SingleRpt?search_topic=TSN&amp;search_value=&quot;,
 	              defaultTitle=&quot;Integrated Taxonomic Information System&quot;
 	}
 }
 data.itis.id = function(id)   
 
     local title = &quot;ITIS id=&quot; .. 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 &amp; ITIS Catalogue of Life, 2020-12-01. 
 		Digital resource at www.catalogueoflife.org. Species 2000: Naturalis, Leiden, the Netherlands. ISSN 2405-8858.
 		Species 2000 &amp; 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       = &quot;col&quot;,  -- need rethink this
 	citationArgs = {
 	    --author = &quot;Catalogue of Life&quot;,
 	    --['editor-last1'] = &quot;Roskov&quot;,   ['editor-first1'] = &quot;Y.&quot;, ['editor-last2'] = &quot;Ower&quot;,     ['editor-first2'] = &quot;G.&quot;, 	    ['editor-last3'] = &quot;Orrell&quot;,   ['editor-first3'] = &quot;T.&quot;, ['editor-last4'] = &quot;Nicolson&quot;, ['editor-first4'] = &quot;D.&quot;, 	    ['editor-last5'] = &quot;Bailly&quot;,   ['editor-first5'] = &quot;N.&quot;, ['editor-last6'] = &quot;Kirk&quot;,     ['editor-first6'] = &quot;P.M.&quot;, 	    ['editor-last7'] = &quot;Bourgoin&quot;, ['editor-first7'] = &quot;T.&quot;, ['editor-last8'] = &quot;DeWalt&quot;,   ['editor-first8'] = &quot;R.E.&quot;, 	    ['editor-last9'] = &quot;Decock&quot;,   ['editor-first9'] = &quot;W.&quot;, ['editor-last10'] = &quot;van Nieukerken&quot;, ['editor-first10'] = &quot;E.J.&quot;, 	    ['editor-last11'] = &quot;Penev&quot;, ['editor-first11'] = &quot;L.&quot;, 
 	    --website   = &quot;[[Catalogue of Life]]&quot;,
 	    --website   = &quot;[[Catalogue of Life|Species 2000 &amp; ITIS Catalogue of Life]]&quot;,
 	    -- website   = &quot;[[Species 2000]] &amp; [[ITIS]] [[Catalogue of Life]]&quot;,
 	    website   = &quot;[[Catalogue of Life]]&quot;,
 	    publisher = &quot;[[Species 2000]]: Leiden, the Netherlands&quot;,
 	    --others    = &quot;Species 2000 &amp; ITIS&quot;
 
 	},
 	customArgs = {exclude=&quot;id,db,1,2,3,4,5,legacy,option&quot;,
 	              baseURL = &quot;https://www.catalogueoflife.org/data/&quot;,
 	              searchStr = &quot;browse?taxonKey=&quot;,
 	              defaultTitle=&quot;Catalogue of Life&quot;
 	}
 }
 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 = &quot;Catalogue of Life taxonKey &quot; .. 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,  &quot;^[0-9abcdef]+$&quot; ) then                                            -- if old-style id
 		local year = &quot;2019&quot;        -- last old-style version available
     	if templateArgs['version'] and string.find( templateArgs['version'], &quot;^%d%d%d%d$&quot;  ) then --if version specied
         	year = templateArgs['version']
         end
     	if templateArgs['option'] == &quot;browse&quot; then 
 		    url = &quot;http://www.catalogueoflife.org/annual-checklist/&quot; .. year .. &quot;/browse/tree/id/&quot; .. id
 		else -- default to option=taxon
 		    url = &quot;http://www.catalogueoflife.org/annual-checklist/&quot; .. year .. &quot;/details/species/id/&quot; .. id
 		end
     else                                                                                  -- else use current version
     	if templateArgs['option'] == &quot;browse&quot; then 
 		    url = url .. &quot;browse?taxonKey=&quot; .. id
 		else -- default to option=taxon
 		    url = url .. &quot;taxon/&quot; .. id
 		end
     end
 
 	return title, url    
 	
 end
 --[[ current links
 				 https://www.catalogueoflife.org/data/search?q=&quot; Chinchilla+chinchilla&amp;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 = &quot;7539827da517bd6273a4a3836578cb24&quot; 
 		local match = &quot;^[0-9abcdef]+$&quot; 
 		if string.find( para1, match ) then
 			url = &quot;http://www.catalogueoflife.org/col/details/species/id/&quot; .. para1  -- &quot;&quot;Old style id&quot;
 			--url =&quot;https://www.catalogueoflife.org/data/search?q=&quot; .. para1
 			if para2 then
 				title = para2
 			else
 				title = &quot;Oldstyle id: &quot; .. para1
 			end
 			
 		else
 
 			--https://www.catalogueoflife.org/data/search?q=&quot; Chinchilla+chinchilla&amp;type=EXACT
 			
 			if para1 ~= &quot;&quot; then
 				url = &quot;https://www.catalogueoflife.org/data/search?q=&quot; .. para1 
 				title = &quot;''&quot; .. para1 
 				if para2  then
 					url = url .. &quot;+&quot; .. para2 
 					title = title .. &quot; &quot; .. para2
 				end
 				url = url .. &quot;&amp;type=EXACT&quot;
 				title = title .. &quot;''&quot;
 			end
 			
 		end	
 		if para3 then title = title .. &quot; &quot; .. para3 end   -- add authority
 		if para4 == &quot;nv&quot; then templateArgs['trans-title'] = &quot;synonym&quot; 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=&quot;[[Fossilworks]]&quot;,
 		--publisher=&quot;Paleobiology Database&quot;,
 		--postscript = 'none',
 		postscript = &quot;&amp;#32;from the [[Paleobiology Database]].&quot;,
 		--via=&quot;''fossilworks.org''&quot;   -- an alternative format to using |website=
 	},
 	customArgs = { exclude = &quot;id,collection,date,1&quot;,
 	               baseURL = &quot;http://www.fossilworks.org/cgi-bin/&quot;,
 	               searchStr =&quot;bridge.pl?a=taxonInfo&amp;taxon_no=&quot;,
 	               defaultTitle = &quot;Fossilworks: Gateway to the Paleobiology Database&quot;
 	}
 	--id = function(id) return p.genericIdCitation (frame, title, url)
 }
 data.fossilworks.id = function(id)
 --[[ http://fossilworks.org/cgi-bin/bridge.pl?a=taxonInfo&amp;taxon_no=83087	
     if not templateArgs['id'] then return &quot;no id parameter detected&quot; end
     local searchStr = &quot;bridge.pl?a=taxonInfo&amp;taxon_no=&quot; .. templateArgs['id']
     templateArgs['url']= target.CustomArgs['baseURL'] .. searchStr
     ]]
     local title = &quot;PaleoDB taxon number: &quot; .. 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&amp;collection_no=20072
 	local title = &quot;PaleoDB collection number: &quot; .. collection
 	local url = data.fossilworks.customArgs['baseURL'] .. &quot;bridge.pl?a=collectionSearch&amp;collection_no=&quot; .. collection
 	return title, url 
 end
 data.fossilworks.error = function()
 	return &quot;Requires id and title parameters&quot;
 end
 
 
 --======================  Paleobiology Database: paleobiodb.org =======================================
 
 data.paleobiodb = {
 	citationArgs = {
 		website=&quot;[[Paleobiology Database]]&quot;
 	},
 	customArgs = { exclude = &quot;id,collection,date,1&quot;,
 	               baseURL = &quot;https://paleobiodb.org/classic/&quot;,
 	               searchStr =&quot;basicTaxonInfo?taxon_no=&quot;,
 	               defaultTitle = &quot;Paleobiology Database&quot;
 	}
 	--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 &quot;no id parameter detected&quot; end
     ]]
     local title = &quot;PaleoDB taxon number: &quot; .. 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 = &quot;PaleoDB collection number: &quot; .. collection
 	local url = data.paleobiodb.customArgs['baseURL'] .. &quot;basicCollectionSearch?collection_no=&quot; .. collection
 	return title, url 
 end
 data.paleobiodb.error = function()
 	return &quot;Requires id and title parameters&quot;
 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 .. &quot; &quot; .. templateArgs['authority']
      	return string.gsub( title, &quot;(.*%.)$&quot;, &quot;((%1))&quot;)  -- if authority ends in &quot;.&quot; 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:  [https://www.worldplants.de?deeplink=Helosciadium-Koch ''Helosciadium'']
 		Species: [https://www.worldplants.de?deeplink=Helosciadium-longipedunculatum ''Helosciadium longipedunculatum'']
 		
 		Genus:  [https://www.worldplants.de?deeplink=Lycopodium-L. ''Lycopodium'']
 		Species: [https://www.worldplants.de?deeplink=Lycopodium-clavatum ''Lycopodium clavatum'']
 
 --]]
 data.worldplants = {
 	citationArgs = {
 		last1 = &quot;Hassler&quot;, first1 = &quot;Michael&quot;,
 		website=&quot;World Plants. Synonymic Checklist and Distribution of the World Flora.&quot;,
 		--publisher=&quot;&quot;
 	},
 	customArgs = { exclude = &quot;id,authority,family,genus,species,1&quot;,
 	               baseURL = &quot;https://www.worldplants.de&quot;,
 	               searchStr =&quot;/world-plants-complete-list/complete-plant-list#&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;World Plants&quot;
 	}
 }
 data.worldplants.genus = function(genus)
 	local title = addAuthority(&quot;''&quot; .. genus .. &quot;''&quot;)
 	local genusString = genus 
 	if templateArgs['authority'] then genusString = genus .. &quot;-&quot; .. templateArgs['authority'] end
 	local url = data.worldplants.customArgs['baseURL'] .. &quot;?deeplink=&quot; .. genusString
 	return title, url  
 end
 data.worldplants.species = function(genus, species)
 	local title = addAuthority(&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;)
 	local url = data.worldplants.customArgs['baseURL'] .. &quot;?deeplink=&quot; .. genus .. &quot;-&quot; .. species .. &quot; &quot; .. (templateArgs['authority'] or &quot;&quot;)
 	return title, url  
 end
 --[[ experimental, don't leave live 
 
 data.worldplants.taxon = function(taxon)
 	local title =  taxon .. &quot; &quot; .. (templateArgs['authority'] or &quot;&quot;)
 	local url = data.worldplants.customArgs['baseURL'] .. &quot;?deeplink=&quot; .. taxon
 	return title, url  
 end
 
 data.worldplants.family = function(family)
 	local title = family .. &quot; &quot; .. (templateArgs['authority'] or &quot;&quot;)
 	local url = data.worldplants.customArgs['baseURL'] .. &quot;?deeplink=&quot; .. family
 	return title, url  
 end
 --]]
 data.worldferns = {
 	citationArgs = {
 		last1 = &quot;Hassler&quot;, first1 = &quot;Michael&quot;,
 		website=&quot;World Ferns. Synonymic Checklist and Distribution of the World Flora.&quot;,
 		--publisher=&quot;&quot;
 	},
 	customArgs = { exclude = &quot;id,authority,family,genus,species,1&quot;,
 	               baseURL = &quot;https://www.worldplants.de/&quot;,
 	               searchStr =&quot;world-ferns/ferns-and-lycophytes-list?name=&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;World Ferns&quot;
 	}
 }
 data.worldferns.genus = function(genus)
 	local title = addAuthority(&quot;''&quot; .. genus .. &quot;''&quot;)
 	local genusString = genus 
 	if templateArgs['authority'] then genusString = genus .. &quot;-&quot; .. 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(&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;)
 	local url = data.worldferns.customArgs['baseURL'] .. data.worldferns.customArgs['searchStr'] .. genus .. &quot;-&quot; .. species .. &quot; &quot; .. (templateArgs['authority'] or &quot;&quot;)
 	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&amp;species=abietina            -- or genus + species
 	   http://powo.science.kew.org/?genus=Selago&amp;f=accepted_names            -- filter for accepted names
 	   http://powo.science.kew.org/?genus=Selago&amp;f=genus_f                   -- filter for genus (no species selected)
 	   http://powo.science.kew.org/?genus=Selago&amp;f=genus_f%2Caccepted_names  -- filter for genus and accepted names
 	   http://powo.science.kew.org/?page.size=480&amp;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=&quot;[[Plants of the World Online]]&quot;,
 		publisher=&quot;Royal Botanic Gardens, Kew&quot;,
 		--postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,authority,family,genus,species,1&quot;,
 	               baseURL = &quot;http://powo.science.kew.org/taxon/&quot;,
 	               searchStr =&quot;urn:lsid:ipni.org:names:&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;Plants of the World Online&quot;
 	}
 	--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(&quot;''&quot; .. genus .. &quot;''&quot;)
 	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(&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;)
 	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, &quot;urn:lsid:ipni.org:names:&quot;, &quot;&quot;) -- don't want this twice
 	end
 	return nil
 end
 data.POWO.error = function()
 	return '&lt;span style=&quot;color:red&quot;&gt;Requires id and one of title, family, genus or species parameters&lt;/span&gt;'
 end
 
 --[[Gouda, E.J., Butcher, D. &amp; Gouda, C.S. (cont.updated) 
 Encyclopaedia of Bromeliads, Version 4. http://bromeliad.nl/encyclopedia/ Utrecht University Botanic Gardens
 ]]
 
 data.bromeliad = {
 	citationArgs = {
 		last1=&quot;Gouda&quot;, first1=&quot;E.J.&quot;,
 		last2=&quot;Butcher&quot;, first2=&quot;D.&quot;,
 		last3=&quot;Gouda&quot;, first3=&quot;C.S&quot;,
 		website=&quot;[[Encyclopaedia of Bromeliads]]&quot;,
 		version=&quot;Version 4&quot;,
 		publisher=&quot;Utrecht University Botanic Gardens&quot;,
 		--postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,authority,family,genus,species,list,1&quot;,
 	               baseURL = &quot;https://bromeliad.nl/&quot;,
 	               searchStr =&quot;encyclopedia/index.php?find=&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;Encyclopaedia of Bromeliads, Version 4&quot;
 	}
 	--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'] .. &quot;species/&quot; .. taxon
     return title, url  
 end
 --[[ genus	]]
 data.bromeliad.genus = function(genus)
 
     local title = addAuthority(&quot;''&quot; .. genus .. &quot;''&quot;)                                                                          -- as default value
 	local url = data.bromeliad.customArgs['baseURL'] .. &quot;species/&quot; .. genus
 	if templateArgs['list'] == &quot;species&quot; then
         url = data.bromeliad.customArgs['baseURL'] .. &quot;encyclopedia/brome.php?action=showSpeciesIndex&amp;name=&quot; .. genus .. &quot;&amp;flags=&quot;
     end
     return title, url  
 end
 --[[ 	]]
 data.bromeliad.species = function(genus, species)
 
     local title = addAuthority(&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;)                                                                          -- as default value
 	local url = data.bromeliad.customArgs['baseURL'] .. &quot;species/&quot; .. genus .. &quot;/&quot; .. species 
     return title, url  
 end
 
 --[[ https://bromeliad.nl/encyclopedia/brome.php?action=showTaxon&amp;id=10093 ]]
 data.bromeliad.id = function(id)
 
     local title = id                                                                          -- as default value
 	local url = data.bromeliad.customArgs['baseURL'] .. &quot;encyclopedia/brome.php?action=showTaxon&amp;id=&quot; .. 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&amp;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&amp;type=family
 	Subfamily record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=subfamily&amp;id=1507
 	   Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=3265&amp;type=subfamily
 	Tribe record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=tribe&amp;id=1551 (Millettieae)
 	   Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=1551&amp;type=tribe
 	Subtribe record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=subtribe&amp;id=1507
 	   Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=1507&amp;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&amp;type=genus
 	Species record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomydetail?id=489203 ( Adenodolichos paniculatus)
 	
 ]]
 data.GRIN = {     
 	citationArgs = {
 		website=&quot;[[Germplasm Resources Information Network]] (GRIN)&quot;,
 		publisher=&quot;[[Agricultural Research Service]] (ARS), [[United States Department of Agriculture]] (USDA)&quot;,
 		--postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,authority,family,genus,species,1&quot;,
 	               baseURL = &quot;https://npgsweb.ars-grin.gov/gringlobal&quot;,
 	               searchStr =&quot;/taxon/taxonomydetail?&quot;,                             -- for species record
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;GRIN-Global&quot;
 	}
 	--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
 --→ &quot;Meconopsis Vig.&quot; International Plant Names Index (IPNI). Royal Botanic Gardens, Kew.
 --- 	https://www.ipni.org/n/30149252-2
 --- as {{IPNI |id=30149252-2 |taxon=((Meconopsis |authority=Vig.))}} 
 
 data.IPNI = {     
 	citationArgs = {
 		website=&quot;[[International Plant Names Index]] (IPNI)&quot;,
 		publisher=&quot;Royal Botanic Gardens, Kew&quot;,
 		--postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,authority,family,genus,species,1&quot;,
 	               baseURL = &quot;https://www.ipni.org&quot;,
 	               searchStr =&quot;/n/&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;IPNI&quot;
 	}
 	--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 .. &quot; &quot; .. species, &quot;TITLE_ITALICS&quot;) end
 data.IPNI.genus  = function(genus)  return data.IPNI.taxon(genus, &quot;TITLE_ITALICS&quot;) end
 data.IPNI.taxon = function(taxon, italics)
 	local title = taxon 
 	if italics then title = &quot;''&quot; .. title .. &quot;''&quot;  end
 	title = addAuthority(title)
 --[[	if templateArgs['authority'] then
 		title = title .. &quot; &quot; .. templateArgs['authority']
 		title = string.gsub( title, &quot;(.*%.)$&quot;, &quot;((%1))&quot;)  -- if authority ends in &quot;.&quot; 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=&quot;[[World Flora Online]]&quot;,
 		--publisher=&quot;Missouri Botanical Gardens&quot;,
 		--postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,family,genus,species,authority,1&quot;,
 	               baseURL = &quot;http://www.worldfloraonline.org&quot;,
 	               searchStr =&quot;/taxon/wfo-&quot;,                                       -- not strictly search string
 	               defaultSuffix = &quot;&quot;,
 	               --defaultTitle = &quot;World Flora Online&quot;
 	               defaultTitle = &quot;An Online Flora of All Known Plants&quot;
 	}
 
 }
 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(&quot;''&quot; .. genus .. &quot;''&quot;) 
 	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(&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;) 
 	local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. templateArgs['id']
     return title, url  
 end
 data.WFO.error = function()
 	return &quot;Requires id and title parameters&quot;
 end
 
 data.Tropicos = {
 	citationArgs = {
 		website=&quot;[[Tropicos]]&quot;,
 		--publisher=&quot;Missouri Botanical Gardens&quot;,
 		--postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,1&quot;,
 	               baseURL = &quot;http://legacy.tropicos.org/Name/&quot;,
 	               searchStr =&quot;&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;Tropicos&quot;
 	}
 
 }
 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 &quot;Requires id and title parameters&quot;
 end
 
 
 data.FNA = {
 	citationArgs = {
 		            website=&quot;[[Flora of North America]]&quot;,
 		            --publisher=&quot;http://www.efloras.org&quot;,
 		            --postscript = 'none',
 	},
 	customArgs = { exclude = &quot;id,1&quot;,
 	               baseURL = &quot;http://www.efloras.org/florataxon.aspx&quot;,
 	               searchStr =&quot;?flora_id=1&amp;taxon_id=&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;Flora of North America&quot;
 	}
 	--id = function(id) return p.genericIdCitation (frame, title, url)
 }
 data.FNA.id = function(id)
 --[[ http://www.efloras.org/florataxon.aspx?flora_id=1&amp;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 &quot;Requires id and title parameters&quot;
 end
 -- ATRP: Australian Tropical Rainforest Plants 
 
 
 data.ATRP = {
 	citationArgs = {
 		            website=&quot;[[Australian Tropical Rainforest Plants]]&quot;,
 		            publisher=&quot;[[Commonwealth Scientific and Industrial Research Organisation]] (CSIRO)&quot;,
 		            version = &quot;Edition 8&quot;,
 				    year = 2020,
 		            --postscript = 'none',
 		            last1= &quot;Zich&quot;, first1=&quot;F. A.&quot;, 
 		            last2= &quot;Hyland&quot;,  first2= &quot;B. P. M.&quot;, ['author2-link']=&quot;Bernard Hyland&quot;,
 		            last3= &quot;Whiffin&quot;, first3= &quot;T.&quot;, 
 		            last4= &quot;Kerrigan&quot;,  first4= &quot;R.A.&quot;,
 		            --['display-authors']=3,
 	},
 	customArgs = { exclude = &quot;genus, species,authority, id,1&quot;,
 	               baseURL = &quot;https://apps.lucidcentral.org/rainforest&quot;,
 	               searchStr =&quot;/text/entities/&quot;,
 	               defaultSuffix = &quot;.htm&quot;,
 	               defaultTitle = &quot;[[Australian Tropical Rainforest Plants]]&quot;
 	}
 	--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(&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;) --&quot;''&quot; .. genus .. &quot; &quot; .. species .. &quot;''&quot;
     local url = data.ATRP.customArgs['baseURL'] .. data.ATRP.customArgs['searchStr'] .. genus .. &quot;_&quot; .. species .. data.ATRP.customArgs['defaultSuffix']
     return title, url  
 end
 data.ATRP.error = function()
 	return &quot;Requires genus and species parameters&quot;
 end
 
 -- ============================= Mosses (Goffinet's site) =================================================-- for species in taxon; for species assessments, us {{cite iucn}}
 -- https://bryology.uconn.edu/classification/#Hypnanae
 -- https://bryology.uconn.edu/classification/#Bryales
 data.goffinet = {
 	citationArgs = {
 		first1=&quot;B.&quot;, last1=&quot;Goffinet&quot;, 
 		first2=&quot;W.R.&quot;, last2=&quot;Buck&quot;,
 		website=&quot;Classification of extant moss genera&quot;
 		--publisher=&quot;[[xxx]]&quot;
 	},
 	customArgs = { exclude=&quot;family,genus,species,taxon,id,1&quot;,
 	               baseURL = &quot;https://bryology.uconn.edu/classification/&quot;,
 	               searchString = &quot;#&quot;,
 	               searchSuffix = &quot;&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle=&quot;Classification of the Bryophyta&quot;
 	}	
 }
 data.goffinet.genus  = function(genus)  return data.goffinet.taxon(genus, &quot;GENUS&quot;) end
 data.goffinet.family = function(family) return data.goffinet.taxon(family, &quot;FAMILY&quot;) end
 data.goffinet.order  = function(order)  return data.goffinet.taxon(order, &quot;ORDER&quot;) end
 data.goffinet.taxon  = function(taxon, rank)
     local title = firstToUpper(taxon)
     if rank == &quot;GENUS&quot; then title = &quot;''&quot; .. title .. &quot;''&quot; end
     if not (rank == &quot;GENUS&quot; or rank == &quot;FAMILY&quot;) then  -- upper case anchors for orders and above
     	if taxon ~= &quot;Bryanae&quot; and taxon ~= &quot;Hypnanae&quot; and taxon ~= &quot;Bryales&quot; and taxon ~= &quot;Bryidae&quot; 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. &amp; 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=&quot;[[AlgaeBase]]&quot;,
 	               ['editor1-last']=&quot;Guiry&quot;, ['editor1-first']=&quot;M.D.&quot;,
 	               ['editor2-last']=&quot;Guiry&quot;, ['editor2-first']=&quot;G.M.&quot;,
 		           publisher=&quot;National University of Ireland, Galway&quot;,
 	},
 	customArgs = { exclude = &quot;id,1,genus_id,species_id,spid,genid&quot;,
 	               baseURL = &quot;https://www.algaebase.org/&quot;,
 	               searchStr =&quot;browse/taxonomy/?id=&quot;,
 	               defaultSuffix = &quot;&quot;,
 	               defaultTitle = &quot;AlgaeBase&quot;
 	}
 }
 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'] .. &quot;search/genus/detail/?genus_id=&quot; .. 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'] .. &quot;search/species/detail/?species_id=&quot; .. spid
     return title, url  
 end
 data.AlgaeBase.error = function()
 	return &quot;Requires id and title parameters&quot;
 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 ~= &quot;&quot; then
 			args[k]=v --parents.args[k]
 		end
 	end
 	for k,v in pairs(frame.args) do
 		--check content
 		if v and v ~= &quot;&quot; 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 &quot;&quot;) .. (target.customArgs['defaultSuffix'] or &quot;&quot;)
 	local title = target.customArgs['defaultTitle'] or &quot;&quot;
 	return title, url
 end 
 -- moved up top for scope
 local function firstToUpper2(str)
     return (str:gsub(&quot;^%l&quot;, string.upper))
 end
 -- clear template arguments that won't be recognised by {{cite web}}
 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'] , &quot;%s*,%s*&quot;);	
 		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 {{cite book}}
 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 &quot;&amp;pg=PP1&quot;)
     			
     		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 &quot;&quot;
 			if templateArgs['page'] or templateArgs['gb-page'] then
 				pageSuffix = &quot;&amp;pg=PT&quot; .. (templateArgs['gb-page'] or templateArgs['page'] )
 			end
 			local searchStr = &quot;&quot;
 		    -- quoted search {{#if:{{{text|{{{dq|}}}}}}|&amp;dq={{urlencode:{{{text|{{{dq|}}}}}}}}}}
 		    if templateArgs['q'] then searchStr = &quot;&amp;q=&quot; .. mw.text.encode( templateArgs['q'] ) end
 		    -- search #if:{{{keywords|{{{q|}}}}}}|&amp;q={{urlencode:{{{keywords|{{{q|}}}}}}}}}}
 		    if templateArgs['dq'] then searchStr = &quot;&amp;dq=&quot; .. 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 &quot;Page number for google books required&quot;
     	end
     elseif templateArgs['order'] then
     	templateArgs['chapter'] =  &quot;Order &quot; .. 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']  .. &quot;1&quot; -- 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
 --======= Plants
 p.WFO         = function(frame) return p._main(frame, data.WFO) end
 p.POWO        = function(frame) return p._main(frame, data.POWO) 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 &quot;hello&quot; end
 --#########################################################
 p.main = function(frame) 
 	local source = mw.text.trim(frame.args[1])
 	--TODO force to lower case and use lower case for all functions above
 	
 	if source == &quot;MSW3&quot; then return p.MSW3(frame) end
 	
 	if source == &quot;ref&quot; or source == &quot;reference&quot; then source = &quot;Reference&quot; end   -- aliases
 	if source == &quot;Reference&quot; then return p.Reference(frame) end
     
     if source == &quot;HBWa&quot; then source = &quot;HBWalive&quot; end   -- aliases
     if source == &quot;powo&quot; then source = &quot;POWO&quot; end   -- aliases
     if source == &quot;wfo&quot; then source = &quot;WFO&quot; end   -- aliases
     if source == &quot;mdd&quot; then source = &quot;asm&quot; end   -- aliases
 	--return p[source]['test']
 	if source == &quot;fishbase&quot;              -- unnecessary?
 		or source == &quot;cof&quot; 
 		or source == &quot;fotw5&quot; or source == &quot;Fotw5&quot; 
 		or source == &quot;reptileDB&quot; 
 		or source == &quot;amphibiaweb&quot; 
 		or source == &quot;ASW6&quot; 
 		or source == &quot;asm&quot; 
 		or source == &quot;HBWalive&quot; or source == &quot;HBWa&quot; 
 		or source == &quot;fossilworks&quot; 
 		or source == &quot;WoRMS&quot; or source == &quot;worms&quot; 
 		or source == &quot;POWO&quot; or source == &quot;powo&quot; 
 		or source == &quot;WFO&quot; or source == &quot;wfo&quot; 
 		or source == &quot;AlgaeBase&quot;
 		-- 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 &quot;Error: unrecognised source.&quot; end
     
     local title, url = initialise(frame, source)
     
     --taxon related parameters
     local genus, species, subspecies
     
     if source.db ~= &quot;col&quot; 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 = &quot;genus&quot;; value = genus 
     	elseif family then mode = &quot;family&quot;; value = family
     	elseif order then mode = &quot;order&quot;; value = order
     	elseif taxon then mode = &quot;taxon&quot;; value = taxon
     	elseif id then mode = &quot;id&quot;; value = id
     	elseif spid then mode = &quot;spid&quot;; value = spid
     	elseif genid then mode = &quot;genid&quot;; value = genid	
         elseif search then mode = &quot;search&quot;; value = search	
         elseif citation then mode = &quot;citation&quot;; value = citation	
         elseif collection then mode = &quot;collection&quot;; 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 &quot;Error: parameter not supported for this source&quot; .. &quot; (&quot; .. mode .. &quot;)&quot;
     	end
     else 
     	-- if no mode then use the default title and url set by initialize()
     end
 
     if source.citeTemplate == &quot;Cite book&quot; 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 ~= &quot;&quot; and refs[reference] then 
 			if templateArgs['pages'] then 
 				refs[reference] = refs[reference]:gsub(&quot;}}&quot;, &quot;|pages=&quot;..templateArgs['pages']..&quot;}}&quot;)
 				refs[reference] = refs[reference]:gsub(&quot;|pages=[^|{}%[%]]*(|[^|{}}%[%]]*|pages=)&quot;, &quot;%1&quot;)
 			end
 			if templateArgs['reftags'] == &quot;yes&quot; then
 				refs[reference] = '&lt;ref name=' .. templateArgs[2] ..'&gt;' .. refs[reference] .. '&lt;/ref&gt;'
 			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: &quot;'	.. templateArgs[2] .. '&quot;'
 		end
 	end
 	return &quot;Reference parameter missing.&quot;
 end -- End the function.
 
 
 
 
 -- All modules end by returning the variable containing its functions to Wikipedia.