+
+ let vals = template.map(keys.sort(compare), function (f) f[1], "\n");
+ if (color) {
+ return ["div", { style: "white-space: pre-wrap" }, head, vals];
+ }
+ return head + vals.join("");
+ },
+
+ prettifyJSON: function prettifyJSON(data, indent, invalidOK) {
+ const INDENT = indent || " ";
+
+ function rec(data, level, seen) {
+ if (isObject(data)) {
+ if (~seen.indexOf(data))
+ throw Error("Recursive object passed");
+ seen = seen.concat([data]);
+ }
+
+ let prefix = level + INDENT;
+
+ if (data === undefined)
+ data = null;
+
+ if (~["boolean", "number"].indexOf(typeof data) || data === null)
+ res.push(String(data));
+ else if (isinstance(data, ["String", _]))
+ res.push(JSON.stringify(String(data)));
+ else if (isArray(data)) {
+ if (data.length == 0)
+ res.push("[]");
+ else {
+ res.push("[\n")
+ for (let [i, val] in Iterator(data)) {
+ if (i)
+ res.push(",\n");
+ res.push(prefix)
+ rec(val, prefix, seen);
+ }
+ res.push("\n", level, "]");
+ }
+ }
+ else if (isObject(data)) {
+ res.push("{\n")
+
+ let i = 0;
+ for (let [key, val] in Iterator(data)) {
+ if (i++)
+ res.push(",\n");
+ res.push(prefix, JSON.stringify(key), ": ")
+ rec(val, prefix, seen);
+ }
+ if (i > 0)
+ res.push("\n", level, "}")
+ else
+ res[res.length - 1] = "{}";
+ }
+ else if (invalidOK)
+ res.push({}.toString.call(data));
+ else
+ throw Error("Invalid JSON object");
+ }
+
+ let res = [];
+ rec(data, "", []);
+ return res.join("");