@flourish/sdk 5.2.4 → 5.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.mocha-reporters.json +6 -0
  2. package/.mocharc.ci.json +6 -0
  3. package/RELEASE_NOTES.md +6 -0
  4. package/common/embed/embedding.js +16 -1
  5. package/common/package.json +2 -2
  6. package/common/tsconfig.sdk.tsbuildinfo +1 -1
  7. package/common/utils/data.d.ts +2 -2
  8. package/common/utils/data.js +9 -8
  9. package/common/utils/types.d.ts +1 -0
  10. package/package.json +6 -4
  11. package/server/columns.js +66 -15
  12. package/server/comms_js.js +7 -0
  13. package/server/data.js +210 -15
  14. package/server/index_html.js +61 -20
  15. package/server/json.js +27 -1
  16. package/server/views/index.html +1 -0
  17. package/site/embedded.js +1 -1
  18. package/site/images/icon-open-external.svg +3 -0
  19. package/site/images/icon-plus.svg +3 -0
  20. package/site/images/icon-refresh.svg +3 -0
  21. package/site/images/icon-replace.svg +6 -0
  22. package/site/images/icon-unlink.svg +5 -0
  23. package/site/script.js +2 -2
  24. package/site/sdk.css +2 -2
  25. package/skeleton/package.json +2 -2
  26. package/coverage-sdk/lcov-report/base.css +0 -224
  27. package/coverage-sdk/lcov-report/block-navigation.js +0 -87
  28. package/coverage-sdk/lcov-report/common/utils/columns.js.html +0 -646
  29. package/coverage-sdk/lcov-report/common/utils/index.html +0 -131
  30. package/coverage-sdk/lcov-report/common/utils/state.js.html +0 -559
  31. package/coverage-sdk/lcov-report/favicon.png +0 -0
  32. package/coverage-sdk/lcov-report/index.html +0 -146
  33. package/coverage-sdk/lcov-report/lib/common.js.html +0 -181
  34. package/coverage-sdk/lcov-report/lib/index.html +0 -161
  35. package/coverage-sdk/lcov-report/lib/log.js.html +0 -178
  36. package/coverage-sdk/lcov-report/lib/sdk.js.html +0 -2008
  37. package/coverage-sdk/lcov-report/lib/validate_config.js.html +0 -1459
  38. package/coverage-sdk/lcov-report/prettify.css +0 -1
  39. package/coverage-sdk/lcov-report/prettify.js +0 -2
  40. package/coverage-sdk/lcov-report/sort-arrow-sprite.png +0 -0
  41. package/coverage-sdk/lcov-report/sorter.js +0 -210
  42. package/coverage-sdk/lcov-report/test/lib/index.html +0 -131
  43. package/coverage-sdk/lcov-report/test/lib/sdk.js.html +0 -532
  44. package/coverage-sdk/lcov-report/test/lib/validate_config.js.html +0 -3307
  45. package/coverage-sdk/lcov.info +0 -3556
  46. package/coverage-sdk/tmp/coverage-36833-1757890375186-0.json +0 -1
  47. package/coverage-sdk/tmp/coverage-36834-1757890374890-0.json +0 -1
package/server/data.js CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  Object.defineProperty(exports, '__esModule', { value: true });
8
8
 
9
+ var interpreter$1 = require('@flourish/interpreter');
10
+
9
11
  // Polyfills for IE11 and Edge
10
12
 
11
13
  // Add findIndex method to Array
@@ -37,17 +39,47 @@ if (!Array.prototype.findIndex) {
37
39
  });
38
40
  }
39
41
 
40
- function extractData(data_binding, data_by_id) {
42
+ function extractData(data_binding, data_by_id, column_types_by_id, template_data_binding) {
41
43
  var columns = [];
42
44
  var data_table_ids = [];
43
45
  var num_rows = 0;
44
46
  var dataset = [];
47
+ var interpreters_by_id = {};
45
48
  dataset.column_names = {};
49
+ dataset.metadata = {};
50
+
51
+ function getInterpretationIds(data_table_id, column_index) {
52
+ if (!interpreters_by_id[data_table_id]) return {};
53
+ var by_column_index = interpreters_by_id[data_table_id];
54
+ if (!by_column_index[column_index]) return {};
55
+ return by_column_index[column_index];
56
+ }
57
+
58
+ function getInterpreter(data_table_id, column_index) {
59
+ const { type_id } = getInterpretationIds(data_table_id, column_index);
60
+ if (type_id) return interpreter$1.createInterpreter.getInterpretation(type_id);
61
+ }
62
+
63
+ for (var data_table_id in column_types_by_id) {
64
+ var lookup = {};
65
+ var column_types = column_types_by_id[data_table_id];
66
+ if (!column_types) continue;
67
+
68
+ for (let i = 0; i < column_types.length; i++) {
69
+ const type_id = column_types[i].type_id;
70
+ const of_id = column_types[i].output_format_id;
71
+ const output_format_id = (!of_id || of_id === "auto") ? type_id : of_id;
72
+ lookup[column_types[i].index] = { type_id, output_format_id };
73
+ }
74
+ interpreters_by_id[data_table_id] = lookup;
75
+ }
46
76
 
47
77
  for (var key in data_binding) {
78
+ if (data_binding[key] === null) continue;
48
79
  if (data_binding[key].columns === undefined && data_binding[key].column === undefined) continue;
49
80
 
50
81
  var b = data_binding[key];
82
+ b.template_data_binding = template_data_binding[key];
51
83
  b.key = key;
52
84
 
53
85
  if (!(b.data_table_id in data_by_id)) {
@@ -68,11 +100,30 @@ function extractData(data_binding, data_by_id) {
68
100
  var column_count = data_table[0].length;
69
101
  b.columns = b.columns.filter(function(i) { return i < column_count; });
70
102
  dataset.column_names[key] = b.columns.map(function(i) {
71
- return data_by_id[b.data_table_id][0][i];
103
+ return data_table[0][i];
104
+ });
105
+ dataset.metadata[key] = b.columns.map(function(i) {
106
+ const { type_id, output_format_id } = getInterpretationIds(b.data_table_id, i);
107
+ if (type_id) {
108
+ return {
109
+ type: type_id.split("$")[0],
110
+ type_id,
111
+ output_format_id: output_format_id
112
+ };
113
+ }
114
+ return null;
72
115
  });
73
116
  }
74
117
  else if ("column" in b && b.column != null) {
75
118
  dataset.column_names[key] = data_table[0][b.column];
119
+ const { type_id, output_format_id } = getInterpretationIds(b.data_table_id, b.column);
120
+ if (type_id) {
121
+ dataset.metadata[key] = {
122
+ type: type_id.split("$")[0],
123
+ type_id,
124
+ output_format_id: output_format_id
125
+ };
126
+ }
76
127
  }
77
128
  else {
78
129
  throw new Error("Data binding includes no column(s) specification: " + JSON.stringify(b));
@@ -80,11 +131,23 @@ function extractData(data_binding, data_by_id) {
80
131
 
81
132
  if (data_table_ids.indexOf(b.data_table_id) == -1) {
82
133
  data_table_ids.push(b.data_table_id);
83
- num_rows = Math.max(num_rows, data_by_id[b.data_table_id].length - 1);
134
+ num_rows = Math.max(num_rows, data_table.length - 1);
84
135
  }
85
136
  columns.push(b);
86
137
  }
87
138
 
139
+ function parse(b, column_index, string_value) {
140
+ if (!b.template_data_binding.data_type) return string_value;
141
+ var interpreter = getInterpreter(b.data_table_id, column_index);
142
+ if (interpreter && interpreter.type == "number") string_value = stripCommonFixes(string_value);
143
+ var result = interpreter ? interpreter.parse(string_value) : string_value;
144
+
145
+ // We require our marshalled data to be JSON-serialisable,
146
+ // therefore we convert NaNs to null here.
147
+ if (Number.isNaN(result)) result = null;
148
+ return result;
149
+ }
150
+
88
151
  for (var i = 0; i < num_rows; i++) {
89
152
  var o = {};
90
153
  for (var j = 0; j < columns.length; j++) {
@@ -95,22 +158,60 @@ function extractData(data_binding, data_by_id) {
95
158
  if ("columns" in b && b.columns != null) {
96
159
  o[b.key] = b.columns
97
160
  .filter(function(c) { return c < table[i+1].length; })
98
- .map(function(c) { return table[i+1][c]; });
161
+ .map(function(c) { return parse(b, c, table[i+1][c]); });
99
162
  }
100
163
  else if ("column" in b && b.column != null) {
101
- if (b.column >= table[i+1].length) o[b.key] = "";
102
- else o[b.key] = table[i+1][b.column];
164
+ if (b.column >= table[i+1].length) o[b.key] = parse(b, b.column, "");
165
+ else o[b.key] = parse(b, b.column, table[i+1][b.column]);
103
166
  }
104
167
  }
105
168
  dataset.push(o);
106
169
  }
107
-
108
170
  return dataset;
109
171
  }
110
172
 
173
+ function getColumnTypesForData(data) {
174
+ return transposeNestedArray(data)
175
+ .map(function(column, i) {
176
+ const sliced_column = getSlicedData(column);
177
+ const sample_size = 1000;
178
+ let sample_data;
179
+ if (sliced_column.length > (sample_size * 2)) sample_data = getRandomSeededSample(sliced_column, sample_size);
180
+ else sample_data = sliced_column;
181
+ const type_id = interpretColumn(sample_data)[0].id;
182
+ return { type_id: type_id, index: i, output_format_id: type_id };
183
+ });
184
+ }
185
+
186
+ // Returns a random seeded sample of column values based on the column length.
187
+ // The sample is consistent and will update if the length of column changes.
188
+ function getRandomSeededSample(column, sample_size) {
189
+ if (column.length <= sample_size * 2) return column;
190
+ const rng = mulberry32(column.length);
191
+
192
+ while (column.length > sample_size) {
193
+ const random_index = Math.floor(rng() * column.length);
194
+
195
+ column.splice(random_index, 1);
196
+ }
197
+
198
+ return column;
199
+ }
200
+
201
+ // Seeded RNG implementation taken from https://github.com/bryc/code/blob/master/jshash/PRNGs.md#mulberry32
202
+ function mulberry32(seed) {
203
+ let a = seed;
204
+ return function() {
205
+ a |= 0; a = a + 0x6D2B79F5 | 0;
206
+ var t = Math.imul(a ^ a >>> 15, 1 | a);
207
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
208
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
209
+ };
210
+ }
211
+
111
212
  function trimTrailingEmptyRows(data) {
112
- for (var i = data.length; i-- > 0;) {
113
- if (!data[i] || !data[i].length || data[i].findIndex(function(col) { return col !== null && col !== ""; }) == -1) {
213
+ for (var i = data.length; i-- > 1;) {
214
+ if (!data[i] || !data[i].length || (Array.isArray(data[i]) && data[i].findIndex(function(col) { return col !== null && col !== ""; }) == -1)) {
114
215
  data.splice(i, 1);
115
216
  }
116
217
  else break;
@@ -118,15 +219,109 @@ function trimTrailingEmptyRows(data) {
118
219
  return data;
119
220
  }
120
221
 
121
- function trimWhitespace(data) {
122
- data.forEach(function(row) {
123
- for (var i=0; i < row.length; i++) {
124
- if (row[i] && typeof row[i] == "string") row[i] = row[i].trim();
222
+ function dropReturnCharacters(data) {
223
+ for (const row of data) {
224
+ for (let i = 0; i < row.length; i++) {
225
+ // Due to a bug in HoT, pasting long lines from Excel can lead to the addition of
226
+ // a newline character and a space *before* a space character.
227
+ // This leads to a pattern of new line character followed by two spaces.
228
+ // Here we identify that pattern and revert it.
229
+ row[i] = row[i].replace(/(\r\n|\n|\r) {2}/g, " ");
125
230
  }
126
- });
231
+ }
127
232
  return data;
128
233
  }
129
234
 
235
+ /**
236
+ * Takes an array of arrays (typically tabular data) and rewrites
237
+ * it so that:
238
+ * - Any trailing empty rows are removed
239
+ * - Any cell that was not a string is stringified
240
+ * - Any leading or trailing whitespace of a cell is removed
241
+ *
242
+ * (The potentially modified table is returned to match the convention
243
+ * used by functions this is replacing, although (TODO) I think it
244
+ * would be more obvious that this function has side-effects if it
245
+ * did not return the table and the calling code was changed.)
246
+ *
247
+ * @param {any[][]} data
248
+ * @returns {string[][]}
249
+ */
250
+ function tidyTable(data) {
251
+ trimTrailingEmptyRows(data);
252
+ for (let row of data) {
253
+ for (let i = 0; i < row.length; i++) {
254
+ let value = row[i];
255
+ // Convert null or undefined values to the empty string
256
+ if (value == null) value = "";
257
+ // If the value is not a string, convert it to one
258
+ if (typeof value !== "string") {
259
+ value = "" + value;
260
+ }
261
+ // Now value is a definitely a string, strip any leading
262
+ // or trailing whitespace.
263
+ row[i] = value.trim();
264
+ }
265
+ }
266
+ return data;
267
+ }
268
+
269
+
270
+ var ERROR_STRINGS = ["#DIV/0", "#N/A", "#NAME?", "#NULL!", "#NUM!", "#REF!", "#VALUE!", "#ERROR!"];
271
+ var interpreter = interpreter$1.createInterpreter().nMax(Infinity).nFailingValues(8).failureFraction(0.1);
272
+
273
+
274
+ function stripCommonFixes(str) {
275
+ str = str || "";
276
+ return str.replace(/[€£$¥%º]/g, "");
277
+ }
278
+
279
+
280
+ function transposeNestedArray(nested_array) {
281
+ var n_inner = nested_array.length;
282
+ var n_outer = n_inner > 0 ? nested_array[0].length : 0;
283
+ var transposed_array = [];
284
+
285
+ for (var i = 0; i < n_outer; i++) {
286
+ var data = [];
287
+ for (var j = 0; j < n_inner; j++) {
288
+ data.push(nested_array[j][i]);
289
+ }
290
+ transposed_array.push(data);
291
+ }
292
+
293
+ return transposed_array;
294
+ }
295
+
296
+
297
+ function getSlicedData(arr) {
298
+ const n = arr.length;
299
+ if (n > 100) return arr.slice(10, n - 10);
300
+ if (n > 50) return arr.slice(5, n - 5);
301
+ if (n > 30) return arr.slice(4, n - 4);
302
+ if (n > 20) return arr.slice(3, n - 3);
303
+ if (n > 10) return arr.slice(2, n - 2);
304
+ if (n > 1) return arr.slice(1, n);
305
+ return arr.slice(0, 1);
306
+ }
307
+
308
+
309
+ function interpretColumn(arr) {
310
+ var idata = arr.filter(function(d) {
311
+ return d && !ERROR_STRINGS.includes(d.trim());
312
+ })
313
+ .map(stripCommonFixes);
314
+ return interpreter(idata);
315
+ }
316
+
317
+ exports.dropReturnCharacters = dropReturnCharacters;
130
318
  exports.extractData = extractData;
319
+ exports.getColumnTypesForData = getColumnTypesForData;
320
+ exports.getRandomSeededSample = getRandomSeededSample;
321
+ exports.getSlicedData = getSlicedData;
322
+ exports.interpretColumn = interpretColumn;
323
+ exports.mulberry32 = mulberry32;
324
+ exports.stripCommonFixes = stripCommonFixes;
325
+ exports.tidyTable = tidyTable;
326
+ exports.transposeNestedArray = transposeNestedArray;
131
327
  exports.trimTrailingEmptyRows = trimTrailingEmptyRows;
132
- exports.trimWhitespace = trimWhitespace;
@@ -1,9 +1,48 @@
1
1
  "use strict";
2
- const URL = require("url");
3
- const parse5 = require("parse5"), RewriteLinks = require("rewrite-links");
4
- const { defaultTreeAdapter: TA } = require("parse5");
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const url_1 = __importDefault(require("url"));
40
+ const parse5 = __importStar(require("parse5"));
41
+ // @ts-expect-error no type definitions exist for rewrite-links
42
+ const rewrite_links_1 = __importDefault(require("rewrite-links"));
43
+ const parse5_1 = require("parse5");
5
44
  function findChild(node, nodeName, ok_if_not_found) {
6
- for (const child of TA.getChildNodes(node)) {
45
+ for (const child of parse5_1.defaultTreeAdapter.getChildNodes(node)) {
7
46
  if (child.nodeName == nodeName) {
8
47
  return child;
9
48
  }
@@ -26,45 +65,45 @@ function replaceTitle(document, title) {
26
65
  const head = findHead(document);
27
66
  let title_node = findChild(head, "title", true);
28
67
  if (title_node) {
29
- for (const child of TA.getChildNodes(title_node)) {
30
- TA.detachNode(child);
68
+ for (const child of parse5_1.defaultTreeAdapter.getChildNodes(title_node)) {
69
+ parse5_1.defaultTreeAdapter.detachNode(child);
31
70
  }
32
71
  }
33
72
  else {
34
- title_node = TA.createElement("title", head.namespaceURI, []);
35
- TA.appendChild(head, title_node);
73
+ title_node = parse5_1.defaultTreeAdapter.createElement("title", head.namespaceURI, []);
74
+ parse5_1.defaultTreeAdapter.appendChild(head, title_node);
36
75
  }
37
- TA.insertText(title_node, title);
76
+ parse5_1.defaultTreeAdapter.insertText(title_node, title);
38
77
  }
39
78
  function appendFragmentToBody(document, fragment) {
40
79
  const body = findBody(document);
41
- for (const child of TA.getChildNodes(fragment)) {
42
- TA.appendChild(body, child);
80
+ for (const child of parse5_1.defaultTreeAdapter.getChildNodes(fragment)) {
81
+ parse5_1.defaultTreeAdapter.appendChild(body, child);
43
82
  }
44
83
  }
45
84
  function insertOembedLink(document, oembed_url) {
46
85
  const head = findHead(document);
47
- const link_node = TA.createElement("link", head.namespaceURI, [
86
+ const link_node = parse5_1.defaultTreeAdapter.createElement("link", head.namespaceURI, [
48
87
  { name: "rel", value: "alternate" },
49
88
  { name: "type", value: "application/json+oembed" },
50
89
  { name: "href", value: oembed_url },
51
90
  ]);
52
- TA.appendChild(head, link_node);
91
+ parse5_1.defaultTreeAdapter.appendChild(head, link_node);
53
92
  }
54
93
  function insertCanonicalLink(document, canonical_url) {
55
94
  const head = findHead(document);
56
- const link_node = TA.createElement("link", head.namespaceURI, [
95
+ const link_node = parse5_1.defaultTreeAdapter.createElement("link", head.namespaceURI, [
57
96
  { name: "rel", value: "canonical" },
58
97
  { name: "href", value: canonical_url },
59
98
  ]);
60
- TA.appendChild(head, link_node);
99
+ parse5_1.defaultTreeAdapter.appendChild(head, link_node);
61
100
  }
62
101
  function rewriteLinks(document, static_prefix) {
63
102
  if (!static_prefix.endsWith("/")) {
64
103
  static_prefix += "/";
65
104
  }
66
- const rewriter = new RewriteLinks(function (url) {
67
- // We dont want to rewrite URLs that are just fragment identifiers
105
+ const rewriter = new rewrite_links_1.default(function (url) {
106
+ // We don't want to rewrite URLs that are just fragment identifiers
68
107
  if (url.startsWith("#")) {
69
108
  return url;
70
109
  }
@@ -72,12 +111,12 @@ function rewriteLinks(document, static_prefix) {
72
111
  if (url == "" || url == ".") {
73
112
  return url;
74
113
  }
75
- return URL.resolve(static_prefix, url); // eslint-disable-line node/no-deprecated-api
114
+ return url_1.default.resolve(static_prefix, url); // eslint-disable-line node/no-deprecated-api
76
115
  });
77
116
  return rewriter.rewriteDocument(document);
78
117
  }
79
118
  async function render(template_text, params) {
80
- const document = parse5.parse(template_text), script_fragment = params.parsed_script || parse5.parseFragment(params.script);
119
+ const document = parse5.parse(template_text), script_fragment = params.parsed_script || parse5.parseFragment(params.script || "");
81
120
  replaceTitle(document, params.title);
82
121
  if (params.canonical_url) {
83
122
  insertCanonicalLink(document, params.canonical_url);
@@ -89,5 +128,7 @@ async function render(template_text, params) {
89
128
  const rewritten_document = await rewriteLinks(document, params.static);
90
129
  return parse5.serialize(rewritten_document);
91
130
  }
92
- exports.render = render;
131
+ exports.default = {
132
+ render,
133
+ };
93
134
  //# sourceMappingURL=index_html.js.map
package/server/json.js CHANGED
@@ -20,8 +20,33 @@ function safeStringify(obj) {
20
20
  return raw.replace(/[\u2028\u2029<]/g, escapeChar);
21
21
  }
22
22
 
23
+ function javaScriptStringify(v) {
24
+ var type = typeof v;
25
+ if (v == null) {
26
+ // Catches both null and undefined
27
+ return "null";
28
+ }
29
+ else if (type === "number" || type === "boolean" || type === "bigint" || type === "string" || type === "symbol") {
30
+ return safeStringify(v);
31
+ }
32
+ if (Array.isArray(v)) {
33
+ return "[" + v.map(javaScriptStringify).join(",") + "]";
34
+ }
35
+ else if (v instanceof Date) {
36
+ return "new Date(" + v.getTime() + ")";
37
+ }
38
+ else if (Object.prototype.toString.call(v) === "[object Object]") {
39
+ return "{" + Object.keys(v).map(function (k) {
40
+ return safeStringify(k) + ":" + javaScriptStringify(v[k]);
41
+ }) + "}";
42
+ }
43
+ else {
44
+ throw new Error("javaScriptStringify couldn't handle " + type + " object: " + v);
45
+ }
46
+ }
47
+
23
48
  function stringifyDataset(dataset) {
24
- return "(function(array, fields){ array.column_names = fields; return array; })(" + safeStringify(dataset) + ", " + safeStringify(dataset.column_names) + ")";
49
+ return "(function(array, column_names, metadata){ array.column_names = column_names; array.metadata = metadata; return array; })(" + javaScriptStringify(dataset) + ", " + safeStringify(dataset.column_names) + ", " + safeStringify(dataset.metadata) + ")";
25
50
  }
26
51
 
27
52
  function stringifyPreparedData(data) {
@@ -36,5 +61,6 @@ function stringifyPreparedData(data) {
36
61
  return s;
37
62
  }
38
63
 
64
+ exports.javaScriptStringify = javaScriptStringify;
39
65
  exports.safeStringify = safeStringify;
40
66
  exports.stringifyPreparedData = stringifyPreparedData;
@@ -11,6 +11,7 @@
11
11
 
12
12
 
13
13
  <link rel="stylesheet" type="text/css" href="/sdk.css">
14
+
14
15
  <script data-ot-ignore src="/script.js" charset="utf-8"></script>
15
16
  </head>
16
17
  <body class="sdk">