Módulo:Citas

Icono de documentación de módulo Documentación del módulo[ver] [editar] [historial] [purgar]

A continuación se muestra la documentación transcluida desde la subpágina /doc. [salta a la caja de código]


Uso

Este módulo permite generar citas de libros, noticias, notas de álbumes y DVD, etc.

Módulos auxiliares
Funciones

Esta documentación está transcluida desde Módulo:Citas/doc.
Por favor, añade las categorías en la subpágina de documentación y los interwikis en Wikidata. Subpáginas de este módulo.

local z = {     error_categories = {};     error_ids = {};     message_tail = {}; } -- Include translation message hooks, ID and error handling configuration settings. --local cfg = mw.loadData( 'Mdódulo:Citas/Configuración/pruebas' );  -- Contains a list of all recognized parameters --local whitelist = mw.loadData( 'Módulo:Citas/Whitelist/pruebas' ); --local dates = require('Módulo:Citas/ValidaciónFechas/pruebas').dates		-- location of date validation code  --Módulo para formatear las fechas local DateModule = require('Módulo:Date')._Date   -- Whether variable is set or not function is_set( var )     return not (var == nil or var == ''); end  -- First set variable or nil if none function first_set(...)     local list = {...};     for _, var in pairs(list) do         if is_set( var ) then             return var;         end     end end  -- Whether needle is in haystack function inArray( needle, haystack )     if needle == nil then         return false;     end     for n,v in ipairs( haystack ) do         if v == needle then             return n;         end     end     return false; end  --[[ Formatea una fecha para que se devuelva de la siguiente forma: "1 de enero de 2020" Formats a date so it is returned as follows: "1 de enero de 2020" ]]  function format_date(date_string) 	function dateFormatter(text) 		return DateModule(text):text('%-d de %B de %-Y') 	end  	local stat, res = pcall(dateFormatter, date_string) 	 	if stat then       return res     else       return date_string     end end  --[[ Categorize and emit an error message when the citation contains one or more deprecated parameters.  Because deprecated parameters (currently |day=, |month=, |coauthor=, and |coauthors=) aren't related to each other and because these parameters may be concatenated into the variables used by |date= and |author#= (and aliases) details of which parameter caused the error message are not provided.  Only one error message is emitted regarless of the number of deprecated parameters in the citation. ]] function deprecated_parameter( name ) --		table.insert( z.message_tail, { seterror( 'deprecated_params', {error_message}, true ) } );		-- add error message 		table.insert( z.message_tail, { seterror( 'deprecated_params', { name }, true ) } );		-- add error message end  -- Populates numbered arguments in a message string using an argument table. function substitute( msg, args ) --	return args and tostring( mw.message.newRawMessage( msg, args ) ) or msg; 	return args and mw.message.newRawMessage( msg, args ):plain() or msg; end  --[[ Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. This function will positive kern  either single or double quotes: 	"'Unkerned title with leading and trailing single quote marks'" 	" 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example) ]] function kern_quotes (str) 	local left='<span style="padding-left:0.2em;">%1</span>';		-- spacing to use when title contains leading single or double quote mark 	local right='<span style="padding-right:0.2em;">%1</span>';		-- spacing to use when title contains trailing single or double quote mark 	 	if  str:match ("^[\"\'][^\']") then 		str = string.gsub( str, "^[\"\']", left, 1 );				-- replace (captured) leading single or double quote with left-side <span> 	end 	if str:match ("[^\'][\"\']$") then 		str = string.gsub( str, "[\"\']$", right, 1 );			-- replace (captured) trailing single or double quote with right-side <span> 	end 	return str; end  -- Wraps a string using a message_list configuration taking one argument function wrap( key, str, lower )     if not is_set( str ) then         return "";     elseif inArray( key, { 'italic-title', 'trans-italic-title' } ) then         str = safeforitalics( str );     end     if lower == true then         return substitute( cfg.messages[key]:lower(), {str} );     else         return substitute( cfg.messages[key], {str} );     end         end  --[[ Argument wrapper.  This function provides support for argument  mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] function argument_wrapper( args )     local origin = {};          return setmetatable({         ORIGIN = function( self, k )             local dummy = self[k]; --force the variable to be loaded.             return origin[k];         end     },     {         __index = function ( tbl, k )             if origin[k] ~= nil then                 return nil;             end                          local args, list, v = args, cfg.aliases[k];                          if type( list ) == 'table' then                 v, origin[k] = selectone( args, list, 'redundant_parameters' );                 if origin[k] == nil then                     origin[k] = ''; -- Empty string, not nil                 end             elseif list ~= nil then                 v, origin[k] = args[list], list;             else                 -- maybe let through instead of raising an error?                 -- v, origin[k] = args[k], k;                 error( cfg.messages['unknown_argument_map'] );             end                          -- Empty strings, not nil;             if v == nil then                 v = cfg.defaults[k] or '';                 origin[k] = '';             end                          tbl = rawset( tbl, k, v );             return v;         end,     }); end  --[[ Looks for a parameter's name in the whitelist.  Parameters in the whitelist can have three values: 	true - active, supported parameters 	false - deprecated, supported parameters 	nil - unsupported parameters ]] function validate( name ) 	local name = tostring( name ); 	local state = whitelist.basic_arguments[ name ]; 	 	-- Normal arguments 	if true == state then return true; end		-- valid actively supported parameter 	if false == state then 		deprecated_parameter ( name );			-- parameter is deprecated but still supported 		return true; 	end 	 	-- Arguments with numbers in them 	name = name:gsub( "%d+", "#" );				-- replace digit(s) with # (last25 becomes last# 	state = whitelist.numbered_arguments[ name ]; 	if true == state then return true; end		-- valid actively supported parameter 	if false == state then 		deprecated_parameter ( name );			-- parameter is deprecated but still supported 		return true; 	end 	 	return false;								-- Not supported because not found or name is set to nil end  -- Formats a comment for error trapping function errorcomment( content, hidden )     return wrap( hidden and 'hidden-error' or 'visible-error', content ); end  --[[ Sets an error condition and returns the appropriate error message.  The actual placement of the error message in the output is the responsibility of the calling function. ]] function seterror( error_id, arguments, raw, prefix, suffix )     local error_state = cfg.error_conditions[ error_id ];          prefix = prefix or "";     suffix = suffix or "";          if error_state == nil then         error( cfg.messages['undefined_error'] );     elseif is_set( error_state.category ) then         table.insert( z.error_categories, error_state.category );     end          local message = substitute( error_state.message, arguments );          message = message .. " ([[" .. cfg.messages['help page link'] ..          "#" .. error_state.anchor .. "|" ..         cfg.messages['help page label'] .. "]])";          z.error_ids[ error_id ] = true;     if inArray( error_id, { 'bare_url_missing_title', 'trans_missing_title' } )             and z.error_ids['citation_missing_title'] then         return '', false;     end          message = table.concat({ prefix, message, suffix });          if raw == true then         return message, error_state.hidden;     end                      return errorcomment( message, error_state.hidden ); end  -- Formats a wiki style external link function externallinkid(options)     local url_string = options.id;     if options.encode == true or options.encode == nil then         url_string = mw.uri.encode( url_string );     end     return wrap( 'id', internallink(options.link, options.label) ..         (options.separator or "&nbsp;") .. mw.ustring.format( '[%s%s%s %s]',          options.prefix, url_string, options.suffix or "",         mw.text.nowiki(options.id)     )); end  -- Formats a wiki style internal link function internallinkid(options)     return wrap( 'id', internallink(options.link, options.label) ..         (options.separator or "&nbsp;") .. mw.ustring.format( '[[%s%s%s|%s]]',         options.prefix, options.id, options.suffix or "",         mw.text.nowiki(options.id)     )); end  -- Format an internal link, if link is really set function internallink( link, label ) 	if link and link ~= '' then 		return mw.ustring.format( '[[%s|%s]]', link, label ) 	else 		return label 	end end  -- Format an external link with error checking function externallink( URL, label, source )     local error_str = "";     if not is_set( label ) then         label = URL;         if is_set( source ) then             error_str = seterror( 'bare_url_missing_title', { wrap( 'parameter', source ) }, false, " " );         else             error( cfg.messages["bare_url_no_origin"] );         end     end     if not checkurl( URL ) then         error_str = seterror( 'bad_url', {}, false, " " ) .. error_str;     elseif mw.title.getCurrentTitle():inNamespaces(0, 100, 104) and     	not mw.title.getCurrentTitle().text:match('Wikipedia') and     	URL:match('//[%a%.%-]+%.wikipedia%.org') then     	error_str = seterror( 'bad_url_autorreferencia', {}, false, " " ) .. error_str;     end     return table.concat({ "[", URL, " ", safeforurl( label ), "]", error_str }); end --[[--------------------------< N O R M A L I Z E _ L C C N >--------------------------------------------------  lccn normalization (http://www.loc.gov/marc/lccn-namespace.html#normalization) 1. Remove all blanks. 2. If there is a forward slash (/) in the string, remove it, and remove all characters to the right of the forward slash. 3. If there is a hyphen in the string: 	a. Remove it. 	b. Inspect the substring following (to the right of) the (removed) hyphen. Then (and assuming that steps 1 and 2 have been carried out): 		1. All these characters should be digits, and there should be six or less. (not done in this function) 		2. If the length of the substring is less than 6, left-fill the substring with zeroes until the length is six.  Returns a normalized lccn for lccn() to validate.  There is no error checking (step 3.b.1) performed in this function. ]]  local function normalize_lccn (lccn) 	lccn = lccn:gsub ("%s", "");									-- 1. strip whitespace  	if nil ~= string.find (lccn,'/') then 		lccn = lccn:match ("(.-)/");								-- 2. remove forward slash and all character to the right of it 	end  	local prefix 	local suffix 	prefix, suffix = lccn:match ("(.+)%-(.+)");						-- 3.a remove hyphen by splitting the string into prefix and suffix  	if nil ~= suffix then											-- if there was a hyphen 		suffix=string.rep("0", 6-string.len (suffix)) .. suffix;	-- 3.b.2 left fill the suffix with 0s if suffix length less than 6 		lccn=prefix..suffix;										-- reassemble the lccn 	end 	 	return lccn; 	end --[[ Format LCCN link and do simple error checking.  LCCN is a character string 8-12 characters long. The length of the LCCN dictates the character type of the first 1-3 characters; the rightmost eight are always digits. http://info-uri.info/registry/OAIHandler?verb=GetRecord&metadataPrefix=reg&identifier=info:lccn/  length = 8 then all digits length = 9 then lccn[1] is alpha length = 10 then lccn[1] and lccn[2] are both alpha or both digits length = 11 then lccn[1] is alpha, lccn[2] and lccn[3] are both alpha or both digits length = 12 then lccn[1] and lccn[2] are both alpha  ]] function lccn(id) 	local handler = cfg.id_handlers['LCCN']; 	local err_cat =  '';								-- presume that LCCN is valid  	id = normalize_lccn (id); 	 	local len = id:len();								-- get the length of the lccn  	if 8 == len then 		if id:match("[^%d]") then						-- if LCCN has anything but digits (nil if only digits) 			err_cat = ' ' .. seterror( 'bad_lccn' );	-- set an error message 		end 	elseif 9 == len then								-- LCCN should be adddddddd 		if nil == id:match("%a%d%d%d%d%d%d%d%d") then			-- does it match our pattern? 			err_cat = ' ' .. seterror( 'bad_lccn' );	-- set an error message 		end 	elseif 10 == len then								-- LCCN should be aadddddddd or dddddddddd 		if id:match("[^%d]") then							-- if LCCN has anything but digits (nil if only digits) ... 			if nil == id:match("^%a%a%d%d%d%d%d%d%d%d") then	-- ... see if it matches our pattern 				err_cat = ' ' .. seterror( 'bad_lccn' );	-- no match, set an error message 			end 		end 	elseif 11 == len then								-- LCCN should be aaadddddddd or adddddddddd 		if not (id:match("^%a%a%a%d%d%d%d%d%d%d%d") or id:match("^%a%d%d%d%d%d%d%d%d%d%d")) then	-- see if it matches one of our patterns 			err_cat = ' ' .. seterror( 'bad_lccn' );	-- no match, set an error message 		end 	elseif 12 == len then								-- LCCN should be aadddddddddd 		if not id:match("^%a%a%d%d%d%d%d%d%d%d%d%d") then	-- see if it matches our pattern 			err_cat = ' ' .. seterror( 'bad_lccn' );	-- no match, set an error message 		end 	else 		err_cat = ' ' .. seterror( 'bad_lccn' );		-- wrong length, set an error message 	end  	return externallinkid({link = handler.link, label = handler.label, 			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; end  --[[ Format PMID and do simple error checking.  PMIDs are sequential numbers beginning at 1 and counting up.  This code checks the PMID to see that it contains only digits and is less than test_limit; the value in local variable test_limit will need to be updated periodically as more PMIDs are issued. ]] function pmid(id) 	local test_limit = 45000000;						-- update this value as PMIDs approach 	local handler = cfg.id_handlers['PMID']; 	local err_cat =  '';								-- presume that PMID is valid 	 	if id:match("[^%d]") then							-- if PMID has anything but digits 		err_cat = ' ' .. seterror( 'bad_pmid' );		-- set an error message 	else												-- PMID is only digits 		local id_num = tonumber(id);					-- convert id to a number for range testing 		if 1 > id_num or test_limit < id_num then		-- if PMID is outside test limit boundaries 			err_cat = ' ' .. seterror( 'bad_pmid' );	-- set an error message 		end 	end 	 	return externallinkid({link = handler.link, label = handler.label, 			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; end  --[[ Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date.  If embargo date is in the future, returns true; otherwse, returns false because the embargo has expired or |embargo= not set in this cite. ]] function is_embargoed(embargo) 	if is_set(embargo) then 		local lang = mw.getContentLanguage(); 		local good1, embargo_date, good2, todays_date; 		good1, embargo_date = pcall( lang.formatDate, lang, 'U', embargo ); 		good2, todays_date = pcall( lang.formatDate, lang, 'U' ); 	 		if good1 and good2 and tonumber( embargo_date ) >= tonumber( todays_date ) then	--is embargo date is in the future? 			return true;	-- still embargoed 		end 	end 	return false;			-- embargo expired or |embargo= not set end  --[[ Format a PMC, do simple error checking, and check for embargoed articles.  The embargo parameter takes a date for a value. If the embargo date is in the future the PMC identifier will not be linked to the article.  If the embargo specifies a date in the past, or if it is empty or omitted, then the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.  PMCs are sequential numbers beginning at 1 and counting up.  This code checks the PMC to see that it contains only digits and is less than test_limit; the value in local variable test_limit will need to be updated periodically as more PMCs are issued. ]] function pmc(id, embargo) 	local test_limit = 12000000;							-- update this value as PMCs approach 	local handler = cfg.id_handlers['PMC']; 	local err_cat =  '';								-- presume that PMC is valid      	local text;  	if id:match("^PMC%d") then 		id = id:sub(4, j)								-- remove 'PMC' preffix if given 	end 	if id:match("[^%d]") then							-- if PMC has anything but digits 		err_cat = ' ' .. seterror( 'bad_pmc' );			-- set an error message 	else												-- PMC is only digits 		local id_num = tonumber(id);					-- convert id to a number for range testing 		if 1 > id_num or test_limit < id_num then		-- if PMC is outside test limit boundaries 			err_cat = ' ' .. seterror( 'bad_pmc' );		-- set an error message 		end 	end 	 	if is_embargoed(embargo) then 		text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id .. err_cat;	--still embargoed so no external link 	else 		text = externallinkid({link = handler.link, label = handler.label,			--no embargo date, ok to link to article 			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat; 	end 	return text; end  -- Formats a DOI and checks for DOI errors.  -- DOI names contain two parts: prefix and suffix separated by a forward slash. --  Prefix: directory indicator '10.' followed by a registrant code --  Suffix: character string of any length chosen by the registrant  -- This function checks a DOI name for: prefix/suffix.  If the doi name contains spaces or endashes, -- or, if it ends with a period or a comma, this function will emit a bad_doi error message.  -- DOI names are case-insensitive and can incorporate any printable Unicode characters so the test for spaces, endash, -- and terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely if ever used in doi names.  function doi(id, inactive)     local cat = ""     local handler = cfg.id_handlers['DOI'];          local text; 	if is_set(inactive) then 		local inactive_year = inactive:match("%d%d%d%d") or '';		-- try to get the year portion from the inactive date 		text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id; 		if is_set(inactive_year) then 			table.insert( z.error_categories, "Wikipedia:Páginas con DOI inactivos desde " .. inactive_year ); 		else 			table.insert( z.error_categories, "Wikipedia:Páginas con DOI inactivos" );	-- when inactive doesn't contain a recognizable year 		end 		inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"  	else  		text = externallinkid({link = handler.link, label = handler.label, 			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) 		inactive = ""  	end  	if nil == id:match("^10%.[^%s–]-/[^%s–]-[^%.,]$") then	-- doi must begin with '10.', must contain a fwd slash, must not contain spaces or endashes, and must not end with period or comma 		cat = ' ' .. seterror( 'bad_doi' ); 	end 	return text .. inactive .. cat  end  -- Formats an OpenLibrary link, and checks for associated errors. function openlibrary(id)     local code = id:sub(-1,-1)     local handler = cfg.id_handlers['OL'];     if ( code == "A" ) then         return externallinkid({link=handler.link, label=handler.label,             prefix="http://openlibrary.org/authors/OL",id=id, separator=handler.separator,             encode = handler.encode})     elseif ( code == "M" ) then         return externallinkid({link=handler.link, label=handler.label,             prefix="http://openlibrary.org/books/OL",id=id, separator=handler.separator,             encode = handler.encode})     elseif ( code == "W" ) then         return externallinkid({link=handler.link, label=handler.label,             prefix= "http://openlibrary.org/works/OL",id=id, separator=handler.separator,             encode = handler.encode})     else         return externallinkid({link=handler.link, label=handler.label,             prefix= "http://openlibrary.org/OL",id=id, separator=handler.separator,             encode = handler.encode}) ..              ' ' .. seterror( 'bad_ol' );     end end  --[[ Validate and format an issn.  This code fixes the case where an editor has included an ISSN in the citation but has separated the two groups of four digits with a space.  When that condition occurred, the resulting link looked like this:  	|issn=0819 4327 gives: [http://www.worldcat.org/issn/0819 4327 0819 4327]  -- can't have spaces in an external link 	 This code now prevents that by inserting a hyphen at the issn midpoint.  It also validates the issn for length and makes sure that the checkdigit agrees with the calculated value.  Incorrect length (8 digits), characters other than 0-9 and X, or checkdigit / calculated value mismatch will all cause a check issn error message.  The issn is always displayed with a hyphen, even if the issn was given as a single group of 8 digits. ]] function issn(id) 	local ModuloIdentificadores = require('Módulo:Identificadores')	 	local issn_copy = id;		-- save a copy of unadulterated issn; use this version for display if issn does not validate 	local handler = cfg.id_handlers['ISSN']; 	local text; 	local valid_issn = true;  	id=id:gsub( "[%s-–]", "" );									-- strip spaces, hyphens, and ndashes from the issn  	if 8 ~= id:len() or nil == id:match( "^%d*X?$" ) then		-- validate the issn: 8 didgits long, containing only 0-9 or X in the last position 		valid_issn=false;										-- wrong length or improper character 	else 		valid_issn=ModuloIdentificadores.esValidoISXN(id, 8);	-- validate issn 	end  	if true == valid_issn then 		id = string.sub( id, 1, 4 ) .. "-" .. string.sub( id, 5 );	-- if valid, display correctly formatted version 	else 		id = issn_copy;											-- if not valid, use the show the invalid issn with error message 	end 	 	text = externallinkid({link = handler.link, label = handler.label, 		prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})   	if false == valid_issn then 		text = text .. ' ' .. seterror( 'bad_issn' )			-- add an error message if the issn is invalid 	end  	 	return text end  --[[ This function sets default title types (equivalent to the citation including |type=<default value>) for those citations that have defaults. Also handles the special case where it is desireable to omit the title type from the rendered citation (|type=none). ]] function set_titletype(cite_class, title_type) 	if is_set(title_type) then 		if "none" == title_type then 			title_type = "";					-- if |type=none then type parameter not displayed 		end 		return title_type;						-- if |type= has been set to any other value use that value 	end  --	if "AV media notes" == cite_class or "DVD notes" == cite_class then		-- if this citation is cite AV media notes or cite DVD notes 	if "notas audiovisual" == cite_class or "notas de DVD" == cite_class then		-- if this citation is cite AV media notes or cite DVD notes		 		return "Media notes";					-- display AV media notes / DVD media notes annotation -- Falta traducir  	elseif "podcast" == cite_class then			-- if this citation is cite podcast 		return "Podcast";						-- display podcast annotation  	elseif "pressrelease" == cite_class then	-- if this citation is cite press release 		return "Press release";					-- display press release annotation  	elseif "techreport" == cite_class then		-- if this citation is cite techreport 		return "Technical report";				-- display techreport annotation 		 	elseif "tesis" == cite_class then			-- if this citation is cite thesis (degree option handled after this function returns) 			return "Tesis";			 			-- display simple thesis annotation (without |degree= modification)			 	end end  --[[ Determines whether a URL string is valid  At present the only check is whether the string appears to  be prefixed with a URI scheme.  It is not determined whether  the URI scheme is valid or whether the URL is otherwise well  formed. ]] function checkurl( url_str )     -- Protocol-relative or URL scheme     return url_str:sub(1,2) == "//" or url_str:match( "^[^/]*:" ) ~= nil; end  -- Removes irrelevant text and dashes from ISBN number -- Similar to that used for Special:BookSources function cleanisbn( isbn_str )     return isbn_str:gsub( "[^-0-9X]", "" ); end  -- Extract page numbers from external wikilinks in any of the |page=, |pages=, or |at= parameters for use in COinS. function get_coins_pages (pages) 	if not is_set (pages) then return pages; end			-- if no page numbers then we're done 	     while true do     	local urlPattern = "%[%w*:?//[^ ]+%s+([%w%d].*)%]" 		local urlMatch = pages:match(urlPattern); -- pattern is the opening bracket, the url and following space(s): "[url " 		if nil == urlMatch then break; end					-- no more urls 		pages = pages:gsub(urlPattern, "%1");					-- remove as many instances of pattern as possible 	end 	pages = pages:gsub("[%[%]]", "");						-- remove the brackets 	pages = pages:gsub("–", "-" );							-- replace endashes with hyphens 	pages = pages:gsub("&%w+;", "-" );						-- and replace html entities (&ndash; etc) with hyphens; do we need to replace numerical entities like &#32; and the like? 	return pages; end  -- Gets the display text for a wikilink like [[A|B]] or [[B]] gives B function removewikilink( str )     return (str:gsub( "%[%[([^%[%]]*)%]%]", function(l)         return l:gsub( "^[^|]*|(.*)$", "%1" ):gsub("^%s*(.-)%s*$", "%1");     end)); end  -- Escape sequences for content that will be used for URL descriptions function safeforurl( str )     if str:match( "%[%[.-%]%]" ) ~= nil then          table.insert( z.message_tail, { seterror( 'wikilink_in_url', {}, true ) } );     end          return str:gsub( '[%[%]\n]', {             ['['] = '&#91;',         [']'] = '&#93;',         ['\n'] = ' ' } ); end  -- Convierte un guión largo (signo de negativo) en un guión corto. function dashtohyphen( str )     if not is_set(str) or str:match( "[%[%]{}<>]" ) ~= nil then         return str;     end         return str:gsub( '–', '-' ); end  -- Protects a string that will be wrapped in wiki italic markup '' ... '' function safeforitalics( str )     --[[ Note: We can not use <i> for italics, as the expected behavior for     italics specified by ''...'' in the title is that they will be inverted     (i.e. unitalicized) in the resulting references.  In addition, <i> and ''     tend to interact poorly under Mediawiki's HTML tidy. ]]          if not is_set(str) then         return str;     else         if str:sub(1,1) == "'" then str = "<span></span>" .. str; end         if str:sub(-1,-1) == "'" then str = str .. "<span></span>"; end                  -- Remove newlines as they break italics.         return str:gsub( '\n', ' ' );     end end  --[[ Joins a sequence of strings together while checking for duplicate separation characters. ]] function safejoin( tbl, duplicate_char )     --[[     Note: we use string functions here, rather than ustring functions.          This has considerably faster performance and should work correctly as      long as the duplicate_char is strict ASCII.  The strings     in tbl may be ASCII or UTF8.     ]]          local str = '';     local comp = '';     local end_chr = '';     local trim;     for _, value in ipairs( tbl ) do         if value == nil then value = ''; end                  if str == '' then             str = value;         elseif value ~= '' then             if value:sub(1,1) == '<' then                 -- Special case of values enclosed in spans and other markup.                 comp = value:gsub( "%b<>", "" );             else                 comp = value;             end                          if comp:sub(1,1) == duplicate_char then                 trim = false;                 end_chr = str:sub(-1,-1);                 -- str = str .. "<HERE(enchr=" .. end_chr.. ")"                 if end_chr == duplicate_char then                     str = str:sub(1,-2);                 elseif end_chr == "'" then                     if str:sub(-3,-1) == duplicate_char .. "''" then                         str = str:sub(1, -4) .. "''";                     elseif str:sub(-5,-1) == duplicate_char .. "]]''" then                         trim = true;                     elseif str:sub(-4,-1) == duplicate_char .. "]''" then                         trim = true;                     end                 elseif end_chr == "]" then                     if str:sub(-3,-1) == duplicate_char .. "]]" then                         trim = true;                     elseif str:sub(-2,-1) == duplicate_char .. "]" then                         trim = true;                     end                 elseif end_chr == " " then                     if str:sub(-2,-1) == duplicate_char .. " " then                         str = str:sub(1,-3);                     end                 end                  if trim then                     if value ~= comp then                          local dup2 = duplicate_char;                         if dup2:match( "%A" ) then dup2 = "%" .. dup2; end                                                  value = value:gsub( "(%b<>)" .. dup2, "%1", 1 )                     else                         value = value:sub( 2, -1 );                     end                 end             end             str = str .. value;         end     end     return str; end    -- Attempts to convert names to initials. function reducetoinitials(first)     local initials = {}     for word in string.gmatch(first, "%S+") do         table.insert(initials, string.sub(word,1,1)) -- Vancouver format does not include full stops.     end     return table.concat(initials) -- Vancouver format does not include spaces. end  -- Formats a list of people (e.g. authors / editors)  function listpeople(control, people)     local sep = control.sep;     local namesep = control.namesep     local format = control.format     local maximum = control.maximum     local lastauthoramp = control.lastauthoramp;     local text = {}     local etal = false;          if sep:sub(-1,-1) ~= " " then sep = sep .. " " end     if maximum ~= nil and maximum < 1 then return "", 0; end          for i,person in ipairs(people) do         if is_set(person.last) then             local mask = person.mask             local one             local sep_one = sep;             if maximum ~= nil and i > maximum then                 etal = true;                 break;             elseif (mask ~= nil) then                 local n = tonumber(mask)                 if (n ~= nil) then                     one = string.rep("&mdash;",n)                 else                     one = mask;                     sep_one = " ";                 end             else                 one = person.last                 local first = person.first                 if is_set(first) then                      if ( "vanc" == format ) then first = reducetoinitials(first) end                     one = one .. namesep .. first                  end                 if is_set(person.link) then one = "[[" .. person.link .. "|" .. one .. "]]" end                 if is_set(person.link) and nil ~= person.link:find("//") then one = one .. " " .. seterror( 'bad_authorlink' ) end	-- check for url in author link;             end             table.insert( text, one )             table.insert( text, sep_one )         end     end      local count = #text / 2;     if count > 0 then          if count > 1 and is_set(lastauthoramp) and not etal then             text[#text-2] = " & ";         end         text[#text] = nil;      end          local result = table.concat(text) -- construct list     if etal then          local etal_text = cfg.messages['et al'];         result = result .. " " .. etal_text;     end          -- if necessary wrap result in <span> tag to format in Small Caps     if ( "scap" == format ) then result =          '<span class="smallcaps" style="font-variant:small-caps">' .. result .. '</span>';     end      return result, count end  -- Generates a CITEREF anchor ID. function anchorid( options )     return "CITAREF" .. table.concat( options ); --return "CITEREF" .. table.concat( options ); end  -- Gets name list from the input arguments function extractnames(args, list_name)     local names = {};     local i = 1;     local last;          while true do         last = selectone( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i );         if not is_set(last) then             -- just in case someone passed in an empty parameter             break;         end         names[i] = {             last = last,             first = selectone( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i ),             link = selectone( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ),             mask = selectone( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i )         };         i = i + 1;     end     return names; end  -- Populates ID table from arguments using configuration settings function extractids( args )     local id_list = {};     for k, v in pairs( cfg.id_handlers ) do             v = selectone( args, v.parameters, 'redundant_parameters' );         if is_set(v) then id_list[k] = v; end     end     return id_list; end  -- Takes a table of IDs and turns it into a table of formatted ID outputs. function buildidlist( id_list, options )     local new_list, handler = {};          function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end;          for k, v in pairs( id_list ) do         -- fallback to read-only cfg         handler = setmetatable( { ['id'] = v }, fallback(k) );                  if handler.mode == 'external' then             table.insert( new_list, {handler.label, externallinkid( handler ) } );         elseif handler.mode == 'internal' then             table.insert( new_list, {handler.label, internallinkid( handler ) } );         elseif handler.mode ~= 'manual' then             error( cfg.messages['unknown_ID_mode'] );         elseif k == 'DOI' then             table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );         elseif k == 'LCCN' then             table.insert( new_list, {handler.label, lccn( v ) } );         elseif k == 'OL' then             table.insert( new_list, {handler.label, openlibrary( v ) } );         elseif k == 'PMC' then             table.insert( new_list, {handler.label, pmc( v, options.Embargo ) } );         elseif k == 'PMID' then             table.insert( new_list, {handler.label, pmid( v ) } );         elseif k == 'ISSN' then         	table.insert( new_list, {handler.label, issn( v:upper() ) } );         elseif k == 'ISBN' then             --local ISBN = internallinkid( handler );             --if not checkisbn( v ) and not is_set(options.IgnoreISBN) then             --    ISBN = ISBN .. seterror( 'bad_isbn', {}, false, " ", "" );             --end        	         	local ISBN         	if options.ISBNCorrecto or options.ISBNSugerido or is_set(options.IgnoreISBN) then         		ISBN = internallinkid( handler );         	else -- ISBN incorrecto.       			ISBN = internallinkid( handler ) .. seterror( 'bad_isbn', {}, false, " ", "" );         	end              table.insert( new_list, {handler.label, ISBN } );                         else             error( cfg.messages['unknown_manual_ID'] );         end     end          function comp( a, b )	-- used in following table.sort()         return a[1] < b[1];     end          table.sort( new_list, comp );     for k, v in ipairs( new_list ) do         new_list[k] = v[2];     end          return new_list; end  function CorregirISBN(ISBNIncorrecto) 	local ModuloIdentificadores = require('Módulo:Identificadores')	 	local ISBNCorregido 	 --  Convertir mayúsculas	 	ISBNCorregido = ISBNIncorrecto:upper()  --  Corregir guiones 	ISBNCorregido = ISBNCorregido:gsub("%–","-"); 	 --  Eliminar ISBN del principio     ISBNCorregido =ISBNCorregido:match("ISBN (.*)") or ISBNCorregido; 	 --  Eliminar separadores como "." y "," del final 	ISBNCorregido = ISBNCorregido:gsub("[%.,]","");  	if ModuloIdentificadores.esValidoISBN(ISBNCorregido) then  		return ISBNCorregido 	end	  --  Ver si se trata de un ISBN de 13	 	local ISBNCorregidoSin978 	ISBNCorregidoSin978 = ISBNCorregido:match("^978[%s-]*(.*)") 	if ISBNCorregidoSin978 and ModuloIdentificadores.esValidoISBN(ISBNCorregidoSin978) then --  	"978" + ISBN10 		return ISBNCorregidoSin978 	end 	 --	ISBN de 13 al que se ha quitado 978	 	if ModuloIdentificadores.esValidoISBN('978'..ISBNCorregido) then  		if ISBNCorregido:match('-') then  			return '978-' .. ISBNCorregido 		elseif ISBNCorregido:match(' ') then  			return '978 ' .. ISBNCorregido 		else 			return '978' .. ISBNCorregido 		end 	end 	 --  13 ISBN o 13: ISBN 	local ISBNCorregidoSi13 	ISBNCorregidoSin13 = ISBNCorregido:match("^13:?[%s]+(.*)") 	if ISBNCorregidoSin13 and ModuloIdentificadores.esValidoISBN(ISBNCorregidoSin13) then  		return ISBNCorregidoSin13 	end end  function CorregirISBNs(ISBNIncorrecto1, ISBNIncorrecto2) -- Tomar aquel de los dos ISBNs correctos si uno de ellos es un ISBN10 y el -- otro el correspondiente ISBN13  	local ISBN1Corregido = CorregirISBN(ISBNIncorrecto1) 	local ISBN2Corregido = CorregirISBN(ISBNIncorrecto2) 	 	if ISBN1Corregido and ISBN2Corregido then --  	Ambos son correctos. 		if ISBN1Corregido == ISBN2Corregido then --			Ambos son iguales (tras corregirse) 			return ISBN1Corregido 		end  --		Ver si uno de ellos es un ISBN10 y el otro un ISBN13	 		local ISBNSinDigitoControl 		ISBNSinDigitoControl = ISBN1Corregido:match("(.*).") 		if ISBNSinDigitoControl and ISBN2Corregido:match("978[%s-]*" .. ISBNSinDigitoControl) then 			return ISBN2Corregido 		end 		 		ISBNSinDigitoControl = ISBN2Corregido:match("(.*).") 		if ISBNSinDigitoControl and ISBN1Corregido:match("978[%s-]*" .. ISBNSinDigitoControl) then 			return ISBN1Corregido 		end		 		 	elseif ISBN1Corregido then 		return ISBN1Corregido 	elseif ISBN2Corregido then 		return ISBN1Corregido 	end end  function SugerirISBN(ISBNIncorrecto) 	local ISBNSugerido  --  Ejemplos:  --      0 88254 165 x 					--> 0 88254 165 X --      0-7153-5734-4.  				--> 0-7153-5734-4 --      0–313–31807–7 					--> 0-313-31807-7 --		ISBN(13): 9788495379092  --  	978-0-7432-9302-0 y 0-7432-9302-0 --		9788430948949 8430948945  --		8496702057 9788496702059 --		0198152213, 978019815221 --		13 978-0-511-41399-5  --		13: 9788432238406  --  ISBN con caracteres incorrectos. 	ISBNSugerido=CorregirISBN(ISBNIncorrecto) 	if ISBNSugerido then  		return ISBNSugerido 	end 	 --  ISBN10, ISBN13 o ISBN13, ISBN10 	local ISBN1, ISBN2 	ISBN1, ISBN2 = ISBNIncorrecto:match("(.*),%s*(.*)") 	if is_set(ISBN1) and is_set(ISBN2) then 		ISBNSugerido = 	CorregirISBNs(ISBN1, ISBN2) 		 		if ISBNSugerido then 			return ISBNSugerido 		end  	end  --  ISBN10 y ISBN13 o ISBN13 y ISBN10 	ISBN1, ISBN2 = ISBNIncorrecto:match("(.*)%s+y%s+(.*)") 	if is_set(ISBN1) and is_set(ISBN2) then 		ISBNSugerido = 	CorregirISBNs(ISBN1, ISBN2) 		 		if ISBNSugerido then 			return ISBNSugerido 		end  	end  --  ISBN10 ISBN13 o ISBN13 ISBN10 	ISBN1, ISBN2 = ISBNIncorrecto:match("(.*)%s+(.*)") 	if is_set(ISBN1) and is_set(ISBN2) then 		ISBNSugerido = 	CorregirISBNs(ISBN1, ISBN2) 		 		if ISBNSugerido then 			return ISBNSugerido 		end  	end	 end    -- Chooses one matching parameter from a list of parameters to consider -- Generates an error if more than one match is present. function selectone( args, possible, error_condition, index )     local value = nil;     local selected = '';     local error_list = {};          if index ~= nil then index = tostring(index); end          -- Handle special case of "#" replaced by empty string     if index == '1' then         for _, v in ipairs( possible ) do             v = v:gsub( "#", "" );             if is_set(args[v]) then                 if value ~= nil and selected ~= v then                     table.insert( error_list, v );                 else                     value = args[v];                     selected = v;                 end             end         end             end          for _, v in ipairs( possible ) do         if index ~= nil then             v = v:gsub( "#", index );         end         if is_set(args[v]) then             if value ~= nil and selected ~=  v then                 table.insert( error_list, v );             else                 value = args[v];                 selected = v;             end         end     end          if #error_list > 0 then         local error_str = "";         for _, k in ipairs( error_list ) do             if error_str ~= "" then error_str = error_str .. cfg.messages['parameter-separator'] end             error_str = error_str .. wrap( 'parameter', k );         end         if #error_list > 1 then             error_str = error_str .. cfg.messages['parameter-final-separator'];         else             error_str = error_str .. cfg.messages['parameter-pair-separator'];         end         error_str = error_str .. wrap( 'parameter', selected );         table.insert( z.message_tail, { seterror( error_condition, {error_str}, true ) } );     end          return value, selected; end  -- COinS metadata (see <http://ocoins.info/>) allows automated tools to parse -- the citation information. function COinS(data)     if 'table' ~= type(data) or nil == next(data) then         return '';     end          local ctx_ver = "Z39.88-2004";          -- treat table strictly as an array with only set values.     local OCinSoutput = setmetatable( {}, {         __newindex = function(self, key, value)             if is_set(value) then                 rawset( self, #self+1, table.concat{ key, '=', mw.uri.encode( removewikilink( value ) ) } );             end         end     });          if is_set(data.Chapter) then         OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book";         OCinSoutput["rft.genre"] = "bookitem";         OCinSoutput["rft.btitle"] = data.Chapter;         OCinSoutput["rft.atitle"] = data.Title;     elseif is_set(data.Periodical) then         OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";         OCinSoutput["rft.genre"] = "article";         OCinSoutput["rft.jtitle"] = data.Periodical;         OCinSoutput["rft.atitle"] = data.Title;     else         OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book";         OCinSoutput["rft.genre"] = "book"         OCinSoutput["rft.btitle"] = data.Title;     end          OCinSoutput["rft.place"] = data.PublicationPlace;     OCinSoutput["rft.date"] = data.Date;     OCinSoutput["rft.series"] = data.Series;     OCinSoutput["rft.volume"] = data.Volume;     OCinSoutput["rft.issue"] = data.Issue;     OCinSoutput["rft.pages"] = data.Pages;     OCinSoutput["rft.edition"] = data.Edition;     OCinSoutput["rft.pub"] = data.PublisherName;          for k, v in pairs( data.ID_list ) do         local id, value = cfg.id_handlers[k].COinS;         if k == 'ISBN' then value = cleanisbn( v ); else value = v; end         if string.sub( id or "", 1, 4 ) == 'info' then             OCinSoutput["rft_id"] = table.concat{ id, "/", v };         else             OCinSoutput[ id ] = value;         end     end          local last, first;     for k, v in ipairs( data.Authors ) do         last, first = v.last, v.first;         if k == 1 then             if is_set(last) then                 OCinSoutput["rft.aulast"] = last;             end             if is_set(first) then                  OCinSoutput["rft.aufirst"] = first;             end         end         if is_set(last) and is_set(first) then             OCinSoutput["rft.au"] = table.concat{ last, ", ", first };         elseif is_set(last) then             OCinSoutput["rft.au"] = last;         end     end          OCinSoutput.rft_id = data.URL;     OCinSoutput.rfr_id = table.concat{ "info:sid/", mw.site.server:match( "[^/]*$" ), ":", data.RawPage };     OCinSoutput = setmetatable( OCinSoutput, nil );          -- sort with version string always first, and combine.     table.sort( OCinSoutput );     table.insert( OCinSoutput, 1, "ctx_ver=" .. ctx_ver );  -- such as "Z39.88-2004"     return table.concat(OCinSoutput, "&"); end  --[[ This is the main function doing the majority of the citation formatting. ]] function citation0( config, args) 	local ModuloIdentificadores = require('Módulo:Identificadores')	     --[[      Load Input Parameters     The argment_wrapper facillitates the mapping of multiple     aliases to single internal variable.     ]]     local A = argument_wrapper( args );      local i      local PPrefix = A['PPrefix']     local PPPrefix = A['PPPrefix']     if is_set( A['NoPP'] ) then PPPrefix = "" PPrefix = "" end          -- Pick out the relevant fields from the arguments.  Different citation templates     -- define different field names for the same underlying things.         local Authors = A['Authors'];     local a = extractnames( args, 'AuthorList' );      local Coauthors = A['Coauthors'];          local Editors = A['Editors'];     local e = extractnames( args, 'EditorList' );      local Year = A['Year'];     local wYear=Year;     local PublicationDate = A['PublicationDate'];     local OrigYear = A['OrigYear'];     local Date = A['Date'];     local wfecha = Date;     local LayDate = A['LayDate'];     ------------------------------------------------- Get title data     local Title = A['Title'];     local BookTitle = A['BookTitle'];     local Conference = A['Conference'];     local TransTitle = A['TransTitle'];     local TitleNote = A['TitleNote'];     local TitleLink = A['TitleLink'];     local Chapter = A['Chapter'];     local ChapterLink = A['ChapterLink'];     local TransChapter = A['TransChapter'];     local TitleType = A['TitleType'];     local Degree = A['Degree'];     local Docket = A['Docket'];     local ArchiveURL = A['ArchiveURL'];     local URL = A['URL']     local URLorigin = A:ORIGIN('URL');     local ChapterURL = A['ChapterURL'];     local ChapterURLorigin = A:ORIGIN('ChapterURL');     local ConferenceURL = A['ConferenceURL'];     local ConferenceURLorigin = A:ORIGIN('ConferenceURL');     local SinURL     = false;     local Periodical = A['Periodical'];  	local Series = A['Series'];     local Volume = A['Volume'];     local Issue = A['Issue'];     local Position = '';     local Page = A['Page'];     local Pages = dashtohyphen( A['Pages'] );	     local At = A['At'];     local Others = A['Others'];     local Edition = A['Edition'];     local PublicationPlace = A['PublicationPlace']     local Place = A['Place'];     local Passage = A['Passage'];     local PassageURL = A['PassageURL'];          local PublisherName = A['PublisherName'];     local UrlAccess = A['UrlAccess'];     local RegistrationRequired = A['RegistrationRequired'];     local SubscriptionRequired = A['SubscriptionRequired'];     local Via = A['Via'];     local AccessDate = A['AccessDate'];     local MesAcceso  = A['MesAcceso']; -- Inexistente en la plantilla original     local AnyoAcceso  = A['AñoAcceso']; -- Inexistente en la plantilla original     local ArchiveDate = A['ArchiveDate'];     local Agency = A['Agency'];     local DeadURL = A['DeadURL']     local Language = A['Language'];     local Format = A['Format'];     local Ref = A['Ref']; 	local DoiBroken = A['DoiBroken']; 	local ID = A['ID'];     local IgnoreISBN = A['IgnoreISBN'];     local Embargo = A['Embargo'];     local Texto1  = A['Texto1']     local ID_list = extractids( args );     local ISBNCorrecto = false;     local ISBNSugerido;      if is_set (ID_list['ISBN']) and not is_set (IgnoreISBN)  then     	if ModuloIdentificadores.esValidoISBN(ID_list['ISBN']) then      		ISBNCorrecto= true     	else     		ISBNSugerido = SugerirISBN(ID_list['ISBN'])     		if ISBNSugerido then     			ID_list['ISBN'] = ISBNSugerido     		end     	end     end     local Lista_Identificadores_Formateados={} -- Lista de identificadores con enlaces y en su caso con  los errores          local Quote = A['Quote'];     local TransQuote = A['TransQuote']; 	local PostScript = A['PostScript'];      local LayURL = A['LayURL'];     local LaySource = A['LaySource'];     local Transcript = A['Transcript'];     local TranscriptURL = A['TranscriptURL']      local TranscriptURLorigin = A:ORIGIN('TranscriptURL');     local sepc = A['Separator'];      local LastAuthorAmp = A['LastAuthorAmp'];     local no_tracking_cats = A['NoTracking'];  --these are used by cite interview 	local Callsign = A['Callsign']; 	local City = A['City']; 	local Cointerviewers = A['Cointerviewers'];			-- deprecated 	local Interviewer = A['Interviewer'];				-- deprecated 	local Program = A['Program'];  --Parámetros que no se utilizan en la plantilla inglesa 	local SinEd = A['SinEd'] 	local Extra = A['Extra'] 	local Traductor   = A['Traductor'] 	local Traductores = A['Traductores']  --local variables that are not cs1 parameters     local page_type;									-- is this needed?  Doesn't appear to be used anywhere;     local use_lowercase     local this_page = mw.title.getCurrentTitle();		--Also used for COinS and for language --	local anchor_year;									-- used in the CITEREF identifier 	local COinS_date;									-- used in the COinS metadata  --check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories. 	if not is_set(no_tracking_cats) then				-- ignore if we are already not going to categorize this page 		for k, v in pairs( cfg.uncategorized_namespaces ) do	-- otherwise, spin through the list of namespaces we don't include in error categories 			if this_page.nsText == v then				-- if we find one 				no_tracking_cats = "true";				-- set no_trackin_cats 				break;									-- and we're done             end         end     end  -- check for extra |page=, |pages= or |at= parameters.      if is_set(Page) then --      La categoría de la plantilla inglesa es intraducible. Utilizo otro error similar.          --if is_set(Pages) or is_set(At) then         --    Page = Page .. " " .. seterror('extra_pages');	-- add error message         --    Pages = '';										-- unset the others         --    At = '';         --end         if is_set(Pages) then             Page = Page .. " " .. seterror('redundant_parameters', '<code>&#124;página=</code> y <code>&#124;páginas=</code>');             Pages = '';										-- unset the others             At = '';         	Passage = '';         elseif is_set(At) then             Page = Page .. " " .. seterror('redundant_parameters', '<code>&#124;página=</code> y <code>&#124;en=</code>');             Pages = '';										-- unset the others             At = '';         	Passage = '';         elseif is_set(Passage) then             Page = Page .. " " .. seterror('redundant_parameters', '<code>&#124;página=</code> y <code>&#124;pasaje=</code>');             Pages = '';										-- unset the others             At = '';         	Passage = '';         end     elseif is_set(Pages) then         if is_set(At) then             -- Pages = Pages .. " " .. seterror('extra_pages');	-- add error messages             Pages = Pages .. " " .. seterror('redundant_parameters', '<code>&#124;páginas=</code> y <code>&#124;en=</code>');             At = '';         	Passage = '';         elseif is_set(Passage) then             Pages = Pages .. " " .. seterror('redundant_parameters', '<code>&#124;páginas=</code> y <code>&#124;pasaje=</code>');             At = '';         	Passage = '';         end     elseif is_set(At) then     	if is_set(Passage) then             At = At .. " " .. seterror('redundant_parameters', '<code>&#124;en=</code> y <code>&#124;pasaje=</code>');         	Passage = '';         end     end  -- both |publication-place= and |place= (|location=) allowed if different     if not is_set(PublicationPlace) and is_set(Place) then         PublicationPlace = Place;							-- promote |place= (|location=) to |publication-place     end          if PublicationPlace == Place then Place = ''; end		-- don't need both if they are the same      --[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: 	|encyclopedia and |title then map |title to |article and |encyclopedia to |title 	|encyclopedia and |article then map |encyclopedia to |title 	|encyclopedia then map |encyclopedia to |title  	|trans_title maps to |trans_chapter when |title is re-mapped  All other combinations of |encyclopedia, |title, and |article are not modified ]] --	if ( config.ClaseCita == "encyclopaedia" ) then 	if ( config.ClaseCita == "enciclopedia" ) then		 		if is_set(Periodical) then					-- Periodical is set when |encyclopedia is set 			if is_set(Title) then 				if not is_set(Chapter) then 					Chapter = Title;				-- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title 					TransChapter = TransTitle; 					Title = Periodical; 					Periodical = '';				-- redundant so unset 					TransTitle = '';				-- redundant so unset 				end 			else									-- |title not set 				Title = Periodical;					-- |encyclopedia set and |article set or not set so map |encyclopedia to |title 				Periodical = '';					-- redundant so unset 			end 		end 	end  --special cases for classic book 	if config.ClaseCita == 'libro' and is_set(Passage) then 		if is_set(PassageURL) then 			Passage = externallink( PassageURL, Passage ) 		end 		if not is_set (sepc) then 			sepc = ' '; 		end 	else 		Passage = '' 	end  --special cases for citation. 	if (config.ClaseCita == "citation") then		-- for citation templates 		if not is_set (sepc) then						-- if |separator= is not set 			sepc = ',';									-- set citation separator to its default (comma) 		end 	else												-- not a citation template 		if not is_set (sepc) then						-- if |separator= has not been set 			sepc = '.';									-- set cite xxx separator to its default (period) 		end 	end  	if not is_set (Ref) then						-- if |ref= is not set 		-- if inArray(config.ClaseCita, {"citation", "libro", "publicación", "web"}) then		-- for citation templates -- En la Wikipedia inglesa solo se usan citas Harvard para la clase citation	 -- Quedan habilitadas las citas Harvard para cualquier clase que contenga algún autor o editor 		if  #a > 0 or #e > 0 then 			Ref = "harv";								-- set default |ref=harv 		end 	end	  -- check for specital case where |separator=none 	if 'none' == sepc:lower() then						-- if |separator=none 		sepc = '';										-- then set it to a empty string 	end 	 	use_lowercase = ( sepc ~= '.' ); 	     Others = is_set(Others) and (sepc .. " " .. Others) or "";	  -- Special case for cite techreport. 	if (config.ClaseCita == "techreport") then	-- special case for cite techreport 		if is_set(Issue) then						-- cite techreport uses 'number', which other citations aliase to 'issue' 			if not is_set(ID) then					-- can we use ID for the "number"? 				ID = Issue;							-- yes, use it 				Issue = "";							-- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadata 			else									-- can't use ID so emit error message 				ID = ID .. " " .. seterror('redundant_parameters', '<code>&#124;id=</code> and <code>&#124;number=</code>'); 			end 		end	 -- special case for cite interview 	elseif (config.ClaseCita == "entrevista") then 		if is_set(Program) then 			ID = ' ' .. Program; 		end 		if is_set(Callsign) then 			if is_set(ID) then 				ID = ID .. sepc .. ' ' .. Callsign; 			else 				ID = ' ' .. Callsign; 			end 		end 		if is_set(City) then 			if is_set(ID) then 				ID = ID .. sepc .. ' ' .. City; 			else 				ID = ' ' .. City; 			end 		end  		if is_set(Interviewer) then 			if is_set(TitleType) then 				Others = sepc .. ' ' .. TitleType .. ' con ' .. Interviewer  -- ' ' .. TitleType .. ' con ' .. Interviewer; 				TitleType = ''; 			else 				Others = sepc .. ' ' .. wrap('interview', Interviewer, use_lowercase) .. Others  -- ' ' .. 'Entrevista con ' .. Interviewer; 			end 			if is_set(Cointerviewers) then 				Others = Others .. sepc .. ' ' .. Cointerviewers; 			end 		else 			Others = Others .. sepc .. ' (Entrevista)' --'(Interview)'; 		end 	elseif is_set(ID) then 	   ID = wrap( 'id', ID) 	end  --Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set --	if config.ClaseCita == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then 	if config.ClaseCita == "publicación" and not is_set(URL) and is_set(ID_list['PMC']) then 		if not is_embargoed(Embargo) then 			URL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC'];	-- set url to be the same as the PMC external link if not embargoed 			URLorigin = cfg.id_handlers['PMC'].parameters[1];		-- set URLorigin to parameter name for use in error message if citation is missing a |title= 		end 	end      if is_set(Texto1) and Texto1:match("%S+") then         -- Informar la URL con el valor del campo 1 en su caso    	     	if config.ClaseCita == "web" and not is_set(URL) and checkurl(Texto1) then        	    table.insert( z.message_tail, { seterror( 'url_sugerida', {Texto1, 'url'}, true ) } )     	    --URL    = Texto1   Utilizar URL como texto.     	else     		table.insert( z.message_tail, { seterror( 'text_ignored', {Texto1}, true ) } )     	end     end 	 -- Account for the oddity that is {{cite conference}}, before generation of COinS data. --TODO: if this is only for {{cite conference}}, shouldn't we be checking? (if config.ClaseCita=='conference' then ...)      	if 'conferencia' == config.ClaseCita then 		if is_set(BookTitle) then 			Chapter = Title; --			ChapterLink = TitleLink;											-- |chapterlink= is deprecated 			ChapterURL = URL; 			ChapterUrlAccess = UrlAccess; 			ChapterURLorigin = URLorigin; 			URLorigin = ''; 			ChapterFormat = Format; 			TransChapter = TransTitle; 			Title = BookTitle; 			Format = ''; --			TitleLink = ''; 			TransTitle = ''; 			URL = ''; 		end 	elseif 'speech' ~= config.ClaseCita then 		Conference = '';														-- not cite conference or cite speech so make sure this is empty string 	end 	 -- Account for the oddity that is {{cite episode}}, before generation of COinS data. --[[	-- {{cite episode}} is not currently supported by this module 	if config.ClaseCita == "episode" then 		local AirDate = A['AirDate']; 		local SeriesLink = A['SeriesLink']; 		local Season = A['Season']; 		local SeriesNumber = A['SeriesNumber']; 		local Network = A['Network']; 		local Station = A['Station']; 		local s, n = {}, {}; 		local Sep = (first_set(A["SeriesSeparator"], A["Separator"]) or "") .. " "; 		 		if is_set(Issue) then table.insert(s, cfg.messages["episode"] .. " " .. Issue); Issue = ''; end 		if is_set(Season) then table.insert(s, cfg.messages["season"] .. " " .. Season); end 		if is_set(SeriesNumber) then table.insert(s, cfg.messages["series"] .. " " .. SeriesNumber); end 		if is_set(Network) then table.insert(n, Network); end 		if is_set(Station) then table.insert(n, Station); end 		 		Date = Date or AirDate; 		Chapter = Title; 		ChapterLink = TitleLink; 		TransChapter = TransTitle; 		Title = Series; 		TitleLink = SeriesLink; 		TransTitle = ''; 		 		Series = table.concat(s, Sep); 		ID = table.concat(n, Sep); 	end -- end of {{cite episode}} stuff]]  -- legacy: promote concatenation of |day=, |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set. 	if not is_set(Date) then 		Date = Year;						-- promote Year to Date 		Year = nil;							-- make nil so Year as empty string isn't used for CITEREF 		if is_set(Date) then 			local Month = A['Month']; 			if is_set(Month) then 				Date = Month .. " de " .. Date; --Month .. " " .. Date; 				local Day = A['Day'] 				if is_set(Day) then Date = Day .. " de " .. Date end --if is_set(Day) then Date = Day .. " " .. Date end 			end 		elseif is_set(PublicationDate) then	-- use PublicationDate when |date= and |year= are not set 			Date = PublicationDate;			-- promonte PublicationDate to Date 			PublicationDate = '';			-- unset, no longer needed 		end 	end  	if PublicationDate == Date then PublicationDate = ''; end	-- if PublicationDate is same as Date, don't display in rendered citation   --[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata.  Date validation supporting code is in Módulo:Citas/ValidaciónFechas ]]  --[[ 	anchor_year, COinS_date, error_message = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken, 		['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year}); 	if is_set(error_message) then 		table.insert( z.message_tail, { seterror( 'bad_date', {error_message}, true ) } );	-- add this error message 	end ]] -- At this point fields may be nil if they weren't specified in the template use.  We can use that fact.      -- COinS metadata (see <http://ocoins.info/>) for     -- automated parsing of citation information.     local OCinSoutput = COinS{         ['Periodical'] = Periodical,         ['Chapter'] = Chapter,         ['Title'] = Title,         ['PublicationPlace'] = PublicationPlace,         ['Date'] = first_set(COinS_date, Date),		-- COinS_date has correctly formatted date if Date is valid; any reason to keep Date here?  Should we be including invalid dates in metadata?         ['Series'] = Series,         ['Volume'] = Volume,         ['Issue'] = Issue,         ['Pages'] = get_coins_pages (first_set(Page, Pages, At)),	-- pages stripped of external links         ['Edition'] = Edition,         ['PublisherName'] = PublisherName,         ['URL'] = first_set( URL, ChapterURL ),         ['Authors'] = a,         ['ID_list'] = ID_list,         ['RawPage'] = this_page.prefixedText,     };      if is_set(Periodical) and not is_set(Chapter) and is_set(Title) then         Chapter = Title;         ChapterLink = TitleLink;         TransChapter = TransTitle;         Title = '';         TitleLink = '';         TransTitle = '';     end      -- Now perform various field substitutions.     -- We also add leading spaces and surrounding markup and punctuation to the     -- various parts of the citation, but only when they are non-nil.     if not is_set(Authors) then         local Maximum = tonumber( A['DisplayAuthors'] );                  -- Preserve old-style implicit et al.         if not is_set(Maximum) and #a == 9 then              Maximum = 8;             table.insert( z.message_tail, { seterror('implict_etal_author', {}, true ) } );         elseif not is_set(Maximum) then             Maximum = #a + 1;         end                      local control = {              sep = A["AuthorSeparator"] .. " ",             namesep = (first_set(A["AuthorNameSeparator"], A["NameSeparator"]) or "") .. " ",             format = A["AuthorFormat"],             maximum = Maximum,             lastauthoramp = LastAuthorAmp         };                  -- If the coauthor field is also used, prevent ampersand and et al. formatting.         if is_set(Coauthors) then             control.lastauthoramp = nil;             control.maximum = #a + 1;         end                  Authors = listpeople(control, a)      end  	if not is_set(Authors) and is_set(Coauthors) then	-- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified 		table.insert( z.message_tail, { seterror('coauthors_missing_author', {}, true) } );	-- emit error message 		 		-- Utilizo temporalmente los coautores como autores. 		Authors = Coauthors 		Coauthors = nil 	end      local EditorCount     if not is_set(Editors) then         local Maximum = tonumber( A['DisplayEditors'] );         -- Preserve old-style implicit et al.         if not is_set(Maximum) and #e == 4 then              Maximum = 3;             table.insert( z.message_tail, { seterror('implict_etal_editor', {}, true) } );         elseif not is_set(Maximum) then             Maximum = #e + 1;         end          local control = {              sep = A["EditorSeparator"] .. " ",             namesep = (first_set(A["EditorNameSeparator"], A["NameSeparator"]) or "") .. " ",             format = A['EditorFormat'],             maximum = Maximum,             lastauthoramp = LastAuthorAmp         };          Editors, EditorCount = listpeople(control, e);     else         EditorCount = 1;     end      local Cartography = "";     local Scale = "";     if config.ClaseCita == "map" then         if not is_set( Authors ) and is_set( PublisherName ) then             Authors = PublisherName;             PublisherName = "";         end         Cartography = A['Cartography'];         if is_set( Cartography ) then             Cartography = sepc .. " " .. wrap( 'cartography', Cartography, use_lowercase );         end                 Scale = A['Scale'];         if is_set( Scale ) then             Scale = sepc .. " " .. Scale;         end             end          if  not is_set(URL) and         not is_set(ChapterURL) and         not is_set(ArchiveURL) and         not is_set(ConferenceURL) and         not is_set(TranscriptURL) then                  sinURL = true                  -- Test if cite web or cite podcast |url= is missing or empty  		if inArray(config.ClaseCita, {"web","podcast"}) then	 			table.insert( z.message_tail, { seterror( 'cite_web_url', {}, true ) } ); 		end                  -- Test if format is given without giving a URL         if is_set(Format) then             Format = Format .. seterror( 'format_missing_url' );         end     end          -- Test if citation has no title     if  not is_set(Chapter) and         not is_set(Title) and         not is_set(Periodical) and         not is_set(Conference) and         not is_set(TransTitle) and         not is_set(TransChapter) and         not is_set(Passage) then         table.insert( z.message_tail, { seterror( 'citation_missing_title', {}, true ) } );     end          Format = is_set(Format) and " " .. wrap( 'format', Format ) or ""; --is_set(Format) and " (" .. Format .. ")" or "";          local OriginalURL = URL     DeadURL = DeadURL:lower();     if is_set( ArchiveURL ) then         if ( DeadURL ~= "no" ) then             URL = ArchiveURL             URLorigin = A:ORIGIN('ArchiveURL')         end     end          -- Format chapter / article title     if is_set(Chapter) and is_set(ChapterLink) then          Chapter = "[[" .. ChapterLink .. "|" .. Chapter .. "]]";     end     if is_set(Periodical) and is_set(Title) then         Chapter = wrap( 'italic-title', Chapter );         TransChapter = wrap( 'trans-italic-title', TransChapter );     else 		Chapter = kern_quotes (Chapter);				-- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks         Chapter = wrap( 'quoted-title', Chapter );         TransChapter = wrap( 'trans-quoted-title', TransChapter );     end          local TransError = ""     if is_set(TransChapter) then         if not is_set(Chapter) then             TransError = " " .. seterror( 'trans_missing_chapter' );         else             TransChapter = " " .. TransChapter;         end     end          Chapter = Chapter .. TransChapter;          if is_set(Chapter) then         if not is_set(ChapterLink) then             if is_set(ChapterURL) then                 Chapter = externallink( ChapterURL, Chapter ) .. TransError;                 if not is_set(URL) then                     Chapter = Chapter .. Format;                     Format = "";                 end             elseif is_set(URL) then                  Chapter = externallink( URL, Chapter ) .. TransError .. Format;                 URL = "";                 Format = "";             else                 Chapter = Chapter .. TransError;             end                     elseif is_set(ChapterURL) then             Chapter = Chapter .. " " .. externallink( ChapterURL, nil, ChapterURLorigin ) ..                  TransError;         else             Chapter = Chapter .. TransError;         end         Chapter = Chapter .. sepc .. " " -- with end-space     elseif is_set(ChapterURL) then         Chapter = " " .. externallink( ChapterURL, nil, ChapterURLorigin ) .. sepc .. " ";     end                  -- Format main title.     if is_set(TitleLink) and is_set(Title) then         Title = "[[" .. TitleLink .. "|" .. Title .. "]]"     end          if is_set(Traductor) and is_set(Traductores) then     	Traductor = " " .. wrap( 'traductores', Traductores) .. " " .. seterror('redundant_parameters', '<code>&#124;traductor=</code> y <code>&#124;traductores=</code>')     elseif is_set(Traductor) then     	Traductor = " " .. wrap( 'traductor', Traductor)     elseif is_set(Traductores) then     	Traductor = " " .. wrap( 'traductores', Traductores)     end          Traductores = ''          if is_set(Periodical) then 		Title = kern_quotes (Title);				-- if necessary, separate title's leading and trailing quote marks from Module provided quote marks         Title = wrap( 'quoted-title', Title );         TransTitle = wrap( 'trans-quoted-title', TransTitle ); --  elseif inArray(config.ClaseCita, {"web","news","pressrelease","conference","podcast"}) and     elseif inArray(config.ClaseCita, {"web","noticia","pressrelease","conference","podcast"}) and    	             not is_set(Chapter) then 		Title = kern_quotes (Title);				-- if necessary, separate title's leading and trailing quote marks from Module provided quote marks         Title = wrap( 'quoted-title', Title );         TransTitle = wrap( 'trans-quoted-title', TransTitle );     else         Title = wrap( 'italic-title', Title );         TransTitle = wrap( 'trans-italic-title', TransTitle );     end          TransError = "";     if is_set(TransTitle) then         if not is_set(Title) then             TransError = " " .. seterror( 'trans_missing_title' );         else             TransTitle = " " .. TransTitle;         end     end          Title = Title .. Traductor .. TransTitle;          if is_set(Title) then         if not is_set(TitleLink) and is_set(URL) then              Title = externallink( URL, Title, URL_origin, UrlAccess ) .. TransError .. Format                    URL = "";             TieneURL = true;             Format = "";         else             Title = Title .. TransError;         end     end          if is_set(Place) then         Place = " " .. wrap( 'written', Place, use_lowercase ) .. sepc .. " ";     end          if is_set(Conference) then         if is_set(ConferenceURL) then             Conference = externallink( ConferenceURL, Conference );         end         Conference = sepc .. " " .. Conference     elseif is_set(ConferenceURL) then         Conference = sepc .. " " .. externallink( ConferenceURL, nil, ConferenceURLorigin );     end          if not is_set(Position) then         local Minutes = A['Minutes'];         if is_set(Minutes) then             Position = " " .. Minutes .. " " .. cfg.messages['minutes'];         else             local Time = A['Time'];             if is_set(Time) then                 local TimeCaption = A['TimeCaption']                 if not is_set(TimeCaption) then                     TimeCaption = cfg.messages['event'];                     if sepc ~= '.' then                         TimeCaption = TimeCaption:lower();                     end                 end                 Position = " " .. TimeCaption .. " " .. Time;             end         end     else         Position = " " .. Position;         At = '';     end          if not is_set(Page) then         if is_set(Pages) then             if is_set(Periodical) and --              not inArray(config.ClaseCita, {"encyclopaedia","web","book","news","podcast"}) then                 not inArray(config.ClaseCita, {"enciclopedia","web","libro","noticia","podcast"}) then                 Pages = ": " .. Pages;             elseif tonumber(Pages) ~= nil then                 Pages = sepc .." " .. PPrefix .. Pages;             else                 Pages = sepc .." " .. PPPrefix .. Pages;             end         end     else         if is_set(Periodical) and --          not inArray(config.ClaseCita, {"encyclopaedia","web","book","news","podcast"}) then             not inArray(config.ClaseCita, {"enciclopedia","web","libro","noticia","podcast"}) then            	             Page = ": " .. Page;         else             Page = sepc .." " .. PPrefix .. Page;         end     end          At = is_set(At) and (sepc .. " " .. At) or "";     Passage = is_set(Passage) and (sepc .. " " .. Passage) or "";     Position = is_set(Position) and (sepc .. " " .. Position) or "";     if config.ClaseCita == 'map' then         local Section = A['Section'];         local Inset = A['Inset'];         if first_set( Pages, Page, At ) ~= nil or sepc ~= '.' then             if is_set( Section ) then                 Section = ", " .. wrap( 'section', Section, true );             end             if is_set( Inset ) then                 Inset = ", " .. wrap( 'inset', Inset, true );             end         else             if is_set( Section ) then                 Section = sepc .. " " .. wrap( 'section', Section, use_lowercase );                 if is_set( Inset ) then                     Inset = ", " .. wrap( 'inset', Inset, true );                 end             elseif is_set( Inset ) then                 Inset = sepc .. " " .. wrap( 'inset', Inset, use_lowercase );             end                     end                     At = At .. Section .. Inset;             end      	--[[Look in the list of iso639-1 language codes to see if the value provided in the language parameter matches one of them.  If a match is found,  	use that value; if not, then use the value that was provided with the language parameter. 	 	Categories are assigned in a manner similar to the {{xx icon}} templates - categorizes only mainspace citations and only when the language code is not 'en' (English). 	]] 	 	if is_set (Language) then 		-- Poner en minúsculas el primer caracter del idioma si está en mayúsculas 		Language = Language:gsub("^%u", string.lower)  		if Language == 'español' or Language == 'castellano' or Language == 'es' or Language:match('^es%-.*') then 			Language="";	-- No mostrar el idioma español 		else 			local name = mw.language.fetchLanguageName( Language:lower(), "es" );	-- experiment: this seems to return correct ISO 639-1 language names 		 			if is_set (name) then 				Language=" " .. wrap( 'language', name ); 			else 				Language=" " .. wrap( 'language', Language );	-- no match, use parameter's value 			end 		end  	else 		Language="";	-- Asegurarnos de que el idioma no es nulo. 	end  -- handle type parameter for those CS1 citations that have default values  --	if inArray(config.ClaseCita, {"AV media notes", "DVD notes", "podcast", "pressrelease", "techreport", "thesis"}) then 	if inArray(config.ClaseCita, {"notas audiovisual", "notas de DVD", "podcast", "pressrelease", "techreport", "tesis"}) then		 		TitleType = set_titletype (config.ClaseCita, TitleType); 		if is_set(Degree) and "Tesis" == TitleType then	-- special case for cite thesis 			TitleType = "Tesis de " .. Degree; 		end 	end  	if is_set(TitleType) then					-- if type parameter is specified 		TitleType = " (" .. TitleType .. ")";	-- display it in parentheses 	end  	TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or ""; 	 	if is_set(Edition) then 		if is_set(SinEd) then -- No existe el parámetro en el módulo de la wikipedia inglesa. 			Edition = " " .. wrap( 'sin edición', Edition ) -- No existe el parámetro en el módulo de la wikipedia inglesa. 		else 			Edition = " " .. wrap( 'edition', Edition ) 		end 	else 		Edition = "" 	end     Issue = is_set(Issue) and (" (" .. Issue .. ")") or "";     Series = is_set(Series) and (sepc .. " " .. Series) or "";     OrigYear = is_set(OrigYear) and (" [" .. OrigYear .. "]") or "";     Agency = is_set(Agency) and (sepc .. " " .. Agency) or "";      if is_set(Volume) then         if Volume:match ('^%d+$') or Volume:match ('^[MDCLXVI]+$') -- negrita solamente si el capítulo está reflejado como cifra decimal o números romanos           then Volume = " <b>" .. dashtohyphen(Volume) .. "</b>";           else Volume = sepc .." " .. Volume;         end     end  --[[ This code commented out while discussion continues until after week of 2014-03-23 live module update;     if is_set(Volume) then         if ( mw.ustring.len(Volume) > 4 )           then Volume = sepc .. " " .. Volume;           else               Volume = " <b>" .. hyphentodash(Volume) .. "</b>";               if is_set(Series) then Volume = sepc .. Volume;               end         end     end ]]         ------------------------------------ totally unrelated data     --[[ Loosely mimic {{subscription required}} template; Via parameter identifies a delivery source that is not the publisher; these sources often, but not always, exist     behind a registration or paywall.  So here, we've chosen to decouple via from subscription (via has never been part of the registration required template).          Subscription implies paywall; Registration does not.  If both are used in a citation, the subscription required link note is displayed. There are no error messages for this condition.     ]]     if is_set(Via) then         Via = " " .. wrap( 'via', Via );     end  	if UrlAccess == 'registration' then 		RegistrationRequired = true 	end 	if is_set(SubscriptionRequired) then         SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; --here when 'via' parameter not used but 'subscription' is     elseif is_set(RegistrationRequired) then         SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; --here when 'via' and 'subscription' parameters not used but 'registration' is     end  --  if is_set(AccessDate) then     if is_set(AccessDate)  or is_set(AnyoAcceso) then         -- Test if accessdate is given without giving a URL         if  sinURL then             table.insert( z.message_tail, { seterror( 'accessdate_missing_url', {}, true ) } );            	AccessDate = '';         else         	if is_set(AccessDate) then 				if is_set(MesAcceso) and is_set(AnyoAcceso) then 					AccessDate = AccessDate .. seterror('redundant_parameters', '<code>&#124;fechaacceso=</code>, <code>&#124;añoacceso=</code> y <code>&#124;mesacceso=</code>') 				elseif is_set(MesAcceso) then 					AccessDate = AccessDate .. seterror('redundant_parameters', '<code>&#124;fechaacceso=</code> y <code>&#124;mesacceso=</code>') 				elseif is_set(AnyoAcceso) then 					if string.find(AccessDate, '%sde%s') then 						AccessDate = AccessDate .. ' de ' .. AnyoAcceso 				    else 						AccessDate = AccessDate .. seterror('redundant_parameters', '<code>&#124;fechaacceso=</code> y <code>&#124;Añoacceso=</code>'); 					end 				end         	elseif is_set(MesAcceso) then          		AccessDate = MesAcceso .. ' de ' .. AnyoAcceso         	else          		AccessDate = AnyoAcceso         	end             local retrv_text =