Stats collection script, dynamic scatter plot page
authorJoel Martin <github@martintribe.org>
Mon, 18 Mar 2019 05:31:02 +0000 (00:31 -0500)
committerJoel Martin <github@martintribe.org>
Thu, 21 Mar 2019 04:34:21 +0000 (23:34 -0500)
docs/graph/all_data.json [new file with mode: 0644]
docs/graph/base_data.yaml [new file with mode: 0644]
docs/graph/collect_data.js [new file with mode: 0755]
docs/graph/graph_languages.js [new file with mode: 0644]
docs/graph/index.html [new file with mode: 0644]
docs/graph/package.json [new file with mode: 0644]

diff --git a/docs/graph/all_data.json b/docs/graph/all_data.json
new file mode 100644 (file)
index 0000000..9126bc9
--- /dev/null
@@ -0,0 +1,1303 @@
+{
+  "ada": {
+    "dir": "ada",
+    "name": "Ada",
+    "syntax": "Algol",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 9,
+    "perf2": 28,
+    "perf3": 1089,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 5942,
+    "files": 29,
+    "author_name": "Chris Moore",
+    "author_url": "https://github.com/zmower",
+    "lloc": 3759
+  },
+  "awk": {
+    "dir": "awk",
+    "name": "GNU Awk",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 14,
+    "perf2": 47,
+    "perf3": 702,
+    "star_count": 355,
+    "rank": 50,
+    "sloc": 5213,
+    "files": 17,
+    "author_name": "Miutsuru Kariya",
+    "author_url": "https://github.com/kariya-mitsuru",
+    "lloc": 0
+  },
+  "bash": {
+    "dir": "bash",
+    "name": "Bash 4",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 1681,
+    "perf2": 7748,
+    "perf3": 5,
+    "star_count": 59906,
+    "rank": 14,
+    "sloc": 2392,
+    "files": 18,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "basic": {
+    "dir": "basic",
+    "name": "BASIC",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [
+      "cbm",
+      "qbasic"
+    ],
+    "perf1": 11,
+    "perf2": 49,
+    "perf3": 871,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 3963,
+    "files": 23,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 3956
+  },
+  "c": {
+    "dir": "c",
+    "name": "C",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 0.9,
+    "perf2": 2,
+    "perf3": 17211,
+    "star_count": 90804,
+    "rank": 9,
+    "sloc": 3701,
+    "files": 26,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 2012
+  },
+  "cpp": {
+    "dir": "cpp",
+    "name": "C++",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 0.9,
+    "perf2": 1,
+    "perf3": 16045,
+    "star_count": 139366,
+    "rank": 6,
+    "sloc": 3532,
+    "files": 29,
+    "author_name": "Stephen Thirlwall",
+    "author_url": "https://github.com/sdt",
+    "lloc": 1617
+  },
+  "cs": {
+    "dir": "cs",
+    "name": "C#",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 9,
+    "perf2": 10,
+    "perf3": 14958,
+    "star_count": 76670,
+    "rank": 10,
+    "sloc": 3396,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1760
+  },
+  "chuck": {
+    "dir": "chuck",
+    "name": "ChucK",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 35,
+    "perf2": 113,
+    "perf3": 132,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 4962,
+    "files": 98,
+    "author_name": "Vasilij Schneidermann",
+    "author_url": "https://github.com/wasamasa",
+    "lloc": 1796
+  },
+  "clojure": {
+    "dir": "clojure",
+    "name": "Clojure",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [
+      "clj",
+      "cljs"
+    ],
+    "perf1": 25,
+    "perf2": 66,
+    "perf3": 2373,
+    "star_count": 5502,
+    "rank": 27,
+    "sloc": 1207,
+    "files": 23,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "coffee": {
+    "dir": "coffee",
+    "name": "CoffeeScript",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 7,
+    "perf2": 33,
+    "perf3": 18111,
+    "star_count": 8569,
+    "rank": 22,
+    "sloc": 1073,
+    "files": 21,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "common-lisp": {
+    "dir": "common-lisp",
+    "name": "Common Lisp",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 1,
+    "perf2": 2,
+    "perf3": 14665,
+    "star_count": 1146,
+    "rank": 38,
+    "sloc": 2607,
+    "files": 22,
+    "author_name": "Iqbal Ansari",
+    "author_url": "https://github.com/iqbalansari",
+    "lloc": 0
+  },
+  "crystal": {
+    "dir": "crystal",
+    "name": "Crystal",
+    "syntax": "OTHER",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 1,
+    "perf2": 2,
+    "perf3": 28255,
+    "star_count": 938,
+    "rank": 41,
+    "sloc": 2157,
+    "files": 18,
+    "author_name": "Linda_pp",
+    "author_url": "https://github.com/rhysd",
+    "lloc": 0
+  },
+  "d": {
+    "dir": "d",
+    "name": "D",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 0.9,
+    "perf2": 2,
+    "perf3": 15621,
+    "star_count": 653,
+    "rank": 45,
+    "sloc": 2979,
+    "files": 18,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 1434
+  },
+  "dart": {
+    "dir": "dart",
+    "name": "Dart",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 14,
+    "perf2": 38,
+    "perf3": 509,
+    "star_count": 2498,
+    "rank": 34,
+    "sloc": 2279,
+    "files": 18,
+    "author_name": "Harry Terkelsen",
+    "author_url": "https://github.com/hterkelsen",
+    "lloc": 1142
+  },
+  "elixir": {
+    "dir": "elixir",
+    "name": "Elixir",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 14,
+    "perf2": 52,
+    "perf3": 765,
+    "star_count": 6115,
+    "rank": 24,
+    "sloc": 1824,
+    "files": 20,
+    "author_name": "Martin Ek",
+    "author_url": "https://github.com/ekmartin",
+    "lloc": 0
+  },
+  "elm": {
+    "dir": "elm",
+    "name": "Elm",
+    "syntax": "ML",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 69,
+    "perf2": 167,
+    "perf3": 801,
+    "star_count": 809,
+    "rank": 43,
+    "sloc": 5775,
+    "files": 24,
+    "author_name": "Jos van Bakel",
+    "author_url": "https://github.com/c0deaddict",
+    "lloc": 0
+  },
+  "elisp": {
+    "dir": "elisp",
+    "name": "Emacs Lisp",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 16,
+    "perf2": 77,
+    "perf3": 593,
+    "star_count": 5689,
+    "rank": 26,
+    "sloc": 1982,
+    "files": 20,
+    "author_name": "Vasilij Schneidermann",
+    "author_url": "https://github.com/wasamasa",
+    "lloc": 0
+  },
+  "erlang": {
+    "dir": "erlang",
+    "name": "Erlang",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 53,
+    "perf2": 175,
+    "perf3": 175,
+    "star_count": 2942,
+    "rank": 31,
+    "sloc": 2215,
+    "files": 18,
+    "author_name": "Nathan Fiedler",
+    "author_url": "https://github.com/nlfiedler",
+    "lloc": 0
+  },
+  "es6": {
+    "dir": "es6",
+    "name": "ES6",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 3,
+    "perf2": 21,
+    "perf3": 12079,
+    "star_count": 668062,
+    "rank": 2,
+    "sloc": 1230,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "fsharp": {
+    "dir": "fsharp",
+    "name": "F#",
+    "syntax": "ML",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 35,
+    "perf2": 29,
+    "perf3": 20634,
+    "star_count": 950,
+    "rank": 39,
+    "sloc": 3033,
+    "files": 22,
+    "author_name": "Peter Stephens",
+    "author_url": "https://github.com/pstephens",
+    "lloc": 404
+  },
+  "factor": {
+    "dir": "factor",
+    "name": "Factor",
+    "syntax": "Stack",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 2,
+    "perf2": 1,
+    "perf3": 27766,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1305,
+    "files": 33,
+    "author_name": "Jordan Lewis",
+    "author_url": "https://github.com/jordanlewis",
+    "lloc": 0
+  },
+  "fantom": {
+    "dir": "fantom",
+    "name": "Fantom",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 14,
+    "perf2": 31,
+    "perf3": 40400,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1768,
+    "files": 31,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "forth": {
+    "dir": "forth",
+    "name": "Forth",
+    "syntax": "Stack",
+    "type_check": "OTHER",
+    "modes": [],
+    "perf1": 4,
+    "perf2": 14,
+    "perf3": 2448,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 3351,
+    "files": 21,
+    "author_name": "Chris Houser",
+    "author_url": "https://github.com/chouser",
+    "lloc": 0
+  },
+  "guile": {
+    "dir": "guile",
+    "name": "GNU Guile",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 3,
+    "perf2": 9,
+    "perf3": 3962,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1547,
+    "files": 20,
+    "author_name": "Mu Lei",
+    "author_url": "https://github.com/NalaGinrut",
+    "lloc": 0
+  },
+  "gnu-smalltalk": {
+    "dir": "gnu-smalltalk",
+    "name": "GNU Smalltalk",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 14,
+    "perf2": 45,
+    "perf3": 787,
+    "star_count": 152,
+    "rank": 55,
+    "sloc": 2444,
+    "files": 21,
+    "author_name": "Vasilij Schneidermann",
+    "author_url": "https://github.com/wasamasa",
+    "lloc": 0
+  },
+  "go": {
+    "dir": "go",
+    "name": "Go",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 1,
+    "perf2": 3,
+    "perf3": 10334,
+    "star_count": 215511,
+    "rank": 5,
+    "sloc": 3451,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1792
+  },
+  "groovy": {
+    "dir": "groovy",
+    "name": "Groovy",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 477,
+    "perf2": 746,
+    "perf3": 324,
+    "star_count": 4302,
+    "rank": 29,
+    "sloc": 1598,
+    "files": 19,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "haskell": {
+    "dir": "haskell",
+    "name": "Haskell",
+    "syntax": "ML",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 3,
+    "perf2": 8,
+    "perf3": 4338,
+    "star_count": 6312,
+    "rank": 23,
+    "sloc": 2011,
+    "files": 18,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "haxe": {
+    "dir": "haxe",
+    "name": "Haxe",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [
+      "neko",
+      "python",
+      "cpp",
+      "js"
+    ],
+    "perf1": 5,
+    "perf2": 26,
+    "perf3": 15377,
+    "star_count": 580,
+    "rank": 46,
+    "sloc": 2270,
+    "files": 23,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1045
+  },
+  "hy": {
+    "dir": "hy",
+    "name": "Hy",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 17,
+    "perf2": 67,
+    "perf3": 585,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1215,
+    "files": 18,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "io": {
+    "dir": "io",
+    "name": "Io",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 357,
+    "perf2": 1333,
+    "perf3": 29,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1262,
+    "files": 18,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "java": {
+    "dir": "java",
+    "name": "Java",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 7,
+    "perf2": 24,
+    "perf3": 57275,
+    "star_count": 255160,
+    "rank": 4,
+    "sloc": 3061,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1537
+  },
+  "js": {
+    "dir": "js",
+    "name": "JavaScript",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 3,
+    "perf2": 22,
+    "perf3": 14550,
+    "star_count": 668062,
+    "rank": 1,
+    "sloc": 2779,
+    "files": 33,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "julia": {
+    "dir": "julia",
+    "name": "Julia",
+    "syntax": "Algol",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 253,
+    "perf2": 32,
+    "perf3": 2975,
+    "star_count": 948,
+    "rank": 40,
+    "sloc": 1413,
+    "files": 19,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "kotlin": {
+    "dir": "kotlin",
+    "name": "Kotlin",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 19,
+    "perf2": 75,
+    "perf3": 33381,
+    "star_count": 20958,
+    "rank": 17,
+    "sloc": 1571,
+    "files": 19,
+    "author_name": "Javier Fernandez-Ivern",
+    "author_url": "https://github.com/ivern",
+    "lloc": 0
+  },
+  "livescript": {
+    "dir": "livescript",
+    "name": "LiveScript",
+    "syntax": "ML",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 6,
+    "perf2": 26,
+    "perf3": 7570,
+    "star_count": 116,
+    "rank": 57,
+    "sloc": 2128,
+    "files": 19,
+    "author_name": "Jos van Bakel",
+    "author_url": "https://github.com/c0deaddict",
+    "lloc": 0
+  },
+  "logo": {
+    "dir": "logo",
+    "name": "Logo",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 19182,
+    "perf2": 53948,
+    "perf3": 0.01,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 2139,
+    "files": 20,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "lua": {
+    "dir": "lua",
+    "name": "Lua",
+    "syntax": "Algol",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 10,
+    "perf2": 44,
+    "perf3": 955,
+    "star_count": 8769,
+    "rank": 21,
+    "sloc": 1909,
+    "files": 21,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "make": {
+    "dir": "make",
+    "name": "GNU Make",
+    "syntax": "OTHER",
+    "type_check": "OTHER",
+    "modes": [],
+    "perf1": 5050,
+    "perf2": 31077,
+    "perf3": 1,
+    "star_count": 2034,
+    "rank": 35,
+    "sloc": 1821,
+    "files": 22,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "mal": {
+    "dir": "mal",
+    "name": "mal itself",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 277,
+    "perf2": 1346,
+    "perf3": 40,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 890,
+    "files": 13,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "matlab": {
+    "dir": "matlab",
+    "name": "MATLAB",
+    "syntax": "Algol",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 1709,
+    "perf2": 6295,
+    "perf3": 5,
+    "star_count": 2867,
+    "rank": 32,
+    "sloc": 2204,
+    "files": 27,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "miniMAL": {
+    "dir": "miniMAL",
+    "name": "miniMAL",
+    "syntax": "JSON",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 1340,
+    "perf2": 5383,
+    "perf3": 7,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1691,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "nasm": {
+    "dir": "nasm",
+    "name": "NASM",
+    "syntax": "OTHER",
+    "type_check": "OTHER",
+    "modes": [],
+    "perf1": 0.9,
+    "perf2": 2,
+    "perf3": 24147,
+    "star_count": 1195,
+    "rank": 37,
+    "sloc": 14483,
+    "files": 19,
+    "author_name": "Ben Dudson",
+    "author_url": "https://github.com/bendudson",
+    "lloc": 0
+  },
+  "nim": {
+    "dir": "nim",
+    "name": "Nim",
+    "syntax": "Python",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 1,
+    "perf2": 2,
+    "perf3": 30900,
+    "star_count": 529,
+    "rank": 48,
+    "sloc": 1423,
+    "files": 17,
+    "author_name": "Dennis Felsing",
+    "author_url": "https://github.com/def-",
+    "lloc": 0
+  },
+  "objpascal": {
+    "dir": "objpascal",
+    "name": "Object Pascal",
+    "syntax": "Algol",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 4,
+    "perf2": 12,
+    "perf3": 2830,
+    "star_count": 1324,
+    "rank": 36,
+    "sloc": 6179,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 3971
+  },
+  "objc": {
+    "dir": "objc",
+    "name": "Objective C",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 6,
+    "perf2": 28,
+    "perf3": 1599,
+    "star_count": 48248,
+    "rank": 16,
+    "sloc": 2363,
+    "files": 26,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1059
+  },
+  "ocaml": {
+    "dir": "ocaml",
+    "name": "OCaml",
+    "syntax": "ML",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 1,
+    "perf2": 2,
+    "perf3": 23267,
+    "star_count": 3646,
+    "rank": 30,
+    "sloc": 1269,
+    "files": 17,
+    "author_name": "Chris Houser",
+    "author_url": "https://github.com/chouser",
+    "lloc": 0
+  },
+  "perl": {
+    "dir": "perl",
+    "name": "Perl",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 13,
+    "perf2": 50,
+    "perf3": 790,
+    "star_count": 4679,
+    "rank": 28,
+    "sloc": 2265,
+    "files": 22,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1107
+  },
+  "perl6": {
+    "dir": "perl6",
+    "name": "Perl 6",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 441,
+    "perf2": 1182,
+    "perf3": 23,
+    "star_count": 137,
+    "rank": 56,
+    "sloc": 1238,
+    "files": 18,
+    "author_name": "Hinrik Örn Sigurðsson",
+    "author_url": "https://github.com/hinrik",
+    "lloc": 484
+  },
+  "php": {
+    "dir": "php",
+    "name": "PHP",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 8,
+    "perf2": 28,
+    "perf3": 1268,
+    "star_count": 135579,
+    "rank": 7,
+    "sloc": 1998,
+    "files": 21,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1074
+  },
+  "picolisp": {
+    "dir": "picolisp",
+    "name": "Picolisp",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 2,
+    "perf2": 7,
+    "perf3": 6005,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1366,
+    "files": 20,
+    "author_name": "Vasilij Schneidermann",
+    "author_url": "https://github.com/wasamasa",
+    "lloc": 0
+  },
+  "plpgsql": {
+    "dir": "plpgsql",
+    "name": "PL/pgSQL",
+    "syntax": "Algol",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 478,
+    "perf2": 3830,
+    "perf3": 20,
+    "star_count": 897,
+    "rank": 42,
+    "sloc": 3679,
+    "files": 21,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "plsql": {
+    "dir": "plsql",
+    "name": "PL/SQL",
+    "syntax": "Algol",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 19182,
+    "perf2": 1921,
+    "perf3": 0.01,
+    "star_count": 199,
+    "rank": 53,
+    "sloc": 4180,
+    "files": 21,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "powershell": {
+    "dir": "powershell",
+    "name": "PowerShell",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 1921,
+    "perf2": 7832,
+    "perf3": 5,
+    "star_count": 5795,
+    "rank": 25,
+    "sloc": 1147,
+    "files": 12,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "ps": {
+    "dir": "ps",
+    "name": "PostScript",
+    "syntax": "Stack",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 38,
+    "perf2": 274,
+    "perf3": 198,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 2482,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "python": {
+    "dir": "python",
+    "name": "Python",
+    "syntax": "Python",
+    "type_check": "Dynamic",
+    "modes": [
+      "python2",
+      "python3"
+    ],
+    "perf1": 7,
+    "perf2": 29,
+    "perf3": 1371,
+    "star_count": 336045,
+    "rank": 3,
+    "sloc": 1358,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 1344
+  },
+  "rpython": {
+    "dir": "rpython",
+    "name": "RPython",
+    "syntax": "Python",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 0.9,
+    "perf2": 1,
+    "perf3": 69848,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 2102,
+    "files": 19,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 2096
+  },
+  "r": {
+    "dir": "r",
+    "name": "R",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 78,
+    "perf2": 295,
+    "perf3": 117,
+    "star_count": 2644,
+    "rank": 33,
+    "sloc": 1625,
+    "files": 19,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "racket": {
+    "dir": "racket",
+    "name": "Racket",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 2,
+    "perf2": 7,
+    "perf3": 4865,
+    "star_count": 281,
+    "rank": 51,
+    "sloc": 1193,
+    "files": 18,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "rexx": {
+    "dir": "rexx",
+    "name": "Rexx",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 160,
+    "perf2": 660,
+    "perf3": 61,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 2747,
+    "files": 19,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "ruby": {
+    "dir": "ruby",
+    "name": "Ruby",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 2,
+    "perf2": 8,
+    "perf3": 4163,
+    "star_count": 54043,
+    "rank": 15,
+    "sloc": 1291,
+    "files": 20,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "rust": {
+    "dir": "rust",
+    "name": "Rust",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 0.9,
+    "perf2": 1,
+    "perf3": 16720,
+    "star_count": 19178,
+    "rank": 18,
+    "sloc": 2862,
+    "files": 18,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 714
+  },
+  "scala": {
+    "dir": "scala",
+    "name": "Scala",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 27,
+    "perf2": 66,
+    "perf3": 25785,
+    "star_count": 13634,
+    "rank": 19,
+    "sloc": 1849,
+    "files": 18,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "scheme": {
+    "dir": "scheme",
+    "name": "Scheme (R7RS)",
+    "syntax": "Lisp",
+    "type_check": "Dynamic",
+    "modes": [
+      "chibi",
+      "kawa",
+      "gauche",
+      "chicken",
+      "sagittarius",
+      "cyclone",
+      "foment"
+    ],
+    "perf1": 6,
+    "perf2": 19,
+    "perf3": 2231,
+    "star_count": 718,
+    "rank": 44,
+    "sloc": 1269,
+    "files": 13,
+    "author_name": "Vasilij Schneidermann",
+    "author_url": "https://github.com/wasamasa",
+    "lloc": 0
+  },
+  "skew": {
+    "dir": "skew",
+    "name": "Skew",
+    "syntax": "OTHER",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 6,
+    "perf2": 11,
+    "perf3": 3608,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 1638,
+    "files": 19,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "swift": {
+    "dir": "swift",
+    "name": "Swift 2",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 2,
+    "perf2": 6,
+    "perf3": 5322,
+    "star_count": 66012,
+    "rank": 11,
+    "sloc": 2963,
+    "files": 14,
+    "author_name": "Keith Rollin",
+    "author_url": "https://github.com/keith-rollin",
+    "lloc": 0
+  },
+  "swift3": {
+    "dir": "swift3",
+    "name": "Swift 3",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 8,
+    "perf2": 27,
+    "perf3": 1234,
+    "star_count": 66012,
+    "rank": 12,
+    "sloc": 2362,
+    "files": 17,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "swift4": {
+    "dir": "swift4",
+    "name": "Swift 4",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 5,
+    "perf2": 16,
+    "perf3": 2065,
+    "star_count": 66012,
+    "rank": 13,
+    "sloc": 1767,
+    "files": 17,
+    "author_name": "陆遥",
+    "author_url": "https://github.com/LispLY",
+    "lloc": 0
+  },
+  "tcl": {
+    "dir": "tcl",
+    "name": "Tcl",
+    "syntax": "OTHER",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 24,
+    "perf2": 103,
+    "perf3": 373,
+    "star_count": 171,
+    "rank": 54,
+    "sloc": 2468,
+    "files": 20,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "ts": {
+    "dir": "ts",
+    "name": "TypeScript",
+    "syntax": "C",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 4,
+    "perf2": 14,
+    "perf3": 26534,
+    "star_count": 93555,
+    "rank": 8,
+    "sloc": 2836,
+    "files": 20,
+    "author_name": "Masahiro Wakame",
+    "author_url": "https://github.com/vvakame",
+    "lloc": 0
+  },
+  "vhdl": {
+    "dir": "vhdl",
+    "name": "VHDL",
+    "syntax": "Algol",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 3,
+    "perf2": 9,
+    "perf3": 3342,
+    "star_count": 217,
+    "rank": 52,
+    "sloc": 4258,
+    "files": 19,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 0
+  },
+  "vimscript": {
+    "dir": "vimscript",
+    "name": "Vimscript",
+    "syntax": "Algol",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 219,
+    "perf2": 1055,
+    "perf3": 43,
+    "star_count": 10096,
+    "rank": 20,
+    "sloc": 2147,
+    "files": 22,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 12
+  },
+  "vb": {
+    "dir": "vb",
+    "name": "Visual Basic.NET",
+    "syntax": "Algol",
+    "type_check": "Static",
+    "modes": [],
+    "perf1": 14,
+    "perf2": 14,
+    "perf3": 10121,
+    "star_count": 578,
+    "rank": 47,
+    "sloc": 3839,
+    "files": 19,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 394
+  },
+  "wasm": {
+    "dir": "wasm",
+    "name": "WebAssembly",
+    "syntax": "Lisp",
+    "type_check": "Static",
+    "modes": [
+      "wace_libc",
+      "node",
+      "warpy"
+    ],
+    "perf1": 2,
+    "perf2": 10,
+    "perf3": 3742,
+    "star_count": 365,
+    "rank": 49,
+    "sloc": 5270,
+    "files": 26,
+    "author_name": "Joel Martin",
+    "author_url": "https://github.com/kanaka",
+    "lloc": 0
+  },
+  "yorick": {
+    "dir": "yorick",
+    "name": "Yorick",
+    "syntax": "C",
+    "type_check": "Dynamic",
+    "modes": [],
+    "perf1": 67,
+    "perf2": 288,
+    "perf3": 147,
+    "star_count": null,
+    "rank": 68,
+    "sloc": 2398,
+    "files": 19,
+    "author_name": "Dov Murik",
+    "author_url": "https://github.com/dubek",
+    "lloc": 210
+  }
+}
\ No newline at end of file
diff --git a/docs/graph/base_data.yaml b/docs/graph/base_data.yaml
new file mode 100644 (file)
index 0000000..161e47f
--- /dev/null
@@ -0,0 +1,79 @@
+headers:
+  - [dir           , name             , syntax , type_check , modes]
+
+languages:
+  - [ada           , Ada              , Algol  , Static     , []]
+  - [awk           , GNU Awk          , C      , Dynamic    , []]
+  - [bash          , Bash 4           , OTHER  , Dynamic    , []]
+  - [basic         , BASIC            , OTHER  , Dynamic    , [cbm, qbasic]]
+  - [c             , C                , C      , Static     , []]
+  - [cpp           , C++              , C      , Static     , []]
+  - [cs            , C#               , C      , Static     , []]
+  - [chuck         , ChucK            , C      , Static     , []]
+  - [clojure       , Clojure          , Lisp   , Dynamic    , [clj, cljs]]
+  - [coffee        , CoffeeScript     , OTHER  , Dynamic    , []]
+  - [common-lisp   , Common Lisp      , Lisp   , Dynamic    , []]
+  - [crystal       , Crystal          , OTHER  , Static     , []]
+  - [d             , D                , C      , Static     , []]
+  - [dart          , Dart             , C      , Static     , []]
+  - [elixir        , Elixir           , OTHER  , Dynamic    , []]
+  - [elm           , Elm              , ML     , Static     , []]
+  - [elisp         , Emacs Lisp       , Lisp   , Dynamic    , []]
+  - [erlang        , Erlang           , OTHER  , Dynamic    , []]
+  - [es6           , ES6              , C      , Dynamic    , []]
+  - [fsharp        , F#               , ML     , Static     , []]
+  - [factor        , Factor           , Stack  , Dynamic    , []]
+  - [fantom        , Fantom           , C      , Static     , []]
+  - [forth         , Forth            , Stack  , OTHER      , []]
+  - [guile         , GNU Guile        , Lisp   , Dynamic    , []]
+  - [gnu-smalltalk , GNU Smalltalk    , OTHER  , Dynamic    , []]
+  - [go            , Go               , C      , Static     , []]
+  - [groovy        , Groovy           , C      , Dynamic    , []]
+  - [haskell       , Haskell          , ML     , Static     , []]
+  - [haxe          , Haxe             , C      , Static     , [neko,python,cpp,js]]
+  - [hy            , Hy               , Lisp   , Dynamic    , []]
+  - [io            , Io               , OTHER  , Dynamic    , []]
+  - [java          , Java             , C      , Static     , []]
+  - [js            , JavaScript       , C      , Dynamic    , []]
+  - [julia         , Julia            , Algol  , Dynamic    , []]
+  - [kotlin        , Kotlin           , C      , Static     , []]
+  - [livescript    , LiveScript       , ML     , Dynamic    , []]
+  - [logo          , Logo             , OTHER  , Dynamic    , []]
+  - [lua           , Lua              , Algol  , Dynamic    , []]
+  - [make          , GNU Make         , OTHER  , OTHER      , []]
+  - [mal           , mal itself       , Lisp   , Dynamic    , []]
+  - [matlab        , MATLAB           , Algol  , Dynamic    , []]
+  - [miniMAL       , miniMAL          , JSON   , Dynamic    , []]
+  - [nasm          , NASM             , OTHER  , OTHER      , []]
+  - [nim           , Nim              , Python , Static     , []]
+  - [objpascal     , Object Pascal    , Algol  , Static     , []]
+  - [objc          , Objective C      , C      , Static     , []]
+  - [ocaml         , OCaml            , ML     , Static     , []]
+  - [perl          , Perl             , C      , Dynamic    , []]
+  - [perl6         , Perl 6           , C      , Dynamic    , []]
+  - [php           , PHP              , C      , Dynamic    , []]
+  - [picolisp      , Picolisp         , Lisp   , Dynamic    , []]
+  - [plpgsql       , PL/pgSQL         , Algol  , Static     , []]
+  - [plsql         , PL/SQL           , Algol  , Static     , []]
+  - [powershell    , PowerShell       , OTHER  , Dynamic    , []]
+  - [ps            , PostScript       , Stack  , Dynamic    , []]
+  - [python        , Python           , Python , Dynamic    , [python2,python3]]
+  - [rpython       , RPython          , Python , Static     , []]
+  - [r             , R                , C      , Dynamic    , []]
+  - [racket        , Racket           , Lisp   , Dynamic    , []]
+  - [rexx          , Rexx             , OTHER  , Dynamic    , []]
+  - [ruby          , Ruby             , OTHER  , Dynamic    , []]
+  - [rust          , Rust             , C      , Static     , []]
+  - [scala         , Scala            , C      , Static     , []]
+  - [scheme        , Scheme (R7RS)    , Lisp   , Dynamic    , [chibi,kawa,gauche,chicken,sagittarius,cyclone,foment]]
+  - [skew          , Skew             , OTHER  , Static     , []]
+  - [swift         , Swift 2          , C      , Static     , []]
+  - [swift3        , Swift 3          , C      , Static     , []]
+  - [swift4        , Swift 4          , C      , Static     , []]
+  - [tcl           , Tcl              , OTHER  , Dynamic    , []]
+  - [ts            , TypeScript       , C      , Static     , []]
+  - [vhdl          , VHDL             , Algol  , Static     , []]
+  - [vimscript     , Vimscript        , Algol  , Dynamic    , []]
+  - [vb            , Visual Basic.NET , Algol  , Static     , []]
+  - [wasm          , WebAssembly      , Lisp   , Static     , [wace_libc,node,warpy]]
+  - [yorick        , Yorick           , C      , Dynamic    , []]
diff --git a/docs/graph/collect_data.js b/docs/graph/collect_data.js
new file mode 100755 (executable)
index 0000000..efca8a0
--- /dev/null
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+
+const { promisify } = require('util')
+const readFile = promisify(require('fs').readFile)
+const writeFile = promisify(require('fs').writeFile)
+const readdir = promisify(require('fs').readdir)
+const path = require('path')
+const yaml = require('js-yaml')
+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'] || '../../'
+
+
+const githutToNames = {
+    'Awk':          ['GNU Awk'],
+    'Shell':        ['Bash 4'],
+    'JavaScript':   ['JavaScript', 'ES6'],
+    'Makefile':     ['GNU Make'],
+    'Matlab':       ['MATLAB'],
+    'Assembly':     ['NASM'],
+    'Pascal':       ['Object Pascal'],
+    'Objective-C':  ['Objective C'],
+    'PLpgSQL':      ['PL/pgSQL'],
+    'PLSQL':        ['PL/SQL'],
+    'Scheme':       ['Scheme (R7RS)'],
+    'Smalltalk':    ['GNU Smalltalk'],
+    'Swift':        ['Swift 2', 'Swift 3', 'Swift 4'],
+    'Vim script':   ['Vimscript'],
+    'Visual Basic': ['Visual Basic.NET'],
+}
+
+function vlog(...args) {
+    if (VERBOSE) {
+        console.log(...args)
+    }
+}
+
+function die(code, ...args) {
+    console.error(...args)
+    process.exit(code)
+}
+
+async function main() {
+    const logsPath = path.resolve(process.argv[2])
+    const outPath = path.resolve(process.argv[3])
+
+    vlog(`Loading base data yaml from '${BASE_PATH}`)
+    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(`Loading log data from '${logsPath}'`)
+    const logFiles = (await readdir(logsPath))
+        .map(x => parseInt(x))
+        .sort((a, b) => a - b)
+    let logData = []
+    for (const f of logFiles) {
+        if (!(/^[0-9]+$/.exec(f))) { continue }
+        const path = logsPath + "/" + f
+        logData.push([await readFile(path, 'utf8'), path])
+    }
+
+    let dirs = []
+    let names = []
+    let dataList = []
+    let dataByDir  = {}
+    let dataByName = {}
+
+    vlog(`Processing base data`)
+    for (let d of baseYaml['languages']) {
+        let data = {'dir':         d[0],
+                    'name':        d[1],
+                    'syntax':      d[2],
+                    'type_check':  d[3],
+                    'modes':       d[4],
+                    'perf1':       null,
+                    'perf2':       null,
+                    'perf3':       0,
+                    'star_count':  null,
+                    'rank':        null,
+                    'sloc':        0,
+                    'files':       0}
+        dirs.push(d[0])
+        names.push(d[1])
+        dataList.push(data)
+        dataByDir[d[0]]  = data
+        dataByName[d[1]] = data
+    }
+
+    vlog(`Processing README implementations table`)
+    const readme_re = /^\| \[([^\[]*)\].* \| \[([^|]*)\]\(([^|]*)\)  *\| *$/
+    for (let row of readmeLines.filter(l => /^\| [\[]/.exec(l))) {
+        t = readme_re.exec(row)
+        if (t) {
+            if (t[1] in dataByName) {
+                let data = dataByName[t[1]]
+                data.author_name = t[2]
+                data.author_url  = t[3]
+            } else {
+                die(1, `README language '${t[1]}' not found in base data`)
+            }
+        } else {
+            die(1, `No match for README table row: ${row}`)
+        }
+    }
+
+    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
+            } else {
+                vlog(`  ignoring GitHut language ${name}`)
+            }
+        }
+    }
+
+    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) {
+        const dir_match = (/export IMPL=(\S+)/i).exec(log)
+        if (!dir_match) { die(1, `no IMPL found in ${file}`) }
+        const dir = dir_match[1]
+        const data = dataByDir[dir]
+//        if (data.perf1 !== null) {
+//            vlog(`  ${dir} already has perf data, ignoring ${file}`)
+//            continue
+//        }
+        const perfs = {}
+        const logLines = log.split(/\n/)
+        for (let i = 0; i < logLines.length; i++) {
+            const match_run = perf_run_re.exec(logLines[i])
+            if (match_run) {
+                // Find the result line
+                let match_num = null
+                do {
+                    i += 1
+                    match_num = perf_num_re.exec(logLines[i])
+                    if (match_num) {
+                        num = parseFloat(match_num[1] || match_num[2], 10)
+                        perfs[match_run[1]] = num
+                    }
+                } while ((!match_num) && i < logLines.length)
+            }
+        }
+        if ((perfs.perf3 > data.perf3) || !data.perf3) {
+            data.perf1 = perfs.perf1
+            data.perf2 = perfs.perf2
+            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(`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(`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))
+
+    process.exit(0)
+}
+
+main()
diff --git a/docs/graph/graph_languages.js b/docs/graph/graph_languages.js
new file mode 100644 (file)
index 0000000..3dd3ff6
--- /dev/null
@@ -0,0 +1,214 @@
+const malColors = [
+    "#1f77b4","#bf7f0e","#4cb00c","#b62728","#9467bd","#bc664b","#b377c2","#0fbf5f","#bcbd22","#17beef",
+    "#1f6784","#8f7f0e","#4c800c","#862728","#54678d","#8c564b","#8377c2","#0f8f5f","#8c8d22","#178eef",
+    "#1f97d4","#ff7f0e","#4cf00c","#f62728","#c467fd","#fc764b","#f377c2","#0fff5f","#fcfd22","#17feef",
+]
+
+const axisSet = new Set(['perf1', 'perf2', 'perf3', 'rank', 'sloc', 'files'])
+const colorSet = new Set(['type_check', 'syntax', 'author_name'])
+const perfSet = new Set(['perf1', 'perf2', 'perf3'])
+const invertSet = new Set(['rank', 'perf1', 'perf2'])
+const perfLogSet = new Set(['perf1', 'perf2', 'sloc', 'files'])
+
+let cfg = {
+    ckey: 'syntax',
+    xkey: 'rank',
+    ykey: 'perf3',
+    skey: 'sloc',
+
+    xlog: false,
+    ylog: true,
+}
+
+let allData
+let graphData = []
+let chart
+
+//
+// Util functions
+//
+
+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') {
+        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
+    if (invertSet.has(key)) {
+        extent.reverse()
+    }
+    return extent
+}
+
+function malScale(log) {
+    return log ? d3.scale.log() : d3.scale.linear()
+}
+
+function malTickValues(key, log) {
+    if (log && perfSet.has(key)) {
+        return [1, 10, 100, 1000, 10000, 100000]
+    } else {
+        return null
+    }
+}
+
+function malCircleSize(key, min, max, val) {
+    let size = (val || 0.01) - (min - 0.01)
+    if (invertSet.has(key)) {
+        size = (max + 0.01) - size
+    }
+//    if (perfLogSet.has(key)) {
+//        size = Math.log(size)
+//    }
+//    console.log(key, max, val, size)
+    return size
+}
+
+
+//
+// UI / Axis Data / query parameters
+//
+
+// Parser query string and update cfg map with valid config options
+(function parseQuery(q) {
+    const pairs = (q[0] === '?' ? q.substr(1) : q).split('&')
+    for (const [p1, p2] of pairs.map(p => p.split('='))) {
+        let k = decodeURIComponent(p1).toLowerCase()
+        let v = p2 ? decodeURIComponent(p2) : true
+        if (v in {"true":1,"1":1,"yes":1}) { v = true }
+        if (v in {"false":1,"0":1,"no":1}) { v = false }
+        if (k in cfg && (axisSet.has(v) || colorSet.has(v))) {
+            cfg[k] = v
+        }
+        if ((new Set(['xlog', 'ylog'])).has(k) && typeof v === 'boolean') {
+            cfg[k] = v
+        }
+    }
+})(location.search)
+
+// Set the checked elements based on the the cfg
+for (const key of Object.keys(cfg)) {
+    for (const node of document.getElementsByName(key)) {
+        let val = node.value
+        if (val in {"true":1,"1":1,"yes":1}) { val = true }
+        if (val in {"false":1,"0":1,"no":1}) { val = false }
+        if (val === cfg[key]) {
+            node.checked = true
+        } else {
+            node.checked = false
+        }
+    }
+}
+
+// Add onchange to all selector radio buttons/check boxes
+for (let input of document.getElementsByClassName('selects')) {
+    input.addEventListener('change', function(evt) {
+        if (new Set(['xlog', 'ylog']).has(evt.target.name)) {
+            cfg[evt.target.name] = evt.target.checked
+        } else {
+            cfg[evt.target.name] = evt.target.value
+        }
+        const query = Object.entries(cfg).map(([k,v]) => k + "=" + v).join('&')
+        history.pushState(null, '', '?' + query)
+        updateGraphData()
+    })
+}
+
+
+//
+// Graph rendering / updating
+//
+
+function updateGraphData() {
+    let xMax = 0
+    let yMax = 0
+    let sMin = null
+    let sMax = null
+    const colorSet = new Set(Object.values(allData).map(d => d[cfg.ckey]))
+    const colorList = Array.from(colorSet.values())
+    // empty the graphData without recreating it
+    while (graphData.length > 0) { graphData.pop() }
+    graphData.push(...colorList.map(t => ({key: t, values: []})))
+    for (var dir of Object.keys(allData)) {
+        const impl = allData[dir]
+        if (impl[cfg.xkey] > xMax) { xMax = impl[cfg.xkey] }
+        if (impl[cfg.ykey] > yMax) { yMax = impl[cfg.ykey] }
+        if (sMin === null) { sMin = impl[cfg.skey] }
+        if (impl[cfg.skey] < sMin) { sMin = impl[cfg.skey] }
+        if (impl[cfg.skey] > sMax) { sMax = impl[cfg.skey] }
+    }
+    for (var dir of Object.keys(allData)) {
+        const impl = allData[dir]
+        // Invert size for inverted data
+        graphData[colorList.indexOf(impl[cfg.ckey])].values.push({
+            x: impl[cfg.xkey] || 0,
+            y: impl[cfg.ykey] || 0,
+            size: malCircleSize(cfg.skey, sMin, sMax, impl[cfg.skey]),
+            shape: 'circle',
+            label: impl.name,
+            impl: impl,
+        })
+    }
+
+    // Update the axes domain, scale and tick values
+    chart.xDomain(malExtent(allData, cfg.xkey))
+    chart.yDomain(malExtent(allData, cfg.ykey))
+    chart.xScale(malScale(cfg.xlog))
+    chart.yScale(malScale(cfg.ylog))
+    chart.xAxis.tickValues(malTickValues(cfg.xkey, cfg.xlog))
+    chart.yAxis.tickValues(malTickValues(cfg.ykey, cfg.ylog))
+
+    // Update the graph
+    d3.select('#mal svg')
+        .data([graphData])
+        .transition().duration(350).ease('linear')
+        .call(chart)
+
+    chart.update()
+
+    nv.utils.windowResize(chart.update)
+}
+
+nv.addGraph(function() {
+    chart = nv.models.scatterChart()
+        .showDistX(true)
+        .showDistY(true)
+        .showLabels(true)
+        .duration(300)
+        .color(malColors)
+    chart.dispatch.on('renderEnd', function() {
+        console.log('render complete')
+    })
+    chart.dispatch.on('stateChange', function(e) {
+        nv.log('New State:', JSON.stringify(e))
+    })
+    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>' +
+            '</p>'
+    })
+    d3.json("all_data.json", function (error, data) {
+        allData = data
+        updateGraphData()
+    })
+    return chart
+})
+
diff --git a/docs/graph/index.html b/docs/graph/index.html
new file mode 100644 (file)
index 0000000..5a5af98
--- /dev/null
@@ -0,0 +1,99 @@
+<html>
+<head>
+    <meta charset="utf-8">
+    <link href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.css" rel="stylesheet" type="text/css">
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.js"></script>
+
+    <style>
+        text {
+            font: 12px sans-serif;
+        }
+        svg {
+            display: block;
+        }
+        .impl-data {
+            text-align: left !important;
+        }
+        #title {
+            text-align: center;
+            padding: 5px;
+        }
+       #mal {
+            height: 80%;
+            width: 100%;
+       }
+        html, body, #mal, svg {
+            margin: 0px;
+            padding: 0px;
+        }
+    </style>
+</head>
+<body class='with-3d-shadow with-transitions'>
+
+<div>
+    <h2 id="title">Mal Implementation Stats</h2>
+</div>
+
+<div>
+    <table border=0>
+        <tr>
+            <th align=right>Color data:</th>
+            <td>
+                <input type="radio" class="selects" name="ckey" value="syntax">Syntax Style
+                <input type="radio" class="selects" name="ckey" value="type_check">Type Discipline
+                <input type="radio" class="selects" name="ckey" value="author_name">Author
+            </td>
+            <td>&nbsp;</td>
+            <td>&nbsp;</td>
+        </tr>
+        <tr>
+            <th align=right>X-Axis data:</th>
+            <td>
+                <input type="radio" class="selects" name="xkey" value="perf1">Perf 1
+                <input type="radio" class="selects" name="xkey" value="perf2">Perf 2
+                <input type="radio" class="selects" name="xkey" value="perf3">Perf 3
+                <input type="radio" class="selects" name="xkey" value="rank">Popularity
+                <input type="radio" class="selects" name="xkey" value="sloc">SLOC size
+                <input type="radio" class="selects" name="xkey" value="files">File count
+            </td>
+            <td>&nbsp;</td>
+            <td><input type="checkbox" class="selects" name="xlog" value=true>Logarithmic</td>
+        </tr>
+        <tr>
+            <th align=right>Y-Axis data:</th>
+            <td>
+                <input type="radio" class="selects" name="ykey" value="perf1">Perf 1
+                <input type="radio" class="selects" name="ykey" value="perf2">Perf 2
+                <input type="radio" class="selects" name="ykey" value="perf3">Perf 3
+                <input type="radio" class="selects" name="ykey" value="rank">Popularity
+                <input type="radio" class="selects" name="ykey" value="sloc">SLOC size
+                <input type="radio" class="selects" name="ykey" value="files">File count
+            </td>
+            <td>&nbsp;</td>
+            <td><input type="checkbox" class="selects" name="ylog" value=true>Logarithmic</td>
+        </tr>
+        <tr>
+            <th align=right>Circle size:</th>
+            <td>
+                <input type="radio" class="selects" name="skey" value="perf1">Perf 1
+                <input type="radio" class="selects" name="skey" value="perf2">Perf 2
+                <input type="radio" class="selects" name="skey" value="perf3">Perf 3
+                <input type="radio" class="selects" name="skey" value="rank">Popularity
+                <input type="radio" class="selects" name="skey" value="sloc">SLOC size
+                <input type="radio" class="selects" name="skey" value="files">File count
+            </td>
+            <td>&nbsp;</td>
+            <td>&nbsp;</td>
+        </tr>
+    </table>
+</div>
+
+<div id="mal" class="chartWrap">
+    <svg></svg>
+</div>
+
+<script src="graph_languages.js"></script>
+</body>
+
+</html>
diff --git a/docs/graph/package.json b/docs/graph/package.json
new file mode 100644 (file)
index 0000000..eb72dbe
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "name": "mal_graph",
+    "version": "0.0.1",
+    "description": "Graph Mal Languages",
+    "dependencies": {
+        "js-yaml": "3.12.2",
+        "request": "2.88.0",
+        "request-promise-native": "1.0.7"
+    }
+}