<?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%2FWnt%2FFindFeatures%2FdisplayDatabase</id>
	<title>Module:Sandbox/Wnt/FindFeatures/displayDatabase - 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%2FWnt%2FFindFeatures%2FdisplayDatabase"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/Wnt/FindFeatures/displayDatabase&amp;action=history"/>
	<updated>2026-04-18T02:08:41Z</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/Wnt/FindFeatures/displayDatabase&amp;diff=146413&amp;oldid=prev</id>
		<title>imported&gt;Primefac: Primefac moved page Module:FindFeatures/displayDatabase to Module:Sandbox/Wnt/FindFeatures/displayDatabase without leaving a redirect: per TFD closure</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/Wnt/FindFeatures/displayDatabase&amp;diff=146413&amp;oldid=prev"/>
		<updated>2019-11-23T23:37:57Z</updated>

		<summary type="html">&lt;p&gt;Primefac moved page &lt;a href=&quot;/index.php?title=Module:FindFeatures/displayDatabase&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Module:FindFeatures/displayDatabase (page does not exist)&quot;&gt;Module:FindFeatures/displayDatabase&lt;/a&gt; to &lt;a href=&quot;/research/Module:Sandbox/Wnt/FindFeatures/displayDatabase&quot; title=&quot;Module:Sandbox/Wnt/FindFeatures/displayDatabase&quot;&gt;Module:Sandbox/Wnt/FindFeatures/displayDatabase&lt;/a&gt; without leaving a redirect: per TFD closure&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt; -- This module finds features with coordinates in a certain area on a globe.&lt;br /&gt;
 -- current focus is Mars.  Earth, celestial, etc. would be nice also.&lt;br /&gt;
 -- all three dimensionality is hereby banned from the procedure on account of requiring far too much intelligence to get working.&lt;br /&gt;
&lt;br /&gt;
local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
local p = {}&lt;br /&gt;
debuglog=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
function tidyNum(text)&lt;br /&gt;
	text = mw.ustring.gsub(text, &amp;quot; &amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
	text = mw.ustring.gsub(text, &amp;quot;,&amp;quot;, &amp;quot;.&amp;quot;)&lt;br /&gt;
	return tonumber(text)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function parseValue(text)&lt;br /&gt;
	-- extract 3 or 2 or 1 values from the string.  Can contain . or , as a decimal, no spaces allowed.&lt;br /&gt;
    local d, m, s = mw.ustring.match(text,&amp;quot;(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&amp;amp;%*%(%)%=|\~&amp;#039;]+(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&amp;amp;%*%(%)%=|\~&amp;#039;]+(%-?%d+[%.,]?%d*)&amp;quot;)&lt;br /&gt;
    if not d then d, m = mw.ustring.match(text,&amp;quot;(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&amp;amp;%*%(%)%=|\~&amp;#039;]+(%-?%d+[%.,]?%d*)&amp;quot;) end&lt;br /&gt;
    if not d then d = mw.ustring.match(text,&amp;quot;(%-?%d+[%.,]?%d*)&amp;quot;) end&lt;br /&gt;
    if d then&lt;br /&gt;
    	d = tidyNum(d or &amp;quot;0&amp;quot;) + tidyNum(m or &amp;quot;0&amp;quot;)/60 + tidyNum(s or &amp;quot;0&amp;quot;)/3600&lt;br /&gt;
    end&lt;br /&gt;
    debuglog = debuglog .. tostring(d)&lt;br /&gt;
    return d&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function parseDirection(text)&lt;br /&gt;
	local direction = mw.ustring.match(text,&amp;quot;%A([NSEWnsew])%A&amp;quot;) or mw.ustring.match(text,&amp;quot;^([NSEWnsew])%A&amp;quot;) or mw.ustring.match(text,&amp;quot;%A([NSEWnsew])$&amp;quot;)&lt;br /&gt;
    if (not direction) then&lt;br /&gt;
    	direction = mw.ustring.match(text,&amp;quot;([Nn])[Oo][Rr][Tt][Hh]&amp;quot;) or mw.ustring.match(text,&amp;quot;([Ss])[Oo][Uu][Tt][Hh]&amp;quot;) or mw.ustring.match(text,&amp;quot;([Ee])[Aa][Ss][Tt]&amp;quot;) or mw.ustring.match(text,&amp;quot;([Ww])[Ee][Ss][Tt]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
    if direction then direction = mw.ustring.upper(direction) end&lt;br /&gt;
    return direction&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function parseCoord(text)&lt;br /&gt;
	local text = mw.ustring.upper(text) -- we&amp;#039;re only getting direction letters and numbers here&lt;br /&gt;
	local coord = {}&lt;br /&gt;
	local ok&lt;br /&gt;
	-- maybe it&amp;#039;s a Coord call like &amp;quot;{{Coord|37.3|N|259.0|E|globe:Mars_type:mountain}}&amp;quot; - then only search the template&lt;br /&gt;
    text = mw.ustring.match(text,&amp;quot;{{COORD(.-)}}&amp;quot;) or text&lt;br /&gt;
	-- maybe it&amp;#039;s a simple coordinate like 37N,33E?&lt;br /&gt;
	-- note: currently does NOT hunt for deg, min, sec variations.  ASSuMEs that order.&lt;br /&gt;
	-- In this case, parsing what to do based on three numbers starts to fall apart (what if there are five?)&lt;br /&gt;
	-- Instead, look for the direction markers first, then split into two bound parsing problems&lt;br /&gt;
    local first, second = mw.ustring.match(text,&amp;quot;^(.-%A)[NSEW](%A.-)$&amp;quot;)&lt;br /&gt;
    if first and second and mw.ustring.match(first,&amp;quot;%d&amp;quot;) then&lt;br /&gt;
    	coord[1] = parseValue(first)&lt;br /&gt;
    	second = mw.ustring.match(second, &amp;quot;^(.-%A)[NSEW]%A.-$&amp;quot;) or mw.ustring.match(second, &amp;quot;^(.-%A)[NSEW]$&amp;quot;) or second&lt;br /&gt;
    	coord[2] = parseValue(second)&lt;br /&gt;
    	if (coord[1] and coord[2]) then ok = true end&lt;br /&gt;
    end&lt;br /&gt;
    if (ok) then&lt;br /&gt;
         -- at this point the amounts of coord[1] (lat) and coord[2] (lon) are set, but what directions?&lt;br /&gt;
        local firstdir = parseDirection(text)&lt;br /&gt;
        local seconddir = firstdir&lt;br /&gt;
        if firstdir then&lt;br /&gt;
            frag = text&lt;br /&gt;
            repeat -- I just keep the first letter of the direction, not the context, so need to run forward to it&lt;br /&gt;
            	frag = mw.ustring.match(frag, firstdir .. &amp;quot;(.*)$&amp;quot;)&lt;br /&gt;
            	seconddir = parseDirection(frag)&lt;br /&gt;
            until seconddir ~= firstdir&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
    	-- last ditch effort: take the first two numbers in the section, WHATEVER they are.  Can be signed.  No directions!&lt;br /&gt;
    	coord[1], coord[2] = mw.ustring.match(text,&amp;quot;(%-?%d+[%.,]?%d*)[%a%c%s%z!@#$%%^&amp;amp;%*%(%)%=|&amp;#039;{}:;&amp;lt;&amp;gt;~`]+(%-?%d+[%.,]?%d*)&amp;quot;)&lt;br /&gt;
    	debuglog = debuglog .. &amp;quot;L&amp;quot; .. tostring(coord[1]) .. &amp;quot;D&amp;quot; .. tostring(coord[2])&lt;br /&gt;
    	if not (coord[1] and coord[2]) then return nil end&lt;br /&gt;
    	coord[1] = tidyNum(coord[1])&lt;br /&gt;
    	coord[2] = tidyNum(coord[2])&lt;br /&gt;
    	debuglog = debuglog .. &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    -- invert signs for west, south positions&lt;br /&gt;
    if (firstdir == &amp;quot;W&amp;quot; or firstdir == &amp;quot;S&amp;quot;) then&lt;br /&gt;
    	coord[1] = -1 * coord[1]&lt;br /&gt;
    end&lt;br /&gt;
    if (seconddir == &amp;quot;W&amp;quot; or seconddir == &amp;quot;S&amp;quot;) then&lt;br /&gt;
    	coord[2] = -1 * coord[2]&lt;br /&gt;
    end&lt;br /&gt;
    -- if first is E/W, put it second&lt;br /&gt;
    if (firstdir == &amp;quot;W&amp;quot; or firstdir == &amp;quot;E&amp;quot;) then&lt;br /&gt;
    	coord[1], coord[2] = coord[2], coord[1]&lt;br /&gt;
    end&lt;br /&gt;
    -- default without directions specified: first = latitude, no sign reversal&lt;br /&gt;
    if (not firstdir) then&lt;br /&gt;
    	firstdir = &amp;quot;N&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    if (not seconddir) then&lt;br /&gt;
    	seconddir = &amp;quot;E&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    debuglog = debuglog .. tostring(coord[1]) .. tostring(coord[2])&lt;br /&gt;
	if mw.ustring.match(seconddir,&amp;quot;[NS]&amp;quot;) or mw.ustring.match(firstdir,&amp;quot;[EW]&amp;quot;) then&lt;br /&gt;
	    return nil, &amp;quot;two of one direction in coordinate&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	while coord[2] &amp;gt; 180 do&lt;br /&gt;
            coord[2] = coord[2] - 360&lt;br /&gt;
        end&lt;br /&gt;
        while coord[2] &amp;lt; -180 do&lt;br /&gt;
            coord[2] = coord[2] + 360&lt;br /&gt;
        end&lt;br /&gt;
	-- at this point firstdir and seconddir no longer mean anything - direction is in the + or - and first or second position&lt;br /&gt;
	return coord, warning&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getData(pagetitle, database, pRadius, eRadius)&lt;br /&gt;
	local pagecontent&lt;br /&gt;
	if pagetitle then&lt;br /&gt;
		pagecontent = pagetitle:getContent()&lt;br /&gt;
	end&lt;br /&gt;
	if not pagecontent then return database end&lt;br /&gt;
	pagecontent = mw.ustring.gsub(pagecontent, &amp;quot;^.-{|&amp;quot;, &amp;quot;{|&amp;quot;) -- remove all before first table&lt;br /&gt;
	if not pagecontent then return database end&lt;br /&gt;
	pagecontent = mw.ustring.gsub(pagecontent, &amp;quot;|}.-{|&amp;quot;, &amp;quot;&amp;quot;) or pagecontent -- remove all between tables&lt;br /&gt;
	pagecontent = mw.ustring.gsub(pagecontent, &amp;quot;|}.-$&amp;quot;, &amp;quot;|}&amp;quot;) or pagecontent -- remove all after table&lt;br /&gt;
	local pagerecord = mw.text.split(pagecontent,&amp;quot;|%-&amp;quot;) -- separate all table rows into records&lt;br /&gt;
	for i = 1, #pagerecord do&lt;br /&gt;
		recordname = mw.ustring.match(pagerecord[i],&amp;quot;%[%[(.-)%]%]&amp;quot;)&lt;br /&gt;
		recordcoord = parseCoord(pagerecord[i])&lt;br /&gt;
		if recordname and recordcoord then table.insert(database,{recordname, recordcoord}) end&lt;br /&gt;
	end&lt;br /&gt;
	return database&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getDatabase(pages, pRadius, eRadius)&lt;br /&gt;
	local database = {}&lt;br /&gt;
	local page = mw.text.split(pages,&amp;quot;|&amp;quot;)&lt;br /&gt;
	for i = 1, #page do&lt;br /&gt;
		local pagename = mw.text.trim(page[i] or &amp;quot;&amp;quot;)&lt;br /&gt;
		local pagetitle = mw.title.new(pagename)&lt;br /&gt;
		database = getData(pagetitle,database, pRadius, eRadius) -- (so far as I know this is a self assignment, actually)&lt;br /&gt;
	end&lt;br /&gt;
	return database&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function display(dataitem)&lt;br /&gt;
	local recordname, recordcoord = dataitem[1], dataitem[2]&lt;br /&gt;
	return &amp;#039;&amp;quot;&amp;#039;..recordname..&amp;#039;&amp;quot;, {&amp;#039; .. recordcoord[1] .. &amp;quot;, &amp;quot; .. recordcoord[2] .. &amp;quot;}&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function displayDatabase(database)&lt;br /&gt;
	local outarray = {}&lt;br /&gt;
	local outprefix = &amp;quot;&amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;\nreturn {{&amp;quot;&lt;br /&gt;
	local delimiter = &amp;quot;},\n{&amp;quot;&lt;br /&gt;
	local outsuffix = &amp;quot;}}\n&amp;lt;/pre&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
	for i = 1, #database do&lt;br /&gt;
		table.insert(outarray,display(database[i]))&lt;br /&gt;
	end&lt;br /&gt;
	return (outprefix .. table.concat(outarray, delimiter) .. outsuffix)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._main(frame, pRadius, eRadius, defaultdata)&lt;br /&gt;
	 -- for now this is not really intended to be called except from other functions here - use planet name to call&lt;br /&gt;
     -- handle args in this module&lt;br /&gt;
     -- other parameters are REQUIRED.&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	data = args.data or defaultdata&lt;br /&gt;
	database = getDatabase(data, pRadius, eRadius)&lt;br /&gt;
    return displayDatabase(database) .. debuglog&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.mars(frame)&lt;br /&gt;
     -- module name defines Mars - now set the radius accordingly&lt;br /&gt;
	local pRadius = 3376.2 -- km (polar)&lt;br /&gt;
	local eRadius = 3396.2 -- km (equatorial)&lt;br /&gt;
    local defaultdata = &amp;#039;List of mountains on Mars|List of craters on Mars: A-G|List of craters on Mars: H-N|List of craters on Mars: O-Z|List of catenae on Mars&amp;#039;&lt;br /&gt;
    return p._main(frame, pRadius, eRadius, defaultdata)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.venus(frame)&lt;br /&gt;
	local pRadius = 6051.8 -- km&lt;br /&gt;
	local eRadius = 6051.8 -- km (doh, it doesn&amp;#039;t spin much!)&lt;br /&gt;
	local defaultdata = &amp;#039;List of craters on Venus|List of montes on Venus|List of coronae on Venus&amp;#039;&lt;br /&gt;
	return p._main(frame, pRadius, eRadius, defaultdata)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.moon(frame)&lt;br /&gt;
	-- NOTE: our articles listing craters on the Moon don&amp;#039;t include coordinates!&lt;br /&gt;
	-- Also there are so many it might run out the clock on the module, we&amp;#039;d have to see&lt;br /&gt;
	local pRadius = 1735.97 -- km&lt;br /&gt;
	local eRadius = 1738.14 -- km&lt;br /&gt;
	local defaultdata = &amp;#039;List of lunar features&amp;#039; -- (duplicates:) &amp;#039;List of mountains on the Moon|List of valleys on the Moon|List of maria on the Moon&amp;#039;&lt;br /&gt;
	return p._main(frame, pRadius, eRadius, defaultdata)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.mercury(frame)&lt;br /&gt;
	local pRadius = 2439.7 -- km&lt;br /&gt;
	local eRadius = 2439.7 -- km&lt;br /&gt;
	local defaultdata = &amp;#039;List of geological features on Mercury|List of craters on Mercury&amp;#039;&lt;br /&gt;
	-- no coord templates in these, watch for bad coordinates&lt;br /&gt;
	return p._main(frame, pRadius, eRadius, defaultdata)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.earthCraters(frame)&lt;br /&gt;
	-- a general list of all Earth features would be beyond a simple Lua module!&lt;br /&gt;
	local pRadius = 6356.8 -- km&lt;br /&gt;
	local eRadius = 6378.1 -- km&lt;br /&gt;
	local defaultdata = &amp;#039;List of impact craters in Africa|List of impact craters in Antarctica|List of impact craters in Asia|List of impact craters in Australia|List of impact craters in Europe|List of impact craters in North America|List of impact craters in South America&amp;#039;&lt;br /&gt;
	return p._main(frame, pRadius, eRadius, defaultdata)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Primefac</name></author>
	</entry>
</feed>