Wiki - KEONHACAI COPA

Mô đun:Coordinates/sandbox

Tài liệu mô đun[tạo]
--[[
Mô đun này hỗ trợ {{Coord}} và các bản mẫu liên quan. Nó cung cấp vài
phương thức, nhất là:

{{#gọi:Coordinates | coord }} : Hàm tổng quát để định dạng và hiển thị các giá
trị tọa độ.

{{#gọi:Coordinates | dec2dms }} : Hàm đơn giản để chuyển đổi các giá trị thập
phân ra định dạng độ-phút-giây.

{{#gọi:Coordinates | dms2dec }} : Hàm đơn giản để chuyển đổi định dạng
độ-phút-giây ra định dạng độ thập phân.

{{#gọi:Coordinates | link }} : Xuất địa chỉ của các công cụ

]]

require('strict')

local math_mod = require("Mô đun:Math")
local coordinates = {};

local current_page = mw.title.getCurrentTitle()
local page_name = mw.uri.encode( current_page.prefixedText, 'WIKI' );
local coord_link = '//tools.wmflabs.org/geohack/geohack.php?language=vi&pagename=' .. page_name .. '&params='

-- Định dạng các số theo quy tắc tiếng Việt (thí dụ 1.234,56).
local lang = mw.getContentLanguage()

--[[ Hàm hỗ trợ thay thế {{coord/display/title}} ]]
local function displaytitle(s, notes)
	local l = "[[Hệ tọa độ địa lý|Tọa độ]]: " .. s
	local co = '<span id="coordinates">' .. l .. notes .. '</span>';
	return '<span style="font-size: small;">' .. co .. '</span>';
end

--[[ Hàm hỗ trợ thay thế {{coord/display/inline}} ]]
local function displayinline(s, notes)
	return s .. notes	
end

--[[ Hàm hỗ trợ được sử dụng để nhận ra định dạng độ-phút-giây. ]]
local function dmsTest(first, second)
	if type(first) ~= 'string' or type(second) ~= 'string' then
		return nil
	end
	local s = (first .. second):upper()
	return s:find('^[NS][EW]$') or s:find('^[EW][NS]$')
end


--[[ Wrapper function to grab args, see Mô đun:Arguments for this function's documentation. ]]
local function makeInvokeFunc(funcName)
	return function (frame)
		local args = require('Mô đun:Arguments').getArgs(frame, {
			wrappers = 'Bản mẫu:Tọa độ'
		})
		return coordinates[funcName](args, frame)
	end
end

--[[ Helper function, handle optional args. ]]
local function optionalArg(arg, supplement)
	return arg and arg .. supplement or ''
end

--[[
Định dạng những thông báo lỗi cần hiển thị.
]]
local function errorPrinter(errors)
	local result = ""
	for i,v in ipairs(errors) do
		local errorHTML = '<strong class="error">Tọa độ: ' .. v[2] .. '</strong>'
		result = result .. errorHTML .. "<br />"
	end
	return result
end

--[[
Tính lớp CSS cần để hiển thị tọa độ.

Bảng kiểu CSS thường ẩn geo-nondefault, trừ khi một nguời dùng đã ghi đè thiết lập này.
default là chế độ do nguời dùng định rõ khi nhúng {{coord}}.
mode là chế độ hiển thị (dec hoặc dms) dùng để tính lớp CSS.
]]
local function displayDefault(default, mode)
	if default == "" then
		default = "dec"
	end
	
	if default == mode then
		return "geo-default"
	else
		return "geo-nondefault"
	end
end

--[[
specPrinter

Hàm định dạng giá trị cho ra. Lấy cấu trúc do parseDec hoặc parseDMS tạo ra và
định dạng nó để nhúng vào Wikipedia.
]]
local function specPrinter(args, coordinateSpec)
	local uriComponents = coordinateSpec["param"]
	if uriComponents == "" then
		-- RETURN error, should never be empty or nil
		return "LỖI tham số trống"
	end
	if args["name"] then
		uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"])
	end
	
	local geodmshtml = '<span class="geo-dms" title="Bản đồ, ảnh không trung, và các dữ liệu khác cho vị trí này">'
			 .. '<span class="latitude">' .. coordinateSpec["dms-lat"] .. '</span> '
			 .. '<span class="longitude">' ..coordinateSpec["dms-long"] .. '</span>'
			 .. '</span>'

	local lat = tonumber( coordinateSpec["dec-lat"] ) or 0
	local geodeclat
	if lat < 0 then
		-- FIXME this breaks the pre-existing precision
		geodeclat = tostring(coordinateSpec["dec-lat"]):sub(2) .. "°N"
	else
		geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°B"
	end

	local long = tonumber( coordinateSpec["dec-long"] ) or 0
	local geodeclong
	if long < 0 then
		-- FIXME does not handle unicode minus
		geodeclong = tostring(coordinateSpec["dec-long"]):sub(2) .. "°T"
	else
		geodeclong = (coordinateSpec["dec-long"] or 0) .. "°Đ"
	end
	
	local geodechtml = '<span class="geo-dec" title="Bản đồ, ảnh không trung, và các dữ liệu khác cho vị trí này">'
			 .. geodeclat .. ' '
			 .. geodeclong
			 .. '</span>'

	local geonumhtml = '<span class="geo">'
			 .. coordinateSpec["dec-lat"] .. '; '
			 .. coordinateSpec["dec-long"]
			 .. '</span>'

	local inner = '<span class="' .. displayDefault(coordinateSpec["default"], "dms" ) .. '">' .. geodmshtml .. '</span>'
				.. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
				.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';

	if not args["name"] 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

	return '<span class="plainlinks nourlexpansion">' .. 
		'[' .. coord_link .. uriComponents .. ' ' .. inner .. ']' .. '</span>'
end

--[[ Hàm hỗ trợ chuyển đổi số thập phân thành độ. ]]
local function convert_dec2dms_d(coordinate)
	local d = math_mod._round( coordinate, 0 ) .. "°"
	return d .. ""
end

--[[ Hàm hỗ trợ chuyển đổi số thập phân thành độ và phút. ]]
local 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 .."°"
	
	return d .. string.format( "%02d′", m )
end

--[[ Hàm hỗ trợ chuyển đổi số thập phân thành độ, phút, và giây. ]]
local 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 .."°"

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

--[[
Hàm hỗ trợ chuyển đổi vĩ độ hoặc kinh độ thập phân thành định dạng độ-phút-giây
theo độ chính xác được định rõ.
]]
local function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
	local coord = tonumber(coordinate)
	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

--[[
Chuyển đổi định dạng độ-phút-giây thành tọa độ thập phân B hay Đ.
]]
local function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str)
	local degrees = tonumber(degrees_str)
	local minutes = tonumber(minutes_str) or 0
	local seconds = tonumber(seconds_str) or 0
	
	local factor = 1
	if direction == "S" or direction == "W" then
		factor = -1
	end
	
	local precision = 0
	if seconds_str then
		precision = 5 + math.max( math_mod._precision(seconds_str), 0 );
	elseif minutes_str 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

--[[
Kiểm tra các giá trị cho vào để nhận ra lỗi không đúng phạm vi.
]]
local 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, "vĩ độ < 0 có chữ bán cầu"})
		end
		if long_d < 0 then
			table.insert(errors, {source, "kinh độ < 0 có chữ bán cầu"})
		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, "vĩ độ > 90"})
	end
	if lat_d < -90 then
		table.insert(errors, {source, "vĩ độ < -90"})
	end
	if lat_m >= 60 then
		table.insert(errors, {source, "vĩ phút >= 60"})
	end
	if lat_m < 0 then
		table.insert(errors, {source, "vĩ phút < 0"})
	end
	if lat_s >= 60 then
		table.insert(errors, {source, "vĩ giây >= 60"})
	end
	if lat_s < 0 then
		table.insert(errors, {source, "vĩ giây < 0"})
	end
	if long_d >= 360 then
		table.insert(errors, {source, "kinh độ >= 360"})
	end
	if long_d <= -360 then
		table.insert(errors, {source, "kinh độ <= -360"})
	end
	if long_m >= 60 then
		table.insert(errors, {source, "kinh phút >= 60"})
	end
	if long_m < 0 then
		table.insert(errors, {source, "kinh phút < 0"})
	end
	if long_s >= 60 then
		table.insert(errors, {source, "kinh giây >= 60"})
	end
	if long_s < 0 then
		table.insert(errors, {source, "kinh giây < 0"})
	end
	
	return errors;
end

--[[
parseDec

Biến đổi vĩ độ và kinh độ thành một cấu trúc để hiển thị tọa độ.
]]
local function parseDec( lat, long, format )
	local coordinateSpec = {}
	local errors = {}
	
	if not long then
		return nil, {{"parseDec", "Thiếu kinh độ"}}
	elseif not tonumber(long) then
		return nil, {{"parseDec", "Không thể phân tích số từ kinh độ: " .. 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, "B", "N", mode)  -- {{coord/dec2dms|{{{1}}}|B|N|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
	coordinateSpec["dms-long"] = convert_dec2dms( long, "Đ", "T", mode)  -- {{coord/dec2dms|{{{2}}}|Đ|T|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}	
	
	if format then
		coordinateSpec.default = format
	else
		coordinateSpec.default = "dec"
	end

	return coordinateSpec, errors
end

--[[
parseDMS

Biến đổi vĩ độ và kinh độ dưới dạng độ-phút-giây thành cấu trúc để hiển thị các
tọa độ.
]]
local function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format )
	local coordinateSpec, errors, backward = {}, {}
	
	lat_f = lat_f:upper();
	long_f = long_f:upper();
	
	-- Nhận các chữ bán cầu tiếng Việt.
	if long_f == "B" or lat_f == "Đ" or lat_f == "T" then
		local englishFlags = {B = "N", N = "S", T = "W", ["Đ"] = "E"}
		local lat_f = englishFlags[lat_f] or lat_f
		local long_f = englishFlags[long_f] or long_f
	end
	
	-- Check if specified backward
	if lat_f == 'E' or lat_f == 'W' then
		lat_d, long_d, lat_m, long_m, lat_s, long_s, lat_f, long_f, backward = long_d, lat_d, long_m, lat_m, long_s, lat_s, long_f, lat_f, true;
	end	
	
	errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true );
	if not long_d then
		return nil, {{"parseDMS", "Thiếu kinh độ" }}
	elseif not tonumber(long_d) then
		return nil, {{"parseDMS", "Không thể phân tích số từ kinh độ:" .. long_d }}
	end
	
	if not lat_m and not lat_s and not long_m and not long_s 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' then 
				long_d = '-' .. long_d;
			end
			
			return parseDec( lat_d, long_d, format );
		end		
	end   

	-- Việt hóa các chữ bán cầu.
	local vietFlags = {N = "B", S = "N", W = "T", E = "Đ"}
	local viet_lat_f = vietFlags[lat_f:upper()] or lat_f
	local viet_long_f = vietFlags[long_f:upper()] or long_f
	
	-- Định dạng các số thập phân.
	if tonumber(lat_s) then lat_s = lang:formatNum(tonumber(lat_s)) end
	if tonumber(long_s) then long_s = lang:formatNum(tonumber(long_s)) end
	
	coordinateSpec["dms-lat"]  = lat_d.."°"..optionalArg(lat_m,"′") .. optionalArg(lat_s,"″") .. viet_lat_f
	coordinateSpec["dms-long"] = long_d.."°"..optionalArg(long_m,"′") .. optionalArg(long_s,"″") .. viet_long_f
	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}}}}}

	if format then
		coordinateSpec.default = format
	else
		coordinateSpec.default = "dms"
	end   

	return coordinateSpec, errors, backward
end

--[[
Kiểm tra các đối số cho vào để nhận ra kiểu dữ liệu được cung cấp và xử lý đúng
cách.
]]
local function formatTest(args)
	local result, errors
	local backward, primary = false, false

	local function getParam(args, lim)
		local ret = {}
		for i = 1, lim do
			ret[i] = args[i] or ''
		end
		return table.concat(ret, '_')
	end
	
	if not args[1] then
		-- no lat logic
		return errorPrinter( {{"formatTest", "Thiếu vĩ độ"}} )
	elseif not tonumber(args[1]) then
		-- bad lat logic
		return errorPrinter( {{"formatTest", "Không thể phân tích số từ vĩ độ:" .. args[1]}} )
	elseif not args[4] and not args[5] and not args[6] then
		-- dec logic
		result, errors = parseDec(args[1], args[2], args.format)
		if not result then
			return errorPrinter(errors);
		end
		result.param = table.concat({args[1], 'N', args[2] or '', 'E', args[3] or ''}, '_')
	elseif dmsTest(args[4], args[8]) then
		-- dms logic
		result, errors, backward = parseDMS(args[1], args[2], args[3], args[4], 
			args[5], args[6], args[7], args[8], args.format)
		if args[10] then
			table.insert(errors, {'formatTest', 'Tham số dư'})
		end
		if not result then
			return errorPrinter(errors)
		end
		result.param = getParam(args, 9)
	elseif dmsTest(args[3], args[6]) then
		-- dm logic
		result, errors, backward = parseDMS(args[1], args[2], nil, args[3], 
			args[4], args[5], nil, args[6], args['format'])
		if args[8] then
			table.insert(errors, {'formatTest', 'Tham số dư'})
		end
		if not result then
			return errorPrinter(errors)
		end
		result.param = getParam(args, 7)
	elseif dmsTest(args[2], args[4]) then
		-- d logic
		result, errors, backward = parseDMS(args[1], nil, nil, args[2], 
			args[3], nil, nil, args[4], args.format)
		if args[6] then
			table.insert(errors, {'formatTest', 'Tham số dư'})
		end	
		if not result then
			return errorPrinter(errors)
		end
		result.param = getParam(args, 5)
	else
		-- Error
		return errorPrinter({{"formatTest", "Định dạng đối số không rõ"}})
	end
	result.name = args.name
	
	local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'}
	for _, v in ipairs(extra_param) do
		if args[v] then 
			table.insert(errors, {'formatTest', 'Tham số: "' .. v .. '=" cần phải là "' .. v .. ':"' })
		end
	end
	
	local ret = specPrinter(args, result)
	if #errors > 0 then
		ret = ret .. ' ' .. errorPrinter(errors) .. '[[Thể loại:Trang có thẻ tọa độ hỏng]]'
	end
	return ret, backward
end

--[[
Xếp vào các thể loại theo dõi Wikidata.
]]
local function makeWikidataCategories()
	local ret
	if mw.wikibase and current_page.namespace == 0 then
		local entity = mw.wikibase.getEntityObject()
		if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1] then
			local snaktype = entity.claims.P625[1].mainsnak.snaktype
			if snaktype == 'value' then
				-- coordinates exist both here and on Wikidata, and can be compared.
				ret = 'Tọa độ trên Wikidata'
			elseif snaktype == 'somevalue' then
				ret = 'Tọa độ trên Wikidata có giá trị không rõ'
			elseif snaktype == 'novalue' then
				ret = 'Tọa độ trên Wikidata không có giá trị'
			end
		else
			-- We have to either import the coordinates to Wikidata or remove them here.
			ret = 'Tọa độ không có sẵn trên Wikidata'
		end
	end
	if ret then
		return string.format('[[Thể loại:%s]]', ret)
	else
		return ''
	end
end

--[[
link

Hàm đơn giản xuất địa chỉ tọa độ cho những mục đích khác.

Cách sử dụng:
	{{#gọi:Coordinates | link }}
	
]]
function coordinates.link(frame)
	return coord_link;
end

--[[
dec2dms

Hàm bọc cho phép các bản mẫu gọi dec2dms trực tiếp.

Cách sử dụng:
	{{ #gọi:Coordinates | dec2dms | tọa độ thập phân | hậu tố cho số dương | 
		hậu tố cho số âm | độ chính xác }}

decimal_coordinate được chuyển đổi thành định dạng độ-phút-giây. Nếu là số
dương, hậu tố cho số dương được bổ sung (thường là N hay E); nếu là số dương,
hậu tố cho số dương được bổ sung. Độ chính xác định rõ mức chi tiết là một trong
“D”, “DM”, hay “DMS”.
]]
coordinates.dec2dms = makeInvokeFunc('_dec2dms')
function coordinates._dec2dms(args)
	local coordinate = args[1]
	local firstPostfix = args[2] or ''
	local secondPostfix = args[3] or ''
	local precision = args[4] or ''

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

--[[
Hàm hỗ trợ quyết định sử dụng định dạng độ, độ-phút, hay độ-phút-giây, tùy độ
chính xác của giá trị thập phân cho vào.
]]
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

Hàm bọc cho phép các bản mẫu gọi dms2dec trực tiếp.

Cách sử dụng:
	{{ #gọi:Coordinates | dms2dec | chữ bán cầu | độ | 
		phút | giây }}

Chuyển đổi các giá trị độ-phút-giây thành định dạng thập phân.
direction_flag là một trong N, S, E, và W và định rõ giá trị cho ra là số dương
(N và E) hoặc số âm (S và W).
]]
coordinates.dms2dec = makeInvokeFunc('_dms2dec')
function coordinates._dms2dec(args)
	local direction = args[1]
	local degrees = args[2]
	local minutes = args[3]
	local seconds = args[4]

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

--[[
coord

Chỗ vào chính của hàm Lua thay thế {{Coord}}.

Cách sử dụng:
	{{ #gọi:Coordinates | coord }}
	{{ #gọi:Coordinates | coord | vĩ độ | kinh độ }}
	{{ #gọi:Coordinates | coord | vĩ độ | chữ vĩ độ | kinh độ | chữ kinh độ }}

	
	Tra cứu trang tài liệu của {{Coord}} để biết đến nhiều tham số và
	tùy chọn khác.

Lưu ý: Hàm này cung cấp các phần tử hiển thị thị giác của {{Coord}}. Để
cho có thể tải các tọa độ lên cơ sở dữ liệu, hàm cú pháp {{#coordinates:}} cũng cần
được gọi. Hàm này được gọi tự động trong phiên bản Lua của {{Coord}}.
]]
coordinates.coord = makeInvokeFunc('_coord')
function coordinates._coord(args)
	if (not args[1] or not tonumber(args[1])) and not args[2] and mw.wikibase.getEntityObject() then
		args[3] = args[1]; args[1] = nil
		local entity = mw.wikibase.getEntityObject()
		if entity 
			and entity.claims
			and entity.claims.P625
			and entity.claims.P625[1].mainsnak.snaktype == 'value'
		then
			local precision = entity.claims.P625[1].mainsnak.datavalue.value.precision
			args[1]=entity.claims.P625[1].mainsnak.datavalue.value.latitude
			args[2]=entity.claims.P625[1].mainsnak.datavalue.value.longitude
			if precision then
				precision=-math_mod._round(math.log(precision)/math.log(10),0)
				args[1]=math_mod._round(args[1],precision)
				args[2]=math_mod._round(args[2],precision)
			end
		end
	end
	
	local contents, backward = formatTest(args)
	local Notes = args.notes or ''
	local Display = args.display and args.display:lower() or 'inline'

	local function isInline(s)
		-- Finds whether coordinates are displayed inline.
		return s:find('inline') ~= nil or s == 'i' or s == 'it' or s == 'ti'
	end
	local function isInTitle(s)
		-- Finds whether coordinates are displayed in the title.
		return s:find('title') ~= nil or s == 't' or s == 'it' or s == 'ti'
	end
	
	local function coord_wrapper(in_args)
		-- Calls the parser function {{#coordinates:}}.
		return mw.getCurrentFrame():callParserFunction('#coordinates', in_args) or ''
	end
	
	local text = ''
	if isInline(Display) then
		text = text .. displayinline(contents, Notes)
	end
	if isInTitle(Display) then
		text = text
			.. displaytitle(contents, Notes)
			.. makeWikidataCategories()
	end
	if not args.nosave then
		local page_title, count = mw.title.getCurrentTitle(), 1
		if backward then
			local tmp = {}
			while not string.find((args[count-1] or ''), '[EW]') do tmp[count] = (args[count] or ''); count = count+1 end
			tmp.count = count; count = 2*(count-1)
			while count >= tmp.count do table.insert(tmp, 1, (args[count] or '')); count = count-1 end
			for i, v in ipairs(tmp) do args[i] = v end
		else
			while count <= 9 do args[count] = (args[count] or ''); count = count+1 end
		end
		if isInTitle(Display) and not page_title.isTalkPage and page_title.subpageText ~= 'doc' and page_title.subpageText ~= 'testcases' then args[10] = 'primary' end
		args.notes, args.format, args.display = nil
		text = text .. coord_wrapper(args)
	end
	return text
end

--[[
coord2text

Extracts a single value from a transclusion of {{Coord}}.
IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.

Cách sử dụng:

    {{#gọi:Coordinates | coord2text | {{Coord}} | parameter }}

Valid values for the second parameter are: lat (signed integer), long (signed integer), type, scale, dim, region, globe, source

]]
function coordinates.coord2text(frame)
	if frame.args[1] == '' or frame.args[2] == '' or not frame.args[2] then return nil end
	frame.args[2] = mw.text.trim(frame.args[2])
	if frame.args[2] == 'lat' or frame.args[2] == 'long' then
		local result, negative = mw.text.split((mw.ustring.match(frame.args[1],'[%.%d]+°[NS] [%.%d]+°[EW]') or ''), ' ')
		if frame.args[2] == 'lat' then
			result, negative = result[1], 'S'
		else
			result, negative = result[2], 'W'
		end
		result = mw.text.split(result, '°')
		if result[2] == negative then result[1] = '-'..result[1] end
		return result[1]
	else
		return mw.ustring.match(frame.args[1], 'params=.-_'..frame.args[2]..':(.-)[ _]')
	end
end

--[[
coordinsert

Injects some text into the Geohack link of a transclusion of {{Coord}} (if that text isn't already in the transclusion). Outputs the modified transclusion of {{Coord}}.
IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.

Cách sử dụng:

    {{#gọi:Coordinates | coordinsert | {{Coord}} | parameter:value | parameter:value | … }}

Do not make Geohack unhappy by inserting something which isn't mentioned in the {{Coord}} documentation.

]]
function coordinates.coordinsert(frame)
	for i, v in ipairs(frame.args) do
		if i ~= 1 then
			if not mw.ustring.find(frame.args[1], (mw.ustring.match(frame.args[i], '^(.-:)') or '')) then frame.args[1] = mw.ustring.gsub(frame.args[1], '(params=.-)_? ', '%1_'..frame.args[i]..' ') end
		end
	end
	return frame.args[1]
end

return coordinates
Wiki - Keonhacai copa chuyên cung cấp kiến thức thể thao, keonhacai tỷ lệ kèo, bóng đá, khoa học, kiến thức hằng ngày được chúng tôi cập nhật mỗi ngày mà bạn có thể tìm kiếm tại đây có nguồn bài viết: https://vi.wikipedia.org/wiki/M%C3%B4_%C4%91un:Coordinates/sandbox