Zum Inhalt springen

„Modul:Sort/cellNum“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
2020-04-10
2020-04-16
Zeile 1: Zeile 1:
local Sort = { suite = "Sort",
local Sort = { suite = "Sort",
sub = "cellNum",
sub = "cellNum",
serial = "2020-04-10",
serial = "2020-04-16",
item = 88370026,
item = 88370026,
globals = { Cell = 90144855,
globals = { Cell = 90144855,
Zeile 20: Zeile 20:




Sort.digits = { { 0x30 },
{ 0x0660, "Arab" },
{ 0x06F0, "Arab" },
{ 0x07C0, "Nkoo" },
{ 0x0966, "Deva" },
{ 0x09E6, "Beng" },
{ 0x0A66, "Guru" },
{ 0x0AE6, "Gujr" },
{ 0x0B66, "Orya" },
{ 0x0BE6, "Taml" },
{ 0x0C66, "Telu" },
{ 0x0CE6, "Knda" },
{ 0x0D66, "Mlym" },
{ 0x0DE6, "Sinh" },
{ 0x0E50, "Thai" },
{ 0x0ED0, "Laoo" },
{ 0x0F20, "Tibt" },
{ 0x1040, "Mymr" },
{ 0x1369, "Ethi" },
{ 0x17E0, "Khmr" },
{ 0x1810, "Mong" },
{ 0x1946, "Limb" },
{ 0x19D0, "Talu" },
{ 0x1A80, "Lana" },
{ 0x1A90, "Lana" },
{ 0x1B50, "Bali" },
{ 0x1BB0, "Sund" },
{ 0x1C40, "Lepc" },
{ 0x1C50, "Olck" },
{ 0xA620, "Vaii" },
{ 0xA8D0, "Saur" },
{ 0xA900, "Kali" },
{ 0xA9D0, "Java" },
--{ 0xA9F0, "" }, MYANMAR TAI LAING
{ 0xAA50, "Cham" },
{ 0xABF0, "Mtei" },
{ 0x102E, "Copt" },
{ 0x1104A, "Osma" },
{ 0x110D3, "Rohg" },
--{ 0x110E6, "" }, RUMI
{ 0x11106, "Brah" },
{ 0x1110F, "Sora" },
{ 0x11113, "Cakm" },
{ 0x1111D, "Shrd" },
{ 0x1112F, "Sind" },
{ 0x11145, "Newa" },
{ 0x1114D, "Tirh" },
{ 0x11165, "Modi" },
{ 0x1116C, "Takr" },
{ 0x11173, "Ahom" },
{ 0x1118E, "Wara" },
{ 0x111C5, "Bhks" },
{ 0x111D5, "Gonm" },
{ 0x111DA, "Gong" },
{ 0x116A6, "Mroo" },
{ 0x116B5, "Hmng" },
{ 0x116E8, "Medf" },
{ 0x11E14, "Hmnp" },
{ 0x11E2F, "Wcho" },
{ 0x11E8C, "Mend" },
{ 0x11E95, "Adlm" }
}
Sort.heading = { [0x2D] = 45,
[0x2212] = 45, -- -
[0xB1] = 177, -- +/-
[0x2B] = 43, -- +
}
Sort.mpz = -0.5
Sort.mpz = -0.5
Sort.supreme = mw.ustring.char( 8734 ) -- infinit
Sort.supreme = mw.ustring.char( 8734 ) -- infinit
Zeile 121: Zeile 188:
local r
local r
if not ask then
if not ask then
Sort.minus = Sort.minus or mw.ustring.char( 8722 )
Sort.minus = Sort.minus or mw.ustring.char( 0x2212 )
elseif ask == "sep" then
elseif ask == "sep" then
if not Sort.sepDec then
if not Sort.sepDec then
Zeile 131: Zeile 198:
Sort.sepGroup, s, Sort.sepDec = mw.ustring.match( s, seek )
Sort.sepGroup, s, Sort.sepDec = mw.ustring.match( s, seek )
Sort.sepDec = Sort.sepDec or "."
Sort.sepDec = Sort.sepDec or "."
Sort.keyDec = mw.ustring.codepoint( Sort.sepDec, 1, 1 )
if s then
if s then
Sort.nGroup = #s
Sort.nGroup = #s
Zeile 216: Zeile 284:




local fine = function ( all, ahead, assist, adjacent )
local fine = function ( about )
-- Equip number with styled special characters
-- Equip number with styled special characters
-- Precondition:
-- Precondition:
-- all -- string, formatted entire presentation
-- about -- table, parameters of base number
-- ahead -- boolean, heading minus
-- .show -- string, digits
-- assist -- boolean, grouping possible
-- .low -- boolean, heading minus
-- adjacent -- boolean, decimal
-- .sign -- string, heading sign
-- .sub -- string, decimal fraction
-- .long -- boolean, grouping possible
-- Postcondition:
-- Postcondition:
-- Returns updated entire presentation
-- Returns updated entire presentation
local r = all
local r
if ahead and mw.ustring.codepoint( r, 1, 1 ) == 8722 then
if about.long then
factory( "sep" )
local n = mw.ustring.len( about.show )
local k = n - Sort.nGroup + 1
local i, m, e, s
r = mw.ustring.sub( about.show, k )
n = k - Sort.nGroup
for j = n, -1, - Sort.nGroup do
if j > 0 then
i = j
else
i = 1
end
m = j + Sort.nGroup - 1
s = mw.ustring.sub( about.show, i, m )
e = factory( 1000 ):wikitext( s )
r = tostring( e ) .. r
end -- for j
end
r = r or about.show
if about.low then
factory( "minus" )
factory( "minus" )
r = Sort.spanMinus .. mw.ustring.sub( r, 2 )
r = Sort.spanMinus .. r
elseif about.sign then
r = about.sign .. r
end
end
if adjacent then
if about.sub then
local s = about.sub
factory( "sep" )
factory( "sep" )
factory( "dec" )
factory( "dec" )
if Sort.spanDec then
r = r .. Sort.spanDec
r = mw.ustring.gsub( r, Sort.seekDec, Sort.spanDec )
if Sort.nGroup then
local n = mw.ustring.len( s )
end
if n > Sort.nGroup + 2 then
end
factory( "sep" )
if assist then
if Sort.seekGroup then
local e, s
Sort.seek1000 = Sort.seek1000 or
"(%d?%d?%d)" .. Sort.seekGroup
repeat
s = mw.ustring.match( r, Sort.seek1000 )
if s then
e = factory( 1000 ):wikitext( s )
r = mw.ustring.gsub( r,
s .. Sort.seekGroup,
tostring( e ) )
end
until not s
end
end
if adjacent and Sort.nGroup then
local i = mw.ustring.find( r, Sort.spanDec, 1, true )
if i then
local suffix
i = i + mw.ustring.len( Sort.spanDec )
suffix = mw.ustring.sub( r, i )
if #suffix > Sort.nGroup + 1 and
suffix:match( "^%d+$" ) then
local k = 0
local k = 0
local n = #suffix - Sort.nGroup
local m = n - Sort.nGroup
local e, s
local e, sg
r = mw.ustring.sub( r, 1, i - 1 )
for j = 1, m, Sort.nGroup do
for j = 1, n, Sort.nGroup do
sg = mw.ustring.sub( about.sub,
s = suffix:sub( j, j + Sort.nGroup - 1 )
j,
e = factory( "fractpart" ):wikitext( s )
j + Sort.nGroup - 1 )
r = r .. tostring( e )
e = factory( "fractpart" ):wikitext( sg )
k = k + Sort.nGroup
r = r .. tostring( e )
k = k + Sort.nGroup
end -- for j
end -- for j
r = r .. suffix:sub( k + 1, #suffix )
s = s:sub( k + 1, n )
end
end
end
end
r = r .. s
end
end
return feeder( "cssNum" ) .. r
return feeder( "cssNum" ) .. r
Zeile 285: Zeile 355:
-- Precondition:
-- Precondition:
-- all -- string, formatted entire presentation
-- all -- string, formatted entire presentation
-- assign -- number, integer
-- assign -- table, exponent
-- .show -- string, digits
-- .low -- boolean, < 0
-- Postcondition:
-- Postcondition:
-- Returns
-- Returns
Zeile 291: Zeile 363:
-- 2. string, styled number
-- 2. string, styled number
local r1 = all
local r1 = all
local r2
local r2 = assign.show
if assign < 0 then
if assign.low then
r2 = tostring( -1 * assign )
if Sort.cssNum then
if Sort.cssNum then
factory( "minus" )
factory( "minus" )
Zeile 302: Zeile 373:
r2 = Sort.minus .. r2
r2 = Sort.minus .. r2
end
end
else
r2 = tostring( assign )
end
end
return r1, r2
return r1, r2
Zeile 314: Zeile 383:
-- Precondition:
-- Precondition:
-- args -- table, parameters
-- args -- table, parameters
-- .exp -- number, exponent
-- .exp -- table, exponent
-- ahead -- string, formatted presentation
-- ahead -- string, formatted presentation
-- Postcondition:
-- Postcondition:
Zeile 326: Zeile 395:
local s
local s
r, s = fined( r, args.exp )
r, s = fined( r, args.exp )
em:wikitext( "E" )
em:wikitext( "e" )
ep:node( mw.html.create( "sup" )
ep:node( mw.html.create( "sup" )
:wikitext( s ) )
:wikitext( s ) )
Zeile 346: Zeile 415:
-- after -- boolean, decimal separator expected
-- after -- boolean, decimal separator expected
-- Postcondition:
-- Postcondition:
-- Returns
-- Returns table, with analysis
-- 1. number, of value, or false
-- .long -- >= 1000 etc.
-- 2. number, of trailing zeros, or false
-- .low -- < 0
-- .sign -- minus, plus, plusminus
local r1 = mw.text.trim( assign )
-- .show -- leading digits, scripting
local r2
-- .sub -- decimal fragment digits, scripting
if r1:find( "%d" ) then
if mw.ustring.codepoint( r1, 1, 1 ) == 8722 then
-- .sort -- signed ASCII sort text
r1 = "-" .. mw.ustring.sub( r1, 2 )
-- .script -- script code
-- .scream -- error text
local r = { }
local s = assign
local k, init
local face = function ()
local j
if init == 45 then
j = 8722
else
j = init
end
return mw.ustring.char( j )
end -- face()
factory( "sep" )
if s:find( "&", 1, true ) then
s = mw.text.decode( s )
:gsub( "&plusmn;", mw.ustring.char( 0x00B1 ) )
:gsub( "&thinsp;", mw.ustring.char( 0x2009 ) )
end
s = mw.ustring.gsub( s, "%s", "" )
k = mw.ustring.codepoint( s, 1, 1 )
init = Sort.heading[ k ]
if init then
s = mw.ustring.sub( s, 2 )
k = mw.ustring.codepoint( s, 1, 1 )
r.low = ( init == 45 )
end
if after then
local m = mw.ustring.find( s, Sort.sepGroup, 1, true )
local dig, j0, j9, n
if m and
Sort.separated and
mw.ustring.match( s, Sort.separated ) then
s = mw.ustring.gsub( s, Sort.seekGroup, "" )
end
end
if after then
for i = 1, #Sort.digits do
local i, k
dig = Sort.digits[ i ]
factory( "sep" )
j0 = dig[ 1 ]
i = mw.ustring.find( r1, Sort.sepGroup, 1, true )
j9 = j0 + 9
if i and Sort.separated and
if k >= j0 and k <= j9 then
mw.ustring.match( r1, Sort.separated ) then
r.script = dig[ 2 ]
r1 = mw.ustring.gsub( r1, Sort.seekGroup, "" )
n = mw.ustring.len( s )
i = false
break -- for i
elseif k < j0 then
break -- for i
end
end
end -- for i
k = mw.ustring.find( r1, Sort.sepDec, 1, true )
if k then
if n then
r2 = 0
m = 0
if i and i < k then
for i = 1, n do
r1 = mw.ustring.gsub( r1, Sort.seekGroup, "" )
if k == j0 then
i = false
m = i
if i < n then
k = mw.ustring.codepoint( s, i + 1, i + 1 )
end
else
break -- for i
end
end
if Sort.sepDec ~= "." then
end -- for i
r1 = mw.ustring.gsub( r1, Sort.seekDec, "." )
if m > 0 then
s = mw.ustring.sub( s, m + 1 )
n = n - m
end
m = 0
for i = 1, n do
if k == Sort.keyDec or k == 46 then
k = false
break -- for i
elseif k >= j0 and k <= j9 then
r.sort = string.format( "%s%c",
r.sort or "",
k - j0 + 48 )
if i < n then
k = mw.ustring.codepoint( s, i + 1, i + 1 )
end
m = i
end
end -- for i
if m > 0 then
r.long = ( m > Sort.nGroup )
r.sort = r.sort or "0"
r.show = mw.ustring.sub( s, 1, m )
if not k then
m = m + 1
s = mw.ustring.sub( s, m + 1 )
end
n = n - m
else
r.show = mw.ustring.char( j0 )
r.sort = "0"
if not k then
s = mw.ustring.sub( s, 2 )
n = n - 1
end
end
elseif r1:find( ".", 1, true ) then
r2 = 0
end
end
if r2 then
if r.low and r.sort ~= "0" then
if r1:match( "0$" ) then
r.sort = "-" .. r.sort
r2 = 1
end
k = mw.ustring.len( r1 ) - 1
if n > 0 then
repeat
if k then
if mw.ustring.sub( r1, k, k ) == "0" then
r.scream = s
r2 = r2 + 1
else
k = k - 1
r.sort = r.sort .. "."
k = mw.ustring.codepoint( s, 1, 1 )
for i = 1, n do
if k and k >= j0 and k <= j9 then
r.sort = string.format( "%s%c",
r.sort,
k - j0 + 48 )
if i < n then
k = mw.ustring.codepoint( s,
i + 1,
i + 1 )
end
else
else
k = -9
k = false
end
end
until k < 2
end -- for i
elseif Sort.sepDec ~= "." then
if k then
r2 = false
r.sub = s
else
r.scream = s
r.show = false
end
end
end
end
end
else
r.scream = assign
end
if init and not r.scream then
r.sign = face()
end
end
r1 = tonumber( r1 ) or false
r2 = r2 or false
else
else
r1 = false
k = tonumber( s )
if k then
k = math.floor( k )
r.show = tostring( k )
r.sort = r.show
if init then
r.sign = face()
if init == 45 then
r.sort = "-" .. r.sort
elseif init == 177 then
r.sort = false
end
end
else
r.scream = assign
end
end
end
return r1, r2
return r
end -- flat()
end -- flat()






local fore = function ( args, amount, above )
local fore = function ( args )
-- Create and merge sort attribute
-- Create and merge sort attribute
-- Precondition:
-- Precondition:
-- args -- table, parameters
-- args -- table, parameters
-- .n -- table, for base number
-- .sort -- string|nil
-- .exp -- table|nil, for exponent
-- amount -- number, for base
-- amount -- number, for base
-- above -- number|nil, for exponent
-- Postcondition:
-- Postcondition:
-- attributes extended
-- attributes extended
local s = tostring( amount )
local s = args.n.sort or "0"
if args.exp and args.exp.sort then
local i = s:find( ".", 1, true )
s = string.format( "%sE%s", s, args.exp.sort )
if i then
factory( "sep" )
if Sort.sepDec ~= "." then
s = string.format( "%s%s%s",
s:sub( 1, i - 1 ),
Sort.sepDec,
s:sub( i + 1 ) )
end
end
if above and above ~= 0 then
s = string.format( "%sE%d", s, above )
end
end
Sort.Cell.faced( args, s )
Sort.Cell.faced( args, s )
Zeile 435: Zeile 601:
-- Precondition:
-- Precondition:
-- args -- table, parameters
-- args -- table, parameters
-- .pad -- number|false, for padding
-- .pad -- number|false, for padding
-- .pre -- string|false, for prefix
-- .pre -- string|false, for prefix
-- .lead -- boolean, for plus sign
-- .n -- table, for base
-- .n -- number, for base
-- .low -- boolean, < 0
-- .z -- number|false, for trailing zeroes
-- .sign -- minus, plus, plusminus
-- .suffix -- string|false, extending base
-- .show -- leading digits
-- .exp -- number|false, for exponent
-- .sub -- decimal fragment digits
-- .post -- string|false, for postfix
-- .script -- script code
-- .round -- number|false, for rounding
-- .suffix -- string|false, extending base
-- .cell -- boolean, enfoce sort value
-- .exp -- table|false, for exponent
-- .post -- string|false, for postfix
-- .round -- number|false, for rounding
-- .cell -- boolean, enfoce sort value
-- Postcondition:
-- Postcondition:
-- Returns string
-- Returns string
local low = ( args.n < 0 )
local r = args.n.show or args.n.scream
local e, i, less, link, long, move, n, r, s, shift
local e, move, s, shift
if low then
n = -1 * args.n
else
n = args.n
end
less = ( n > math.floor( n ) )
long = ( n >= 1000 )
if low or less or long or args.z or args.suffix then
factory()
r = Sort.contLang:formatNum( n )
if low then
r = Sort.minus .. r
elseif args.lead then
r = "+" .. r
end
if args.z then
if not mw.ustring.find( r, Sort.sepDec, 1, true ) then
r = r .. Sort.sepDec
end
if args.z > 0 then
r = r .. string.rep( "0", args.z )
end
end
else
r = tostring( n )
end
if args.pad and args.pad < 0 then
if args.pad and args.pad < 0 then
move = args.pad
move = args.pad + mw.ustring.len( args.n.show )
if less then
if args.n.sign then
factory( "sep" )
move = move + 1
i = mw.ustring.find( r, Sort.sepDec, 1, true )
if not i then
i = #r
end
if args.suffix then
i = i + mw.ustring.len( args.suffix )
end
move = move + i
end
end
if move < 0 then
if move < 0 then
move = move + 1
move = move + 1
end
end
if args.pre and move then
end
if args.pre and move then
move = move + mw.ustring.len( args.pre ) + 1
end
move = move + mw.ustring.len( args.pre ) + 1
end
end
if move then
if move then
Zeile 511: Zeile 646:
end
end
elseif args.pad then
elseif args.pad then
factory( "sep" )
move = args.pad
i = mw.ustring.find( r, Sort.sepDec, 1, true )
if args.n.sub then
move = move - mw.ustring.len( args.n.sub ) - 1
if i then
i = #r - i
if args.suffix then
shift = ""
move = move - mw.ustring.len( args.suffix )
end
else
else
i = 0
move = move + 0.5
shift = Sort.sepDec
end
end
i = args.pad - i
if args.post then
if args.post then
i = i - mw.ustring.len( args.post ) - 1
move = move - mw.ustring.len( args.post ) - 1
end
end
if i > 0 then
if move > 0 then
shift = shift .. string.rep( "0", i )
shift = string.rep( "0", move )
e = mw.html.create( "span" )
e = mw.html.create( "span" )
:css( "visibility", "hidden" )
:css( "visibility", "hidden" )
Zeile 532: Zeile 666:
end
end
end
end
if Sort.cssNum then
if args.n.low or args.n.long or args.n.sub then
if low or long or less then
r = fine( args.n )
r = fine( r, low, long, less )
end
end
end
if args.suffix then
if args.suffix then
Zeile 541: Zeile 673:
end
end
if args.exp then
if args.exp then
link = ( args.exp < 0 )
if Sort.cssNumExp then
if Sort.cssNumExp then
r = finest( args, r )
r = finest( args, r )
else
else
Sort.stick = Sort.stick or mw.ustring.char( 183 )
Sort.stick = Sort.stick or mw.ustring.char( 0xB7 )
r, s = fined( r, args.exp )
r, s = fined( r, args.exp )
e = mw.html.create( "sup" )
e = mw.html.create( "sup" )
Zeile 555: Zeile 686:
end
end
end
end
if args.pre or link or args.post then
if args.pre or
args.exp and args.exp.low or
args.post or
args.n.script then
if args.pre then
if args.pre then
r = string.format( "%s %s", args.pre, r )
r = string.format( "%s %s", args.pre, r )
Zeile 568: Zeile 702:
not Sort.Cell.following() then
not Sort.Cell.following() then
e:attr( "dir", "ltr" )
e:attr( "dir", "ltr" )
end
if args.n.script then
e:attr( "lang", "und-" .. args.n.script )
end
end
r = tostring( e )
r = tostring( e )
Zeile 577: Zeile 714:
args.pre or
args.pre or
( args.cell and
( args.cell and
( args.lead or
( args.n.low or
low or
args.n.sign or
less or
args.n.sub or
long or
args.n.long or
args.exp ) ) then
args.suffix or
fore( args, args.n, args.exp )
args.exp or
args.n.script ) ) then
fore( args )
end
end
return r
return r
Zeile 600: Zeile 739:
if type( args ) == "table" then
if type( args ) == "table" then
local present = Sort.Cell.first( args )
local present = Sort.Cell.first( args )
local s = type( args.n )
local s = type( args.exp )
if s == "string" then
Sort.Cell.fair( args, "exp", present )
elseif s == "number" then
present.exp = args.exp
end
s = type( args.n )
if s == "string" then
if s == "string" then
s = mw.text.trim( args.n )
s = mw.text.trim( args.n )
Zeile 615: Zeile 760:
end
end
if not present.infinit then
if not present.infinit then
local i = s:find( "%d[.,]?[eE]%-?%d+$" )
if not present.exp then
if i and
local i = s:find( "%d[.,]?[eE]%-?%d+$" )
( not args.exp or args.exp == "" ) then
if i then
local split = s:sub( i + 2 ):upper()
local split = s:sub( i + 2 ):upper()
if split:sub( 1, 1 ) == "E" then
if split:sub( 1, 1 ) == "E" then
split = split:sub( 2 )
split = split:sub( 2 )
end
present.exp = split
s = s:sub( 1, i )
end
end
present.exp = tonumber( split )
s = s:sub( 1, i )
end
end
present.n, present.z = flat( s, true )
present.n = flat( s, true )
end
end
elseif s == "number" then
elseif s == "number" then
present.n = args.n
local k = args.n
present.n = { low = ( k < 0 ),
sort = tostring( k ) }
present.n.show = present.n.sort
if present.n.low then
present.n.show = present.n.show:sub( 2 )
end
k = present.n.show:find( ".", 1, true )
if k then
present.n.sub = present.n.show:sub( k + 1 )
k = k - 1
present.n.show = present.n.show:sub( 1, k )
else
k = mw.ustring.len( present.n.show )
end
present.n.long = ( k > Sort.nGroup )
end
end
if present.n or present.infinit then
if present.n or present.infinit then
if present.n then
if present.n then
s = type( args.exp )
s = type( present.exp )
if s == "string" and args.exp ~= "" then
if s == "string" then
present.exp = flat( args.exp )
present.exp = flat( present.exp )
elseif s == "number" then
elseif s == "number" then
present.exp = args.exp
local k = present.exp
present.exp = { low = ( k < 0 ) }
if present.exp.low then
k = -1 * k
end
k = math.floor( k )
present.exp.show = tostring( k )
if k > 0 then
present.exp.sort = present.exp.show
if present.exp.low then
present.exp.sort = "-" .. present.exp.sort
end
end
end
end
Sort.Cell.fair( args, "suffix", present )
Sort.Cell.fair( args, "suffix", present )
Zeile 650: Zeile 823:
Sort.Cell.fair( args, "pre", present )
Sort.Cell.fair( args, "pre", present )
Sort.Cell.fair( args, "post", present )
Sort.Cell.fair( args, "post", present )
s = type( args.plus )
if not present.n.low then
if s == "string" then
s = type( args.plus )
present.lead = ( args.plus == "1" or
if s == "string" then
args.plus == "+" )
if args.plus == "1" or
elseif s == "boolean" then
args.plus == "+" then
present.lead = args.plus
present.n.sign = "+"
end
end
if present.lead and present.n < 0 then
elseif s == "boolean" then
present.lead = false
present.n.sign = "+"
end
end
end
if args.cssNum and not Sort.cssNum then
if args.cssNum and not Sort.cssNum then
Zeile 670: Zeile 844:
r = format( present )
r = format( present )
else
else
fore( args, present.infinit * 9999999, 999 )
present.n = { sort = "9999999" }
if present.infinit < 0 then
present.n.sort = "-" .. present.n.sort
end
present.exp = { sort = "999" }
fore( present )
end
end
r = Sort.Cell.finalize( present, r )
r = Sort.Cell.finalize( present, r )

Version vom 16. April 2020, 00:06 Uhr

Vorlagenprogrammierung Diskussionen Lua Test Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus

Dies ist die (produktive) Mutterversion eines global benutzten Lua-Moduls.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Versionsbezeichnung auf WikiData: 2024-06-01

Updating notwendig

(lokal: 2020-04-16)

local Sort = { suite   = "Sort",
               sub     = "cellNum",
               serial  = "2020-04-16",
               item    = 88370026,
               globals = { Cell      = 90144855,
                           FormatNum = 15709679 } }
--[=[
Sort/cellNum
         support table cells with numerical content and number formatting
]=]
local Failsafe  = Sort
local GlobalMod = Sort



if mw.site.server:find( ".beta.wmflabs.org", 4, true ) then
    require( "Module:No Globals" )
end



Sort.digits  = { {    0x30 },
                 {  0x0660, "Arab" },
                 {  0x06F0, "Arab" },
                 {  0x07C0, "Nkoo" },
                 {  0x0966, "Deva" },
                 {  0x09E6, "Beng" },
                 {  0x0A66, "Guru" },
                 {  0x0AE6, "Gujr" },
                 {  0x0B66, "Orya" },
                 {  0x0BE6, "Taml" },
                 {  0x0C66, "Telu" },
                 {  0x0CE6, "Knda" },
                 {  0x0D66, "Mlym" },
                 {  0x0DE6, "Sinh" },
                 {  0x0E50, "Thai" },
                 {  0x0ED0, "Laoo" },
                 {  0x0F20, "Tibt" },
                 {  0x1040, "Mymr" },
                 {  0x1369, "Ethi" },
                 {  0x17E0, "Khmr" },
                 {  0x1810, "Mong" },
                 {  0x1946, "Limb" },
                 {  0x19D0, "Talu" },
                 {  0x1A80, "Lana" },
                 {  0x1A90, "Lana" },
                 {  0x1B50, "Bali" },
                 {  0x1BB0, "Sund" },
                 {  0x1C40, "Lepc" },
                 {  0x1C50, "Olck" },
                 {  0xA620, "Vaii" },
                 {  0xA8D0, "Saur" },
                 {  0xA900, "Kali" },
                 {  0xA9D0, "Java" },
               --{  0xA9F0, "" },        MYANMAR TAI LAING
                 {  0xAA50, "Cham" },
                 {  0xABF0, "Mtei" },
                 {  0x102E, "Copt" },
                 { 0x1104A, "Osma" },
                 { 0x110D3, "Rohg" },
               --{ 0x110E6, "" },        RUMI
                 { 0x11106, "Brah" },
                 { 0x1110F, "Sora" },
                 { 0x11113, "Cakm" },
                 { 0x1111D, "Shrd" },
                 { 0x1112F, "Sind" },
                 { 0x11145, "Newa" },
                 { 0x1114D, "Tirh" },
                 { 0x11165, "Modi" },
                 { 0x1116C, "Takr" },
                 { 0x11173, "Ahom" },
                 { 0x1118E, "Wara" },
                 { 0x111C5, "Bhks" },
                 { 0x111D5, "Gonm" },
                 { 0x111DA, "Gong" },
                 { 0x116A6, "Mroo" },
                 { 0x116B5, "Hmng" },
                 { 0x116E8, "Medf" },
                 { 0x11E14, "Hmnp" },
                 { 0x11E2F, "Wcho" },
                 { 0x11E8C, "Mend" },
                 { 0x11E95, "Adlm" }
               }
Sort.heading  = { [0x2D]   =  45,
                  [0x2212] =  45,   -- -
                  [0xB1]   = 177,   -- +/-
                  [0x2B]   =  43,   -- +
                }
Sort.mpz     = -0.5
Sort.supreme = mw.ustring.char( 8734 )    -- infinit



local foreignModule = function ( access, advanced, append, alt, alert )
    -- Fetch global module
    -- Precondition:
    --     access    -- string, with name of base module
    --     advanced  -- true, for require(); else mw.loadData()
    --     append    -- string, with subpage part, if any; or false
    --     alt       -- number, of wikidata item of root; or false
    --     alert     -- true, for throwing error on data problem
    -- Postcondition:
    --     Returns whatever, probably table
    -- 2019-10-29
    local storage = access
    local finer = function ()
                      if append then
                          storage = string.format( "%s/%s",
                                                   storage,
                                                   append )
                      end
                  end
    local fun, lucky, r, suited
    if advanced then
        fun = require
    else
        fun = mw.loadData
    end
    GlobalMod.globalModules = GlobalMod.globalModules or { }
    suited = GlobalMod.globalModules[ access ]
    if not suited then
        finer()
        lucky, r = pcall( fun,  "Module:" .. storage )
    end
    if not lucky then
        if not suited  and
           type( alt ) == "number"  and
           alt > 0 then
            suited = string.format( "Q%d", alt )
            suited = mw.wikibase.getSitelink( suited )
            GlobalMod.globalModules[ access ] = suited or true
        end
        if type( suited ) == "string" then
            storage = suited
            finer()
            lucky, r = pcall( fun, storage )
        end
        if not lucky and alert then
            error( "Missing or invalid page: " .. storage, 0 )
        end
    end
    return r
end -- foreignModule()



local fetch = function ( access, append )
    -- Fetch global library
    -- Precondition:
    --     access    -- string|false, with name of base module
    --     append    -- string, with subpage part, if any; or false
    local store, sub, suite
    if access then
        suite = access
        store = access
    else
        suite = Sort.suite
        if append then
            sub   = append:lower()
            store = append
        else
            store = "Sorter"
        end
    end
    if type( Sort[ store ] ) == "nil" then
        local bib = foreignModule( suite,
                                   true,
                                   sub,
                                   Sort.globals[ store ],
                                   true )
        if bib  and  type( bib[ suite ] ) == "function" then
            Sort[ store ] = bib[ suite ]()
        else
            error( tostring( bib ) )
        end
    end
end -- fetch()



local factory = function ( ask )
    -- Ensure config data
    -- Precondition:
    --     assign    -- string|nil, particular query
    -- Postcondition:
    --     config data available
    --     Returns elements for "*", 10, 1000, fractpart
    local r
    if not ask then
        Sort.minus = Sort.minus  or  mw.ustring.char( 0x2212 )
    elseif ask == "sep" then
        if not Sort.sepDec then
            local seek = "%d(%p?)(%d?%d?456)(%p)7"
            local s
            Sort.contLang = Sort.contLang  or
                            mw.language.getContentLanguage()
            s             = Sort.contLang:formatNum( 123456.7 )
            Sort.sepGroup, s, Sort.sepDec = mw.ustring.match( s, seek )
            Sort.sepDec = Sort.sepDec or "."
            Sort.keyDec = mw.ustring.codepoint( Sort.sepDec, 1, 1 )
            if s then
                Sort.nGroup = #s
            end
            if Sort.sepDec == "." then
                Sort.seekDec = "%%."
            else
                Sort.seekDec = Sort.sepDec
            end
            if Sort.sepGroup  and  Sort.sepGroup ~= "" then
                if Sort.sepGroup == "." then
                    Sort.seekGroup = "%."
                else
                    Sort.seekGroup = Sort.sepGroup
                end
                Sort.separated = string.format( "%s%%d%%d%%d%s",
                                                Sort.seekGroup,
                                                Sort.seekGroup )
            end
        end
    elseif ask == "dec" then
        if not Sort.spanDec then
            if Sort.sepDec == "." then
                Sort.spanDec = "."
            else
                local e = mw.html.create( "span" )
                                 :addClass( "numericFormat-dec" )
                                 :node( mw.html.create( "span" )
                                               :wikitext( "." ) )
                Sort.spanDec = tostring( e )
            end
        end
    elseif ask == "minus" then
        if not Sort.spanMinus then
            local e = mw.html.create( "span" )
                             :addClass( "numericFormat-minus" )
                                 :node( mw.html.create( "span" )
                                               :wikitext( "-" ) )
            Sort.spanMinus = tostring( e )
        end
    elseif ask == 1000 then
        r = mw.html.create( "span" )
                   :addClass( "numericFormat-1000" )
    elseif ask == "fractpart" then
        r = mw.html.create( "span" )
                   :addClass( "numericFormat-fractpart" )
    elseif ask == "*" then
        r = mw.html.create( "span" )
                   :addClass( "numericFormat-multiply" )
    elseif ask == 10 then
        r = mw.html.create( "span" )
                   :addClass( "numericFormat-10" )
        --    ::before { content: "10"; }
    end
    return r
end -- factory()



local feeder = function ( access )
    -- Retrieve first TemplateStyles transclusion
    -- Precondition:
    --     access   -- string, TemplateStyles ID
    local ts = Sort[ access ]
    local r
    if ts  and  not  ts.loaded then
        local s = type( ts.origin )
        local src
        ts.loaded = true
        if s == "string" then
            src = ts.origin
        elseif s == "table" then
            src = ts.origin.prefixedText
        end
        if src then
            Sort.frame = Sort.frame or mw.getCurrentFrame()
            r = Sort.frame:extensionTag( "templatestyles",
                                         nil,
                                         { src = src } )
        end
    end
    return r or ""
end -- feeder()



local fine = function ( about )
    -- Equip number with styled special characters
    -- Precondition:
    --     about    -- table, parameters of base number
    --                 .show   -- string, digits
    --                 .low    -- boolean, heading minus
    --                 .sign   -- string, heading sign
    --                 .sub    -- string, decimal fraction
    --                 .long   -- boolean, grouping possible
    -- Postcondition:
    --     Returns updated entire presentation
    local r
    if about.long then
        factory( "sep" )
        local n = mw.ustring.len( about.show )
        local k = n - Sort.nGroup + 1
        local i, m, e, s
        r = mw.ustring.sub( about.show, k )
        n = k - Sort.nGroup
        for j = n,  -1,  - Sort.nGroup do
            if j > 0 then
                i = j
            else
                i = 1
            end
            m = j + Sort.nGroup - 1
            s = mw.ustring.sub( about.show, i, m )
            e = factory( 1000 ):wikitext( s )
            r = tostring( e ) .. r
        end --  for j
    end
    r = r or about.show
    if about.low then
        factory( "minus" )
        r = Sort.spanMinus .. r
    elseif about.sign then
        r = about.sign .. r
    end
    if about.sub then
        local s = about.sub
        factory( "sep" )
        factory( "dec" )
        r = r .. Sort.spanDec
        if Sort.nGroup then
            local n = mw.ustring.len( s )
            if n  >  Sort.nGroup + 2 then
                local k = 0
                local m = n - Sort.nGroup
                local e, sg
                for j = 1, m, Sort.nGroup do
                    sg = mw.ustring.sub( about.sub,
                                         j,
                                         j + Sort.nGroup - 1 )
                    e  = factory( "fractpart" ):wikitext( sg )
                    r  = r .. tostring( e )
                    k  = k + Sort.nGroup
                end --  for j
                s = s:sub( k + 1,  n )
            end
        end
        r = r .. s
    end
    return feeder( "cssNum" ) .. r
end -- fine()



local fined = function ( all, assign )
    -- Append styled number
    -- Precondition:
    --     all       -- string, formatted entire presentation
    --     assign    -- table, exponent
    --                  .show   -- string, digits
    --                  .low    -- boolean, < 0
    -- Postcondition:
    --     Returns
    --         1. string, updated entire presentation
    --         2. string, styled number
    local r1 = all
    local r2 = assign.show
    if assign.low then
        if Sort.cssNum then
            factory( "minus" )
            r2 = Sort.spanMinus .. r2
            r1 = feeder( "cssNum" ) .. r1
        else
            factory()
            r2 = Sort.minus .. r2
        end
    end
    return r1, r2
end -- fined()



local finest = function ( args, ahead )
    -- Append styled decimal power
    -- Precondition:
    --     args     -- table, parameters
    --                 .exp    -- table, exponent
    --     ahead    -- string, formatted presentation
    -- Postcondition:
    --     Returns expanded presentation
    local r = string.format( "%s%s%s",
                             feeder( "cssNum" ),
                             feeder( "cssNumExp" ),
                             ahead )
    local em = factory( "*" )
    local ep = factory( 10 )
    local s
    r, s = fined( r, args.exp )
    em:wikitext( "e" )
    ep:node( mw.html.create( "sup" )
                    :wikitext( s ) )
    s = Sort.Cell.feature( args, "color" )  or  "#000000"
    em:css( "background-color", s )
    r = string.format( "%s%s%s",
                       r,
                       tostring( em ),
                       tostring( ep ) )
    return r
end -- finest()



local flat = function ( assign, after )
    -- Parse decimal number
    -- Precondition:
    --     assign    -- string, number to be parsed
    --     after     -- boolean, decimal separator expected
    -- Postcondition:
    --     Returns table, with analysis
    --             .long      -- >= 1000  etc.
    --             .low       -- < 0
    --             .sign      -- minus, plus, plusminus
    --             .show      -- leading digits, scripting
    --             .sub       -- decimal fragment digits, scripting
    --             .sort      -- signed ASCII sort text
    --             .script    -- script code
    --             .scream    -- error text
    local r = { }
    local s = assign
    local k, init
    local face = function ()
                     local j
                     if init == 45 then
                         j = 8722
                     else
                         j = init
                     end
                     return mw.ustring.char( j )
                 end -- face()
    factory( "sep" )
    if s:find( "&", 1, true ) then
        s = mw.text.decode( s )
                   :gsub( "&plusmn;", mw.ustring.char( 0x00B1 ) )
                   :gsub( "&thinsp;", mw.ustring.char( 0x2009 ) )
    end
    s    = mw.ustring.gsub( s, "%s", "" )
    k    = mw.ustring.codepoint( s, 1, 1 )
    init = Sort.heading[ k ]
    if init then
        s = mw.ustring.sub( s, 2 )
        k = mw.ustring.codepoint( s, 1, 1 )
        r.low = ( init == 45 )
    end
    if after then
        local m = mw.ustring.find( s, Sort.sepGroup, 1, true )
        local dig, j0, j9, n
        if m  and
           Sort.separated  and
           mw.ustring.match( s, Sort.separated ) then
            s = mw.ustring.gsub( s, Sort.seekGroup, "" )
        end
        for i = 1, #Sort.digits do
            dig = Sort.digits[ i ]
            j0  = dig[ 1 ]
            j9  = j0 + 9
            if k >= j0  and  k <= j9 then
                r.script = dig[ 2 ]
                n        = mw.ustring.len( s )
                break    -- for i
            elseif k < j0 then
                break    -- for i
            end
        end -- for i
        if n then
            m = 0
            for i = 1, n do
                if k == j0 then
                    m = i
                    if i < n then
                        k = mw.ustring.codepoint( s,  i + 1,  i + 1 )
                    end
                else
                    break    -- for i
                end
            end -- for i
            if m > 0 then
                s = mw.ustring.sub( s,  m + 1 )
                n = n - m
            end
            m = 0
            for i = 1, n do
                if k == Sort.keyDec  or  k == 46 then
                    k = false
                    break    -- for i
                elseif k >= j0  and  k <= j9 then
                    r.sort = string.format( "%s%c",
                                            r.sort or "",
                                            k - j0 + 48 )
                    if i < n then
                        k = mw.ustring.codepoint( s,  i + 1,  i + 1 )
                    end
                    m = i
                end
            end -- for i
            if m > 0 then
                r.long = ( m > Sort.nGroup )
                r.sort = r.sort or "0"
                r.show = mw.ustring.sub( s, 1, m )
                if not k then
                    m = m + 1
                    s = mw.ustring.sub( s,  m + 1 )
                end
                n = n - m
            else
                r.show = mw.ustring.char( j0 )
                r.sort = "0"
                if not k then
                    s = mw.ustring.sub( s, 2 )
                    n = n - 1
                end
            end
            if r.low  and  r.sort ~= "0" then
                r.sort = "-" .. r.sort
            end
            if n > 0 then
                if k then
                    r.scream = s
                else
                    r.sort = r.sort .. "."
                    k = mw.ustring.codepoint( s, 1, 1 )
                    for i = 1, n do
                        if k  and  k >= j0  and  k <= j9 then
                            r.sort = string.format( "%s%c",
                                                    r.sort,
                                                    k - j0 + 48 )
                            if i < n then
                                k = mw.ustring.codepoint( s,
                                                          i + 1,
                                                          i + 1 )
                            end
                        else
                            k = false
                        end
                    end -- for i
                    if k then
                        r.sub = s
                    else
                        r.scream = s
                        r.show   = false
                    end
                end
            end
        else
            r.scream = assign
        end
        if init  and  not r.scream then
            r.sign = face()
        end
    else
        k = tonumber( s )
        if k then
            k = math.floor( k )
            r.show = tostring( k )
            r.sort = r.show
            if init then
                r.sign = face()
                if init == 45 then
                    r.sort = "-" .. r.sort
                elseif init == 177 then
                    r.sort = false
                end
            end
        else
            r.scream = assign
        end
    end
    return r
end -- flat()



local fore = function ( args )
    -- Create and merge sort attribute
    -- Precondition:
    --     args      -- table, parameters
    --                       .n      -- table, for base number
    --                                  .sort    -- string|nil
    --                       .exp    -- table|nil, for exponent
    --     amount    -- number, for base
    -- Postcondition:
    --     attributes extended
    local s = args.n.sort or "0"
    if args.exp  and  args.exp.sort then
        s = string.format( "%sE%s", s, args.exp.sort )
    end
    Sort.Cell.faced( args, s )
end -- fore()



local format = function ( args )
    -- Format visible number
    -- Precondition:
    --     args    -- table, parameters
    --                .pad       -- number|false, for padding
    --                .pre       -- string|false, for prefix
    --                .n         -- table, for base
    --                              .low       -- boolean, < 0
    --                              .sign      -- minus, plus, plusminus
    --                              .show      -- leading digits
    --                              .sub       -- decimal fragment digits
    --                              .script    -- script code
    --                .suffix    -- string|false, extending base
    --                .exp       -- table|false, for exponent
    --                .post      -- string|false, for postfix
    --                .round     -- number|false, for rounding
    --                .cell      -- boolean, enfoce sort value
    -- Postcondition:
    --     Returns string
    local r = args.n.show or args.n.scream
    local e, move, s, shift
    if args.pad  and  args.pad < 0 then
        move = args.pad + mw.ustring.len( args.n.show )
        if args.n.sign then
            move = move + 1
        end
        if move < 0 then
            move = move + 1
        end
        if args.pre and move then
            move = move + mw.ustring.len( args.pre ) + 1
        end
    end
    if move then
        if move < 0 then
            if not Sort.shift then
                if Sort.Cell.following() then
                    Sort.shift = "left"
                else
                    Sort.shift = "right"
                end
                Sort.shift = "padding-" .. Sort.shift
            end
            Sort.Cell.feature( args,
                               Sort.shift,
                               string.format( "%.2fem",
                                              Sort.mpz * move ) )
        end
    elseif args.pad then
        move = args.pad
        if args.n.sub then
            move = move - mw.ustring.len( args.n.sub ) - 1
            if args.suffix then
                move = move - mw.ustring.len( args.suffix )
            end
        else
            move = move + 0.5
        end
        if args.post then
           move = move - mw.ustring.len( args.post ) - 1
        end
        if move > 0 then
            shift = string.rep( "0", move )
            e     = mw.html.create( "span" )
                           :css( "visibility", "hidden" )
                           :wikitext( shift )
            shift = tostring( e )
        end
    end
    if args.n.low or args.n.long or args.n.sub then
        r = fine( args.n )
    end
    if args.suffix then
        r = r .. args.suffix
    end
    if args.exp then
        if Sort.cssNumExp then
            r = finest( args, r )
        else
            Sort.stick = Sort.stick  or  mw.ustring.char( 0xB7 )
            r, s = fined( r, args.exp )
            e = mw.html.create( "sup" )
                       :wikitext( s )
            r = string.format( "%s%s10%s",
                               r,
                               Sort.stick,
                               tostring( e ) )
        end
    end
    if args.pre  or
       args.exp and args.exp.low  or
       args.post  or
       args.n.script then
        if args.pre then
            r =  string.format( "%s %s", args.pre, r )
        end
        if args.post then
            r =  string.format( "%s %s", r, args.post )
        end
        e = mw.html.create( "span" )
                   :css( "white-space", "nowrap" )
                   :wikitext( r )
        if ( args.pre or args.post )  and
           not Sort.Cell.following() then
            e:attr( "dir", "ltr" )
        end
        if args.n.script then
            e:attr( "lang", "und-" .. args.n.script )
        end
        r = tostring( e )
    end
    if shift then
        r =  r .. shift
    end
    if args.pad   or
       args.pre   or
       ( args.cell  and
         ( args.n.low   or
           args.n.sign  or
           args.n.sub   or
           args.n.long  or
           args.suffix  or
           args.exp     or
           args.n.script ) ) then
        fore( args )
    end
    return r
end -- format()



local furnish = function ( args )
    -- Execute task
    -- Parameter:
    --     args    -- table, parameters
    -- Postcondition:
    --     Returns string, or expands .cell
    --     Throws error on failure
    local r
    fetch( false, "Cell" )
    if type( args ) == "table" then
        local present = Sort.Cell.first( args )
        local s = type( args.exp )
        if s == "string" then
           Sort.Cell.fair( args, "exp", present )
        elseif s == "number" then
            present.exp = args.exp
        end
        s = type( args.n )
        if s == "string" then
            s = mw.text.trim( args.n )
            if s == Sort.supreme then
                present.infinit = 1
            elseif mw.ustring.len( s ) == 2  and
                   mw.ustring.codepoint( s, 2, 2 ) == 8734 then
                local m = mw.ustring.codepoint( s, 1, 1 )
                if m == 45  or  m == 8722 then
                    present.infinit = -1
                elseif m == 43 then
                    present.infinit = 1
                end
            end
            if not present.infinit then
                if not present.exp then
                    local i = s:find( "%d[.,]?[eE]%-?%d+$" )
                    if i then
                        local split = s:sub( i + 2 ):upper()
                        if split:sub( 1, 1 ) == "E" then
                            split = split:sub( 2 )
                        end
                        present.exp = split
                        s           = s:sub( 1, i )
                    end
                end
                present.n = flat( s, true )
            end
        elseif s == "number" then
            local k = args.n
            present.n = { low  = ( k < 0 ),
                          sort = tostring( k ) }
            present.n.show = present.n.sort
            if present.n.low then
                present.n.show = present.n.show:sub( 2 )
            end
            k = present.n.show:find( ".", 1, true )
            if k then
                present.n.sub  = present.n.show:sub( k + 1 )
                k = k - 1
                present.n.show = present.n.show:sub( 1, k )
            else
                k = mw.ustring.len( present.n.show )
            end
            present.n.long = ( k > Sort.nGroup )
        end
        if present.n or present.infinit then
            if present.n then
                s = type( present.exp )
                if s == "string" then
                    present.exp = flat( present.exp )
                elseif s == "number" then
                    local k = present.exp
                    present.exp = { low = ( k < 0 ) }
                    if present.exp.low then
                        k = -1 * k
                    end
                    k = math.floor( k )
                    present.exp.show = tostring( k )
                    if k > 0 then
                        present.exp.sort = present.exp.show
                        if present.exp.low then
                            present.exp.sort = "-" .. present.exp.sort
                        end
                    end
                end
                Sort.Cell.fair( args, "suffix", present )
                s = type( args.pad )
                if s == "string" then
                    present.pad = tonumber( args.pad )
                elseif s == "number" then
                    present.pad = args.pad
                end
                if present.pad  and  present.pad == 0 then
                    present.pad = false
                end
                Sort.Cell.fair( args, "pre", present )
                Sort.Cell.fair( args, "post", present )
                if not present.n.low then
                    s = type( args.plus )
                    if s == "string" then
                        if args.plus == "1"  or
                           args.plus == "+" then
                            present.n.sign = "+"
                        end
                    elseif s == "boolean" then
                        present.n.sign = "+"
                    end
                end
                if args.cssNum  and  not Sort.cssNum then
                    Sort.cssNum = { }
                    Sort.cssNum.origin = args.cssNum
                end
                if args.cssNumExp  and  not Sort.cssNumExp then
                    Sort.cssNumExp = { }
                    Sort.cssNumExp.origin = args.cssNumExp
                end
                r = format( present )
            else
                present.n = { sort = "9999999" }
                if present.infinit < 0 then
                    present.n.sort = "-" .. present.n.sort
                end
                present.exp = { sort = "999" }
                fore( present )
            end
            r = Sort.Cell.finalize( present, r )
        else
            Sort.Cell.fault( "???", args )
        end
    else
        error( "'args' is not a table" )
    end
    return r
end -- furnish()



Sort.f = function ( args )
    -- Create table cell start
    -- Parameter:
    --     args    -- table, parameters
    --                .pad        -- number|string, for padding
    --                .pre        -- string, for prefix
    --                .plus       -- boolean|string, for plus sign
    --                .n          -- number|string, for base
    --                .suffix     -- string, extending base
    --                .exp        -- number|string, for exponent
    --                .post       -- string, for postfix
    --                .round      -- number|string, for rounding
    --                .cell       -- string|boolean|table, enforce sort
    --                .rowspan    -- number|string, for cell attribute
    --                .colspan    -- number|string, for cell attribute
    --                .class      -- string, for cell attribute
    --                .style      -- string|table, for cell attribute
    --                .id         -- string, for cell attribute
    --                .cssNum     -- string|title, for templatestyles
    --                .cssNumExp  -- string|title, for templatestyles
    --                .cat        -- string|nil, for error category
    --                .frame      -- table, if present
    -- Postcondition:
    --     Returns string, or expands .cell, or nil
    local lucky, r = pcall( furnish, args )
    if not lucky then
        local e = mw.html.create( "span" )
                         :addClass( "error" )
                         :wikitext( "Module:Sort/cell * " .. r )
        if type( args.cell ) == "table"  and
           type( args.cell.wikitext ) == "function" then
            args.cell:node( e )
        else
            r = tostring( e )
        end
    end
    return r
end -- Sort.f()



Failsafe.failsafe = function ( atleast )
    -- Retrieve versioning and check for compliance
    -- Precondition:
    --     atleast  -- string, with required version or "wikidata" or "~"
    --                 or false
    -- Postcondition:
    --     Returns  string  -- with queried version, also if problem
    --              false   -- if appropriate
    -- 2019-10-15
    local last  = ( atleast == "~" )
    local since = atleast
    local r
    if last  or  since == "wikidata" then
        local item = Failsafe.item
        since = false
        if type( item ) == "number"  and  item > 0 then
            local entity = mw.wikibase.getEntity( string.format( "Q%d",
                                                                 item ) )
            if type( entity ) == "table" then
                local seek = Failsafe.serialProperty or "P348"
                local vsn  = entity:formatPropertyValues( seek )
                if type( vsn ) == "table"  and
                   type( vsn.value ) == "string"  and
                   vsn.value ~= "" then
                    if last  and  vsn.value == Failsafe.serial then
                        r = false
                    else
                        r = vsn.value
                    end
                end
            end
        end
    end
    if type( r ) == "nil" then
        if not since  or  since <= Failsafe.serial then
            r = Failsafe.serial
        else
            r = false
        end
    end
    return r
end -- Failsafe.failsafe()



-- Export
local p = { }

p.f = function ( frame )
    -- Template call
    Sort.frame = frame
    return Sort.f( frame.args )  or  ""
end -- p.f

p.failsafe = function ( frame )
    -- Versioning interface
    local s = type( frame )
    local since
    if s == "table" then
        since = frame.args[ 1 ]
    elseif s == "string" then
        since = frame
    end
    if since then
        since = mw.text.trim( since )
        if since == "" then
            since = false
        end
    end
    return Failsafe.failsafe( since )  or  ""
end -- p.failsafe

p.Sort = function ()
    -- Module interface
    return Sort
end

return p