Modulo:Coordinates

El Vikipedio, la libera enciklopedio
Dokumentado Dokumentado


Ŝablona programado Diskutoj Lua Testoj Subpaĝoj
Modulo Esperanto English Deutsch

Modulo: Dokumentado


Se vi havas demandon pri ĉi tiu Lua-modulo, tiam vi povas demandi en la diskutejo pri Lua-moduloj. La Intervikiaj ligiloj estu metataj al Vikidatumoj. (Vidu Helpopaĝon pri tio.)
--[[ Coordinates 2020-05-04
This module is intended to replace the functionality of {{Coord}} and related
templates.  It provides several methods, including

{{#Invoke:Coordinates | coord }} : General function formatting and displaying
coordinate values.

{{#Invoke:Coordinates | dec2dms }} : Simple function for converting decimal
degree values to DMS format.

{{#Invoke:Coordinates | dms2dec }} : Simple function for converting DMS format
to decimal degree format.

{{#Invoke:Coordinates | dec2ch1903 }} : Simple function for converting decimal
degree values to CH1903 format.

{{#Invoke:Coordinates | dms2ch1903 }} : Simple function for converting DMS format
to CH1903 format.

{{#Invoke:Coordinates | dec2utm }} : Simple function for converting decimal
degree values to UTM format.

{{#Invoke:Coordinates | dms2utm }} : Simple function for converting DMS format
to UTM format.

]]

math_mod = require( "Module:Math" );
globalFrame = nil

coordinates = {};


-- por koordinatoj
local function koordinatoj(latitudo, longitudo, regiono, tipo, nomo, supre, teksto )
			local t = "dms"
			if teksto ~= "" and teksto ~= nil then
				t = teksto
			end
			local frame = mw.getCurrentFrame()
			local n = frame:expandTemplate {
				title="Koordinato",
				args ={
					NS=latitudo,
					EW=longitudo,
					region=regiono,
					type=tipo,
					name=nomo,
					text=t, 	    	    	         -- la koordinatoj aperu en la informkesto
					article=supre				    	 -- ĉu ankaŭ supre? se jes, la parametro havu la valoron /
				}
			}
			return n
end	


-- {{#invoke:map|tag|type=maplink|text=(mapo)|geotype=Point|title={{{name}}}|latitude={{{NS|0}}} |longitude={{{EW|0}}}|zoom=15|image=|marker-symbol={{#switch:{{{type|}}}|country|state|adm1st|adm2nd|city=city|isle=circle|mountain|landmark=triangle|waterbody=water|#default=<!-- fino "switch"-->}}|marker-size=large|marker-color=4682B4}} 
-- from {{Ŝablono:CoordinateLINK}}
local function mapligilo (lat, long, name, ctype)
		local frame = mw.getCurrentFrame()	
		local s = ''
		if ctype == 'country' or ctype == 'state' or ctype == 'adm1st' or ctype == 'adm2nd' or ctype == 'city' then
			s = 'city'
		elseif ctype == 'isle' then
			s = 'circle'
		elseif ctype == 'mountain' or ctype == 'landmark' then
			s = 'triangle'
		elseif ctype == 'waterbody' then
			s = 'water'
		end
		local koord = koordinatoj(lat, long)
		local r = frame:expandTemplate {
			title='Mapligilo',
			args={
				text='(mapo)',
				type='point',
				title=name,
				coord=koord,
				zoom='15',
				['marker']=s,
				['marker-size']='large',
				['marker-color']='4682B4'
			}
		}
		return r
end	


--[[ Helper function, replacement for {{coord/display/title}} ]]
function displaytitle (s, notes, globe)
    if mw.ustring.lower(mw.ustring.sub(s,1,5)) == "(div)" then
        s = mw.ustring.sub(s,6);
        tag = "div"
    end
    if mw.ustring.lower(mw.ustring.sub(s,1,6)) == "(span)" then
        s = mw.ustring.sub(s,7);
        tag = "span"
    end
    local l = "[[Geografia koordinata sistemo|Koordinatoj]]: " .. s
    -- local l = "" .. s
    if tag ~= "" and tag ~= nil then 
    co = '<' .. tag .. ' id="coordinates">' .. l .. notes .. '</' .. tag .. '>';        
    else
    co = '<span id="coordinates">' .. l .. notes .. '</span>';
    end
    if tag == "div" then
        return co 
    else 
        return '<span style="font-size: small;">' .. co .. '</span>' 
    end
end

--[[ Helper function, replacement for {{CoordinateNOx}}, but its text is elsewhere ]]
function displaytitle2 (s, format)
    --local l = "[[Geographic coordinate system|Coordinates]]: " .. s
    local l = "" .. s
    if format ~= "" and format ~= nil then
        co = '<span id="coordinates" style="' .. format .. '">' .. l .. '</span>';
    else co = '<span id="coordinates">' .. l .. '</span>';
    end
    return '<span style="font-size: small;">' .. co .. '</span>'
end  

--[[ Helper function, Replacement for {{coord/display/inline}} ]]
function displayinline (s, notes)
    return s .. notes    
end

--[[ Helper function, used in detecting DMS formatting ]]
local dmsTest = function(first, second)
    local concatenated = first:upper() .. second:upper();
    
    return concatenated == "NE" or concatenated == "NO" or concatenated == "NW" or concatenated == "NU" or concatenated == "SE" or concatenated == "SO"  
        or concatenated == "SW" or concatenated == "SU" or concatenated == "EN" or concatenated == "ON" or concatenated == "WN"  or concatenated == "UN" 
        or concatenated == "ES" or concatenated == "OS" or concatenated == "WS" or concatenated == "US"
end

--[[
parseDec

Transforms decimal format latitude and longitude into the a
structure to be used in displaying coordinates
]]
function parseDec( lat, long, format )
    local coordinateSpec = {}
    local errors = {}
    
    if long == "" or long == nil then
        return nil, {{"parseDec", "Mankas longitudo"}}
    elseif not tonumber(formatPoint(long),10) then 
    	return nil, {{"parseDec", "Longitudo ne povis esti parsata kiel numero: " .. long}} 
	elseif not tonumber(long) then
		return nil, {{"parseDec", "Longitudo ne povis esti parsata kiel numero: " .. long}}        
    end
    
    errors = validate( lat, nil, nil, long, nil, nil, 'parseDec', false );    
    coordinateSpec["dec-lat"]  = lat;
    coordinateSpec["dec-long"] = long;

    local mode = coordinates.determineMode( lat, long );
    coordinateSpec["dms-lat"]  = convert_dec2dms( lat, "N", "S", mode)  -- {{coord/dec2dms|{{{1}}}|N|S|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
    coordinateSpec["dms-long"] = convert_dec2dms( long, "O", "U", mode)  -- {{coord/dec2dms|{{{2}}}|E|W|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}  
    coordinateSpec["dmslong-lat"]  = convert_dec2dms( lat, "Nordo", "Sudo", mode)  -- {{coord/dec2dms|{{{1}}}|N|S|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
    coordinateSpec["dmslong-long"] = convert_dec2dms( long, "Oriento", "Okcidento", mode)  -- {{coord/dec2dms|{{{2}}}|E|W|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}      
    --added formats
    coordinateSpec['ch1903-x'], coordinateSpec['ch1903-y'] = convert_dec2ch1903("",lat,long,0) -- for Swiss coordinates
    coordinateSpec['zonenumber'], coordinateSpec['zonedir'], coordinateSpec['zone'], coordinateSpec['utm-x'], coordinateSpec['utm-y'] = convert_dec2utm("",lat,long,0) -- for UTM coordinates
    coordinateSpec["dm-lat"]  = convert_dec2dms( lat, "N", "S", "dm")  
    coordinateSpec["dm-long"] = convert_dec2dms( long, "O", "U", "dm") 
    coordinateSpec["d-lat"]  = convert_dec2dms( lat, "N", "S", "d")  
    coordinateSpec["d-long"] = convert_dec2dms( long, "O", "U", "d")     
 
    
    if format ~= "" then
        coordinateSpec.default = format
    else
        coordinateSpec.default = "dec"
    end

    return coordinateSpec, errors
end

--[[ Helper function, handle optional args. ]]
function optionalArg(arg, suplement)
    if arg ~= nil and arg ~= "" then
        return arg .. suplement
    end
    return ""
end

--[[
parseDMS

Transforms degrees, minutes, seconds format latitude and longitude 
into the a structure to be used in displaying coordinates
]]
function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format )
    local coordinateSpec = {}
    local errors = {}
    
    lat_f = lat_f:upper();
    -- long_f = string.gsub(long_f:upper(),'W','U');
    long_f = long_f:upper();

    local lat_flong = 'Nordo';
    if lat_f == 'S' then
        lat_flong = 'Sudo';
    end
    local long_flong = 'Okcidento';
    if long_f == 'E' or long_f == 'O' then
        long_flong = 'Oriento';
    end
    
    
    -- Check if specified backward
    if lat_f == 'E' or lat_f == "O" or lat_f == 'W' or lat_f == 'U' then
        local t_d, t_m, t_s, t_f;
        t_d = lat_d;
        t_m = lat_m;
        t_s = lat_s;
        t_f = lat_f;
        lat_d = long_d;
        lat_m = long_m;
        lat_s = long_s;
        lat_f = long_f;
        long_d = t_d;
        long_m = t_m;
        long_s = t_s;
        long_f = t_f;
    end    
    
    errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true );
    if long_d == nil or long_d == "" then
        table.insert(errors, {"parseDMS", "Mankas longitudo" })
    elseif not tonumber(formatPoint(long_d),10) then
		return nil, {{"parseDMS", "Longitudo ne povis esti parsata kiel numero:" .. long_d }}        	
    elseif not tonumber(long_d) then
		return nil, {{"parseDMS", "Longitudo ne povis esti parsata kiel numero:" .. long_d }}
    end
    
    if lat_m == nil and lat_s == nil and long_m == nil and long_s == nil and #errors == 0 then 
        if math_mod._precision( lat_d ) > 0 or math_mod._precision( long_d ) > 0 then
            if lat_f:upper() == 'S' then 
                lat_d = '-' .. lat_d;
            end
            if long_f:upper() == 'W' or long_f:upper() == 'U' then 
                long_d = '-' .. long_d;
            end     
            
            return parseDec( lat_d, long_d, format );
        end        
    end   
    
    if long_f == "W" then
        long_f = "U"        -- montri direkton, escepte de coordinateSpec["param"]
    end
    if long_f == "E" then
        long_f = "O"        -- montri direkton, escepte de coordinateSpec["param"]
    end    
    coordinateSpec["dms-lat"]  = lat_d.."°&nbsp;"..optionalArg(lat_m,"′&nbsp;") .. optionalArg(lat_s,"″&nbsp;") .. lat_f
    coordinateSpec["dmslong-lat"]  = lat_d.."°&nbsp;"..optionalArg(lat_m,"′&nbsp;") .. optionalArg(lat_s,"″&nbsp;") .. lat_flong
    coordinateSpec["dms-long"] = long_d.."°&nbsp;"..optionalArg(long_m,"′&nbsp;") .. optionalArg(long_s,"″&nbsp;") .. long_f
    coordinateSpec["dmslong-long"] = long_d.."°&nbsp;"..optionalArg(long_m,"′&nbsp;") .. optionalArg(long_s,"″&nbsp;") .. long_flong
    coordinateSpec["dec-lat"]  = convert_dms2dec(lat_f, lat_d, lat_m, lat_s) -- {{coord/dms2dec|{{{4}}}|{{{1}}}|0{{{2}}}|0{{{3}}}}}
    coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) -- {{coord/dms2dec|{{{8}}}|{{{5}}}|0{{{6}}}|0{{{7}}}}}
    --added formats
    coordinateSpec['ch1903-x'], coordinateSpec['ch1903-y'] = convert_dms2ch1903(lat_f, lat_d, lat_m, lat_s ,long_f, long_d, long_m, long_s) -- for Swiss coordinates
    coordinateSpec['zonenumber'], coordinateSpec['zonedir'], coordinateSpec['zone'], coordinateSpec['utm-x'], coordinateSpec['utm-y'] = convert_dms2utm(lat_f, lat_d, lat_m, lat_s ,long_f, long_d, long_m, long_s) -- for UTM coordinates
    coordinateSpec["dm-lat"]  = lat_d.."°&nbsp;"..optionalArg(lat_m,"′&nbsp;") .. lat_f
    coordinateSpec["dm-long"] = long_d.."°&nbsp;"..optionalArg(long_m,"′&nbsp;") .. long_f
    coordinateSpec["d-lat"]  = lat_d.."°&nbsp;" .. lat_f
    coordinateSpec["d-long"] = long_d.."°&nbsp;" .. long_f    
    
    
    if format ~= "" then
        coordinateSpec.default = format
    else
        coordinateSpec.default = "dms"
    end   

    return coordinateSpec, errors
end

--[[
specPrinter

Output formatter.  Takes the structure generated by either parseDec
or parseDMS and formats it for inclusion on Wikipedia.
]]
function specPrinter(args, coordinateSpec)
    local uriComponents = coordinateSpec["param"]
    if uriComponents == "" then
        -- RETURN error, should never be empty or nil
        return "ERARO param estis malplena"
    end

    if args["name"] ~= "" and args["name"] ~= nil then
        uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"])
    end
    
    local lang=mw.language.getContentLanguage():getCode();
    
    local geodmshtml = '<span class="geo-dms" title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dms-lat"] .. ' ' ..  coordinateSpec["dms-long"] .. '">'
             .. '<span class="latitude">' .. coordinateSpec["dms-lat"] .. '</span> '
             .. '<span class="longitude">' ..coordinateSpec["dms-long"] .. '</span>'
             .. '</span>'
    local geodmhtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dm-lat"] .. ' ' ..  coordinateSpec["dm-long"] .. '">'
             .. '<span title="Latitude">' .. coordinateSpec["dm-lat"] .. '</span> '
             .. '<span title="Longitude">' ..coordinateSpec["dm-long"] .. '</span>'
             .. '</span>'       
    local geodhtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["d-lat"] .. ' ' ..  coordinateSpec["d-long"] .. '">'
             .. '<span title="Latitude">' .. coordinateSpec["d-lat"] .. '</span> '
             .. '<span title="Longitude">' ..coordinateSpec["d-long"] .. '</span>'
             .. '</span>'               
    local geodmslonghtml = '<span class="geo-dms" title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dmslong-lat"] .. ' ' ..  coordinateSpec["dmslong-long"] .. '">'
             .. '<span class="latitude">' .. coordinateSpec["dmslong-lat"] .. '</span> '
             .. '<span class="longitude">' ..coordinateSpec["dmslong-long"] .. '</span>'
             .. '</span>'
    local lat = tonumber( coordinateSpec["dec-lat"] ) or 0
    if lat < 0 then
        -- FIXME this breaks the pre-existing precision
        geodeclat = coordinateSpec["dec-lat"]:sub(2) .. " °S"
        catlat    = coordinateSpec["dec-lat"]:sub(2) 
        catdirlat = "° S"
        --geodeclat = "-" .. coordinateSpec["dec-lat"]:sub(2)
    else
        geodeclat = (coordinateSpec["dec-lat"] or 0) .. " °N"
        catlat    = (coordinateSpec["dec-lat"] or 0) 
        catdirlat = "° N"
        --geodeclat = (coordinateSpec["dec-lat"] or 0)
    end

    local long = tonumber( coordinateSpec["dec-long"] ) or 0
    if long < 0 then
        -- FIXME does not handle unicode minus
        geodeclong = coordinateSpec["dec-long"]:sub(2) .. " °U"
        catlong    = coordinateSpec["dec-long"]:sub(2) 
        catdirlong = "° U"
        --geodeclong = '-' .. coordinateSpec["dec-long"]:sub(2)
    else
        geodeclong = (coordinateSpec["dec-long"] or 0) .. " °O"
        catlong    = (coordinateSpec["dec-long"] or 0) 
        catdirlong = "° E" -- O estus pli taŭga, se por okcidento estas U
        --geodeclong = (coordinateSpec["dec-long"] or 0)
    end
    
    -- it creates coding for categories, if the paramter "category" is used. after that returns it
    if args['category'] =="jes" or args['category'] =="yes" then
        -- category scheme from {{Ŝablono:Koord/kategorioj}}
        local cat =""
        catlong = math.floor (catlong) -- catlong % 10000
        catlat = math.floor (catlat) -- catlat % 10000
        if catlong == 180 then cat= "[[Kategorio:179° U]][[Kategorio:179° E]]"
        else cat ="[[Kategorio:" .. catlong .. catdirlong .. "]]"  
        end
        cat = cat .. "[[Kategorio:" .. catlat .. catdirlat .. "]]"
        return cat
    elseif args['category'] == "ne" or args['category'] == "no" then
        cat = "[[Kategorio:Artikolo kun koordinatoj, sed sen koordinataj ligiloj]]" 
        return cat
    end
    
    local geodechtml = '<span class="geo-dec" title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dec-lat"] .. ' ' ..  coordinateSpec["dec-long"] .. '">'
             .. geodeclat .. ', '
             .. geodeclong
             .. '</span>'

    local geonumhtml = '<span class="geo">'
             .. coordinateSpec["dec-lat"] .. '; '
             .. coordinateSpec["dec-long"]
             .. '</span>'
             
--cf http://www.mediawiki.org/wiki/Extension:GeoData
    local geodata = ''
    local r,s,t=string.match (coordinateSpec["param"],'(.*)_(E?W?)_(.*)')
    local globe,globend=string.match (coordinateSpec["param"],'_globe:(.*)(_*)')
    local ctype,ctypend = string.match(coordinateSpec["param"],'type:(.*)(_*)')
    --Désactivé pour les astres à cause de problèmes de longitudes planétocentriques/planétographiques
    if globe == nil or globe == 'earth' then
    	geodata = '{{#coordinates:' .. coordinateSpec["dec-lat"] .. '|' .. coordinateSpec["dec-long"] .. '|primary|' .. t .. '}}'
    end
    if args['geodata'] ~= nil then
        return geodata;
    end             

    local inner;
    if coordinateSpec["default"] == "dms" then
        inner = '<span class="' .. displayDefault(coordinateSpec["default"], "dms" ) .. '">' .. geodmshtml .. '</span>'
                    .. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
                    .. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';
    elseif coordinateSpec["default"] == "dm" then
        inner = '<span class="' .. displayDefault(coordinateSpec["default"], "dm" ) .. '">' .. geodmhtml .. '</span>'
                    .. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
                    .. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';
    elseif coordinateSpec["default"] == "d" then
        inner = '<span class="' .. displayDefault(coordinateSpec["default"], "d" ) .. '">' .. geodhtml .. '</span>'
                    .. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
                    .. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';                    
    else
        inner = '<span class="' .. displayDefault(coordinateSpec["default"], "dms long" ) .. '">' .. geodmslonghtml .. '</span>'
                    .. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
                    .. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';        
    end


    if args["name"] == "" or args["name"] == nil then
        inner = inner .. geodechtml 
                .. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span></span>'
    else
        inner = inner .. '<span class="vcard">' .. geodechtml 
                .. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span>'
                .. '<span style="display:none">&#xfeff; (<span class="fn org">'
                .. args["name"] .. '</span>)</span></span></span>'
    end

    if args["link"] == "jes" or args["link"] == "yes" or args["link"] == "" or args["link"] == nil then
    return '<span class="plainlinks nourlexpansion">' .. globalFrame:preprocess(
        '[http://tools.wmflabs.org/geohack/geohack.php?pagename={{FULLPAGENAMEE}}&language=' .. lang .. '&params=' ..
        uriComponents .. ' ' .. inner .. ']') .. '</span> ' .. mapligilo (lat, long, name, ctype)
    elseif args["link"] == "ne" or args["link"] == "no" then
    return '<span class="plainlinks nourlexpansion">' .. inner .. '</span>'    	
    end    
end

--[[
specPrinter2 - for {{Koordinato}} 

Output formatter.  Takes the structure generated by either parseDec
or parseDMS and formats it for inclusion on Wikipedia.
]]
function specPrinter2(args, coordinateSpec)
    local uriComponents = coordinateSpec["param"]
    if uriComponents == "" then
        -- RETURN error, should never be empty or nil
        return "ERARO param estis malplena"
    end

    if args["name"] ~= "" and args["name"] ~= nil then
        uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"])
    end
    
    local lang=mw.language.getContentLanguage():getCode();
    
    local geodmshtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dms-lat"] .. ' ' ..  coordinateSpec["dms-long"] .. '">'
             .. '<span title="Latitude">' .. coordinateSpec["dms-lat"] .. '</span> '
             .. '<span title="Longitude">' ..coordinateSpec["dms-long"] .. '</span>'
             .. '</span>'
    local geodmslonghtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dmslong-lat"] .. ' ' ..  coordinateSpec["dmslong-long"] .. '">'
             .. '<span title="Latitude">' .. coordinateSpec["dmslong-lat"] .. '</span> '
             .. '<span title="Longitude">' ..coordinateSpec["dmslong-long"] .. '</span>'
             .. '</span>'
    local geodmhtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dm-lat"] .. ' ' ..  coordinateSpec["dm-long"] .. '">'
             .. '<span title="Latitude">' .. coordinateSpec["dm-lat"] .. '</span> '
             .. '<span title="Longitude">' ..coordinateSpec["dm-long"] .. '</span>'
             .. '</span>'    
    local geodhtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["d-lat"] .. ' ' ..  coordinateSpec["d-long"] .. '">'
             .. '<span title="Latitude">' .. coordinateSpec["d-lat"] .. '</span> '
             .. '<span title="Longitude">' ..coordinateSpec["d-long"] .. '</span>'
             .. '</span>'               
             
    local lat = tonumber( coordinateSpec["dec-lat"] ) or 0
    if lat < 0 then
        -- FIXME this breaks the pre-existing precision
        geodeclat = coordinateSpec["dec-lat"]:sub(2) .. " °S"
        catlat    = coordinateSpec["dec-lat"]:sub(2) 
        catdirlat = "° S"
        --geodeclat = "-" .. coordinateSpec["dec-lat"]:sub(2)
    else
        geodeclat = (coordinateSpec["dec-lat"] or 0) .. " °N"
        catlat    = (coordinateSpec["dec-lat"] or 0) 
        catdirlat = "° N"
        --geodeclat = (coordinateSpec["dec-lat"] or 0)
    end

    local long = tonumber( coordinateSpec["dec-long"] ) or 0
    if long < 0 then
        -- FIXME does not handle unicode minus
        geodeclong = coordinateSpec["dec-long"]:sub(2) .. " °U"
        catlong    = coordinateSpec["dec-long"]:sub(2) 
        catdirlong = "° U"
        --geodeclong = '-' .. coordinateSpec["dec-long"]:sub(2)
    else
        geodeclong = (coordinateSpec["dec-long"] or 0) .. " °O"
        catlong    = (coordinateSpec["dec-long"] or 0) 
        catdirlong = "° E" -- O estus pli taŭga, se por okcidento estas U
        --geodeclong = (coordinateSpec["dec-long"] or 0)
    end
    
    -- it creates coding for categories, if the paramter "category" is used. after that returns it
    if args['category'] =="jes" or args['category'] =="yes" then
        -- category scheme from {{Ŝablono:Koord/kategorioj}}
        local cat =""
        catlong = math.floor (catlong) -- catlong % 10000
        catlat = math.floor (catlat) -- catlat % 10000
        if catlong == 180 then cat= "[[Kategorio:179° U]][[Kategorio:179° E]]"
        else cat ="[[Kategorio:" .. catlong .. catdirlong .. "]]"  
        end
        cat = cat .. "[[Kategorio:" .. catlat .. catdirlat .. "]]"
        return cat        
    elseif args['category'] == "ne" or args['category'] == "no" then
        cat = "[[Kategorio:Artikolo kun koordinatoj, sed sen koordinataj ligiloj]]" 
        return cat
    end
    
    local geodechtml = '<span title="Mapoj, elĉielaj bildoj kaj aliaj datumoj por ' .. coordinateSpec["dec-lat"] .. ' ' ..  coordinateSpec["dec-long"] .. '">'
             .. '<span title="Latitudo">' .. geodeclat .. '</span>' .. ', '
             .. '<span title="Longitudo">' .. geodeclong .. '</span>'
             .. '</span>'

    local geonumhtml = '<span class="geo">'
             .. coordinateSpec["dec-lat"] .. '; '
             .. coordinateSpec["dec-long"]
             .. '</span>'
             
    --<span title="Svislandaj landaj koordinatoj">CH1903:&nbsp;</span>
    --<span title="y easting">562330</span>&nbsp;/&nbsp;<span title="x northing">124404</span>
    if coordinateSpec['ch1903-x'] ~= nil and coordinateSpec['ch1903-y'] ~= nil then
    geoch1903html = '<span title="Svislandaj landaj koordinatoj">CH1903:&nbsp;</span>'
        .. '<span title="y easting">' .. coordinateSpec['ch1903-y'] .. '</span>&nbsp;/&nbsp;'        
        .. '<span title="x northing">' .. coordinateSpec ['ch1903-x'] .. '</span>' 
        ch1903 = "yes"
    end    
    
    --UTM format
    if coordinateSpec['utm-x'] ~= nil and coordinateSpec['utm-y'] ~= nil then
    geoutmhtml = '<span title="Universal Transverse Mercator, baziĝanta sur WGS84">UTM:&nbsp;</span>'
        .. 'Zono&nbsp;<span title="Zononumero">' .. coordinateSpec['zonenumber'] .. '</span>'
        .. '<span title="Zonobendo, ' .. coordinateSpec['zonedir'] .. ' de la ekvatoro">' .. coordinateSpec['zone'] .. '</span>, '
        .. '<span title="easting">' .. coordinateSpec['utm-y'] .. '</span>&nbsp;/&nbsp;'        
        .. '<span title="northing">' .. coordinateSpec['utm-x'] .. '</span>' 
        utm = "yes"
    end      

    local inner;
        
    if coordinateSpec["default"] == "dms" then
        inner = geodmshtml 
    elseif coordinateSpec["default"] == "dms long" then
        inner = geodmslonghtml 
    elseif coordinateSpec["default"] == "dm" then
        inner = geodmhtml    
    elseif coordinateSpec["default"] == "d" then
        inner = geodhtml            
    elseif coordinateSpec["default"] == "ch1903" and ch1903 == "yes" then
        inner = geoch1903html
    elseif coordinateSpec["default"] == "utm" and utm == "yes" then
        inner = geoutmhtml        
    else inner = geodechtml 
    end

    local id = " "
    local display = args['display'] -- or "inline"
    if display == nil then display = "inline"
    end        
    if string.find( display, 'inline' ) ~= nil then
    -- creates a text for id, if it used in the text, not in the title       
        if args["name"] ~= "" and args["name"] ~= nil then
        id = ' id="' .. args['name'] .. '" '    
        else id = ' id="text_coordinates" '
        end                
        -- for microformats according to {{Koordinato}}
        micro = '<span class="geo microformat"><span class="latitude">' .. coordinateSpec["dec-lat"] .. '</span>'
        micro = micro .. '<span class="longitude">' .. coordinateSpec["dec-long"] .. '</span><span class="elevation"></span></span>'
        --sortkey has to be added only, if display is "inline"
        --replacement for {{CoordinateSort}}
        if args['sortkey'] ~= "" and args['sortkey'] ~= nil then
            local k = args['sortkey']             
            local z = 500.0000005
            local h
            key = '<span style="display:none">!' 
                k = mw.ustring.upper(k) -- capitalize 
                if k == "EW" or k == "LONG" then 
                   h = math_mod._round(z + long, 6) .. math_mod._round(z + lat, 6)
                   key = key .. h
                else 
                   h = math_mod._round(z + lat, 6) .. math_mod._round(z + long, 6)
                   key = key .. h
                end     
            key = key .. '</span>'
        else key = ""    
        end
        if args['format2'] ~= "" and args['format2'] ~= nil then
        -- create second format
               local format2 = args['format2']:lower()
               if format2 == "dms" then
                    f2 = geodmshtml 
               elseif format2 == "dms long" then
                    f2 = geodmslonghtml 
               elseif format2 == "ch1903" and ch1903 == "yes" then
                    f2 = geoch1903html
               elseif format2 == "utm" and utm == "yes" then
                    f2 = geoutmhtml                    
               else f2 = geodechtml 
               end
               -- f2 = ' ( ' .. f2 .. ' ) '
        else f2 = ""   
        end    
        if args['format3'] ~= "" and args['format3'] ~= nil then
        -- create third format
               local format3 = args['format3']:lower()
               if format3 == "dms" then
                    f3 = geodmshtml 
               elseif format3 == "dms long" then
                    f3 = geodmslonghtml 
               elseif format3 == "ch1903" and ch1903 == "yes" then
                    f3 = geoch1903html
               elseif format3 == "utm" and utm == "yes" then
                    f2 = geoutmhtml                       
               else f3 = geodechtml 
               end
               -- f3 = ' ( ' .. f3 .. ' ) '
        else f3 = ""                
        end        
        if args['format4'] ~= "" and args['format4'] ~= nil then
        -- create fourth format
               local format4 = args['format4']:lower()
               if format4 == "dms" then
                    f4 = geodmshtml 
               elseif format4 == "dms long" then
                    f4 = geodmslonghtml 
               elseif format4 == "ch1903" and ch1903 == "yes" then
                    f4 = geoch1903html
               elseif format4 == "utm" and utm == "yes" then
                    f2 = geoutmhtml                       
               else f4 = geodechtml 
               end
               -- f4 = ' ( ' .. f4 .. ' ) '
        else f4 = ""    
        end    
    else     
        micro = '<div class="geo microformat"><span class="latitude">' .. coordinateSpec["dec-lat"] .. '</span>'
        micro = micro .. '<span class="longitude">' .. coordinateSpec["dec-long"] .. '</span><span class="elevation"></span></div>'
        key = ""
        f2 = ""
        f3 = ""
        f4 = ""
    end   
    if string.find( display, 'title' ) ~= nil then
        if args['formatitle2'] ~= "" and args['formatitle2'] ~= nil then
        -- create second format
               local formatitle2 = args['formatitle2']:lower()
        --       if formatitle2 == "dms" then
        --            ft2 = geodmshtml 
        --       elseif formatitle2 == "dms long" then
        --            ft2 = geodmslonghtml 
        --       elseif formatitle2 == "ch1903" and ch1903 == "yes" then
               if formatitle2 == "ch1903" and ch1903 == "yes" then
                    ft2 = geoch1903html
               else ft2 = geodechtml 
               end
               -- ft2 = ' ( ' .. ft2 .. ' ) '
        else ft2 = ""   
        end        
    end    
    
    -- add a clip before and after the added formats
    if args['second'] == "yes" then
        if ft2 ~= "" and ft2 ~= nil then
        otherformat = ' (' .. ft2 .. ')'
        else otherformat = ''
        end
    else
        if (f2 ~= "" and f2 ~= nil) or (f3 ~= "" and f3 ~= nil) or (f4 ~= "" and f4 ~= nil) then
        if f2 ~= "" and f2 ~= nil and f3 ~= "" and f3 ~= nil then 
            f2f3 = ' ; '
        else f2f3 = ""    
        end
        if f3 ~= "" and f3 ~= nil and f4 ~= "" and f4 ~= nil then 
            f3f4 = ' ; '
        else f3f4 = ""    
        end        
        otherformat = ' (' .. f2 .. f2f3 .. f3 .. f3f4 .. f4 .. ')'
        else otherformat = ''    
        end
    end 
    
    -- a little trick for return the microformats only
    if args['micro'] == "yes" then
       return micro
    end    

    -- analyzes the parameter "word", if it a has a value for certain symbol
    if args['word'] ~= "" and args['word'] ~= nil then
        local word = args['word']
        upperword = string.upper(word)
        --ICON0 and ICON1
        if upperword == "ICON0" then
            word = "⊙"
        elseif upperword == "ICON" then
            word = "⦁"    
        elseif upperword == "ICON1" then
            word = "<sup>▼</sup>"
        elseif upperword == "ICON2" then
            word = "[[Dosiero:Erioll world.svg|15px|link=|loko]]"
        end
        if args['name'] ~= "" and args['name'] ~= nil then
            word = '<span title="' .. args['name'] .. '">' .. word .. '</span>'
        else
            word = '<span>' .. word .. '</span>'
        end
        return key .. '<span' .. id .. 'class="plainlinks nourlexpansion">' .. globalFrame:preprocess(
        '[http://tools.wmflabs.org/geohack/geohack.php?pagename={{FULLPAGENAMEE}}&language=' .. lang .. '&params=' ..
        uriComponents .. ' ' .. word .. ']') .. '</span>'
    else
       return key .. '<span' .. id .. 'class="plainlinks nourlexpansion">' .. globalFrame:preprocess(
        '[http://tools.wmflabs.org/geohack/geohack.php?pagename={{FULLPAGENAMEE}}&language=' .. lang .. '&params=' ..
        uriComponents .. ' ' .. inner .. otherformat .. ']') .. '</span>' 
    end
end

--[[
Formats any error messages generated for display
]]
function errorPrinter(errors)
    local result = ""
    for i,v in ipairs(errors) do
        local errorHTML = '<strong class="error">Koordinatoj: ' .. v[2] .. '</strong>'
        result = result .. errorHTML .. "<br />"
    end
    return result
end

--[[
Determine the required CSS class to display coordinates

Usually geo-nondefault is hidden by CSS, unless a user has overridden this for himself
default is the mode as specificied by the user when calling the {{coord}} template
mode is the display mode (dec or dms) that we will need to determine the css class for 
]]
function displayDefault(default, mode)
    if default == "" then
        default = "dec"
    end
    
    if default:sub(1,4) == mode:sub(1,4) or default:sub(1,3) == mode:sub(1,3) then
        return "geo-default"
    else
        return "geo-nondefault"
    end
end

--[[ 
Check the input arguments for coord to determine the kind of data being provided
and then make the necessary processing.
]]
function formatTest(args)
    local result, errors;
    local primary = false;
    
    if args[1] == "" then
        -- no lat logic
        return errorPrinter( {{"formatTest", "Mankas latitudo"}} )
--	elseif not tonumber(formatPoint(args[1]), 10) then
		-- bad lat logic
--		return errorPrinter( {{"formatTest", "Ne eblas parsi latitudon kiel numeron:" .. args[1]}} )        
--	elseif not tonumber(args[1]) then
		-- bad lat logic
--		return errorPrinter( {{"formatTest", "Ne eblas parsi latitudon kiel numeron:" .. args[1]}} )        
    elseif args[4] == "" and args[5] == "" and args[6] == "" then
        -- dec logic
        result, errors = parseDec( formatPoint(args[1]), formatPoint(args[2]), args['format'] )
        if result == nil then
            return errorPrinter( errors );
        end              
        local declat = tonumber( formatPoint(args[1]), 10 ) or 0
        if declat < 0 then 
            dirNS = "_S_" 
            declat = 0 - declat
        else 
            dirNS = "_N_"   
            declat = formatPoint(args[1])
        end
        local declong = tonumber( formatPoint(args[2]), 10 ) or 0
        if declong < 0 then 
            dirEW = "_W_"
            declong = 0 - declong
        else 
            dirEW = "_E_"    
            declong = formatPoint(args[2])
        end
        result.param    = table.concat( {declat, dirNS, declong, dirEW, args[3] } );
        --result.param    = table.concat( {formatPoint(args[1]), "_N_", formatPoint(args[2]), "_E_", args[3] } );
    elseif dmsTest(args[4], args[8]) then
        -- dms logic
        result, errors = parseDMS( args[1], args[2], formatPoint(args[3]), args[4], 
            args[5], args[6], formatPoint(args[7]), args[8], args['format'] )
        result.param = table.concat( { args[1], args[2], formatPoint(args[3]), args[4], args[5],
            args[6], formatPoint(args[7]), formatLongEW(args[8]), args[9] } , '_' );
        if args[10] ~= '' then
        	local deko = '<span style="display:none;">' .. args[10] .. '</span>'
            table.insert( errors, { 'formatTest', 'Kromaj neatenditaj parametroj/10' .. deko } );
        end        
    elseif dmsTest(args[3], args[6]) then
        -- dm logic
        result, errors = parseDMS( args[1], formatPoint(args[2]), nil, args[3], 
            args[4], formatPoint(args[5]), nil, args[6], args['format'] )
        result.param = table.concat( { args[1], formatPoint(args[2]), args[3], args[4], formatPoint(args[5]),
            formatLongEW(args[6]), args[7] } , '_' );
        if args[8] ~= '' then
        	local oko = '<span style="display:none;">' .. args[8] .. '</span>'
            table.insert( errors, { 'formatTest', 'Kromaj neatenditaj parametroj/8' .. oko } );
        end        
    elseif dmsTest(args[2], args[4]) then
        -- d logic
        result, errors = parseDMS( formatPoint(args[1]), nil, nil, args[2], 
            formatPoint(args[3]), nil, nil, args[4], args['format'] )
        result.param = table.concat( { formatPoint(args[1]), args[2], formatPoint(args[3]), formatLongEW(args[4]), args[5] } , '_' );
        if args[6] ~= '' then
        	local seso = '<span style="display:none;">' .. args[6] .. '</span>'
            table.insert( errors, { 'formatTest', 'Kromaj neatenditaj parametroj/6' .. seso } );
        end        
    else
        -- Error
        return errorPrinter( {{"formatTest", "Nekonata argumenta formato"}} )
    end
    result.name     = args["name"] or args["nomo"]
    
    local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'}
    for _, v in ipairs( extra_param ) do
        if (args[v] or '') ~= '' then 
            table.insert( errors, {'formatTest', 'Parametro: "' .. v .. '=" estu "' .. v .. ':"' } );
        end
    end
    
    if args['mode'] == "de" then
      if #errors == 0 then
          return specPrinter2( args, result )    
      else
          return specPrinter2( args, result ) .. " " .. errorPrinter(errors) .. '[[Kategorio:Artikoloj kun problemo de koordinatoj]]'; 
      end      
    else  
      if #errors == 0 then
          return specPrinter( args, result )    
      else
          return specPrinter( args, result ) .. " " .. errorPrinter(errors) .. '[[Kategorio:Artikoloj kun problemo de koordinatoj]]'; 
      end    
    end
end

--[[ Helper function, convert the decimal comma to decimal point ]]
function formatPoint(num)
    return mw.ustring.gsub(num, ",", ".")
end
--[[ Helper function, convert longitude U to W or longitude O to E]]
function formatLongEW(dir)
    if dir:upper() == "U" then
        return "W"
    end
    if dir:upper() == "O" then
        return "E"
    end    
    return dir
end

--[[ 
Helper function, convert decimal latitude or longitude to 
degrees, minutes, and seconds format based on the specified precision.  
]]
function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
    local coord = tonumber(coordinate) or 0
    local postfix
    if coord >= 0 then
        postfix = firstPostfix
    else
        postfix = secondPostfix
    end

    precision = precision:lower();
    if precision == "dms" then
        return convert_dec2dms_dms( math.abs( coord ) ) .. postfix;
    elseif precision == "dm" then
        return convert_dec2dms_dm( math.abs( coord ) ) .. postfix;
    elseif precision == "d" then
        return convert_dec2dms_d( math.abs( coord ) ) .. postfix;
    end
end

--[[ Helper function, convert decimal to degrees ]]
function convert_dec2dms_d(coordinate)
    local d = math_mod._round( coordinate, 0 ) .. "°&nbsp;"
    return d .. ""
end

--[[ Helper function, convert decimal to degrees and minutes ]]
function convert_dec2dms_dm(coordinate)    
    coordinate = math_mod._round( coordinate * 60, 0 );
    local m = coordinate % 60;
    coordinate = math.floor( (coordinate - m) / 60 );
    local d = coordinate % 360 .."°&nbsp;"
    
    return d .. string.format( "%02d′&nbsp;", m )
end

--[[ Helper function, convert decimal to degrees, minutes, and seconds ]]
function convert_dec2dms_dms(coordinate)
    coordinate = math_mod._round( coordinate * 60 * 60, 0 );
    local s = coordinate % 60
    coordinate = math.floor( (coordinate - s) / 60 );
    local m = coordinate % 60
    coordinate = math.floor( (coordinate - m) / 60 );
    local d = coordinate % 360 .."°&nbsp;"

    return d .. string.format( "%02d′&nbsp;", m ) .. string.format( "%02d″&nbsp;", s )
end

--[[
Convert DMS format into a N or E decimal coordinate
]]
function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str)
    local degrees = tonumber(degrees_str) or 0
    local minutes = tonumber(minutes_str) or 0
    local seconds = tonumber(seconds_str) or 0
    
    local factor
    direction = mw.ustring.gsub(direction, '^[ ]*(.-)[ ]*$', '%1');
    if direction == "N" or direction == "E" or direction == "O" then
        factor = 1
    else
        factor = -1
    end
    
    local precision = 0
    if seconds_str ~= nil and seconds_str ~= '' then
        precision = 5 + math.max( math_mod._precision(seconds_str), 0 );
    elseif minutes_str ~= nil and minutes_str ~= '' then
        precision = 3 + math.max( math_mod._precision(minutes_str), 0 );
    else
        precision = math.max( math_mod._precision(degrees_str), 0 );
    end
    
    local decimal = factor * (degrees+(minutes+seconds/60)/60) 
    return string.format( "%." .. precision .. "f", decimal ) -- not tonumber since this whole thing is string based.
end

--[[ Helper function 
  Convert decimal into CH1903 - replacement for {{Coordinate/to CH1903}}
]] 
function convert_dec2ch1903(label,lat,lon,prec)
              local errors = {}
              local b_lbl = (label or "" ) ~= "";
              local n     =  math.floor (tonumber(prec) or 0);
              local lat = tonumber(lat)
              local lon = tonumber(lon)
              if( lat < 45.7 or lat > 47.9 or lon < 5.8 or lon > 10.6 ) then
                 --ErrMsg(ErrCode='OOR', ErrFun='WGS84toCH1903',ErrData="keine")
                 table.insert(errors, {"dec2ch1903", "latitudaj gradoj < 45.7 aŭ > 47.9 aŭ longitudaj gradoj < 5.8 aŭ > 10.6"})
              end
              -- genaue Berechnung, Lua kann sich das leisten
              local phi    = (lat * 3600 - 169028.66 ) /10000;
              local lambda = (lon * 3600 - 26782.5) / 10000;
              local x = 200147.07 + 308807.95 * phi    +  3745.25 * lambda^2 +    76.63 * phi^2 + 119.79 * phi^3 - 194.56 * lambda^2 * phi;
              local y = 600072.37 + 211455.93 * lambda - 10938.51 * lambda * phi - 0.36 * lambda * phi^2 - 44.54 * lambda^3;
              x = (math.floor(x* 10^n + 0.5))/10^n;
              y = (math.floor(y* 10^n + 0.5))/10^n;
              x = math_mod._round( x, 0 )
              y = math_mod._round( y, 0 )
              return x .. "", y .. "", errors;
end

--[[ Helper function 
  Convert dms into CH1903 
]] 
function convert_dms2ch1903(lat_f, lat_d, lat_m, lat_s ,long_f, long_d, long_m, long_s)
            local errors = {}
            local label = ""
            local prec = 0
            local lat = convert_dms2dec(lat_f, lat_d, lat_m, lat_s)
            local lon = convert_dms2dec(long_f, long_d, long_m, long_s)
            local x, y = convert_dec2ch1903(label, lat, lon, prec)
            x = tonumber(x) .. ""
            y = tonumber(y) .. ""
            return x, y, errors
end    

--[[ Helper function - replacement for {{Coordinate/to UTM/Easting}}
   ({{{A}}})
 + ( 1 - ({{{T}}}) + ({{{C}}}) ) * ({{{A}}})^3 / 6
 + ( 5 - 18*({{{T}}}) + ({{{T}}})^2 + 72*({{{C}}}) - 0.39089<!--58e²/(1-e²)-->) * ({{{A}}})^5 / 120
]]
function easting (A,T,C)
    local easting = (A) 
      + ( 1 - (T) + (C) ) * (A)^3 / 6 
      + ( 5 - 18*(T) + (T)^2 + 72*(C) - 0.39089) * (A)^5 / 120
    return easting
end    
--[[ Helper function - replacement for {{Coordinate/to UTM/Northing}}
  ({{{A}}})^2 / 2
+ ( 5 - ({{{T}}}) + 9*({{{C}}}) + 4*({{{C}}})^2 ) * ({{{A}}})^4 / 24
+ ( 61 - 58*({{{T}}}) + ({{{T}}})^2 + 600*({{{C}}}) - 2.22403) * ({{{A}}})^6 / 720
]]
function northing (A,T,C)
    local northing = (A)^2 / 2 + ( 5 - (T) + 9*(C) + 4*(C)^2 ) * (A)^4 / 24 + ( 61 - 58*(T) + (T)^2 + 600*(C) - 2.22403) * (A)^6 / 720
    return northing 
end    
 
--[[ Helper function 
  Convert decimal into UTM - replacement for {{Coordinate/to UTM}}
]] 
function convert_dec2utm(label,lat,lon,prec)
              local errors = {}
              local b_lbl = (label or "" ) ~= "";
              local n     =  math.floor (tonumber(prec) or 0);
              local lat = tonumber(lat)
              local lon = tonumber(lon)
              local zonenumber = math.ceil(lon/6)+30
              if lat < 0 then
                  zonedir = "sude"
              else
                  zonedir = "norde"
              end
              local z = math.floor(lat/8)
              if z == -10 then zone = "C"
              elseif z == -9 then zone = "D"
              elseif z == -8 then zone = "E"
              elseif z == -7 then zone = "F"
              elseif z == -6 then zone = "G"
              elseif z == -5 then zone = "H"
              elseif z == -4 then zone = "J"
              elseif z == -3 then zone = "K"
              elseif z == -2 then zone = "L"
              elseif z == -1 then zone = "M"
              elseif z == 0 then zone = "N"
              elseif z == 1 then zone = "P"
              elseif z == 2 then zone = "Q"
              elseif z == 3 then zone = "R"
              elseif z == 4 then zone = "S"
              elseif z == 5 then zone = "T"
              elseif z == 6 then zone = "U"
              elseif z == 7 then zone = "V"
              elseif z == 8 then zone = "W"
              elseif z == 9 then zone = "X"
              elseif math.abs(lat-78) <= 6 then zone = "X"    
              else table.insert(errors, {"dec2utm", "latitudaj gradoj estas ekster la eblaj valoroj."})      
                  if lat > 0 then
                      if lon > 0 then zone = "B"
                      else zone = "A"  
                      end
                  else 
                      if lon > 0 then zone = "Z"
                      else zone = "Y"
                      end
                  end
              end 
              local k_0 = 0.9996
              local a = 6378137
              local pi = 3.1415926535898
              local A = (lon - math.ceil(lon/6) * 6 + 3)/180*pi * math.cos(lat/180*pi)
              local T = math.tan(lat/180*pi)^2
              local C = 0.0067394968 * math.cos(lat/180*pi)^2
              local y = 500000 + k_0 * a / ( 1 - 0.00669438 * math.sin(lat/180*pi)^2 )^.5 * easting(A,T,C);
              if lat < 0 then 
                  x1 = 1
              else
                  x1 = 0
              end
              local x = x1*10000000 + k_0 * a * (0.9983243 * ( lat/180*pi) - 2.51460708e-3 * math.sin(2 * lat/180*pi) 
                + 2.63904664e-6 * math.sin(4 * lat/180*pi) - 3.41804618e-9 * math.sin(6 * lat/180*pi) 
                + math.tan(lat/180*pi) / ( 1 - 0.00669438 * math.sin(lat/180*pi)^2 )^.5 * (northing(A,T,C) ) ); 
              x = math_mod._round( x, 0 )
              y = math_mod._round( y, 0 )
              return zonenumber .. "", zonedir .. "", zone .. "", x .. "", y .. "", errors;
end

--[[ Helper function 
  Convert dms into UTM 
]] 
function convert_dms2utm(lat_f, lat_d, lat_m, lat_s ,long_f, long_d, long_m, long_s)
            local errors = {}
            local label = ""
            local prec = 0
            local lat = convert_dms2dec(lat_f, lat_d, lat_m, lat_s)
            local lon = convert_dms2dec(long_f, long_d, long_m, long_s)
            local zonenumber, zonedir, zone, x, y = convert_dec2utm(label, lat, lon, prec)
            x = tonumber(x) .. ""
            y = tonumber(y) .. ""
            return zonenumber, zonedir, zone, x, y, errors
end  

--[[ 
Checks input values to for out of range errors.
]]
function validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, source, strong )
    local errors = {};
    lat_d = tonumber( lat_d ) or 0;
    lat_m = tonumber( lat_m ) or 0;
    lat_s = tonumber( lat_s ) or 0;
    long_d = tonumber( long_d ) or 0;
    long_m = tonumber( long_m ) or 0;
    long_s = tonumber( long_s ) or 0;

    if strong then
        if lat_d < 0 then
            table.insert(errors, {source, "latitudaj gradoj < 0 kun hemisfera flago"})
        end
        if long_d < 0 then
            table.insert(errors, {source, "longitudaj gradoj < 0 kun hemisfera flago"})
        end
        --[[ 
        #coordinates is inconsistent about whether this is an error.  If globe: is
        specified, it won't error on this condition, but otherwise it will.
        
        For not simply disable this check.
        
        if long_d > 180 then
            table.insert(errors, {source, "longitude degrees > 180 with hemisphere flag"})
        end
        ]]
    end    
        
    if lat_d > 90 then
        table.insert(errors, {source, "latitudaj gradoj > 90"})
    end
    if lat_d < -90 then
        table.insert(errors, {source, "latitudaj gradoj < -90"})
    end
    if lat_m >= 60 then
        table.insert(errors, {source, "latitudaj minutoj >= 60"})
    end
    if lat_m < 0 then
        table.insert(errors, {source, "latitudaj minutoj < 0"})
    end
    if lat_s >= 60 then
        table.insert(errors, {source, "latitudaj sekundoj >= 60"})
    end
    if lat_s < 0 then
        table.insert(errors, {source, "latitudaj sekundoj < 0"})
    end
    if long_d >= 360 then
        table.insert(errors, {source, "longitudaj gradoj >= 360"})
    end
    if long_d <= -360 then
        table.insert(errors, {source, "longitudaj gradoj <= -360"})
    end
    if long_m >= 60 then
        table.insert(errors, {source, "longitudaj minutoj >= 60"})
    end
    if long_m < 0 then
        table.insert(errors, {source, "longitudaj minutoj < 0"})
    end
    if long_s >= 60 then
        table.insert(errors, {source, "longitudaj sekundoj >= 60"})
    end
    if long_s < 0 then
        table.insert(errors, {source, "longitudaj sekundoj < 0"})
    end
    
    return errors;
end

--[[
dec2dms

Wrapper to allow templates to call dec2dms directly.

Usage:
    {{ Invoke:Coordinates | dec2dms | decimal_coordinate | positive_suffix | 
        negative_suffix | precision }}
    
decimal_coordinate is converted to DMS format.  If positive, the positive_suffix
is appended (typical N or E), if negative, the negative suffix is appended.  The
specified precision is one of 'D', 'DM', or 'DMS' to specify the level of detail
to use.
]]
function coordinates.dec2dms(frame)
    globalFrame = frame
    local coordinate = frame.args[1]
    local firstPostfix = frame.args[2]
    local secondPostfix = frame.args[3]
    local precision = frame.args[4]

    return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
end

--[[ Wrapper to allow templates to call dec2ch1903 directly 
]]
function coordinates.dec2ch1903 (frame)
    globaFrame = frame
    local label = frame.args[1]
    local lat = frame.args[2]
    local lon = frame.args[3]
    local prec = frame.args[4]
    local text = ""
    local x, y = convert_dec2ch1903(label,lat,lon, prec)
    if label ~= "" and label ~= nil then
        text = '<span title="Svislandaj landaj koordinatoj">CH1903:&nbsp;</span>'
        .. '<span title="y easting">' .. y .. '</span>&nbsp;/&nbsp;'        
        .. '<span title="x northing">' .. x .. '</span>' 
    else
        text = "CH1903: " .. y .. " / " .. x
    end    
    return text
end    

--[[ Wrapper to allow templates to call dec2utm directly 
]]
function coordinates.dec2utm (frame)
    globaFrame = frame
    local label = frame.args[1]
    local lat = frame.args[2]
    local lon = frame.args[3]
    local prec = frame.args[4]
    local text = ""
    local zonenumber, zonedir, zone, x, y = convert_dec2utm(label,lat,lon, prec)
    -- if label ~= "" and label ~= nil then
        text = '<span title="Universal Transverse Mercator, baziĝanta sur WGS84">UTM:&nbsp;</span>'
        .. 'Zono&nbsp;<span title="Zononumero">' .. zonenumber .. '</span>'
        .. '<span title="Zonobendo, ' .. zonedir .. ' de la ekvatoro">' .. zone .. '</span>, '
        .. '<span title="easting">' .. y .. '</span>&nbsp;/&nbsp;'        
        .. '<span title="northing">' .. x .. '</span>' 
    -- else
       -- text = "CH1903: " .. y .. " / " .. x
    -- end    
    return text
end

--[[
Helper function to determine whether to use D, DM, or DMS
format depending on the precision of the decimal input.
]]
function coordinates.determineMode( value1, value2 )
    local precision = math.max( math_mod._precision( value1 ), math_mod._precision( value2 ) );
    if precision <= 0 then
        return 'd'
    elseif precision <= 2 then
        return 'dm';
    else
        return 'dms';
    end
end        

--[[
dms2dec

Wrapper to allow templates to call dms2dec directly.

Usage:
    {{ Invoke:Coordinates | dms2dec | direction_flag | degrees | 
        minutes | seconds }}
    
Converts DMS values specified as degrees, minutes, seconds too decimal format.
direction_flag is one of N, S, E, W, and determines whether the output is 
positive (i.e. N and E) or negative (i.e. S and W).
]]
function coordinates.dms2dec(frame)
    globalFrame = frame
    
    local direction = frame.args[1]
    local degrees = frame.args[2]
    local minutes = frame.args[3]
    local seconds = frame.args[4]  
    
    if frame.args[2] == nil then 
        local explode=mw.text.split( frame.args[1], '/' )
        if (#explode > 1) then
            direction = explode[#explode]
            degrees = explode[1]
        else
            local sign, val=string.match (explode[1], '([\-]*)([%d.]*)')
            if sign == '-' then direction='S' else direction='N' end
            degrees = val
        end    
        if(#explode>2) then 
            minutes = explode[2]
        end
        if(#explode>3) then 
            seconds = explode[3]
        end
    end     

    return convert_dms2dec(direction, degrees, minutes, seconds)
end

--[[
dms2ch1903

Wrapper to allow templates to call dms2ch1903 directly.

Usage:
    {{ Invoke:Coordinates | dms2ch1903 | direction_flag1 | degrees | 
        minutes | seconds | direction_flag2 | degrees | minutes | seconds }}
    
Converts DMS values specified as degrees, minutes, seconds too format of Swiss coordinates.
direction_flag1 is one of N, S and direction_flag2 is one of E, W, and determines whether the output is 
positive (i.e. N and E) or negative (i.e. S and W).
]]
function coordinates.dms2ch1903(frame)
    globalFrame = frame
    
    local lat_f = frame.args[1]
    local lat_d = frame.args[2]
    local lat_m = frame.args[3]
    local lat_s = frame.args[4]
    local long_f = frame.args[5]
    local long_d = frame.args[6]
    local long_m = frame.args[7]
    local long_s = frame.args[8]
    local label = frame.args['label']
    local text = ""
    
    if frame.args[3] == nil then 
        local explode1=mw.text.split( frame.args[1]:match( '^%s*(.-)%s*$' ), '/' )
        local explode2=mw.text.split( frame.args[2]:match( '^%s*(.-)%s*$' ), '/' )  
        --latitude
        if (#explode1 > 1) then
            lat_f = explode1[#explode1]
            lat_d = explode1[1]
        else
            local sign, val=string.match (explode1[1], '([\-]*)([%d.]*)')
            if sign == '-' then lat_f='S' else lat_f='N' end
            lat_d = val
        end    
        if(#explode1>2) then 
            lat_m = explode1[2]
        end
        if(#explode1>3) then 
            lat_s = explode1[3]
        end
        --longitude
        if (#explode2 > 1) then
            long_f = explode2[#explode2]
            long_d = explode2[1]
        else
            local sign, val=string.match (explode2[1], '([\-]*)([%d.]*)')
            if sign == '-' then long_f='W' else long_f='E' end
            long_d = val
        end    
        if(#explode2>2) then 
            long_m = explode2[2]
        end
        if(#explode2>3) then 
            long_s = explode2[3]
        end
    end     
    
    local x, y = convert_dms2ch1903(lat_f, lat_d, lat_m, lat_s, long_f, long_d, long_m, long_s)
    if label ~= "" and label ~= nil then
        text = '<span title="Svislandaj landaj koordinatoj">CH1903:&nbsp;</span>'
        .. '<span title="y easting">' .. y .. '</span>&nbsp;/&nbsp;'        
        .. '<span title="x northing">' .. x .. '</span>' 
    else
        text = "CH1903: " .. y .. " / " .. x
    end    
    return text
end    

--[[
dms2utm

Wrapper to allow templates to call dms2utm directly.

Usage:
    {{ Invoke:Coordinates | dms2utm | direction_flag1 | degrees | 
        minutes | seconds | direction_flag2 | degrees | minutes | seconds }}
    
Converts DMS values specified as degrees, minutes, seconds too format of Swiss coordinates.
direction_flag1 is one of N, S and direction_flag2 is one of E, W, and determines whether the output is 
positive (i.e. N and E) or negative (i.e. S and W).
]]
function coordinates.dms2utm(frame)
    globalFrame = frame
    
    local lat_f = frame.args[1]
    local lat_d = frame.args[2]
    local lat_m = frame.args[3]
    local lat_s = frame.args[4]
    local long_f = frame.args[5]
    local long_d = frame.args[6]
    local long_m = frame.args[7]
    local long_s = frame.args[8]
    local label = frame.args['label']
    local text = ""
    
    if frame.args[3] == nil then 
        local explode1=mw.text.split( frame.args[1]:match( '^%s*(.-)%s*$' ), '/' )
        local explode2=mw.text.split( frame.args[2]:match( '^%s*(.-)%s*$' ), '/' )  
        --latitude
        if (#explode1 > 1) then
            lat_f = explode1[#explode1]
            lat_d = explode1[1]
        else
            local sign, val=string.match (explode1[1], '([\-]*)([%d.]*)')
            if sign == '-' then lat_f='S' else lat_f='N' end
            lat_d = val
        end    
        if(#explode1>2) then 
            lat_m = explode1[2]
        end
        if(#explode1>3) then 
            lat_s = explode1[3]
        end
        --longitude
        if (#explode2 > 1) then
            long_f = explode2[#explode2]
            long_d = explode2[1]
        else
            local sign, val=string.match (explode2[1], '([\-]*)([%d.]*)')
            if sign == '-' then long_f='W' else long_f='E' end
            long_d = val
        end    
        if(#explode2>2) then 
            long_m = explode2[2]
        end
        if(#explode2>3) then 
            long_s = explode2[3]
        end
    end     
    
    local zonenumber, zonedir, zone, x, y = convert_dms2utm(lat_f, lat_d, lat_m, lat_s, long_f, long_d, long_m, long_s)
    -- if label ~= "" and label ~= nil then
        text = '<span title="Universal Transverse Mercator, baziĝanta sur WGS84">UTM:&nbsp;</span>'
        .. 'Zono&nbsp;<span title="Zononumero">' .. zonenumber .. '</span>'
        .. '<span title="Zonobendo, ' .. zonedir .. ' de la ekvatoro">' .. zone .. '</span>, '
        .. '<span title="easting">' .. y .. '</span>&nbsp;/&nbsp;'        
        .. '<span title="northing">' .. x .. '</span>' 
    -- else
       -- text = "CH1903: " .. y .. " / " .. x
    -- end     
    return text
end 

--[[ Helper function, returns values for "display", if the parameter "montru" is used instead
if the given text in "montru" is empty, it returns nil
if the given text in "montru" isn't empty, it returns an utilizable value
]]
function coordinates.montru (montru)
    local text = ""
    -- if montru isn't empty, then it changes the text in "montru" in lower case letters
    if montru ~= "" and montru ~= nil then montru = string.lower(montru)
       -- it analyzes the text
       if string.find(montru, "titolo") ~= nil then text = "title"
       end    
       if string.find(montru, "entekste") ~= nil then 
           if text == "" then text = "inline" 
           else text = "inline," .. text
           end    
       end    
    -- elseif montru == nil then text = montru    
    end     
    return text
end    

--[[ Helper function, returns values for "format", if the paramter "formato" is used instead
if the given text in "formato" is empty, it returns nil
if the given text in "formato" isn't empty, it returns an utilizable value
]]
function coordinates.formato (formato)
    local text = ""
    if formato ~= nil and formato ~= "" then
       -- if formato isn't empty, then it changes the text in "formato" into lower case letters 
       formato = string.lower(formato)
       -- the value of formato is analyzed
       if formato == "gms" or formato == "dms" then text = "dms"
       elseif formato == "gm" or formato == "dm" then text = "dm"
       elseif formato == "g" or formato == "grado" or formato == "d" then text = "d"       	
       elseif formato == "gms-longa" or formato == "gms longa" or formato == "dms long" then text = "dms long"   
       elseif formato == "dek" or formato == "dec" then text = "dec"   
       -- if there is a nonsense text in "formato", then it returns "dms"  
       else text = "dms"    
       end
    else text = formato   
    end   
    return text
end    

--[[ Helper function, for {{Koordinato}}, which returns values for "format", if the paramter "formato" is used instead
if the given text in "formato" is empty, it returns nil
if the given text in "formato" isn't empty, it returns an utilizable value
]]
function coordinates.formattext (formato)
    local text = ""
    if formato ~= nil and formato ~= "" then
       -- if formato isn't empty, then it changes the text in "formato" into lower case letters 
       formato = string.lower(formato)
       -- the value of formato is analyzed
       if formato == "gms" or formato == "dms" then text = "dms"
       elseif formato == "gm" or formato == "dm" then text = "dm"
       elseif formato == "g" or formato == "grado" or formato == "d" then text = "d"       	
       elseif formato == "gms-longa" or formato == "gms longa" or formato == "dms long" then text = "dms long"   
       -- addition for {{Koordinato}}
       elseif formato == "ch1903" then text = formato
       elseif formato == "utm" then text = formato
       elseif formato == "dek" or formato == "dec" then text = "dec"   
       -- some icons for {{Koordinato}}
       elseif formato == "icon0" or formato == "icon1" or formato == "icon2" then text = formato
       -- any image with the name space prefix
       elseif mw.ustring.lower(mw.ustring.sub(formato,1,5)) == "file:" or mw.ustring.lower(mw.ustring.sub(formato,1,6)) == "image:"
           or mw.ustring.lower(mw.ustring.sub(formato,1,8)) == "dosiero:" then text = formato
       -- if there is an other text in "formato", then it returns dms  
       else text = "dms" 
       end
    else text = formato   
    end   
    return text
end    

--[[ Helper function, chiefly for {{Koordinato}}, which returns values for "formatitle", if the paramter "titolformato" is used instead
if the given text in "formato" is empty, it returns nil
if the given text in "formato" isn't empty, it returns an utilizable value
]]
function coordinates.formatarticle (formato)
    local text = ""
    if formato ~= nil and formato ~= "" then
       -- if formato isn't empty, then it changes the text in "formato" into lower case letters 
       formato = string.lower(formato)
       -- the value of formato is analyzed
       if formato == "gms" or formato == "dms" then text = "dms"
       elseif formato == "gm" or formato == "dm" then text = "dm"	
       elseif formato == "g" or formato == "grado" or formato == "d" then text = "d"	       	
       elseif formato == "gms-longa" or formato == "gms longa" or formato == "dms long" then text = "dms long"   
       -- addition for {{Koordinato}}
       elseif formato == "ch1903" then text = formato
       elseif formato == "dek" or formato == "dec" then text = "dec"   
       -- if there is an other text in "formato", then it returns dms  
       else text = "dms" 
       end
    else text = formato   
    end   
    return text
end    

--[[
coord

Main entry point for Lua function to replace {{coord}}

Usage:
    {{ Invoke:Coordinates | coord }}
    {{ Invoke:Coordinates | coord | lat | long }}
    {{ Invoke:Coordinates | coord | lat | lat_flag | long | long_flag }}
    ...
    
    Refer to {{coord}} documentation page for many additional parameters and 
    configuration options.
    
Note: This function provides the visual display elements of {{coord}}.  In
order to load coordinates into the database, the {{#coordinates:}} parser 
function must also be called, this is done automatically in the Lua
version of {{coord}}.
]]
function coordinates.coord(frame)
    globalFrame = frame
    
    local text = ''
    
    local args = frame.args
    if args[1] == nil then
        local pFrame = frame:getParent();
        args = pFrame.args;
        for k,v in pairs( frame.args ) do
            args[k] = v;
        end
    end
    
    for i=1,10 do 
        if args[i] == nil then 
            args[i] = ""
        else
            args[i] = args[i]:match( '^%s*(.-)%s*$' );  --remove whitespace
        end        
    end
    if args['mode'] == "de" then
        args['format'] = coordinates.formattext(args['format']) or coordinates.formattext(args['formato']) or '';
    else    
        args['format'] = coordinates.formato(args['format']) or coordinates.formato(args['formato']) or '';
    end
    args['name'] = args['name'] or args['nomo']
    args['category'] = args['category'] or args['kategorio'];
    args['link'] = args['link'] or args['ligu'];

    local latdms=mw.text.split( args[1], '/' )
    local lngdms=mw.text.split( args[2], '/' )
    if #latdms > 1 or #lngdms >1 then 
        -- je copie
        local argsN=mw.clone(args)   
        local i = 1 -- point de départ
        local ia = 1 -- point de départ
        while (latdms[i] ~= nil) do
          args[ia]=mw.text.trim(latdms[i])
          i = i + 1
          ia = ia +1
        end
        local i = 1 -- point de départ
        while (lngdms[i] ~= nil) do
          args[ia]=mw.text.trim(lngdms[i])
          i = i + 1
          ia = ia +1
        end
        local i = 3 -- point de départ
        while (argsN[i] ~= nil) do
          args[ia]=argsN[i]
          i = i + 1
          ia = ia +1
        end
    end       
    
    --definition of the planete
    local astre
    for _, l in ipairs(args) do
        for w in string.gmatch(l, "globe:(%a+)") do
            astre=w
            break
        end
    end    
    
    local contents = formatTest(args)
    local Notes = args.notes or ""
    local Display = string.lower(args.display or coordinates.montru(args.montru) or "inline")
    if Display == '' then
        Display = 'inline';
    end
    
    local havedisplay = "";
 
    if string.find( Display, 'inline' ) ~= nil or Display == 'i' or 
            Display == 'it' or Display == 'ti'  or (args['category'] ~= "" and args['category'] ~= nil) 
            or args['link'] == "ne" or args['link']  == "no" then
        text = text .. displayinline(contents, Notes)
        havedisplay = havedisplay .. "i";
    end
    if (args['category'] == "" or args['category'] == nil) and (args['link'] == "" 
    	or args['link'] == nil or args['link'] == "jes" or args['link'] == "yes") then 
       if string.find( Display, 'title' ) ~= nil or Display == 't' or 
              Display == 'it' or Display == 'ti' then
           if args['formatitle'] ~= nil then
              args['format'] = args['formatitle'] or args['format']
              contents = formatTest(args)
           end   
           text = text .. displaytitle(contents, Notes, astre)
           args['geodata']="primary"
           text = text ..  globalFrame:preprocess(formatTest(args) )
 
           havedisplay = havedisplay .. "t";
       end
    end
 
    if havedisplay == "" then
        --rien n'a été affiché!
        text = text .. displayinline(contents, Notes) .. errorPrinter( {{"display", "argumento display estas malĝusta"}} )
 
    end 

    return text
end

function coordinates.Coord(frame)
    return coordinates.coord(frame)
end

--[[ coord2 - variant of coord for use in Modulo:Coordinates2
]]
function coordinates.coord2(frame)
        globalFrame = frame.args.gf 
        local origArgs = {}
 
             if frame == mw.getCurrentFrame() then
                 origArgs = frame:getParent().args
             else        
                 origArgs = frame.args
             end
 
         args = {}
            for k, v in pairs(origArgs) do                 
                     args[k] = v                    
            end
    for i=1,10 do 
        if args[i] == nil then 
            args[i] = ""
        else
            args[i] = args[i]:match( '^%s*(.-)%s*$' );  --remove whitespace
        end        
    end

    args['format'] = coordinates.formattext(args['format']) or coordinates.formattext(args['formato']) or '';        
    args['formatitle'] = coordinates.formatarticle(args['formatitle']) or coordinates.formatarticle(args['titolformato']) -- or '';
    args['name'] = args['name'] or args['nomo']
    args['category'] = args['category'] or args['kategorio'];
    args['mode'] = "de"

    local latdms=mw.text.split( args[1], '/' )
    local lngdms=mw.text.split( args[2], '/' )
    if #latdms > 1 or #lngdms >1 then 
        -- je copie
        local argsN=mw.clone(args)   
        local i = 1 -- point de départ
        local ia = 1 -- point de départ
        while (latdms[i] ~= nil) do
          args[ia]=mw.text.trim(latdms[i])
          i = i + 1
          ia = ia +1
        end
        local i = 1 -- point de départ
        while (lngdms[i] ~= nil) do
          args[ia]=mw.text.trim(lngdms[i])
          i = i + 1
          ia = ia +1
        end
        local i = 3 -- point de départ
        while (argsN[i] ~= nil) do
          args[ia]=argsN[i]
          i = i + 1
          ia = ia +1
        end
    end       

    local contents = formatTest(args)
    local Notes = args.notes or ""
    -- local Display = string.lower(args.display or coordinates.montru(args.montru) or "inline")
    local Display = string.lower(args.display or "inline")    
    if Display == '' then
        Display = 'inline';
    end
    
    local text = ''
    if string.find( Display, 'inline' ) ~= nil or Display == 'i' or 
            Display == 'it' or Display == 'ti' or (args['category'] ~= "" and args['category'] ~= nil) then
        text = displayinline(contents, Notes)
        isInline = "yes"
    else isInline = "no"    
    end
    if args['category'] == "" or args['category'] == nil then
        -- creates the code for the microformat
        args['micro'] = "yes"
        content = formatTest(args)
        args['micro'] = ""
        text = text .. content -- adds it to the return string
      if string.find( Display, 'title' ) ~= nil or Display == 't' or 
            Display == 'it' or Display == 'ti' then
        -- a helper parameter for uses, if there are more than one format for the coordinates              
        args['second'] = "yes"  
        if args['formatitle'] ~= nil then
            args['format'] = args['formatitle'] -- or args['format']
            contents = formatTest(args)
        end           
        if isInline == "no" then
            -- a little bit tricky methode to put in an information about the tags to be used
            contents = "(div)" .. contents  
        else contents = "(span)" .. contents      
        end
        text = text .. displaytitle(contents, Notes)
      end    
    end
    if string.find( Display, 'project' ) ~= nil then
        -- message from {{CoordinateNOx}}. but its HTML-code is elsewhere
        text = displaytitle2('Koordinatoj mankas! [[Projekto:Geografiaj koordinatoj|Bonvolu kunhelpi]]',"background:#FFC")
    end        
    return text
end

return coordinates