clarity-js 0.7.3 → 0.7.5

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.
package/build/clarity.js CHANGED
@@ -1,23 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var dom = /*#__PURE__*/Object.freeze({
4
- __proto__: null,
5
- get add () { return add; },
6
- get get () { return get; },
7
- get getId () { return getId; },
8
- get getNode () { return getNode; },
9
- get getValue () { return getValue; },
10
- get has () { return has; },
11
- get hashText () { return hashText; },
12
- get iframe () { return iframe; },
13
- get lookup () { return lookup; },
14
- get parse () { return parse$1; },
15
- get sameorigin () { return sameorigin; },
16
- get start () { return start$i; },
17
- get stop () { return stop$g; },
18
- get update () { return update$1; },
19
- get updates () { return updates$2; }
20
- });
21
3
  var upload$1 = /*#__PURE__*/Object.freeze({
22
4
  __proto__: null,
23
5
  get queue () { return queue; },
@@ -30,11 +12,11 @@ var extract = /*#__PURE__*/Object.freeze({
30
12
  get clone () { return clone; },
31
13
  get compute () { return compute$4; },
32
14
  get data () { return data$5; },
33
- get fragments () { return fragments; },
34
15
  get keys () { return keys; },
35
16
  get reset () { return reset$4; },
36
17
  get start () { return start$c; },
37
18
  get stop () { return stop$b; },
19
+ get trigger () { return trigger$1; },
38
20
  get update () { return update; }
39
21
  });
40
22
  var limit = /*#__PURE__*/Object.freeze({
@@ -137,7 +119,6 @@ var config$1 = {
137
119
  mask: [],
138
120
  unmask: [],
139
121
  regions: [],
140
- extract: [],
141
122
  cookies: [],
142
123
  fraud: true,
143
124
  checksum: [],
@@ -168,7 +149,7 @@ function stop$C() {
168
149
  startTime = 0;
169
150
  }
170
151
 
171
- var version$1 = "0.7.3";
152
+ var version$1 = "0.7.5";
172
153
 
173
154
  // tslint:disable: no-bitwise
174
155
  function hash (input, precision) {
@@ -921,168 +902,540 @@ var selector = /*#__PURE__*/Object.freeze({
921
902
  reset: reset$l
922
903
  });
923
904
 
924
- // Track the start time to be able to compute duration at the end of the task
925
- var idleTimeout = 5000;
926
- var tracker = {};
927
- var queuedTasks = [];
928
- var activeTask = null;
929
- var pauseTask = null;
930
- var resumeResolve = null;
931
- function pause$1() {
932
- if (pauseTask === null) {
933
- pauseTask = new Promise(function (resolve) {
934
- resumeResolve = resolve;
935
- });
936
- }
905
+ var index = 1;
906
+ var nodes = [];
907
+ var values = [];
908
+ var updateMap = [];
909
+ var hashMap = {};
910
+ var override = [];
911
+ var unmask = [];
912
+ var maskText = [];
913
+ var maskExclude = [];
914
+ var maskDisable = [];
915
+ var maskTags = [];
916
+ // The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced
917
+ var idMap = null; // Maps node => id.
918
+ var iframeMap = null; // Maps iframe's contentDocument => parent iframe element
919
+ var privacyMap = null; // Maps node => Privacy (enum)
920
+ var fraudMap = null; // Maps node => FraudId (number)
921
+ function start$x() {
922
+ reset$k();
923
+ parse$1(document, true);
937
924
  }
938
- function resume$1() {
939
- if (pauseTask) {
940
- resumeResolve();
941
- pauseTask = null;
942
- if (activeTask === null) {
943
- run();
925
+ function stop$u() {
926
+ reset$k();
927
+ }
928
+ function reset$k() {
929
+ index = 1;
930
+ nodes = [];
931
+ values = [];
932
+ updateMap = [];
933
+ hashMap = {};
934
+ override = [];
935
+ unmask = [];
936
+ maskText = "address,password,contact" /* Mask.Text */.split("," /* Constant.Comma */);
937
+ maskExclude = "password,secret,pass,social,ssn,code,hidden" /* Mask.Exclude */.split("," /* Constant.Comma */);
938
+ maskDisable = "radio,checkbox,range,button,reset,submit" /* Mask.Disable */.split("," /* Constant.Comma */);
939
+ maskTags = "INPUT,SELECT,TEXTAREA" /* Mask.Tags */.split("," /* Constant.Comma */);
940
+ idMap = new WeakMap();
941
+ iframeMap = new WeakMap();
942
+ privacyMap = new WeakMap();
943
+ fraudMap = new WeakMap();
944
+ reset$l();
945
+ }
946
+ // We parse new root nodes for any regions or masked nodes in the beginning (document) and
947
+ // later whenever there are new additions or modifications to DOM (mutations)
948
+ function parse$1(root, init) {
949
+ if (init === void 0) { init = false; }
950
+ // Wrap selectors in a try / catch block.
951
+ // It's possible for script to receive invalid selectors, e.g. "'#id'" with extra quotes, and cause the code below to fail
952
+ try {
953
+ // Parse unmask configuration into separate query selectors and override tokens as part of initialization
954
+ if (init) {
955
+ config$1.unmask.forEach(function (x) { return x.indexOf("!" /* Constant.Bang */) < 0 ? unmask.push(x) : override.push(x.substr(1)); });
956
+ }
957
+ // Since mutations may happen on leaf nodes too, e.g. text nodes, which may not support all selector APIs.
958
+ // We ensure that the root note supports querySelectorAll API before executing the code below to identify new regions.
959
+ if ("querySelectorAll" in root) {
960
+ config$1.regions.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return observe$c(e, "".concat(x[0])); }); }); // Regions
961
+ config$1.mask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 3 /* Privacy.TextImage */); }); }); // Masked Elements
962
+ config$1.checksum.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return fraudMap.set(e, x[0]); }); }); // Fraud Checksum Check
963
+ unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* Privacy.None */); }); }); // Unmasked Elements
944
964
  }
945
965
  }
966
+ catch (e) {
967
+ log$1(5 /* Code.Selector */, 1 /* Severity.Warning */, e ? e.name : null);
968
+ }
946
969
  }
947
- function reset$k() {
948
- tracker = {};
949
- queuedTasks = [];
950
- activeTask = null;
951
- pauseTask = null;
970
+ function getId(node, autogen) {
971
+ if (autogen === void 0) { autogen = false; }
972
+ if (node === null) {
973
+ return null;
974
+ }
975
+ var id = idMap.get(node);
976
+ if (!id && autogen) {
977
+ id = index++;
978
+ idMap.set(node, id);
979
+ }
980
+ return id ? id : null;
952
981
  }
953
- function schedule$1(task, priority) {
954
- if (priority === void 0) { priority = 0 /* Priority.Normal */; }
955
- return __awaiter(this, void 0, void 0, function () {
956
- var _i, queuedTasks_1, q, promise;
957
- return __generator(this, function (_a) {
958
- // If this task is already scheduled, skip it
959
- for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
960
- q = queuedTasks_1[_i];
961
- if (q.task === task) {
962
- return [2 /*return*/];
963
- }
964
- }
965
- promise = new Promise(function (resolve) {
966
- var insert = priority === 1 /* Priority.High */ ? "unshift" : "push";
967
- // Queue this task for asynchronous execution later
968
- // We also store a unique page identifier (id) along with the task to ensure
969
- // ensure that we do not accidentally execute this task in context of a different page
970
- queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
971
- });
972
- // If there is no active task running, and Clarity is not in pause state,
973
- // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
974
- if (activeTask === null && pauseTask === null) {
975
- run();
976
- }
977
- return [2 /*return*/, promise];
978
- });
979
- });
982
+ function add(node, parent, data, source) {
983
+ var id = getId(node, true);
984
+ var parentId = parent ? getId(parent) : null;
985
+ var previousId = getPreviousId(node);
986
+ var parentValue = null;
987
+ var regionId = exists(node) ? id : null;
988
+ var fraudId = fraudMap.has(node) ? fraudMap.get(node) : null;
989
+ var privacyId = config$1.content ? 1 /* Privacy.Sensitive */ : 3 /* Privacy.TextImage */;
990
+ if (parentId >= 0 && values[parentId]) {
991
+ parentValue = values[parentId];
992
+ parentValue.children.push(id);
993
+ regionId = regionId === null ? parentValue.region : regionId;
994
+ fraudId = fraudId === null ? parentValue.metadata.fraud : fraudId;
995
+ privacyId = parentValue.metadata.privacy;
996
+ }
997
+ // If there's an explicit region attribute set on the element, use it to mark a region on the page
998
+ if (data.attributes && "data-clarity-region" /* Constant.RegionData */ in data.attributes) {
999
+ observe$c(node, data.attributes["data-clarity-region" /* Constant.RegionData */]);
1000
+ regionId = id;
1001
+ }
1002
+ nodes[id] = node;
1003
+ values[id] = {
1004
+ id: id,
1005
+ parent: parentId,
1006
+ previous: previousId,
1007
+ children: [],
1008
+ data: data,
1009
+ selector: null,
1010
+ hash: null,
1011
+ region: regionId,
1012
+ metadata: { active: true, suspend: false, privacy: privacyId, position: null, fraud: fraudId, size: null },
1013
+ };
1014
+ privacy(node, values[id], parentValue);
1015
+ updateSelector(values[id]);
1016
+ size$1(values[id]);
1017
+ track$5(id, source);
980
1018
  }
981
- function run() {
982
- var entry = queuedTasks.shift();
983
- if (entry) {
984
- activeTask = entry;
985
- entry.task().then(function () {
986
- // Bail out if the context in which this task was operating is different from the current page
987
- // An example scenario where task could span across pages is Single Page Applications (SPA)
988
- // A task that started on page #1, but completes on page #2
989
- if (entry.id !== id()) {
990
- return;
1019
+ function update$1(node, parent, data, source) {
1020
+ var id = getId(node);
1021
+ var parentId = parent ? getId(parent) : null;
1022
+ var previousId = getPreviousId(node);
1023
+ var changed = false;
1024
+ var parentChanged = false;
1025
+ if (id in values) {
1026
+ var value = values[id];
1027
+ value.metadata.active = true;
1028
+ // Handle case where internal ordering may have changed
1029
+ if (value.previous !== previousId) {
1030
+ changed = true;
1031
+ value.previous = previousId;
1032
+ }
1033
+ // Handle case where parent might have been updated
1034
+ if (value.parent !== parentId) {
1035
+ changed = true;
1036
+ var oldParentId = value.parent;
1037
+ value.parent = parentId;
1038
+ // Move this node to the right location under new parent
1039
+ if (parentId !== null && parentId >= 0) {
1040
+ var childIndex = previousId === null ? 0 : values[parentId].children.indexOf(previousId) + 1;
1041
+ values[parentId].children.splice(childIndex, 0, id);
1042
+ // Update region after the move
1043
+ value.region = exists(node) ? id : values[parentId].region;
991
1044
  }
992
- entry.resolve();
993
- activeTask = null; // Reset active task back to null now that the promise is resolved
994
- run();
995
- }).catch(function (error) {
996
- // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
997
- if (entry.id !== id()) {
998
- return;
1045
+ else {
1046
+ // Mark this element as deleted if the parent has been updated to null
1047
+ remove(id, source);
999
1048
  }
1000
- if (error) {
1001
- log$1(0 /* Code.RunTask */, 1 /* Severity.Warning */, error.name, error.message, error.stack);
1049
+ // Remove reference to this node from the old parent
1050
+ if (oldParentId !== null && oldParentId >= 0) {
1051
+ var nodeIndex = values[oldParentId].children.indexOf(id);
1052
+ if (nodeIndex >= 0) {
1053
+ values[oldParentId].children.splice(nodeIndex, 1);
1054
+ }
1002
1055
  }
1003
- activeTask = null;
1004
- run();
1005
- });
1056
+ parentChanged = true;
1057
+ }
1058
+ // Update data
1059
+ for (var key in data) {
1060
+ if (diff(value["data"], data, key)) {
1061
+ changed = true;
1062
+ value["data"][key] = data[key];
1063
+ }
1064
+ }
1065
+ // Update selector
1066
+ updateSelector(value);
1067
+ track$5(id, source, changed, parentChanged);
1006
1068
  }
1007
1069
  }
1008
- function state$9(timer) {
1009
- var id = key(timer);
1010
- if (id in tracker) {
1011
- var elapsed = performance.now() - tracker[id].start;
1012
- return (elapsed > tracker[id].yield) ? 0 /* Task.Wait */ : 1 /* Task.Run */;
1070
+ function sameorigin(node) {
1071
+ var output = false;
1072
+ if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "IFRAME" /* Constant.IFrameTag */) {
1073
+ var frame = node;
1074
+ // To determine if the iframe is same-origin or not, we try accessing it's contentDocument.
1075
+ // If the browser throws an exception, we assume it's cross-origin and move on.
1076
+ // However, if we do a get a valid document object back, we assume the contents are accessible and iframe is same-origin.
1077
+ try {
1078
+ var doc = frame.contentDocument;
1079
+ if (doc) {
1080
+ iframeMap.set(frame.contentDocument, frame);
1081
+ output = true;
1082
+ }
1083
+ }
1084
+ catch ( /* do nothing */_a) { /* do nothing */ }
1013
1085
  }
1014
- // If this task is no longer being tracked, send stop message to the caller
1015
- return 2 /* Task.Stop */;
1086
+ return output;
1016
1087
  }
1017
- function start$x(timer) {
1018
- tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* Setting.LongTask */ };
1088
+ function iframe(node) {
1089
+ var doc = node.nodeType === Node.DOCUMENT_NODE ? node : null;
1090
+ return doc && iframeMap.has(doc) ? iframeMap.get(doc) : null;
1019
1091
  }
1020
- function restart$2(timer) {
1021
- var id = key(timer);
1022
- if (tracker && tracker[id]) {
1023
- var c = tracker[id].calls;
1024
- var y = tracker[id].yield;
1025
- start$x(timer);
1026
- tracker[id].calls = c + 1;
1027
- tracker[id].yield = y;
1092
+ function privacy(node, value, parent) {
1093
+ var data = value.data;
1094
+ var metadata = value.metadata;
1095
+ var current = metadata.privacy;
1096
+ var attributes = data.attributes || {};
1097
+ var tag = data.tag.toUpperCase();
1098
+ switch (true) {
1099
+ case maskTags.indexOf(tag) >= 0:
1100
+ var type = attributes["type" /* Constant.Type */];
1101
+ var meta_1 = "" /* Constant.Empty */;
1102
+ Object.keys(attributes).forEach(function (x) { return meta_1 += attributes[x].toLowerCase(); });
1103
+ var exclude = maskExclude.some(function (x) { return meta_1.indexOf(x) >= 0; });
1104
+ // Regardless of privacy mode, always mask off user input from input boxes or drop downs with two exceptions:
1105
+ // (1) The node is detected to be one of the excluded fields, in which case we drop everything
1106
+ // (2) The node's type is one of the allowed types (like checkboxes)
1107
+ metadata.privacy = tag === "INPUT" /* Constant.InputTag */ && maskDisable.indexOf(type) >= 0 ? current : (exclude ? 4 /* Privacy.Exclude */ : 2 /* Privacy.Text */);
1108
+ break;
1109
+ case "data-clarity-mask" /* Constant.MaskData */ in attributes:
1110
+ metadata.privacy = 3 /* Privacy.TextImage */;
1111
+ break;
1112
+ case "data-clarity-unmask" /* Constant.UnmaskData */ in attributes:
1113
+ metadata.privacy = 0 /* Privacy.None */;
1114
+ break;
1115
+ case privacyMap.has(node):
1116
+ // If this node was explicitly configured to contain sensitive content, honor that privacy setting
1117
+ metadata.privacy = privacyMap.get(node);
1118
+ break;
1119
+ case fraudMap.has(node):
1120
+ // If this node was explicitly configured to be evaluated for fraud, then also mask content
1121
+ metadata.privacy = 2 /* Privacy.Text */;
1122
+ break;
1123
+ case tag === "*T" /* Constant.TextTag */:
1124
+ // If it's a text node belonging to a STYLE or TITLE tag or one of scrub exceptions, then capture content
1125
+ var pTag = parent && parent.data ? parent.data.tag : "" /* Constant.Empty */;
1126
+ var pSelector_1 = parent && parent.selector ? parent.selector[1 /* Selector.Default */] : "" /* Constant.Empty */;
1127
+ var tags = ["STYLE" /* Constant.StyleTag */, "TITLE" /* Constant.TitleTag */, "svg:style" /* Constant.SvgStyle */];
1128
+ metadata.privacy = tags.includes(pTag) || override.some(function (x) { return pSelector_1.indexOf(x) >= 0; }) ? 0 /* Privacy.None */ : current;
1129
+ break;
1130
+ case current === 1 /* Privacy.Sensitive */:
1131
+ // In a mode where we mask sensitive information by default, look through class names to aggressively mask content
1132
+ metadata.privacy = inspect(attributes["class" /* Constant.Class */], maskText, metadata);
1133
+ break;
1028
1134
  }
1029
1135
  }
1030
- function stop$u(timer) {
1031
- var end = performance.now();
1032
- var id = key(timer);
1033
- var duration = end - tracker[id].start;
1034
- sum(timer.cost, duration);
1035
- count$1(5 /* Metric.InvokeCount */);
1036
- // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
1037
- // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
1038
- if (tracker[id].calls > 0) {
1039
- sum(4 /* Metric.TotalCost */, duration);
1136
+ function inspect(input, lookup, metadata) {
1137
+ if (input && lookup.some(function (x) { return input.indexOf(x) >= 0; })) {
1138
+ return 2 /* Privacy.Text */;
1040
1139
  }
1140
+ return metadata.privacy;
1041
1141
  }
1042
- function suspend$1(timer) {
1043
- return __awaiter(this, void 0, void 0, function () {
1044
- var id, _a;
1045
- return __generator(this, function (_b) {
1046
- switch (_b.label) {
1047
- case 0:
1048
- id = key(timer);
1049
- if (!(id in tracker)) return [3 /*break*/, 2];
1050
- stop$u(timer);
1051
- _a = tracker[id];
1052
- return [4 /*yield*/, wait()];
1053
- case 1:
1054
- _a.yield = (_b.sent()).timeRemaining();
1055
- restart$2(timer);
1056
- _b.label = 2;
1057
- case 2:
1058
- // After we are done with suspending task, ensure that we are still operating in the right context
1059
- // If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
1060
- return [2 /*return*/, id in tracker ? 1 /* Task.Run */ : 2 /* Task.Stop */];
1142
+ function diff(a, b, field) {
1143
+ if (typeof a[field] === "object" && typeof b[field] === "object") {
1144
+ for (var key in a[field]) {
1145
+ if (a[field][key] !== b[field][key]) {
1146
+ return true;
1061
1147
  }
1148
+ }
1149
+ for (var key in b[field]) {
1150
+ if (b[field][key] !== a[field][key]) {
1151
+ return true;
1152
+ }
1153
+ }
1154
+ return false;
1155
+ }
1156
+ return a[field] !== b[field];
1157
+ }
1158
+ function position(parent, child) {
1159
+ child.metadata.position = 1;
1160
+ var idx = parent ? parent.children.indexOf(child.id) : -1;
1161
+ while (idx-- > 0) {
1162
+ var sibling = values[parent.children[idx]];
1163
+ if (child.data.tag === sibling.data.tag) {
1164
+ child.metadata.position = sibling.metadata.position + 1;
1165
+ break;
1166
+ }
1167
+ }
1168
+ return child.metadata.position;
1169
+ }
1170
+ function updateSelector(value) {
1171
+ var parent = value.parent && value.parent in values ? values[value.parent] : null;
1172
+ var prefix = parent ? parent.selector : null;
1173
+ var d = value.data;
1174
+ var p = position(parent, value);
1175
+ var s = { id: value.id, tag: d.tag, prefix: prefix, position: p, attributes: d.attributes };
1176
+ value.selector = [get$1(s, 0 /* Selector.Alpha */), get$1(s, 1 /* Selector.Beta */)];
1177
+ value.hash = value.selector.map(function (x) { return x ? hash(x) : null; });
1178
+ value.hash.forEach(function (h) { return hashMap[h] = value.id; });
1179
+ }
1180
+ function hashText(hash) {
1181
+ var id = lookup(hash);
1182
+ var node = getNode(id);
1183
+ return node !== null && node.textContent !== null ? node.textContent.substr(0, 25 /* Setting.ClickText */) : '';
1184
+ }
1185
+ function getNode(id) {
1186
+ if (id in nodes) {
1187
+ return nodes[id];
1188
+ }
1189
+ return null;
1190
+ }
1191
+ function getValue(id) {
1192
+ if (id in values) {
1193
+ return values[id];
1194
+ }
1195
+ return null;
1196
+ }
1197
+ function get(node) {
1198
+ var id = getId(node);
1199
+ return id in values ? values[id] : null;
1200
+ }
1201
+ function lookup(hash) {
1202
+ return hash in hashMap ? hashMap[hash] : null;
1203
+ }
1204
+ function has(node) {
1205
+ return getId(node) in nodes;
1206
+ }
1207
+ function updates$2() {
1208
+ var output = [];
1209
+ for (var _i = 0, updateMap_1 = updateMap; _i < updateMap_1.length; _i++) {
1210
+ var id = updateMap_1[_i];
1211
+ if (id in values) {
1212
+ output.push(values[id]);
1213
+ }
1214
+ }
1215
+ updateMap = [];
1216
+ return output;
1217
+ }
1218
+ function remove(id, source) {
1219
+ if (id in values) {
1220
+ var value = values[id];
1221
+ value.metadata.active = false;
1222
+ value.parent = null;
1223
+ track$5(id, source);
1224
+ }
1225
+ }
1226
+ function size$1(value) {
1227
+ // If this element is a image node, and is masked, then track box model for the current element
1228
+ if (value.data.tag === "IMG" /* Constant.ImageTag */ && value.metadata.privacy === 3 /* Privacy.TextImage */) {
1229
+ value.metadata.size = [];
1230
+ }
1231
+ }
1232
+ function getPreviousId(node) {
1233
+ var id = null;
1234
+ // Some nodes may not have an ID by design since Clarity skips over tags like SCRIPT, NOSCRIPT, META, COMMENTS, etc..
1235
+ // In that case, we keep going back and check for their sibling until we find a sibling with ID or no more sibling nodes are left.
1236
+ while (id === null && node.previousSibling) {
1237
+ id = getId(node.previousSibling);
1238
+ node = node.previousSibling;
1239
+ }
1240
+ return id;
1241
+ }
1242
+ function track$5(id, source, changed, parentChanged) {
1243
+ if (changed === void 0) { changed = true; }
1244
+ if (parentChanged === void 0) { parentChanged = false; }
1245
+ // Keep track of the order in which mutations happened, they may not be sequential
1246
+ // Edge case: If an element is added later on, and pre-discovered element is moved as a child.
1247
+ // In that case, we need to reorder the pre-discovered element in the update list to keep visualization consistent.
1248
+ var uIndex = updateMap.indexOf(id);
1249
+ if (uIndex >= 0 && source === 1 /* Source.ChildListAdd */ && parentChanged) {
1250
+ updateMap.splice(uIndex, 1);
1251
+ updateMap.push(id);
1252
+ }
1253
+ else if (uIndex === -1 && changed) {
1254
+ updateMap.push(id);
1255
+ }
1256
+ }
1257
+
1258
+ var dom = /*#__PURE__*/Object.freeze({
1259
+ __proto__: null,
1260
+ add: add,
1261
+ get: get,
1262
+ getId: getId,
1263
+ getNode: getNode,
1264
+ getValue: getValue,
1265
+ has: has,
1266
+ hashText: hashText,
1267
+ iframe: iframe,
1268
+ lookup: lookup,
1269
+ parse: parse$1,
1270
+ sameorigin: sameorigin,
1271
+ start: start$x,
1272
+ stop: stop$u,
1273
+ update: update$1,
1274
+ updates: updates$2
1275
+ });
1276
+
1277
+ // Track the start time to be able to compute duration at the end of the task
1278
+ var idleTimeout = 5000;
1279
+ var tracker = {};
1280
+ var queuedTasks = [];
1281
+ var activeTask = null;
1282
+ var pauseTask = null;
1283
+ var resumeResolve = null;
1284
+ function pause$1() {
1285
+ if (pauseTask === null) {
1286
+ pauseTask = new Promise(function (resolve) {
1287
+ resumeResolve = resolve;
1062
1288
  });
1063
- });
1289
+ }
1064
1290
  }
1065
- function key(timer) {
1066
- return "".concat(timer.id, ".").concat(timer.cost);
1291
+ function resume$1() {
1292
+ if (pauseTask) {
1293
+ resumeResolve();
1294
+ pauseTask = null;
1295
+ if (activeTask === null) {
1296
+ run();
1297
+ }
1298
+ }
1067
1299
  }
1068
- function wait() {
1300
+ function reset$j() {
1301
+ tracker = {};
1302
+ queuedTasks = [];
1303
+ activeTask = null;
1304
+ pauseTask = null;
1305
+ }
1306
+ function schedule$1(task, priority) {
1307
+ if (priority === void 0) { priority = 0 /* Priority.Normal */; }
1069
1308
  return __awaiter(this, void 0, void 0, function () {
1309
+ var _i, queuedTasks_1, q, promise;
1070
1310
  return __generator(this, function (_a) {
1071
- switch (_a.label) {
1072
- case 0:
1073
- if (!pauseTask) return [3 /*break*/, 2];
1074
- return [4 /*yield*/, pauseTask];
1075
- case 1:
1076
- _a.sent();
1077
- _a.label = 2;
1078
- case 2: return [2 /*return*/, new Promise(function (resolve) {
1079
- requestIdleCallback(resolve, { timeout: idleTimeout });
1080
- })];
1311
+ // If this task is already scheduled, skip it
1312
+ for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
1313
+ q = queuedTasks_1[_i];
1314
+ if (q.task === task) {
1315
+ return [2 /*return*/];
1316
+ }
1317
+ }
1318
+ promise = new Promise(function (resolve) {
1319
+ var insert = priority === 1 /* Priority.High */ ? "unshift" : "push";
1320
+ // Queue this task for asynchronous execution later
1321
+ // We also store a unique page identifier (id) along with the task to ensure
1322
+ // ensure that we do not accidentally execute this task in context of a different page
1323
+ queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
1324
+ });
1325
+ // If there is no active task running, and Clarity is not in pause state,
1326
+ // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
1327
+ if (activeTask === null && pauseTask === null) {
1328
+ run();
1081
1329
  }
1330
+ return [2 /*return*/, promise];
1082
1331
  });
1083
1332
  });
1084
1333
  }
1085
- // Use native implementation of requestIdleCallback if it exists.
1334
+ function run() {
1335
+ var entry = queuedTasks.shift();
1336
+ if (entry) {
1337
+ activeTask = entry;
1338
+ entry.task().then(function () {
1339
+ // Bail out if the context in which this task was operating is different from the current page
1340
+ // An example scenario where task could span across pages is Single Page Applications (SPA)
1341
+ // A task that started on page #1, but completes on page #2
1342
+ if (entry.id !== id()) {
1343
+ return;
1344
+ }
1345
+ entry.resolve();
1346
+ activeTask = null; // Reset active task back to null now that the promise is resolved
1347
+ run();
1348
+ }).catch(function (error) {
1349
+ // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
1350
+ if (entry.id !== id()) {
1351
+ return;
1352
+ }
1353
+ if (error) {
1354
+ log$1(0 /* Code.RunTask */, 1 /* Severity.Warning */, error.name, error.message, error.stack);
1355
+ }
1356
+ activeTask = null;
1357
+ run();
1358
+ });
1359
+ }
1360
+ }
1361
+ function state$9(timer) {
1362
+ var id = key(timer);
1363
+ if (id in tracker) {
1364
+ var elapsed = performance.now() - tracker[id].start;
1365
+ return (elapsed > tracker[id].yield) ? 0 /* Task.Wait */ : 1 /* Task.Run */;
1366
+ }
1367
+ // If this task is no longer being tracked, send stop message to the caller
1368
+ return 2 /* Task.Stop */;
1369
+ }
1370
+ function start$w(timer) {
1371
+ tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* Setting.LongTask */ };
1372
+ }
1373
+ function restart$2(timer) {
1374
+ var id = key(timer);
1375
+ if (tracker && tracker[id]) {
1376
+ var c = tracker[id].calls;
1377
+ var y = tracker[id].yield;
1378
+ start$w(timer);
1379
+ tracker[id].calls = c + 1;
1380
+ tracker[id].yield = y;
1381
+ }
1382
+ }
1383
+ function stop$t(timer) {
1384
+ var end = performance.now();
1385
+ var id = key(timer);
1386
+ var duration = end - tracker[id].start;
1387
+ sum(timer.cost, duration);
1388
+ count$1(5 /* Metric.InvokeCount */);
1389
+ // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
1390
+ // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
1391
+ if (tracker[id].calls > 0) {
1392
+ sum(4 /* Metric.TotalCost */, duration);
1393
+ }
1394
+ }
1395
+ function suspend$1(timer) {
1396
+ return __awaiter(this, void 0, void 0, function () {
1397
+ var id, _a;
1398
+ return __generator(this, function (_b) {
1399
+ switch (_b.label) {
1400
+ case 0:
1401
+ id = key(timer);
1402
+ if (!(id in tracker)) return [3 /*break*/, 2];
1403
+ stop$t(timer);
1404
+ _a = tracker[id];
1405
+ return [4 /*yield*/, wait()];
1406
+ case 1:
1407
+ _a.yield = (_b.sent()).timeRemaining();
1408
+ restart$2(timer);
1409
+ _b.label = 2;
1410
+ case 2:
1411
+ // After we are done with suspending task, ensure that we are still operating in the right context
1412
+ // If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
1413
+ return [2 /*return*/, id in tracker ? 1 /* Task.Run */ : 2 /* Task.Stop */];
1414
+ }
1415
+ });
1416
+ });
1417
+ }
1418
+ function key(timer) {
1419
+ return "".concat(timer.id, ".").concat(timer.cost);
1420
+ }
1421
+ function wait() {
1422
+ return __awaiter(this, void 0, void 0, function () {
1423
+ return __generator(this, function (_a) {
1424
+ switch (_a.label) {
1425
+ case 0:
1426
+ if (!pauseTask) return [3 /*break*/, 2];
1427
+ return [4 /*yield*/, pauseTask];
1428
+ case 1:
1429
+ _a.sent();
1430
+ _a.label = 2;
1431
+ case 2: return [2 /*return*/, new Promise(function (resolve) {
1432
+ requestIdleCallback(resolve, { timeout: idleTimeout });
1433
+ })];
1434
+ }
1435
+ });
1436
+ });
1437
+ }
1438
+ // Use native implementation of requestIdleCallback if it exists.
1086
1439
  // Otherwise, fall back to a custom implementation using requestAnimationFrame & MessageChannel.
1087
1440
  // While it's not possible to build a perfect polyfill given the nature of this API, the following code attempts to get close.
1088
1441
  // Background context: requestAnimationFrame invokes the js code right before: style, layout and paint computation within the frame.
@@ -1159,6 +1512,41 @@ function tokenize (tokens) {
1159
1512
  return output;
1160
1513
  }
1161
1514
 
1515
+ var data$c;
1516
+ function reset$i() {
1517
+ data$c = null;
1518
+ }
1519
+ function start$v() {
1520
+ reset$i();
1521
+ compute$7();
1522
+ }
1523
+ function compute$7() {
1524
+ var body = document.body;
1525
+ var d = document.documentElement;
1526
+ var bodyClientWidth = body ? body.clientWidth : null;
1527
+ var bodyScrollWidth = body ? body.scrollWidth : null;
1528
+ var bodyOffsetWidth = body ? body.offsetWidth : null;
1529
+ var documentClientWidth = d ? d.clientWidth : null;
1530
+ var documentScrollWidth = d ? d.scrollWidth : null;
1531
+ var documentOffsetWidth = d ? d.offsetWidth : null;
1532
+ var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
1533
+ var bodyClientHeight = body ? body.clientHeight : null;
1534
+ var bodyScrollHeight = body ? body.scrollHeight : null;
1535
+ var bodyOffsetHeight = body ? body.offsetHeight : null;
1536
+ var documentClientHeight = d ? d.clientHeight : null;
1537
+ var documentScrollHeight = d ? d.scrollHeight : null;
1538
+ var documentOffsetHeight = d ? d.offsetHeight : null;
1539
+ var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
1540
+ // Check that width or height has changed from before, and also that width & height are not null values
1541
+ if ((data$c === null || width !== data$c.width || height !== data$c.height) && width !== null && height !== null) {
1542
+ data$c = { width: width, height: height };
1543
+ encode$4(8 /* Event.Document */);
1544
+ }
1545
+ }
1546
+ function end() {
1547
+ reset$i();
1548
+ }
1549
+
1162
1550
  function encode$4 (type, timer, ts) {
1163
1551
  if (timer === void 0) { timer = null; }
1164
1552
  if (ts === void 0) { ts = null; }
@@ -1185,7 +1573,7 @@ function encode$4 (type, timer, ts) {
1185
1573
  queue(tokens);
1186
1574
  return [3 /*break*/, 10];
1187
1575
  case 2:
1188
- for (_i = 0, _b = state$1; _i < _b.length; _i++) {
1576
+ for (_i = 0, _b = state$8; _i < _b.length; _i++) {
1189
1577
  r = _b[_i];
1190
1578
  tokens = [r.time, 7 /* Event.Region */];
1191
1579
  tokens.push(r.data.id);
@@ -1194,7 +1582,7 @@ function encode$4 (type, timer, ts) {
1194
1582
  tokens.push(r.data.name);
1195
1583
  queue(tokens);
1196
1584
  }
1197
- reset$6();
1585
+ reset$h();
1198
1586
  return [3 /*break*/, 10];
1199
1587
  case 3:
1200
1588
  // Check if we are operating within the context of the current page
@@ -1229,7 +1617,7 @@ function encode$4 (type, timer, ts) {
1229
1617
  if (data[key]) {
1230
1618
  switch (key) {
1231
1619
  case "tag":
1232
- box = size$1(value);
1620
+ box = size(value);
1233
1621
  factor = mangle ? -1 : 1;
1234
1622
  tokens.push(value.id * factor);
1235
1623
  if (value.parent && active) {
@@ -1277,7 +1665,7 @@ function shouldMangle(value) {
1277
1665
  var privacy = value.metadata.privacy;
1278
1666
  return value.data.tag === "*T" /* Constant.TextTag */ && !(privacy === 0 /* Privacy.None */ || privacy === 1 /* Privacy.Sensitive */);
1279
1667
  }
1280
- function size$1(value) {
1668
+ function size(value) {
1281
1669
  if (value.metadata.size !== null && value.metadata.size.length === 0) {
1282
1670
  var img = getNode(value.id);
1283
1671
  if (img) {
@@ -1293,95 +1681,207 @@ function attribute(key, value, privacy) {
1293
1681
  return "".concat(key, "=").concat(text$1(value, key, privacy));
1294
1682
  }
1295
1683
 
1296
- var data$c;
1297
- function reset$j() {
1298
- data$c = null;
1299
- }
1300
- function start$w() {
1301
- reset$j();
1302
- compute$7();
1303
- }
1304
- function compute$7() {
1305
- var body = document.body;
1306
- var d = document.documentElement;
1307
- var bodyClientWidth = body ? body.clientWidth : null;
1308
- var bodyScrollWidth = body ? body.scrollWidth : null;
1309
- var bodyOffsetWidth = body ? body.offsetWidth : null;
1310
- var documentClientWidth = d ? d.clientWidth : null;
1311
- var documentScrollWidth = d ? d.scrollWidth : null;
1312
- var documentOffsetWidth = d ? d.offsetWidth : null;
1313
- var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
1314
- var bodyClientHeight = body ? body.clientHeight : null;
1315
- var bodyScrollHeight = body ? body.scrollHeight : null;
1316
- var bodyOffsetHeight = body ? body.offsetHeight : null;
1317
- var documentClientHeight = d ? d.clientHeight : null;
1318
- var documentScrollHeight = d ? d.scrollHeight : null;
1319
- var documentOffsetHeight = d ? d.offsetHeight : null;
1320
- var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
1321
- // Check that width or height has changed from before, and also that width & height are not null values
1322
- if ((data$c === null || width !== data$c.width || height !== data$c.height) && width !== null && height !== null) {
1323
- data$c = { width: width, height: height };
1324
- encode$4(8 /* Event.Document */);
1325
- }
1326
- }
1327
- function end() {
1328
- reset$j();
1329
- }
1330
-
1331
1684
  var state$8 = [];
1332
- function start$v() {
1333
- reset$i();
1334
- }
1335
- function observe$c(root) {
1336
- bind(root, "change", recompute$8, true);
1685
+ var regionMap = null; // Maps region nodes => region name
1686
+ var regions = {};
1687
+ var queue$2 = [];
1688
+ var watch = false;
1689
+ var observer$1 = null;
1690
+ function start$u() {
1691
+ reset$h();
1692
+ observer$1 = null;
1693
+ regionMap = new WeakMap();
1694
+ regions = {};
1695
+ queue$2 = [];
1696
+ watch = window["IntersectionObserver"] ? true : false;
1337
1697
  }
1338
- function recompute$8(evt) {
1339
- var element = target(evt);
1340
- if (element) {
1341
- var value = element.value;
1342
- var checksum = value && value.length >= 5 /* Setting.WordLength */ && config$1.fraud ? hash(value, 24 /* Setting.ChecksumPrecision */) : "" /* Constant.Empty */;
1343
- state$8.push({ time: time(evt), event: 42 /* Event.Change */, data: { target: target(evt), type: element.type, value: value, checksum: checksum } });
1344
- schedule$1(encode$3.bind(this, 42 /* Event.Change */));
1698
+ function observe$c(node, name) {
1699
+ if (regionMap.has(node) === false) {
1700
+ regionMap.set(node, name);
1701
+ observer$1 = observer$1 === null && watch ? new IntersectionObserver(handler$3, {
1702
+ // Get notified as intersection continues to change
1703
+ // This allows us to process regions that get partially hidden during the lifetime of the page
1704
+ // See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
1705
+ // By default, intersection observers only fire an event when even a single pixel is visible and not thereafter.
1706
+ threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
1707
+ }) : observer$1;
1708
+ if (observer$1 && node && node.nodeType === Node.ELEMENT_NODE) {
1709
+ observer$1.observe(node);
1710
+ }
1345
1711
  }
1346
1712
  }
1347
- function reset$i() {
1348
- state$8 = [];
1713
+ function exists(node) {
1714
+ // Check if regionMap is not null before looking up a node
1715
+ // Since, dom module stops after region module, it's possible that we may set regionMap to be null
1716
+ // and still attempt to call exists on a late coming DOM mutation (or addition), effectively causing a script error
1717
+ return regionMap && regionMap.has(node);
1349
1718
  }
1350
- function stop$t() {
1351
- reset$i();
1352
- }
1353
-
1354
- function offset (element) {
1355
- var output = { x: 0, y: 0 };
1356
- // Walk up the chain to ensure we compute offset distance correctly
1357
- // In case where we may have nested IFRAMEs, we keep walking up until we get to the top most parent page
1358
- if (element && element.offsetParent) {
1359
- do {
1360
- var parent_1 = element.offsetParent;
1361
- var frame = parent_1 === null ? iframe(element.ownerDocument) : null;
1362
- output.x += element.offsetLeft;
1363
- output.y += element.offsetTop;
1364
- element = frame ? frame : parent_1;
1365
- } while (element);
1719
+ function track$4(id, event) {
1720
+ var node = getNode(id);
1721
+ var data = id in regions ? regions[id] : { id: id, visibility: 0 /* RegionVisibility.Rendered */, interaction: 16 /* InteractionState.None */, name: regionMap.get(node) };
1722
+ // Determine the interaction state based on incoming event
1723
+ var interaction = 16 /* InteractionState.None */;
1724
+ switch (event) {
1725
+ case 9 /* Event.Click */:
1726
+ interaction = 20 /* InteractionState.Clicked */;
1727
+ break;
1728
+ case 27 /* Event.Input */:
1729
+ interaction = 30 /* InteractionState.Input */;
1730
+ break;
1366
1731
  }
1367
- return output;
1368
- }
1369
-
1370
- var UserInputTags = ["input", "textarea", "radio", "button", "canvas"];
1371
- var state$7 = [];
1372
- function start$u() {
1373
- reset$h();
1374
- }
1375
- function observe$b(root) {
1376
- bind(root, "click", handler$3.bind(this, 9 /* Event.Click */, root), true);
1732
+ // Process updates to this region, if applicable
1733
+ process$6(node, data, interaction, data.visibility);
1377
1734
  }
1378
- function handler$3(event, root, evt) {
1379
- var frame = iframe(root);
1380
- var d = frame ? frame.contentDocument.documentElement : document.documentElement;
1381
- var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
1382
- var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
1383
- // In case of iframe, we adjust (x,y) to be relative to top parent's origin
1384
- if (frame) {
1735
+ function compute$6() {
1736
+ // Process any regions where we couldn't resolve an "id" for at the time of last intersection observer event
1737
+ // This could happen in cases where elements are not yet processed by Clarity's virtual DOM but browser reports a change, regardless.
1738
+ // For those cases we add them to the queue and re-process them below
1739
+ var q = [];
1740
+ for (var _i = 0, queue_1 = queue$2; _i < queue_1.length; _i++) {
1741
+ var r = queue_1[_i];
1742
+ var id = getId(r.node);
1743
+ if (!(id in regions)) {
1744
+ if (id) {
1745
+ r.data.id = id;
1746
+ regions[id] = r.data;
1747
+ state$8.push(clone$1(r.data));
1748
+ }
1749
+ else {
1750
+ q.push(r);
1751
+ }
1752
+ }
1753
+ }
1754
+ queue$2 = q;
1755
+ // Schedule encode only when we have at least one valid data entry
1756
+ if (state$8.length > 0) {
1757
+ encode$4(7 /* Event.Region */);
1758
+ }
1759
+ }
1760
+ function handler$3(entries) {
1761
+ for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
1762
+ var entry = entries_1[_i];
1763
+ var target = entry.target;
1764
+ var rect = entry.boundingClientRect;
1765
+ var overlap = entry.intersectionRect;
1766
+ var viewport = entry.rootBounds;
1767
+ // Only capture regions that have non-zero width or height to avoid tracking and sending regions
1768
+ // that cannot ever be seen by the user. In some cases, websites will have a multiple copy of the same region
1769
+ // like search box - one for desktop, and another for mobile. In those cases, CSS media queries determine which one should be visible.
1770
+ // Also, if these regions ever become non-zero width or height (through AJAX, user action or orientation change) - we will automatically start monitoring them from that point onwards
1771
+ if (regionMap.has(target) && rect.width + rect.height > 0 && viewport.width > 0 && viewport.height > 0) {
1772
+ var id = target ? getId(target) : null;
1773
+ var data = id in regions ? regions[id] : { id: id, name: regionMap.get(target), interaction: 16 /* InteractionState.None */, visibility: 0 /* RegionVisibility.Rendered */ };
1774
+ // For regions that have relatively smaller area, we look at intersection ratio and see the overlap relative to element's area
1775
+ // However, for larger regions, area of regions could be bigger than viewport and therefore comparison is relative to visible area
1776
+ var viewportRatio = overlap ? (overlap.width * overlap.height * 1.0) / (viewport.width * viewport.height) : 0;
1777
+ var visible = viewportRatio > 0.05 /* Setting.ViewportIntersectionRatio */ || entry.intersectionRatio > 0.8 /* Setting.IntersectionRatio */;
1778
+ // If an element is either visible or was visible and has been scrolled to the end
1779
+ // i.e. Scrolled to end is determined by if the starting position of the element + the window height is more than the total element height.
1780
+ // starting position is relative to the viewport - so Intersection observer returns a negative value for rect.top to indicate that the element top is above the viewport
1781
+ var scrolledToEnd = (visible || data.visibility == 10 /* RegionVisibility.Visible */) && Math.abs(rect.top) + viewport.height > rect.height;
1782
+ // Process updates to this region, if applicable
1783
+ process$6(target, data, data.interaction, (scrolledToEnd ?
1784
+ 13 /* RegionVisibility.ScrolledToEnd */ :
1785
+ (visible ? 10 /* RegionVisibility.Visible */ : 0 /* RegionVisibility.Rendered */)));
1786
+ // Stop observing this element now that we have already received scrolled signal
1787
+ if (data.visibility >= 13 /* RegionVisibility.ScrolledToEnd */ && observer$1) {
1788
+ observer$1.unobserve(target);
1789
+ }
1790
+ }
1791
+ }
1792
+ if (state$8.length > 0) {
1793
+ encode$4(7 /* Event.Region */);
1794
+ }
1795
+ }
1796
+ function process$6(n, d, s, v) {
1797
+ // Check if received a state that supersedes existing state
1798
+ var updated = s > d.interaction || v > d.visibility;
1799
+ d.interaction = s > d.interaction ? s : d.interaction;
1800
+ d.visibility = v > d.visibility ? v : d.visibility;
1801
+ // If the corresponding node is already discovered, update the internal state
1802
+ // Otherwise, track it in a queue to reprocess later.
1803
+ if (d.id) {
1804
+ if ((d.id in regions && updated) || !(d.id in regions)) {
1805
+ regions[d.id] = d;
1806
+ state$8.push(clone$1(d));
1807
+ }
1808
+ }
1809
+ else {
1810
+ queue$2.push({ node: n, data: d });
1811
+ }
1812
+ }
1813
+ function clone$1(r) {
1814
+ return { time: time(), data: { id: r.id, interaction: r.interaction, visibility: r.visibility, name: r.name } };
1815
+ }
1816
+ function reset$h() {
1817
+ state$8 = [];
1818
+ }
1819
+ function stop$s() {
1820
+ reset$h();
1821
+ regionMap = null;
1822
+ regions = {};
1823
+ queue$2 = [];
1824
+ if (observer$1) {
1825
+ observer$1.disconnect();
1826
+ observer$1 = null;
1827
+ }
1828
+ watch = false;
1829
+ }
1830
+
1831
+ var state$7 = [];
1832
+ function start$t() {
1833
+ reset$g();
1834
+ }
1835
+ function observe$b(root) {
1836
+ bind(root, "change", recompute$8, true);
1837
+ }
1838
+ function recompute$8(evt) {
1839
+ var element = target(evt);
1840
+ if (element) {
1841
+ var value = element.value;
1842
+ var checksum = value && value.length >= 5 /* Setting.WordLength */ && config$1.fraud ? hash(value, 24 /* Setting.ChecksumPrecision */) : "" /* Constant.Empty */;
1843
+ state$7.push({ time: time(evt), event: 42 /* Event.Change */, data: { target: target(evt), type: element.type, value: value, checksum: checksum } });
1844
+ schedule$1(encode$3.bind(this, 42 /* Event.Change */));
1845
+ }
1846
+ }
1847
+ function reset$g() {
1848
+ state$7 = [];
1849
+ }
1850
+ function stop$r() {
1851
+ reset$g();
1852
+ }
1853
+
1854
+ function offset (element) {
1855
+ var output = { x: 0, y: 0 };
1856
+ // Walk up the chain to ensure we compute offset distance correctly
1857
+ // In case where we may have nested IFRAMEs, we keep walking up until we get to the top most parent page
1858
+ if (element && element.offsetParent) {
1859
+ do {
1860
+ var parent_1 = element.offsetParent;
1861
+ var frame = parent_1 === null ? iframe(element.ownerDocument) : null;
1862
+ output.x += element.offsetLeft;
1863
+ output.y += element.offsetTop;
1864
+ element = frame ? frame : parent_1;
1865
+ } while (element);
1866
+ }
1867
+ return output;
1868
+ }
1869
+
1870
+ var UserInputTags = ["input", "textarea", "radio", "button", "canvas"];
1871
+ var state$6 = [];
1872
+ function start$s() {
1873
+ reset$f();
1874
+ }
1875
+ function observe$a(root) {
1876
+ bind(root, "click", handler$2.bind(this, 9 /* Event.Click */, root), true);
1877
+ }
1878
+ function handler$2(event, root, evt) {
1879
+ var frame = iframe(root);
1880
+ var d = frame ? frame.contentDocument.documentElement : document.documentElement;
1881
+ var x = "pageX" in evt ? Math.round(evt.pageX) : ("clientX" in evt ? Math.round(evt["clientX"] + d.scrollLeft) : null);
1882
+ var y = "pageY" in evt ? Math.round(evt.pageY) : ("clientY" in evt ? Math.round(evt["clientY"] + d.scrollTop) : null);
1883
+ // In case of iframe, we adjust (x,y) to be relative to top parent's origin
1884
+ if (frame) {
1385
1885
  var distance = offset(frame);
1386
1886
  x = x ? x + Math.round(distance.x) : x;
1387
1887
  y = y ? y + Math.round(distance.y) : y;
@@ -1403,7 +1903,7 @@ function handler$3(event, root, evt) {
1403
1903
  var eY = l ? Math.max(Math.floor(((y - l.y) / l.h) * 32767 /* Setting.ClickPrecision */), 0) : 0;
1404
1904
  // Check for null values before processing this event
1405
1905
  if (x !== null && y !== null) {
1406
- state$7.push({
1906
+ state$6.push({
1407
1907
  time: time(evt),
1408
1908
  event: event,
1409
1909
  data: {
@@ -1478,39 +1978,39 @@ function context(a) {
1478
1978
  }
1479
1979
  return 0 /* BrowsingContext.Self */;
1480
1980
  }
1481
- function reset$h() {
1482
- state$7 = [];
1981
+ function reset$f() {
1982
+ state$6 = [];
1483
1983
  }
1484
- function stop$s() {
1485
- reset$h();
1984
+ function stop$q() {
1985
+ reset$f();
1486
1986
  }
1487
1987
 
1488
- var state$6 = [];
1489
- function start$t() {
1490
- reset$g();
1988
+ var state$5 = [];
1989
+ function start$r() {
1990
+ reset$e();
1491
1991
  }
1492
- function observe$a(root) {
1992
+ function observe$9(root) {
1493
1993
  bind(root, "cut", recompute$7.bind(this, 0 /* Clipboard.Cut */), true);
1494
1994
  bind(root, "copy", recompute$7.bind(this, 1 /* Clipboard.Copy */), true);
1495
1995
  bind(root, "paste", recompute$7.bind(this, 2 /* Clipboard.Paste */), true);
1496
1996
  }
1497
1997
  function recompute$7(action, evt) {
1498
- state$6.push({ time: time(evt), event: 38 /* Event.Clipboard */, data: { target: target(evt), action: action } });
1998
+ state$5.push({ time: time(evt), event: 38 /* Event.Clipboard */, data: { target: target(evt), action: action } });
1499
1999
  schedule$1(encode$3.bind(this, 38 /* Event.Clipboard */));
1500
2000
  }
1501
- function reset$g() {
1502
- state$6 = [];
2001
+ function reset$e() {
2002
+ state$5 = [];
1503
2003
  }
1504
- function stop$r() {
1505
- reset$g();
2004
+ function stop$p() {
2005
+ reset$e();
1506
2006
  }
1507
2007
 
1508
2008
  var timeout$5 = null;
1509
- var state$5 = [];
1510
- function start$s() {
1511
- reset$f();
2009
+ var state$4 = [];
2010
+ function start$q() {
2011
+ reset$d();
1512
2012
  }
1513
- function observe$9(root) {
2013
+ function observe$8(root) {
1514
2014
  bind(root, "input", recompute$6, true);
1515
2015
  }
1516
2016
  function recompute$6(evt) {
@@ -1526,31 +2026,31 @@ function recompute$6(evt) {
1526
2026
  }
1527
2027
  var data = { target: input, value: v };
1528
2028
  // If last entry in the queue is for the same target node as the current one, remove it so we can later swap it with current data.
1529
- if (state$5.length > 0 && (state$5[state$5.length - 1].data.target === data.target)) {
1530
- state$5.pop();
2029
+ if (state$4.length > 0 && (state$4[state$4.length - 1].data.target === data.target)) {
2030
+ state$4.pop();
1531
2031
  }
1532
- state$5.push({ time: time(evt), event: 27 /* Event.Input */, data: data });
2032
+ state$4.push({ time: time(evt), event: 27 /* Event.Input */, data: data });
1533
2033
  clearTimeout(timeout$5);
1534
- timeout$5 = setTimeout(process$6, 1000 /* Setting.InputLookAhead */, 27 /* Event.Input */);
2034
+ timeout$5 = setTimeout(process$5, 1000 /* Setting.InputLookAhead */, 27 /* Event.Input */);
1535
2035
  }
1536
2036
  }
1537
- function process$6(event) {
2037
+ function process$5(event) {
1538
2038
  schedule$1(encode$3.bind(this, event));
1539
2039
  }
1540
- function reset$f() {
1541
- state$5 = [];
2040
+ function reset$d() {
2041
+ state$4 = [];
1542
2042
  }
1543
- function stop$q() {
2043
+ function stop$o() {
1544
2044
  clearTimeout(timeout$5);
1545
- reset$f();
2045
+ reset$d();
1546
2046
  }
1547
2047
 
1548
- var state$4 = [];
2048
+ var state$3 = [];
1549
2049
  var timeout$4 = null;
1550
- function start$r() {
1551
- reset$e();
2050
+ function start$p() {
2051
+ reset$c();
1552
2052
  }
1553
- function observe$8(root) {
2053
+ function observe$7(root) {
1554
2054
  bind(root, "mousedown", mouse.bind(this, 13 /* Event.MouseDown */, root), true);
1555
2055
  bind(root, "mouseup", mouse.bind(this, 14 /* Event.MouseUp */, root), true);
1556
2056
  bind(root, "mousemove", mouse.bind(this, 12 /* Event.MouseMove */, root), true);
@@ -1574,7 +2074,7 @@ function mouse(event, root, evt) {
1574
2074
  }
1575
2075
  // Check for null values before processing this event
1576
2076
  if (x !== null && y !== null) {
1577
- handler$2({ time: time(evt), event: event, data: { target: target(evt), x: x, y: y } });
2077
+ handler$1({ time: time(evt), event: event, data: { target: target(evt), x: x, y: y } });
1578
2078
  }
1579
2079
  }
1580
2080
  function touch(event, root, evt) {
@@ -1591,36 +2091,36 @@ function touch(event, root, evt) {
1591
2091
  y = y && frame ? y + Math.round(frame.offsetTop) : y;
1592
2092
  // Check for null values before processing this event
1593
2093
  if (x !== null && y !== null) {
1594
- handler$2({ time: t, event: event, data: { target: target(evt), x: x, y: y } });
2094
+ handler$1({ time: t, event: event, data: { target: target(evt), x: x, y: y } });
1595
2095
  }
1596
2096
  }
1597
2097
  }
1598
2098
  }
1599
- function handler$2(current) {
2099
+ function handler$1(current) {
1600
2100
  switch (current.event) {
1601
2101
  case 12 /* Event.MouseMove */:
1602
2102
  case 15 /* Event.MouseWheel */:
1603
2103
  case 19 /* Event.TouchMove */:
1604
- var length_1 = state$4.length;
1605
- var last = length_1 > 1 ? state$4[length_1 - 2] : null;
2104
+ var length_1 = state$3.length;
2105
+ var last = length_1 > 1 ? state$3[length_1 - 2] : null;
1606
2106
  if (last && similar$1(last, current)) {
1607
- state$4.pop();
2107
+ state$3.pop();
1608
2108
  }
1609
- state$4.push(current);
2109
+ state$3.push(current);
1610
2110
  clearTimeout(timeout$4);
1611
- timeout$4 = setTimeout(process$5, 500 /* Setting.LookAhead */, current.event);
2111
+ timeout$4 = setTimeout(process$4, 500 /* Setting.LookAhead */, current.event);
1612
2112
  break;
1613
2113
  default:
1614
- state$4.push(current);
1615
- process$5(current.event);
2114
+ state$3.push(current);
2115
+ process$4(current.event);
1616
2116
  break;
1617
2117
  }
1618
2118
  }
1619
- function process$5(event) {
2119
+ function process$4(event) {
1620
2120
  schedule$1(encode$3.bind(this, event));
1621
2121
  }
1622
- function reset$e() {
1623
- state$4 = [];
2122
+ function reset$c() {
2123
+ state$3 = [];
1624
2124
  }
1625
2125
  function similar$1(last, current) {
1626
2126
  var dx = last.data.x - current.data.x;
@@ -1630,16 +2130,16 @@ function similar$1(last, current) {
1630
2130
  var match = current.data.target === last.data.target;
1631
2131
  return current.event === last.event && match && distance < 20 /* Setting.Distance */ && gap < 25 /* Setting.Interval */;
1632
2132
  }
1633
- function stop$p() {
2133
+ function stop$n() {
1634
2134
  clearTimeout(timeout$4);
1635
2135
  // Send out any pending pointer events in the pipeline
1636
- if (state$4.length > 0) {
1637
- process$5(state$4[state$4.length - 1].event);
2136
+ if (state$3.length > 0) {
2137
+ process$4(state$3[state$3.length - 1].event);
1638
2138
  }
1639
2139
  }
1640
2140
 
1641
2141
  var data$b;
1642
- function start$q() {
2142
+ function start$o() {
1643
2143
  bind(window, "resize", recompute$5);
1644
2144
  recompute$5();
1645
2145
  }
@@ -1653,20 +2153,20 @@ function recompute$5() {
1653
2153
  };
1654
2154
  encode$3(11 /* Event.Resize */);
1655
2155
  }
1656
- function reset$d() {
2156
+ function reset$b() {
1657
2157
  data$b = null;
1658
2158
  }
1659
- function stop$o() {
1660
- reset$d();
2159
+ function stop$m() {
2160
+ reset$b();
1661
2161
  }
1662
2162
 
1663
- var state$3 = [];
2163
+ var state$2 = [];
1664
2164
  var timeout$3 = null;
1665
- function start$p() {
1666
- state$3 = [];
2165
+ function start$n() {
2166
+ state$2 = [];
1667
2167
  recompute$4();
1668
2168
  }
1669
- function observe$7(root) {
2169
+ function observe$6(root) {
1670
2170
  var frame = iframe(root);
1671
2171
  var node = frame ? frame.contentWindow : (root === document ? window : root);
1672
2172
  bind(node, "scroll", recompute$4, true);
@@ -1692,19 +2192,19 @@ function recompute$4(event) {
1692
2192
  if ((event === null && x === 0 && y === 0) || (x === null || y === null)) {
1693
2193
  return;
1694
2194
  }
1695
- var length = state$3.length;
1696
- var last = length > 1 ? state$3[length - 2] : null;
2195
+ var length = state$2.length;
2196
+ var last = length > 1 ? state$2[length - 2] : null;
1697
2197
  if (last && similar(last, current)) {
1698
- state$3.pop();
2198
+ state$2.pop();
1699
2199
  }
1700
- state$3.push(current);
2200
+ state$2.push(current);
1701
2201
  clearTimeout(timeout$3);
1702
- timeout$3 = setTimeout(process$4, 500 /* Setting.LookAhead */, 10 /* Event.Scroll */);
2202
+ timeout$3 = setTimeout(process$3, 500 /* Setting.LookAhead */, 10 /* Event.Scroll */);
1703
2203
  }
1704
- function reset$c() {
1705
- state$3 = [];
2204
+ function reset$a() {
2205
+ state$2 = [];
1706
2206
  }
1707
- function process$4(event) {
2207
+ function process$3(event) {
1708
2208
  schedule$1(encode$3.bind(this, event));
1709
2209
  }
1710
2210
  function similar(last, current) {
@@ -1712,18 +2212,18 @@ function similar(last, current) {
1712
2212
  var dy = last.data.y - current.data.y;
1713
2213
  return (dx * dx + dy * dy < 20 /* Setting.Distance */ * 20 /* Setting.Distance */) && (current.time - last.time < 25 /* Setting.Interval */);
1714
2214
  }
1715
- function stop$n() {
2215
+ function stop$l() {
1716
2216
  clearTimeout(timeout$3);
1717
- state$3 = [];
2217
+ state$2 = [];
1718
2218
  }
1719
2219
 
1720
2220
  var data$a = null;
1721
2221
  var previous = null;
1722
2222
  var timeout$2 = null;
1723
- function start$o() {
1724
- reset$b();
2223
+ function start$m() {
2224
+ reset$9();
1725
2225
  }
1726
- function observe$6(root) {
2226
+ function observe$5(root) {
1727
2227
  bind(root, "selectstart", recompute$3.bind(this, root), true);
1728
2228
  bind(root, "selectionchange", recompute$3.bind(this, root), true);
1729
2229
  }
@@ -1745,7 +2245,7 @@ function recompute$3(root) {
1745
2245
  var startNode = data$a.start ? data$a.start : null;
1746
2246
  if (previous !== null && data$a.start !== null && startNode !== current.anchorNode) {
1747
2247
  clearTimeout(timeout$2);
1748
- process$3(21 /* Event.Selection */);
2248
+ process$2(21 /* Event.Selection */);
1749
2249
  }
1750
2250
  data$a = {
1751
2251
  start: current.anchorNode,
@@ -1755,40 +2255,40 @@ function recompute$3(root) {
1755
2255
  };
1756
2256
  previous = current;
1757
2257
  clearTimeout(timeout$2);
1758
- timeout$2 = setTimeout(process$3, 500 /* Setting.LookAhead */, 21 /* Event.Selection */);
2258
+ timeout$2 = setTimeout(process$2, 500 /* Setting.LookAhead */, 21 /* Event.Selection */);
1759
2259
  }
1760
- function process$3(event) {
2260
+ function process$2(event) {
1761
2261
  schedule$1(encode$3.bind(this, event));
1762
2262
  }
1763
- function reset$b() {
2263
+ function reset$9() {
1764
2264
  previous = null;
1765
2265
  data$a = { start: 0, startOffset: 0, end: 0, endOffset: 0 };
1766
2266
  }
1767
- function stop$m() {
1768
- reset$b();
2267
+ function stop$k() {
2268
+ reset$9();
1769
2269
  clearTimeout(timeout$2);
1770
2270
  }
1771
2271
 
1772
- var state$2 = [];
1773
- function start$n() {
1774
- reset$a();
2272
+ var state$1 = [];
2273
+ function start$l() {
2274
+ reset$8();
1775
2275
  }
1776
- function observe$5(root) {
2276
+ function observe$4(root) {
1777
2277
  bind(root, "submit", recompute$2, true);
1778
2278
  }
1779
2279
  function recompute$2(evt) {
1780
- state$2.push({ time: time(evt), event: 39 /* Event.Submit */, data: { target: target(evt) } });
2280
+ state$1.push({ time: time(evt), event: 39 /* Event.Submit */, data: { target: target(evt) } });
1781
2281
  schedule$1(encode$3.bind(this, 39 /* Event.Submit */));
1782
2282
  }
1783
- function reset$a() {
1784
- state$2 = [];
2283
+ function reset$8() {
2284
+ state$1 = [];
1785
2285
  }
1786
- function stop$l() {
1787
- reset$a();
2286
+ function stop$j() {
2287
+ reset$8();
1788
2288
  }
1789
2289
 
1790
2290
  var data$9;
1791
- function start$m() {
2291
+ function start$k() {
1792
2292
  bind(window, "pagehide", recompute$1);
1793
2293
  }
1794
2294
  function recompute$1(evt) {
@@ -1796,15 +2296,15 @@ function recompute$1(evt) {
1796
2296
  encode$3(26 /* Event.Unload */, time(evt));
1797
2297
  stop();
1798
2298
  }
1799
- function reset$9() {
2299
+ function reset$7() {
1800
2300
  data$9 = null;
1801
2301
  }
1802
- function stop$k() {
1803
- reset$9();
2302
+ function stop$i() {
2303
+ reset$7();
1804
2304
  }
1805
2305
 
1806
2306
  var data$8;
1807
- function start$l() {
2307
+ function start$j() {
1808
2308
  bind(document, "visibilitychange", recompute);
1809
2309
  recompute();
1810
2310
  }
@@ -1813,61 +2313,61 @@ function recompute(evt) {
1813
2313
  data$8 = { visible: "visibilityState" in document ? document.visibilityState : "default" };
1814
2314
  encode$3(28 /* Event.Visibility */, time(evt));
1815
2315
  }
1816
- function reset$8() {
2316
+ function reset$6() {
1817
2317
  data$8 = null;
1818
2318
  }
1819
- function stop$j() {
1820
- reset$8();
2319
+ function stop$h() {
2320
+ reset$6();
1821
2321
  }
1822
2322
 
1823
- function start$k() {
2323
+ function start$i() {
1824
2324
  start$g();
1825
- start$u();
1826
- start$t();
1827
- start$r();
1828
2325
  start$s();
1829
- start$q();
1830
- start$l();
2326
+ start$r();
1831
2327
  start$p();
2328
+ start$q();
1832
2329
  start$o();
1833
- start$v();
2330
+ start$j();
1834
2331
  start$n();
1835
2332
  start$m();
2333
+ start$t();
2334
+ start$l();
2335
+ start$k();
1836
2336
  }
1837
- function stop$i() {
2337
+ function stop$g() {
1838
2338
  stop$e();
1839
- stop$s();
1840
- stop$r();
1841
- stop$p();
1842
2339
  stop$q();
1843
- stop$o();
1844
- stop$j();
2340
+ stop$p();
1845
2341
  stop$n();
2342
+ stop$o();
1846
2343
  stop$m();
1847
- stop$t();
2344
+ stop$h();
1848
2345
  stop$l();
1849
2346
  stop$k();
2347
+ stop$r();
2348
+ stop$j();
2349
+ stop$i();
1850
2350
  }
1851
- function observe$4(root) {
1852
- observe$7(root);
2351
+ function observe$3(root) {
2352
+ observe$6(root);
1853
2353
  // Only monitor following interactions if the root node is a document
1854
2354
  // In case of shadow DOM, following events automatically bubble up to the parent document.
1855
2355
  if (root.nodeType === Node.DOCUMENT_NODE) {
1856
- observe$b(root);
1857
2356
  observe$a(root);
1858
- observe$8(root);
1859
2357
  observe$9(root);
1860
- observe$6(root);
1861
- observe$c(root);
2358
+ observe$7(root);
2359
+ observe$8(root);
1862
2360
  observe$5(root);
2361
+ observe$b(root);
2362
+ observe$4(root);
1863
2363
  }
1864
2364
  }
1865
2365
 
1866
2366
  var interaction = /*#__PURE__*/Object.freeze({
1867
2367
  __proto__: null,
1868
- observe: observe$4,
1869
- start: start$k,
1870
- stop: stop$i
2368
+ observe: observe$3,
2369
+ start: start$i,
2370
+ stop: stop$g
1871
2371
  });
1872
2372
 
1873
2373
  var digitsRegex = /[^0-9\.]/g;
@@ -1970,7 +2470,7 @@ function processNode (node, source) {
1970
2470
  // later whenever there are new additions or modifications to DOM (mutations)
1971
2471
  if (node === document)
1972
2472
  parse$1(document);
1973
- observe$3(node);
2473
+ observe$2(node);
1974
2474
  break;
1975
2475
  case Node.DOCUMENT_FRAGMENT_NODE:
1976
2476
  var shadowRoot = node;
@@ -1978,7 +2478,7 @@ function processNode (node, source) {
1978
2478
  parse$1(shadowRoot);
1979
2479
  var type = typeof (shadowRoot.constructor);
1980
2480
  if (type === "function" /* Constant.Function */ && shadowRoot.constructor.toString().indexOf("[native code]" /* Constant.NativeCode */) >= 0) {
1981
- observe$3(shadowRoot);
2481
+ observe$2(shadowRoot);
1982
2482
  // See: https://wicg.github.io/construct-stylesheets/ for more details on adoptedStyleSheets.
1983
2483
  // At the moment, we are only able to capture "open" shadow DOM nodes. If they are closed, they are not accessible.
1984
2484
  // In future we may decide to proxy "attachShadow" call to gain access, but at the moment, we don't want to
@@ -2063,7 +2563,7 @@ function processNode (node, source) {
2063
2563
  case "HEAD":
2064
2564
  var head = { tag: tag, attributes: attributes };
2065
2565
  var l = insideFrame && ((_a = node.ownerDocument) === null || _a === void 0 ? void 0 : _a.location) ? node.ownerDocument.location : location;
2066
- head.attributes["*B" /* Constant.Base */] = l.protocol + "//" + l.hostname + l.pathname;
2566
+ head.attributes["*B" /* Constant.Base */] = l.protocol + "//" + l.host + l.pathname;
2067
2567
  dom[call](node, parent, head, source);
2068
2568
  break;
2069
2569
  case "BASE":
@@ -2073,7 +2573,7 @@ function processNode (node, source) {
2073
2573
  // We create "a" element so we can generate protocol and hostname for relative paths like "/path/"
2074
2574
  var a = document.createElement("a");
2075
2575
  a.href = attributes["href"];
2076
- baseHead.data.attributes["*B" /* Constant.Base */] = a.protocol + "//" + a.hostname + a.pathname;
2576
+ baseHead.data.attributes["*B" /* Constant.Base */] = a.protocol + "//" + a.host + a.pathname;
2077
2577
  }
2078
2578
  break;
2079
2579
  case "STYLE":
@@ -2098,931 +2598,400 @@ function processNode (node, source) {
2098
2598
  child = element.shadowRoot;
2099
2599
  }
2100
2600
  dom[call](node, parent, data, source);
2101
- break;
2102
- }
2103
- break;
2104
- }
2105
- return child;
2106
- }
2107
- function observe$3(root) {
2108
- if (has(root)) {
2109
- return;
2110
- }
2111
- observe$2(root); // Observe mutations for this root node
2112
- observe$4(root); // Observe interactions for this root node
2113
- }
2114
- function getStyleValue(style) {
2115
- // Call trim on the text content to ensure we do not process white spaces ( , \n, \r\n, \t, etc.)
2116
- // Also, check if stylesheet has any data-* attribute, if so process rules instead of looking up text
2117
- var value = style.textContent ? style.textContent.trim() : "" /* Constant.Empty */;
2118
- var dataset = style.dataset ? Object.keys(style.dataset).length : 0;
2119
- if (value.length === 0 || dataset > 0) {
2120
- value = getCssRules(style.sheet);
2121
- }
2122
- return value;
2123
- }
2124
- function getCssRules(sheet) {
2125
- var value = "" /* Constant.Empty */;
2126
- var cssRules = null;
2127
- // Firefox throws a SecurityError when trying to access cssRules of a stylesheet from a different domain
2128
- try {
2129
- cssRules = sheet ? sheet.cssRules : [];
2130
- }
2131
- catch (e) {
2132
- log$1(1 /* Code.CssRules */, 1 /* Severity.Warning */, e ? e.name : null);
2133
- if (e && e.name !== "SecurityError") {
2134
- throw e;
2135
- }
2136
- }
2137
- if (cssRules !== null) {
2138
- for (var i = 0; i < cssRules.length; i++) {
2139
- value += cssRules[i].cssText;
2140
- }
2141
- }
2142
- return value;
2143
- }
2144
- function getAttributes(element) {
2145
- var output = {};
2146
- var attributes = element.attributes;
2147
- if (attributes && attributes.length > 0) {
2148
- for (var i = 0; i < attributes.length; i++) {
2149
- var name_1 = attributes[i].name;
2150
- if (IGNORE_ATTRIBUTES.indexOf(name_1) < 0) {
2151
- output[name_1] = attributes[i].value;
2152
- }
2153
- }
2154
- }
2155
- // For INPUT tags read the dynamic "value" property if an explicit "value" attribute is not set
2156
- if (element.tagName === "INPUT" /* Constant.InputTag */ && !("value" /* Constant.Value */ in output) && element.value) {
2157
- output["value" /* Constant.Value */] = element.value;
2158
- }
2159
- return output;
2160
- }
2161
-
2162
- function traverse (root, timer, source) {
2163
- return __awaiter(this, void 0, void 0, function () {
2164
- var queue, node, next, state, subnode;
2165
- return __generator(this, function (_a) {
2166
- switch (_a.label) {
2167
- case 0:
2168
- queue = [root];
2169
- _a.label = 1;
2170
- case 1:
2171
- if (!(queue.length > 0)) return [3 /*break*/, 4];
2172
- node = queue.shift();
2173
- next = node.firstChild;
2174
- while (next) {
2175
- queue.push(next);
2176
- next = next.nextSibling;
2177
- }
2178
- state = state$9(timer);
2179
- if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 3];
2180
- return [4 /*yield*/, suspend$1(timer)];
2181
- case 2:
2182
- state = _a.sent();
2183
- _a.label = 3;
2184
- case 3:
2185
- if (state === 2 /* Task.Stop */) {
2186
- return [3 /*break*/, 4];
2187
- }
2188
- subnode = processNode(node, source);
2189
- if (subnode) {
2190
- queue.push(subnode);
2191
- }
2192
- return [3 /*break*/, 1];
2193
- case 4: return [2 /*return*/];
2194
- }
2195
- });
2196
- });
2197
- }
2198
-
2199
- var observers = [];
2200
- var mutations = [];
2201
- var insertRule = null;
2202
- var deleteRule = null;
2203
- var attachShadow = null;
2204
- var queue$2 = [];
2205
- var timeout$1 = null;
2206
- var activePeriod = null;
2207
- var history$4 = {};
2208
- function start$j() {
2209
- observers = [];
2210
- queue$2 = [];
2211
- timeout$1 = null;
2212
- activePeriod = 0;
2213
- history$4 = {};
2214
- // Some popular open source libraries, like styled-components, optimize performance
2215
- // by injecting CSS using insertRule API vs. appending text node. A side effect of
2216
- // using javascript API is that it doesn't trigger DOM mutation and therefore we
2217
- // need to override the insertRule API and listen for changes manually.
2218
- if (insertRule === null) {
2219
- insertRule = CSSStyleSheet.prototype.insertRule;
2220
- CSSStyleSheet.prototype.insertRule = function () {
2221
- if (active()) {
2222
- schedule(this.ownerNode);
2223
- }
2224
- return insertRule.apply(this, arguments);
2225
- };
2226
- }
2227
- if (deleteRule === null) {
2228
- deleteRule = CSSStyleSheet.prototype.deleteRule;
2229
- CSSStyleSheet.prototype.deleteRule = function () {
2230
- if (active()) {
2231
- schedule(this.ownerNode);
2232
- }
2233
- return deleteRule.apply(this, arguments);
2234
- };
2235
- }
2236
- // Add a hook to attachShadow API calls
2237
- // In case we are unable to add a hook and browser throws an exception,
2238
- // reset attachShadow variable and resume processing like before
2239
- if (attachShadow === null) {
2240
- attachShadow = Element.prototype.attachShadow;
2241
- try {
2242
- Element.prototype.attachShadow = function () {
2243
- if (active()) {
2244
- return schedule(attachShadow.apply(this, arguments));
2245
- }
2246
- else {
2247
- return attachShadow.apply(this, arguments);
2248
- }
2249
- };
2250
- }
2251
- catch (_a) {
2252
- attachShadow = null;
2253
- }
2254
- }
2255
- }
2256
- function observe$2(node) {
2257
- // Create a new observer for every time a new DOM tree (e.g. root document or shadowdom root) is discovered on the page
2258
- // In the case of shadow dom, any mutations that happen within the shadow dom are not bubbled up to the host document
2259
- // For this reason, we need to wire up mutations every time we see a new shadow dom.
2260
- // Also, wrap it inside a try / catch. In certain browsers (e.g. legacy Edge), observer on shadow dom can throw errors
2261
- try {
2262
- var m = api("MutationObserver" /* Constant.MutationObserver */);
2263
- var observer = m in window ? new window[m](measure(handle$1)) : null;
2264
- if (observer) {
2265
- observer.observe(node, { attributes: true, childList: true, characterData: true, subtree: true });
2266
- observers.push(observer);
2267
- }
2268
- }
2269
- catch (e) {
2270
- log$1(2 /* Code.MutationObserver */, 0 /* Severity.Info */, e ? e.name : null);
2271
- }
2272
- }
2273
- function monitor(frame) {
2274
- // Bind to iframe's onload event so we get notified anytime there's an update to iframe content.
2275
- // This includes cases where iframe location is updated without explicitly updating src attribute
2276
- // E.g. iframe.contentWindow.location.href = "new-location";
2277
- if (has(frame) === false) {
2278
- bind(frame, "load" /* Constant.LoadEvent */, generate.bind(this, frame, "childList" /* Constant.ChildList */), true);
2279
- }
2280
- }
2281
- function stop$h() {
2282
- for (var _i = 0, observers_1 = observers; _i < observers_1.length; _i++) {
2283
- var observer = observers_1[_i];
2284
- if (observer) {
2285
- observer.disconnect();
2286
- }
2287
- }
2288
- observers = [];
2289
- history$4 = {};
2290
- mutations = [];
2291
- queue$2 = [];
2292
- activePeriod = 0;
2293
- timeout$1 = null;
2294
- }
2295
- function active$2() {
2296
- activePeriod = time() + 3000 /* Setting.MutationActivePeriod */;
2297
- }
2298
- function handle$1(m) {
2299
- // Queue up mutation records for asynchronous processing
2300
- var now = time();
2301
- track$6(6 /* Event.Mutation */, now);
2302
- mutations.push({ time: now, mutations: m });
2303
- schedule$1(process$2, 1 /* Priority.High */).then(function () {
2304
- setTimeout(compute$7);
2305
- measure(compute$6)();
2306
- });
2307
- }
2308
- function process$2() {
2309
- return __awaiter(this, void 0, void 0, function () {
2310
- var timer, record, instance, _i, _a, mutation, state, target, type, value;
2311
- return __generator(this, function (_b) {
2312
- switch (_b.label) {
2313
- case 0:
2314
- timer = { id: id(), cost: 3 /* Metric.LayoutCost */ };
2315
- start$x(timer);
2316
- _b.label = 1;
2317
- case 1:
2318
- if (!(mutations.length > 0)) return [3 /*break*/, 8];
2319
- record = mutations.shift();
2320
- instance = time();
2321
- _i = 0, _a = record.mutations;
2322
- _b.label = 2;
2323
- case 2:
2324
- if (!(_i < _a.length)) return [3 /*break*/, 6];
2325
- mutation = _a[_i];
2326
- state = state$9(timer);
2327
- if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 4];
2328
- return [4 /*yield*/, suspend$1(timer)];
2329
- case 3:
2330
- state = _b.sent();
2331
- _b.label = 4;
2332
- case 4:
2333
- if (state === 2 /* Task.Stop */) {
2334
- return [3 /*break*/, 6];
2335
- }
2336
- target = mutation.target;
2337
- type = track$5(mutation, timer, instance);
2338
- if (type && target && target.ownerDocument) {
2339
- parse$1(target.ownerDocument);
2340
- }
2341
- if (type && target && target.nodeType == Node.DOCUMENT_FRAGMENT_NODE && target.host) {
2342
- parse$1(target);
2343
- }
2344
- switch (type) {
2345
- case "attributes" /* Constant.Attributes */:
2346
- processNode(target, 3 /* Source.Attributes */);
2347
- break;
2348
- case "characterData" /* Constant.CharacterData */:
2349
- processNode(target, 4 /* Source.CharacterData */);
2350
- break;
2351
- case "childList" /* Constant.ChildList */:
2352
- processNodeList(mutation.addedNodes, 1 /* Source.ChildListAdd */, timer);
2353
- processNodeList(mutation.removedNodes, 2 /* Source.ChildListRemove */, timer);
2354
- break;
2355
- case "suspend" /* Constant.Suspend */:
2356
- value = get(target);
2357
- if (value) {
2358
- value.metadata.suspend = true;
2359
- }
2360
- break;
2361
- }
2362
- _b.label = 5;
2363
- case 5:
2364
- _i++;
2365
- return [3 /*break*/, 2];
2366
- case 6: return [4 /*yield*/, encode$4(6 /* Event.Mutation */, timer, record.time)];
2367
- case 7:
2368
- _b.sent();
2369
- return [3 /*break*/, 1];
2370
- case 8:
2371
- stop$u(timer);
2372
- return [2 /*return*/];
2373
- }
2374
- });
2375
- });
2376
- }
2377
- function track$5(m, timer, instance) {
2378
- var value = m.target ? get(m.target.parentNode) : null;
2379
- // Check if the parent is already discovered and that the parent is not the document root
2380
- if (value && value.data.tag !== "HTML" /* Constant.HTML */) {
2381
- var inactive = time() > activePeriod;
2382
- var target = get(m.target);
2383
- var element = target && target.selector ? target.selector.join() : m.target.nodeName;
2384
- var parent_1 = value.selector ? value.selector.join() : "" /* Constant.Empty */;
2385
- // We use selector, instead of id, to determine the key (signature for the mutation) because in some cases
2386
- // repeated mutations can cause elements to be destroyed and then recreated as new DOM nodes
2387
- // In those cases, IDs will change however the selector (which is relative to DOM xPath) remains the same
2388
- var key = [parent_1, element, m.attributeName, names(m.addedNodes), names(m.removedNodes)].join();
2389
- // Initialize an entry if it doesn't already exist
2390
- history$4[key] = key in history$4 ? history$4[key] : [0, instance];
2391
- var h = history$4[key];
2392
- // Lookup any pending nodes queued up for removal, and process them now if we suspended a mutation before
2393
- if (inactive === false && h[0] >= 10 /* Setting.MutationSuspendThreshold */) {
2394
- processNodeList(h[2], 2 /* Source.ChildListRemove */, timer);
2395
- }
2396
- // Update the counter
2397
- h[0] = inactive ? (h[1] === instance ? h[0] : h[0] + 1) : 1;
2398
- h[1] = instance;
2399
- // Return updated mutation type based on if we have already hit the threshold or not
2400
- if (h[0] === 10 /* Setting.MutationSuspendThreshold */) {
2401
- // Store a reference to removedNodes so we can process them later
2402
- // when we resume mutations again on user interactions
2403
- h[2] = m.removedNodes;
2404
- return "suspend" /* Constant.Suspend */;
2405
- }
2406
- else if (h[0] > 10 /* Setting.MutationSuspendThreshold */) {
2407
- return "" /* Constant.Empty */;
2408
- }
2409
- }
2410
- return m.type;
2411
- }
2412
- function names(nodes) {
2413
- var output = [];
2414
- for (var i = 0; nodes && i < nodes.length; i++) {
2415
- output.push(nodes[i].nodeName);
2416
- }
2417
- return output.join();
2418
- }
2419
- function processNodeList(list, source, timer) {
2420
- return __awaiter(this, void 0, void 0, function () {
2421
- var length, i, state;
2422
- return __generator(this, function (_a) {
2423
- switch (_a.label) {
2424
- case 0:
2425
- length = list ? list.length : 0;
2426
- i = 0;
2427
- _a.label = 1;
2428
- case 1:
2429
- if (!(i < length)) return [3 /*break*/, 6];
2430
- if (!(source === 1 /* Source.ChildListAdd */)) return [3 /*break*/, 2];
2431
- traverse(list[i], timer, source);
2432
- return [3 /*break*/, 5];
2433
- case 2:
2434
- state = state$9(timer);
2435
- if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 4];
2436
- return [4 /*yield*/, suspend$1(timer)];
2437
- case 3:
2438
- state = _a.sent();
2439
- _a.label = 4;
2440
- case 4:
2441
- if (state === 2 /* Task.Stop */) {
2442
- return [3 /*break*/, 6];
2443
- }
2444
- processNode(list[i], source);
2445
- _a.label = 5;
2446
- case 5:
2447
- i++;
2448
- return [3 /*break*/, 1];
2449
- case 6: return [2 /*return*/];
2450
- }
2451
- });
2452
- });
2453
- }
2454
- function schedule(node, fragment) {
2455
- if (fragment === void 0) { fragment = false; }
2456
- // Only schedule manual trigger for this node if it's not already in the queue
2457
- if (queue$2.indexOf(node) < 0) {
2458
- queue$2.push(node);
2459
- }
2460
- // Cancel any previous trigger before scheduling a new one.
2461
- // It's common for a webpage to call multiple synchronous "insertRule" / "deleteRule" calls.
2462
- // And in those cases we do not wish to monitor changes multiple times for the same node.
2463
- if (timeout$1) {
2464
- clearTimeout(timeout$1);
2465
- }
2466
- timeout$1 = setTimeout(function () { trigger$1(fragment); }, 33 /* Setting.LookAhead */);
2467
- return node;
2468
- }
2469
- function trigger$1(fragment) {
2470
- for (var _i = 0, queue_1 = queue$2; _i < queue_1.length; _i++) {
2471
- var node = queue_1[_i];
2472
- // Generate a mutation for this node only if it still exists
2473
- if (node) {
2474
- var shadowRoot = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
2475
- // Skip re-processing shadowRoot if it was already discovered
2476
- if (shadowRoot && has(node)) {
2477
- continue;
2478
- }
2479
- generate(node, shadowRoot || fragment ? "childList" /* Constant.ChildList */ : "characterData" /* Constant.CharacterData */);
2480
- }
2481
- }
2482
- queue$2 = [];
2483
- }
2484
- function generate(target, type) {
2485
- measure(handle$1)([{
2486
- addedNodes: [target],
2487
- attributeName: null,
2488
- attributeNamespace: null,
2489
- nextSibling: null,
2490
- oldValue: null,
2491
- previousSibling: null,
2492
- removedNodes: [],
2493
- target: target,
2494
- type: type
2495
- }]);
2496
- }
2497
-
2498
- var index = 1;
2499
- var nodes = [];
2500
- var values = [];
2501
- var updateMap = [];
2502
- var hashMap = {};
2503
- var override = [];
2504
- var unmask = [];
2505
- var updatedFragments = {};
2506
- var maskText = [];
2507
- var maskExclude = [];
2508
- var maskDisable = [];
2509
- var maskTags = [];
2510
- // The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced
2511
- var idMap = null; // Maps node => id.
2512
- var iframeMap = null; // Maps iframe's contentDocument => parent iframe element
2513
- var privacyMap = null; // Maps node => Privacy (enum)
2514
- var fraudMap = null; // Maps node => FraudId (number)
2515
- function start$i() {
2516
- reset$7();
2517
- parse$1(document, true);
2518
- }
2519
- function stop$g() {
2520
- reset$7();
2521
- }
2522
- function reset$7() {
2523
- index = 1;
2524
- nodes = [];
2525
- values = [];
2526
- updateMap = [];
2527
- hashMap = {};
2528
- override = [];
2529
- unmask = [];
2530
- maskText = "address,password,contact" /* Mask.Text */.split("," /* Constant.Comma */);
2531
- maskExclude = "password,secret,pass,social,ssn,code,hidden" /* Mask.Exclude */.split("," /* Constant.Comma */);
2532
- maskDisable = "radio,checkbox,range,button,reset,submit" /* Mask.Disable */.split("," /* Constant.Comma */);
2533
- maskTags = "INPUT,SELECT,TEXTAREA" /* Mask.Tags */.split("," /* Constant.Comma */);
2534
- idMap = new WeakMap();
2535
- iframeMap = new WeakMap();
2536
- privacyMap = new WeakMap();
2537
- fraudMap = new WeakMap();
2538
- reset$l();
2539
- }
2540
- // We parse new root nodes for any regions or masked nodes in the beginning (document) and
2541
- // later whenever there are new additions or modifications to DOM (mutations)
2542
- function parse$1(root, init) {
2543
- if (init === void 0) { init = false; }
2544
- // Wrap selectors in a try / catch block.
2545
- // It's possible for script to receive invalid selectors, e.g. "'#id'" with extra quotes, and cause the code below to fail
2546
- try {
2547
- // Parse unmask configuration into separate query selectors and override tokens as part of initialization
2548
- if (init) {
2549
- config$1.unmask.forEach(function (x) { return x.indexOf("!" /* Constant.Bang */) < 0 ? unmask.push(x) : override.push(x.substr(1)); });
2550
- }
2551
- // Since mutations may happen on leaf nodes too, e.g. text nodes, which may not support all selector APIs.
2552
- // We ensure that the root note supports querySelectorAll API before executing the code below to identify new regions.
2553
- if ("querySelectorAll" in root) {
2554
- config$1.regions.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return observe$1(e, "".concat(x[0])); }); }); // Regions
2555
- config$1.mask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 3 /* Privacy.TextImage */); }); }); // Masked Elements
2556
- config$1.checksum.forEach(function (x) { return root.querySelectorAll(x[1]).forEach(function (e) { return fraudMap.set(e, x[0]); }); }); // Fraud Checksum Check
2557
- unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* Privacy.None */); }); }); // Unmasked Elements
2558
- }
2559
- }
2560
- catch (e) {
2561
- log$1(5 /* Code.Selector */, 1 /* Severity.Warning */, e ? e.name : null);
2601
+ break;
2602
+ }
2603
+ break;
2562
2604
  }
2605
+ return child;
2563
2606
  }
2564
- function getId(node, autogen) {
2565
- if (autogen === void 0) { autogen = false; }
2566
- if (node === null) {
2567
- return null;
2568
- }
2569
- var id = idMap.get(node);
2570
- if (!id && autogen) {
2571
- id = index++;
2572
- idMap.set(node, id);
2607
+ function observe$2(root) {
2608
+ if (has(root)) {
2609
+ return;
2573
2610
  }
2574
- return id ? id : null;
2611
+ observe$1(root); // Observe mutations for this root node
2612
+ observe$3(root); // Observe interactions for this root node
2575
2613
  }
2576
- function add(node, parent, data, source) {
2577
- var id = getId(node, true);
2578
- var parentId = parent ? getId(parent) : null;
2579
- var previousId = getPreviousId(node);
2580
- var parentValue = null;
2581
- var regionId = exists(node) ? id : null;
2582
- var fragmentId = null;
2583
- var fraudId = fraudMap.has(node) ? fraudMap.get(node) : null;
2584
- var privacyId = config$1.content ? 1 /* Privacy.Sensitive */ : 3 /* Privacy.TextImage */;
2585
- if (parentId >= 0 && values[parentId]) {
2586
- parentValue = values[parentId];
2587
- parentValue.children.push(id);
2588
- regionId = regionId === null ? parentValue.region : regionId;
2589
- fragmentId = parentValue.fragment;
2590
- fraudId = fraudId === null ? parentValue.metadata.fraud : fraudId;
2591
- privacyId = parentValue.metadata.privacy;
2592
- }
2593
- // If there's an explicit region attribute set on the element, use it to mark a region on the page
2594
- if (data.attributes && "data-clarity-region" /* Constant.RegionData */ in data.attributes) {
2595
- observe$1(node, data.attributes["data-clarity-region" /* Constant.RegionData */]);
2596
- regionId = id;
2614
+ function getStyleValue(style) {
2615
+ // Call trim on the text content to ensure we do not process white spaces ( , \n, \r\n, \t, etc.)
2616
+ // Also, check if stylesheet has any data-* attribute, if so process rules instead of looking up text
2617
+ var value = style.textContent ? style.textContent.trim() : "" /* Constant.Empty */;
2618
+ var dataset = style.dataset ? Object.keys(style.dataset).length : 0;
2619
+ if (value.length === 0 || dataset > 0) {
2620
+ value = getCssRules(style.sheet);
2597
2621
  }
2598
- nodes[id] = node;
2599
- values[id] = {
2600
- id: id,
2601
- parent: parentId,
2602
- previous: previousId,
2603
- children: [],
2604
- data: data,
2605
- selector: null,
2606
- hash: null,
2607
- region: regionId,
2608
- metadata: { active: true, suspend: false, privacy: privacyId, position: null, fraud: fraudId, size: null },
2609
- fragment: fragmentId,
2610
- };
2611
- privacy(node, values[id], parentValue);
2612
- updateSelector(values[id]);
2613
- size(values[id]);
2614
- track$4(id, source, values[id].fragment);
2622
+ return value;
2615
2623
  }
2616
- function update$1(node, parent, data, source) {
2617
- var id = getId(node);
2618
- var parentId = parent ? getId(parent) : null;
2619
- var previousId = getPreviousId(node);
2620
- var changed = false;
2621
- var parentChanged = false;
2622
- if (id in values) {
2623
- var value = values[id];
2624
- value.metadata.active = true;
2625
- // Handle case where internal ordering may have changed
2626
- if (value.previous !== previousId) {
2627
- changed = true;
2628
- value.previous = previousId;
2629
- }
2630
- // Handle case where parent might have been updated
2631
- if (value.parent !== parentId) {
2632
- changed = true;
2633
- var oldParentId = value.parent;
2634
- value.parent = parentId;
2635
- // Move this node to the right location under new parent
2636
- if (parentId !== null && parentId >= 0) {
2637
- var childIndex = previousId === null ? 0 : values[parentId].children.indexOf(previousId) + 1;
2638
- values[parentId].children.splice(childIndex, 0, id);
2639
- // Update region after the move
2640
- value.region = exists(node) ? id : values[parentId].region;
2641
- }
2642
- else {
2643
- // Mark this element as deleted if the parent has been updated to null
2644
- remove(id, source);
2645
- }
2646
- // Remove reference to this node from the old parent
2647
- if (oldParentId !== null && oldParentId >= 0) {
2648
- var nodeIndex = values[oldParentId].children.indexOf(id);
2649
- if (nodeIndex >= 0) {
2650
- values[oldParentId].children.splice(nodeIndex, 1);
2651
- }
2652
- }
2653
- parentChanged = true;
2654
- }
2655
- // Update data
2656
- for (var key in data) {
2657
- if (diff(value["data"], data, key)) {
2658
- changed = true;
2659
- value["data"][key] = data[key];
2660
- }
2624
+ function getCssRules(sheet) {
2625
+ var value = "" /* Constant.Empty */;
2626
+ var cssRules = null;
2627
+ // Firefox throws a SecurityError when trying to access cssRules of a stylesheet from a different domain
2628
+ try {
2629
+ cssRules = sheet ? sheet.cssRules : [];
2630
+ }
2631
+ catch (e) {
2632
+ log$1(1 /* Code.CssRules */, 1 /* Severity.Warning */, e ? e.name : null);
2633
+ if (e && e.name !== "SecurityError") {
2634
+ throw e;
2661
2635
  }
2662
- // track node if it is a part of scheduled fragment mutation
2663
- if (value.fragment && updatedFragments[value.fragment]) {
2664
- changed = true;
2636
+ }
2637
+ if (cssRules !== null) {
2638
+ for (var i = 0; i < cssRules.length; i++) {
2639
+ value += cssRules[i].cssText;
2665
2640
  }
2666
- // Update selector
2667
- updateSelector(value);
2668
- track$4(id, source, values[id].fragment, changed, parentChanged);
2669
2641
  }
2642
+ return value;
2670
2643
  }
2671
- function sameorigin(node) {
2672
- var output = false;
2673
- if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "IFRAME" /* Constant.IFrameTag */) {
2674
- var frame = node;
2675
- // To determine if the iframe is same-origin or not, we try accessing it's contentDocument.
2676
- // If the browser throws an exception, we assume it's cross-origin and move on.
2677
- // However, if we do a get a valid document object back, we assume the contents are accessible and iframe is same-origin.
2678
- try {
2679
- var doc = frame.contentDocument;
2680
- if (doc) {
2681
- iframeMap.set(frame.contentDocument, frame);
2682
- output = true;
2644
+ function getAttributes(element) {
2645
+ var output = {};
2646
+ var attributes = element.attributes;
2647
+ if (attributes && attributes.length > 0) {
2648
+ for (var i = 0; i < attributes.length; i++) {
2649
+ var name_1 = attributes[i].name;
2650
+ if (IGNORE_ATTRIBUTES.indexOf(name_1) < 0) {
2651
+ output[name_1] = attributes[i].value;
2683
2652
  }
2684
2653
  }
2685
- catch ( /* do nothing */_a) { /* do nothing */ }
2686
2654
  }
2687
- return output;
2688
- }
2689
- function iframe(node) {
2690
- var doc = node.nodeType === Node.DOCUMENT_NODE ? node : null;
2691
- return doc && iframeMap.has(doc) ? iframeMap.get(doc) : null;
2692
- }
2693
- function privacy(node, value, parent) {
2694
- var data = value.data;
2695
- var metadata = value.metadata;
2696
- var current = metadata.privacy;
2697
- var attributes = data.attributes || {};
2698
- var tag = data.tag.toUpperCase();
2699
- switch (true) {
2700
- case maskTags.indexOf(tag) >= 0:
2701
- var type = attributes["type" /* Constant.Type */];
2702
- var meta_1 = "" /* Constant.Empty */;
2703
- Object.keys(attributes).forEach(function (x) { return meta_1 += attributes[x].toLowerCase(); });
2704
- var exclude = maskExclude.some(function (x) { return meta_1.indexOf(x) >= 0; });
2705
- // Regardless of privacy mode, always mask off user input from input boxes or drop downs with two exceptions:
2706
- // (1) The node is detected to be one of the excluded fields, in which case we drop everything
2707
- // (2) The node's type is one of the allowed types (like checkboxes)
2708
- metadata.privacy = tag === "INPUT" /* Constant.InputTag */ && maskDisable.indexOf(type) >= 0 ? current : (exclude ? 4 /* Privacy.Exclude */ : 2 /* Privacy.Text */);
2709
- break;
2710
- case "data-clarity-mask" /* Constant.MaskData */ in attributes:
2711
- metadata.privacy = 3 /* Privacy.TextImage */;
2712
- break;
2713
- case "data-clarity-unmask" /* Constant.UnmaskData */ in attributes:
2714
- metadata.privacy = 0 /* Privacy.None */;
2715
- break;
2716
- case privacyMap.has(node):
2717
- // If this node was explicitly configured to contain sensitive content, honor that privacy setting
2718
- metadata.privacy = privacyMap.get(node);
2719
- break;
2720
- case fraudMap.has(node):
2721
- // If this node was explicitly configured to be evaluated for fraud, then also mask content
2722
- metadata.privacy = 2 /* Privacy.Text */;
2723
- break;
2724
- case tag === "*T" /* Constant.TextTag */:
2725
- // If it's a text node belonging to a STYLE or TITLE tag or one of scrub exceptions, then capture content
2726
- var pTag = parent && parent.data ? parent.data.tag : "" /* Constant.Empty */;
2727
- var pSelector_1 = parent && parent.selector ? parent.selector[1 /* Selector.Default */] : "" /* Constant.Empty */;
2728
- var tags = ["STYLE" /* Constant.StyleTag */, "TITLE" /* Constant.TitleTag */, "svg:style" /* Constant.SvgStyle */];
2729
- metadata.privacy = tags.includes(pTag) || override.some(function (x) { return pSelector_1.indexOf(x) >= 0; }) ? 0 /* Privacy.None */ : current;
2730
- break;
2731
- case current === 1 /* Privacy.Sensitive */:
2732
- // In a mode where we mask sensitive information by default, look through class names to aggressively mask content
2733
- metadata.privacy = inspect(attributes["class" /* Constant.Class */], maskText, metadata);
2734
- break;
2655
+ // For INPUT tags read the dynamic "value" property if an explicit "value" attribute is not set
2656
+ if (element.tagName === "INPUT" /* Constant.InputTag */ && !("value" /* Constant.Value */ in output) && element.value) {
2657
+ output["value" /* Constant.Value */] = element.value;
2735
2658
  }
2736
- }
2737
- function inspect(input, lookup, metadata) {
2738
- if (input && lookup.some(function (x) { return input.indexOf(x) >= 0; })) {
2739
- return 2 /* Privacy.Text */;
2659
+ return output;
2660
+ }
2661
+
2662
+ function traverse (root, timer, source) {
2663
+ return __awaiter(this, void 0, void 0, function () {
2664
+ var queue, node, next, state, subnode;
2665
+ return __generator(this, function (_a) {
2666
+ switch (_a.label) {
2667
+ case 0:
2668
+ queue = [root];
2669
+ _a.label = 1;
2670
+ case 1:
2671
+ if (!(queue.length > 0)) return [3 /*break*/, 4];
2672
+ node = queue.shift();
2673
+ next = node.firstChild;
2674
+ while (next) {
2675
+ queue.push(next);
2676
+ next = next.nextSibling;
2677
+ }
2678
+ state = state$9(timer);
2679
+ if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 3];
2680
+ return [4 /*yield*/, suspend$1(timer)];
2681
+ case 2:
2682
+ state = _a.sent();
2683
+ _a.label = 3;
2684
+ case 3:
2685
+ if (state === 2 /* Task.Stop */) {
2686
+ return [3 /*break*/, 4];
2687
+ }
2688
+ subnode = processNode(node, source);
2689
+ if (subnode) {
2690
+ queue.push(subnode);
2691
+ }
2692
+ return [3 /*break*/, 1];
2693
+ case 4: return [2 /*return*/];
2694
+ }
2695
+ });
2696
+ });
2697
+ }
2698
+
2699
+ var observers = [];
2700
+ var mutations = [];
2701
+ var insertRule = null;
2702
+ var deleteRule = null;
2703
+ var attachShadow = null;
2704
+ var queue$1 = [];
2705
+ var timeout$1 = null;
2706
+ var activePeriod = null;
2707
+ var history$4 = {};
2708
+ function start$h() {
2709
+ observers = [];
2710
+ queue$1 = [];
2711
+ timeout$1 = null;
2712
+ activePeriod = 0;
2713
+ history$4 = {};
2714
+ // Some popular open source libraries, like styled-components, optimize performance
2715
+ // by injecting CSS using insertRule API vs. appending text node. A side effect of
2716
+ // using javascript API is that it doesn't trigger DOM mutation and therefore we
2717
+ // need to override the insertRule API and listen for changes manually.
2718
+ if (insertRule === null) {
2719
+ insertRule = CSSStyleSheet.prototype.insertRule;
2720
+ CSSStyleSheet.prototype.insertRule = function () {
2721
+ if (active()) {
2722
+ schedule(this.ownerNode);
2723
+ }
2724
+ return insertRule.apply(this, arguments);
2725
+ };
2740
2726
  }
2741
- return metadata.privacy;
2742
- }
2743
- function diff(a, b, field) {
2744
- if (typeof a[field] === "object" && typeof b[field] === "object") {
2745
- for (var key in a[field]) {
2746
- if (a[field][key] !== b[field][key]) {
2747
- return true;
2727
+ if (deleteRule === null) {
2728
+ deleteRule = CSSStyleSheet.prototype.deleteRule;
2729
+ CSSStyleSheet.prototype.deleteRule = function () {
2730
+ if (active()) {
2731
+ schedule(this.ownerNode);
2748
2732
  }
2733
+ return deleteRule.apply(this, arguments);
2734
+ };
2735
+ }
2736
+ // Add a hook to attachShadow API calls
2737
+ // In case we are unable to add a hook and browser throws an exception,
2738
+ // reset attachShadow variable and resume processing like before
2739
+ if (attachShadow === null) {
2740
+ attachShadow = Element.prototype.attachShadow;
2741
+ try {
2742
+ Element.prototype.attachShadow = function () {
2743
+ if (active()) {
2744
+ return schedule(attachShadow.apply(this, arguments));
2745
+ }
2746
+ else {
2747
+ return attachShadow.apply(this, arguments);
2748
+ }
2749
+ };
2749
2750
  }
2750
- for (var key in b[field]) {
2751
- if (b[field][key] !== a[field][key]) {
2752
- return true;
2753
- }
2751
+ catch (_a) {
2752
+ attachShadow = null;
2754
2753
  }
2755
- return false;
2756
2754
  }
2757
- return a[field] !== b[field];
2758
2755
  }
2759
- function position(parent, child) {
2760
- child.metadata.position = 1;
2761
- var idx = parent ? parent.children.indexOf(child.id) : -1;
2762
- while (idx-- > 0) {
2763
- var sibling = values[parent.children[idx]];
2764
- if (child.data.tag === sibling.data.tag) {
2765
- child.metadata.position = sibling.metadata.position + 1;
2766
- break;
2756
+ function observe$1(node) {
2757
+ // Create a new observer for every time a new DOM tree (e.g. root document or shadowdom root) is discovered on the page
2758
+ // In the case of shadow dom, any mutations that happen within the shadow dom are not bubbled up to the host document
2759
+ // For this reason, we need to wire up mutations every time we see a new shadow dom.
2760
+ // Also, wrap it inside a try / catch. In certain browsers (e.g. legacy Edge), observer on shadow dom can throw errors
2761
+ try {
2762
+ var m = api("MutationObserver" /* Constant.MutationObserver */);
2763
+ var observer = m in window ? new window[m](measure(handle$1)) : null;
2764
+ if (observer) {
2765
+ observer.observe(node, { attributes: true, childList: true, characterData: true, subtree: true });
2766
+ observers.push(observer);
2767
2767
  }
2768
2768
  }
2769
- return child.metadata.position;
2770
- }
2771
- function updateSelector(value) {
2772
- var parent = value.parent && value.parent in values ? values[value.parent] : null;
2773
- var prefix = parent ? parent.selector : null;
2774
- var d = value.data;
2775
- var p = position(parent, value);
2776
- var s = { id: value.id, tag: d.tag, prefix: prefix, position: p, attributes: d.attributes };
2777
- value.selector = [get$1(s, 0 /* Selector.Alpha */), get$1(s, 1 /* Selector.Beta */)];
2778
- value.hash = value.selector.map(function (x) { return x ? hash(x) : null; });
2779
- value.hash.forEach(function (h) { return hashMap[h] = value.id; });
2780
- // Match fragment configuration against both alpha and beta hash
2781
- if (value.hash.some(function (h) { return fragments.indexOf(h) !== -1; })) {
2782
- value.fragment = value.id;
2783
- }
2784
- }
2785
- function hashText(hash) {
2786
- var id = lookup(hash);
2787
- var node = getNode(id);
2788
- return node !== null && node.textContent !== null ? node.textContent.substr(0, 25 /* Setting.ClickText */) : '';
2789
- }
2790
- function getNode(id) {
2791
- if (id in nodes) {
2792
- return nodes[id];
2769
+ catch (e) {
2770
+ log$1(2 /* Code.MutationObserver */, 0 /* Severity.Info */, e ? e.name : null);
2793
2771
  }
2794
- return null;
2795
2772
  }
2796
- function getValue(id) {
2797
- if (id in values) {
2798
- return values[id];
2773
+ function monitor(frame) {
2774
+ // Bind to iframe's onload event so we get notified anytime there's an update to iframe content.
2775
+ // This includes cases where iframe location is updated without explicitly updating src attribute
2776
+ // E.g. iframe.contentWindow.location.href = "new-location";
2777
+ if (has(frame) === false) {
2778
+ bind(frame, "load" /* Constant.LoadEvent */, generate.bind(this, frame, "childList" /* Constant.ChildList */), true);
2799
2779
  }
2800
- return null;
2801
2780
  }
2802
- function get(node) {
2803
- var id = getId(node);
2804
- return id in values ? values[id] : null;
2805
- }
2806
- function lookup(hash) {
2807
- return hash in hashMap ? hashMap[hash] : null;
2808
- }
2809
- function has(node) {
2810
- return getId(node) in nodes;
2811
- }
2812
- function updates$2() {
2813
- var output = [];
2814
- for (var _i = 0, updateMap_1 = updateMap; _i < updateMap_1.length; _i++) {
2815
- var id = updateMap_1[_i];
2816
- if (id in values) {
2817
- output.push(values[id]);
2781
+ function stop$f() {
2782
+ for (var _i = 0, observers_1 = observers; _i < observers_1.length; _i++) {
2783
+ var observer = observers_1[_i];
2784
+ if (observer) {
2785
+ observer.disconnect();
2818
2786
  }
2819
2787
  }
2820
- updateMap = [];
2821
- for (var id in updatedFragments) {
2822
- update(updatedFragments[id], id, true);
2823
- }
2824
- updatedFragments = {};
2825
- return output;
2826
- }
2827
- function remove(id, source) {
2828
- if (id in values) {
2829
- var value = values[id];
2830
- value.metadata.active = false;
2831
- value.parent = null;
2832
- track$4(id, source);
2833
- }
2834
- }
2835
- function size(value) {
2836
- // If this element is a image node, and is masked, then track box model for the current element
2837
- if (value.data.tag === "IMG" /* Constant.ImageTag */ && value.metadata.privacy === 3 /* Privacy.TextImage */) {
2838
- value.metadata.size = [];
2839
- }
2788
+ observers = [];
2789
+ history$4 = {};
2790
+ mutations = [];
2791
+ queue$1 = [];
2792
+ activePeriod = 0;
2793
+ timeout$1 = null;
2840
2794
  }
2841
- function getPreviousId(node) {
2842
- var id = null;
2843
- // Some nodes may not have an ID by design since Clarity skips over tags like SCRIPT, NOSCRIPT, META, COMMENTS, etc..
2844
- // In that case, we keep going back and check for their sibling until we find a sibling with ID or no more sibling nodes are left.
2845
- while (id === null && node.previousSibling) {
2846
- id = getId(node.previousSibling);
2847
- node = node.previousSibling;
2848
- }
2849
- return id;
2795
+ function active$2() {
2796
+ activePeriod = time() + 3000 /* Setting.MutationActivePeriod */;
2850
2797
  }
2851
- function track$4(id, source, fragment, changed, parentChanged) {
2852
- if (fragment === void 0) { fragment = null; }
2853
- if (changed === void 0) { changed = true; }
2854
- if (parentChanged === void 0) { parentChanged = false; }
2855
- // if updated node is a part of fragment and the fragment is not being tracked currently, schedule a mutation on the fragment node
2856
- if (fragment && !updatedFragments[fragment]) {
2857
- var node = getNode(fragment);
2858
- var value = getValue(fragment);
2859
- if (node && value) {
2860
- schedule(node, true);
2861
- value.hash.forEach(function (h) {
2862
- if (fragments.indexOf(h) !== -1) {
2863
- updatedFragments[fragment] = h;
2864
- }
2865
- });
2866
- }
2867
- }
2868
- // Keep track of the order in which mutations happened, they may not be sequential
2869
- // Edge case: If an element is added later on, and pre-discovered element is moved as a child.
2870
- // In that case, we need to reorder the pre-discovered element in the update list to keep visualization consistent.
2871
- var uIndex = updateMap.indexOf(id);
2872
- if (uIndex >= 0 && source === 1 /* Source.ChildListAdd */ && parentChanged) {
2873
- updateMap.splice(uIndex, 1);
2874
- updateMap.push(id);
2875
- }
2876
- else if (uIndex === -1 && changed) {
2877
- updateMap.push(id);
2878
- }
2879
- }
2880
-
2881
- var state$1 = [];
2882
- var regionMap = null; // Maps region nodes => region name
2883
- var regions = {};
2884
- var queue$1 = [];
2885
- var watch = false;
2886
- var observer$1 = null;
2887
- function start$h() {
2888
- reset$6();
2889
- observer$1 = null;
2890
- regionMap = new WeakMap();
2891
- regions = {};
2892
- queue$1 = [];
2893
- watch = window["IntersectionObserver"] ? true : false;
2798
+ function handle$1(m) {
2799
+ // Queue up mutation records for asynchronous processing
2800
+ var now = time();
2801
+ track$6(6 /* Event.Mutation */, now);
2802
+ mutations.push({ time: now, mutations: m });
2803
+ schedule$1(process$1, 1 /* Priority.High */).then(function () {
2804
+ setTimeout(compute$7);
2805
+ measure(compute$6)();
2806
+ });
2894
2807
  }
2895
- function observe$1(node, name) {
2896
- if (regionMap.has(node) === false) {
2897
- regionMap.set(node, name);
2898
- observer$1 = observer$1 === null && watch ? new IntersectionObserver(handler$1, {
2899
- // Get notified as intersection continues to change
2900
- // This allows us to process regions that get partially hidden during the lifetime of the page
2901
- // See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
2902
- // By default, intersection observers only fire an event when even a single pixel is visible and not thereafter.
2903
- threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
2904
- }) : observer$1;
2905
- if (observer$1 && node && node.nodeType === Node.ELEMENT_NODE) {
2906
- observer$1.observe(node);
2808
+ function process$1() {
2809
+ return __awaiter(this, void 0, void 0, function () {
2810
+ var timer, record, instance, _i, _a, mutation, state, target, type, value;
2811
+ return __generator(this, function (_b) {
2812
+ switch (_b.label) {
2813
+ case 0:
2814
+ timer = { id: id(), cost: 3 /* Metric.LayoutCost */ };
2815
+ start$w(timer);
2816
+ _b.label = 1;
2817
+ case 1:
2818
+ if (!(mutations.length > 0)) return [3 /*break*/, 8];
2819
+ record = mutations.shift();
2820
+ instance = time();
2821
+ _i = 0, _a = record.mutations;
2822
+ _b.label = 2;
2823
+ case 2:
2824
+ if (!(_i < _a.length)) return [3 /*break*/, 6];
2825
+ mutation = _a[_i];
2826
+ state = state$9(timer);
2827
+ if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 4];
2828
+ return [4 /*yield*/, suspend$1(timer)];
2829
+ case 3:
2830
+ state = _b.sent();
2831
+ _b.label = 4;
2832
+ case 4:
2833
+ if (state === 2 /* Task.Stop */) {
2834
+ return [3 /*break*/, 6];
2835
+ }
2836
+ target = mutation.target;
2837
+ type = track$3(mutation, timer, instance);
2838
+ if (type && target && target.ownerDocument) {
2839
+ parse$1(target.ownerDocument);
2840
+ }
2841
+ if (type && target && target.nodeType == Node.DOCUMENT_FRAGMENT_NODE && target.host) {
2842
+ parse$1(target);
2843
+ }
2844
+ switch (type) {
2845
+ case "attributes" /* Constant.Attributes */:
2846
+ processNode(target, 3 /* Source.Attributes */);
2847
+ break;
2848
+ case "characterData" /* Constant.CharacterData */:
2849
+ processNode(target, 4 /* Source.CharacterData */);
2850
+ break;
2851
+ case "childList" /* Constant.ChildList */:
2852
+ processNodeList(mutation.addedNodes, 1 /* Source.ChildListAdd */, timer);
2853
+ processNodeList(mutation.removedNodes, 2 /* Source.ChildListRemove */, timer);
2854
+ break;
2855
+ case "suspend" /* Constant.Suspend */:
2856
+ value = get(target);
2857
+ if (value) {
2858
+ value.metadata.suspend = true;
2859
+ }
2860
+ break;
2861
+ }
2862
+ _b.label = 5;
2863
+ case 5:
2864
+ _i++;
2865
+ return [3 /*break*/, 2];
2866
+ case 6: return [4 /*yield*/, encode$4(6 /* Event.Mutation */, timer, record.time)];
2867
+ case 7:
2868
+ _b.sent();
2869
+ return [3 /*break*/, 1];
2870
+ case 8:
2871
+ stop$t(timer);
2872
+ return [2 /*return*/];
2873
+ }
2874
+ });
2875
+ });
2876
+ }
2877
+ function track$3(m, timer, instance) {
2878
+ var value = m.target ? get(m.target.parentNode) : null;
2879
+ // Check if the parent is already discovered and that the parent is not the document root
2880
+ if (value && value.data.tag !== "HTML" /* Constant.HTML */) {
2881
+ var inactive = time() > activePeriod;
2882
+ var target = get(m.target);
2883
+ var element = target && target.selector ? target.selector.join() : m.target.nodeName;
2884
+ var parent_1 = value.selector ? value.selector.join() : "" /* Constant.Empty */;
2885
+ // We use selector, instead of id, to determine the key (signature for the mutation) because in some cases
2886
+ // repeated mutations can cause elements to be destroyed and then recreated as new DOM nodes
2887
+ // In those cases, IDs will change however the selector (which is relative to DOM xPath) remains the same
2888
+ var key = [parent_1, element, m.attributeName, names(m.addedNodes), names(m.removedNodes)].join();
2889
+ // Initialize an entry if it doesn't already exist
2890
+ history$4[key] = key in history$4 ? history$4[key] : [0, instance];
2891
+ var h = history$4[key];
2892
+ // Lookup any pending nodes queued up for removal, and process them now if we suspended a mutation before
2893
+ if (inactive === false && h[0] >= 10 /* Setting.MutationSuspendThreshold */) {
2894
+ processNodeList(h[2], 2 /* Source.ChildListRemove */, timer);
2895
+ }
2896
+ // Update the counter
2897
+ h[0] = inactive ? (h[1] === instance ? h[0] : h[0] + 1) : 1;
2898
+ h[1] = instance;
2899
+ // Return updated mutation type based on if we have already hit the threshold or not
2900
+ if (h[0] === 10 /* Setting.MutationSuspendThreshold */) {
2901
+ // Store a reference to removedNodes so we can process them later
2902
+ // when we resume mutations again on user interactions
2903
+ h[2] = m.removedNodes;
2904
+ return "suspend" /* Constant.Suspend */;
2905
+ }
2906
+ else if (h[0] > 10 /* Setting.MutationSuspendThreshold */) {
2907
+ return "" /* Constant.Empty */;
2907
2908
  }
2908
2909
  }
2910
+ return m.type;
2909
2911
  }
2910
- function exists(node) {
2911
- // Check if regionMap is not null before looking up a node
2912
- // Since, dom module stops after region module, it's possible that we may set regionMap to be null
2913
- // and still attempt to call exists on a late coming DOM mutation (or addition), effectively causing a script error
2914
- return regionMap && regionMap.has(node);
2915
- }
2916
- function track$3(id, event) {
2917
- var node = getNode(id);
2918
- var data = id in regions ? regions[id] : { id: id, visibility: 0 /* RegionVisibility.Rendered */, interaction: 16 /* InteractionState.None */, name: regionMap.get(node) };
2919
- // Determine the interaction state based on incoming event
2920
- var interaction = 16 /* InteractionState.None */;
2921
- switch (event) {
2922
- case 9 /* Event.Click */:
2923
- interaction = 20 /* InteractionState.Clicked */;
2924
- break;
2925
- case 27 /* Event.Input */:
2926
- interaction = 30 /* InteractionState.Input */;
2927
- break;
2912
+ function names(nodes) {
2913
+ var output = [];
2914
+ for (var i = 0; nodes && i < nodes.length; i++) {
2915
+ output.push(nodes[i].nodeName);
2928
2916
  }
2929
- // Process updates to this region, if applicable
2930
- process$1(node, data, interaction, data.visibility);
2917
+ return output.join();
2931
2918
  }
2932
- function compute$6() {
2933
- // Process any regions where we couldn't resolve an "id" for at the time of last intersection observer event
2934
- // This could happen in cases where elements are not yet processed by Clarity's virtual DOM but browser reports a change, regardless.
2935
- // For those cases we add them to the queue and re-process them below
2936
- var q = [];
2937
- for (var _i = 0, queue_1 = queue$1; _i < queue_1.length; _i++) {
2938
- var r = queue_1[_i];
2939
- var id = getId(r.node);
2940
- if (!(id in regions)) {
2941
- if (id) {
2942
- r.data.id = id;
2943
- regions[id] = r.data;
2944
- state$1.push(clone$1(r.data));
2945
- }
2946
- else {
2947
- q.push(r);
2919
+ function processNodeList(list, source, timer) {
2920
+ return __awaiter(this, void 0, void 0, function () {
2921
+ var length, i, state;
2922
+ return __generator(this, function (_a) {
2923
+ switch (_a.label) {
2924
+ case 0:
2925
+ length = list ? list.length : 0;
2926
+ i = 0;
2927
+ _a.label = 1;
2928
+ case 1:
2929
+ if (!(i < length)) return [3 /*break*/, 6];
2930
+ if (!(source === 1 /* Source.ChildListAdd */)) return [3 /*break*/, 2];
2931
+ traverse(list[i], timer, source);
2932
+ return [3 /*break*/, 5];
2933
+ case 2:
2934
+ state = state$9(timer);
2935
+ if (!(state === 0 /* Task.Wait */)) return [3 /*break*/, 4];
2936
+ return [4 /*yield*/, suspend$1(timer)];
2937
+ case 3:
2938
+ state = _a.sent();
2939
+ _a.label = 4;
2940
+ case 4:
2941
+ if (state === 2 /* Task.Stop */) {
2942
+ return [3 /*break*/, 6];
2943
+ }
2944
+ processNode(list[i], source);
2945
+ _a.label = 5;
2946
+ case 5:
2947
+ i++;
2948
+ return [3 /*break*/, 1];
2949
+ case 6: return [2 /*return*/];
2948
2950
  }
2949
- }
2950
- }
2951
- queue$1 = q;
2952
- // Schedule encode only when we have at least one valid data entry
2953
- if (state$1.length > 0) {
2954
- encode$4(7 /* Event.Region */);
2955
- }
2951
+ });
2952
+ });
2956
2953
  }
2957
- function handler$1(entries) {
2958
- for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
2959
- var entry = entries_1[_i];
2960
- var target = entry.target;
2961
- var rect = entry.boundingClientRect;
2962
- var overlap = entry.intersectionRect;
2963
- var viewport = entry.rootBounds;
2964
- // Only capture regions that have non-zero width or height to avoid tracking and sending regions
2965
- // that cannot ever be seen by the user. In some cases, websites will have a multiple copy of the same region
2966
- // like search box - one for desktop, and another for mobile. In those cases, CSS media queries determine which one should be visible.
2967
- // Also, if these regions ever become non-zero width or height (through AJAX, user action or orientation change) - we will automatically start monitoring them from that point onwards
2968
- if (regionMap.has(target) && rect.width + rect.height > 0 && viewport.width > 0 && viewport.height > 0) {
2969
- var id = target ? getId(target) : null;
2970
- var data = id in regions ? regions[id] : { id: id, name: regionMap.get(target), interaction: 16 /* InteractionState.None */, visibility: 0 /* RegionVisibility.Rendered */ };
2971
- // For regions that have relatively smaller area, we look at intersection ratio and see the overlap relative to element's area
2972
- // However, for larger regions, area of regions could be bigger than viewport and therefore comparison is relative to visible area
2973
- var viewportRatio = overlap ? (overlap.width * overlap.height * 1.0) / (viewport.width * viewport.height) : 0;
2974
- var visible = viewportRatio > 0.05 /* Setting.ViewportIntersectionRatio */ || entry.intersectionRatio > 0.8 /* Setting.IntersectionRatio */;
2975
- // If an element is either visible or was visible and has been scrolled to the end
2976
- // i.e. Scrolled to end is determined by if the starting position of the element + the window height is more than the total element height.
2977
- // starting position is relative to the viewport - so Intersection observer returns a negative value for rect.top to indicate that the element top is above the viewport
2978
- var scrolledToEnd = (visible || data.visibility == 10 /* RegionVisibility.Visible */) && Math.abs(rect.top) + viewport.height > rect.height;
2979
- // Process updates to this region, if applicable
2980
- process$1(target, data, data.interaction, (scrolledToEnd ?
2981
- 13 /* RegionVisibility.ScrolledToEnd */ :
2982
- (visible ? 10 /* RegionVisibility.Visible */ : 0 /* RegionVisibility.Rendered */)));
2983
- // Stop observing this element now that we have already received scrolled signal
2984
- if (data.visibility >= 13 /* RegionVisibility.ScrolledToEnd */ && observer$1) {
2985
- observer$1.unobserve(target);
2986
- }
2987
- }
2954
+ function schedule(node) {
2955
+ // Only schedule manual trigger for this node if it's not already in the queue
2956
+ if (queue$1.indexOf(node) < 0) {
2957
+ queue$1.push(node);
2988
2958
  }
2989
- if (state$1.length > 0) {
2990
- encode$4(7 /* Event.Region */);
2959
+ // Cancel any previous trigger before scheduling a new one.
2960
+ // It's common for a webpage to call multiple synchronous "insertRule" / "deleteRule" calls.
2961
+ // And in those cases we do not wish to monitor changes multiple times for the same node.
2962
+ if (timeout$1) {
2963
+ clearTimeout(timeout$1);
2991
2964
  }
2965
+ timeout$1 = setTimeout(function () { trigger$2(); }, 33 /* Setting.LookAhead */);
2966
+ return node;
2992
2967
  }
2993
- function process$1(n, d, s, v) {
2994
- // Check if received a state that supersedes existing state
2995
- var updated = s > d.interaction || v > d.visibility;
2996
- d.interaction = s > d.interaction ? s : d.interaction;
2997
- d.visibility = v > d.visibility ? v : d.visibility;
2998
- // If the corresponding node is already discovered, update the internal state
2999
- // Otherwise, track it in a queue to reprocess later.
3000
- if (d.id) {
3001
- if ((d.id in regions && updated) || !(d.id in regions)) {
3002
- regions[d.id] = d;
3003
- state$1.push(clone$1(d));
2968
+ function trigger$2() {
2969
+ for (var _i = 0, queue_1 = queue$1; _i < queue_1.length; _i++) {
2970
+ var node = queue_1[_i];
2971
+ // Generate a mutation for this node only if it still exists
2972
+ if (node) {
2973
+ var shadowRoot = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
2974
+ // Skip re-processing shadowRoot if it was already discovered
2975
+ if (shadowRoot && has(node)) {
2976
+ continue;
2977
+ }
2978
+ generate(node, shadowRoot ? "childList" /* Constant.ChildList */ : "characterData" /* Constant.CharacterData */);
3004
2979
  }
3005
2980
  }
3006
- else {
3007
- queue$1.push({ node: n, data: d });
3008
- }
3009
- }
3010
- function clone$1(r) {
3011
- return { time: time(), data: { id: r.id, interaction: r.interaction, visibility: r.visibility, name: r.name } };
3012
- }
3013
- function reset$6() {
3014
- state$1 = [];
3015
- }
3016
- function stop$f() {
3017
- reset$6();
3018
- regionMap = null;
3019
- regions = {};
3020
2981
  queue$1 = [];
3021
- if (observer$1) {
3022
- observer$1.disconnect();
3023
- observer$1 = null;
3024
- }
3025
- watch = false;
2982
+ }
2983
+ function generate(target, type) {
2984
+ measure(handle$1)([{
2985
+ addedNodes: [target],
2986
+ attributeName: null,
2987
+ attributeNamespace: null,
2988
+ nextSibling: null,
2989
+ oldValue: null,
2990
+ previousSibling: null,
2991
+ removedNodes: [],
2992
+ target: target,
2993
+ type: type
2994
+ }]);
3026
2995
  }
3027
2996
 
3028
2997
  function target(evt) {
@@ -3055,7 +3024,7 @@ function metadata$2(node, event, text) {
3055
3024
  output.hash = value.hash;
3056
3025
  output.privacy = metadata_1.privacy;
3057
3026
  if (value.region) {
3058
- track$3(value.region, event);
3027
+ track$4(value.region, event);
3059
3028
  }
3060
3029
  if (metadata_1.fraud) {
3061
3030
  check$4(metadata_1.fraud, value.id, text || value.data.value);
@@ -3082,7 +3051,7 @@ function encode$3 (type, ts) {
3082
3051
  case 18 /* Event.TouchEnd */:
3083
3052
  case 19 /* Event.TouchMove */:
3084
3053
  case 20 /* Event.TouchCancel */:
3085
- for (_i = 0, _a = state$4; _i < _a.length; _i++) {
3054
+ for (_i = 0, _a = state$3; _i < _a.length; _i++) {
3086
3055
  entry = _a[_i];
3087
3056
  pTarget = metadata$2(entry.data.target, entry.event);
3088
3057
  if (pTarget.id > 0) {
@@ -3094,10 +3063,10 @@ function encode$3 (type, ts) {
3094
3063
  track$7(entry.event, entry.data.x, entry.data.y);
3095
3064
  }
3096
3065
  }
3097
- reset$e();
3066
+ reset$c();
3098
3067
  break;
3099
3068
  case 9 /* Event.Click */:
3100
- for (_b = 0, _c = state$7; _b < _c.length; _b++) {
3069
+ for (_b = 0, _c = state$6; _b < _c.length; _b++) {
3101
3070
  entry = _c[_b];
3102
3071
  cTarget = metadata$2(entry.data.target, entry.event, entry.data.text);
3103
3072
  tokens = [entry.time, entry.event];
@@ -3117,10 +3086,10 @@ function encode$3 (type, ts) {
3117
3086
  queue(tokens);
3118
3087
  track$2(entry.time, entry.event, cHash, entry.data.x, entry.data.y, entry.data.reaction, entry.data.context);
3119
3088
  }
3120
- reset$h();
3089
+ reset$f();
3121
3090
  break;
3122
3091
  case 38 /* Event.Clipboard */:
3123
- for (_d = 0, _e = state$6; _d < _e.length; _d++) {
3092
+ for (_d = 0, _e = state$5; _d < _e.length; _d++) {
3124
3093
  entry = _e[_d];
3125
3094
  tokens = [entry.time, entry.event];
3126
3095
  target = metadata$2(entry.data.target, entry.event);
@@ -3130,24 +3099,24 @@ function encode$3 (type, ts) {
3130
3099
  queue(tokens);
3131
3100
  }
3132
3101
  }
3133
- reset$g();
3102
+ reset$e();
3134
3103
  break;
3135
3104
  case 11 /* Event.Resize */:
3136
3105
  r = data$b;
3137
3106
  tokens.push(r.width);
3138
3107
  tokens.push(r.height);
3139
3108
  track$7(type, r.width, r.height);
3140
- reset$d();
3109
+ reset$b();
3141
3110
  queue(tokens);
3142
3111
  break;
3143
3112
  case 26 /* Event.Unload */:
3144
3113
  u = data$9;
3145
3114
  tokens.push(u.name);
3146
- reset$9();
3115
+ reset$7();
3147
3116
  queue(tokens);
3148
3117
  break;
3149
3118
  case 27 /* Event.Input */:
3150
- for (_f = 0, _g = state$5; _f < _g.length; _f++) {
3119
+ for (_f = 0, _g = state$4; _f < _g.length; _f++) {
3151
3120
  entry = _g[_f];
3152
3121
  iTarget = metadata$2(entry.data.target, entry.event, entry.data.value);
3153
3122
  tokens = [entry.time, entry.event];
@@ -3155,7 +3124,7 @@ function encode$3 (type, ts) {
3155
3124
  tokens.push(text$1(entry.data.value, "input", iTarget.privacy));
3156
3125
  queue(tokens);
3157
3126
  }
3158
- reset$f();
3127
+ reset$d();
3159
3128
  break;
3160
3129
  case 21 /* Event.Selection */:
3161
3130
  s = data$a;
@@ -3166,12 +3135,12 @@ function encode$3 (type, ts) {
3166
3135
  tokens.push(s.startOffset);
3167
3136
  tokens.push(endTarget.id);
3168
3137
  tokens.push(s.endOffset);
3169
- reset$b();
3138
+ reset$9();
3170
3139
  queue(tokens);
3171
3140
  }
3172
3141
  break;
3173
3142
  case 10 /* Event.Scroll */:
3174
- for (_h = 0, _j = state$3; _h < _j.length; _h++) {
3143
+ for (_h = 0, _j = state$2; _h < _j.length; _h++) {
3175
3144
  entry = _j[_h];
3176
3145
  sTarget = metadata$2(entry.data.target, entry.event);
3177
3146
  if (sTarget.id > 0) {
@@ -3183,10 +3152,10 @@ function encode$3 (type, ts) {
3183
3152
  track$7(entry.event, entry.data.x, entry.data.y);
3184
3153
  }
3185
3154
  }
3186
- reset$c();
3155
+ reset$a();
3187
3156
  break;
3188
3157
  case 42 /* Event.Change */:
3189
- for (_k = 0, _l = state$8; _k < _l.length; _k++) {
3158
+ for (_k = 0, _l = state$7; _k < _l.length; _k++) {
3190
3159
  entry = _l[_k];
3191
3160
  tokens = [entry.time, entry.event];
3192
3161
  target = metadata$2(entry.data.target, entry.event);
@@ -3199,10 +3168,10 @@ function encode$3 (type, ts) {
3199
3168
  queue(tokens);
3200
3169
  }
3201
3170
  }
3202
- reset$i();
3171
+ reset$g();
3203
3172
  break;
3204
3173
  case 39 /* Event.Submit */:
3205
- for (_m = 0, _o = state$2; _m < _o.length; _m++) {
3174
+ for (_m = 0, _o = state$1; _m < _o.length; _m++) {
3206
3175
  entry = _o[_m];
3207
3176
  tokens = [entry.time, entry.event];
3208
3177
  target = metadata$2(entry.data.target, entry.event);
@@ -3211,7 +3180,7 @@ function encode$3 (type, ts) {
3211
3180
  queue(tokens);
3212
3181
  }
3213
3182
  }
3214
- reset$a();
3183
+ reset$8();
3215
3184
  break;
3216
3185
  case 22 /* Event.Timeline */:
3217
3186
  for (_p = 0, _q = updates$1; _p < _q.length; _p++) {
@@ -3232,7 +3201,7 @@ function encode$3 (type, ts) {
3232
3201
  tokens.push(v.visible);
3233
3202
  queue(tokens);
3234
3203
  visibility(t, v.visible);
3235
- reset$8();
3204
+ reset$6();
3236
3205
  break;
3237
3206
  }
3238
3207
  return [2 /*return*/];
@@ -3416,7 +3385,7 @@ function send(payload, zipped, sequence, beacon) {
3416
3385
  if (beacon === void 0) { beacon = false; }
3417
3386
  // Upload data if a valid URL is defined in the config
3418
3387
  if (typeof config$1.upload === "string" /* Constant.String */) {
3419
- var url = config$1.upload;
3388
+ var url_1 = config$1.upload;
3420
3389
  var dispatched = false;
3421
3390
  // If it's the last payload, attempt to upload using sendBeacon first.
3422
3391
  // The advantage to using sendBeacon is that browser can decide to upload asynchronously, improving chances of success
@@ -3425,7 +3394,7 @@ function send(payload, zipped, sequence, beacon) {
3425
3394
  if (beacon && "sendBeacon" in navigator) {
3426
3395
  try {
3427
3396
  // Navigator needs to be bound to sendBeacon before it is used to avoid errors in some browsers
3428
- dispatched = navigator.sendBeacon.bind(navigator)(url, payload);
3397
+ dispatched = navigator.sendBeacon.bind(navigator)(url_1, payload);
3429
3398
  if (dispatched) {
3430
3399
  done(sequence);
3431
3400
  }
@@ -3447,7 +3416,9 @@ function send(payload, zipped, sequence, beacon) {
3447
3416
  transit[sequence] = { data: payload, attempts: 1 };
3448
3417
  }
3449
3418
  var xhr_1 = new XMLHttpRequest();
3450
- xhr_1.open("POST", url);
3419
+ xhr_1.open("POST", url_1, true);
3420
+ xhr_1.timeout = 15000 /* Setting.UploadTimeout */;
3421
+ xhr_1.ontimeout = function () { report(new Error("".concat("Timeout" /* Constant.Timeout */, " : ").concat(url_1))); };
3451
3422
  if (sequence !== null) {
3452
3423
  xhr_1.onreadystatechange = function () { measure(check$3)(xhr_1, sequence); };
3453
3424
  }
@@ -3533,22 +3504,31 @@ function delay() {
3533
3504
  return typeof config$1.upload === "string" /* Constant.String */ ? Math.max(Math.min(gap, 30000 /* Setting.MaxUploadDelay */), 100 /* Setting.MinUploadDelay */) : config$1.delay;
3534
3505
  }
3535
3506
  function response(payload) {
3536
- var parts = payload && payload.length > 0 ? payload.split(" ") : ["" /* Constant.Empty */];
3537
- switch (parts[0]) {
3538
- case "END" /* Constant.End */:
3539
- // Clear out session storage and end the session so we can start fresh the next time
3540
- trigger(6 /* Check.Server */);
3541
- break;
3542
- case "UPGRADE" /* Constant.Upgrade */:
3543
- // Upgrade current session to send back playback information
3544
- upgrade("Auto" /* Constant.Auto */);
3545
- break;
3546
- case "ACTION" /* Constant.Action */:
3547
- // Invoke action callback, if configured and has a valid value
3548
- if (config$1.action && parts.length > 1) {
3549
- config$1.action(parts[1]);
3550
- }
3551
- break;
3507
+ var lines = payload && payload.length > 0 ? payload.split("\n") : [];
3508
+ for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
3509
+ var line = lines_1[_i];
3510
+ var parts = line && line.length > 0 ? line.split(/ (.*)/) : ["" /* Constant.Empty */];
3511
+ switch (parts[0]) {
3512
+ case "END" /* Constant.End */:
3513
+ // Clear out session storage and end the session so we can start fresh the next time
3514
+ trigger(6 /* Check.Server */);
3515
+ break;
3516
+ case "UPGRADE" /* Constant.Upgrade */:
3517
+ // Upgrade current session to send back playback information
3518
+ upgrade("Auto" /* Constant.Auto */);
3519
+ break;
3520
+ case "ACTION" /* Constant.Action */:
3521
+ // Invoke action callback, if configured and has a valid value
3522
+ if (config$1.action && parts.length > 1) {
3523
+ config$1.action(parts[1]);
3524
+ }
3525
+ break;
3526
+ case "EXTRACT" /* Constant.Extract */:
3527
+ if (parts.length > 1) {
3528
+ trigger$1(parts[1]);
3529
+ }
3530
+ break;
3531
+ }
3552
3532
  }
3553
3533
  }
3554
3534
 
@@ -3653,30 +3633,27 @@ var data$5 = {};
3653
3633
  var keys = [];
3654
3634
  var variables = {};
3655
3635
  var selectors = {};
3656
- var fragments = [];
3657
3636
  function start$c() {
3637
+ reset$4();
3638
+ }
3639
+ function trigger$1(input) {
3658
3640
  try {
3659
- var e = config$1.extract;
3660
- if (!e) {
3661
- return;
3662
- }
3663
- for (var i = 0; i < e.length; i += 3) {
3664
- var source = e[i];
3665
- var key = e[i + 1];
3641
+ var parts = input && input.length > 0 ? input.split(/ (.*)/) : ["" /* Constant.Empty */];
3642
+ var key = parseInt(parts[0]);
3643
+ var values = parts.length > 1 ? JSON.parse(parts[1]) : {};
3644
+ variables[key] = {};
3645
+ selectors[key] = {};
3646
+ for (var v in values) {
3647
+ var id = parseInt(v);
3648
+ var value = values[v];
3649
+ var source = value.startsWith("~" /* Constant.Tilde */) ? 0 /* ExtractSource.Javascript */ : 2 /* ExtractSource.Text */;
3666
3650
  switch (source) {
3667
3651
  case 0 /* ExtractSource.Javascript */:
3668
- var variable = e[i + 2];
3669
- variables[key] = parse(variable);
3670
- break;
3671
- case 1 /* ExtractSource.Cookie */:
3672
- /*Todo: Add cookie extract logic*/
3652
+ var variable = value.substring(1, value.length);
3653
+ variables[key][id] = parse(variable);
3673
3654
  break;
3674
3655
  case 2 /* ExtractSource.Text */:
3675
- var match_1 = e[i + 2];
3676
- selectors[key] = match_1;
3677
- break;
3678
- case 3 /* ExtractSource.Fragment */:
3679
- fragments = e[i + 2];
3656
+ selectors[key][id] = value;
3680
3657
  break;
3681
3658
  }
3682
3659
  }
@@ -3691,15 +3668,25 @@ function clone(v) {
3691
3668
  function compute$4() {
3692
3669
  try {
3693
3670
  for (var v in variables) {
3694
- var value = str(evaluate(clone(variables[v])));
3695
- if (value) {
3696
- update(v, value);
3697
- }
3698
- }
3699
- for (var s in selectors) {
3700
- var node = document.querySelector(selectors[s]);
3701
- if (node) {
3702
- update(s, node.innerText);
3671
+ var key = parseInt(v);
3672
+ if (!(key in keys)) {
3673
+ var variableData = variables[key];
3674
+ for (var v_1 in variableData) {
3675
+ var variableKey = parseInt(v_1);
3676
+ var value = str(evaluate(clone(variableData[variableKey])));
3677
+ if (value) {
3678
+ update(key, variableKey, value);
3679
+ }
3680
+ }
3681
+ var selectorData = selectors[key];
3682
+ for (var s in selectorData) {
3683
+ var selectorKey = parseInt(s);
3684
+ var nodes = document.querySelectorAll(selectorData[selectorKey]);
3685
+ if (nodes) {
3686
+ var text = Array.from(nodes).map(function (e) { return e.innerText; });
3687
+ update(key, selectorKey, text.join("<SEP>" /* Constant.Seperator */).substring(0, 10000 /* Setting.ExtractLimit */));
3688
+ }
3689
+ }
3703
3690
  }
3704
3691
  }
3705
3692
  }
@@ -3709,20 +3696,20 @@ function compute$4() {
3709
3696
  encode$1(40 /* Event.Extract */);
3710
3697
  }
3711
3698
  function reset$4() {
3699
+ data$5 = {};
3712
3700
  keys = [];
3701
+ variables = {};
3702
+ selectors = {};
3713
3703
  }
3714
- function update(key, value, force) {
3715
- if (force === void 0) { force = false; }
3716
- if (!(key in data$5) || (key in data$5 && data$5[key] !== value) || force) {
3717
- data$5[key] = value;
3704
+ function update(key, subkey, value) {
3705
+ if (!(key in data$5)) {
3706
+ data$5[key] = [];
3718
3707
  keys.push(key);
3719
3708
  }
3709
+ data$5[key].push([subkey, value]);
3720
3710
  }
3721
3711
  function stop$b() {
3722
- data$5 = {};
3723
- keys = [];
3724
- variables = {};
3725
- selectors = {};
3712
+ reset$4();
3726
3713
  }
3727
3714
  function parse(variable) {
3728
3715
  var syntax = [];
@@ -3887,7 +3874,7 @@ function encode$1 (event) {
3887
3874
  for (var _d = 0, extractKeys_1 = extractKeys; _d < extractKeys_1.length; _d++) {
3888
3875
  var e = extractKeys_1[_d];
3889
3876
  tokens.push(e);
3890
- tokens.push(data$5[e]);
3877
+ tokens.push([].concat.apply([], data$5[e]));
3891
3878
  }
3892
3879
  reset$4();
3893
3880
  queue(tokens, false);
@@ -4276,7 +4263,7 @@ function report(e) {
4276
4263
  // Using POST request instead of a GET request (img-src) to not violate existing CSP rules
4277
4264
  // Since, Clarity already uses XHR to upload data, we stick with similar POST mechanism for reporting too
4278
4265
  var xhr = new XMLHttpRequest();
4279
- xhr.open("POST", url);
4266
+ xhr.open("POST", url, true);
4280
4267
  xhr.send(JSON.stringify(payload));
4281
4268
  history$1.push(e.message);
4282
4269
  }
@@ -4388,7 +4375,7 @@ var status = false;
4388
4375
  function start$6() {
4389
4376
  status = true;
4390
4377
  start$G();
4391
- reset$k();
4378
+ reset$j();
4392
4379
  reset$1();
4393
4380
  reset$2();
4394
4381
  start$7();
@@ -4397,7 +4384,7 @@ function stop$5() {
4397
4384
  stop$6();
4398
4385
  reset$2();
4399
4386
  reset$1();
4400
- reset$k();
4387
+ reset$j();
4401
4388
  stop$C();
4402
4389
  status = false;
4403
4390
  }
@@ -4480,14 +4467,14 @@ function discover() {
4480
4467
  case 0:
4481
4468
  ts = time();
4482
4469
  timer = { id: id(), cost: 3 /* Metric.LayoutCost */ };
4483
- start$x(timer);
4470
+ start$w(timer);
4484
4471
  return [4 /*yield*/, traverse(document, timer, 0 /* Source.Discover */)];
4485
4472
  case 1:
4486
4473
  _a.sent();
4487
4474
  return [4 /*yield*/, encode$4(5 /* Event.Discover */, timer, ts)];
4488
4475
  case 2:
4489
4476
  _a.sent();
4490
- stop$u(timer);
4477
+ stop$t(timer);
4491
4478
  return [2 /*return*/];
4492
4479
  }
4493
4480
  });
@@ -4497,16 +4484,16 @@ function discover() {
4497
4484
  function start$3() {
4498
4485
  // The order below is important
4499
4486
  // and is determined by interdependencies of modules
4500
- start$w();
4487
+ start$v();
4488
+ start$u();
4489
+ start$x();
4501
4490
  start$h();
4502
- start$i();
4503
- start$j();
4504
4491
  start$4();
4505
4492
  }
4506
4493
  function stop$3() {
4494
+ stop$s();
4495
+ stop$u();
4507
4496
  stop$f();
4508
- stop$g();
4509
- stop$h();
4510
4497
  end();
4511
4498
  }
4512
4499
 
@@ -4676,7 +4663,7 @@ function stop$2() {
4676
4663
  function host(url) {
4677
4664
  var a = document.createElement("a");
4678
4665
  a.href = url;
4679
- return a.hostname;
4666
+ return a.host;
4680
4667
  }
4681
4668
 
4682
4669
  function start$1() {