regen JS
authorDaniel Gruno <humbedooh@apache.org>
Wed, 17 Jan 2018 18:37:26 +0000 (19:37 +0100)
committerDaniel Gruno <humbedooh@apache.org>
Wed, 17 Jan 2018 18:37:26 +0000 (19:37 +0100)
ui/js/kibble.v1.js

index 799938f..9daf1fb 100644 (file)
@@ -1,5 +1,5 @@
-// Generated by CoffeeScript 1.9.3
-var API, APIVERSION, Chart, HTML, Row, Widget, aSourceTypes, accountCallback, addSourceType, addSources, addorguser, addsources, affiliate, affiliation, affiliationWizard, altemail, app, badModal, bio, chartOnclick, chartToSvg, chartWrapperButtons, charts_donutchart, charts_gaugechart, charts_linechart, charts_linechart_stacked, charts_linked, charts_radarchart, cog, comstat, copyCSS, currentSources, dataTable, datepicker, datepickers, defaultOrgChanged, deletesource, doResetPass, donut, downloadBlob, explorer, fScreen, factors, fetch, fetchPhonebook, filterPerson, filterView, findWidget, gauge, genColors, get, getResetToken, getSourceType, globArgs, hsl2rgb, imexplorer, inviteMember, isArray, isHash, issueexplorer, keyValueForm, kibbleLogin, kibbleLoginCallback, kibbleSignup, linechart, loadPageWidgets, logexplorer, login, mailexplorer, make5, makeOrg, manageviews, memberInvited, membershipList, messages, mk, multiviewexplorer, mvp, newview, orgCreated, orgadmin, orglist, pageID, paragraph, patch, phonebook_cached, post, postPublishLink, preferences, pubWidget, publishWidget, publisher, publisherPublic, publisherWidget, put, pwReset, quickColors, radar, radarIndicators, rcollate, redirs, relationship, remail, remorguser, removeMember, renderAccountInfo, renderPhonebook, report, resetpw, rmview, rotateTable, rowZ, saveprefs, saveview, sendEmail, set, setDefaultOrg, setupPage, setupPhonebook, showMore, showType, signout, signup, sourceAdded, sourceTypes, sourceadd, sourceexplorer, sourcelist, sourceret, st, stackChart, subFilter, subFilterGlob, swi, switchChartType, tagList, theme, toFullscreen, toNormal, top5, treemap, trend, trendBox, txt, updateTimeseriesWidgets, updateWidgets, userAccount, validateLogin, validateSignup, viewJS, viewexplorer, widgetCache, widgetexplorer, worldmap, xdelete, xxCharts,
+// Generated by CoffeeScript 1.10.0
+var API, APIVERSION, Chart, HTML, Row, Widget, aSourceTypes, accountCallback, addSourceType, addSources, addorguser, addsources, affiliate, affiliation, affiliationWizard, altemail, app, badModal, bio, chartOnclick, chartToSvg, chartWrapperButtons, charts_donutchart, charts_gaugechart, charts_linechart, charts_linechart_stacked, charts_linked, charts_radarchart, cog, comstat, copyCSS, currentSources, dataTable, datepicker, datepickers, defaultOrgChanged, deletesource, doResetPass, donut, downloadBlob, explorer, fScreen, factors, fetch, fetchPhonebook, filterPerson, filterView, findWidget, gauge, genColors, get, getResetToken, getSourceType, globArgs, hsl2rgb, imexplorer, inviteMember, isArray, isHash, issueexplorer, jsondump, keyValueForm, kibbleLogin, kibbleLoginCallback, kibbleSignup, linechart, loadPageWidgets, logexplorer, login, mailexplorer, make5, makeOrg, manageviews, memberInvited, membershipList, messages, mk, multiviewexplorer, mvp, newview, orgCreated, orgadmin, orglist, pageID, paragraph, patch, phonebook_cached, post, postPublishLink, preferences, pubWidget, publishWidget, publisher, publisherPublic, publisherWidget, put, pwReset, quickColors, radar, radarIndicators, rcollate, redirs, relationship, remail, remorguser, removeMember, renderAccountInfo, renderPhonebook, report, resetpw, rmview, rotateTable, rowZ, saveprefs, saveview, sendEmail, set, setDefaultOrg, setupPage, setupPhonebook, showMore, showType, signout, signup, sourceAdded, sourceTypes, sourceadd, sourceexplorer, sourcelist, sourceret, st, stackChart, subFilter, subFilterGlob, swi, switchChartType, tagList, theme, toFullscreen, toNormal, top5, treemap, trend, trendBox, txt, updateTimeseriesWidgets, updateWidgets, userAccount, validateLogin, validateSignup, viewJS, viewexplorer, widgetCache, widgetexplorer, worldmap, xdelete, xxCharts,
   indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
 
 signup = function(form) {
@@ -953,7 +953,7 @@ copyCSS = function(destination, source) {
 };
 
 downloadBlob = function(name, uri) {
-  var blob, e, saveLink, url;
+  var blob, e, error, saveLink, url;
   if (navigator.msSaveOrOpenBlob) {
     return navigator.msSaveOrOpenBlob(uriToBlob(uri), name);
   } else {
@@ -970,8 +970,8 @@ downloadBlob = function(name, uri) {
           return URL.revokeObjectURL(url);
         });
       };
-    } catch (_error) {
-      e = _error;
+    } catch (error) {
+      e = error;
       console.warn('This browser does not support object URLs. Falling back to string URL.');
       saveLink.href = uri;
     }
@@ -1455,7 +1455,11 @@ updateTimeseriesWidgets = function(range) {
       to: to,
       from: from
     });
-    return updateWidgets('worldmap', null, {
+    updateWidgets('worldmap', null, {
+      to: to,
+      from: from
+    });
+    return updateWidgets('jsondump', null, {
       to: to,
       from: from
     });
@@ -1660,7 +1664,10 @@ explorer = function(json, state) {
     updateWidgets('mvp', null, {
       source: source
     });
-    return updateWidgets('comstat', null, {
+    updateWidgets('comstat', null, {
+      source: source
+    });
+    return updateWidgets('jsondump', null, {
       source: source
     });
   });
@@ -1706,7 +1713,10 @@ explorer = function(json, state) {
     updateWidgets('mvp', null, {
       author: author
     });
-    return updateWidgets('comstat', null, {
+    updateWidgets('comstat', null, {
+      author: author
+    });
+    return updateWidgets('jsondump', null, {
       author: author
     });
   });
@@ -1809,9 +1819,12 @@ sourceexplorer = function(json, state) {
     updateWidgets('mvp', null, {
       source: source
     });
-    return updateWidgets('comstat', null, {
+    updateWidgets('comstat', null, {
       source: source
     });
+    return updateWidgets('jsondump', null, {
+      author: author
+    });
   });
 };
 
@@ -2274,6 +2287,7 @@ subFilter = function() {
   updateWidgets('mvp', null, x);
   updateWidgets('comstat', null, x);
   updateWidgets('worldmap', null, x);
+  updateWidgets('jsondump', null, x);
   return $("a").each(function() {
     var m, url;
     url = $(this).attr('href');
@@ -2367,6 +2381,7 @@ viewexplorer = function(json, state) {
     updateWidgets('mvp', null, x);
     updateWidgets('comstat', null, x);
     updateWidgets('worldmap', null, x);
+    updateWidgets('jsondump', null, x);
     return $("a").each(function() {
       var m, url;
       url = $(this).attr('href');
@@ -2863,7 +2878,7 @@ fetch = function(url, xstate, callback, nocreds) {
   xmlHttp.open("GET", "api/" + url, true);
   xmlHttp.send(null);
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, mpart, response;
+    var e, error, js, mpart, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -2884,8 +2899,8 @@ fetch = function(url, xstate, callback, nocreds) {
         try {
           response = JSON.parse(xmlHttp.responseText);
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -2910,7 +2925,7 @@ put = function(url, json, xstate, callback, nocreds) {
   xmlHttp.open("PUT", "api/" + url, true);
   xmlHttp.send(JSON.stringify(json || {}));
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, response;
+    var e, error, js, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -2931,8 +2946,8 @@ put = function(url, json, xstate, callback, nocreds) {
             return;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -2957,7 +2972,7 @@ patch = function(url, json, xstate, callback, nocreds) {
   xmlHttp.open("PATCH", "api/" + url, true);
   xmlHttp.send(JSON.stringify(json || {}));
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, response;
+    var e, error, js, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -2978,8 +2993,8 @@ patch = function(url, json, xstate, callback, nocreds) {
             return;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -3004,7 +3019,7 @@ xdelete = function(url, json, xstate, callback, nocreds) {
   xmlHttp.open("DELETE", "api/" + url, true);
   xmlHttp.send(JSON.stringify(json || {}));
   return xmlHttp.onreadystatechange = function(state) {
-    var e, js, response;
+    var e, error, js, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -3025,8 +3040,8 @@ xdelete = function(url, json, xstate, callback, nocreds) {
             return;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -3062,7 +3077,7 @@ post = function(url, json, xstate, callback, snap) {
   xmlHttp.setRequestHeader("Content-type", "application/json");
   xmlHttp.send(fdata);
   return xmlHttp.onreadystatechange = function(state) {
-    var e, response;
+    var e, error, response;
     if (xmlHttp.readyState === 4 && xmlHttp.status === 500) {
       if (snap) {
         snap(xstate);
@@ -3076,8 +3091,8 @@ post = function(url, json, xstate, callback, snap) {
             xstate.widget.json = response;
           }
           return callback(response, xstate);
-        } catch (_error) {
-          e = _error;
+        } catch (error) {
+          e = error;
           return callback(JSON.parse(xmlHttp.responseText), xstate);
         }
       }
@@ -3668,6 +3683,9 @@ setupPage = function(json, state) {
           case 'membership':
             results1.push(widget.load(membershipList));
             break;
+          case 'jsondump':
+            results1.push(widget.load(jsondump));
+            break;
           default:
             results1.push(void 0);
         }
@@ -4353,7 +4371,7 @@ sourceadd = function(json, state) {
     div.inject(opt);
     div.inject(lbl);
     obj.inject(new HTML('p', {}, el.description || ""));
-    obj.inject(keyValueForm('textarea', 'source', 'Source URL:', "For example: " + el.example + ". You can add multiple sources, one per line."));
+    obj.inject(keyValueForm('textarea', 'source', 'Source URL/ID:', "For example: " + el.example + ". You can add multiple sources, one per line."));
     if (el.optauth) {
       obj.inject((el.authrequired ? "Required" : "Optional") + " authentication options:");
       ref = el.optauth;
@@ -5054,6 +5072,9 @@ updateWidgets = function(type, target, eargs) {
         case 'worldmap':
           results.push(widget.load(worldmap));
           break;
+        case 'jsondump':
+          results.push(widget.load(jsondump));
+          break;
         default:
           results.push(void 0);
       }
@@ -5282,7 +5303,7 @@ Row = (function() {
 })();
 
 comstat = function(json, state) {
-  var aa, ab, chk, i, js, lb, len, len1, len2, len3, m, nl, notice, p, person, q, ref, ref1, ref2, ref3, row, stbl, tb, tbl, tr, u, widget;
+  var aa, ab, chk, hash, i, js, key, lb, len, len1, len2, len3, m, nl, notice, oemail, p, person, q, ref, ref1, ref2, ref3, repo, row, stbl, tb, tbl, tr, u, url, widget;
   if (json && json.stats) {
     row = new Row();
     p = new HTML('p', {}, globArgs.committersOnly === 'true' ? "You are currently only seeing stats for committers. To view statistics for all contributors (committers and authors), please uncheck the box below:" : "You are currently seeing stats for both committership and authorship of code. To view only committership stats, tick the box below:");
@@ -5304,9 +5325,8 @@ comstat = function(json, state) {
       js = {
         alphaSort: true,
         counts: {
-          "Regulars": json.stats.code.seen - json.stats.code.newcomers - json.stats.code.returning,
-          "Newcomers": json.stats.code.newcomers,
-          "Returning": json.stats.code.returning
+          "Regulars": json.stats.code.seen - json.stats.code.newcomers.length,
+          "Newcomers": json.stats.code.newcomers.length
         }
       };
       widget = new Widget(4, {
@@ -5321,23 +5341,27 @@ comstat = function(json, state) {
         widget: widget
       });
       nl = 0;
-      if (json.stats.code.newtbl.length && json.stats.code.newtbl.length >= 0) {
-        nl = json.stats.code.newtbl.length;
+      if (json.stats.code.newcomers.length && json.stats.code.newcomers.length >= 0) {
+        nl = json.stats.code.newcomers.length;
       }
-      stbl = new Widget(4, {
+      stbl = new Widget(6, {
         name: "New code contributors (" + nl + ")"
       });
       tbl = mk('table', {
         "class": "table table-striped"
       });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address")]);
+      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "First commit")]);
       app(tbl, tr);
       tb = new HTML('tbody');
-      ref = json.stats.code.newtbl;
+      ref = json.stats.code.newcomers;
       for (i = q = 0, len = ref.length; q < len; i = ++q) {
         person = ref[i];
+        oemail = person;
+        hash = json.bios[person].code[1].id.split('/')[1];
+        repo = json.bios[person].code[1].sourceURL;
+        person = json.bios[person].bio;
         if (i > 6) {
-          m = json.stats.code.newtbl.length - 7;
+          m = json.stats.code.newcomers.length - 7;
           tr = mk('tr', {
             scope: 'row'
           }, [
@@ -5359,8 +5383,8 @@ comstat = function(json, state) {
             "class": "img-circle img-responsive",
             src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
           })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address)
+            href: "?page=people&email=" + oemail
+          }, person.name)), mk('td', {}, oemail), mk('td', {}, repo + " / " + hash)
         ]);
         tb.inject(tr);
       }
@@ -5393,9 +5417,8 @@ comstat = function(json, state) {
       js = {
         alphaSort: true,
         counts: {
-          "Regulars": json.stats.issues.seen - json.stats.issues.newcomers - json.stats.issues.returning,
-          "Newcomers": json.stats.issues.newcomers,
-          "Returning": json.stats.issues.returning
+          "Regulars": json.stats.issues.seen - json.stats.issues.newcomers.length,
+          "Newcomers": json.stats.issues.newcomers.length
         }
       };
       widget = new Widget(4, {
@@ -5410,23 +5433,27 @@ comstat = function(json, state) {
         widget: widget
       });
       nl = 0;
-      if (json.stats.issues.newtbl.length && json.stats.issues.newtbl.length >= 0) {
-        nl = json.stats.issues.newtbl.length;
+      if (json.stats.issues.newcomers.length && json.stats.issues.newcomers.length >= 0) {
+        nl = json.stats.issues.newcomers.length;
       }
-      stbl = new Widget(4, {
+      stbl = new Widget(6, {
         name: "New issue contributors (" + nl + ")"
       });
       tbl = mk('table', {
         "class": "table table-striped"
       });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address")]);
+      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "First issue")]);
       app(tbl, tr);
       tb = new HTML('tbody');
-      ref1 = json.stats.issues.newtbl;
+      ref1 = json.stats.issues.newcomers;
       for (i = u = 0, len1 = ref1.length; u < len1; i = ++u) {
         person = ref1[i];
+        oemail = person;
+        url = json.bios[person].issue[1].sourceURL;
+        key = json.bios[person].issue[1].key || url;
+        person = json.bios[person].bio;
         if (i > 6) {
-          m = json.stats.issues.newtbl.length - 7;
+          m = json.stats.issues.newcomers.length - 7;
           tr = mk('tr', {
             scope: 'row'
           }, [
@@ -5448,8 +5475,10 @@ comstat = function(json, state) {
             "class": "img-circle img-responsive",
             src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
           })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address)
+            href: "?page=people&email=" + oemail
+          }, person.name)), mk('td', {}, oemail), mk('td', {}, mk('a', {
+            href: url || "#"
+          }, txt(key)))
         ]);
         tb.inject(tr);
       }
@@ -5457,7 +5486,7 @@ comstat = function(json, state) {
       stbl.inject(tbl);
       row.inject(stbl);
       if (json.stats.issues.timeseries && json.stats.issues.timeseries.length > 0) {
-        widget = new Widget(4, {
+        widget = new Widget(6, {
           name: "New issue contributors over time:",
           representation: 'bars'
         });
@@ -5477,89 +5506,91 @@ comstat = function(json, state) {
       }
       state.widget.inject(row.div);
     }
-    if (json.stats.converts.issue_to_code.length && json.stats.converts.issue_to_code.length > 0) {
-      row = new Row();
-      stbl = new Widget(6, {
-        name: "Previous issue contributors who are now contributing code:"
-      });
-      tbl = mk('table', {
-        "class": "table table-striped"
-      });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first issue to first code contribution:")]);
-      app(tbl, tr);
-      tb = new HTML('tbody');
-      ref2 = json.stats.converts.issue_to_code;
-      for (i = aa = 0, len2 = ref2.length; aa < len2; i = ++aa) {
-        person = ref2[i];
-        if (i > 20) {
-          break;
+    if (json.stats.converts) {
+      if (json.stats.converts.issue_to_code.length && json.stats.converts.issue_to_code.length > 0) {
+        row = new Row();
+        stbl = new Widget(6, {
+          name: "Previous issue contributors who are now contributing code:"
+        });
+        tbl = mk('table', {
+          "class": "table table-striped"
+        });
+        tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first issue to first code contribution:")]);
+        app(tbl, tr);
+        tb = new HTML('tbody');
+        ref2 = json.stats.converts.issue_to_code;
+        for (i = aa = 0, len2 = ref2.length; aa < len2; i = ++aa) {
+          person = ref2[i];
+          if (i > 20) {
+            break;
+          }
+          tr = mk('tr', {
+            scope: 'row'
+          }, [
+            mk('td', {}, new HTML('img', {
+              style: {
+                width: '32px',
+                height: '32px'
+              },
+              "class": "img-circle img-responsive",
+              src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
+            })), mk('td', {}, mk('a', {
+              href: "?page=people&email=" + person.address
+            }, person.name)), mk('td', {}, person.address), mk('td', {
+              style: {
+                textAlign: 'right'
+              }
+            }, (Math.floor(person.tdiff / 86400.)).pretty())
+          ]);
+          tb.inject(tr);
         }
-        tr = mk('tr', {
-          scope: 'row'
-        }, [
-          mk('td', {}, new HTML('img', {
-            style: {
-              width: '32px',
-              height: '32px'
-            },
-            "class": "img-circle img-responsive",
-            src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
-          })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address), mk('td', {
-            style: {
-              textAlign: 'right'
-            }
-          }, (Math.floor(person.tdiff / 86400.)).pretty())
-        ]);
-        tb.inject(tr);
-      }
-      app(tbl, tb);
-      stbl.inject(tbl);
-      row.inject(stbl);
-      state.widget.inject(row.div);
-    }
-    if (json.stats.converts.email_to_code.length && json.stats.converts.email_to_code.length > 0) {
-      row = new Row();
-      stbl = new Widget(6, {
-        name: "Previous email authors who are now contributing code:"
-      });
-      tbl = mk('table', {
-        "class": "table table-striped"
-      });
-      tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first email to first code contribution:")]);
-      app(tbl, tr);
-      tb = new HTML('tbody');
-      ref3 = json.stats.converts.email_to_code;
-      for (i = ab = 0, len3 = ref3.length; ab < len3; i = ++ab) {
-        person = ref3[i];
-        if (i > 20) {
-          break;
+        app(tbl, tb);
+        stbl.inject(tbl);
+        row.inject(stbl);
+        state.widget.inject(row.div);
+      }
+      if (json.stats.converts.email_to_code.length && json.stats.converts.email_to_code.length > 0) {
+        row = new Row();
+        stbl = new Widget(6, {
+          name: "Previous email authors who are now contributing code:"
+        });
+        tbl = mk('table', {
+          "class": "table table-striped"
+        });
+        tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first email to first code contribution:")]);
+        app(tbl, tr);
+        tb = new HTML('tbody');
+        ref3 = json.stats.converts.email_to_code;
+        for (i = ab = 0, len3 = ref3.length; ab < len3; i = ++ab) {
+          person = ref3[i];
+          if (i > 20) {
+            break;
+          }
+          tr = mk('tr', {
+            scope: 'row'
+          }, [
+            mk('td', {}, new HTML('img', {
+              style: {
+                width: '32px',
+                height: '32px'
+              },
+              "class": "img-circle img-responsive",
+              src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
+            })), mk('td', {}, mk('a', {
+              href: "?page=people&email=" + person.address
+            }, person.name)), mk('td', {}, person.address), mk('td', {
+              style: {
+                textAlign: 'right'
+              }
+            }, (Math.floor(person.tdiff / 86400.)).pretty())
+          ]);
+          tb.inject(tr);
         }
-        tr = mk('tr', {
-          scope: 'row'
-        }, [
-          mk('td', {}, new HTML('img', {
-            style: {
-              width: '32px',
-              height: '32px'
-            },
-            "class": "img-circle img-responsive",
-            src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon"
-          })), mk('td', {}, mk('a', {
-            href: "?page=people&email=" + person.address
-          }, person.name)), mk('td', {}, person.address), mk('td', {
-            style: {
-              textAlign: 'right'
-            }
-          }, (Math.floor(person.tdiff / 86400.)).pretty())
-        ]);
-        tb.inject(tr);
+        app(tbl, tb);
+        stbl.inject(tbl);
+        row.inject(stbl);
+        return state.widget.inject(row.div);
       }
-      app(tbl, tb);
-      stbl.inject(tbl);
-      row.inject(stbl);
-      return state.widget.inject(row.div);
     }
   } else {
     notice = new HTML('h2', {}, "Community growth stats only works with user-defined views!");
@@ -5737,6 +5768,17 @@ factors = function(json, state) {
   }
 };
 
+jsondump = function(json, state) {
+  var pre;
+  pre = new HTML('pre', {
+    style: {
+      whiteSpace: 'pre-wrap'
+    }
+  });
+  pre.inject(JSON.stringify(json, null, 2));
+  return state.widget.inject(pre, true);
+};
+
 linechart = function(json, state) {
   var aa, ab, cat, catdata, cats, catseries, chartBox, chk, dates, div, filled, from, id, item, key, label, len, len1, len2, len3, list, m, opt, point, q, range, ref, ref1, ref2, ref3, rv, stack, tName, to, type, u, val;
   div = document.createElement('div');