Bước tới nội dung

Mô đun:Canada NTS

Bách khoa toàn thư mở Wikipedia
require('strict');																-- alarm when global variables etc are usedlocal get_args = require ('Mô đun:Arguments').getArgs;							-- simplfy frame and parent frame argument fetching--[[--------------------------< W I K I D A T A _ L A T _ L O N G _ G E T >------------------------------------returns latitude and longitude from wikidata for current page; nil elseNanaimo BC is Q16461 → latitude: 49.164166666667; longitude: -123.93638888889TODO: accept a <qid> argument? if called with <qid> fetch lat/lon for that qid and not for current page]]local function wikidata_lat_lon_get()	local qid = mw.wikibase.getEntityIdForCurrentPage();						-- get the qid for the current page	if qid then		local value_t = mw.wikibase.getBestStatements (qid, 'P625')[1];			-- attempt to get P625; nil when article does not have P625		if value_t then			value_t = value_t.mainsnak.datavalue.value;							--point to the value table			return value_t.latitude, value_t.longitude;							-- return coordinates from value_t		end	endend--[[--------------------------< A R T I C L E _ N A M E _ F R O M _ Q I D _ G E T >----------------------------returns local article name for this wiki using <qid>; nil elseTODO: if no local article fallback to en.wiki]]local function article_name_from_qid_get (qid)	local this_wiki_code = mw.language.getContentLanguage():getCode();			-- get this wiki's language code	if 'wikidata' == mw.site.server then		this_wiki_code = mw.getCurrentFrame():callParserFunction('int', {'lang'}); -- on Wikidata so use interface language setting instead	end	local wd_article = mw.wikibase.getSitelink (qid, this_wiki_code .. 'wiki');	-- fetch article title from WD; nil when no title available at this wiki	if wd_article then		wd_article = table.concat ({':', this_wiki_code, ':', wd_article});		-- interwiki-style link without brackets if taken from WD; leading colon required	end	return wd_article;															-- article title from WD; nil elseend--[[--------------------------< _ N A M E >--------------------------------------------------------------------This function takes in a National Tiling System ID and outputs the name of the National Topographic System mapsheet with that ID.  If no map sheet has been published under that ID, the output will be blank.]]local function _name (args_t)	local data_t = mw.loadData ('Mô đun:Canada NTS/data');						-- load the ~/data module		if not data_t[args_t[1]] then												-- nil when NTS ID not listed in ~/data		return "";	elseif '' == data_t[args_t[1]] then											-- when sheet has no title		return '(untitled)';													-- return a place-holder; lowercase here because capitalized implies that 'Untitled' is the 'title'	end	local title_parts_t = mw.text.split (data_t[args_t[1]], '|');				-- title_parts[1] is link part of a wikilink; title_parts[2] is wikilink label (map name) or nil	if mw.title.getCurrentTitle().text == title_parts_t[1] then					-- don't create wikilink to the current article		return title_parts_t[2] or title_parts_t[1];							-- return plaintext wikilink label or plain text article title (wikilink)	end	return string.format ('[[%s]]', data_t[args_t[1]]);							-- return wikilinked map titleend--[[--------------------------< N A M E >----------------------------------------------------------------------external invoke interfaceThis function takes in a National Tiling System ID and outputs the name of the National Topographic System map sheet with that ID.If no map sheet has been published under that ID, the output will be blank.{{#invoke:Canada NTS|name|<NTS map sheet ID>}}]]local function name (frame)	local args_t = get_args (frame);	if not args_t[1] then		return '<span style="color:#d33">National Tiling System ID required</span>';	-- TODO: better, more informative error handling	end		return _name (args_t);end--[[--------------------------< C O O R D _ L I M I T S _ T >--------------------------------------------------a sequence of sequences.  Each sequence in <coord_limits_t> has two coordinate sequences that defines a rectangleidentified by the northwest and southeast corners of a subsection in the NTS series map.  The first coordinate sequence identifies the northwestcorner of the subsection; the second sequence identifies the southwest corner of the subsection.]]local coord_limits_t = {	{{44, 88}, {40, 56}},														-- series: 40, 30, 20, 10	{{48, 88}, {44, 48}},														-- series: 41, 31, 21, 11, 1	{{56, 136}, {48, 48}},														-- series: 102, 92, ..., 2; 103, 93, ..., 3	{{68, 144}, {56, 56}},														-- series: 114, 104, ..., 14; 115, 105, ..., 15; 116, 106, ..., 16	{{72, 144}, {68, 64}},														-- series: 117, 107, ..., 27	{{76, 128}, {72, 72}},														-- series: 98, 88, ..., 38	{{80, 128}, {76, 64}},														-- series: 99, 89, ..., 29	{{84, 104}, {80, 56}},														-- series: 560, 340, 120	}--[[--------------------------< L A T _ L O N _ V A L I D A T E >----------------------------------------------validates <lat> and <lon> to be inside one of the rectangles defined in <coord_limits_t>returns true when in bounds; false else]]local function lat_lon_validate (lat, lon)	for _, coord_limit_t in ipairs (coord_limits_t) do							-- loop through the rectangle sequences in <coord_limits_t>		local lat_N = coord_limit_t[1][1];										-- for readability ...		local lat_S = coord_limit_t[2][1];		local lon_W = coord_limit_t[1][2];		local lon_E = coord_limit_t[2][2];		if (lat >= lat_S) and (lat < lat_N) and (lon >= lon_E) and (lon < lon_W) then			return true;														-- <lat> and <lon> locate a point within bounds so done		end	end		return false;																-- <lat> and <lon> locate a point out of bounds so doneend--[[--------------------------< E X T E N T S >----------------------------------------------------------------Calculates bounding boxes for 1:50,000 and 1:250,000 scale map sheets/areas from latitude and longitude]]local function extents (lat, lon)	local belt = math.floor((lat - 40) * 4);	local strip = math.floor((lon - 48) * 2);	local s, n, e, w															-- 1:50,000 scale bounding box	local a_s, a_n, a_e, a_w													-- 1:250,000 scale bounding box	local lat_limits = -- Latitude limits of bounding box		{ s = belt / 4 + 40,		n = belt / 4 + 40.25,		a_s = math.floor(lat),		a_n = math.floor(lat + 1)		}	local lon_limits = {e, w, a_e, a_w}																				-- Calculation of longitude limits is different depending on zone	if lat >= 40 and lat < 68 then												-- Southern zone		lon_limits["e"] = strip / 2 + 48;		lon_limits["w"] = strip / 2 + 48.5;		lon_limits["a_e"] = math.floor(strip / 4) * 2 + 48;		lon_limits["a_w"] = math.floor(strip / 4) * 2 + 50;	elseif lat >= 68 and lat < 80 then											-- Arctic zone		lon_limits["e"] = math.floor(strip / 2) + 48;		lon_limits["w"] = math.floor(strip / 2) + 49;		lon_limits["a_e"] = math.floor(strip / 8) * 4 + 48;		lon_limits["a_w"] = math.floor(strip / 8) * 4 + 52;	elseif lat >= 80 and lat < 88 then											-- High Arctic zone		lon_limits["e"] = math.floor(strip / 2) + 48;		lon_limits["w"] = math.floor(strip / 2) + 49;		lon_limits["a_e"] = math.floor(strip / 8) * 4 + 48;		lon_limits["a_w"] = math.floor(strip / 8) * 4 + 52;	end	return {		south = lat_limits["s"], north = lat_limits["n"], east = lon_limits["e"], west = lon_limits["w"],	-- 1:50,000 scale maps		area_south = lat_limits["a_s"], area_north = lat_limits["a_n"], area_east = lon_limits["a_e"], area_west = lon_limits["a_w"]	-- 1:250,000 scale maps		}end--[[--------------------------< N T S _ I D _ F R O M _ L A T _ L O N _ G E T >--------------------------------calculates NTS identifier from latitude and longitude.  If <lat> and <lon> not supplied, attempts to fetchcoordinates from wikidatawhen successful, returns NTS identifier; nil else]]local function nts_id_from_lat_long_get (lat, lon)	if not (lat and lon) then													-- nil when missing, empty, or not a number		lat, lon = wikidata_lat_lon_get();										-- <lat>/<lon> template param(s) invalid or missing; attempt to get <lat>/<lon> from wikidata	end																				-- wikidata uses negative numbers for west (and south) so must account for that	if lat then																	-- normalize coords; assumes that given coords are intended to be on canada nts map		if 0 > lat then			lat = lat * -1.0;													-- required because wikidata coords are signed		end		if 0 > lon then			lon = lon * -1.0;													-- required because wikidata coords are signed		end	else		return nil;	end		if not lat_lon_validate (lat, lon) then		return nil;																-- <lat>/<lon> out of bounds; TODO: better error handling/messaging	end	local series, numarea, area, sheet_inter, sheet	if lat >= 40 and lat < 68 then												-- Southern zone		series = (math.floor((lon - 48) / 8) * 10) + math.floor((lat - 40) / 4)	-- Calculate 1:1,000,000 map series ID		numarea = tonumber(math.floor(((lat - 40) / 4) % 1 * 4) * 10 + math.floor(((lon - 48) / 8) % 1 * 4))	-- Calculate 1:250,000 map area ID		local southern_zone_t = {[0]='A', [1]='B', [2]='C', [3]='D', [13]='E', [12]='F', [11]='G', [10]='H', [20]='I', [21]='J', [22]='K', [23]='L', [33]='M', [32]='N', [31]='O', [30]='P'};		area = southern_zone_t[numarea];										-- translate		sheet_inter = math.floor((lat % 1) * 4) * 10 + math.floor((((lon - 48) / 8) % 1 * 4) % 1 * 4)	-- Calculate 1:50,000 map sheet ID	elseif lat >= 68 and lat < 80 then											-- Arctic zone		series = (math.floor((lon - 48) / 8) * 10) + math.floor((lat - 40) / 4)	-- Calculate 1:1,000,000 map series ID		numarea = (math.floor(lat % 4) * 10) + math.floor((lon / 4) % 2)		-- Calculate 1:250,000 map area ID		local arctic_zone_t = {[0]='A', [1]='B', [11]='C', [10]='D', [20]='E', [21]='F', [31]='G', [30]='H'};		area = arctic_zone_t[numarea];											-- translate		sheet_inter = math.floor((lat % 1) * 4) * 10 + math.floor(lon % 4)		-- Calculate 1:50,000 map sheet ID	elseif lat >= 80 and lat < 88 then											-- High Arctic zone		if lon >= 56 and lon < 72 then											-- Calculate 1:1,000,000 map series ID			if lat >= 84 then series = 121 else series = 120 end				-- These are correct - Go to <https://maps.canada.ca/czs/index-en.html>, select "Overlay reference layers", then "National Tiling System grid coverage"		elseif lon >= 72 and lon < 88 then										-- there are no maps above 84°N so series 121, 341, and 561 do not exist in National Topographic System, but do exist in National Tiling System			if lat >= 84 then series = 341 else series = 340 end		elseif lon >= 88 and lon < 104 then			if lat >= 84 then series = 561 else series = 560 end		elseif lon >= 104 and lon < 120 then									-- These are correct - Go to <https://maps.canada.ca/czs/index-en.html>, select "Overlay reference layers", then "National Tiling System grid coverage"			if lat >= 84 then series = 781 else series = 780 end				-- 780, 781, 910, or 911		elseif lon >= 120 and lon < 136 then			if lat >= 84 then series = 911 else series = 910 end		end -- Remember the difference between the National Topographic System and the National Tiling System				numarea = (math.floor(lat % 4) * 10) + (math.floor((lon / 8) + 1) % 2)	-- Calculate 1:250,000 map area ID		local high_arctic_zone_t = {[0]='A', [1]='B', [11]='C', [10]='D', [20]='E', [21]='F', [31]='G', [30]='H'};		area = high_arctic_zone_t[numarea];										-- translate		sheet_inter = math.floor((lat % 1) * 4) * 10 + math.floor((lon % 8) / 2)	-- Calculate 1:50,000 map sheet ID	end	local sheet_t = {[0]=1, [1]=2, [2]=3, [3]=4, [13]=5, [12]=6, [11]=7, [10]=8, [20]=9, [21]=10, [22]=11, [23]=12, [33]=13, [32]=14, [31]=15, [30]=16}	sheet = sheet_t[sheet_inter]	return series, area, sheetend--[[--------------------------< N T S _ S E R I E S _ V A L I D A T E >----------------------------------------return <series> as a number when valid and in-bounds; nil else<series> – must be a map series number as enumerated in File:NTS Zones and Map Series Numbers.png; leading zeros allowed]]local function nts_series_validate (series)	series = (series and tonumber (series));									-- convert series to a number	if not series then		return nil;																-- something other than a number; declare failure and abandon	end	local series_limits_t = {{1, 3}, {10, 16}, {20, 27}, {29, 49}, {52, 59}, {62, 69}, {72, 79}, {82, 89}, {92, 99}, {102, 107}, {114, 117}, {120, 120}, {340, 340}, {560, 560}}	for _, limits_t in ipairs (series_limits_t) do								-- loop through the series limits		if (series >= limits_t[1]) and (series <= limits_t[2]) then				-- is series within these limits?			return series;														-- yes, return series as a number		end	endend--[[--------------------------< N T S _ A R E A _ V A L I D A T E >--------------------------------------------return <area> when valid and in-bounds; nil else<area> – must be a single uppercase letter; when <series> identifies a map series in the 	High Arctic and Arctic zones: [A-H]	Southern zone: [A-P]]]local function nts_area_validate (series, area)	local is_northern;															-- a flag		local northern_series_t = {{27, 27}, {29, 29}, {37, 39}, {47, 49}, {57, 59}, {67, 69}, {77, 79}, {87, 89}, {97, 99}, {107, 107}, {117, 117}, {120, 120}, {340, 340}, {560, 560}}	for _, limits_t in ipairs (northern_series_t) do		if (series >= limits_t[1]) and (series <= limits_t[2]) then				-- is series in arctic or high arctic?			is_northern = true;													-- yes, set the flag			break;																-- and go on to the next tests		end	end		if is_northern then															-- if arctic or high arctic series		if not area:match ('^[A-H]$') then										-- area must be a single uppercase letter in the range A-H			return nil;															-- out of bounds, declare failure and abandon		end	else																		-- here when southern series		if not area:match ('^[A-P]$') then										-- area must be a single uppercase letter in the range A-P			return nil;															-- out of bounds, declare failure and abandon		end	end	return area;end--[[--------------------------< N T S _ S H E E T _ V A L I D A T E >------------------------------------------return <sheet> when valid and in-bounds; nil else<sheet> – optional; if present must be a number: [1-16]; leading zeros allowed]]local function nts_sheet_validate (sheet)	sheet = (sheet and tonumber (sheet)) or nil;								-- sheet as a number; or if not a number or not present, nil		if not sheet then		return nil;																-- something other than a number; declare failure and abandon	end	if (1 > sheet) or (16 < sheet) then											-- must be a number in the range 1–16		return nil;																-- out of bounds, declare failure and abandon	end	return sheet;																-- return sheet as a numberend--[[--------------------------< E X T E N T S _ F R O M _ G R I D >--------------------------------------------Calculates bounding boxes of 1:50,000 and 1:250,000 scale map sheets/areas from map sheet ID<series> is 1:1,000,000 scale map series – a 1-to-three digit number<area> is 1:250,000 scale map area – an uppercase letter A-P<sheet> is 1:50,000 scale map sheet – a number 1–16]]local function extents_from_grid (series, area, sheet)	local belt                                                                  -- 192 belts between 40°N and 88°N, each 0.25° of latitude in breadth	local belt_area_south = {["A"]=0, ["B"]=0, ["C"]=0, ["D"]=0, ["E"]=4, ["F"]=4, ["G"]=4, ["H"]=4, ["I"]=8, ["J"]=8, ["K"]=8, ["L"]=8, ["M"]=12, ["N"]=12, ["O"]=12, ["P"]=12}	local belt_area_north = {["A"]=0, ["B"]=0, ["C"]=4, ["D"]=4, ["E"]=8, ["F"]=8, ["G"]=12, ["H"]=12}	local belt_sheet = {[1]=0, [2]=0, [3]=0, [4]=0, [5]=1, [6]=1, [7]=1, [8]=1, [9]=2, [10]=2, [11]=2, [12]=2, [13]=3, [14]=3, [15]=3, [16]=3}	if series >= 120 then		belt = 160 + series % 10 * 16 + (belt_area_north[area] or 0) + (belt_sheet[sheet] or 0)	elseif series < 120 and series % 10 * 16 >= 112 then		belt = series % 10 * 16 + (belt_area_north[area] or 0) + (belt_sheet[sheet] or 0)	else		belt = series % 10 * 16 + (belt_area_south[area] or 0) + (belt_sheet[sheet] or 0)	end	local strip																	-- 192 strips between 48°W and 144°W, each 0.5° of longitude in breadth	local strip_series_high_arctic = {[12]=16, [34]=48, [56]=80, [78]=112, [91]=144}	local strip_area_southern = {["A"]=0, ["B"]=4, ["C"]=8, ["D"]=12, ["E"]=12, ["F"]=8, ["G"]=4, ["H"]=0, ["I"]=0, ["J"]=4, ["K"]=8, ["L"]=12, ["M"]=12, ["N"]=8, ["O"]=4, ["P"]=0}	local strip_area_arctic = {["A"]=0, ["B"]=8, ["C"]=8, ["D"]=0, ["E"]=0, ["F"]=8, ["G"]=8, ["H"]=0}	local strip_area_high_arctic = {["A"]=0, ["B"]=16, ["C"]=16, ["D"]=0, ["E"]=0, ["F"]=16, ["G"]=16, ["H"]=0}	local strip_sheet_southern = {[1]=0, [2]=1, [3]=2, [4]=3, [5]=3, [6]=2, [7]=1, [8]=0, [9]=0, [10]=1, [11]=2, [12]=3, [13]=3, [14]=2, [15]=1, [16]=0}	local strip_sheet_arctic = {[1]=0, [2]=2, [3]=4, [4]=6, [5]=6, [6]=4, [7]=2, [8]=0, [9]=0, [10]=2, [11]=4, [12]=6, [13]=6, [14]=4, [15]=2, [16]=0}	local strip_sheet_high_arctic = {[1]=0, [2]=4, [3]=8, [4]=12, [5]=12, [6]=8, [7]=4, [8]=0, [9]=0, [10]=4, [11]=8, [12]=12, [13]=12, [14]=8, [15]=4, [16]=0}	local east_limit, west_limit;												-- For 1:50,000 scale map sheet	local area_east_limit, area_west_limit;										-- For 1:250,000 scale map area	if series >= 120 then														-- High Arctic zone		strip = strip_series_high_arctic[math.floor(series / 10)] + (strip_area_high_arctic[area] or 0) + (strip_sheet_high_arctic[sheet] or 0);		east_limit = strip * 0.5 + 48		west_limit = (strip + 4) * 0.5 + 48		area_east_limit = math.floor(strip / 16) * 8 + 48		area_west_limit = math.floor((strip + 16) / 16) * 8 + 48	elseif series < 120 and math.floor(series % 10) >= 7 then					-- Arctic zone		strip = math.floor(series / 10) * 16 + (strip_area_arctic[area] or 0) + (strip_sheet_arctic[sheet] or 0);		east_limit = strip * 0.5 + 48		west_limit = (strip + 2) * 0.5 + 48		area_east_limit = math.floor(strip / 8) * 4 + 48		area_west_limit = math.floor((strip + 8) / 8) * 4 + 48	else																		-- Southern zone		strip = math.floor(series / 10) * 16 + (strip_area_southern[area] or 0) + (strip_sheet_southern[sheet] or 0);		east_limit = strip * 0.5 + 48		west_limit = (strip + 1) * 0.5 + 48		area_east_limit = math.floor(strip / 4) * 2 + 48		area_west_limit = math.floor((strip + 4) / 4) * 2 + 48	end		local grid_limits = {		["south"] = belt * 0.25 + 40,		["north"] = belt * 0.25 + 40.25,		["area_south"] = math.floor(belt / 4) + 40,		["area_north"] = math.floor(belt / 4) + 41,		["east"] = east_limit,		["west"] = west_limit,		["area_east"] = area_east_limit,		["area_west"] = area_west_limit		}		return grid_limitsend--[[--------------------------< G R I D >----------------------------------------------------------------------This function takes a Canadian National Tiling System map sheet ID, or latitude and longitude either as input orfrom the wikidata qid of the current page and creates a url for the map sheet.  Latitude and longitude are indecimal degrees, and automatically assumed to be north and west, as no Canadian territory lies in the southernor eastern hemispheres.{{#invoke:Canada NTS|grid}} 													-- For 1:50,000 scale map sheet ID, using coordinates from current article's Wikidata entry{{#invoke:Canada NTS|grid|<series>|<area>|<sheet>}}								-- For 1:50,000 scale map sheet ID, using NTS ID (see Template:Canada NTS Map Sheet){{#invoke:Canada NTS|grid|lat=<number>|lon=<number>}}							-- For 1:50,000 scale map sheet ID, using coordinates specified in argumentoptional parameters:	|area= to obtain a 1:250,000 scale map area ID instead	|link= to create an appropriate link to the Canadian government's Geospatial Data Extraction tool	|name= to append the map name (from Module:Canada_NTS/data) to the output]]local function grid (frame)	local args_t = get_args (frame);											-- fetch frame and parent frame parameters into a single table	local lat, lon = tonumber(args_t.lat), tonumber(args_t.lon);																				-- flags to control what the output looks like	local print_area = 'yes' == args_t.area;									-- when true, render only the 'area' portion '30M' instead of sheet '30M11'	local print_link = 'yes' == args_t.link;									-- when true, format the area or sheet output as an external link	local print_name = 'yes' == args_t.name;									-- when true, append map name from ~/data	local series, area, sheet;	for k, v in ipairs (args_t) do		if 1 == k then															-- args_t[1] to series; must be a one-to-three digit number			series = nts_series_validate (args_t[1]);			if not series then				return '<span style="color:#d33">invalid NTS series input</span>';			end			lat = nil;															-- unset these if present because we won't be using them when we have nts id (which may or may not be good)			lon = nil;		elseif 2 == k then														-- args_t[2] to area; must one uppercase letter A-P			area = nts_area_validate (series, args_t[2]);			if not area then				return '<span style="color:#d33">invalid NTS area input</span>';			end		elseif 3 == k then														-- args_t[3] to sheet; must be a number 1-16			sheet = nts_sheet_validate (args_t[3]);			if not sheet then				return '<span style="color:#d33">invalid NTS sheet input</span>';			end		end	end	if series and not sheet then												-- if we have nts id without sheet (an area-only)		print_area = true;														-- set this so that later we create the correct output	end		if not series or not area then		series, area, sheet = nts_id_from_lat_long_get (lat, lon);		if not series then			return '<span style="color:#d33">lat/long input fail</span>';		-- TODO: better, more informative error handling		end	end	local output = print_area and (series .. area) or (series .. area .. sheet);	print_name = print_name and (' ' .. _name ({output})) or '';				-- reuse <print_name> to hold name or empty string	local extents_t = {};														-- to hold bounding box coordinates for url	if print_link and lat then													-- when we have lat/lon		extents_t = extents (lat, lon);											-- get a table of sheet and area extents from lat/lon	elseif print_link then														-- when we have nts id		extents_t = extents_from_grid (series, area, sheet);					-- get a table of sheet and area extents from nts id parts		if extents_t == nil then			return '<span style="color:#d33">NTS identifier input fail</span>';	-- TODO: better, more informative error handling		end	else		print_link = nil;														-- unset because we can't create a link	end	if print_link then		local ext_link_fmt_str = '[https://maps.canada.ca/czs/index-en.html?bbox=-%s,%s,-%s,%s&name=NTS_map_sheet_%s %s]';		output = print_area and string.format (ext_link_fmt_str, extents_t.area_west, extents_t.area_south, extents_t.area_east, extents_t.area_north, output, output) or					string.format (ext_link_fmt_str, extents_t.west, extents_t.south, extents_t.east, extents_t.north, output, output);	end	output = output .. print_name;												-- append name or empty string	return output;																-- and doneend--[[--------------------------< D O C _ S U P P O R T >--------------------------------------------------------]]local function doc_support (frame)	local args_t = get_args (frame);											-- fetch frame and parent frame parameters into a single table	local data = mw.loadData ('Mô đun:Canada NTS/data');						-- load the ~/data module	local lang_obj = mw.language.getContentLanguage();							-- get language object for number formatting	local count = 0;															-- a generic counter 	local area_count = 0;														-- counter for area maps (1:250,000)	local sheet_count = 0;														-- counter for sheet maps (1:50,000)		if 'count' == args_t[1] then												-- count the number of entries in ~/data		for k, _ in pairs (data) do												-- don't care about key and value			if k:match ('[A-P]$') then				area_count = area_count + 1;									-- bump the counter			else				sheet_count = sheet_count + 1;									-- bump the counter			end		end		return string.format ('%s (1:250,000: %s; 1:50,000: %s)', lang_obj:formatNum (sheet_count + area_count), lang_obj:formatNum (area_count), lang_obj:formatNum (sheet_count));			elseif 'untitled' == args_t[1] then											-- count the number of entries in ~/data that do not have a NTS title		for _, v in pairs (data) do												-- don't care about key			if '' == v then														-- when value is empty string, no title so				count = count + 1;												-- bump the counter			end		end	end	return lang_obj:formatNum(count);											-- make all pretty-like and doneend--[[--------------------------< E X P O R T E D   F U N C T I O N S >------------------------------------------]]return {	grid = grid,																-- entry points from invokes	name = name,	doc_support = doc_support,		extents_from_grid = extents_from_grid,										-- entry points when this module is require()d into other modules	nts_series_validate = nts_series_validate,	nts_area_validate = nts_area_validate,	nts_sheet_validate = nts_sheet_validate,	}