AutosortTable: Creates a table which is automatically sorted
 
Usage: (Remove the hidden comments before use)
 
 
 
 
]]
 
local _module = {}
 
_module.create = function(frame)
 
 local args = frame.args
 
 -- Named parameters
 
 local class = args.class
 local style = args.style
 local sep = args.separator
 local order = args.order
 local desc = args.descending or ""
 local nsort = args.numeric or ""
 local hidden = args.hidden or ""
 local header = args.header
 local footer = args.footer
 local colstyle = args.colstyle
 
 -- Frequently-used functions
 
 local strIndexOf = mw.ustring.find
 local strSplit = mw.text.split
 local strSub = mw.ustring.sub
 local strTrim = mw.text.trim
 
 local seplen = #sep
 local nsortLookup, descLookup, hiddenLookup = {}, {}, {}
 
 -- Create the table
 
 local html = mw.html.create
 local htable = html:tag('table')
 if class then htable:attr end
 if style then htable:attr end
 
 -- Parses a row string. The key paremter is used to assign a unique key to the result so that equal rows do not cause sort errors.
 local parse = function
 local css
 local firstSep = strIndexOf
 if firstSep == 1 then -- no CSS
 css = nil
 s = strSub
 else -- CSS before first separator
 css = strSub
 s = strSub
 end 
 
 return { key = key, css = css, data = strSplit }
 end
 
 --
 Writes a row to the table.
 css: CSS to apply to the row.
 data: The data (cells) of the row
 _type: Can be 'header', 'footer' or nil.
 
 local writeHtml = function
 local row = htable:tag('tr')
 if css then row:attr('style', strTrim(css)) end
 
 for i, v in ipairs(data) do
 if not hiddenLookup[i] then
 local cell
 if _type == 'header' then
 -- Header: use the 'th' tag with scope="col"
 cell = row:tag('th')
 cell:attr
 elseif _type == 'footer' then
 -- Footer: Mark as 'sortbottom' so that it does not sort whe the table is made user-sortable
 -- with the 'wikitable sortable' class
 cell = row:tag('td')
 cell:class('sortbottom')
 else
 -- Ordinary cell
 cell = row:tag('td')
 local cellCss = colstyle and colstyle[i]
 if cellCss then cell:attr('style', strTrim(cellCss)) end -- Apply the column styling, if necessary
 end
 cell:wikitext(strTrim(v))
 end
 end
 
 return row
 end
 
 -- Parse the column styles
 if colstyle then colstyle = parse.data end
 
 -- Write the header first
 if header then
 local headerData = parse(header)
 writeHtml
 end
 
 -- Parse the data
 local data = {}
 for i, v in ipairs(frame.args) do data[i] = parse end
 
 order = strSplit
 nsort = strSplit
 desc = strSplit
 hidden = strSplit
 
 for i, v in ipairs(order) do order[i] = tonumber(v) end
 for i, v in ipairs(nsort) do nsortLookup[tonumber(v) or -1] = true end
 for i, v in ipairs(desc) do descLookup[tonumber(v) or -1] = true end
 for i, v in ipairs(hidden) do hiddenLookup[tonumber(v) or -1] = true end
 
 --Sorting comparator function.
 local sortFunc = function
 local ad, bd = a.data, b.data
 for i = 1, #order do
 local index = order[i]
 local ai, bi = ad[index], bd[index]
 if nsortLookup[index] then
 -- Numeric sort. Find the first occurence of a number an use it. Decimal points are allowed. Scientific notation not supported.
 ai = tonumber( (ai:find and ai:match('[+-]?%d*%.%d+') or ai:match('[+-]?%d+')) or 0 )
 bi = tonumber( (bi:find and bi:match('[+-]?%d*%.%d+') or bi:match('[+-]?%d+')) or 0 )
 end
 if ai ~= bi then
 if descLookup[index] then return ai > bi else return ai < bi end
 end
 end
 return a.key < b.key
 end
 table.sort
 
 -- Write the sorted data to the HTML output
 for i, v in ipairs(data) do writeHtml end
 
 -- Write the footer
 if footer then
 local footerData = parse(footer)
 writeHtml
 end
 
 return tostring(html)
 
end