Module:Sandbox/trappist the monk/nts explained

require ('strict'); -- alarm when global variables etc are used

local nts = require ('Module:Canada NTS'); -- for extents_from_grid, nts_series_validate, nts_are_validate, nts_sheet_validatelocal data = mw.loadData ('Module:Canada NTS/data'); -- load the ~/data module

----------------------------< 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 ; nil else

local function wikidata_lat_lon_get (qid) 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, -1.0 * value_t.longitude; -- return coordinates from value_t; longitude normalized end endend

----------------------------< T A B B I N G >----------------------------------------------------------------

return the number of tabs necessary to more-or-less position comments at column 80 (the right-side margin linein the wiki code editor)

local function tabbing (str) return math.ceil ((80 - 4 - str:len) / 4); -- the -4 because every line begins with a tab characterend

----------------------------< S O R T >----------------------------------------------------------------------

sort by keys; ascending order numerically by series then by area (alpha sort) then numerically by sheet

local function sort (a, b) local a_key_series, a_key_area, a_key_sheet = a:match ('(%d+)(%u)(%d*)'); -- extract series, area, sheet NTS id parts from local b_key_series, b_key_area, b_key_sheet = b:match ('(%d+)(%u)(%d*)'); -- extract series, area, sheet NTS id parts from a_key_series = tonumber (a_key_series); -- convert numerical parts of key from to numbers for comparison a_key_sheet = tonumber (a_key_sheet); -- nil when is empty string a_key_sheet = a_key_sheet and a_key_sheet or 0 -- optional so when omitted set to 0 for comparison b_key_series = tonumber (b_key_series); -- convert numerical parts of key from to numbers for comparison b_key_sheet = tonumber (b_key_sheet); -- nil when is empty string b_key_sheet = b_key_sheet and b_key_sheet or 0 -- optional so when omitted set to 0 for comparison

if a_key_series ~= b_key_series then -- do the comparisons; by series first return a_key_series < b_key_series; elseif a_key_area ~= b_key_area then -- then by area return a_key_area < b_key_area; else return a_key_sheet < b_key_sheet; -- and lastly by sheet endend

----------------------------< L A T _ B O U N D S _ C H E C K >----------------------------------------------

is same as or north of and is same as or south of ?

returns direction 'north' or 'south' when out of bounds; nil else

local function lat_bounds_check (lat, north, south) if lat < south then return 'south'; -- out of bounds south of elseif lat > north then return 'north'; -- out of bounds north of endend

----------------------------< L O N _ B O U N D S _ C H E C K >----------------------------------------------

is same as or east of and is same as or west of ?

returns direction 'east' or 'west' when out of bounds; nil else

local function lon_bounds_check (lon, west, east) if lon < east then return 'east'; -- out of bounds east of elseif lon > west then return 'west'; -- out of bounds west of endend

--

local function is_in_bounds (series, area, sheet, lat, lon) local extents_t = nts.extents_from_grid (tonumber(series), area, tonumber(sheet)); -- fetch extents for this nts key

local lat_fail, lon_fail; -- flags local north, west, south, east; -- map extents

if

sheet then -- is this searies, area, sheet an area map? north, west, south, east = extents_t.area_north, extents_t.area_west, extents_t.area_south, extents_t.area_east; lat_fail = lat_bounds_check (lat, north, south); lon_fail = lon_bounds_check (lon, west, east); else -- here when sheet map north, west, south, east = extents_t.north, extents_t.west, extents_t.south, extents_t.east; lat_fail = lat_bounds_check (lat, north, south); lon_fail = lon_bounds_check (lon, west, east); end

if lat_fail or lon_fail then -- build error message if 'north'

lat_fail then return string.format ('P625 %s latitude out of bounds: WD lat/lon: <%s>,%s (NW: <%s>,%s / SE: %s,%s)', lat_fail, lat, lon, north, west, south, east); elseif 'south'

lat_fail then return string.format ('P625 %s latitude out of bounds: WD lat/lon: <%s>,%s (NW: %s,%s / SE: <%s>,%s)', lat_fail, lat, lon, north, west, south, east); elseif 'west'

lon_fail then return string.format ('P625 %s longitude out of bounds: WD lat/lon: %s,<%s> (NW: %s,<%s> / SE: %s,%s)', lon_fail, lat, lon, north, west, south, east); elseif 'east'

lon_fail then return string.format ('P625 %s longitude out of bounds: WD lat/lon: %s,<%s> (NW: %s,%s / SE: %s,<%s>)', lon_fail, lat, lon, north, west, south, east); end end return ; -- in bounds so return empty string message for concatenationend

--main|94}}

local function main (frame) local map_series; -- number of the series that we are operating on; for invokes, this is only number or start of a range local map_series_end; -- for invokes only; end of a range of map series local invoked;

if 'table'

type (frame) then map_series = frame.args[1]; -- for an invoke if frame.args[2] then map_series_end = frame.args[2]; end invoked = true; -- flag used to modify final output rendering else map_series = frame; -- when called from the debug console end

local temp_t = -- output goes in this sequence table until rendering for k, v in pairs (data) do -- for each entry in the data mofule local series, area, sheet = k:match ('^(%d+)(%u)(%d*)'); -- fetch series, area, sheet from the entry's key if tonumber(series) >= tonumber(map_series) and tonumber(series) <= tonumber(map_series_end or map_series) then -- when this map is one of the map series we're looking for local map_title_parts = mw.text.split (v, '|'); -- extract an article title local qid = mw.wikibase.getEntityIdForTitle (map_title_parts[1]); -- does this article title have a wikidata entry local lat, lon = wikidata_lat_lon_get (qid); -- attempt to get P625 lat/lon from wikidata's entry for the article title local bounds_msg = ; -- gets an error message if lat/lon from wikidata not within bounds of NTS map

if qid and lat then -- when article title has wikidata entry an wikidata has P625 (latitude/longitude) bounds_msg = is_in_bounds (series, area, sheet, lat, lon); -- empty string when in bounds; message else elseif qid then -- lat can be nil when qid points to dab page or article does not have P625 bounds_msg = string.format ('%s missing P625', qid); -- no lat/lon so no P625 end local str; if not qid then -- when article title doesn't have a wikidata entry str = string.format ('\t["%s"] = "%s",', k, v); -- mimic the original elseif not lat then -- has qid but does not have P625 str = string.format ('["%s"] = "%s",', k, v); -- mimic the original + bounds_msg str = string.format ('\t%s%s-- %s', str, string.rep ('\t', tabbing (str)), bounds_msg); elseif map_title_parts[2] then -- for piped article links str = string.format ('["%s"] = "%s|%s",', k, qid, map_title_parts[2]); str = string.format ('\t%s%s-- %s; %s', str, string.rep ('\t', tabbing (str)), map_title_parts[1], bounds_msg); else -- map name same as en.wiki article title str = string.format ('["%s"] = "%s",', k, qid, map_title_parts[1]); str = string.format ('\t%s%s-- %s; %s', str, string.rep ('\t', tabbing (str)), map_title_parts[1], bounds_msg); end

if invoked then -- when this function called through an invoke str = str:gsub ('\t', ' ') -- replace plain-text tabs with html numeric entities end

table.insert (temp_t, str); -- save end end

table.sort (temp_t, sort); -- ascending numerical sort by key (NTS id) for i=#temp_t, 1, -1 do -- working backwards through the table if temp_t[i]:match ('%d+%u"%]') then -- if this key is an area key (no sheet) table.insert (temp_t, i, ); -- insert an empty string to separate area-from-area elseif i > 1 and temp_t[i]:match ('%["(%d+)') ~= temp_t[i-1]:match ('%["(%d+)') then -- because some series list don't begin with area maps (15 for example) table.insert (temp_t, i, ''); -- insert an empty string to separate area-from-area end end if invoked then -- when this function called through an invoke return table.concat ({'<pre>', table.concat (temp_t, '<br />'),'</pre>'}); -- concatenate into a big string using <br /> tags and wrapped in <pre>...</pre> tagsand done else return table.concat (temp_t, '\n'); -- concatenate into a big string using plain-text newlines and done end end --[[--------------------------< N T S _ K E Y _ V A L I D A T E >---------------------------------------------- debug console function to makes sure that all keys in Module:Canada NTS/data have the correct form =p.nts_key_validate ]]

local function nts_key_validate for k, _ in pairs (data) do local series, area, sheet = k:match ('^(%d+)(%u)(%d*)$'); if not series then return '

invalid key: ' .. k .. ''; end if not nts.nts_series_validate (tonumber(series)) then return 'invalid series: ' .. k .. ''; end if not nts.nts_area_validate (tonumber(series), area) then return 'invalid area: ' .. k .. ''; end if ~= sheet and not nts.nts_sheet_validate (tonumber(sheet)) then return 'invalid sheet: ' .. k .. ''; end end return 'keys are valid';end

----------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------

return