@atlaskit/react-ufo 4.11.1 → 4.11.3
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/CHANGELOG.md +14 -0
- package/dist/cjs/create-interaction-extra-metrics-payload/index.js +58 -11
- package/dist/cjs/create-payload/utils/get-vc-metrics.js +1 -0
- package/dist/cjs/interaction-metrics/index.js +7 -6
- package/dist/cjs/interaction-metrics/interaction-extra-metrics.js +17 -10
- package/dist/cjs/interaction-metrics-init/index.js +2 -2
- package/dist/cjs/segment/segment.js +3 -19
- package/dist/cjs/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +8 -18
- package/dist/es2019/create-interaction-extra-metrics-payload/index.js +40 -5
- package/dist/es2019/create-payload/utils/get-vc-metrics.js +2 -1
- package/dist/es2019/interaction-metrics/index.js +7 -5
- package/dist/es2019/interaction-metrics/interaction-extra-metrics.js +14 -9
- package/dist/es2019/interaction-metrics-init/index.js +2 -2
- package/dist/es2019/segment/segment.js +2 -12
- package/dist/es2019/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +8 -18
- package/dist/esm/create-interaction-extra-metrics-payload/index.js +58 -11
- package/dist/esm/create-payload/utils/get-vc-metrics.js +2 -1
- package/dist/esm/interaction-metrics/index.js +7 -6
- package/dist/esm/interaction-metrics/interaction-extra-metrics.js +17 -10
- package/dist/esm/interaction-metrics-init/index.js +2 -2
- package/dist/esm/segment/segment.js +2 -16
- package/dist/esm/vc/vc-observer-new/metric-calculator/abstract-base-vc-calculator.js +8 -18
- package/dist/types/config/index.d.ts +4 -0
- package/dist/types/create-interaction-extra-metrics-payload/index.d.ts +9 -1
- package/dist/types/create-post-interaction-log-payload/index.d.ts +1 -1
- package/dist/types/interaction-metrics/interaction-extra-metrics.d.ts +6 -3
- package/dist/types-ts4.5/config/index.d.ts +4 -0
- package/dist/types-ts4.5/create-interaction-extra-metrics-payload/index.d.ts +9 -1
- package/dist/types-ts4.5/create-post-interaction-log-payload/index.d.ts +1 -1
- package/dist/types-ts4.5/interaction-metrics/interaction-extra-metrics.d.ts +6 -3
- package/package.json +1 -4
- package/dist/cjs/segment/segment-highlight.js +0 -39
- package/dist/es2019/segment/segment-highlight.js +0 -27
- package/dist/esm/segment/segment-highlight.js +0 -30
- package/dist/types/segment/segment-highlight.d.ts +0 -6
- package/dist/types-ts4.5/segment/segment-highlight.d.ts +0 -6
|
@@ -208,24 +208,14 @@ export default class AbstractVCCalculatorBase {
|
|
|
208
208
|
// Only create debug details if callbacks exist
|
|
209
209
|
let v3RevisionDebugDetails = null;
|
|
210
210
|
if (shouldCalculateDebugDetails) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
};
|
|
220
|
-
} else {
|
|
221
|
-
v3RevisionDebugDetails = {
|
|
222
|
-
revision: this.revisionNo,
|
|
223
|
-
isClean: isVCClean,
|
|
224
|
-
abortReason: dirtyReason,
|
|
225
|
-
vcLogs: enhancedVcLogs,
|
|
226
|
-
interactionId
|
|
227
|
-
};
|
|
228
|
-
}
|
|
211
|
+
v3RevisionDebugDetails = {
|
|
212
|
+
revision: this.revisionNo,
|
|
213
|
+
isClean: isVCClean && !interactionAbortReason && isPageVisible,
|
|
214
|
+
abortReason: !isPageVisible ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : interactionAbortReason,
|
|
215
|
+
vcLogs: enhancedVcLogs,
|
|
216
|
+
interactionId,
|
|
217
|
+
interactionType
|
|
218
|
+
};
|
|
229
219
|
}
|
|
230
220
|
|
|
231
221
|
// Handle devtool callback
|
|
@@ -24,13 +24,13 @@ import { optimizeReactProfilerTimings } from '../create-payload/utils/optimize-r
|
|
|
24
24
|
import { optimizeRequestInfo } from '../create-payload/utils/optimize-request-info';
|
|
25
25
|
import { optimizeSpans } from '../create-payload/utils/optimize-spans';
|
|
26
26
|
import { interactionSpans as atlaskitInteractionSpans } from '../interaction-metrics';
|
|
27
|
-
function createInteractionExtraLogPayload(_x, _x2) {
|
|
27
|
+
function createInteractionExtraLogPayload(_x, _x2, _x3, _x4) {
|
|
28
28
|
return _createInteractionExtraLogPayload.apply(this, arguments);
|
|
29
29
|
}
|
|
30
30
|
function _createInteractionExtraLogPayload() {
|
|
31
|
-
_createInteractionExtraLogPayload = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(interactionId, interaction) {
|
|
32
|
-
var _getTTAI, _window$location;
|
|
33
|
-
var config, end, start, ufoName, rate, type, abortReason, routeName, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, knownSegments, sanitisedUfoName, configRate, pageVisibilityAtTTAI, isPageLoad, calculatePageVisibilityFromTheStartOfPageLoad, moreAccuratePageVisibilityAtTTAI, extraTTAI, newUFOName, finalVCMetrics, vcRevisionPayload, effectiveVCRevisionPayload, isThirdParty, filteredData, getDetailedInteractionMetrics, segments3p, segmentTree, payload;
|
|
31
|
+
_createInteractionExtraLogPayload = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(interactionId, interaction, lastInteractionFinish, lastInteractionFinishVCResult) {
|
|
32
|
+
var _getTTAI, _lastInteractionFinis, _getTTAI2, _window$location;
|
|
33
|
+
var config, end, start, ufoName, rate, type, abortReason, routeName, previousInteractionName, isPreviousInteractionAborted, abortedByInteractionName, knownSegments, minorInteractions, sanitisedUfoName, configRate, pageVisibilityAtTTAI, isPageLoad, calculatePageVisibilityFromTheStartOfPageLoad, moreAccuratePageVisibilityAtTTAI, extraTTAI, newUFOName, finalVCMetrics, vcRevisionPayload, effectiveVCRevisionPayload, normalTTAI, lastInteractionFinishStart, lastInteractionFinishEnd, lastInteractionFinishVC90, lastInteractionFinishVCClean, lastInteractionFinishVCRev, lastInteractionFinishRevision, isThirdParty, filteredData, getDetailedInteractionMetrics, segments3p, segmentTree, payload;
|
|
34
34
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
35
35
|
while (1) switch (_context.prev = _context.next) {
|
|
36
36
|
case 0:
|
|
@@ -41,7 +41,7 @@ function _createInteractionExtraLogPayload() {
|
|
|
41
41
|
}
|
|
42
42
|
throw Error('UFO Configuration not provided');
|
|
43
43
|
case 3:
|
|
44
|
-
end = interaction.end, start = interaction.start, ufoName = interaction.ufoName, rate = interaction.rate, type = interaction.type, abortReason = interaction.abortReason, routeName = interaction.routeName, previousInteractionName = interaction.previousInteractionName, isPreviousInteractionAborted = interaction.isPreviousInteractionAborted, abortedByInteractionName = interaction.abortedByInteractionName, knownSegments = interaction.knownSegments;
|
|
44
|
+
end = interaction.end, start = interaction.start, ufoName = interaction.ufoName, rate = interaction.rate, type = interaction.type, abortReason = interaction.abortReason, routeName = interaction.routeName, previousInteractionName = interaction.previousInteractionName, isPreviousInteractionAborted = interaction.isPreviousInteractionAborted, abortedByInteractionName = interaction.abortedByInteractionName, knownSegments = interaction.knownSegments, minorInteractions = interaction.minorInteractions;
|
|
45
45
|
sanitisedUfoName = sanitizeUfoName(ufoName);
|
|
46
46
|
configRate = getExtraInteractionRate(sanitisedUfoName, type);
|
|
47
47
|
if (coinflip(configRate)) {
|
|
@@ -52,7 +52,7 @@ function _createInteractionExtraLogPayload() {
|
|
|
52
52
|
case 8:
|
|
53
53
|
pageVisibilityAtTTAI = getPageVisibilityUpToTTAI(interaction);
|
|
54
54
|
isPageLoad = type === 'page_load' || type === 'transition';
|
|
55
|
-
if (isPageLoad) {
|
|
55
|
+
if (!(!isPageLoad || minorInteractions !== undefined && minorInteractions.length > 0)) {
|
|
56
56
|
_context.next = 12;
|
|
57
57
|
break;
|
|
58
58
|
}
|
|
@@ -78,6 +78,46 @@ function _createInteractionExtraLogPayload() {
|
|
|
78
78
|
}
|
|
79
79
|
return _context.abrupt("return", null);
|
|
80
80
|
case 23:
|
|
81
|
+
if (!(!lastInteractionFinish || lastInteractionFinish !== null && lastInteractionFinish !== void 0 && lastInteractionFinish.abortReason || lastInteractionFinish !== null && lastInteractionFinish !== void 0 && (_lastInteractionFinis = lastInteractionFinish.errors) !== null && _lastInteractionFinis !== void 0 && _lastInteractionFinis.length)) {
|
|
82
|
+
_context.next = 25;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
return _context.abrupt("return", null);
|
|
86
|
+
case 25:
|
|
87
|
+
normalTTAI = (_getTTAI2 = getTTAI(lastInteractionFinish)) !== null && _getTTAI2 !== void 0 ? _getTTAI2 : undefined;
|
|
88
|
+
lastInteractionFinishStart = typeof lastInteractionFinish.start === 'number' ? Math.round(lastInteractionFinish.start) : undefined;
|
|
89
|
+
lastInteractionFinishEnd = typeof lastInteractionFinish.end === 'number' ? Math.round(lastInteractionFinish.end) : undefined;
|
|
90
|
+
lastInteractionFinishVC90 = null;
|
|
91
|
+
lastInteractionFinishVCClean = false;
|
|
92
|
+
if (!lastInteractionFinishVCResult) {
|
|
93
|
+
_context.next = 41;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
lastInteractionFinishVCRev = lastInteractionFinishVCResult['ufo:vc:rev'];
|
|
97
|
+
lastInteractionFinishRevision = lastInteractionFinishVCRev === null || lastInteractionFinishVCRev === void 0 ? void 0 : lastInteractionFinishVCRev.find(function (_ref2) {
|
|
98
|
+
var revision = _ref2.revision;
|
|
99
|
+
return revision === DEFAULT_TTVC_REVISION;
|
|
100
|
+
});
|
|
101
|
+
if (!(lastInteractionFinishRevision !== null && lastInteractionFinishRevision !== void 0 && lastInteractionFinishRevision.clean)) {
|
|
102
|
+
_context.next = 38;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
lastInteractionFinishVCClean = true;
|
|
106
|
+
lastInteractionFinishVC90 = lastInteractionFinishRevision['metric:vc90'];
|
|
107
|
+
_context.next = 39;
|
|
108
|
+
break;
|
|
109
|
+
case 38:
|
|
110
|
+
return _context.abrupt("return", null);
|
|
111
|
+
case 39:
|
|
112
|
+
_context.next = 42;
|
|
113
|
+
break;
|
|
114
|
+
case 41:
|
|
115
|
+
if (normalTTAI !== undefined && typeof normalTTAI === 'number' && normalTTAI === extraTTAI) {
|
|
116
|
+
// Because TTAI is equal between with and without 3p, we can assume VC90 is also equal
|
|
117
|
+
lastInteractionFinishVC90 = effectiveVCRevisionPayload === null || effectiveVCRevisionPayload === void 0 ? void 0 : effectiveVCRevisionPayload['metric:vc90'];
|
|
118
|
+
lastInteractionFinishVCClean = effectiveVCRevisionPayload === null || effectiveVCRevisionPayload === void 0 ? void 0 : effectiveVCRevisionPayload.clean;
|
|
119
|
+
}
|
|
120
|
+
case 42:
|
|
81
121
|
// Helper function to check if labelStack contains third-party type
|
|
82
122
|
isThirdParty = function isThirdParty(labelStack) {
|
|
83
123
|
var _labelStack$some;
|
|
@@ -120,9 +160,9 @@ function _createInteractionExtraLogPayload() {
|
|
|
120
160
|
getDetailedInteractionMetrics = function getDetailedInteractionMetrics() {
|
|
121
161
|
var _interaction$hold3pIn;
|
|
122
162
|
return {
|
|
123
|
-
errors: filteredData.errors.map(function (
|
|
124
|
-
var labelStack =
|
|
125
|
-
others = _objectWithoutProperties(
|
|
163
|
+
errors: filteredData.errors.map(function (_ref3) {
|
|
164
|
+
var labelStack = _ref3.labelStack,
|
|
165
|
+
others = _objectWithoutProperties(_ref3, _excluded);
|
|
126
166
|
return _objectSpread(_objectSpread({}, others), {}, {
|
|
127
167
|
labelStack: labelStack && optimizeLabelStack(labelStack, getReactUFOPayloadVersion(interaction.type))
|
|
128
168
|
});
|
|
@@ -183,13 +223,20 @@ function _createInteractionExtraLogPayload() {
|
|
|
183
223
|
reactProfilerTimings: optimizeReactProfilerTimings(filteredData.reactProfilerTimings, start, getReactUFOPayloadVersion(interaction.type)),
|
|
184
224
|
customData: filteredData.customData
|
|
185
225
|
}, getDetailedInteractionMetrics()),
|
|
186
|
-
'vc:effective:revision': DEFAULT_TTVC_REVISION
|
|
226
|
+
'vc:effective:revision': DEFAULT_TTVC_REVISION,
|
|
227
|
+
lastInteractionFinish: {
|
|
228
|
+
start: lastInteractionFinishStart,
|
|
229
|
+
end: lastInteractionFinishEnd,
|
|
230
|
+
ttai: normalTTAI,
|
|
231
|
+
vc90: lastInteractionFinishVC90,
|
|
232
|
+
vcClean: lastInteractionFinishVCClean
|
|
233
|
+
}
|
|
187
234
|
}
|
|
188
235
|
}
|
|
189
236
|
};
|
|
190
237
|
payload.attributes.properties['event:sizeInKb'] = getPayloadSize(payload.attributes.properties);
|
|
191
238
|
return _context.abrupt("return", payload);
|
|
192
|
-
case
|
|
239
|
+
case 51:
|
|
193
240
|
case "end":
|
|
194
241
|
return _context.stop();
|
|
195
242
|
}
|
|
@@ -4,7 +4,7 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
4
4
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5
5
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
6
6
|
import { getConfig, getMostRecentVCRevision } from '../../config';
|
|
7
|
-
import { postInteractionLog } from '../../interaction-metrics';
|
|
7
|
+
import { interactionExtraMetrics, postInteractionLog } from '../../interaction-metrics';
|
|
8
8
|
import getInteractionStatus from './get-interaction-status';
|
|
9
9
|
import getPageVisibilityUpToTTAI from './get-page-visibility-up-to-ttai';
|
|
10
10
|
import getSSRDoneTimeValue from './get-ssr-done-time-value';
|
|
@@ -90,6 +90,7 @@ function _getVCMetrics() {
|
|
|
90
90
|
if (!include3p) {
|
|
91
91
|
// For Post Interaction, last interaction should be without 3p
|
|
92
92
|
postInteractionLog.setLastInteractionFinishVCResult(result);
|
|
93
|
+
interactionExtraMetrics.setLastInteractionFinishVCResult(result);
|
|
93
94
|
}
|
|
94
95
|
mostRecentVCRevision = getMostRecentVCRevision(interaction.ufoName);
|
|
95
96
|
mostRecentVCRevisionPayload = result === null || result === void 0 || (_result$ufoVcRev = result['ufo:vc:rev']) === null || _result$ufoVcRev === void 0 ? void 0 : _result$ufoVcRev.find(function (_ref) {
|
|
@@ -688,7 +688,8 @@ function finishInteraction(id, data) {
|
|
|
688
688
|
PreviousInteractionLog.isAborted = data.abortReason != null;
|
|
689
689
|
if (data.ufoName) {
|
|
690
690
|
if (fg('platform_ufo_enable_ttai_with_3p')) {
|
|
691
|
-
|
|
691
|
+
var _interactionExtraMetr;
|
|
692
|
+
if (((_interactionExtraMetr = interactionExtraMetrics.finishedInteraction) === null || _interactionExtraMetr === void 0 ? void 0 : _interactionExtraMetr.id) !== id) {
|
|
692
693
|
// If this same interaction was not already handled, handle it
|
|
693
694
|
handleInteraction(id, data);
|
|
694
695
|
}
|
|
@@ -773,7 +774,7 @@ export function tryComplete(interactionId, endTime) {
|
|
|
773
774
|
var postInteraction = /*#__PURE__*/function () {
|
|
774
775
|
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
775
776
|
var _getConfig7;
|
|
776
|
-
var _getConfig8, experimentalVC90, experimentalTTAI, _yield$getExperimenta, start, end, _getConfig9, _getConfig0;
|
|
777
|
+
var _getConfig8, experimentalVC90, experimentalTTAI, _yield$getExperimenta, start, end, _interactionExtraMetr2, _getConfig9, _getConfig0;
|
|
777
778
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
778
779
|
while (1) switch (_context.prev = _context.next) {
|
|
779
780
|
case 0:
|
|
@@ -816,7 +817,7 @@ export function tryComplete(interactionId, endTime) {
|
|
|
816
817
|
}));
|
|
817
818
|
case 17:
|
|
818
819
|
if (fg('platform_ufo_enable_ttai_with_3p')) {
|
|
819
|
-
if (interactionExtraMetrics.
|
|
820
|
+
if (((_interactionExtraMetr2 = interactionExtraMetrics.finishedInteraction) === null || _interactionExtraMetr2 === void 0 ? void 0 : _interactionExtraMetr2.id) !== interactionId) {
|
|
820
821
|
// If interactionExtraMetrics is not waiting for measuring this interaction
|
|
821
822
|
if ((_getConfig9 = getConfig()) !== null && _getConfig9 !== void 0 && (_getConfig9 = _getConfig9.experimentalInteractionMetrics) !== null && _getConfig9 !== void 0 && _getConfig9.enabled) {
|
|
822
823
|
remove(interactionId);
|
|
@@ -839,15 +840,15 @@ export function tryComplete(interactionId, endTime) {
|
|
|
839
840
|
};
|
|
840
841
|
}();
|
|
841
842
|
if (fg('platform_ufo_enable_ttai_with_3p')) {
|
|
842
|
-
var _interaction$hold3pAc;
|
|
843
|
+
var _interaction$hold3pAc, _interactionExtraMetr3;
|
|
843
844
|
var noMoreActive3pHolds = ((_interaction$hold3pAc = interaction.hold3pActive) === null || _interaction$hold3pAc === void 0 ? void 0 : _interaction$hold3pAc.size) === 0 || interaction.hold3pActive === undefined;
|
|
844
|
-
if (noMoreActiveHolds && interactionExtraMetrics.
|
|
845
|
+
if (noMoreActiveHolds && ((_interactionExtraMetr3 = interactionExtraMetrics.finishedInteraction) === null || _interactionExtraMetr3 === void 0 ? void 0 : _interactionExtraMetr3.id) !== interactionId) {
|
|
845
846
|
// If it's not waiting for extra metrics to complete, finish the interaction as normal
|
|
846
847
|
if (!activeSubmitted) {
|
|
847
848
|
var _getConfig1, _getConfig10, _getConfig11;
|
|
848
849
|
finishInteraction(interactionId, interaction, endTime);
|
|
849
850
|
if ((_getConfig1 = getConfig()) !== null && _getConfig1 !== void 0 && (_getConfig1 = _getConfig1.extraInteractionMetrics) !== null && _getConfig1 !== void 0 && _getConfig1.enabled) {
|
|
850
|
-
interactionExtraMetrics.
|
|
851
|
+
interactionExtraMetrics.updateFinishedInteraction(interaction);
|
|
851
852
|
}
|
|
852
853
|
if ((_getConfig10 = getConfig()) !== null && _getConfig10 !== void 0 && (_getConfig10 = _getConfig10.extraSearchPageInteraction) !== null && _getConfig10 !== void 0 && _getConfig10.enabled && interaction.ufoName === ((_getConfig11 = getConfig()) === null || _getConfig11 === void 0 || (_getConfig11 = _getConfig11.extraSearchPageInteraction) === null || _getConfig11 === void 0 ? void 0 : _getConfig11.searchPageMetricName) && fg('react_ufo_unified_search_ignoring_sain_metric')) {
|
|
853
854
|
onSearchPageInteractionComplete(interactionId, interaction);
|
|
@@ -9,8 +9,8 @@ import { remove } from './index';
|
|
|
9
9
|
var InteractionExtraMetrics = /*#__PURE__*/function () {
|
|
10
10
|
function InteractionExtraMetrics() {
|
|
11
11
|
_classCallCheck(this, InteractionExtraMetrics);
|
|
12
|
-
// Store the finished interaction
|
|
13
|
-
_defineProperty(this, "
|
|
12
|
+
// Store the finished interaction (as non-3p interaction)
|
|
13
|
+
_defineProperty(this, "finishedInteraction", null);
|
|
14
14
|
// independent VC observer, that observes until `custom.post-interaction-logs` event is sent
|
|
15
15
|
_defineProperty(this, "vcObserver", null);
|
|
16
16
|
_defineProperty(this, "sinkHandlerFn", function () {});
|
|
@@ -48,12 +48,17 @@ var InteractionExtraMetrics = /*#__PURE__*/function () {
|
|
|
48
48
|
return (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'page_load' || (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'transition';
|
|
49
49
|
}
|
|
50
50
|
}, {
|
|
51
|
-
key: "
|
|
52
|
-
value: function
|
|
53
|
-
if (
|
|
54
|
-
this.
|
|
51
|
+
key: "updateFinishedInteraction",
|
|
52
|
+
value: function updateFinishedInteraction(interaction) {
|
|
53
|
+
if ((interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'page_load' || (interaction === null || interaction === void 0 ? void 0 : interaction.type) === 'transition') {
|
|
54
|
+
this.finishedInteraction = interaction;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
}, {
|
|
58
|
+
key: "setLastInteractionFinishVCResult",
|
|
59
|
+
value: function setLastInteractionFinishVCResult(result) {
|
|
60
|
+
this.lastInteractionFinishVCResult = result;
|
|
61
|
+
}
|
|
57
62
|
}, {
|
|
58
63
|
key: "sinkHandler",
|
|
59
64
|
value: function sinkHandler(fn) {
|
|
@@ -67,7 +72,7 @@ var InteractionExtraMetrics = /*#__PURE__*/function () {
|
|
|
67
72
|
var updatedData = _objectSpread(_objectSpread({}, data), {}, {
|
|
68
73
|
vcObserver: (_this$vcObserver3 = this.vcObserver) !== null && _this$vcObserver3 !== void 0 ? _this$vcObserver3 : undefined
|
|
69
74
|
});
|
|
70
|
-
this.sinkHandlerFn(id, updatedData);
|
|
75
|
+
this.sinkHandlerFn(id, updatedData, this.finishedInteraction, this.lastInteractionFinishVCResult);
|
|
71
76
|
}
|
|
72
77
|
this.stopVCObserver();
|
|
73
78
|
remove(id);
|
|
@@ -76,11 +81,13 @@ var InteractionExtraMetrics = /*#__PURE__*/function () {
|
|
|
76
81
|
}, {
|
|
77
82
|
key: "reset",
|
|
78
83
|
value: function reset() {
|
|
84
|
+
var _this$finishedInterac;
|
|
79
85
|
this.stopVCObserver();
|
|
80
|
-
if (this.
|
|
81
|
-
remove(this.
|
|
86
|
+
if ((_this$finishedInterac = this.finishedInteraction) !== null && _this$finishedInterac !== void 0 && _this$finishedInterac.id) {
|
|
87
|
+
remove(this.finishedInteraction.id);
|
|
82
88
|
}
|
|
83
|
-
this.
|
|
89
|
+
this.finishedInteraction = null;
|
|
90
|
+
this.lastInteractionFinishVCResult = undefined;
|
|
84
91
|
}
|
|
85
92
|
}, {
|
|
86
93
|
key: "stopAll",
|
|
@@ -73,14 +73,14 @@ function sinkPostInteractionLog(instance, createPostInteractionLogPayload) {
|
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
function sinkInteractionExtraMetrics(instance, createInteractionExtraLogPayload) {
|
|
76
|
-
interactionExtraMetrics.sinkHandler(function (interactionId, interaction) {
|
|
76
|
+
interactionExtraMetrics.sinkHandler(function (interactionId, interaction, lastInteractionFinish, lastInteractionFinishVCResult) {
|
|
77
77
|
scheduleIdleCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
78
78
|
var payload, devToolObserver;
|
|
79
79
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
80
80
|
while (1) switch (_context.prev = _context.next) {
|
|
81
81
|
case 0:
|
|
82
82
|
_context.next = 2;
|
|
83
|
-
return createInteractionExtraLogPayload(interactionId, interaction);
|
|
83
|
+
return createInteractionExtraLogPayload(interactionId, interaction, lastInteractionFinish, lastInteractionFinishVCResult);
|
|
84
84
|
case 2:
|
|
85
85
|
payload = _context.sent;
|
|
86
86
|
if (payload) {
|
|
@@ -2,7 +2,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
2
2
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
3
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
4
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
-
import React, {
|
|
5
|
+
import React, { Profiler, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
|
|
6
6
|
import { unstable_NormalPriority as NormalPriority, unstable_scheduleCallback as scheduleCallback } from 'scheduler';
|
|
7
7
|
import { v4 as createUUID } from 'uuid';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
@@ -16,18 +16,9 @@ import UFORouteName from '../route-name-context';
|
|
|
16
16
|
import generateId from '../short-id';
|
|
17
17
|
import scheduleOnPaint from './schedule-on-paint';
|
|
18
18
|
var tryCompleteHandle;
|
|
19
|
-
var AsyncSegmentHighlight = /*#__PURE__*/lazy(function () {
|
|
20
|
-
return import( /* webpackChunkName: "@atlaskit-internal_ufo-segment-highlight" */'./segment-highlight').then(function (module) {
|
|
21
|
-
return {
|
|
22
|
-
default: module.SegmentHighlight
|
|
23
|
-
};
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
19
|
|
|
27
|
-
// KARL TODO: finish self profiling
|
|
28
20
|
/** A portion of the page we apply measurement to */
|
|
29
21
|
export default function UFOSegment(_ref) {
|
|
30
|
-
var _getConfig2;
|
|
31
22
|
var segmentName = _ref.name,
|
|
32
23
|
children = _ref.children,
|
|
33
24
|
_ref$mode = _ref.mode,
|
|
@@ -278,16 +269,11 @@ export default function UFOSegment(_ref) {
|
|
|
278
269
|
return l.name;
|
|
279
270
|
}).join('/');
|
|
280
271
|
}, [labelStack]);
|
|
281
|
-
var enableSegmentHighlighting = (_getConfig2 = getConfig()) === null || _getConfig2 === void 0 ? void 0 : _getConfig2.enableSegmentHighlighting;
|
|
282
272
|
return /*#__PURE__*/React.createElement(UFOInteractionContext.Provider, {
|
|
283
273
|
value: interactionContext
|
|
284
274
|
}, /*#__PURE__*/React.createElement(Profiler, {
|
|
285
275
|
id: reactProfilerId,
|
|
286
276
|
onRender: onRender
|
|
287
|
-
}, children
|
|
288
|
-
fallback: null
|
|
289
|
-
}, /*#__PURE__*/React.createElement(AsyncSegmentHighlight, {
|
|
290
|
-
segmentName: segmentName
|
|
291
|
-
}))));
|
|
277
|
+
}, children));
|
|
292
278
|
}
|
|
293
279
|
UFOSegment.displayName = 'UFOSegment';
|
|
@@ -304,24 +304,14 @@ var AbstractVCCalculatorBase = /*#__PURE__*/function () {
|
|
|
304
304
|
// Only create debug details if callbacks exist
|
|
305
305
|
v3RevisionDebugDetails = null;
|
|
306
306
|
if (shouldCalculateDebugDetails) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
};
|
|
316
|
-
} else {
|
|
317
|
-
v3RevisionDebugDetails = {
|
|
318
|
-
revision: this.revisionNo,
|
|
319
|
-
isClean: isVCClean,
|
|
320
|
-
abortReason: dirtyReason,
|
|
321
|
-
vcLogs: enhancedVcLogs,
|
|
322
|
-
interactionId: interactionId
|
|
323
|
-
};
|
|
324
|
-
}
|
|
307
|
+
v3RevisionDebugDetails = {
|
|
308
|
+
revision: this.revisionNo,
|
|
309
|
+
isClean: isVCClean && !interactionAbortReason && isPageVisible,
|
|
310
|
+
abortReason: !isPageVisible ? 'browser_backgrounded' : dirtyReason !== null && dirtyReason !== void 0 ? dirtyReason : interactionAbortReason,
|
|
311
|
+
vcLogs: enhancedVcLogs,
|
|
312
|
+
interactionId: interactionId,
|
|
313
|
+
interactionType: interactionType
|
|
314
|
+
};
|
|
325
315
|
}
|
|
326
316
|
|
|
327
317
|
// Handle devtool callback
|
|
@@ -132,6 +132,10 @@ export type Config = {
|
|
|
132
132
|
readonly rates?: Rates;
|
|
133
133
|
readonly kind?: Record<InteractionType, number>;
|
|
134
134
|
};
|
|
135
|
+
/**
|
|
136
|
+
* @private
|
|
137
|
+
* @deprecated - to be removed on next major version
|
|
138
|
+
*/
|
|
135
139
|
readonly enableSegmentHighlighting?: boolean;
|
|
136
140
|
readonly enableAdditionalPerformanceMarks?: boolean;
|
|
137
141
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { InteractionMetrics } from '../common';
|
|
2
|
+
import type { VCResult } from '../common/vc/types';
|
|
2
3
|
import type { LabelStack } from '../interaction-context';
|
|
3
|
-
declare function createInteractionExtraLogPayload(interactionId: string, interaction: InteractionMetrics): Promise<{
|
|
4
|
+
declare function createInteractionExtraLogPayload(interactionId: string, interaction: InteractionMetrics, lastInteractionFinish: InteractionMetrics | null, lastInteractionFinishVCResult?: VCResult): Promise<{
|
|
4
5
|
actionSubject: string;
|
|
5
6
|
action: string;
|
|
6
7
|
eventType: string;
|
|
@@ -96,6 +97,13 @@ declare function createInteractionExtraLogPayload(interactionId: string, interac
|
|
|
96
97
|
'metric:ttai:3p': number;
|
|
97
98
|
};
|
|
98
99
|
'vc:effective:revision': string;
|
|
100
|
+
lastInteractionFinish: {
|
|
101
|
+
start: number | undefined;
|
|
102
|
+
end: number | undefined;
|
|
103
|
+
ttai: number | undefined;
|
|
104
|
+
vc90: number | null;
|
|
105
|
+
vcClean: boolean;
|
|
106
|
+
};
|
|
99
107
|
};
|
|
100
108
|
};
|
|
101
109
|
} | null>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PostInteractionLogOutput } from '../common';
|
|
2
2
|
import type { LateMutation } from '../common/react-ufo-payload-schema';
|
|
3
|
-
declare function createPostInteractionLogPayload({ lastInteractionFinish, reactProfilerTimings, lastInteractionFinishVCResult, postInteractionFinishVCResult, postInteractionHoldInfo }: PostInteractionLogOutput): {
|
|
3
|
+
declare function createPostInteractionLogPayload({ lastInteractionFinish, reactProfilerTimings, lastInteractionFinishVCResult, postInteractionFinishVCResult, postInteractionHoldInfo, }: PostInteractionLogOutput): {
|
|
4
4
|
actionSubject: string;
|
|
5
5
|
action: string;
|
|
6
6
|
eventType: string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type VCResult } from '../common/vc/types';
|
|
1
2
|
import type { VCObserverInterface, VCObserverOptions } from '../vc/types';
|
|
2
3
|
import { type InteractionMetrics } from './index';
|
|
3
4
|
export default class InteractionExtraMetrics {
|
|
4
|
-
|
|
5
|
+
finishedInteraction: InteractionMetrics | null;
|
|
5
6
|
vcObserver: VCObserverInterface | null;
|
|
7
|
+
lastInteractionFinishVCResult?: VCResult;
|
|
6
8
|
private sinkHandlerFn;
|
|
7
9
|
initializeVCObserver(options: VCObserverOptions): void;
|
|
8
10
|
startVCObserver({ startTime }: {
|
|
@@ -10,8 +12,9 @@ export default class InteractionExtraMetrics {
|
|
|
10
12
|
}, interactionId: string): void;
|
|
11
13
|
stopVCObserver(): void;
|
|
12
14
|
eligibleToMeasure(interactionId: string): boolean;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
updateFinishedInteraction(interaction: InteractionMetrics): void;
|
|
16
|
+
setLastInteractionFinishVCResult(result: VCResult): void;
|
|
17
|
+
sinkHandler(fn: (interactionId: string, interaction: InteractionMetrics, lastInteractionFinish: InteractionMetrics | null, lastInteractionFinishVCResult?: VCResult) => void | Promise<void>): void;
|
|
15
18
|
onInteractionComplete(id: string, data: InteractionMetrics): void;
|
|
16
19
|
reset(): void;
|
|
17
20
|
stopAll(id: string): void;
|
|
@@ -132,6 +132,10 @@ export type Config = {
|
|
|
132
132
|
readonly rates?: Rates;
|
|
133
133
|
readonly kind?: Record<InteractionType, number>;
|
|
134
134
|
};
|
|
135
|
+
/**
|
|
136
|
+
* @private
|
|
137
|
+
* @deprecated - to be removed on next major version
|
|
138
|
+
*/
|
|
135
139
|
readonly enableSegmentHighlighting?: boolean;
|
|
136
140
|
readonly enableAdditionalPerformanceMarks?: boolean;
|
|
137
141
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { InteractionMetrics } from '../common';
|
|
2
|
+
import type { VCResult } from '../common/vc/types';
|
|
2
3
|
import type { LabelStack } from '../interaction-context';
|
|
3
|
-
declare function createInteractionExtraLogPayload(interactionId: string, interaction: InteractionMetrics): Promise<{
|
|
4
|
+
declare function createInteractionExtraLogPayload(interactionId: string, interaction: InteractionMetrics, lastInteractionFinish: InteractionMetrics | null, lastInteractionFinishVCResult?: VCResult): Promise<{
|
|
4
5
|
actionSubject: string;
|
|
5
6
|
action: string;
|
|
6
7
|
eventType: string;
|
|
@@ -96,6 +97,13 @@ declare function createInteractionExtraLogPayload(interactionId: string, interac
|
|
|
96
97
|
'metric:ttai:3p': number;
|
|
97
98
|
};
|
|
98
99
|
'vc:effective:revision': string;
|
|
100
|
+
lastInteractionFinish: {
|
|
101
|
+
start: number | undefined;
|
|
102
|
+
end: number | undefined;
|
|
103
|
+
ttai: number | undefined;
|
|
104
|
+
vc90: number | null;
|
|
105
|
+
vcClean: boolean;
|
|
106
|
+
};
|
|
99
107
|
};
|
|
100
108
|
};
|
|
101
109
|
} | null>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PostInteractionLogOutput } from '../common';
|
|
2
2
|
import type { LateMutation } from '../common/react-ufo-payload-schema';
|
|
3
|
-
declare function createPostInteractionLogPayload({ lastInteractionFinish, reactProfilerTimings, lastInteractionFinishVCResult, postInteractionFinishVCResult, postInteractionHoldInfo }: PostInteractionLogOutput): {
|
|
3
|
+
declare function createPostInteractionLogPayload({ lastInteractionFinish, reactProfilerTimings, lastInteractionFinishVCResult, postInteractionFinishVCResult, postInteractionHoldInfo, }: PostInteractionLogOutput): {
|
|
4
4
|
actionSubject: string;
|
|
5
5
|
action: string;
|
|
6
6
|
eventType: string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type VCResult } from '../common/vc/types';
|
|
1
2
|
import type { VCObserverInterface, VCObserverOptions } from '../vc/types';
|
|
2
3
|
import { type InteractionMetrics } from './index';
|
|
3
4
|
export default class InteractionExtraMetrics {
|
|
4
|
-
|
|
5
|
+
finishedInteraction: InteractionMetrics | null;
|
|
5
6
|
vcObserver: VCObserverInterface | null;
|
|
7
|
+
lastInteractionFinishVCResult?: VCResult;
|
|
6
8
|
private sinkHandlerFn;
|
|
7
9
|
initializeVCObserver(options: VCObserverOptions): void;
|
|
8
10
|
startVCObserver({ startTime }: {
|
|
@@ -10,8 +12,9 @@ export default class InteractionExtraMetrics {
|
|
|
10
12
|
}, interactionId: string): void;
|
|
11
13
|
stopVCObserver(): void;
|
|
12
14
|
eligibleToMeasure(interactionId: string): boolean;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
updateFinishedInteraction(interaction: InteractionMetrics): void;
|
|
16
|
+
setLastInteractionFinishVCResult(result: VCResult): void;
|
|
17
|
+
sinkHandler(fn: (interactionId: string, interaction: InteractionMetrics, lastInteractionFinish: InteractionMetrics | null, lastInteractionFinishVCResult?: VCResult) => void | Promise<void>): void;
|
|
15
18
|
onInteractionComplete(id: string, data: InteractionMetrics): void;
|
|
16
19
|
reset(): void;
|
|
17
20
|
stopAll(id: string): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/react-ufo",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.3",
|
|
4
4
|
"description": "Parts of React UFO that are publicly available",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -124,9 +124,6 @@
|
|
|
124
124
|
"platform_ufo_enable_interactivity_jsm": {
|
|
125
125
|
"type": "boolean"
|
|
126
126
|
},
|
|
127
|
-
"platform_ufo_unify_abort_status_in_ttvc_debug_data": {
|
|
128
|
-
"type": "boolean"
|
|
129
|
-
},
|
|
130
127
|
"platform_ufo_exclude_3p_elements_from_ttai": {
|
|
131
128
|
"type": "boolean"
|
|
132
129
|
},
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.SegmentHighlight = SegmentHighlight;
|
|
9
|
-
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
-
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
-
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
12
|
-
function SegmentHighlight(_ref) {
|
|
13
|
-
var segmentName = _ref.segmentName;
|
|
14
|
-
var _useState = (0, _react.useState)(false),
|
|
15
|
-
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
16
|
-
segmentHighlight = _useState2[0],
|
|
17
|
-
setSegmentHighlight = _useState2[1];
|
|
18
|
-
(0, _react.useEffect)(function () {
|
|
19
|
-
try {
|
|
20
|
-
var shouldHighlightSegments = sessionStorage.getItem('segmentsHighlight') === 'true';
|
|
21
|
-
setSegmentHighlight(shouldHighlightSegments);
|
|
22
|
-
} catch (err) {
|
|
23
|
-
/* do nothing */
|
|
24
|
-
}
|
|
25
|
-
}, []);
|
|
26
|
-
if (segmentHighlight) {
|
|
27
|
-
return (
|
|
28
|
-
/*#__PURE__*/
|
|
29
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
30
|
-
_react.default.createElement("span", {
|
|
31
|
-
"data-segment-name": segmentName,
|
|
32
|
-
style: {
|
|
33
|
-
display: 'none'
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
-
export function SegmentHighlight({
|
|
3
|
-
segmentName
|
|
4
|
-
}) {
|
|
5
|
-
const [segmentHighlight, setSegmentHighlight] = useState(false);
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
try {
|
|
8
|
-
const shouldHighlightSegments = sessionStorage.getItem('segmentsHighlight') === 'true';
|
|
9
|
-
setSegmentHighlight(shouldHighlightSegments);
|
|
10
|
-
} catch (err) {
|
|
11
|
-
/* do nothing */
|
|
12
|
-
}
|
|
13
|
-
}, []);
|
|
14
|
-
if (segmentHighlight) {
|
|
15
|
-
return (
|
|
16
|
-
/*#__PURE__*/
|
|
17
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
18
|
-
React.createElement("span", {
|
|
19
|
-
"data-segment-name": segmentName,
|
|
20
|
-
style: {
|
|
21
|
-
display: 'none'
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
-
import React, { useEffect, useState } from 'react';
|
|
3
|
-
export function SegmentHighlight(_ref) {
|
|
4
|
-
var segmentName = _ref.segmentName;
|
|
5
|
-
var _useState = useState(false),
|
|
6
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
7
|
-
segmentHighlight = _useState2[0],
|
|
8
|
-
setSegmentHighlight = _useState2[1];
|
|
9
|
-
useEffect(function () {
|
|
10
|
-
try {
|
|
11
|
-
var shouldHighlightSegments = sessionStorage.getItem('segmentsHighlight') === 'true';
|
|
12
|
-
setSegmentHighlight(shouldHighlightSegments);
|
|
13
|
-
} catch (err) {
|
|
14
|
-
/* do nothing */
|
|
15
|
-
}
|
|
16
|
-
}, []);
|
|
17
|
-
if (segmentHighlight) {
|
|
18
|
-
return (
|
|
19
|
-
/*#__PURE__*/
|
|
20
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
21
|
-
React.createElement("span", {
|
|
22
|
-
"data-segment-name": segmentName,
|
|
23
|
-
style: {
|
|
24
|
-
display: 'none'
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return null;
|
|
30
|
-
}
|