Rosetta Code/List authors of task descriptions: Difference between revisions

m
(Move full listing to its own page)
m (→‎{{header|Wren}}: Minor tidy)
 
(22 intermediate revisions by 6 users not shown)
Line 1:
{{draft task}}In this task, the goal is to compile an authorship list for task descriptions. A pseudocode example (in imperative style) that should accomplish this is as follows:
 
<langsyntaxhighlight lang="pseudocode">for each task page
grab page source, discard everything after the first ==section==.
Cache as $previous. Note $author.
Line 9:
compare $previous2 to $previous. If different, record $author to $list.
replace $previous with $previous2
replace $author with $author2</langsyntaxhighlight>
 
The following resources for HTTP interface information for MediaWiki may prove to be useful:
Line 21:
Please '''DO NOT''' add a full output for ''each'' programming language; just show a representative sample. For an full listing, see [[Rosetta_Code/List_authors_of_task_descriptions/Full_list]].
 
=={{header|Go}}==
<syntaxhighlight lang="go">package main
 
import (
=={{header|Perl 6}}==
"fmt"
"io/ioutil"
"net/http"
"regexp"
"sort"
"strings"
)
 
type authorNumber struct {
author string
number int
}
 
func main() {
ex1 := `<li><a href="/wiki/(.*?)"`
ex2 := `a href="/(wiki/User:|mw/index\.php\?title=User:|wiki/Special:Contributions/)([^"&]+)`
re1 := regexp.MustCompile(ex1)
re2 := regexp.MustCompile(ex2)
url1 := "http://rosettacode.org/wiki/Category:Programming_Tasks"
url2 := "http://rosettacode.org/wiki/Category:Draft_Programming_Tasks"
urls := []string{url1, url2}
var tasks []string
for _, url := range urls {
resp, _ := http.Get(url)
body, _ := ioutil.ReadAll(resp.Body)
// find all tasks
matches := re1.FindAllStringSubmatch(string(body), -1)
resp.Body.Close()
for _, match := range matches {
// exclude any 'category' references
if !strings.HasPrefix(match[1], "Category:") {
tasks = append(tasks, match[1])
}
}
}
authors := make(map[string]int)
for _, task := range tasks {
// check the last or only history page for each task
page := fmt.Sprintf("http://rosettacode.org/mw/index.php?title=%s&dir=prev&action=history", task)
resp, _ := http.Get(page)
body, _ := ioutil.ReadAll(resp.Body)
// find all the users in that page
matches := re2.FindAllStringSubmatch(string(body), -1)
resp.Body.Close()
// the task author should be the final user on that page
author := matches[len(matches)-1][2]
author = strings.ReplaceAll(author, "_", " ")
// add this task to the author's count
authors[author]++
}
// sort the authors in descending order by number of tasks created
authorNumbers := make([]authorNumber, 0, len(authors))
for k, v := range authors {
authorNumbers = append(authorNumbers, authorNumber{k, v})
}
sort.Slice(authorNumbers, func(i, j int) bool {
return authorNumbers[i].number > authorNumbers[j].number
})
// print the top twenty say
fmt.Println("Total tasks :", len(tasks))
fmt.Println("Total authors :", len(authors))
fmt.Println("\nThe top 20 authors by number of tasks created are:\n")
fmt.Println("Pos Tasks Author")
fmt.Println("=== ===== ======")
lastNumber, lastIndex := 0, -1
for i, authorNumber := range authorNumbers[0:20] {
j := i
if authorNumber.number == lastNumber {
j = lastIndex
} else {
lastIndex = i
lastNumber = authorNumber.number
}
fmt.Printf("%2d: %3d %s\n", j+1, authorNumber.number, authorNumber.author)
}
}</syntaxhighlight>
 
{{out}}
As of 5th March 2020:
<pre>
Total tasks : 1237
Total authors : 287
 
The top 20 authors by number of tasks created are:
 
Pos Tasks Author
=== ===== ======
1: 178 Paddy3118
2: 71 Markhobley
3: 61 Gerard Schildberger
4: 55 Mwn3d
5: 39 NevilleDNZ
6: 33 Short Circuit
7: 30 Nigel Galloway
8: 29 Thundergnat
9: 23 Grondilu
10: 21 Dkf
11: 20 Fwend
11: 20 Blue Prawn
13: 19 CalmoSoft
14: 18 Kernigh
15: 17 ShinTakezou
15: 17 Dmitry-kazakov
15: 17 Ledrug
18: 13 Abu
18: 13 Paulo Jorente
18: 13 Waldorf
</pre>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">""" Rosetta code task rosettacode.org/wiki/Rosetta_Code/List_authors_of_task_descriptions """
 
using Dates
using DataFrames
using EzXML
using HTTP
using JSON3
 
""" Get Rosetta Code authors of tasks, output as dataframe """
function rosetta_code_authors(verbose = false)
URL = "https://rosettacode.org/w/api.php?"
PARAMS = ["action" => "query", "format" => "json", "formatversion" => "2", "generator" => "categorymembers",
"gcmtitle" => "Category:Programming_Tasks", "gcmlimit" => "500", "rawcontinue" => "", "prop" => "title"]
DRAFTPARAMS = ["action" => "query", "format" => "json", "formatversion" => "2", "generator" => "categorymembers",
"gcmtitle" => "Category:Draft_Programming_Tasks", "gcmlimit" => "500", "rawcontinue" => "", "prop" => "title"]
 
titles = Pair{String, Bool}[]
dateformat = DateFormat("HH:SS, d U y")
df = empty!(DataFrame([[""], [""], [now()], [true]], ["Author", "Title", "CreationDate", "IsDraftTask"]))
 
for param in [PARAMS, DRAFTPARAMS] # get the titles of the tasks and draft tasks, store list in alltasks
continueposition = ""
queryparams = copy(param)
isdraft = param == DRAFTPARAMS
while true
resp = HTTP.get(URL * join(map(p -> p[1] * (p[2] == "" ? "" : ("=" * p[2])), queryparams), "&"))
json = JSON3.read(String(resp.body))
pages = json.query.pages
for p in pages
push!(titles, p.title => isdraft)
end
!haskey(json, "query-continue") && break # break if no more pages, else continue to next pages
queryparams = vcat(param, "gcmcontinue" => json["query-continue"]["categorymembers"]["gcmcontinue"])
end
end
 
 
for (i, title) in pairs(titles) # Get author of first revision of each page, assumed to be task creator/author
resp = HTTP.get("https://rosettacode.org/w/index.php?title=" * escape(title[1]) * "&dir=prev&action=history")
html = root(parsehtml(String(resp.body)))
xpath = "//span[@class=\"history-user\"]/a"
header = findlast(xpath, html)
author = header != nothing ? nodecontent(header) : ""
xpath2 = "//a[@class=\"mw-changeslist-date\"]"
header2 = findlast(xpath2, html)
creationdate = header2 != nothing ? DateTime(nodecontent(header2), dateformat) : missing
if author != ""
author = replace(author, r".+>" => "") # clean up from the hosting change
push!(df, [author, title[1], creationdate, title[2]])
verbose && println("Processed author $author of $title created $creationdate: page $i of ", length(titles))
end
end
sort!(df, :CreationDate, rev = true)
authorfreqs = sort!(combine(groupby(df, :Author), nrow => :Freq), :Freq, rev = true)
return df, authorfreqs
end
 
rosetta_code_authors()
</syntaxhighlight>{{out}}
<pre>
(1569×4 DataFrame
Row │ Author Title CreationDate IsDraftTask
│ String String DateTime Bool
──────┼───────────────────────────────────────────────────────────────────────────────────
1 │ Markjreed Sieve of Pritchard 2022-08-25T19:00:09 false
2 │ Thundergnat Penta-power prime seeds 2022-08-19T20:00:59 true
3 │ Thundergnat Quad-power prime seeds 2022-08-19T20:00:23 true
4 │ Thundergnat Riordan numbers 2022-08-18T18:00:20 true
5 │ Thundergnat Pairs with common factors 2022-08-18T12:00:07 true
6 │ Thundergnat Klarner-Rado sequence 2022-08-17T22:00:36 true
⋮ │ ⋮ ⋮ ⋮ ⋮
1564 │ Created by: X Determine if a string is numeric 2007-01-21T19:00:47 false
1565 │ MikeMol Empty program 2007-01-18T15:00:11 false
1566 │ 207.74.29.206 Window creation 2007-01-15T19:00:41 false
1567 │ MikeMol Table creation 2007-01-14T20:00:07 true
1568 │ MikeMol Hello world/Text 2007-01-09T16:00:45 false
1569 │ MikeMol File input/output 2007-01-09T14:00:45 false
1557 rows omitted,
315×2 DataFrame
Row │ Author Freq
│ String Int64
─────┼────────────────────────────
1 │ Paddy3118 199
2 │ CalmoSoft 135
3 │ Thundergnat 74
4 │ Markhobley 71
5 │ Gerard Schildberger 66
6 │ Mwn3d 55
⋮ │ ⋮ ⋮
310 │ Til 1
311 │ Backupbrain 1
312 │ Fabian 1
313 │ Vcelier 1
314 │ Created by: X 1
315 │ 207.74.29.206 1
303 rows omitted)
</pre>
 
=={{header|Nim}}==
{{trans|Go}}
<syntaxhighlight lang="nim">import algorithm, httpclient, re, strutils, tables
 
let
re1 = re("""<li><a href="/wiki/(.*?)"""")
re2 = re("""a href="/wiki/User:|mw/index\.php\?title=User:|wiki/Special:Contributions/([^"&]+)""")
 
const
Url1 = "http://rosettacode.org/wiki/Category:Programming_Tasks"
Url2 = "http://rosettacode.org/wiki/Category:Draft_Programming_Tasks"
Urls = [Url1, Url2]
 
var client = newHttpClient()
 
var tasks: seq[string]
var matches: array[1, string]
var start = 0
for url in Urls:
let body = client.getContent(url)
# Find all tasks.
while true:
start = body.find(re1, matches, start) + 1
if start == 0: break
if not matches[0].startsWith("Category:"):
tasks.add matches[0]
 
var authors: CountTable[string]
for task in tasks:
# Check the last or only history page for each task.
let page = "http://rosettacode.org/mw/index.php?title=$#&dir=prev&action=history".format(task)
let body = client.getContent(page)
# Find all the users in that page. The task author should be the final user on that page.
var matches: array[1, string]
start = 0
while true:
start = body.find(re2, matches, start) + 1
if start == 0: break
let author = matches[0].replace('-', ' ')
# Add this task to the author's count.
authors.inc(author)
 
# Sort the authors in descending order by number of tasks created.
authors.sort(Descending)
 
# Print the top twenty.
echo "Total tasks: ", tasks.len
echo "Total authors: ", authors.len
echo "\nThe top 20 authors by number of tasks created are:\n"
echo "Pos Tasks Author"
echo "=== ===== ======"
var pos = 0
for author, count in authors.pairs:
inc pos
echo ($pos).align(2), " ", ($count).align(3), " ", author
if pos == 20: break</syntaxhighlight>
 
{{out}}
On 2021-06-29.
<pre>The top 20 authors by number of tasks created are:
 
Pos Tasks Author
=== ===== ======
1 196 Paddy3118
2 84 CalmoSoft
3 72 Markhobley
4 66 Gerard_Schildberger
5 55 Mwn3d
6 39 NevilleDNZ
7 39 Thundergnat
8 33 Nigel_Galloway
9 33 Short_Circuit
10 23 Grondilu
11 21 Blue_Prawn
12 20 Fwend
13 20 Dkf
14 18 Kernigh
15 17 Ledrug
16 17 ShinTakezou
17 17 Dmitry kazakov
18 14 Wherrera
19 13 Waldorf
20 13 Abu</pre>
 
=={{header|Phix}}==
To keep the output nice and short, lists the top 5 task creators.<br>
Uses a cache: once a .hist file has been downloaded for a given
task, it is assumed to be good forever. Each task is about 20K,
so it will download around 25MB in total, for >= 1,219 tasks.
It does those sequentially, using curl_easy_ handles. I guess
if you really wanted to then using curl_multi_ handles would
properly thrash the rosettacode servers.
{{libheader|Phix/libcurl}}
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\List_task_authors.exw</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (libcurl, file i/o, peek, progress..)</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">rosettacode_cache</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- see [[Rosetta_Code/Count_examples#Phix]]</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">history_user</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">`&lt;span class='history-user'&gt;&lt;a href="`</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">count_tasks</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">get_file_type</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"rc_cache"</span><span style="color: #0000FF;">)!=</span><span style="color: #004600;">FILETYPE_DIRECTORY</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">create_directory</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"rc_cache"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"cannot create rc_cache directory"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tasks</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dewiki</span><span style="color: #0000FF;">(</span><span style="color: #000000;">open_category</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Programming_Tasks"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))</span>
<span style="color: #0000FF;">&</span> <span style="color: #000000;">dewiki</span><span style="color: #0000FF;">(</span><span style="color: #000000;">open_category</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Draft_Programming_Tasks"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ntasks</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tasks</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">users</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span>
<span style="color: #000000;">utask</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span>
<span style="color: #000000;">ntask</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">ntasks</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tasks</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">url</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"http://rosettacode.org/mw/index.php?title=%s&action=history&dir=prev&limit=1"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">}),</span>
<span style="color: #000000;">contents</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">open_download</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">&</span><span style="color: #008000;">".hist"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">url</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ntasks</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #000000;">history_user</span><span style="color: #0000FF;">,</span><span style="color: #000000;">contents</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'&gt;'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">contents</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">history_user</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"&lt;/a&gt;"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">contents</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">e</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">user</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">contents</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..</span><span style="color: #000000;">e</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">user</span><span style="color: #0000FF;">,</span><span style="color: #000000;">users</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">users</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">users</span><span style="color: #0000FF;">,</span><span style="color: #000000;">user</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">utask</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">utask</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">ntask</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ntask</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">utask</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span>
<span style="color: #000000;">ntask</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">html_clean</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (in case you want to show them)</span>
<span style="color: #000000;">tasks</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ti</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">get_key</span><span style="color: #0000FF;">()=</span><span style="color: #000000;">#1B</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">progress</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"escape keyed\n"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">curl_cleanup</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">progress</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">nusers</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">users</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tags</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ntask</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nusers</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">top5</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">nusers</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ui</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tags</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ntask</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ui</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">5</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s tasks:%d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">users</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ui</span><span style="color: #0000FF;">],</span><span style="color: #000000;">ntask</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ui</span><span style="color: #0000FF;">]})</span>
<span style="color: #000000;">top5</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">if</span> <span style="color: #000000;">top5</span><span style="color: #0000FF;">></span><span style="color: #000000;">5</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ntasks</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nusers</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">progress</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Total: %d tasks by %d authors\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">count_tasks</span><span style="color: #0000FF;">())</span>
<!--</syntaxhighlight>-->
{{out}}
As of 6th Jan 2020
<pre>
Paddy3118 tasks:176
Markhobley tasks:71
Gerard Schildberger tasks:59
Mwn3d tasks:55
NevilleDNZ tasks:39
Short Circuit tasks:33
Total: 1219
</pre>
As of 6th Jan 2022
<pre>
Paddy3118 tasks:199
CalmoSoft tasks:128
Markhobley tasks:71
Gerard Schildberger tasks:66
Mwn3d tasks:55
Thundergnat tasks:44
Total: 1492 tasks by 307 authors
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.03}}
 
The pseudocode above is no longer really useful as the page format has changed significantly since this task was written. Rather than checking '''every''' edit to see if it was a change to the task description, we'll just assume the user that created the page is the task author. This isn't 100% accurate; a very few pages got renamed and recreated by someone other than the original author without preserving the history, so they are misreported (15 Puzzle Game for instance,) but is as good as it is likely to get without extensive manual intervention. Subsequent edits to the task description are not credited. As it is, we must still make ''thousands'' of requests and pound the server pretty hard. Checking '''every''' edit would make the task several of orders of magnitude more abusive of the server (and my internet connection.)
 
<syntaxhighlight lang="raku" perl6line>use HTTP::UserAgent;
use URI::Escape;
use JSON::Fast;
Line 40 ⟶ 428:
my $client = HTTP::UserAgent.new;
 
my $url = 'httphttps://rosettacode.org/mww';
 
my $tablefile = './RC_Authors.txt';
Line 49 ⟶ 437:
# clear screen
run($*DISTRO.is-win ?? 'cls' !! 'clear');
 
%tasks = $hashfile.IO.e ?? $hashfile.IO.slurp.&from-json !! ( );
sleep 1;
 
#=begin update
 
note 'RetreivingRetrieving task information...';
 
my %filter;
for %cat.keys -> $category {
for %cat.keys.sort -> $category {
mediawiki-query(
$url, 'pages',
Line 62 ⟶ 454:
:rawcontinue(),
:prop<title>
).map( { %filter{.<title>} = %cat{$category} } )
}
mediawiki-query(
 
$url, 'pages',
my $delete = %tasks.keys (-) %filter.keys;
:titles(.<title>),
 
:prop<revisions>,
%tasks.delete($_) for $delete.keys; #Tasks that have changed names or been removed
:rvprop<user|timestamp>,
 
:rvstart<2000-01-01T01:01:01Z>,
my @add;
:rvdir<newer>,
for %filter.keys -> $title {
:rvlimit<1>
if %tasks{$title}:exists {
)}
%tasks{$title}<category> = %filter{$title} # update status
).map({
} else {
print clear, 1 + $++, ' ', %cat{$category}, ' ', .[0]<title>;
%tasks{@add.[0]<push: $title>}<category> => %catfilter{$categorytitle}; # New Tasks
}
}
 
if @add {
.say for 'Adding new tasks:', |@add;
}
 
for @add -> $task {
mediawiki-query(
$url, 'pages',
:titles($task.key),
:prop<revisions>,
:rvprop<user|timestamp>,
:rvstart<2000-01-01T01:01:01Z>,
:rvdir<newer>,
:rvlimit<1>
).map: {
print clear, 1 + $++, ' ', .[0]<title>;
%tasks{.[0]<title>}<category> = $task.value;
%tasks{.[0]<title>}<author> = .[0]<revisions>[0]<user>;
%tasks{.[0]<title>}<date> = .[0]<revisions>[0]<timestamp>.subst(/'T'.+$/, '')
}
)
}
 
Line 103 ⟶ 513:
# Add table boilerplate and header
$out.say:
"\{|class=\"wikitable sortable\"\n",
"|+ As of { Date.today } :: Total Tasks: { $count }:: Tasks: { $taskcnt }",
" ::<span style=\"background-color:#ffd\"> Draft Tasks: { $draftcnt }\n </span>",
":: By {+%tasks{*}».<author>.unique} Authors\n",
"! Author !! Authored"
"! Author !! Tasks !! Authored"
;
 
# Get sorted unique list of task authors
for %tasks{*}».<author>.unique.sort(*.&naturally) -> $author {
 
# Get list of tasks by this author
Line 116 ⟶ 527:
my $s = +@these == 1 ?? '' !! 's';
 
# Add author and contributions link to the first celltwo cells
$out.say:
$out.say: "|-\n| [[User:$author|$author]] : [[Special:Contributions/$author|",
$author ~~ /\d/
" { +@these } task{ $s }]]";
?? "|- id=\"$author\"\n|data-sort-value=\"{ sort-key $author }\"|[[User:$author|$author]]\n"~
"|data-sort-value=\"{ +@these }\"|[[Special:Contributions/$author|"~
"{ +@these } task{ $s }]]"
!! "|- id=\"$author\"\n|[[User:$author|$author]]\n"~
"|data-sort-value=\"{ +@these }\"|[[Special:Contributions/$author|"~
"{ +@these } task{ $s }]]"
;
 
if +@these > 2 {
$out.say: "|style=\"padding: 0px;\"|\n",
$out.say: "\{|class=\"broadtable sortable\" style=\"widthpadding: 100%0px;\"|\n",
"\{|class=\"broadtable sortable\" style=\"width: 100%;\"\n",
"! Task Name !! Date Added !! Status";
"! Task Name !! Date Added !! Status";
}
else {
$out.say: "|style=\"padding: 0px;\"|\n",
"\{|class=\"broadtable\" style=\"width: 100%;\"";
}
 
# Tasks by this author, sorted by name
Line 142 ⟶ 566:
$out.say( "|}\n" );
$out.close;
 
 
note "Table file saved as: {$tablefile.IO.absolute}";
Line 160 ⟶ 585:
sub uri-query-string (*%fields) { %fields.map({ "{.key}={uri-escape .value}" }).join("&") }
 
sub sort-key ($a) { $a.lc.subst(/(\d+)/, ->$/ {0~(65+($0.chars)).chr~$0},:g) }
 
sub clear { "\r" ~ ' ' x 100 ~ "\r" }</syntaxhighlight>
</lang>
 
{{out|Sample output}}
Line 169 ⟶ 593:
See full output at [[Rosetta_Code/List_authors_of_task_descriptions/Full_list]]
 
{|class="wikitable sortable"
|+ As of 2018-0304-3110 :: Total Tasks: 1080:: Tasks: 871 ::<span style="background-color:#ffd"> Draft Tasks: 209 </span>:: By 251 Authors
! Author !! Tasks !! Authored
|-
| data-sort-value="0B2powers"|[[User:2Powers|2Powers]] : [[Special:Contributions/2Powers| 2 tasks]]
|data-sort-value="2"|[[Special:Contributions/2Powers|2 tasks]]
|style="padding: 0px;"|
{|class="broadtable sortable" style="width: 100%;"
! Task Name !! Date Added !! Status
|-
|style="background-color: #ffd;"| [[Names%20to%20numbers|Names to numbers]]
Line 187 ⟶ 611:
|}
|-
| data-sort-value="0C12.0D175.0C32.0C19"|[[User:12.175.32.19|12.175.32.19]] : [[Special:Contributions/12.175.32.19| 1 task]]
|data-sort-value="1"|[[Special:Contributions/12.175.32.19|1 task]]
|style="padding: 0px;"|
{|class="broadtable sortable" style="width: 100%;"
! Task Name !! Date Added !! Status
|-
|style="background-color: #fff;"| [[Soundex|Soundex]]
Line 197 ⟶ 621:
|}
|-
| data-sort-value="0C12me0C21"|[[User:12Me21|12Me21]] : [[Special:Contributions/12Me21| 1 task]]
|data-sort-value="1"|[[Special:Contributions/12Me21|1 task]]
|style="padding: 0px;"|
{|class="broadtable sortable" style="width: 100%;"
! Task Name !! Date Added !! Status
|-
|style="background-color: #fff;"| [[Draw%20a%20rotating%20cube|Draw a rotating cube]]
Line 207 ⟶ 631:
|}
|-
|colspan="23"|many rows omitted...
|-
| data-sort-value="zorro0E1024"|[[User:Zorro1024|Zorro1024]] : [[Special:Contributions/Zorro1024| 2 tasks]]
|data-sort-value="2"|[[Special:Contributions/Zorro1024|2 tasks]]
|style="padding: 0px;"|
{|class="broadtable sortable" style="width: 100%;"
! Task Name !! Date Added !! Status
|-
|style="background-color: #fff;"| [[Perfect%20shuffle|Perfect shuffle]]
Line 223 ⟶ 647:
|}
|-
| data-sort-value="zzo0C38"|[[User:Zzo38|Zzo38]] : [[Special:Contributions/Zzo38| 1 task]]
|data-sort-value="1"|[[Special:Contributions/Zzo38|1 task]]
|style="padding: 0px;"|
{|class="broadtable sortable" style="width: 100%;"
! Task Name !! Date Added !! Status
|-
|style="background-color: #fff;"| [[Thue-Morse|Thue-Morse]]
Line 233 ⟶ 657:
|}
|-
| [[User:Русский|Русский]] : [[Special:Contributions/Русский| 3 tasks]]
|data-sort-value="3"|[[Special:Contributions/Русский|3 tasks]]
|style="padding: 0px;"|
{|class="broadtable sortable" style="width: 100%;"
Line 251 ⟶ 676:
|}
|}
 
=={{header|Wren}}==
{{libheader|libcurl}}
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
An embedded program so we can use libcurl.
 
Takes upwards of 80 minutes to run as the history page(s) for each task need to be downloaded and parsed to find the author. Worse still, given we are pounding a busy server pretty hard, there are lots of 'bad gateway' and other errors (94 on this particular run!) which necessitate adding tasks back to the task list until they are eventually downloaded and parsed successfully which can add several minutes to the overall time.
<syntaxhighlight lang="wren">/* Rosetta_Code_List_authors_of_task_descriptions.wren */
 
import "./pattern" for Pattern
import "./fmt" for Fmt
 
var CURLOPT_URL = 10002
var CURLOPT_FOLLOWLOCATION = 52
var CURLOPT_WRITEFUNCTION = 20011
var CURLOPT_WRITEDATA = 10001
 
foreign class Buffer {
construct new() {} // C will allocate buffer of a suitable size
 
foreign value // returns buffer contents as a string
}
 
foreign class Curl {
construct easyInit() {}
 
foreign easySetOpt(opt, param)
 
foreign easyPerform()
 
foreign easyCleanup()
}
 
var curl = Curl.easyInit()
 
var getContent = Fn.new { |url|
var buffer = Buffer.new()
curl.easySetOpt(CURLOPT_URL, url)
curl.easySetOpt(CURLOPT_FOLLOWLOCATION, 1)
curl.easySetOpt(CURLOPT_WRITEFUNCTION, 0) // write function to be supplied by C
curl.easySetOpt(CURLOPT_WRITEDATA, buffer)
curl.easyPerform()
return buffer.value
}
 
var p1 = Pattern.new("title/=\"[+1^\"]\"")
var p2 = Pattern.new("cmcontinue/=\"[+1^\"]\"")
var pi = "\"&"
var p3 = Pattern.new("a href/=\"//[wiki//User:|w//index.php?title/=User:|wiki//Special:Contributions//][+1/I]\"", 0, pi)
 
var findTasks = Fn.new { |category|
var url = "https://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:%(category)&cmlimit=500&format=xml"
var cmcontinue = ""
var tasks = []
while (true) {
var content = getContent.call(url + cmcontinue)
var matches1 = p1.findAll(content)
for (m in matches1) {
var title = m.capsText[0].replace("&#039;", "'").replace("&quot;", "\"")
tasks.add(title)
}
var m2 = p2.find(content)
if (m2) cmcontinue = "&cmcontinue=%(m2.capsText[0])" else break
}
return tasks
}
 
var tasks = findTasks.call("Programming_Tasks") // 'full' tasks only
tasks.addAll(findTasks.call("Draft_Programming_Tasks"))
var tc = tasks.count
var authors = {}
while (tasks.count > 0) {
var task = tasks[0].replace(" ", "_").replace("+", "\%2B")
// check the last or only history page for each task
var url = "https://rosettacode.org/w/index.php?title=%(task)&dir=prev&action=history"
tasks.removeAt(0)
var content = getContent.call(url)
content = content.replace("http://www.rosettacode.org", "")
var matches = p3.findAll(content)
// if there are no matches there must have been a 'bad gateway' or other error
if (matches.count == 0) {
// add back a failed task until it eventually succeeds
tasks.add(task)
continue
}
// the task author should be the final user on that page
var author = matches[-1].capsText[1].replace("_", " ")
// add this task to the author's count
if (authors.containsKey(author)) {
authors[author] = authors[author] + 1
} else {
authors[author] = 1
}
}
 
// sort the authors in descending order by number of tasks created
var authorNumbers = authors.toList
authorNumbers.sort { |a, b| a.value > b.value }
// print those who've completed at least 9 tasks
System.print("As at 10th September 2022:\n")
System.print("Total tasks : %(tc)")
System.print("Total authors : %(authors.count)")
System.print("\nThe authors who have created at least 9 tasks are:\n")
System.print("Pos Tasks Author")
System.print("==== ===== ======")
var lastNumber = 0
var lastIndex = -1
var i = 0
for (authorNumber in authorNumbers.where { |me| me.value >= 9 }) {
var j = i
var eq = " "
if (authorNumber.value == lastNumber) {
j = lastIndex
eq = "="
} else {
lastIndex = i
lastNumber = authorNumber.value
}
Fmt.print("$3d$s $3d $s", j+1, eq, authorNumber.value, authorNumber.key)
i = i + 1
}
curl.easyCleanup()</syntaxhighlight>
<br>
We now embed this script in the following C program, build and run.
<syntaxhighlight lang="c">/* gcc Rosetta_Code_List_authors_of_task_descriptions.c -o Rosetta_Code_List_authors_of_task_descriptions -lcurl -lwren -lm */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"
 
struct MemoryStruct {
char *memory;
size_t size;
};
 
/* C <=> Wren interface functions */
 
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(!ptr) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
 
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
 
void C_bufferAllocate(WrenVM* vm) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct MemoryStruct));
ms->memory = malloc(1);
ms->size = 0;
}
 
void C_bufferFinalize(void* data) {
struct MemoryStruct *ms = (struct MemoryStruct *)data;
free(ms->memory);
}
 
void C_curlAllocate(WrenVM* vm) {
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
*pcurl = curl_easy_init();
}
 
void C_value(WrenVM* vm) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 0);
wrenSetSlotString(vm, 0, ms->memory);
}
 
void C_easyPerform(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_perform(curl);
}
 
void C_easyCleanup(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_cleanup(curl);
}
 
void C_easySetOpt(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
if (opt < 10000) {
long lparam = (long)wrenGetSlotDouble(vm, 2);
curl_easy_setopt(curl, opt, lparam);
} else if (opt < 20000) {
if (opt == CURLOPT_WRITEDATA) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 2);
curl_easy_setopt(curl, opt, (void *)ms);
} else if (opt == CURLOPT_URL) {
const char *url = wrenGetSlotString(vm, 2);
curl_easy_setopt(curl, opt, url);
}
} else if (opt < 30000) {
if (opt == CURLOPT_WRITEFUNCTION) {
curl_easy_setopt(curl, opt, &WriteMemoryCallback);
}
}
}
 
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Buffer") == 0) {
methods.allocate = C_bufferAllocate;
methods.finalize = C_bufferFinalize;
} else if (strcmp(className, "Curl") == 0) {
methods.allocate = C_curlAllocate;
}
}
return methods;
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Buffer") == 0) {
if (!isStatic && strcmp(signature, "value") == 0) return C_value;
} else if (strcmp(className, "Curl") == 0) {
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform;
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup;
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}
 
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}
 
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
config.loadModuleFn = &loadModule;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Rosetta_Code_List_authors_of_task_descriptions.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</syntaxhighlight>
 
{{out}}
<pre>
As at 10th September 2022:
 
Total tasks : 1569
Total authors : 315
 
The authors who have created at least 9 tasks are:
 
Pos Tasks Author
==== ===== ======
1 199 Paddy3118
2 135 CalmoSoft
3 74 Thundergnat
4 71 Markhobley
5 66 Gerard Schildberger
6 55 Mwn3d
7 39 NevilleDNZ
7= 39 Nigel Galloway
9 33 MikeMol
10 27 PureFox
11 23 Grondilu
12 21 Blue Prawn
13 20 Fwend
13= 20 Dkf
15 19 Wherrera
16 18 Kernigh
17 17 Dmitry-kazakov
17= 17 ShinTakezou
17= 17 Ledrug
20 13 Paulo Jorente
20= 13 Abu
20= 13 Waldorf
23 12 Ce
23= 12 Kevin Reid
23= 12 Puppydrum64
26 10 Bearophile
26= 10 Tinku99
28 9 TimSC
28= 9 Petelomax
28= 9 EMBee
28= 9 Trizen
</pre>
9,479

edits