Add GH Pull/Push, StackOverflow tags, README.
authorJoel Martin <github@martintribe.org>
Mon, 25 Mar 2019 04:24:44 +0000 (23:24 -0500)
committerJoel Martin <github@martintribe.org>
Mon, 25 Mar 2019 17:47:17 +0000 (12:47 -0500)
- Add GitHub/GitHut pull requests and pushes.
- Add StackOverflow tag counts (this also involves some hard-coded
  rollup of certain tags).
- Add README with update instructions.
- Move graph specific data mangling from collect code to graph
  rendering code.

docs/graph/README.md [new file with mode: 0644]
docs/graph/all_data.json
docs/graph/collect_data.js
docs/graph/graph_languages.js
docs/graph/index.html
docs/graph/package.json

diff --git a/docs/graph/README.md b/docs/graph/README.md
new file mode 100644 (file)
index 0000000..65416ac
--- /dev/null
@@ -0,0 +1,39 @@
+# Mal Implementation Stats Graph
+
+
+## Updating the data
+
+* Install prerequisites:
+
+```
+sudo aptitude install ruby2.3-dev
+sudo gem install travis --no-rdoc --no-ri
+```
+
+* Download the latest successful travis build (BUILD is the travis
+  build number):
+
+```
+cd docs/graph
+
+BUILD=983
+
+for x in $(seq 1 90); do echo ${BUILD}/${x}; mkdir -p logs/${BUILD}; while ! travis logs ${BUILD}.${x} > logs/${BUILD}/${x}; do true; done; done
+```
+
+* Run the [StackOverflow tags query](https://data.stackexchange.com/stackoverflow/query/edit/1013465) and update the CSV link:
+
+```
+export SO_TAG_CSV_URL=... # from the query page
+```
+
+```
+
+* Download GitHub and StackOverflow data and generate the final
+  combined data set:
+
+```
+PATH=$PATH:~/personal/programming/loccount
+
+time VERBOSE=1 node ./collect_data.js logs/${BUILD}/ all_data.json
+```
index 9126bc9..d1c587b 100644 (file)
@@ -8,12 +8,18 @@
     "perf1": 9,
     "perf2": 28,
     "perf3": 1089,
-    "star_count": null,
-    "rank": 68,
+    "pull_count": 221,
+    "pull_rank": 58,
+    "push_count": 18891,
+    "push_rank": 54,
+    "star_count": 213,
+    "star_rank": 60,
     "sloc": 5942,
     "files": 29,
     "author_name": "Chris Moore",
     "author_url": "https://github.com/zmower",
+    "so_count": 1620,
+    "so_rank": 50,
     "lloc": 3759
   },
   "awk": {
     "perf1": 14,
     "perf2": 47,
     "perf3": 702,
-    "star_count": 355,
-    "rank": 50,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": 4052,
+    "push_rank": 60,
+    "star_count": 5775,
+    "star_rank": 49,
     "sloc": 5213,
     "files": 17,
     "author_name": "Miutsuru Kariya",
     "author_url": "https://github.com/kariya-mitsuru",
+    "so_count": 23834,
+    "so_rank": 23,
     "lloc": 0
   },
   "bash": {
     "perf1": 1681,
     "perf2": 7748,
     "perf3": 5,
-    "star_count": 59906,
-    "rank": 14,
+    "pull_count": 492673,
+    "pull_rank": 12,
+    "push_count": 4076842,
+    "push_rank": 10,
+    "star_count": 1314476,
+    "star_rank": 14,
     "sloc": 2392,
     "files": 18,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 109843,
+    "so_rank": 14,
     "lloc": 0
   },
   "basic": {
     "perf1": 11,
     "perf2": 49,
     "perf3": 871,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 3963,
     "files": 23,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 673,
+    "so_rank": 54,
     "lloc": 3956
   },
   "c": {
     "syntax": "C",
     "type_check": "Static",
     "modes": [],
-    "perf1": 0.9,
+    "perf1": 0,
     "perf2": 2,
     "perf3": 17211,
-    "star_count": 90804,
-    "rank": 9,
+    "pull_count": 827476,
+    "pull_rank": 9,
+    "push_count": 5526508,
+    "push_rank": 8,
+    "star_count": 2273480,
+    "star_rank": 10,
     "sloc": 3701,
     "files": 26,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 299022,
+    "so_rank": 7,
     "lloc": 2012
   },
   "cpp": {
     "syntax": "C",
     "type_check": "Static",
     "modes": [],
-    "perf1": 0.9,
+    "perf1": 0,
     "perf2": 1,
     "perf3": 16045,
-    "star_count": 139366,
-    "rank": 6,
+    "pull_count": 1356841,
+    "pull_rank": 7,
+    "push_count": 8102807,
+    "push_rank": 6,
+    "star_count": 2690455,
+    "star_rank": 9,
     "sloc": 3532,
     "files": 29,
     "author_name": "Stephen Thirlwall",
     "author_url": "https://github.com/sdt",
+    "so_count": 666534,
+    "so_rank": 6,
     "lloc": 1617
   },
   "cs": {
     "perf1": 9,
     "perf2": 10,
     "perf3": 14958,
-    "star_count": 76670,
-    "rank": 10,
+    "pull_count": 756538,
+    "pull_rank": 10,
+    "push_count": 4833303,
+    "push_rank": 9,
+    "star_count": 1311416,
+    "star_rank": 15,
     "sloc": 3396,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 1325942,
+    "so_rank": 4,
     "lloc": 1760
   },
   "chuck": {
     "perf1": 35,
     "perf2": 113,
     "perf3": 132,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 4962,
     "files": 98,
     "author_name": "Vasilij Schneidermann",
     "author_url": "https://github.com/wasamasa",
+    "so_count": 19,
+    "so_rank": 71,
     "lloc": 1796
   },
   "clojure": {
     "perf1": 25,
     "perf2": 66,
     "perf3": 2373,
-    "star_count": 5502,
-    "rank": 27,
+    "pull_count": 88279,
+    "pull_rank": 23,
+    "push_count": 482086,
+    "push_rank": 23,
+    "star_count": 228280,
+    "star_rank": 22,
     "sloc": 1207,
     "files": 23,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 15387,
+    "so_rank": 29,
     "lloc": 0
   },
   "coffee": {
     "perf1": 7,
     "perf2": 33,
     "perf3": 18111,
-    "star_count": 8569,
-    "rank": 22,
+    "pull_count": 179032,
+    "pull_rank": 19,
+    "push_count": 686417,
+    "push_rank": 20,
+    "star_count": 512339,
+    "star_rank": 17,
     "sloc": 1073,
     "files": 21,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 9675,
+    "so_rank": 35,
     "lloc": 0
   },
   "common-lisp": {
     "perf1": 1,
     "perf2": 2,
     "perf3": 14665,
-    "star_count": 1146,
-    "rank": 38,
+    "pull_count": 7509,
+    "pull_rank": 45,
+    "push_count": 89833,
+    "push_rank": 40,
+    "star_count": 31757,
+    "star_rank": 36,
     "sloc": 2607,
     "files": 22,
     "author_name": "Iqbal Ansari",
     "author_url": "https://github.com/iqbalansari",
+    "so_count": 4719,
+    "so_rank": 43,
     "lloc": 0
   },
   "crystal": {
     "perf1": 1,
     "perf2": 2,
     "perf3": 28255,
-    "star_count": 938,
-    "rank": 41,
+    "pull_count": 7228,
+    "pull_rank": 47,
+    "push_count": 25868,
+    "push_rank": 51,
+    "star_count": 19192,
+    "star_rank": 44,
     "sloc": 2157,
     "files": 18,
     "author_name": "Linda_pp",
     "author_url": "https://github.com/rhysd",
+    "so_count": 456,
+    "so_rank": 56,
     "lloc": 0
   },
   "d": {
     "syntax": "C",
     "type_check": "Static",
     "modes": [],
-    "perf1": 0.9,
+    "perf1": 0,
     "perf2": 2,
     "perf3": 15621,
-    "star_count": 653,
-    "rank": 45,
+    "pull_count": 7432,
+    "pull_rank": 46,
+    "push_count": 67755,
+    "push_rank": 44,
+    "star_count": 15362,
+    "star_rank": 45,
     "sloc": 2979,
     "files": 18,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 2453,
+    "so_rank": 49,
     "lloc": 1434
   },
   "dart": {
     "perf1": 14,
     "perf2": 38,
     "perf3": 509,
-    "star_count": 2498,
-    "rank": 34,
+    "pull_count": 36851,
+    "pull_rank": 34,
+    "push_count": 132610,
+    "push_rank": 35,
+    "star_count": 31684,
+    "star_rank": 37,
     "sloc": 2279,
     "files": 18,
     "author_name": "Harry Terkelsen",
     "author_url": "https://github.com/hterkelsen",
+    "so_count": 14514,
+    "so_rank": 32,
     "lloc": 1142
   },
   "elixir": {
     "perf1": 14,
     "perf2": 52,
     "perf3": 765,
-    "star_count": 6115,
-    "rank": 24,
+    "pull_count": 57336,
+    "pull_rank": 27,
+    "push_count": 168462,
+    "push_rank": 34,
+    "star_count": 133408,
+    "star_rank": 24,
     "sloc": 1824,
     "files": 20,
     "author_name": "Martin Ek",
     "author_url": "https://github.com/ekmartin",
+    "so_count": 6737,
+    "so_rank": 38,
     "lloc": 0
   },
   "elm": {
     "perf1": 69,
     "perf2": 167,
     "perf3": 801,
-    "star_count": 809,
-    "rank": 43,
+    "pull_count": 10763,
+    "pull_rank": 41,
+    "push_count": 51061,
+    "push_rank": 46,
+    "star_count": 29708,
+    "star_rank": 40,
     "sloc": 5775,
     "files": 24,
     "author_name": "Jos van Bakel",
     "author_url": "https://github.com/c0deaddict",
+    "so_count": 1469,
+    "so_rank": 51,
     "lloc": 0
   },
   "elisp": {
     "perf1": 16,
     "perf2": 77,
     "perf3": 593,
-    "star_count": 5689,
-    "rank": 26,
+    "pull_count": 45932,
+    "pull_rank": 32,
+    "push_count": 288975,
+    "push_rank": 26,
+    "star_count": 111705,
+    "star_rank": 27,
     "sloc": 1982,
     "files": 20,
     "author_name": "Vasilij Schneidermann",
     "author_url": "https://github.com/wasamasa",
+    "so_count": 3661,
+    "so_rank": 46,
     "lloc": 0
   },
   "erlang": {
     "perf1": 53,
     "perf2": 175,
     "perf3": 175,
-    "star_count": 2942,
-    "rank": 31,
+    "pull_count": 62128,
+    "pull_rank": 25,
+    "push_count": 242256,
+    "push_rank": 29,
+    "star_count": 114897,
+    "star_rank": 26,
     "sloc": 2215,
     "files": 18,
     "author_name": "Nathan Fiedler",
     "author_url": "https://github.com/nlfiedler",
+    "so_count": 8426,
+    "so_rank": 37,
     "lloc": 0
   },
   "es6": {
     "perf1": 3,
     "perf2": 21,
     "perf3": 12079,
-    "star_count": 668062,
-    "rank": 2,
+    "pull_count": 5493469,
+    "pull_rank": 2,
+    "push_count": 22904060,
+    "push_rank": 2,
+    "star_count": 17647699,
+    "star_rank": 2,
     "sloc": 1230,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 153997,
+    "so_rank": 12,
     "lloc": 0
   },
   "fsharp": {
     "perf1": 35,
     "perf2": 29,
     "perf3": 20634,
-    "star_count": 950,
-    "rank": 39,
+    "pull_count": 25939,
+    "pull_rank": 36,
+    "push_count": 125060,
+    "push_rank": 36,
+    "star_count": 29958,
+    "star_rank": 39,
     "sloc": 3033,
     "files": 22,
     "author_name": "Peter Stephens",
     "author_url": "https://github.com/pstephens",
+    "so_count": 14506,
+    "so_rank": 33,
     "lloc": 404
   },
   "factor": {
     "perf1": 2,
     "perf2": 1,
     "perf3": 27766,
-    "star_count": null,
-    "rank": 68,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": 11230,
+    "push_rank": 57,
+    "star_count": 100,
+    "star_rank": 62,
     "sloc": 1305,
     "files": 33,
     "author_name": "Jordan Lewis",
     "author_url": "https://github.com/jordanlewis",
+    "so_count": 61,
+    "so_rank": 66,
     "lloc": 0
   },
   "fantom": {
     "perf1": 14,
     "perf2": 31,
     "perf3": 40400,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 1768,
     "files": 31,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 54,
+    "so_rank": 67,
     "lloc": 0
   },
   "forth": {
     "perf1": 4,
     "perf2": 14,
     "perf3": 2448,
-    "star_count": null,
-    "rank": 68,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": 7173,
+    "push_rank": 59,
+    "star_count": 106,
+    "star_rank": 61,
     "sloc": 3351,
     "files": 21,
     "author_name": "Chris Houser",
     "author_url": "https://github.com/chouser",
+    "so_count": 210,
+    "so_rank": 60,
     "lloc": 0
   },
   "guile": {
     "perf1": 3,
     "perf2": 9,
     "perf3": 3962,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 1547,
     "files": 20,
     "author_name": "Mu Lei",
     "author_url": "https://github.com/NalaGinrut",
+    "so_count": 186,
+    "so_rank": 61,
     "lloc": 0
   },
   "gnu-smalltalk": {
     "perf1": 14,
     "perf2": 45,
     "perf3": 787,
-    "star_count": 152,
-    "rank": 55,
+    "pull_count": 9786,
+    "pull_rank": 42,
+    "push_count": 39964,
+    "push_rank": 47,
+    "star_count": 1697,
+    "star_rank": 56,
     "sloc": 2444,
     "files": 21,
     "author_name": "Vasilij Schneidermann",
     "author_url": "https://github.com/wasamasa",
+    "so_count": 86,
+    "so_rank": 63,
     "lloc": 0
   },
   "go": {
     "perf1": 1,
     "perf2": 3,
     "perf3": 10334,
-    "star_count": 215511,
-    "rank": 5,
+    "pull_count": 1211699,
+    "pull_rank": 8,
+    "push_count": 3354592,
+    "push_rank": 11,
+    "star_count": 3635813,
+    "star_rank": 5,
     "sloc": 3451,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 36753,
+    "so_rank": 22,
     "lloc": 1792
   },
   "groovy": {
     "perf1": 477,
     "perf2": 746,
     "perf3": 324,
-    "star_count": 4302,
-    "rank": 29,
+    "pull_count": 78505,
+    "pull_rank": 24,
+    "push_count": 330188,
+    "push_rank": 25,
+    "star_count": 99463,
+    "star_rank": 29,
     "sloc": 1598,
     "files": 19,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 22656,
+    "so_rank": 24,
     "lloc": 0
   },
   "haskell": {
     "perf1": 3,
     "perf2": 8,
     "perf3": 4338,
-    "star_count": 6312,
-    "rank": 23,
+    "pull_count": 105004,
+    "pull_rank": 21,
+    "push_count": 772035,
+    "push_rank": 18,
+    "star_count": 244427,
+    "star_rank": 20,
     "sloc": 2011,
     "files": 18,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 40268,
+    "so_rank": 21,
     "lloc": 0
   },
   "haxe": {
     "perf1": 5,
     "perf2": 26,
     "perf3": 15377,
-    "star_count": 580,
-    "rank": 46,
+    "pull_count": 12391,
+    "pull_rank": 40,
+    "push_count": 68980,
+    "push_rank": 43,
+    "star_count": 24119,
+    "star_rank": 41,
     "sloc": 2270,
     "files": 23,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 1400,
+    "so_rank": 52,
     "lloc": 1045
   },
   "hy": {
     "perf1": 17,
     "perf2": 67,
     "perf3": 585,
-    "star_count": null,
-    "rank": 68,
+    "pull_count": 108,
+    "pull_rank": 59,
+    "push_count": 1442,
+    "push_rank": 62,
+    "star_count": 308,
+    "star_rank": 59,
     "sloc": 1215,
     "files": 18,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 29,
+    "so_rank": 70,
     "lloc": 0
   },
   "io": {
     "perf1": 357,
     "perf2": 1333,
     "perf3": 29,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": 224,
+    "push_rank": 64,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 1262,
     "files": 18,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 14548,
+    "so_rank": 31,
     "lloc": 0
   },
   "java": {
     "perf1": 7,
     "perf2": 24,
     "perf3": 57275,
-    "star_count": 255160,
-    "rank": 4,
+    "pull_count": 2390505,
+    "pull_rank": 4,
+    "push_count": 12425871,
+    "push_rank": 4,
+    "star_count": 6191792,
+    "star_rank": 4,
     "sloc": 3061,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 1527471,
+    "so_rank": 2,
     "lloc": 1537
   },
   "js": {
     "perf1": 3,
     "perf2": 22,
     "perf3": 14550,
-    "star_count": 668062,
-    "rank": 1,
-    "sloc": 2779,
-    "files": 33,
+    "pull_count": 5493469,
+    "pull_rank": 1,
+    "push_count": 22904060,
+    "push_rank": 1,
+    "star_count": 17647699,
+    "star_rank": 1,
+    "sloc": 1986,
+    "files": 26,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 3154942,
+    "so_rank": 1,
     "lloc": 0
   },
   "julia": {
     "perf1": 253,
     "perf2": 32,
     "perf3": 2975,
-    "star_count": 948,
-    "rank": 40,
+    "pull_count": 46318,
+    "pull_rank": 31,
+    "push_count": 201339,
+    "push_rank": 33,
+    "star_count": 37036,
+    "star_rank": 35,
     "sloc": 1413,
     "files": 19,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 5134,
+    "so_rank": 42,
     "lloc": 0
   },
   "kotlin": {
     "perf1": 19,
     "perf2": 75,
     "perf3": 33381,
-    "star_count": 20958,
-    "rank": 17,
+    "pull_count": 55156,
+    "pull_rank": 29,
+    "push_count": 229722,
+    "push_rank": 30,
+    "star_count": 167915,
+    "star_rank": 23,
     "sloc": 1571,
     "files": 19,
     "author_name": "Javier Fernandez-Ivern",
     "author_url": "https://github.com/ivern",
+    "so_count": 20934,
+    "so_rank": 25,
     "lloc": 0
   },
   "livescript": {
     "perf1": 6,
     "perf2": 26,
     "perf3": 7570,
-    "star_count": 116,
-    "rank": 57,
+    "pull_count": 238,
+    "pull_rank": 57,
+    "push_count": 14525,
+    "push_rank": 56,
+    "star_count": 8475,
+    "star_rank": 48,
     "sloc": 2128,
     "files": 19,
     "author_name": "Jos van Bakel",
     "author_url": "https://github.com/c0deaddict",
+    "so_count": 66,
+    "so_rank": 64,
     "lloc": 0
   },
   "logo": {
     "modes": [],
     "perf1": 19182,
     "perf2": 53948,
-    "perf3": 0.01,
+    "perf3": 0,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 2139,
     "files": 20,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 43,
+    "so_rank": 68,
     "lloc": 0
   },
   "lua": {
     "perf1": 10,
     "perf2": 44,
     "perf3": 955,
-    "star_count": 8769,
-    "rank": 21,
+    "pull_count": 98464,
+    "pull_rank": 22,
+    "push_count": 597735,
+    "push_rank": 22,
+    "star_count": 241491,
+    "star_rank": 21,
     "sloc": 1909,
     "files": 21,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 15214,
+    "so_rank": 30,
     "lloc": 0
   },
   "make": {
     "perf1": 5050,
     "perf2": 31077,
     "perf3": 1,
-    "star_count": 2034,
-    "rank": 35,
+    "pull_count": 60803,
+    "pull_rank": 26,
+    "push_count": 251529,
+    "push_rank": 27,
+    "star_count": 57750,
+    "star_rank": 32,
     "sloc": 1821,
     "files": 22,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 18769,
+    "so_rank": 27,
     "lloc": 0
   },
   "mal": {
     "perf1": 277,
     "perf2": 1346,
     "perf3": 40,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 890,
     "files": 13,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 0,
+    "so_rank": 73,
     "lloc": 0
   },
   "matlab": {
     "perf1": 1709,
     "perf2": 6295,
     "perf3": 5,
-    "star_count": 2867,
-    "rank": 32,
+    "pull_count": 20935,
+    "pull_rank": 37,
+    "push_count": 264,
+    "push_rank": 63,
+    "star_count": 46295,
+    "star_rank": 34,
     "sloc": 2204,
     "files": 27,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 82801,
+    "so_rank": 16,
     "lloc": 0
   },
   "miniMAL": {
     "perf1": 1340,
     "perf2": 5383,
     "perf3": 7,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 1691,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 0,
+    "so_rank": 74,
     "lloc": 0
   },
   "nasm": {
     "syntax": "OTHER",
     "type_check": "OTHER",
     "modes": [],
-    "perf1": 0.9,
+    "perf1": 0,
     "perf2": 2,
     "perf3": 24147,
-    "star_count": 1195,
-    "rank": 37,
+    "pull_count": 9679,
+    "pull_rank": 43,
+    "push_count": 91017,
+    "push_rank": 39,
+    "star_count": 31339,
+    "star_rank": 38,
     "sloc": 14483,
     "files": 19,
     "author_name": "Ben Dudson",
     "author_url": "https://github.com/bendudson",
+    "so_count": 3420,
+    "so_rank": 47,
     "lloc": 0
   },
   "nim": {
     "perf1": 1,
     "perf2": 2,
     "perf3": 30900,
-    "star_count": 529,
-    "rank": 48,
+    "pull_count": 1674,
+    "pull_rank": 54,
+    "push_count": 7741,
+    "push_rank": 58,
+    "star_count": 4783,
+    "star_rank": 52,
     "sloc": 1423,
     "files": 17,
     "author_name": "Dennis Felsing",
     "author_url": "https://github.com/def-",
+    "so_count": 289,
+    "so_rank": 58,
     "lloc": 0
   },
   "objpascal": {
     "perf1": 4,
     "perf2": 12,
     "perf3": 2830,
-    "star_count": 1324,
-    "rank": 36,
+    "pull_count": 5360,
+    "pull_rank": 48,
+    "push_count": 72591,
+    "push_rank": 42,
+    "star_count": 20971,
+    "star_rank": 43,
     "sloc": 6179,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 57574,
+    "so_rank": 20,
     "lloc": 3971
   },
   "objc": {
     "perf1": 6,
     "perf2": 28,
     "perf3": 1599,
-    "star_count": 48248,
-    "rank": 16,
+    "pull_count": 263283,
+    "pull_rank": 14,
+    "push_count": 1310542,
+    "push_rank": 13,
+    "star_count": 3020863,
+    "star_rank": 6,
     "sloc": 2363,
     "files": 26,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 287020,
+    "so_rank": 8,
     "lloc": 1059
   },
   "ocaml": {
     "perf1": 1,
     "perf2": 2,
     "perf3": 23267,
-    "star_count": 3646,
-    "rank": 30,
+    "pull_count": 56046,
+    "pull_rank": 28,
+    "push_count": 227050,
+    "push_rank": 31,
+    "star_count": 87278,
+    "star_rank": 31,
     "sloc": 1269,
     "files": 17,
     "author_name": "Chris Houser",
     "author_url": "https://github.com/chouser",
+    "so_count": 5633,
+    "so_rank": 41,
     "lloc": 0
   },
   "perl": {
     "perf1": 13,
     "perf2": 50,
     "perf3": 790,
-    "star_count": 4679,
-    "rank": 28,
+    "pull_count": 115736,
+    "pull_rank": 20,
+    "push_count": 628215,
+    "push_rank": 21,
+    "star_count": 119328,
+    "star_rank": 25,
     "sloc": 2265,
     "files": 22,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 61960,
+    "so_rank": 19,
     "lloc": 1107
   },
   "perl6": {
     "perf1": 441,
     "perf2": 1182,
     "perf3": 23,
-    "star_count": 137,
-    "rank": 56,
+    "pull_count": 2624,
+    "pull_rank": 52,
+    "push_count": 14541,
+    "push_rank": 55,
+    "star_count": 846,
+    "star_rank": 58,
     "sloc": 1238,
     "files": 18,
     "author_name": "Hinrik Örn Sigurðsson",
     "author_url": "https://github.com/hinrik",
+    "so_count": 1018,
+    "so_rank": 53,
     "lloc": 484
   },
   "php": {
     "perf1": 8,
     "perf2": 28,
     "perf3": 1268,
-    "star_count": 135579,
-    "rank": 7,
+    "pull_count": 1895495,
+    "pull_rank": 6,
+    "push_count": 9066974,
+    "push_rank": 5,
+    "star_count": 2789804,
+    "star_rank": 8,
     "sloc": 1998,
     "files": 21,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 1270824,
+    "so_rank": 5,
     "lloc": 1074
   },
   "picolisp": {
     "perf1": 2,
     "perf2": 7,
     "perf3": 6005,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 1366,
     "files": 20,
     "author_name": "Vasilij Schneidermann",
     "author_url": "https://github.com/wasamasa",
+    "so_count": 5,
+    "so_rank": 72,
     "lloc": 0
   },
   "plpgsql": {
     "perf1": 478,
     "perf2": 3830,
     "perf3": 20,
-    "star_count": 897,
-    "rank": 42,
+    "pull_count": 16628,
+    "pull_rank": 38,
+    "push_count": 85763,
+    "push_rank": 41,
+    "star_count": 14707,
+    "star_rank": 46,
     "sloc": 3679,
     "files": 21,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 2788,
+    "so_rank": 48,
     "lloc": 0
   },
   "plsql": {
     "syntax": "Algol",
     "type_check": "Static",
     "modes": [],
-    "perf1": 19182,
-    "perf2": 1921,
-    "perf3": 0.01,
-    "star_count": 199,
-    "rank": 53,
+    "perf1": null,
+    "perf2": null,
+    "perf3": 0,
+    "pull_count": 9421,
+    "pull_rank": 44,
+    "push_count": 31400,
+    "push_rank": 48,
+    "star_count": 3983,
+    "star_rank": 54,
     "sloc": 4180,
     "files": 21,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 20149,
+    "so_rank": 26,
     "lloc": 0
   },
   "powershell": {
     "perf1": 1921,
     "perf2": 7832,
     "perf3": 5,
-    "star_count": 5795,
-    "rank": 25,
+    "pull_count": 52513,
+    "pull_rank": 30,
+    "push_count": 217208,
+    "push_rank": 32,
+    "star_count": 90595,
+    "star_rank": 30,
     "sloc": 1147,
     "files": 12,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 66407,
+    "so_rank": 18,
     "lloc": 0
   },
   "ps": {
     "perf1": 38,
     "perf2": 274,
     "perf3": 198,
-    "star_count": null,
-    "rank": 68,
+    "pull_count": 1644,
+    "pull_rank": 55,
+    "push_count": 19145,
+    "push_rank": 53,
+    "star_count": 1034,
+    "star_rank": 57,
     "sloc": 2482,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 458,
+    "so_rank": 55,
     "lloc": 0
   },
   "python": {
     "perf1": 7,
     "perf2": 29,
     "perf3": 1371,
-    "star_count": 336045,
-    "rank": 3,
+    "pull_count": 3673660,
+    "pull_rank": 3,
+    "push_count": 15034581,
+    "push_rank": 3,
+    "star_count": 6487808,
+    "star_rank": 3,
     "sloc": 1358,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 1374530,
+    "so_rank": 3,
     "lloc": 1344
   },
   "rpython": {
     "syntax": "Python",
     "type_check": "Static",
     "modes": [],
-    "perf1": 0.9,
+    "perf1": 0,
     "perf2": 1,
     "perf3": 69848,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 2102,
     "files": 19,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 64,
+    "so_rank": 65,
     "lloc": 2096
   },
   "r": {
     "perf1": 78,
     "perf2": 295,
     "perf3": 117,
-    "star_count": 2644,
-    "rank": 33,
+    "pull_count": 40953,
+    "pull_rank": 33,
+    "push_count": 455945,
+    "push_rank": 24,
+    "star_count": 55128,
+    "star_rank": 33,
     "sloc": 1625,
     "files": 19,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 281400,
+    "so_rank": 9,
     "lloc": 0
   },
   "racket": {
     "perf1": 2,
     "perf2": 7,
     "perf3": 4865,
-    "star_count": 281,
-    "rank": 51,
+    "pull_count": 3167,
+    "pull_rank": 51,
+    "push_count": 28005,
+    "push_rank": 50,
+    "star_count": 5573,
+    "star_rank": 50,
     "sloc": 1193,
     "files": 18,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 4344,
+    "so_rank": 45,
     "lloc": 0
   },
   "rexx": {
     "perf1": 160,
     "perf2": 660,
     "perf3": 61,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 2747,
     "files": 19,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 125,
+    "so_rank": 62,
     "lloc": 0
   },
   "ruby": {
     "perf1": 2,
     "perf2": 8,
     "perf3": 4163,
-    "star_count": 54043,
-    "rank": 15,
+    "pull_count": 2079423,
+    "pull_rank": 5,
+    "push_count": 5952146,
+    "push_rank": 7,
+    "star_count": 2821992,
+    "star_rank": 7,
     "sloc": 1291,
     "files": 20,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 203216,
+    "so_rank": 11,
     "lloc": 0
   },
   "rust": {
     "syntax": "C",
     "type_check": "Static",
     "modes": [],
-    "perf1": 0.9,
+    "perf1": 0,
     "perf2": 1,
     "perf3": 16720,
-    "star_count": 19178,
-    "rank": 18,
+    "pull_count": 197385,
+    "pull_rank": 18,
+    "push_count": 710977,
+    "push_rank": 19,
+    "star_count": 396731,
+    "star_rank": 19,
     "sloc": 2862,
     "files": 18,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 11560,
+    "so_rank": 34,
     "lloc": 714
   },
   "scala": {
     "perf1": 27,
     "perf2": 66,
     "perf3": 25785,
-    "star_count": 13634,
-    "rank": 19,
+    "pull_count": 316175,
+    "pull_rank": 13,
+    "push_count": 1104784,
+    "push_rank": 14,
+    "star_count": 419380,
+    "star_rank": 18,
     "sloc": 1849,
     "files": 18,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 87665,
+    "so_rank": 15,
     "lloc": 0
   },
   "scheme": {
     "perf1": 6,
     "perf2": 19,
     "perf3": 2231,
-    "star_count": 718,
-    "rank": 44,
+    "pull_count": 3528,
+    "pull_rank": 49,
+    "push_count": 63905,
+    "push_rank": 45,
+    "star_count": 21437,
+    "star_rank": 42,
     "sloc": 1269,
     "files": 13,
     "author_name": "Vasilij Schneidermann",
     "author_url": "https://github.com/wasamasa",
+    "so_count": 6678,
+    "so_rank": 39,
     "lloc": 0
   },
   "skew": {
     "perf1": 6,
     "perf2": 11,
     "perf3": 3608,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 1638,
     "files": 19,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 263,
+    "so_rank": 59,
     "lloc": 0
   },
   "swift": {
     "perf1": 2,
     "perf2": 6,
     "perf3": 5322,
-    "star_count": 66012,
-    "rank": 11,
+    "pull_count": 231080,
+    "pull_rank": 15,
+    "push_count": 931308,
+    "push_rank": 15,
+    "star_count": 1992397,
+    "star_rank": 11,
     "sloc": 2963,
     "files": 14,
     "author_name": "Keith Rollin",
     "author_url": "https://github.com/keith-rollin",
+    "so_count": 8527,
+    "so_rank": 36,
     "lloc": 0
   },
   "swift3": {
     "perf1": 8,
     "perf2": 27,
     "perf3": 1234,
-    "star_count": 66012,
-    "rank": 12,
+    "pull_count": 231080,
+    "pull_rank": 16,
+    "push_count": 931308,
+    "push_rank": 16,
+    "star_count": 1992397,
+    "star_rank": 12,
     "sloc": 2362,
     "files": 17,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 18339,
+    "so_rank": 28,
     "lloc": 0
   },
   "swift4": {
     "perf1": 5,
     "perf2": 16,
     "perf3": 2065,
-    "star_count": 66012,
-    "rank": 13,
+    "pull_count": 231080,
+    "pull_rank": 17,
+    "push_count": 931308,
+    "push_rank": 17,
+    "star_count": 1992397,
+    "star_rank": 13,
     "sloc": 1767,
     "files": 17,
     "author_name": "陆遥",
     "author_url": "https://github.com/LispLY",
+    "so_count": 230173,
+    "so_rank": 10,
     "lloc": 0
   },
   "tcl": {
     "perf1": 24,
     "perf2": 103,
     "perf3": 373,
-    "star_count": 171,
-    "rank": 54,
+    "pull_count": 3399,
+    "pull_rank": 50,
+    "push_count": 28306,
+    "push_rank": 49,
+    "star_count": 3111,
+    "star_rank": 55,
     "sloc": 2468,
     "files": 20,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 6056,
+    "so_rank": 40,
     "lloc": 0
   },
   "ts": {
     "perf1": 4,
     "perf2": 14,
     "perf3": 26534,
-    "star_count": 93555,
-    "rank": 8,
+    "pull_count": 564665,
+    "pull_rank": 11,
+    "push_count": 1514203,
+    "push_rank": 12,
+    "star_count": 982634,
+    "star_rank": 16,
     "sloc": 2836,
     "files": 20,
     "author_name": "Masahiro Wakame",
     "author_url": "https://github.com/vvakame",
+    "so_count": 78405,
+    "so_rank": 17,
     "lloc": 0
   },
   "vhdl": {
     "perf1": 3,
     "perf2": 9,
     "perf3": 3342,
-    "star_count": 217,
-    "rank": 52,
+    "pull_count": 240,
+    "pull_rank": 56,
+    "push_count": 20559,
+    "push_rank": 52,
+    "star_count": 4913,
+    "star_rank": 51,
     "sloc": 4258,
     "files": 19,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 4585,
+    "so_rank": 44,
     "lloc": 0
   },
   "vimscript": {
     "perf1": 219,
     "perf2": 1055,
     "perf3": 43,
-    "star_count": 10096,
-    "rank": 20,
+    "pull_count": 15114,
+    "pull_rank": 39,
+    "push_count": 123978,
+    "push_rank": 37,
+    "star_count": 99613,
+    "star_rank": 28,
     "sloc": 2147,
     "files": 22,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 41,
+    "so_rank": 69,
     "lloc": 12
   },
   "vb": {
     "perf1": 14,
     "perf2": 14,
     "perf3": 10121,
-    "star_count": 578,
-    "rank": 47,
+    "pull_count": 30231,
+    "pull_rank": 35,
+    "push_count": 110855,
+    "push_rank": 38,
+    "star_count": 11085,
+    "star_rank": 47,
     "sloc": 3839,
     "files": 19,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 123078,
+    "so_rank": 13,
     "lloc": 394
   },
   "wasm": {
     "perf1": 2,
     "perf2": 10,
     "perf3": 3742,
-    "star_count": 365,
-    "rank": 49,
+    "pull_count": 2242,
+    "pull_rank": 53,
+    "push_count": 3102,
+    "push_rank": 61,
+    "star_count": 4456,
+    "star_rank": 53,
     "sloc": 5270,
     "files": 26,
     "author_name": "Joel Martin",
     "author_url": "https://github.com/kanaka",
+    "so_count": 454,
+    "so_rank": 57,
     "lloc": 0
   },
   "yorick": {
     "perf1": 67,
     "perf2": 288,
     "perf3": 147,
+    "pull_count": null,
+    "pull_rank": null,
+    "push_count": null,
+    "push_rank": null,
     "star_count": null,
-    "rank": 68,
+    "star_rank": null,
     "sloc": 2398,
     "files": 19,
     "author_name": "Dov Murik",
     "author_url": "https://github.com/dubek",
+    "so_count": 0,
+    "so_rank": 75,
     "lloc": 210
   }
 }
\ No newline at end of file
index acc6f86..ef59bfb 100755 (executable)
@@ -6,18 +6,26 @@ const writeFile = promisify(require('fs').writeFile)
 const readdir = promisify(require('fs').readdir)
 const path = require('path')
 const yaml = require('js-yaml')
+const csv = require('csvtojson')
 const request = require('request-promise-native')
 const exec = promisify(require('child_process').exec)
 
 const VERBOSE = process.env['VERBOSE'] || false
 const BASE_PATH = process.env['BASE_PATH'] || 'base_data.yaml'
 const README_PATH = process.env['README_PATH'] || '../../README.md'
-// GitHut Pushes
-//const GITHUT_URL = 'https://raw.githubusercontent.com/madnight/githut/gh-pages/gh-push-event_eb2696.json'
-// GitHut Stars
-const GITHUT_URL = process.env['GITHUT_URL'] || 'https://raw.githubusercontent.com/madnight/githut/gh-pages/gh-star-event_e61175.json'
 const MAL_PATH = process.env['MAL_PATH'] || '../../'
 
+// GitHut 2.0 Pull Requests
+const GITHUT_PULL_URL = process.env['GITHUT_PULL_URL'] || 'https://raw.githubusercontent.com/madnight/githut/master/src/data/gh-pull-request.json'
+// GitHut 2.0 Pushes
+const GITHUT_PUSH_URL = process.env['GITHUT_PUSH_URL'] || 'https://raw.githubusercontent.com/madnight/githut/master/src/data/gh-push-event.json'
+// GitHut 2.0 Stars
+const GITHUT_STAR_URL = process.env['GITHUT_STAR_URL'] || 'https://raw.githubusercontent.com/madnight/githut/master/src/data/gh-star-event.json'
+
+// Refresh this link using this Query page:
+// https://data.stackexchange.com/stackoverflow/query/edit/1013465
+const SO_TAG_CSV_URL = process.env['SO_TAG_CSV_URL'] || 'https://data.stackexchange.com/stackoverflow/csv/1252107'
+
 
 const githutToNames = {
     'Awk':          ['GNU Awk'],
@@ -36,6 +44,28 @@ const githutToNames = {
     'Vim script':   ['Vimscript'],
     'Visual Basic': ['Visual Basic.NET'],
 }
+const dirToSOTags = {
+    'cpp':       ['c++', 'c++98', 'c++11', 'c++14', 'c++17'],
+    'coffee':    ['coffeescript'],
+    'crystal':   ['crystal-lang'],
+    'cs':        ['c#', 'c#-2.0', 'c#-3.0', 'c#-4.0'],
+    'es6':       ['ecmascript-6', 'es6-promise', 'es6-modules', 'es6-class', 'reactjs'],
+    'fsharp':    ['f#', 'f#-interactive', 'f#-data', 'f#-3.0'],
+    'factor':    ['factor-lang'],
+    'js':        ['javascript', 'node.js', 'jquery', 'angular'],
+    'logo':      ['logo-lang'],
+    'make':      ['makefile'],
+    'objpascal': ['delphi', 'freepascal', 'delphi-7', 'delphi-2007', 'delphi-2009', 'delphi-2010', 'delphi-xe', 'delphi-xe2', 'delphi-xe3', 'delphi-xe4', 'delphi-xe5', 'delphi-xe7'],
+    'objc':      ['objective-c'],
+    'python':    ['python', 'python-3.x', 'python-2.7'],
+    'swift':     ['swift2'],
+    'swift3':    ['swift3'],
+    'swift4':    ['swift', 'swift4'],
+    'ts':        ['typescript', 'typescript-generics', 'typescript2.0'],
+    'vimscript': ['viml'],
+    'vb':        ['vb.net'],
+    'wasm':      ['webassembly'],
+}
 
 function vlog(...args) {
     if (VERBOSE) {
@@ -56,8 +86,14 @@ async function main() {
     const baseYaml = yaml.safeLoad(await readFile(BASE_PATH, 'utf8'))
     vlog(`Loading README text from '${README_PATH}`)
     const readmeLines = (await readFile(README_PATH, 'utf8')).split(/\n/)
-    vlog(`Downloading GitHut HTML from '${GITHUT_URL}`)
-    const githutText = (await request(GITHUT_URL))
+    vlog(`Downloading GitHut Pulls HTML from '${GITHUT_PULL_URL}`)
+    const githutPullText = (await request(GITHUT_PULL_URL))
+    vlog(`Downloading GitHut Pushes HTML from '${GITHUT_PUSH_URL}`)
+    const githutPushText = (await request(GITHUT_PUSH_URL))
+    vlog(`Downloading GitHut Stars HTML from '${GITHUT_STAR_URL}`)
+    const githutStarText = (await request(GITHUT_STAR_URL))
+    vlog(`Downloading StackOverflow Tag CSV from '${SO_TAG_CSV_URL}`)
+    const soTagList = await csv().fromStream(request.get(SO_TAG_CSV_URL))
     vlog(`Loading log data from '${logsPath}'`)
     const logFiles = (await readdir(logsPath))
         .map(x => parseInt(x))
@@ -66,7 +102,7 @@ async function main() {
     for (const f of logFiles) {
         if (!(/^[0-9]+$/.exec(f))) { continue }
         const path = logsPath + "/" + f
-        logData.push([await readFile(path, 'utf8'), path])
+        logData.push([await readFile(path, 'utf8'), path, f])
     }
 
     let dirs = []
@@ -85,8 +121,12 @@ async function main() {
                     'perf1':       null,
                     'perf2':       null,
                     'perf3':       0,
+                    'pull_count':  null,
+                    'pull_rank':   null,
+                    'push_count':  null,
+                    'push_rank':   null,
                     'star_count':  null,
-                    'rank':        null,
+                    'star_rank':   null,
                     'sloc':        0,
                     'files':       0}
         dirs.push(d[0])
@@ -96,6 +136,7 @@ async function main() {
         dataByName[d[1]] = data
     }
 
+
     vlog(`Processing README implementations table`)
     const readme_re = /^\| \[([^\[]*)\].* \| \[([^|]*)\]\(([^|]*)\)  *\| *$/
     for (let row of readmeLines.filter(l => /^\| [\[]/.exec(l))) {
@@ -113,31 +154,80 @@ async function main() {
         }
     }
 
-    vlog(`Processing GitHut data`)
-    const gdata = githutText.split(/\n/)
-        .map(JSON.parse)
-        .filter(d => d.year === "2018" && d.quarter === '4')
-        .map(d => (d.count = parseInt(d.count), d))
-        .sort((a,b) => (a.count > b.count) ? -1 : a.count < b.count ? 1 : 0)
-    let curRank = 1
-    for (let gitem of gdata) {
-        const names = githutToNames[gitem.name] || [gitem.name]
-        for (let name of names) {
-            if (name in dataByName) {
-                dataByName[name].star_count = gitem.count
-                dataByName[name].rank = curRank
-                vlog(`  ${dataByName[name].dir} stars: ${gitem.count}, rank: ${curRank}`)
-                curRank += 1
+
+    function githutProcess(textData, kind) {
+        const gMap = textData.split(/\n/)
+            .map(JSON.parse)
+            .reduce((m, d) => (m[d.name] = parseInt(d.count) + (m[d.name] || 0), m), {})
+        const gdata = Object.entries(gMap)
+            .sort(([k1,v1],[k2,v2]) => v2 - v1)
+        let curRank = 1
+        for (let [gname, gcount] of gdata) {
+            const names = githutToNames[gname] || [gname]
+            for (let name of names) {
+                if (name in dataByName) {
+                    dataByName[name][kind + '_count'] = gcount
+                    dataByName[name][kind + '_rank'] = curRank
+                    vlog(`  ${dataByName[name].dir} count: ${gcount}, rank: ${curRank}`)
+                    curRank += 1
+                } else {
+                    vlog(`  ignoring GitHut language ${name}`)
+                }
+            }
+        }
+        return curRank;
+    }
+    vlog(`Processing GitHut Pull Request data`)
+    githutProcess(githutPullText, 'pull')
+    vlog(`Processing GitHut Push data`)
+    githutProcess(githutPushText, 'push')
+    vlog(`Processing GitHut Stars data`)
+    githutProcess(githutStarText, 'star')
+
+
+    vlog(`Processing StackOverflow tag data`)
+    const soMap = soTagList
+        //.map(d => ({tag: d.TagName, count: parseInt(d.Rate)}))
+        //.sort((a,b) => b.count - a.count)
+        .reduce((m,d) => (m[d.TagName] = parseInt(d.Rate), m), {})
+    soMap['mal'] = 0 // NOTE/TODO: StackOverflow mal is something else
+    for (let dir of dirs) {
+        if (!('so_count' in dataByDir[dir])) {
+            dataByDir[dir]['so_count'] = 0
+        }
+        let tags = dirToSOTags[dir]
+        if (!tags) {
+            if (dir in soMap) {
+                tags = [dir]
             } else {
-                vlog(`  ignoring GitHut language ${name}`)
+                vlog(`  ${dir} not found as StackOverflow tag`)
+                tags = []
             }
         }
+        for (let tag of tags) {
+            if (tag in soMap) {
+                dataByDir[dir]['so_count'] += soMap[tag]
+                //vlog(`  ${dir} count: ${count}`)
+            } else {
+                die(1, `${tag} not found in soMap`)
+            }
+        }
+    }
+    vlog()
+    let curRank = 1
+    let soSort = Object.values(dataByDir).sort((a,b) => b.so_count - a.so_count)
+    for (let data of soSort) {
+        data.so_rank = curRank
+        vlog(`  ${data.dir} so_count: ${data.so_count}, rank: ${curRank}`)
+        curRank += 1
     }
+    const maxSORank = curRank
+
 
     vlog(`Processing log file data`)
     const perf_run_re = /Running:.*\.\.\/tests\/(perf[0-9])\.mal/
     const perf_num_re = /Elapsed time: ([0-9.]+) msecs|iters over 10 seconds: ([0-9]+)/
-    for (let [log, file] of logData) {
+    for (let [log, file, idx] of logData) {
         const dir_match = (/export IMPL=(\S+)/i).exec(log)
         if (!dir_match) { die(1, `no IMPL found in ${file}`) }
         const dir = dir_match[1]
@@ -169,49 +259,23 @@ async function main() {
             data.perf3 = perfs.perf3
             vlog(`  ${dir}: ${perfs.perf1}, ${perfs.perf2}, ${perfs.perf3}`)
         } else {
-            vlog(`  ${dir}: ${perfs.perf1}, ${perfs.perf2}, ${perfs.perf3} (perf3 is worse, ignoring ${file})`)
+            vlog(`  ${dir}: ${perfs.perf1}, ${perfs.perf2}, ${perfs.perf3} (perf3 is worse, ignoring log ${idx})`)
         }
     }
 
+
     vlog(`Gathering LOC stats`)
     const stat_re = /SLOC=([0-9]+).*LLOC=([0-9]+).*in ([0-9]+) files/
     process.chdir(MAL_PATH)
     for (let data of dataList) {
-        vlog(`  gathering stats information for ${data.dir}`)
         const { stdout, stderr } = await exec(`make "stats^${data.dir}"`)
         const match = stat_re.exec(stdout.split(/\n/)[1])
         data.sloc = parseInt(match[1], 10)
         data.lloc = parseInt(match[2], 10)
         data.files = parseInt(match[3], 10)
+        vlog(`  ${data.dir}: sloc: ${data.sloc}, lloc: ${data.lloc}, files: ${data.files}`)
     }
 
-    vlog(`Filling in missing attributes`)
-    // leave a gap between actual ranked implementations and those
-    // with no rankings
-    maxRank = curRank + 10
-    maxPerf1 = dataList.reduce((a, d) => d.perf1 > a ? d.perf1 : a, 0)
-    maxPerf2 = dataList.reduce((a, d) => d.perf2 > a ? d.perf1 : a, 0)
-    for (let d of dataList) {
-        if (d.rank === null) {
-            vlog(`  setting rank to ${maxRank} for ${d.dir}`)
-            d.rank = maxRank
-        }
-        if (d.perf1 === null) {
-            vlog(`  setting perf1 to ${maxPerf1} for ${d.dir}`)
-            d.perf1 = maxPerf1
-        }
-        if (d.perf2 === null) {
-            vlog(`  setting perf2 to ${maxPerf2} for ${d.dir}`)
-            d.perf2 = maxPerf2
-        }
-    }
-
-    vlog(`Adjusting perf numbers to avoid 0`)
-    for (let d of dataList) {
-        if (d.perf1 === 0) { d.perf1 = 0.9 }
-        if (d.perf2 === 0) { d.perf2 = 0.9 }
-        if (d.perf3 === 0) { d.perf3 = 0.01 }
-    }
 
     vlog(`Writing full lanaguage data to ${outPath}`)
     await writeFile(outPath, JSON.stringify(dataByDir, null, 2))
index 3b806e7..c033aac 100644 (file)
@@ -5,12 +5,15 @@ const malColors = [
 ]
 
 const axisMap = {
-    'perf1': 'Perf 1',
-    'perf2': 'Perf 2',
-    'perf3': 'Perf 3',
-    'rank':  'Popularity',
-    'sloc':  'SLOC size',
-    'files': 'File count',
+    'pull_rank':  'GH PRs',
+    'push_rank':  'GH Pushes',
+    'star_rank':  'GH Stars',
+    'so_rank':    'SO Tags',
+    'perf1':      'Perf 1',
+    'perf2':      'Perf 2',
+    'perf3':      'Perf 3',
+    'sloc':       'SLOC size',
+    'files':      'File count',
 }
 const colorMap = {
     'syntax': 'Syntax Style',
@@ -21,12 +24,12 @@ const axisKeySet = new Set(Object.keys(axisMap))
 const colorKeySet = new Set(['type_check', 'syntax', 'author_name'])
 
 const perfSet = new Set(['perf1', 'perf2', 'perf3'])
-const invertSet = new Set(['rank', 'perf1', 'perf2'])
+const invertSet = new Set(['pull_rank', 'push_rank', 'star_rank', 'so_rank', 'perf1', 'perf2'])
 const perfLogSet = new Set(['perf1', 'perf2', 'sloc', 'files'])
 
 let cfg = {
     ckey: 'syntax',
-    xkey: 'rank',
+    xkey: 'star_rank',
     ykey: 'perf3',
     skey: 'sloc',
 
@@ -45,14 +48,14 @@ let chart
 function malExtent(data, key) {
     let extent = d3.extent(Object.values(data), d => d[key])
     // pad the bottom rank so it's not on the opposite axis line
-    if (key === 'rank') {
+    if (key.endsWith('_rank')) {
         extent[0] = 0.99 // Setting this to 1 breaks log scale render
         extent[extent.length-1] += 1
     }
     // Replace 0's with 0.01 to prevent divide by zero errors
     if (extent[0] === 0) { extent[0] = 0.0001 }
     if (extent[extent.length-1] === 0) { extent[extent.length-1] = 0.0001 }
-    // For rank, perf1 and perf2 reverse the Axis range
+    // For rankings, perf1, and perf2 reverse the Axis range
     if (invertSet.has(key)) {
         extent.reverse()
     }
@@ -121,8 +124,8 @@ for (let key of ['ckey', 'xkey', 'ykey', 'skey']) {
     const parent = document.getElementById(key + '-controls')
     const ctlMap = ({
         'ckey': colorMap,
-        'xkey': Object.assign({}, axisMap, {'xlog': 'Logarithmic'}),
-        'ykey': Object.assign({}, axisMap, {'ylog': 'Logarithmic'}),
+        'xkey': Object.assign({}, axisMap, {'xlog': 'Log Scale'}),
+        'ykey': Object.assign({}, axisMap, {'ylog': 'Log Scale'}),
         'skey': axisMap,
     })[key]
     for (let [val, name] of Object.entries(ctlMap)) {
@@ -213,30 +216,89 @@ nv.addGraph(function() {
     chart.tooltip.contentGenerator(function(obj) {
         const i = obj.point.impl
         return '<h3>' + i.name + '</h3>' +
-            '<p class="impl-data">' +
-            '<b>Syntax Style</b>: ' + i.syntax + '<br>' +
-            '<b>Type Discipline</b>: ' + i.type_check + '<br>' +
-            '<b>Github Stars</b>: ' + (i.star_count || 'unknown') + '<br>' +
-            '<b>GitHut Relative Rank</b>: ' + i.rank + '<br>' +
-            '<br>' +
-            '<b>Perf 1</b>: ' + i.perf1 + ' ms<br>' +
-            '<b>Perf 2</b>: ' + i.perf2 + ' ms<br>' +
-            '<b>Perf 3</b>: ' + i.perf3 + ' iters / 10 sec<br>' +
-            '<b>SLOC</b>: ' + i.sloc + ' lines<br>' +
-            //'<b>Author</b>: <a href="'  + i.author_url + '">' +
-            //i.author_name + '</a><br>' +
-            '<b>Author</b>: ' + i.author_name + '<br>' +
+            '<ul class="impl-data">' +
+            '<li><b>Syntax Style</b>: ' + i.syntax + '<br>' +
+            '<li><b>Type Discipline</b>: ' + i.type_check + '<br>' +
+            '<li><b>GitHub</b>:' +
+            '  <ul>' +
+            '  <li><b>PR Count</b>: ' + (i.pull_count || 'unknown') + '<br>' +
+            '  <li><b>PR Rank</b>: ' + i.pull_rank + '<br>' +
+            '  <li><b>Push Count</b>: ' + (i.push_count || 'unknown') + '<br>' +
+            '  <li><b>Push Rank</b>: ' + i.push_rank + '<br>' +
+            '  <li><b>Star Count</b>: ' + (i.star_count || 'unknown') + '<br>' +
+            '  <li><b>Star Rank</b>: ' + i.star_rank + '<br>' +
+            '  </ul>' +
+            '<li><b>StackOverflow</b>:' +
+            '  <ul>' +
+            '  <li><b>Tag Count</b>: ' + (i.so_count || 'unknown') + '<br>' +
+            '  <li><b>Tag Rank</b>: ' + i.so_rank + '<br>' +
+            '  </ul>' +
+            '<li><br>' +
+            '<li><b>Perf 1</b>: ' + i.perf1 + ' ms<br>' +
+            '<li><b>Perf 2</b>: ' + i.perf2 + ' ms<br>' +
+            '<li><b>Perf 3</b>: ' + i.perf3 + ' iters / 10 sec<br>' +
+            '<li><b>SLOC</b>: ' + i.sloc + ' lines<br>' +
+            '<li><b>Author</b>: ' + i.author_name + '<br>' +
             '&nbsp; &nbsp; ' + i.author_url.replace(/https?:\/\//, '') + '<br>' +
-            '</p>'
+            '</ul>'
     })
+
+    // Load and mangle the data
     d3.json("all_data.json", function (error, data) {
         allData = data
+
+       console.log(`Filling in missing data attributes`)
+        const dataList = Object.values(allData)
+       // leave a gap between ranked impls and those with no rank
+       const rankGap = 10
+        const maxPullRank = Math.max(...dataList.map(d => d.pull_rank))
+        const maxPushRank = Math.max(...dataList.map(d => d.push_rank))
+        const maxStarRank = Math.max(...dataList.map(d => d.star_rank))
+        const maxSORank = Math.max(...dataList.map(d => d.so_rank))
+       const maxPerf1 = dataList.reduce((a, d) => d.perf1 > a ? d.perf1 : a, 0)
+       const maxPerf2 = dataList.reduce((a, d) => d.perf2 > a ? d.perf1 : a, 0)
+       for (let d of dataList) {
+           if (d.pull_rank === null) {
+               d.pull_rank = maxPullRank + rankGap
+               console.log(`  set pull_rank to ${d.pull_rank} for ${d.dir}`)
+           }
+           if (d.push_rank === null) {
+               d.push_rank = maxPushRank + rankGap
+               console.log(`  set push_rank to ${d.push_rank} for ${d.dir}`)
+           }
+           if (d.star_rank === null) {
+               d.star_rank = maxStarRank + rankGap
+               console.log(`  set star_rank to ${d.star_rank} for ${d.dir}`)
+           }
+           if (d.so_count === 0) {
+               d.so_rank = maxSORank + rankGap
+               console.log(`  set so_rank to ${d.so_rank} for ${d.dir}`)
+           }
+           if (d.perf1 === null) {
+               d.perf1 = maxPerf1
+               console.log(`  set perf1 to ${maxPerf1} for ${d.dir}`)
+           }
+           if (d.perf2 === null) {
+               d.perf2 = maxPerf2
+               console.log(`  set perf2 to ${maxPerf2} for ${d.dir}`)
+           }
+       }
+
+       console.log(`Adjusting perf numbers to avoid 0`)
+       for (let d of dataList) {
+           if (d.perf1 === 0) { d.perf1 = 0.9 }
+           if (d.perf2 === 0) { d.perf2 = 0.9 }
+           if (d.perf3 === 0) { d.perf3 = 0.01 }
+       }
+
         // NOTE: TODO: major hack to workaround bug with switching
         // to/from logarithmic mode. Seems to require at least one
         // value to be less than 1 for it to work
         allData.rpython.perf2 = 0.9
+
         updateGraphData()
     })
+
     return chart
 })
 
index e1a1fe9..a31b336 100644 (file)
     #show {
       display: none;
     }
-    .impl-data {
+    .impl-data, .impl-data ul {
       text-align: left !important;
+      list-style: none;
+      padding: 0;
+      margin: 5;
+    }
+    .impl-data ul {
+      margin: 0 0 0 15;
     }
     #title {
       text-align: center;
index eb72dbe..da5b37d 100644 (file)
@@ -4,6 +4,7 @@
     "description": "Graph Mal Languages",
     "dependencies": {
         "js-yaml": "3.12.2",
+        "csvtojson": "2.0.8",
         "request": "2.88.0",
         "request-promise-native": "1.0.7"
     }