<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2Ftrappist_the_monk%2Fnts</id>
	<title>Module:Sandbox/trappist the monk/nts - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2Ftrappist_the_monk%2Fnts"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/trappist_the_monk/nts&amp;action=history"/>
	<updated>2026-05-07T00:42:34Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Sandbox/trappist_the_monk/nts&amp;diff=146621&amp;oldid=prev</id>
		<title>imported&gt;Legoktm: Replace Module:No globals with require( &quot;strict&quot; )</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/trappist_the_monk/nts&amp;diff=146621&amp;oldid=prev"/>
		<updated>2022-10-23T21:12:36Z</updated>

		<summary type="html">&lt;p&gt;Replace &lt;a href=&quot;/research/Module:No_globals&quot; title=&quot;Module:No globals&quot;&gt;Module:No globals&lt;/a&gt; with require( &amp;quot;strict&amp;quot; )&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;require (&amp;#039;strict&amp;#039;);																-- alarm when global variables etc are used&lt;br /&gt;
&lt;br /&gt;
local nts = require (&amp;#039;Module:Canada NTS&amp;#039;);										-- for extents_from_grid(), nts_series_validate, nts_are_validate, nts_sheet_validate&lt;br /&gt;
local data = mw.loadData (&amp;#039;Module:Canada NTS/data&amp;#039;);							-- load the ~/data module&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; W I K I D A T A _ L A T _ L O N G _ G E T &amp;gt;------------------------------------&lt;br /&gt;
&lt;br /&gt;
returns latitude and longitude from wikidata for &amp;lt;qid&amp;gt;; nil else&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function wikidata_lat_lon_get (qid)&lt;br /&gt;
	if qid then&lt;br /&gt;
		local value_t = mw.wikibase.getBestStatements (qid, &amp;#039;P625&amp;#039;)[1];			-- attempt to get P625; nil when article does not have P625&lt;br /&gt;
		if value_t then&lt;br /&gt;
			value_t = value_t.mainsnak.datavalue.value;							-- point to the value table&lt;br /&gt;
			return value_t.latitude, -1.0 * value_t.longitude;					-- return coordinates from value_t; longitude normalized&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; T A B B I N G &amp;gt;----------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
return the number of tabs necessary to more-or-less position comments at column 80 (the right-side margin line&lt;br /&gt;
in the wiki code editor)&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function tabbing (str)&lt;br /&gt;
	return math.ceil ((80 - 4 - str:len()) / 4);								-- the -4 because every line begins with a tab character&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S O R T &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
sort by keys; ascending order numerically by series then by area (alpha sort) then numerically by sheet&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function sort (a, b)&lt;br /&gt;
	local a_key_series, a_key_area, a_key_sheet = a:match (&amp;#039;(%d+)(%u)(%d*)&amp;#039;);	-- extract series, area, sheet NTS id parts from &amp;lt;a&amp;gt;&lt;br /&gt;
	local b_key_series, b_key_area, b_key_sheet = b:match (&amp;#039;(%d+)(%u)(%d*)&amp;#039;);	-- extract series, area, sheet NTS id parts from &amp;lt;b&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	a_key_series = tonumber (a_key_series);										-- convert numerical parts of key from &amp;lt;a&amp;gt; to numbers for comparison&lt;br /&gt;
	a_key_sheet = tonumber (a_key_sheet);										-- nil when &amp;lt;a_key_sheet&amp;gt; is empty string&lt;br /&gt;
	a_key_sheet = a_key_sheet and a_key_sheet or 0								-- optional so when omitted set to 0 for comparison&lt;br /&gt;
	&lt;br /&gt;
	b_key_series = tonumber (b_key_series);										-- convert numerical parts of key from &amp;lt;a&amp;gt; to numbers for comparison&lt;br /&gt;
	b_key_sheet = tonumber (b_key_sheet);										-- nil when &amp;lt;b_key_sheet&amp;gt; is empty string&lt;br /&gt;
	b_key_sheet = b_key_sheet and b_key_sheet or 0								-- optional so when omitted set to 0 for comparison&lt;br /&gt;
&lt;br /&gt;
	if a_key_series ~= b_key_series then										-- do the comparisons; by series first&lt;br /&gt;
		return a_key_series &amp;lt; b_key_series;&lt;br /&gt;
	elseif a_key_area ~= b_key_area then										-- then by area&lt;br /&gt;
		return a_key_area &amp;lt; b_key_area;&lt;br /&gt;
	else&lt;br /&gt;
		return a_key_sheet &amp;lt; b_key_sheet;										-- and lastly by sheet&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; L A T _ B O U N D S _ C H E C K &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
is &amp;lt;lat&amp;gt; same as or north of &amp;lt;south&amp;gt; and is &amp;lt;lat&amp;gt; same as or south of &amp;lt;north&amp;gt;?&lt;br /&gt;
&lt;br /&gt;
returns direction &amp;#039;north&amp;#039; or &amp;#039;south&amp;#039; when &amp;lt;lat&amp;gt; out of bounds; nil else&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function lat_bounds_check (lat, north, south)&lt;br /&gt;
	if lat &amp;lt; south then&lt;br /&gt;
		return &amp;#039;south&amp;#039;;															-- out of bounds south of &amp;lt;south&amp;gt;&lt;br /&gt;
	elseif lat &amp;gt; north then&lt;br /&gt;
		return &amp;#039;north&amp;#039;;															-- out of bounds north of &amp;lt;north&amp;gt;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; L O N _ B O U N D S _ C H E C K &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
is &amp;lt;lon&amp;gt; same as or east of &amp;lt;west&amp;gt; and is &amp;lt;lat&amp;gt; same as or west of &amp;lt;east&amp;gt;?&lt;br /&gt;
&lt;br /&gt;
returns direction &amp;#039;east&amp;#039; or &amp;#039;west&amp;#039; when &amp;lt;lon&amp;gt; out of bounds; nil else&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function lon_bounds_check (lon, west, east)&lt;br /&gt;
	if lon &amp;lt; east then&lt;br /&gt;
		return &amp;#039;east&amp;#039;;															-- out of bounds east of &amp;lt;east&amp;gt;&lt;br /&gt;
	elseif lon &amp;gt; west then&lt;br /&gt;
		return &amp;#039;west&amp;#039;;															-- out of bounds west of &amp;lt;west&amp;gt;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ I N _ B O U N D S &amp;gt;------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
get map extents using series, area, sheet.  check to see that lat/lon fall within the map extents.&lt;br /&gt;
&lt;br /&gt;
returns empty string for concatenation when lat/lon fall within map extents; an error message else&lt;br /&gt;
&lt;br /&gt;
only one error mesage is returned; if both &amp;lt;lat&amp;gt; and &amp;lt;lon&amp;gt; are out of bounds, this function returns an error&lt;br /&gt;
message for only one of them&lt;br /&gt;
&lt;br /&gt;
because series, area, sheet are taken from Module:Canada NTS/data, they are presumed to be correct&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_in_bounds (series, area, sheet, lat, lon)&lt;br /&gt;
	local extents_t = nts.extents_from_grid (tonumber(series), area, tonumber(sheet));	-- fetch extents for this nts key&lt;br /&gt;
&lt;br /&gt;
	local lat_fail, lon_fail;													-- flags&lt;br /&gt;
	local north, west, south, east;												-- map extents&lt;br /&gt;
&lt;br /&gt;
	if &amp;#039;&amp;#039; == sheet then															-- is this searies, area, sheet an area map?&lt;br /&gt;
		north, west, south, east = extents_t.area_north, extents_t.area_west, extents_t.area_south, extents_t.area_east; &lt;br /&gt;
		lat_fail = lat_bounds_check (lat, north, south);&lt;br /&gt;
		lon_fail = lon_bounds_check (lon, west, east);&lt;br /&gt;
	else																		-- here when sheet map&lt;br /&gt;
		north, west, south, east = extents_t.north, extents_t.west, extents_t.south, extents_t.east; &lt;br /&gt;
		lat_fail = lat_bounds_check (lat, north, south);&lt;br /&gt;
		lon_fail = lon_bounds_check (lon, west, east);&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if lat_fail or lon_fail then												-- build error message&lt;br /&gt;
		if &amp;#039;north&amp;#039; == lat_fail then&lt;br /&gt;
			return string.format (&amp;#039;P625 %s latitude out of bounds: WD lat/lon: &amp;lt;%s&amp;gt;,%s (NW: &amp;lt;%s&amp;gt;,%s / SE: %s,%s)&amp;#039;,&lt;br /&gt;
				lat_fail, lat, lon, north, west, south, east);&lt;br /&gt;
		elseif &amp;#039;south&amp;#039; == lat_fail then&lt;br /&gt;
			return string.format (&amp;#039;P625 %s latitude out of bounds: WD lat/lon: &amp;lt;%s&amp;gt;,%s (NW: %s,%s / SE: &amp;lt;%s&amp;gt;,%s)&amp;#039;,&lt;br /&gt;
				lat_fail, lat, lon, north, west, south, east);&lt;br /&gt;
		elseif &amp;#039;west&amp;#039; == lon_fail then&lt;br /&gt;
			return string.format (&amp;#039;P625 %s longitude out of bounds: WD lat/lon: %s,&amp;lt;%s&amp;gt; (NW: %s,&amp;lt;%s&amp;gt; / SE: %s,%s)&amp;#039;,&lt;br /&gt;
				lon_fail, lat, lon, north, west, south, east);&lt;br /&gt;
		elseif &amp;#039;east&amp;#039; == lon_fail then&lt;br /&gt;
			return string.format (&amp;#039;P625 %s longitude out of bounds: WD lat/lon: %s,&amp;lt;%s&amp;gt; (NW: %s,%s / SE: %s,&amp;lt;%s&amp;gt;)&amp;#039;,&lt;br /&gt;
				lon_fail, lat, lon, north, west, south, east);&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return &amp;#039;&amp;#039;;																	-- in bounds so return empty string message for concatenation&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; M A I N &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
fetch &amp;lt;map_series&amp;gt; entries from Module:Canada NTS/data.  For each of those, attempt to get qid that matches the&lt;br /&gt;
en.wiki article title from wikidata.  Replace article title with the qid, sort and make all pretty like for&lt;br /&gt;
manual replacement in ~/data.&lt;br /&gt;
&lt;br /&gt;
to use the results of this function, Module:Canada NTS requires support for qids in lieu of article names which,&lt;br /&gt;
as of 2022-04-12, does not yet exist&lt;br /&gt;
&lt;br /&gt;
This function may be called from an invoke or from the debug console&lt;br /&gt;
&lt;br /&gt;
&amp;lt;frame&amp;gt; is a text string when called from debug console:&lt;br /&gt;
	=p.main (&amp;#039;92&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	{{#invoke:Sandbox/trappist the monk/nts|main|94}}&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function main (frame)&lt;br /&gt;
	local map_series;															-- number of the series that we are operating on; for invokes, this is only number or start of a range&lt;br /&gt;
	local map_series_end;														-- for invokes only; end of a range of map series&lt;br /&gt;
	local invoked;&lt;br /&gt;
&lt;br /&gt;
	if &amp;#039;table&amp;#039; == type (frame) then&lt;br /&gt;
		map_series = frame.args[1];												-- for an invoke&lt;br /&gt;
		if frame.args[2] then&lt;br /&gt;
			map_series_end = frame.args[2];&lt;br /&gt;
		end&lt;br /&gt;
			&lt;br /&gt;
		invoked = true;															-- flag used to modify final output rendering&lt;br /&gt;
	else&lt;br /&gt;
		map_series = frame;														-- when called from the debug console&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local temp_t = {}															-- output goes in this sequence table until rendering&lt;br /&gt;
	for k, v in pairs (data) do													-- for each entry in the data mofule&lt;br /&gt;
		local series, area, sheet = k:match (&amp;#039;^(%d+)(%u)(%d*)&amp;#039;);				-- fetch series, area, sheet from the entry&amp;#039;s key&lt;br /&gt;
		&lt;br /&gt;
		if tonumber(series) &amp;gt;= tonumber(map_series) and tonumber(series) &amp;lt;= tonumber(map_series_end or map_series) then	-- when this map is one of the map series we&amp;#039;re looking for&lt;br /&gt;
			local map_title_parts = mw.text.split (v, &amp;#039;|&amp;#039;);						-- extract an article title&lt;br /&gt;
			local qid = mw.wikibase.getEntityIdForTitle (map_title_parts[1]);	-- does this article title have a wikidata entry&lt;br /&gt;
			local lat, lon = wikidata_lat_lon_get (qid);						-- attempt to get P625 lat/lon from wikidata&amp;#039;s entry for the article title&lt;br /&gt;
			local bounds_msg = &amp;#039;&amp;#039;;												-- gets an error message if lat/lon from wikidata not within bounds of NTS map&lt;br /&gt;
&lt;br /&gt;
			if qid and lat then													-- when article title has wikidata entry an wikidata has P625 (latitude/longitude)&lt;br /&gt;
				bounds_msg = is_in_bounds (series, area, sheet, lat, lon);		-- empty string when in bounds; message else&lt;br /&gt;
			elseif qid then														-- lat can be nil when qid points to dab page or article does not have P625&lt;br /&gt;
				bounds_msg = string.format (&amp;#039;%s missing P625&amp;#039;, qid);			-- no lat/lon so no P625&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			local str;&lt;br /&gt;
			if not qid then														-- when article title doesn&amp;#039;t have a wikidata entry&lt;br /&gt;
				str = string.format (&amp;#039;\t[&amp;quot;%s&amp;quot;] = &amp;quot;%s&amp;quot;,&amp;#039;, k, v);					-- mimic the original&lt;br /&gt;
			elseif not lat then													-- has qid but does not have P625&lt;br /&gt;
				str = string.format (&amp;#039;[&amp;quot;%s&amp;quot;] = &amp;quot;%s&amp;quot;,&amp;#039;, k, v);					-- mimic the original + bounds_msg&lt;br /&gt;
				str = string.format (&amp;#039;\t%s%s-- %s&amp;#039;, str, string.rep (&amp;#039;\t&amp;#039;, tabbing (str)), bounds_msg);&lt;br /&gt;
			elseif map_title_parts[2] then										-- for piped article links&lt;br /&gt;
				str = string.format (&amp;#039;[&amp;quot;%s&amp;quot;] = &amp;quot;%s|%s&amp;quot;,&amp;#039;, k, qid, map_title_parts[2]);&lt;br /&gt;
				str = string.format (&amp;#039;\t%s%s-- %s; %s&amp;#039;, str, string.rep (&amp;#039;\t&amp;#039;, tabbing (str)), map_title_parts[1], bounds_msg);&lt;br /&gt;
			else																-- map name same as en.wiki article title&lt;br /&gt;
				str = string.format (&amp;#039;[&amp;quot;%s&amp;quot;] = &amp;quot;%s&amp;quot;,&amp;#039;, k, qid, map_title_parts[1]);&lt;br /&gt;
				str = string.format (&amp;#039;\t%s%s-- %s; %s&amp;#039;, str, string.rep (&amp;#039;\t&amp;#039;, tabbing (str)), map_title_parts[1], bounds_msg);&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			if invoked then														-- when this function called through an invoke&lt;br /&gt;
				str = str:gsub (&amp;#039;\t&amp;#039;, &amp;#039;&amp;amp;#9;&amp;#039;)									-- replace plain-text tabs with html numeric entities&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			table.insert (temp_t, str);											-- save &lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	table.sort (temp_t, sort);													-- ascending numerical sort by key (NTS id)&lt;br /&gt;
	for i=#temp_t, 1, -1 do														-- working backwards through the table&lt;br /&gt;
		if temp_t[i]:match (&amp;#039;%d+%u&amp;quot;%]&amp;#039;) then									-- if this key is an area key (no sheet)&lt;br /&gt;
			table.insert (temp_t, i, &amp;#039;&amp;#039;);										-- insert an empty string to separate area-from-area&lt;br /&gt;
		elseif i &amp;gt; 1 and temp_t[i]:match (&amp;#039;%[&amp;quot;(%d+)&amp;#039;) ~= temp_t[i-1]:match (&amp;#039;%[&amp;quot;(%d+)&amp;#039;) then	-- because some series list don&amp;#039;t begin with area maps (15 for example)&lt;br /&gt;
			table.insert (temp_t, i, &amp;#039;&amp;#039;);										-- insert an empty string to separate area-from-area&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if invoked then																-- when this function called through an invoke&lt;br /&gt;
		return table.concat ({&amp;#039;&amp;lt;pre&amp;gt;&amp;#039;, table.concat (temp_t, &amp;#039;&amp;lt;br /&amp;gt;&amp;#039;),&amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;});	-- concatenate into a big string using &amp;lt;br /&amp;gt; tags and wrapped in &amp;lt;pre&amp;gt;...&amp;lt;/pre&amp;gt; tagsand done&lt;br /&gt;
	else&lt;br /&gt;
		return table.concat (temp_t, &amp;#039;\n&amp;#039;);										-- concatenate into a big string using plain-text newlines and done&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; N T S _ K E Y _ V A L I D A T E &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
debug console function to makes sure that all keys in Module:Canada NTS/data have the correct form&lt;br /&gt;
&lt;br /&gt;
=p.nts_key_validate()&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function nts_key_validate()&lt;br /&gt;
	for k, _ in pairs (data) do&lt;br /&gt;
		local series, area, sheet = k:match (&amp;#039;^(%d+)(%u)(%d*)$&amp;#039;);&lt;br /&gt;
		if not series then&lt;br /&gt;
			return &amp;#039;&amp;lt;span style=&amp;quot;color:#d33&amp;quot;&amp;gt;invalid key: &amp;#039; .. k .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		if not nts.nts_series_validate (tonumber(series)) then&lt;br /&gt;
			return &amp;#039;&amp;lt;span style=&amp;quot;color:#d33&amp;quot;&amp;gt;invalid series: &amp;#039; .. k .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
		end&lt;br /&gt;
		if not nts.nts_area_validate (tonumber(series), area) then&lt;br /&gt;
			return &amp;#039;&amp;lt;span style=&amp;quot;color:#d33&amp;quot;&amp;gt;invalid area: &amp;#039; .. k .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
		end&lt;br /&gt;
		if &amp;#039;&amp;#039; ~= sheet and not nts.nts_sheet_validate (tonumber(sheet)) then&lt;br /&gt;
			return &amp;#039;&amp;lt;span style=&amp;quot;color:#d33&amp;quot;&amp;gt;invalid sheet: &amp;#039; .. k .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;keys are valid&amp;#039;;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
--[[--------------------------&amp;lt; E X P O R T E D   F U N C T I O N S &amp;gt;------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	main = main,&lt;br /&gt;
	nts_key_validate = nts_key_validate,&lt;br /&gt;
	}&lt;/div&gt;</summary>
		<author><name>imported&gt;Legoktm</name></author>
	</entry>
</feed>