<?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%3ACCI_stats</id>
	<title>Module:CCI stats - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ACCI_stats"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:CCI_stats&amp;action=history"/>
	<updated>2026-04-15T19:39:22Z</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:CCI_stats&amp;diff=135411&amp;oldid=prev</id>
		<title>imported&gt;Chlod: add option for tabulated data</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:CCI_stats&amp;diff=135411&amp;oldid=prev"/>
		<updated>2022-07-16T22:05:15Z</updated>

		<summary type="html">&lt;p&gt;add option for tabulated data&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local TableTools = require(&amp;quot;Module:TableTools&amp;quot;);&lt;br /&gt;
local getArgs  = require(&amp;quot;Module:Arguments&amp;quot;).getArgs;&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
--- Converts the stats date (days since 1 Jan 1970) into a human-readable&lt;br /&gt;
-- date.&lt;br /&gt;
-- @param date The date to convert&lt;br /&gt;
function p._statsDateToDate(date)&lt;br /&gt;
	return mw.language.getContentLanguage()&lt;br /&gt;
		:formatDate(os.date(&amp;quot;%Y-%m-%d&amp;quot;, date * 86400))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Extracts case open and close dates from wikitext.&lt;br /&gt;
-- @param opens The table to append open dates to.&lt;br /&gt;
-- @param opens The table to append close dates to.&lt;br /&gt;
-- @param wikitext The wikitext to parse.&lt;br /&gt;
function p._extractCaseDates(opens, closes, wikitext)&lt;br /&gt;
    for openDate in mw.ustring.gmatch(wikitext, &amp;quot;data%-cci%-open=[&amp;#039;\&amp;quot;](.-)[&amp;#039;\&amp;quot;]&amp;quot;) do&lt;br /&gt;
        table.insert(opens, tonumber(openDate))&lt;br /&gt;
    end&lt;br /&gt;
    for closeDate in mw.ustring.gmatch(wikitext, &amp;quot;data%-cci%-close=[&amp;#039;\&amp;quot;](.-)[&amp;#039;\&amp;quot;]&amp;quot;) do&lt;br /&gt;
        table.insert(closes, tonumber(closeDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return opens, closes, wikitext&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Returns a tuple containing case dates, the first being all the dates where a&lt;br /&gt;
-- case was opened, the second being all the dates where a case was closed. All&lt;br /&gt;
-- dates are in stats format (i.e. days since the first day of the UNIX epoch,&lt;br /&gt;
-- January 1, 1970).&lt;br /&gt;
-- @param noArchive `true` to exclude counting archives. `closes` will be empty.&lt;br /&gt;
function p._getCaseDates(noArchive)&lt;br /&gt;
    local frame = mw.getCurrentFrame()&lt;br /&gt;
    local opens = {}&lt;br /&gt;
    local closes = {}&lt;br /&gt;
&lt;br /&gt;
    p._extractCaseDates(&lt;br /&gt;
        opens, closes, frame:expandTemplate{ title = &amp;quot;CCIlist&amp;quot; }&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    if not noArchive then&lt;br /&gt;
        p._extractCaseDates(&lt;br /&gt;
            opens, closes, frame:expandTemplate{ title = &amp;quot;Wikipedia:Contributor copyright investigations/Archive&amp;quot; }&lt;br /&gt;
        )&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    table.sort(opens)&lt;br /&gt;
    table.sort(closes)&lt;br /&gt;
    return opens, closes&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Transforms a table of case opening and closing dates and returns a table&lt;br /&gt;
-- of overall case count change for each day. This function will does not return&lt;br /&gt;
-- any duplicate keys.&lt;br /&gt;
function p._caseDatesToCaseNet(opens, closes)&lt;br /&gt;
    local caseNet = {}&lt;br /&gt;
&lt;br /&gt;
    for _, date in ipairs(opens) do&lt;br /&gt;
        if not caseNet[date] then&lt;br /&gt;
            caseNet[date] = 1&lt;br /&gt;
        else&lt;br /&gt;
            caseNet[date] = caseNet[date] + 1&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    for _, date in ipairs(closes) do&lt;br /&gt;
        if not caseNet[date] then&lt;br /&gt;
            caseNet[date] = -1&lt;br /&gt;
        else&lt;br /&gt;
            caseNet[date] = caseNet[date] - 1&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return caseNet&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Gets case net change and count as tabulated data (wikitext)&lt;br /&gt;
function p._caseCountToTabulatedRows(caseNet)&lt;br /&gt;
	local caseTable = mw.html.create(&amp;quot;table&amp;quot;)&lt;br /&gt;
		:addClass(&amp;quot;wikitable&amp;quot;)&lt;br /&gt;
    local caseCountRows = {}&lt;br /&gt;
	&lt;br /&gt;
	caseTable:node(&lt;br /&gt;
		mw.html.create(&amp;quot;tr&amp;quot;)&lt;br /&gt;
			:node(&lt;br /&gt;
				mw.html.create(&amp;quot;th&amp;quot;)&lt;br /&gt;
					:wikitext(&amp;quot;Date&amp;quot;)&lt;br /&gt;
			)&lt;br /&gt;
			:node(&lt;br /&gt;
				mw.html.create(&amp;quot;th&amp;quot;)&lt;br /&gt;
					:wikitext(&amp;quot;Total&amp;quot;)	&lt;br /&gt;
			)&lt;br /&gt;
			:node(&lt;br /&gt;
				mw.html.create(&amp;quot;th&amp;quot;)&lt;br /&gt;
					:wikitext(&amp;quot;Net&amp;quot;)&lt;br /&gt;
			)&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
    local lastValue = 0&lt;br /&gt;
    for date, net in TableTools.sortedPairs(caseNet) do&lt;br /&gt;
    	local newValue = lastValue + net&lt;br /&gt;
    	local caseRow = mw.html.create(&amp;quot;tr&amp;quot;);&lt;br /&gt;
    	&lt;br /&gt;
    	local caseDate = mw.html.create(&amp;quot;td&amp;quot;)&lt;br /&gt;
    		:wikitext(p._statsDateToDate(date));&lt;br /&gt;
    	&lt;br /&gt;
    	local caseCount = mw.html.create(&amp;quot;td&amp;quot;)&lt;br /&gt;
    		:wikitext(newValue);&lt;br /&gt;
    		&lt;br /&gt;
		local caseNet = mw.html.create(&amp;quot;td&amp;quot;)&lt;br /&gt;
			:css(&amp;quot;color&amp;quot;, net &amp;gt; 0 and &amp;quot;#006400&amp;quot; or (net &amp;lt; 0 and &amp;quot;#8b0000&amp;quot; or &amp;quot;inherit&amp;quot;))&lt;br /&gt;
			:css(&amp;quot;font-weight&amp;quot;, net &amp;gt; 2 and &amp;quot;bold&amp;quot; or &amp;quot;normal&amp;quot;)&lt;br /&gt;
			:wikitext(net);&lt;br /&gt;
    	&lt;br /&gt;
    	caseRow&lt;br /&gt;
    		:node(caseDate)&lt;br /&gt;
    		:node(caseCount)&lt;br /&gt;
    		:node(caseNet);&lt;br /&gt;
    	caseTable:node(caseRow);&lt;br /&gt;
        lastValue = newValue&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return caseTable&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Transforms a table of case net dates and returns a table with date:caseCount&lt;br /&gt;
-- pairs.&lt;br /&gt;
function p._caseNetToDateCaseCounts(caseNet)&lt;br /&gt;
    local dateCaseCounts = {}&lt;br /&gt;
&lt;br /&gt;
    local lastValue = 0&lt;br /&gt;
    for date, net in TableTools.sortedPairs(caseNet) do&lt;br /&gt;
    	local newValue = lastValue + net&lt;br /&gt;
        dateCaseCounts[date] = newValue&lt;br /&gt;
        lastValue = newValue&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return dateCaseCounts&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Transforms date case counts to Vega data.&lt;br /&gt;
function p._dateCaseCountsToVega(dateCaseCounts)&lt;br /&gt;
    local values = {}&lt;br /&gt;
&lt;br /&gt;
    for date, caseCount in TableTools.sortedPairs(dateCaseCounts) do&lt;br /&gt;
        table.insert(values, { &lt;br /&gt;
            -- Multiply by seconds in a day to get UNIX timestamp.&lt;br /&gt;
            x = date * 86400000,&lt;br /&gt;
            y = caseCount&lt;br /&gt;
        })&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        data = {&lt;br /&gt;
            {&lt;br /&gt;
            	name = &amp;quot;cases&amp;quot;,&lt;br /&gt;
            	values = values&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
        scales = {&lt;br /&gt;
            {&lt;br /&gt;
                name = &amp;quot;date&amp;quot;,&lt;br /&gt;
                type = &amp;quot;time&amp;quot;,&lt;br /&gt;
                range = &amp;quot;width&amp;quot;,&lt;br /&gt;
                domain = { data = &amp;quot;cases&amp;quot;, field = &amp;quot;x&amp;quot; }&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                name = &amp;quot;open-cases&amp;quot;,&lt;br /&gt;
                range = &amp;quot;height&amp;quot;,&lt;br /&gt;
                nice = true,&lt;br /&gt;
                domain = { data = &amp;quot;cases&amp;quot;, field = &amp;quot;y&amp;quot; }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
        axes = {&lt;br /&gt;
            { type = &amp;quot;x&amp;quot;, scale = &amp;quot;date&amp;quot;, title = &amp;quot;Date&amp;quot; },&lt;br /&gt;
            { type = &amp;quot;y&amp;quot;, scale = &amp;quot;open-cases&amp;quot;, title = &amp;quot;Open cases&amp;quot; }&lt;br /&gt;
        },&lt;br /&gt;
        marks = {&lt;br /&gt;
            {&lt;br /&gt;
                type = &amp;quot;line&amp;quot;,&lt;br /&gt;
                from = { data = &amp;quot;cases&amp;quot; },&lt;br /&gt;
                properties = {&lt;br /&gt;
                    enter = {&lt;br /&gt;
                        x = { scale = &amp;quot;date&amp;quot;, field = &amp;quot;x&amp;quot; },&lt;br /&gt;
                        y = { scale = &amp;quot;open-cases&amp;quot;, field = &amp;quot;y&amp;quot; },&lt;br /&gt;
                        stroke = { value = &amp;quot;#652c90&amp;quot; }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Build a graph with the relevant data.&lt;br /&gt;
local function buildGraph(frame, args, settings)&lt;br /&gt;
    local graphSettings = {&lt;br /&gt;
        version = &amp;quot;2&amp;quot;,&lt;br /&gt;
        width = args.width or 1000,&lt;br /&gt;
        height = args.height or 300&lt;br /&gt;
    }&lt;br /&gt;
    local graphContent = TableTools.deepCopy(graphSettings)&lt;br /&gt;
    for k,v in TableTools.sortedPairs(settings) do graphContent[k] = v end&lt;br /&gt;
&lt;br /&gt;
    return frame:extensionTag{&lt;br /&gt;
        name = &amp;quot;graph&amp;quot;,&lt;br /&gt;
        content = mw.text.jsonEncode(&lt;br /&gt;
            graphContent,&lt;br /&gt;
            mw.text.JSON_PRETTY&lt;br /&gt;
        )&lt;br /&gt;
    }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._graphCases(args)&lt;br /&gt;
    local opens, closes = p._getCaseDates(args.noArchive)&lt;br /&gt;
    local caseNet = p._caseDatesToCaseNet(opens, closes)&lt;br /&gt;
    local dateCaseCounts = p._caseNetToDateCaseCounts(caseNet)&lt;br /&gt;
    local vegaData = p._dateCaseCountsToVega(dateCaseCounts)&lt;br /&gt;
&lt;br /&gt;
    return buildGraph(args.frame, args.args, vegaData)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.graphCases(frame)&lt;br /&gt;
    local args = getArgs(frame, {&lt;br /&gt;
		trim = true,&lt;br /&gt;
		removeBlanks = false&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
    return p._graphCases{&lt;br /&gt;
        frame = frame,&lt;br /&gt;
        args = args,&lt;br /&gt;
        from = args.from,&lt;br /&gt;
        upto = args.upto&lt;br /&gt;
    }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._tabulatedData(args)&lt;br /&gt;
    local opens, closes = p._getCaseDates(args.noArchive)&lt;br /&gt;
    local caseNet = p._caseDatesToCaseNet(opens, closes)&lt;br /&gt;
    &lt;br /&gt;
    return tostring(p._caseCountToTabulatedRows(caseNet))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.tabulatedData(frame)&lt;br /&gt;
    local args = getArgs(frame, {&lt;br /&gt;
		trim = true,&lt;br /&gt;
		removeBlanks = false&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
    return p._tabulatedData{&lt;br /&gt;
        frame = frame,&lt;br /&gt;
        args = args,&lt;br /&gt;
        from = args.from,&lt;br /&gt;
        upto = args.upto&lt;br /&gt;
    }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Chlod</name></author>
	</entry>
</feed>