Module:Track gauge/autodocument/sandbox

-- This module documents the track gauges -- as defined in module:Track gauge/data and module:Track gauge/extra. local p = {} local getArgs = require('Module:Arguments').getArgs local modMath = require('Module:Math') local html = require('Module:HtmlBuilder') local tableTools = require('Module:tableTools') local TrackGauge = require('Module:Track gauge/sandbox') -- sainndbox here local dataPageName = 'Module:Track gauge/data/sandbox' -- sandbox here local dataPageExtra = 'Module:Track gauge/extra/sandbox' -- sandbox here

local stats = {		ttlAliasCount, ttlEntries, ttlAltNameCount, ttlLinkCount, ttlContentCatsCount, ttlMentioningCatsCount, ttlMentioningPageCount }

local gaugeDataAll = nil local gaugeDataExtra = nil -- global counters (to keep between the id-row building calls) local ttlSizeClassCount = {} --local ttlAliasCount = 0-- --local ttlEntries = 0-- local ttlUnitCount = {} local ttlAltNameCount = 0-- local ttlAltName = {} local ttlLinkCount = 0-- local ttlContentCatsCount = 0 -- local ttlMentioningCatsCount = 0 -- local ttlMentioningPageCount = 0 -- local ttlListedRange = {}

local echo = {} --- -- prepareArgs -- Arguments coming from an #invoke or from a module --- local function prepareArgs(frame) local origArgs = getArgs(frame) -- Trim whitespace, make lower-case and remove blank arguments for all arguments -- searchAlias is the cleaned value of [1]. [1] is kept as rawInput for error message local args = {} args['searchAlias'] = '' args['rawInput'] = origArgs[1] or '' for k, v in pairs(origArgs) do		if tonumber(k) == nil then -- Named argument if k == 'docsortlabel' then -- not in RG				args[k] = v			else args[k] = mw.ustring.lower(v) end else -- Unnamed argument, alias to be searched args[k] = TrackGauge.normaliseAliasInput(v) if k == 1 then args['searchAlias'] = args[1] end end end return args end --- -- formatUnitPlaintext -- Pattern '00016.5 mm' for table.sort and catsort. Can be wrapped in class="sortkey" --- local function formatUnitPlaintext(tgEntry, unit, fmtZeroPadding, toFracChar) -- Returns plaintext (ASCII) only. No css. if tgEntry == nil then return '' end if (unit or tgEntry.def) == 'imp' then -- imperial local ft = '' local inch = '' local frac = '' if tgEntry.ft then ft = tgEntry.ft .. ' ft' end if tgEntry.num then frac = ' ' .. tgEntry.num .. '/' .. tgEntry.den if toFracChar then -- as used in contentCat pagenames if frac == ' 1/8' then frac = '⅛' elseif frac == ' 1/4' then frac = '¼' elseif frac == ' 3/8' then frac = '⅜' elseif frac == ' 1/2' then frac = '½' elseif frac == ' 3/4' then frac = '¾' elseif frac == ' 7/8' then frac = '⅞' else frac = frac .. ' (error: fraction character missing in module:Track gauge)' end end if tgEntry['in'] then frac = ' ' .. tgEntry['in'] .. frac .. ' in' else frac = ' ' .. frac .. ' in' end else if tgEntry['in'] then inch = ' ' .. tgEntry['in'] .. ' in' end end return mw.text.trim(ft .. inch .. frac) else -- metric (mm) if fmtZeroPadding == nil or tonumber(fmtZeroPadding) <= 0 then return tgEntry.id .. ' mm' else return string.rep('0', fmtZeroPadding - math.floor(math.log10(tonumber(tgEntry.id))) - 1) .. tgEntry.id .. ' mm' end end end --- -- documentSortKey --- local function documentSortKey(tgEntry) local s = formatUnitPlaintext(tgEntry, 'met', 5) return tostring(html.create.tag('span').addClass('sortkey').wikitext(s)) end --- -- catSortFromTitle -- Currently finds "600 mm" when at end of title, then returns "0600 mm" (for catSort). -- Blank when not found. Used for cat:mentions category page. --- function p.catSortFromTitle local title = mw.title.getCurrentTitle local catSort = string.match(title.text, '%s(%d+%.?%d*)%smm$') or '' if catSort ~= '' then catSort = string.rep('0', 4 - math.floor(math.log10(tonumber(catSort))) - 1) .. catSort .. ' mm' end if catSort == '' then return '*' else return catSort end end --- -- documentGaugeClass --- local function documentGaugeClass(tgEntry, countMentionings) local size = tonumber(tgEntry.id or 0) local j	if size > 1435 then j = 5 elseif size == 1435 then j = 4 elseif size > 500 then j = 3 elseif size >= 100 then j = 2 elseif size > 0 then j = 1 else j = 6 end ttlSizeClassCount[j][2] = ttlSizeClassCount[j][2] +1 ttlSizeClassCount[j][4] = ttlSizeClassCount[j][4] + (countMentionings or 0) return ' ' .. j .. ' ' .. ttlSizeClassCount[j][1] end --- -- anchor -- Anchor text *here* is: ; anchor *there* is: #1000 mm. --- local function anchor(tgEntry, unit, herethere) if tgEntry == nil then return '' end unit = unit or tgEntry.def1 local anch = formatUnitPlaintext(tgEntry, unit, 0) if herethere == 'there' then -- Untested, April 2014 anch = '#' .. anch else anch = html.create.tag('span').attr('id', anch) end return tostring(anch) end --- -- noWrap -- Add span tags to prevent a string from wrapping. --- local function noWrap(s) return mw.ustring.format(' %s ', s) end --- -- frac -- A slimmed-down version of the 1/undefined template (a nowrap to be added with the unit) --- local function frac(whole, num, den) return mw.ustring.format(		' %s%s%s&frasl;%s ',		whole or , whole and ' ' or , num, den		) end --- -- debugReturnArgs --- function p.debugReturnArgs(frame) local args = prepareArgs(frame) local retArgs = {} for k, a in pairs(args) do table.insert(retArgs, k .. '=' .. a)	end return 'Args: ' .. table.concat(retArgs, '; ') end --- -- checkData -- Public. Performs various checks on the /data subpage. --- function p.checkData(frame) --To be checked: numeric input not allowed (deprecated 20140615; as yet remaining: 1435, 56.5). --To be allowed: entry.link empty; then use entry.name. local dataPage = frame and frame.args and frame.args[1] or dataPageName local data = mw.loadData(dataPage) local exists, dupes, dupeSort, ret = {}, {}, {}, {} -- Check for duplicate aliases. for ti, t in ipairs(data) do		for ai, alias in ipairs(t.aliases or {}) do			if not exists[alias] then exists[alias] = { ti, ai } else if not dupes[alias] then dupes[alias] = { exists[alias] } end table.insert(dupes[alias], { ti, ai }) end end end for alias in pairs(dupes) do		table.insert(dupeSort, alias) end table.sort(dupeSort) for i1, alias in ipairs(dupeSort) do		local positions = {} for i2, aliasKeys in ipairs(dupes[alias]) do			local position = mw.ustring.format('gauge %d, alias %d (gauge id: )', aliasKeys[1], aliasKeys[2], data[aliasKeys[1]].id or '') table.insert(positions, position) end local aliasText = mw.ustring.format('Duplicate aliases "%s" detected at the following positions: %s.', alias, mw.text.listToText(positions, '; ')) table.insert(ret, aliasText) end -- Check for numerators without denominators. for ti, t in ipairs(data) do		local num = t.num local den = t.den if num and not den then table.insert(ret, mw.ustring.format('Numerator "%s" with no denominator detected at gauge %d (id: ).', num, ti, t.id or '')) elseif den and not num then table.insert(ret, mw.ustring.format('Denominator "%s" with no numerator detected at gauge %d (id: ).', den, ti, t.id or '')) end end -- Check for gauges with no imperial or no metric measurements. for ti, t in ipairs(data) do		if not (t.ft or t['in'] or t.num or t.den) then table.insert(ret, mw.ustring.format('No imperial measurements found for gauge %d (id: ).', ti, t.id or '')) end if not (t.m or t.mm) then table.insert(ret, mw.ustring.format('No metric measurements found for gauge %d (id: ).', ti, t.id or '')) end end -- Check for non-numeric measurements. local measurements = { 'ft', 'in', 'num', 'den', 'm', 'mm' } for ti, t in ipairs(data) do		for mi, measurement in ipairs(measurements) do			local measurementVal = t[measurement] if measurementVal and not tonumber(measurementVal) then table.insert(ret, mw.ustring.format('Non-numeric  measurement ("%s") found for gauge %d (id:  ).', measurement, measurementVal, ti, t.id or '')) end end end -- Check for gauges with no id. for ti, t in ipairs(data) do		if not t.id then local aliases = {} for i, alias in ipairs(t.aliases) do				table.insert(aliases, mw.ustring.format(' ', alias)) end aliases = mw.ustring.format(' (aliases: %s)', mw.text.listToText(aliases)) table.insert(ret, mw.ustring.format('No id found for track gauge %d%s.', ti, aliases or '')) end end -- Check for gauges with no aliases. for ti, t in ipairs(data) do		if type(t.aliases) ~= 'table' then table.insert(ret, mw.ustring.format('No aliases found for gauge %d (id: ).', ti, t.id or '')) else local isAlias = false for ai, alias in ipairs(t.aliases) do				isAlias = true break end if not isAlias then table.insert(ret, mw.ustring.format('No aliases found for gauge %d (id: ).', ti, t.id or '')) end end end -- Check for named gauges with no links and gauges with links but no names. -- 20140520: no link? could be acceptable. Code falls back to the unlinked name (in test now). if false then -- skipped 2014-05-25 for ti, t in ipairs(data) do		if t.name and not t.link then table.insert(ret, mw.ustring.format('No link found for the named gauge "%s" at position %d (id: ).', t.name, ti, t.id or '')) elseif t.link and not t.name then table.insert(ret, mw.ustring.format('No name found for the gauge with link "%s" at position %d (id: ).', t.link, ti, t.id or '')) end end end -- Check for invalid def1 values. for ti, t in ipairs(data) do	local def = t.def1 if def ~= 'imp' and def ~= 'met' then table.insert(ret, mw.ustring.format('Invalid def1 value "%s" found for gauge %d (id: ).', def or , ti, t.id or )) end end -- Check for unwanted whitespace. for ti, t in ipairs(data) do		for tkey, tval in pairs(t) do			if tkey == 'aliases' and type(tval) == 'table' then for ai, alias in ipairs(tval) do					if mw.ustring.find(alias, '%s') then table.insert(ret, mw.ustring.format('Unwanted whitespace detected in gauge %d alias %d ("%s", gauge id: ).', ti, ai, alias, t.id or '')) end end elseif tkey == 'name' or tkey == 'link' or tkey == 'pagename' or tkey == 'contentcat' then if tval ~= mw.text.trim(tval) then table.insert(ret, mw.ustring.format('Unwanted whitespace detected in  field of gauge %d ("%s", gauge id:  ).', tkey, ti, tval, t.id or '')) end elseif mw.ustring.find(tval, '%s') then table.insert(ret, mw.ustring.format('Unwanted whitespace detected in  field of gauge %d ("%s", gauge id:  ).', tkey, ti, tval, t.id or '')) end end end -- Added April 2014: alias should not double with another id (imp and mm not ambiguous) local self_id = '' local self_def = '' for ti, t in ipairs(data) do		self_id = t.id		self_def = t.def1 for iC, aliasCheck in ipairs(t.aliases) do			if tonumber(aliasCheck) ~= nil then if self_id ~= aliasCheck then for iTwo, tTwo in ipairs(data) do						if aliasCheck == tTwo.id then table.insert(ret,								mw.ustring.format('Input alias %s (%s) from  ambiguous with gauge id=  (%s)' , aliasCheck, self_def, self_id, tTwo.id, tTwo.def1)								) end end end end end end -- Return any errors found. for i, msg in ipairs(ret) do		ret[i] = mw.ustring.format(' %s ', msg) end if #ret > 0 then return mw.ustring.format('Found the following errors in %s:\n* %s', dataPage, table.concat(ret, '\n* ')) else return mw.ustring.format('No errors found in %s.', dataPage) end end --- -- catContent -- content category for the gauge --- function p.catContent(frame) -- catContent (content category for this alias) -- can be hardcoded in the data, or build by size (pattern) local args = prepareArgs(frame) local tgEntry = TrackGauge.getRgEntry(args.searchAlias) if tgEntry == nil then return args['displaynotfound'] or 'No gauge entry found for ' .. (args[1] or '""') end local catTitle local label local catC local docsortlabel = '' if args.docsortlabel ~= nil then docsortlabel = '|' .. args.docsortlabel end if tgEntry.contentcat == '' then catC = '' elseif tgEntry.contentcat ~= nil then catC = 'Category:' .. tgEntry.contentcat .. docsortlabel .. '' else -- no name given, try default name: local catCsuffix = ' gauge railways' if tgEntry.def1 == 'met' then label = formatUnitPlaintext(tgEntry, 'met') catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then catC =  .. catTitle.fullText .. docsortlabel ..  end elseif tgEntry.def1 == 'imp' then label = formatUnitPlaintext(tgEntry, 'imp', nil, true) catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then catC =  .. catTitle.fullText .. docsortlabel ..  end end end return catC end --- -- catMentions -- maintenance only --- function p.catMentions(frame) local args = prepareArgs(frame) local tgEntry = TrackGauge.getRgEntry(args.searchAlias) if tgEntry == nil then return args['displaynotfound'] or 'No gauge entry found for ' .. (args[1] or '""') end local catM = TrackGauge.catMentions(tgEntry, args.docsortlabel, 'show') return catM end --- -- createCatMentions -- Create page, with a preload --- function p.createCatMentions(frame) local pagePreloadName = 'Template:Track gauge/preload-categorypage-trackgauge-mentionings' -- sandbox here local urlAction = 'edit' local args = prepareArgs(frame) local tgEntry = TrackGauge.getRgEntry(args.searchAlias) if tgEntry == nil then return args['displaynotfound'] or 'No track gauge entry found for ' .. (args[1] or '""') end -- Create this cat local ret = {} local checkTitle = mw.title.makeTitle(14, TrackGauge.catMentions(tgEntry, nil, 'pagename')) if checkTitle.exists then table.insert(ret, 'id=' .. tgEntry.id) table.insert(ret,  .. checkTitle.fullText .. ) else local qryString = mw.uri.parseQueryString('action=' .. urlAction .. '&preload=' .. pagePreloadName) local urlCreate = tostring(mw.uri.fullUrl(checkTitle.fullText, qryString)) table.insert(ret, 'id=' .. tgEntry.id) table.insert(ret,  .. checkTitle.fullText .. ) table.insert(ret, '[' .. urlCreate .. ' create]') table.insert(ret, 'preload') table.insert(ret, 'Data source: data or extra') end return table.concat(ret, '; ') end --- -- fromInputToId -- Used cleaned Alias as searchkey --- local function fromInputToId(searchAlias) gaugeDataAll = mw.loadData(dataPageName) for i, tgEntry in ipairs(gaugeDataAll) do		for j, alias in ipairs(tgEntry.aliases) do			if alias == searchAlias then return tgEntry.id			end end end -- Second search: in /Extra gaugeDataExtra = mw.loadData(dataPageExtra) for i, tgEntry in ipairs(gaugeDataExtra) do		for j, alias in ipairs(tgEntry.aliases) do			if alias == searchAlias then return tgEntry.id			end end end -- Third search: by id (autodocument only, not in main RG) if tonumber(searchAlias) ~= nil then for i, tgEntry in ipairs(gaugeDataAll) do			if tgEntry.id == searchAlias then return tgEntry.id			end end for i, tgEntry in ipairs(gaugeDataExtra) do			if tgEntry.id == searchAlias then return tgEntry.id			end end end end --- -- documentInchCount -- Number of inches in decimals. --- local function documentInchCount(tgEntry) local inches = 0 if tgEntry['num'] ~= nil then inches = modMath._round(tonumber((tgEntry['num'] or 0) / (tgEntry['den'] or 1)), 4) end inches = tostring((tonumber(tgEntry['ft'] or 0) * 12)		+ tonumber(tgEntry['in'] or 0) + inches) return inches end --- -- documentInchToMm -- Not used lately --- local function documentInchToMm(inchCount) return tonumber(inchCount or 0) * 25.4 end --- -- documentGaugeSizeFromTitle -- Currently finds "1620 mm" when at end of title, -- then returns "1620". Blank when not found. --- function p.documentGaugeSizeFromTitle local title = mw.title.getCurrentTitle return string.match(title.text, '%s(%d+%.?%d*)%smm$') or '' end --- -- documentBuildTgList -- The table of id's to fill the table --- function documentBuildTgList(args) -- Build series from the list. idFrom and idTo are numerical local tgList = {} local idFrom = -1 local idTo = -1 for i, v in ipairs(args) do		if v == 'all' then idFrom = -math.huge idTo = math.huge break end end if args.docfrom ~= nil then idFrom = tonumber(fromInputToId(args.docfrom)			or mw.ustring.gsub(args.docfrom, 'mm', '')) idTo = math.huge end if args.docto ~= nil then idTo = tonumber(fromInputToId(args.docto)			or mw.ustring.gsub(args.docto, 'mm', '')) end if idTo > 0 then -- Some list is requested from the whole data set if idFrom > idTo then local dummy = idFrom idFrom = idTo idTo = dummy end for i, tgEntry in ipairs(gaugeDataAll) do			if (tonumber(tgEntry.id) >= idFrom) and (tonumber(tgEntry.id) <= idTo) then table.insert(tgList, tonumber(tgEntry.id)) end end for i, tgEntry in ipairs(gaugeDataExtra) do			if (tonumber(tgEntry.id) >= idFrom) and (tonumber(tgEntry.id) <= idTo) then table.insert(tgList, tonumber(tgEntry.id)) end end tgList = tableTools.removeDuplicates(tgList) table.sort(tgList) if #tgList > 1 then ttlListedRange[1] = tgList[1] .. ' mm – ' .. tgList[#tgList] .. ' mm ' end end -- Individual entries can be mentioned in args (all unnamed = numbered params) -- Need a straight table.to keep sequence right local id	local argsAliasesIn = tableTools.compressSparseArray(args) for i, argsAlias in ipairs(argsAliasesIn) do		id = fromInputToId(argsAlias) if id ~= nil then table.insert(tgList, i, tonumber(id)) table.insert(ttlListedRange, i, id .. ' mm; ') end end ttlListedRange = tableTools.compressSparseArray(ttlListedRange) ttlListedRange = tableTools.removeDuplicates(ttlListedRange) tgList = tableTools.compressSparseArray(tgList) tgList = tableTools.removeDuplicates(tgList) return tgList end --- -- documentPostListStats -- build footer statistics table, after list only --- local function documentPostListStats(countTgList, docNote) -- Report data counters local retFoot = {} table.insert(retFoot, '\n*Sources') table.insert(retFoot, ':Data pages: ' .. dataPageName .. ', ' .. dataPageExtra .. '') table.insert(retFoot, '*Data') table.insert(retFoot, ':Listed: ' .. table.concat(ttlListedRange, '') .. ' (' .. countTgList .. ' rows)') table.insert(retFoot, ':Aliases (input options): ' .. stats.ttlAliasCount) table.insert(retFoot, ":Entries (gauge by alias): " .. stats.ttlEntries) table.insert(retFoot, ":Gauges (gauge by size): " .. countTgList) for i, stat in ipairs (ttlUnitCount) do table.insert(retFoot, ':' .. stat[2] .. ': ' .. stat[1]) end table.insert(retFoot, ':Entries with an article link: ' .. ttlLinkCount) table.insert(retFoot, '*Named gauges (alt names)') table.insert(retFoot, ':Entries with a name (' .. ttlAltNameCount .. '&times;): ' .. table.concat(ttlAltName, '; ')) -- Categories (content, maintenance) table.insert(retFoot, '*Categories') table.insert(retFoot, ':Content categories: ' .. ttlContentCatsCount) table.insert(retFoot, ':"Article mentions track gauge" categories: ' .. ttlMentioningCatsCount) table.insert(retFoot, ':Articles listed in "mentions" categories: ' .. ttlMentioningPageCount .. ' (not unique; standard gauge mentionings are not categorized)') -- Size classes (narrow, broad, ..) table.insert(retFoot, '*Size classes') for i, stat in ipairs (ttlSizeClassCount) do		if stat[2] ~= 0 then table.insert(retFoot, ':' .. stat[2] .. ' ' .. stat[3] .. ' (' .. stat[4] .. ' mentionings)') end end if docNote then table.insert(retFoot, '*Note:') table.insert(retFoot, ':' .. docNote) end

local anchor = tostring(html.create.tag('span').attr('id', 'Statistics')) -- help:using colors. Hue=190 (blue) local statTable = anchor .. '\n{| class="wikitable collapsible collapsed" style="background-color:#e6fbff; font-size:85%; width:100%;"' .. '\n|-' .. '\n! style="background-color:#ceecf2; width:100%;" | Track gauge data statistics' .. '\n|-' .. '\n|' .. table.concat(retFoot, '\n') .. '\n|}' return statTable end --- -- documentHeader --- local function documentHeader(numberOfEntries, docTitle, docState) local docHeaderBg = '#cef2e0' -- Green. See template:documentation docHeaderBg = '#f2f2ce' -- sandbox here (Yellow. Comment out for live version)

local sortClass = '' if docTitle == '' then if (numberOfEntries or 0) <= 1 then docTitle = 'Track gauge' else docTitle = 'Track gauges' sortClass = 'sortable' end end if docState == '' then docState = 'uncollapsed' end local pagetitle = mw.title.getCurrentTitle urlPurgePage = 'https://en.wikipedia.org/w/index.php?title=' .. pagetitle.nsText .. ':' .. pagetitle:partialUrl .. '&action=purge' urlPurgePage = tostring(html.create		.tag('span')		.addClass('plainlinks')		.addClass('purgelink')		.attr('title', 'Purge this page (update countings)')		.wikitext('[' .. urlPurgePage .. ' &#x03a3; P]')) --table.insert(echo, urlPurgePage)

local catMparent = TrackGauge.catMentions(nil, 'Mentionings', 'show')

local docTableStyle = 'style="text-align:right; width:100%; font-size:85%;" ' local docTableClass = 'class="wikitable collapsible ' .. docState .. ' ' .. sortClass .. '" ' local docHeaderStyleBg = 'background:' .. docHeaderBg .. ';'	local docHeaderStyle = '! style="'.. docHeaderStyleBg .. '" | ' local retHdr = {} table.insert(retHdr, '\n{| ' .. docTableClass .. docTableStyle) table.insert(retHdr, '|-') table.insert(retHdr, '! colspan=10 style="' .. docHeaderStyleBg .. '" | ' .. docTitle) table.insert(retHdr, '|-') table.insert(retHdr, '! style="' .. docHeaderStyleBg .. '; width:8em;" | Aliases (input options)') table.insert(retHdr, docHeaderStyle .. 'Entry units') table.insert(retHdr, docHeaderStyle .. 'Alt name') table.insert(retHdr, docHeaderStyle .. 'Gauge (mm)') table.insert(retHdr, docHeaderStyle .. 'Gauge (ft, in)') table.insert(retHdr, docHeaderStyle .. 'Gauge (inches)') table.insert(retHdr, docHeaderStyle .. 'Class ') table.insert(retHdr, '! style="' .. docHeaderStyleBg .. ' min-width:5em;" | Link ') table.insert(retHdr, docHeaderStyle .. 'Category (content)') table.insert(retHdr, docHeaderStyle .. urlPurgePage .. ' ' .. catMparent .. ' (maintenance)')

-- Row with the sort buttons: local docHeaderSortcols = '' if (numberOfEntries or 0) > 1 then local colHeaderSortCell = '! style="background-color:' .. docHeaderBg .. '" |' local colRowHeaderSort = { '\n|- style="line-height:90%;"' } for i = 1, 10 do			table.insert(colRowHeaderSort, colHeaderSortCell) end docHeaderSortcols = table.concat(colRowHeaderSort, '\n') .. ' '	end return table.concat(retHdr, '\n') .. docHeaderSortcols end --- -- documentFooter --- local function documentFooter return {'\n|}'} end --- -- documentFromIdToEntrySet -- from fromIdToEntrySet -- From one id, make the set with all one-two-three-more entries (met, inp, variants) --- local function documentFromIdToEntrySet(id, searchedAlias) local docBgColor = '#e6fff2' -- Green. See header bg color --docBgColor = '#ffffe6' -- sandbox here (Yellow. comment out when live) local rowSplit = ' ' -- From the id, build the set of existing entries (met, imp, and variants) local entry = {} local defType = 0 -- data for i, tgEntry in ipairs(gaugeDataAll) do		if id == tgEntry.id then if tgEntry.def1 == 'met' and entry[1] == nil then entry[1] = tgEntry defType = defType + 1 elseif tgEntry.def1 == 'imp' and entry[2] == nil then entry[2] = tgEntry defType = defType + 2 else entry[3 + tableTools.size(entry)] = tgEntry end end end for i, tgEntry in ipairs(gaugeDataExtra) do		if id == tgEntry.id then if tgEntry.def1 == 'met' and entry[1] == nil then entry[1] = tgEntry defType = defType + 1 elseif tgEntry.def1 == 'imp' and entry[2] == nil then entry[2] = tgEntry defType = defType + 2 else entry[3 + tableTools.size(entry)] = tgEntry end end end entry = tableTools.compressSparseArray(entry) -- Entry set is now complete & clean -- Result: the entry table with entries present in /data, -- in sequence if present (1. met, 2. imp, any extra) -- (to build into a single row, maybe with split cells) --Build cell elements, then string row together. local inchCount = documentInchCount(entry[1]) local sortKey = documentSortKey(entry[1], 'met', 5) local aliasList = {} local tempEntryAltName = {} local entryAltName = {} local hasAltName = false for i, e in ipairs(entry) do		local alis = {} for j, v in ipairs(e.aliases) do			if tonumber(v) == nil then -- (plain numbers are not shown) table.insert(alis, tostring(v)) end end for j, v in ipairs(alis) do if string.match(v, '^%d') == nil then -- textual so to italic. alis[j] = tostring(html.create.tag('span').wikitext(v).css('font-style', 'italic')) end end table.insert (aliasList, table.concat(alis, '; ')) stats.ttlAliasCount = stats.ttlAliasCount + #alis -- process Alt name links if e.name or  ~=  then tempEntryAltName[i] = e.link table.insert(ttlAltName, e.id .. ': ' .. e.link) ttlAltNameCount = ttlAltNameCount + 1 hasAltName = true end end if hasAltName then local text for i, v in ipairs(entry) do			table.insert(entryAltName, i, tempEntryAltName[i] or ' ') end end local def = {} -- Definition unit code: 'met' or 'imp' local defText = {} for i, v in ipairs (entry) do		table.insert(def, v.def1) if v.def1 == 'imp' then table.insert(defText, 'imp') ttlUnitCount[2][1] = ttlUnitCount[2][1] + 1 elseif v.def1 == 'met' then table.insert(defText, 'met') ttlUnitCount[1][1] = ttlUnitCount[1][1] + 1 end end if #entry >= 2 then if #entry == 2 and entry[1].def1 ~= entry[2].def1 then -- Regular pair: def in met and in imp ttlUnitCount[3][1] = ttlUnitCount[3][1] + 1 else -- More than 2, or a double unit definition ttlUnitCount[4][1] = ttlUnitCount[4][1] .. ' ' .. id .. ' mm (' .. #entry ..'&times; total);' end end -- mm; ft in -- Measurement (number & unit; met and imp; anchor to here) local measure = {} local unitanchor = { ,  } measure[1] = TrackGauge.formatMet(entry[1]) measure[2] = TrackGauge.formatImp(entry[1]) -- both met and imp from entry[1] if modMath._mod(defType, 2) == 1 then measure[1] = tostring(html.create.tag('span').wikitext(measure[1]).css('font-weight', 'bold')) unitanchor[1] = anchor(entry[1], 'met') end if defType >= 2 then measure[2] = tostring(html.create.tag('span').wikitext(measure[2]).css('font-weight', 'bold')) unitanchor[2] = anchor(entry[1], 'imp') end -- Linked article local linkArticle = {} for i, e in ipairs(entry) do		table.insert(linkArticle, e.pagename) end ttlLinkCount = ttlLinkCount + #linkArticle local eq	if #linkArticle >= 2 then eq = true for i, v in ipairs(linkArticle) do			if v ~= linkArticle[1] then eq = false break end end if eq == true then for i, v in ipairs(linkArticle) do				if i > 1 then linkArticle[i] = nil end end end end for i, lp in ipairs(linkArticle) do		local fmtLp = '' fmtLp =  .. lp ..  linkArticle[i] = tostring(html.create.tag('span').css('text-align', 'left').wikitext(fmtLp)) end -- catContent (content category for this alias). note: function p.catContent is a reduced code of this. -- can be hardcoded in the data, or build by size (pattern) local catContent = {} local catTitle local label local skipCheck = false for i, e in ipairs(entry) do		if e.contentcat == '' then -- no cat; option to prevent expensive calls skipCheck = true elseif e.contentcat ~= nil then label = string.match(e.contentcat, '([%S]*)') or 'nomatch' table.insert(catContent,				'cat:' .. label .. ' ...') end end if #catContent >= 2 then eq = true for i, v in ipairs(catContent) do			if v ~= catContent[1] then eq = false break end end if eq == true then for i, v in ipairs(catContent) do				if i > 1 then catContent[i] = nil end end end end if #catContent == 0 and not skipCheck then local catCsuffix = ' gauge railways' if modMath._mod(defType, 2) == 1 then label = formatUnitPlaintext(entry[1], 'met') catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then table.insert(catContent,					'cat:' .. noWrap(label) .. '') end end if defType >= 2 then label = formatUnitPlaintext(entry[1], 'imp', nil, true) catTitle = mw.title.makeTitle(14, label .. catCsuffix) if catTitle.exists then table.insert(catContent, 'cat:' .. noWrap(label) .. '') end end end ttlContentCatsCount = ttlContentCatsCount + #catContent -- Mentions category local catMentions = TrackGauge.catMentions(entry[1], "cat:ment's", 'show') local catCount = mw.site.stats.pagesInCategory(	TrackGauge.catMentions(entry[1], nil, 'pagename'), pages) ttlMentioningCatsCount = ttlMentioningCatsCount + 1 -- Exists ttlMentioningPageCount = ttlMentioningPageCount + catCount

-- class: Counter SizeClass (narrow, broad, ...) local rgSizeClass = documentGaugeClass(entry[1], catCount)

stats.ttlEntries = stats.ttlEntries + #entry sortCount = mw.text.truncate('00000' .. tostring(catCount), -5, '') sortCount = ' ' .. sortCount .. ' '	catCount = sortCount .. catCount .. ' P'

-- Compose the id-row with all cell values (10 columns) local row = {} table.insert(row, table.concat(aliasList, rowSplit)) table.insert(row, table.concat(defText, rowSplit)) table.insert(row, table.concat(entryAltName, rowSplit)) table.insert(row, sortKey .. unitanchor[1] .. measure[1]) table.insert(row, sortKey .. unitanchor[2] .. measure[2]) table.insert(row, sortKey .. inchCount) table.insert(row, rgSizeClass) table.insert(row, table.concat(linkArticle, rowSplit)) table.insert(row, table.concat(catContent, rowSplit)) table.insert(row, catCount .. ' ' .. catMentions) return '\n|- style="background:' .. docBgColor .. '; border-top:2px solid #aaa;" |' .. '\n|' .. table.concat(row, ' || ') end --- -- documentGauge -- Selfdocument gauge data (one, multiple, range, all) --- function p.documentGauge(frame) local args = prepareArgs(frame) --gaugeDataAll = mw.loadData(dataPageName) --gaugeDataExtra = mw.loadData(dataPageExtra)

stats.ttlAliasCount = -30 stats.ttlEntries = -30 mw.log('msg1') table.insert(echo, #stats) for k, v in pairs(stats) do --INITSTATS table.insert(echo, stats.k)	stats.k = -100 mw.log(stats.k) end -- Init glolbal counters by table: ttlUnitCount = {			[1] = {0, 'Entries defined metric'}, [2] = {0, 'Entries defined imperial'}, [3] = {0, 'Gauge sizes defined both metric and imperial'}, [4] = {'', 'Gauge sizes with multiple entries in one unit'} }		ttlSizeClassCount = {			[1] = {'scaled', 0, 'scaled or model gauges', 0}, [2] = {'min', 0, 'minimum gauges', 0}, [3] = {'narrow', 0, 'narrow gauges', 0}, [4] = {'s.g.', 0, 'standard gauge', 0}, [5] = {'broad', 0, 'broad gauges', 0}, [6] = {'unk', 0, 'unknown', 0} }

local tgList = documentBuildTgList(args) -- Now loop through the prepared tgList[id] and add rows to result 	le -- One row contains all available entries for the id (met, imp, a third variant) local rowRGid = {} for i, numId in ipairs(tgList) do		table.insert(rowRGid, documentFromIdToEntrySet(tostring(numId))) end -- Return args local retArgs = '' if args.docreturnargs == 'on' then retArgs = '\n' .. p.debugReturnArgs(frame) end -- Build statistics footer local retStats = '' if args.docstats == 'on' then retStats = documentPostListStats(#tgList, args.docnote) end -- Build up return 'ECHO:' .. table.concat(echo, '\n') .. documentHeader(#tgList, args.doctitle or , args.docstate or ) .. table.concat(rowRGid, '') .. table.concat(documentFooter, '') .. retStats .. retArgs end

-- doc

function p.docFracAliases(frame) local args = prepareArgs(frame) gaugeDataAll = mw.loadData(dataPageName) gaugeDataExtra = mw.loadData(dataPageExtra)

local tgList = documentBuildTgList(args) local ttlHitCount =0 local rowIMP = {} local fracAlias ='' for i, id in ipairs(tgList) do		for j, tgEntry in pairs(gaugeDataAll) do			if nil and tostring(id) == '53.975' and tostring(id) == tgEntry.id then fracAlias = anchor(tgEntry, 'imp', 'there') fracAlias = mw.ustring.lower(mw.ustring.gsub(fracAlias, '[%s%,%#]', '')) table.insert(rowIMP, fracAlias .. '||' .. i .. '||' .. id ..					'||' .. TrackGauge.formatImp(tgEntry) .. ' || plus ' .. tgEntry.num) end if tostring(id) == tgEntry.id and tgEntry.def1 == 'imp' and tgEntry.num ~= nil then if tgEntry.ft ~= nil then ttlHitCount = ttlHitCount + 1 fracAlias = anchor(tgEntry, 'imp', 'there') fracAlias = mw.ustring.lower(mw.ustring.gsub(fracAlias, '[%s%,%#]', '')) fracAlias = mw.ustring.gsub(fracAlias, '⁄', '/')

table.insert(rowIMP, fracAlias .. '||' .. i .. '||' .. id ..						'||' .. TrackGauge.formatImp(tgEntry)) fracAlias = tostring((tonumber((tgEntry.ft) or 0) * 12) + tonumber(tgEntry["in"] or 0)) .. tgEntry.num .. '/' .. tgEntry.den .. 'in' table.insert(rowIMP, fracAlias .. '||' .. i .. '||' .. id ..						'||' .. TrackGauge.formatImp(tgEntry)) end end end end

return '\n\n|-\n\n|' .. table.concat(rowIMP, '\n\n|-\n\n|') end return p