@paulirish/trace_engine 0.0.51 → 0.0.53
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/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
- package/core/platform/DOMUtilities.d.ts +8 -0
- package/core/platform/DOMUtilities.js +14 -0
- package/core/platform/DOMUtilities.js.map +1 -1
- package/core/platform/StringUtilities.d.ts +1 -5
- package/core/platform/StringUtilities.js +4 -1
- package/core/platform/StringUtilities.js.map +1 -1
- package/core/platform/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/core/platform/platform-tsconfig.json +1 -1
- package/generated/protocol.d.ts +345 -44
- package/locales/af.json +11 -5
- package/locales/am.json +7 -1
- package/locales/ar.json +7 -1
- package/locales/as.json +7 -1
- package/locales/az.json +7 -1
- package/locales/be.json +7 -1
- package/locales/bg.json +7 -1
- package/locales/bn.json +7 -1
- package/locales/bs.json +7 -1
- package/locales/ca.json +7 -1
- package/locales/cs.json +7 -1
- package/locales/cy.json +7 -1
- package/locales/da.json +7 -1
- package/locales/de.json +7 -1
- package/locales/el.json +7 -1
- package/locales/en-GB.json +7 -1
- package/locales/en-US.json +52 -7
- package/locales/en-XL.json +52 -7
- package/locales/es-419.json +7 -1
- package/locales/es.json +7 -1
- package/locales/et.json +7 -1
- package/locales/eu.json +7 -1
- package/locales/fa.json +7 -1
- package/locales/fi.json +7 -1
- package/locales/fil.json +7 -1
- package/locales/fr-CA.json +7 -1
- package/locales/fr.json +7 -1
- package/locales/gl.json +7 -1
- package/locales/gu.json +7 -1
- package/locales/he.json +7 -1
- package/locales/hi.json +7 -1
- package/locales/hr.json +7 -1
- package/locales/hu.json +7 -1
- package/locales/hy.json +7 -1
- package/locales/id.json +7 -1
- package/locales/is.json +7 -1
- package/locales/it.json +7 -1
- package/locales/ja.json +7 -1
- package/locales/ka.json +7 -1
- package/locales/kk.json +7 -1
- package/locales/km.json +7 -1
- package/locales/kn.json +7 -1
- package/locales/ko.json +7 -1
- package/locales/ky.json +7 -1
- package/locales/lo.json +7 -1
- package/locales/lt.json +7 -1
- package/locales/lv.json +7 -1
- package/locales/mk.json +7 -1
- package/locales/ml.json +7 -1
- package/locales/mn.json +7 -1
- package/locales/mr.json +7 -1
- package/locales/ms.json +7 -1
- package/locales/my.json +7 -1
- package/locales/ne.json +7 -1
- package/locales/nl.json +7 -1
- package/locales/no.json +7 -1
- package/locales/or.json +7 -1
- package/locales/pa.json +7 -1
- package/locales/pl.json +7 -1
- package/locales/pt-PT.json +7 -1
- package/locales/pt.json +7 -1
- package/locales/ro.json +7 -1
- package/locales/ru.json +7 -1
- package/locales/si.json +7 -1
- package/locales/sk.json +7 -1
- package/locales/sl.json +7 -1
- package/locales/sq.json +7 -1
- package/locales/sr-Latn.json +7 -1
- package/locales/sr.json +7 -1
- package/locales/sv.json +7 -1
- package/locales/sw.json +7 -1
- package/locales/ta.json +7 -1
- package/locales/te.json +7 -1
- package/locales/th.json +7 -1
- package/locales/tr.json +7 -1
- package/locales/uk.json +7 -1
- package/locales/ur.json +7 -1
- package/locales/uz.json +7 -1
- package/locales/vi.json +7 -1
- package/locales/zh-HK.json +7 -1
- package/locales/zh-TW.json +7 -1
- package/locales/zh.json +7 -1
- package/locales/zu.json +7 -1
- package/models/cpu_profile/cpu_profile-tsconfig.json +1 -1
- package/models/cpu_profile/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/LanternComputationData.js +3 -3
- package/models/trace/LanternComputationData.js.map +1 -1
- package/models/trace/Processor.d.ts +1 -3
- package/models/trace/Processor.js +1 -1
- package/models/trace/Processor.js.map +1 -1
- package/models/trace/TracingManager.js.map +1 -1
- package/models/trace/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/extras/ScriptDuplication.d.ts +5 -2
- package/models/trace/extras/ScriptDuplication.js +4 -2
- package/models/trace/extras/ScriptDuplication.js.map +1 -1
- package/models/trace/extras/StackTraceForEvent.js +88 -47
- package/models/trace/extras/StackTraceForEvent.js.map +1 -1
- package/models/trace/extras/ThirdParties.d.ts +13 -12
- package/models/trace/extras/ThirdParties.js +50 -19
- package/models/trace/extras/ThirdParties.js.map +1 -1
- package/models/trace/extras/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/extras/extras-tsconfig.json +1 -1
- package/models/trace/extras/extras.d.ts +98 -6
- package/models/trace/extras/extras.js +98 -6
- package/models/trace/handlers/AsyncJSCallsHandler.d.ts +5 -0
- package/models/trace/handlers/AsyncJSCallsHandler.js +12 -9
- package/models/trace/handlers/AsyncJSCallsHandler.js.map +1 -1
- package/models/trace/handlers/FramesHandler.js.map +1 -1
- package/models/trace/handlers/NetworkRequestsHandler.d.ts +1 -0
- package/models/trace/handlers/NetworkRequestsHandler.js +37 -23
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
- package/models/trace/handlers/ScriptsHandler.d.ts +5 -1
- package/models/trace/handlers/ScriptsHandler.js +59 -22
- package/models/trace/handlers/ScriptsHandler.js.map +1 -1
- package/models/trace/handlers/WarningsHandler.js +14 -2
- package/models/trace/handlers/WarningsHandler.js.map +1 -1
- package/models/trace/handlers/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/handlers/handlers-tsconfig.json +1 -1
- package/models/trace/handlers/helpers.js +12 -0
- package/models/trace/handlers/helpers.js.map +1 -1
- package/models/trace/handlers/types.d.ts +2 -6
- package/models/trace/handlers/types.js.map +1 -1
- package/models/trace/helpers/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/helpers/helpers-tsconfig.json +1 -1
- package/models/trace/insights/CLSCulprits.d.ts +6 -1
- package/models/trace/insights/CLSCulprits.js +11 -2
- package/models/trace/insights/CLSCulprits.js.map +1 -1
- package/models/trace/insights/Cache.d.ts +0 -1
- package/models/trace/insights/Cache.js +8 -7
- package/models/trace/insights/Cache.js.map +1 -1
- package/models/trace/insights/Common.js +6 -0
- package/models/trace/insights/Common.js.map +1 -1
- package/models/trace/insights/DocumentLatency.d.ts +7 -3
- package/models/trace/insights/DocumentLatency.js +25 -8
- package/models/trace/insights/DocumentLatency.js.map +1 -1
- package/models/trace/insights/DuplicatedJavaScript.js +9 -3
- package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
- package/models/trace/insights/ImageDelivery.d.ts +0 -1
- package/models/trace/insights/ImageDelivery.js +1 -1
- package/models/trace/insights/ImageDelivery.js.map +1 -1
- package/models/trace/insights/LCPPhases.d.ts +1 -1
- package/models/trace/insights/LCPPhases.js +1 -1
- package/models/trace/insights/LCPPhases.js.map +1 -1
- package/models/trace/insights/LegacyJavaScript.d.ts +1 -1
- package/models/trace/insights/LegacyJavaScript.js +6 -3
- package/models/trace/insights/LegacyJavaScript.js.map +1 -1
- package/models/trace/insights/NetworkDependencyTree.d.ts +151 -3
- package/models/trace/insights/NetworkDependencyTree.js +648 -10
- package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
- package/models/trace/insights/RenderBlocking.js +1 -1
- package/models/trace/insights/RenderBlocking.js.map +1 -1
- package/models/trace/insights/ThirdParties.d.ts +1 -1
- package/models/trace/insights/ThirdParties.js +7 -7
- package/models/trace/insights/ThirdParties.js.map +1 -1
- package/models/trace/insights/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/insights/insights-tsconfig.json +1 -1
- package/models/trace/insights/types.d.ts +11 -0
- package/models/trace/insights/types.js.map +1 -1
- package/models/trace/lantern/core/core-tsconfig.json +1 -1
- package/models/trace/lantern/core/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/lantern/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/lantern/graph/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/lantern/graph/graph-tsconfig.json +1 -1
- package/models/trace/lantern/lantern-tsconfig.json +1 -1
- package/models/trace/lantern/metrics/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/lantern/metrics/metrics-tsconfig.json +1 -1
- package/models/trace/lantern/simulation/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/lantern/simulation/simulation-tsconfig.json +1 -1
- package/models/trace/lantern/types/Lantern.d.ts +4 -7
- package/models/trace/lantern/types/Lantern.js +1 -0
- package/models/trace/lantern/types/Lantern.js.map +1 -1
- package/models/trace/lantern/types/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/lantern/types/types-tsconfig.json +1 -1
- package/models/trace/trace-tsconfig.json +1 -1
- package/models/trace/types/Configuration.d.ts +2 -0
- package/models/trace/types/Configuration.js.map +1 -1
- package/models/trace/types/Extensions.d.ts +1 -3
- package/models/trace/types/Extensions.js.map +1 -1
- package/models/trace/types/File.d.ts +2 -1
- package/models/trace/types/File.js.map +1 -1
- package/models/trace/types/TraceEvents.d.ts +51 -26
- package/models/trace/types/TraceEvents.js +6 -0
- package/models/trace/types/TraceEvents.js.map +1 -1
- package/models/trace/types/devtools_entrypoint-bundle-typescript-tsconfig.json +1 -1
- package/models/trace/types/types-tsconfig.json +1 -1
- package/package.json +1 -1
- package/test/test-trace-engine.mjs +2 -2
|
@@ -34,6 +34,7 @@ interface NetworkRequestData {
|
|
|
34
34
|
eventToInitiator: Map<Types.Events.SyntheticNetworkRequest, Types.Events.SyntheticNetworkRequest>;
|
|
35
35
|
webSocket: WebSocketTraceData[];
|
|
36
36
|
entityMappings: HandlerHelpers.EntityMappings;
|
|
37
|
+
linkPreconnectEvents: Types.Events.LinkPreconnect[];
|
|
37
38
|
}
|
|
38
39
|
export declare function reset(): void;
|
|
39
40
|
export declare function handleEvent(event: Types.Events.Event): void;
|
|
@@ -9,6 +9,7 @@ import { data as metaHandlerData } from './MetaHandler.js';
|
|
|
9
9
|
const MILLISECONDS_TO_MICROSECONDS = 1000;
|
|
10
10
|
const SECONDS_TO_MICROSECONDS = 1000000;
|
|
11
11
|
const webSocketData = new Map();
|
|
12
|
+
const linkPreconnectEvents = [];
|
|
12
13
|
const requestMap = new Map();
|
|
13
14
|
const requestsById = new Map();
|
|
14
15
|
const requestsByOrigin = new Map();
|
|
@@ -44,7 +45,7 @@ function storeTraceEventWithRequestId(requestId, key, value) {
|
|
|
44
45
|
}
|
|
45
46
|
function firstPositiveValueInList(entries) {
|
|
46
47
|
for (const entry of entries) {
|
|
47
|
-
if (entry > 0) {
|
|
48
|
+
if (entry && entry > 0) {
|
|
48
49
|
return entry;
|
|
49
50
|
}
|
|
50
51
|
}
|
|
@@ -64,6 +65,7 @@ export function reset() {
|
|
|
64
65
|
entityMappings.eventsByEntity.clear();
|
|
65
66
|
entityMappings.entityByEvent.clear();
|
|
66
67
|
entityMappings.createdEntityCache.clear();
|
|
68
|
+
linkPreconnectEvents.length = 0;
|
|
67
69
|
}
|
|
68
70
|
export function handleEvent(event) {
|
|
69
71
|
if (Types.Events.isResourceChangePriority(event)) {
|
|
@@ -117,13 +119,17 @@ export function handleEvent(event) {
|
|
|
117
119
|
}
|
|
118
120
|
webSocketData.get(identifier)?.events.push(event);
|
|
119
121
|
}
|
|
122
|
+
if (Types.Events.isLinkPreconnect(event)) {
|
|
123
|
+
linkPreconnectEvents.push(event);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
120
126
|
}
|
|
121
127
|
export async function finalize() {
|
|
122
128
|
const { rendererProcessesByFrame } = metaHandlerData();
|
|
123
129
|
for (const [requestId, request] of requestMap.entries()) {
|
|
124
130
|
// If we have an incomplete set of events here, we choose to drop the network
|
|
125
131
|
// request rather than attempt to synthesize the missing data.
|
|
126
|
-
if (!request.sendRequests
|
|
132
|
+
if (!request.sendRequests) {
|
|
127
133
|
continue;
|
|
128
134
|
}
|
|
129
135
|
// In the data we may get multiple willSendRequests and sendRequests, which
|
|
@@ -159,12 +165,18 @@ export async function finalize() {
|
|
|
159
165
|
dur,
|
|
160
166
|
});
|
|
161
167
|
}
|
|
168
|
+
const firstSendRequest = request.sendRequests[0];
|
|
169
|
+
const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];
|
|
170
|
+
// We currently do not want to include data URI requests. We may revisit this in the future.
|
|
171
|
+
if (finalSendRequest.args.data.url.startsWith('data:')) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
162
174
|
// If a ResourceFinish event with an encoded data length is received,
|
|
163
175
|
// then the resource was not cached; it was fetched before it was
|
|
164
176
|
// requested, e.g. because it was pushed in this navigation.
|
|
165
177
|
const isPushedResource = request.resourceFinish?.args.data.encodedDataLength !== 0;
|
|
166
178
|
// This works around crbug.com/998397, which reports pushed resources, and resources served by a service worker as disk cached.
|
|
167
|
-
const isDiskCached = request.receiveResponse.args.data.fromCache &&
|
|
179
|
+
const isDiskCached = !!request.receiveResponse && request.receiveResponse.args.data.fromCache &&
|
|
168
180
|
!request.receiveResponse.args.data.fromServiceWorker && !isPushedResource;
|
|
169
181
|
// If the request contains a resourceMarkAsCached event, it was served from memory cache.
|
|
170
182
|
// The timing data returned is from the original (uncached) request, which
|
|
@@ -180,13 +192,11 @@ export async function finalize() {
|
|
|
180
192
|
const isMemoryCached = request.resourceMarkAsCached !== undefined;
|
|
181
193
|
// If a request has `resourceMarkAsCached` field, the `timing` field is not correct.
|
|
182
194
|
// So let's discard it and override to 0 (which will be handled in later logic if timing field is undefined).
|
|
183
|
-
const timing = isMemoryCached ? undefined : request.receiveResponse
|
|
184
|
-
// If a non-cached
|
|
185
|
-
if (!timing && !isMemoryCached) {
|
|
195
|
+
const timing = isMemoryCached ? undefined : request.receiveResponse?.args.data.timing;
|
|
196
|
+
// If a non-cached response has no |timing|, we ignore it. An example of this is chrome://new-page / about:blank.
|
|
197
|
+
if (request.receiveResponse && !timing && !isMemoryCached) {
|
|
186
198
|
continue;
|
|
187
199
|
}
|
|
188
|
-
const firstSendRequest = request.sendRequests[0];
|
|
189
|
-
const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];
|
|
190
200
|
const initialPriority = finalSendRequest.args.data.priority;
|
|
191
201
|
let finalPriority = initialPriority;
|
|
192
202
|
if (request.changePriority) {
|
|
@@ -247,13 +257,14 @@ export async function finalize() {
|
|
|
247
257
|
// Otherwise it is whichever positive number comes first from the following timing info:
|
|
248
258
|
// DNS start, Connection start, Send Start, or the time duration between our start time and
|
|
249
259
|
// receiving a response.
|
|
250
|
-
const stalled = timing ?
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
const stalled = timing ?
|
|
261
|
+
Types.Timing.Micro(firstPositiveValueInList([
|
|
262
|
+
timing.dnsStart * MILLISECONDS_TO_MICROSECONDS,
|
|
263
|
+
timing.connectStart * MILLISECONDS_TO_MICROSECONDS,
|
|
264
|
+
timing.sendStart * MILLISECONDS_TO_MICROSECONDS,
|
|
265
|
+
request.receiveResponse ? (request.receiveResponse.ts - endRedirectTime) : null,
|
|
266
|
+
])) :
|
|
267
|
+
(request.receiveResponse ? Types.Timing.Micro(request.receiveResponse.ts - startTime) : Types.Timing.Micro(0));
|
|
257
268
|
// Sending HTTP request
|
|
258
269
|
// =======================
|
|
259
270
|
// Time when the HTTP request is sent.
|
|
@@ -273,7 +284,8 @@ export async function finalize() {
|
|
|
273
284
|
Types.Timing.Micro(timing.requestTime * SECONDS_TO_MICROSECONDS + timing.receiveHeadersEnd * MILLISECONDS_TO_MICROSECONDS) :
|
|
274
285
|
startTime;
|
|
275
286
|
const download = timing ? Types.Timing.Micro(((finishTime || downloadStart) - downloadStart)) :
|
|
276
|
-
Types.Timing.Micro(endTime - request.receiveResponse.ts)
|
|
287
|
+
request.receiveResponse ? Types.Timing.Micro(endTime - request.receiveResponse.ts) :
|
|
288
|
+
Types.Timing.Micro(0);
|
|
277
289
|
const totalTime = Types.Timing.Micro(networkDuration + processingDuration);
|
|
278
290
|
// Collect a few values from the timing info.
|
|
279
291
|
// If the Network request is cached, these fields will be zero, so the minus will zero out them.
|
|
@@ -328,12 +340,12 @@ export async function finalize() {
|
|
|
328
340
|
decodedBodyLength,
|
|
329
341
|
encodedDataLength,
|
|
330
342
|
frame,
|
|
331
|
-
fromServiceWorker: request.receiveResponse
|
|
343
|
+
fromServiceWorker: request.receiveResponse?.args.data.fromServiceWorker,
|
|
332
344
|
isLinkPreload: finalSendRequest.args.data.isLinkPreload || false,
|
|
333
|
-
mimeType: request.receiveResponse
|
|
345
|
+
mimeType: request.receiveResponse?.args.data.mimeType ?? '',
|
|
334
346
|
priority: finalPriority,
|
|
335
347
|
initialPriority,
|
|
336
|
-
protocol: request.receiveResponse
|
|
348
|
+
protocol: request.receiveResponse?.args.data.protocol ?? 'unknown',
|
|
337
349
|
redirects,
|
|
338
350
|
// In the event the property isn't set, assume non-blocking.
|
|
339
351
|
renderBlocking: renderBlocking ?? 'non_blocking',
|
|
@@ -341,8 +353,8 @@ export async function finalize() {
|
|
|
341
353
|
requestingFrameUrl,
|
|
342
354
|
requestMethod: finalSendRequest.args.data.requestMethod,
|
|
343
355
|
resourceType: finalSendRequest.args.data.resourceType ?? "Other" /* Protocol.Network.ResourceType.Other */,
|
|
344
|
-
statusCode: request.receiveResponse
|
|
345
|
-
responseHeaders: request.receiveResponse
|
|
356
|
+
statusCode: request.receiveResponse?.args.data.statusCode ?? 0,
|
|
357
|
+
responseHeaders: request.receiveResponse?.args.data.headers ?? null,
|
|
346
358
|
fetchPriorityHint: finalSendRequest.args.data.fetchPriorityHint ?? 'auto',
|
|
347
359
|
initiator: finalSendRequest.args.data.initiator,
|
|
348
360
|
stackTrace: finalSendRequest.args.data.stackTrace,
|
|
@@ -350,8 +362,9 @@ export async function finalize() {
|
|
|
350
362
|
url,
|
|
351
363
|
failed: request.resourceFinish?.args.data.didFail ?? false,
|
|
352
364
|
finished: Boolean(request.resourceFinish),
|
|
353
|
-
|
|
354
|
-
|
|
365
|
+
hasResponse: Boolean(request.receiveResponse),
|
|
366
|
+
connectionId: request.receiveResponse?.args.data.connectionId,
|
|
367
|
+
connectionReused: request.receiveResponse?.args.data.connectionReused,
|
|
355
368
|
},
|
|
356
369
|
},
|
|
357
370
|
cat: 'loading',
|
|
@@ -417,6 +430,7 @@ export function data() {
|
|
|
417
430
|
eventsByEntity: new Map(entityMappings.eventsByEntity),
|
|
418
431
|
createdEntityCache: new Map(entityMappings.createdEntityCache),
|
|
419
432
|
},
|
|
433
|
+
linkPreconnectEvents,
|
|
420
434
|
};
|
|
421
435
|
}
|
|
422
436
|
export function deps() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkRequestsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/NetworkRequestsHandler.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,KAAK,cAAc,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAC,IAAI,IAAI,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAGzD,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAC1C,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAkCxC,MAAM,aAAa,GAAG,IAAI,GAAG,EAA8B,CAAC;AAc5D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwC,CAAC;AACnE,MAAM,YAAY,GAAG,IAAI,GAAG,EAAgD,CAAC;AAC7E,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAI5B,CAAC;AACL,MAAM,cAAc,GAA2C,EAAE,CAAC;AAElE,MAAM,iCAAiC,GAAG,IAAI,GAAG,EAAkD,CAAC;AACpG,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA8E,CAAC;AAElH;;;;GAIG;AACH,MAAM,cAAc,GAAkC;IACpD,cAAc,EAAE,IAAI,GAAG,EAA+C;IACtE,aAAa,EAAE,IAAI,GAAG,EAA6C;IACnE,kBAAkB,EAAE,IAAI,GAAG,EAAiC;CAC7D,CAAC;AAEF,SAAS,4BAA4B,CACjC,SAAiB,EAAE,GAAM,EAAE,KAAsC;IACnE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gDAAgD,SAAS,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAyB,CAAC;QACxD,MAAM,MAAM,GAAG,KAA6B,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,OAAiB;IACjD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,oEAAoE;IACpE,uEAAuE;IACvE,oEAAoE;IACpE,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,YAAY,CAAC,KAAK,EAAE,CAAC;IACrB,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACzB,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,iCAAiC,CAAC,KAAK,EAAE,CAAC;IAC1C,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAC5B,aAAa,CAAC,KAAK,EAAE,CAAC;IACtB,cAAc,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IACtC,cAAc,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;IACrC,cAAc,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,IAAI,KAAK,CAAC,MAAM,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACrF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAClF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,EAAE,KAAK,CAAC,CAAC;QACvF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC;QAC5E,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;QAC9C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC1B,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE;oBAC5B,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;oBAC5B,mBAAmB,EAAE,UAAU;oBAC/B,MAAM,EAAE,EAAE;oBACV,mBAAmB,EAAE,IAAI;iBAC1B,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACpC,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE;oBAC5B,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;oBAClC,mBAAmB,EAAE,UAAU;oBAC/B,MAAM,EAAE,EAAE;oBACV,mBAAmB,EAAE,IAAI;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,EAAC,wBAAwB,EAAC,GAAG,eAAe,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACxD,6EAA6E;QAC7E,8DAA8D;QAC9D,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YACtD,SAAS;QACX,CAAC;QAED,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,gEAAgE;QAChE,0EAA0E;QAC1E,wEAAwE;QACxE,yEAAyE;QACzE,mEAAmE;QACnE,0EAA0E;QAC1E,gBAAgB;QAChB,MAAM,SAAS,GAA4C,EAAE,CAAC;QAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzD,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAEpD,oEAAoE;YACpE,0EAA0E;YAC1E,iEAAiE;YACjE,IAAI,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;YACxB,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YAClE,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrE,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;gBACpD,MAAM,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC5D,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;gBACxB,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;YACxE,CAAC;YAED,SAAS,CAAC,IAAI,CAAC;gBACb,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBAC9B,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;gBACxC,aAAa,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa;gBAClD,EAAE;gBACF,GAAG;aACJ,CAAC,CAAC;QACL,CAAC;QAED,qEAAqE;QACrE,iEAAiE;QACjE,4DAA4D;QAC5D,MAAM,gBAAgB,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,CAAC;QACnF,+HAA+H;QAC/H,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;YAC5D,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,gBAAgB,CAAC;QAC9E,yFAAyF;QACzF,0EAA0E;QAC1E,sEAAsE;QACtE,4EAA4E;QAC5E,qBAAqB;QACrB,EAAE;QACF,yEAAyE;QACzE,iCAAiC;QACjC,sEAAsE;QACtE,yEAAyE;QACzE,uEAAuE;QACvE,MAAM,cAAc,GAAG,OAAO,CAAC,oBAAoB,KAAK,SAAS,CAAC;QAClE,oFAAoF;QACpF,6GAA6G;QAC7G,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QACrF,6EAA6E;QAC7E,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAC/B,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE/E,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC5D,IAAI,aAAa,GAAG,eAAe,CAAC;QACpC,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3B,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC5D,CAAC;QAED,mCAAmC;QACnC,6JAA6J;QAE7J,aAAa;QACb,0BAA0B;QAC1B,gFAAgF;QAChF,+DAA+D;QAC/D,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAE/F,oBAAoB;QACpB,0BAA0B;QAC1B,iFAAiF;QACjF,2EAA2E;QAC3E,oEAAoE;QACpE,MAAM,eAAe,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;YACxD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAE5C,2BAA2B;QAC3B,0BAA0B;QAC1B,yDAAyD;QACzD,0FAA0F;QAC1F,wEAAwE;QACxE,EAAE;QACF,8DAA8D;QAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;QACrF,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7D,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC;YAC3F,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEhC,mBAAmB;QACnB,0BAA0B;QAC1B,6BAA6B;QAC7B,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,eAAe,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3G,sBAAsB;QACtB,0BAA0B;QAC1B,gCAAgC;QAChC,MAAM,kBAAkB,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC;QAEjF,uBAAuB;QACvB,0BAA0B;QAC1B,iGAAiG;QACjG,qGAAqG;QACrG,qDAAqD;QACrD,MAAM,mBAAmB,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;QAE5E,WAAW;QACX,0BAA0B;QAC1B,8FAA8F;QAC9F,kGAAkG;QAClG,qDAAqD;QACrD,MAAM,qBAAqB,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,GAAG,uBAAuB,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1G,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAEhH,UAAU;QACV,0BAA0B;QAC1B,8FAA8F;QAC9F,wBAAwB;QACxB,wFAAwF;QACxF,2FAA2F;QAC3F,wBAAwB;QACxB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC;YACnE,MAAM,CAAC,QAAQ,GAAG,4BAA4B;YAC9C,MAAM,CAAC,YAAY,GAAG,4BAA4B;YAClD,MAAM,CAAC,SAAS,GAAG,4BAA4B;YAC/C,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,GAAG,eAAe,CAAC;SAC/C,CAAC,CAAC,CAAC,CAAC;YACoB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;QAEpF,uBAAuB;QACvB,0BAA0B;QAC1B,sCAAsC;QACtC,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,KAAK,CACd,MAAM,CAAC,WAAW,GAAG,uBAAuB,GAAG,MAAM,CAAC,SAAS,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACrG,SAAS,CAAC;QAEd,UAAU;QACV,0BAA0B;QAC1B,4EAA4E;QAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC;YACpB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAChG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE1B,WAAW;QACX,0BAA0B;QAC1B,mDAAmD;QACnD,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,KAAK,CACd,MAAM,CAAC,WAAW,GAAG,uBAAuB,GAAG,MAAM,CAAC,iBAAiB,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAC7G,SAAS,CAAC;QACd,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,aAAa,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACrE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAEnF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,kBAAkB,CAAC,CAAC;QAE3E,6CAA6C;QAC7C,gGAAgG;QAChG,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC;YAC7B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAC1F,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACxF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC;YAC9B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAC9F,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE1B,8DAA8D;QAC9D,MAAM,EAAC,KAAK,EAAE,GAAG,EAAE,cAAc,EAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAChE,MAAM,EAAC,iBAAiB,EAAE,iBAAiB,EAAC,GACxC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAC,CAAC;QAC7G,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAAC;QAChD,MAAM,kBAAkB,GACpB,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,CAAC,EAAE,EAAE,wBAAwB,CAAC,IAAI,EAAE,CAAC;QACtG,8DAA8D;QAC9D,MAAM,YAAY,GACd,OAAO,CAAC,eAAe,CAAC,sBAAsB,CAAC,sBAAsB,CAAuC;YAC1G,cAAc,EAAE,gBAAgB;YAChC,IAAI,EAAE;gBACJ,IAAI,EAAE;oBACJ,2EAA2E;oBAC3E,aAAa,EAAE;wBACb,SAAS;wBACT,QAAQ;wBACR,aAAa;wBACb,UAAU;wBACV,iBAAiB;wBACjB,YAAY;wBACZ,OAAO;wBACP,cAAc;wBACd,gBAAgB;wBAChB,eAAe;wBACf,kBAAkB;wBAClB,gBAAgB;wBAChB,QAAQ;wBACR,mBAAmB;wBACnB,WAAW;wBACX,aAAa;wBACb,GAAG;wBACH,OAAO;wBACP,SAAS;wBACT,OAAO;qBACR;oBACD,0DAA0D;oBAC1D,iBAAiB;oBACjB,iBAAiB;oBACjB,KAAK;oBACL,iBAAiB,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB;oBACtE,aAAa,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,KAAK;oBAChE,QAAQ,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;oBACpD,QAAQ,EAAE,aAAa;oBACvB,eAAe;oBACf,QAAQ,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS;oBACjE,SAAS;oBACT,4DAA4D;oBAC5D,cAAc,EAAE,cAAc,IAAI,cAAc;oBAChD,SAAS;oBACT,kBAAkB;oBAClB,aAAa,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa;oBACvD,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,qDAAuC;oBAC5F,UAAU,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;oBACxD,eAAe,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE;oBAChE,iBAAiB,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,MAAM;oBACzE,SAAS,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;oBAC/C,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;oBACjD,MAAM;oBACN,GAAG;oBACH,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK;oBAC1D,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;oBACzC,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY;oBAC5D,gBAAgB,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB;iBACrE;aACF;YACD,GAAG,EAAE,SAAS;YACd,IAAI,6EAA6C;YACjD,EAAE,uCAA6B;YAC/B,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC5C,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC7C,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;YACjC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;YAClC,GAAG,EAAE,gBAAgB,CAAC,GAAG;YACzB,GAAG,EAAE,gBAAgB,CAAC,GAAG;SAC1B,CAAC,CAAC;QAEP,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,gBAAgB,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE;YAC3F,OAAO;gBACL,cAAc,EAAE,EAAE;gBAClB,iBAAiB,EAAE,EAAE;gBACrB,GAAG,EAAE,EAAE;aACR,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,mEAAmE;QACnE,uEAAuE;QACvE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,4CAA4C,CAAC,YAAY,CAAC,EAAE,CAAC;YAChF,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;QAED,uEAAuE;QACvE,gEAAgE;QAChE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAEjE,iDAAiD;QACjD,cAAc,CAAC,gCAAgC,CAAC,YAAY,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAEvF,oCAAoC;QACpC,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG;YACtD,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QACnF,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,iCAAiC,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YACzE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1B,iCAAiC,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,MAAM,eAAe,GAAG,iCAAiC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAErF,IAAI,eAAe,EAAE,CAAC;YACpB,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;gBAC7C,mBAAmB,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IACD,qBAAqB,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,gBAAgB;QAC1B,MAAM,EAAE,cAAc;QACtB,gBAAgB,EAAE,mBAAmB;QACrC,SAAS,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;QACtC,cAAc,EAAE;YACd,aAAa,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,aAAa,CAAC;YACpD,cAAc,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC;YACtD,kBAAkB,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,kBAAkB,CAAC;SAC/D;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,qBAAqB;IAC5B,gFAAgF;IAChF,gGAAgG;IAChG,0GAA0G;IAC1G,oDAAoD;IACpD,IAAI;IACJ,2CAA2C;IAC3C,4FAA4F;IAC5F,IAAI;IACJ,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC3B,IAAI,UAAU,GAAqC,IAAI,CAAC;QACxD,IAAI,QAAQ,GAAuC,IAAI,CAAC;QACxD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1C,UAAU,GAAG,KAAK,CAAC;YACrB,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3C,QAAQ,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,mBAAmB,GAAG,kCAAkC,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kCAAkC,CACvC,UAA6C,EAAE,QAA4C,EAC3F,kBAA+C;IACjD,MAAM,EAAC,WAAW,EAAC,GAAG,eAAe,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC;IAC7D,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC;IACvD,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACjC,MAAM,SAAS,GAAG,UAAU,IAAI,QAAQ,IAAI,kBAAkB,CAAC;IAC/D,OAAO;QACL,IAAI,EAAE,8BAA8B;QACpC,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,EAAE,uCAA6B;QAC/B,EAAE,EAAE,OAAO;QACX,GAAG,EAAE,QAA8B;QACnC,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,cAAc,EAAE,SAAS;QACzB,IAAI,EAAE,mBAAmB;QACzB,IAAI,EAAE;YACJ,IAAI,EAAE;gBACJ,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;gBAC1C,QAAQ,mDAAuC;gBAC/C,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE;aACnC;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Protocol from '../../../generated/protocol.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport * as HandlerHelpers from './helpers.js';\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport type {HandlerName} from './types.js';\n\nconst MILLISECONDS_TO_MICROSECONDS = 1000;\nconst SECONDS_TO_MICROSECONDS = 1000000;\n\n// Network requests from traces are actually formed of 5 trace records.\n// This handler tracks all trace records based on the request ID, and\n// then creates a new synthetic trace event for those network requests.\n//\n// This interface, then, defines the shape of the object we intend to\n// keep for each request in the trace. In the finalize we will convert\n// these 5 types of trace records to a synthetic complete event that\n// represents a composite of these trace records.\nexport interface TraceEventsForNetworkRequest {\n changePriority?: Types.Events.ResourceChangePriority;\n willSendRequests?: Types.Events.ResourceWillSendRequest[];\n sendRequests?: Types.Events.ResourceSendRequest[];\n receiveResponse?: Types.Events.ResourceReceiveResponse;\n resourceFinish?: Types.Events.ResourceFinish;\n receivedData?: Types.Events.ResourceReceivedData[];\n resourceMarkAsCached?: Types.Events.ResourceMarkAsCached;\n}\n\nexport interface WebSocketTraceDataForFrame {\n frame: string;\n webSocketIdentifier: number;\n events: Types.Events.WebSocketEvent[];\n syntheticConnection: Types.Events.SyntheticWebSocketConnection|null;\n}\nexport interface WebSocketTraceDataForWorker {\n workerId: string;\n webSocketIdentifier: number;\n events: Types.Events.WebSocketEvent[];\n syntheticConnection: Types.Events.SyntheticWebSocketConnection|null;\n}\nexport type WebSocketTraceData = WebSocketTraceDataForFrame|WebSocketTraceDataForWorker;\n\nconst webSocketData = new Map<number, WebSocketTraceData>();\ninterface NetworkRequestData {\n byId: Map<string, Types.Events.SyntheticNetworkRequest>;\n byOrigin: Map<string, {\n renderBlocking: Types.Events.SyntheticNetworkRequest[],\n nonRenderBlocking: Types.Events.SyntheticNetworkRequest[],\n all: Types.Events.SyntheticNetworkRequest[],\n }>;\n byTime: Types.Events.SyntheticNetworkRequest[];\n eventToInitiator: Map<Types.Events.SyntheticNetworkRequest, Types.Events.SyntheticNetworkRequest>;\n webSocket: WebSocketTraceData[];\n entityMappings: HandlerHelpers.EntityMappings;\n}\n\nconst requestMap = new Map<string, TraceEventsForNetworkRequest>();\nconst requestsById = new Map<string, Types.Events.SyntheticNetworkRequest>();\nconst requestsByOrigin = new Map<string, {\n renderBlocking: Types.Events.SyntheticNetworkRequest[],\n nonRenderBlocking: Types.Events.SyntheticNetworkRequest[],\n all: Types.Events.SyntheticNetworkRequest[],\n}>();\nconst requestsByTime: Types.Events.SyntheticNetworkRequest[] = [];\n\nconst networkRequestEventByInitiatorUrl = new Map<string, Types.Events.SyntheticNetworkRequest[]>();\nconst eventToInitiatorMap = new Map<Types.Events.SyntheticNetworkRequest, Types.Events.SyntheticNetworkRequest>();\n\n/**\n * These are to store ThirdParty data relationships between entities and events. To reduce iterating through data\n * more than we have to, here we start building the caches. After this, the RendererHandler will update\n * the relationships. When handling ThirdParty references, use the one in the RendererHandler instead.\n */\nconst entityMappings: HandlerHelpers.EntityMappings = {\n eventsByEntity: new Map<HandlerHelpers.Entity, Types.Events.Event[]>(),\n entityByEvent: new Map<Types.Events.Event, HandlerHelpers.Entity>(),\n createdEntityCache: new Map<string, HandlerHelpers.Entity>(),\n};\n\nfunction storeTraceEventWithRequestId<K extends keyof TraceEventsForNetworkRequest>(\n requestId: string, key: K, value: TraceEventsForNetworkRequest[K]): void {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, {});\n }\n\n const traceEvents = requestMap.get(requestId);\n if (!traceEvents) {\n throw new Error(`Unable to locate trace events for request ID ${requestId}`);\n }\n\n if (Array.isArray(traceEvents[key])) {\n const target = traceEvents[key] as Types.Events.Event[];\n const values = value as Types.Events.Event[];\n target.push(...values);\n } else {\n traceEvents[key] = value;\n }\n}\n\nfunction firstPositiveValueInList(entries: number[]): number {\n for (const entry of entries) {\n if (entry > 0) {\n return entry;\n }\n }\n\n // In the event we don't find a positive value, we return 0 so as to\n // be a mathematical noop. It's typically not correct to return – say –\n // a -1 here because it would affect the calculation of stats below.\n return 0;\n}\n\nexport function reset(): void {\n requestsById.clear();\n requestsByOrigin.clear();\n requestMap.clear();\n requestsByTime.length = 0;\n networkRequestEventByInitiatorUrl.clear();\n eventToInitiatorMap.clear();\n webSocketData.clear();\n entityMappings.eventsByEntity.clear();\n entityMappings.entityByEvent.clear();\n entityMappings.createdEntityCache.clear();\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (Types.Events.isResourceChangePriority(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'changePriority', event);\n return;\n }\n\n if (Types.Events.isResourceWillSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'willSendRequests', [event]);\n return;\n }\n\n if (Types.Events.isResourceSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'sendRequests', [event]);\n return;\n }\n\n if (Types.Events.isResourceReceiveResponse(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receiveResponse', event);\n return;\n }\n\n if (Types.Events.isResourceReceivedData(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receivedData', [event]);\n return;\n }\n\n if (Types.Events.isResourceFinish(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceFinish', event);\n return;\n }\n\n if (Types.Events.isResourceMarkAsCached(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceMarkAsCached', event);\n return;\n }\n\n if (Types.Events.isWebSocketCreate(event) || Types.Events.isWebSocketInfo(event) ||\n Types.Events.isWebSocketTransfer(event)) {\n const identifier = event.args.data.identifier;\n if (!webSocketData.has(identifier)) {\n if (event.args.data.frame) {\n webSocketData.set(identifier, {\n frame: event.args.data.frame,\n webSocketIdentifier: identifier,\n events: [],\n syntheticConnection: null,\n });\n } else if (event.args.data.workerId) {\n webSocketData.set(identifier, {\n workerId: event.args.data.workerId,\n webSocketIdentifier: identifier,\n events: [],\n syntheticConnection: null,\n });\n }\n }\n\n webSocketData.get(identifier)?.events.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n const {rendererProcessesByFrame} = metaHandlerData();\n for (const [requestId, request] of requestMap.entries()) {\n // If we have an incomplete set of events here, we choose to drop the network\n // request rather than attempt to synthesize the missing data.\n if (!request.sendRequests || !request.receiveResponse) {\n continue;\n }\n\n // In the data we may get multiple willSendRequests and sendRequests, which\n // will indicate that there are redirects for a given (sub)resource. In the\n // case of a navigation, e.g., example.com/ we will get willSendRequests,\n // and we should use these to calculate time spent in redirects.\n // In the case of sub-resources, however, e.g., example.com/foo.js we will\n // *only* get sendRequests, and we use these instead of willSendRequests\n // to detect the time in redirects. We always use the sendRequest for the\n // url, priority etc since it contains those values, but we use the\n // willSendRequest (if it exists) to calculate the timestamp and durations\n // of redirects.\n const redirects: Types.Events.SyntheticNetworkRedirect[] = [];\n for (let i = 0; i < request.sendRequests.length - 1; i++) {\n const sendRequest = request.sendRequests[i];\n const nextSendRequest = request.sendRequests[i + 1];\n\n // Use the willSendRequests as the source for redirects if possible.\n // We default to those of the sendRequests, however, since willSendRequest\n // is not guaranteed to be present in the data for every request.\n let ts = sendRequest.ts;\n let dur = Types.Timing.Micro(nextSendRequest.ts - sendRequest.ts);\n if (request.willSendRequests?.[i] && request.willSendRequests[i + 1]) {\n const willSendRequest = request.willSendRequests[i];\n const nextWillSendRequest = request.willSendRequests[i + 1];\n ts = willSendRequest.ts;\n dur = Types.Timing.Micro(nextWillSendRequest.ts - willSendRequest.ts);\n }\n\n redirects.push({\n url: sendRequest.args.data.url,\n priority: sendRequest.args.data.priority,\n requestMethod: sendRequest.args.data.requestMethod,\n ts,\n dur,\n });\n }\n\n // If a ResourceFinish event with an encoded data length is received,\n // then the resource was not cached; it was fetched before it was\n // requested, e.g. because it was pushed in this navigation.\n const isPushedResource = request.resourceFinish?.args.data.encodedDataLength !== 0;\n // This works around crbug.com/998397, which reports pushed resources, and resources served by a service worker as disk cached.\n const isDiskCached = request.receiveResponse.args.data.fromCache &&\n !request.receiveResponse.args.data.fromServiceWorker && !isPushedResource;\n // If the request contains a resourceMarkAsCached event, it was served from memory cache.\n // The timing data returned is from the original (uncached) request, which\n // means that if we leave the above network record data as-is when the\n // request came from either the disk cache or memory cache, our calculations\n // will be incorrect.\n //\n // So we use this flag so when we calculate the timestamps of the various\n // events, we can overwrite them.\n // These timestamps may not be perfect (indeed they don't always match\n // the Network CDP domain exactly, which is likely an artifact of the way\n // the data is routed on the backend), but they're the closest we have.\n const isMemoryCached = request.resourceMarkAsCached !== undefined;\n // If a request has `resourceMarkAsCached` field, the `timing` field is not correct.\n // So let's discard it and override to 0 (which will be handled in later logic if timing field is undefined).\n const timing = isMemoryCached ? undefined : request.receiveResponse.args.data.timing;\n // If a non-cached request has no |timing| indicates data URLs, we ignore it.\n if (!timing && !isMemoryCached) {\n continue;\n }\n\n const firstSendRequest = request.sendRequests[0];\n const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];\n\n const initialPriority = finalSendRequest.args.data.priority;\n let finalPriority = initialPriority;\n if (request.changePriority) {\n finalPriority = request.changePriority.args.data.priority;\n }\n\n // Network timings are complicated.\n // https://raw.githubusercontent.com/GoogleChrome/lighthouse/main/docs/Network-Timings.svg is generally correct, but.. less so for navigations/redirects/etc.\n\n // Start time\n // =======================\n // The time where the request started, which is either the first willSendRequest\n // event if there is one, or, if there is not, the sendRequest.\n const startTime = (request.willSendRequests?.length) ? Types.Timing.Micro(request.willSendRequests[0].ts) :\n Types.Timing.Micro(firstSendRequest.ts);\n\n // End redirect time\n // =======================\n // It's possible that when we start requesting data we will receive redirections.\n // Here we note the time of the *last* willSendRequest / sendRequest event,\n // which is used later on in the calculations for time queueing etc.\n const endRedirectTime = (request.willSendRequests?.length) ?\n Types.Timing.Micro(request.willSendRequests[request.willSendRequests.length - 1].ts) :\n Types.Timing.Micro(finalSendRequest.ts);\n\n // Finish time and end time\n // =======================\n // The finish time and the end time are subtly different.\n // - Finish time: records the point at which the network stack stopped receiving the data\n // - End time: the timestamp of the finish event itself (if one exists)\n //\n // The end time, then, will be slightly after the finish time.\n const endTime = request.resourceFinish ? request.resourceFinish.ts : endRedirectTime;\n const finishTime = request.resourceFinish?.args.data.finishTime ?\n Types.Timing.Micro(request.resourceFinish.args.data.finishTime * SECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(endTime);\n\n // Network duration\n // =======================\n // Time spent on the network.\n const networkDuration = Types.Timing.Micro(timing ? (finishTime || endRedirectTime) - endRedirectTime : 0);\n\n // Processing duration\n // =======================\n // Time spent from start to end.\n const processingDuration = Types.Timing.Micro(endTime - (finishTime || endTime));\n\n // Redirection duration\n // =======================\n // Time between the first willSendRequest / sendRequest and last. This we place in *front* of the\n // queueing, since the queueing time that we know about from the trace data is only the last request,\n // i.e., the one that occurs after all the redirects.\n const redirectionDuration = Types.Timing.Micro(endRedirectTime - startTime);\n\n // Queueing\n // =======================\n // The amount of time queueing is the time between the request's start time to the requestTime\n // arg recorded in the receiveResponse event. In the cases where the recorded start time is larger\n // that the requestTime we set queueing time to zero.\n const queueingFromTraceData = timing ? timing.requestTime * SECONDS_TO_MICROSECONDS - endRedirectTime : 0;\n const queueing = Types.Timing.Micro(Platform.NumberUtilities.clamp(queueingFromTraceData, 0, Number.MAX_VALUE));\n\n // Stalled\n // =======================\n // If the request is cached, the amount of time stalled is the time between the start time and\n // receiving a response.\n // Otherwise it is whichever positive number comes first from the following timing info:\n // DNS start, Connection start, Send Start, or the time duration between our start time and\n // receiving a response.\n const stalled = timing ? Types.Timing.Micro(firstPositiveValueInList([\n timing.dnsStart * MILLISECONDS_TO_MICROSECONDS,\n timing.connectStart * MILLISECONDS_TO_MICROSECONDS,\n timing.sendStart * MILLISECONDS_TO_MICROSECONDS,\n (request.receiveResponse.ts - endRedirectTime),\n ])) :\n Types.Timing.Micro(request.receiveResponse.ts - startTime);\n\n // Sending HTTP request\n // =======================\n // Time when the HTTP request is sent.\n const sendStartTime = timing ?\n Types.Timing.Micro(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.sendStart * MILLISECONDS_TO_MICROSECONDS) :\n startTime;\n\n // Waiting\n // =======================\n // Time from when the send finished going to when the headers were received.\n const waiting = timing ?\n Types.Timing.Micro((timing.receiveHeadersEnd - timing.sendEnd) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n\n // Download\n // =======================\n // Time from receipt of headers to the finish time.\n const downloadStart = timing ?\n Types.Timing.Micro(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.receiveHeadersEnd * MILLISECONDS_TO_MICROSECONDS) :\n startTime;\n const download = timing ? Types.Timing.Micro(((finishTime || downloadStart) - downloadStart)) :\n Types.Timing.Micro(endTime - request.receiveResponse.ts);\n\n const totalTime = Types.Timing.Micro(networkDuration + processingDuration);\n\n // Collect a few values from the timing info.\n // If the Network request is cached, these fields will be zero, so the minus will zero out them.\n const dnsLookup = timing ? Types.Timing.Micro((timing.dnsEnd - timing.dnsStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const ssl = timing ? Types.Timing.Micro((timing.sslEnd - timing.sslStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const proxyNegotiation = timing ?\n Types.Timing.Micro((timing.proxyEnd - timing.proxyStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const requestSent = timing ?\n Types.Timing.Micro((timing.sendEnd - timing.sendStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const initialConnection = timing ?\n Types.Timing.Micro((timing.connectEnd - timing.connectStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n\n // Finally get some of the general data from the trace events.\n const {frame, url, renderBlocking} = finalSendRequest.args.data;\n const {encodedDataLength, decodedBodyLength} =\n request.resourceFinish ? request.resourceFinish.args.data : {encodedDataLength: 0, decodedBodyLength: 0};\n const parsedUrl = new URL(url);\n const isHttps = parsedUrl.protocol === 'https:';\n const requestingFrameUrl =\n Helpers.Trace.activeURLForFrameAtTime(frame, finalSendRequest.ts, rendererProcessesByFrame) || '';\n // Construct a synthetic trace event for this network request.\n const networkEvent =\n Helpers.SyntheticEvents.SyntheticEventsManager.registerSyntheticEvent<Types.Events.SyntheticNetworkRequest>({\n rawSourceEvent: finalSendRequest,\n args: {\n data: {\n // All data we create from trace events should be added to |syntheticData|.\n syntheticData: {\n dnsLookup,\n download,\n downloadStart,\n finishTime,\n initialConnection,\n isDiskCached,\n isHttps,\n isMemoryCached,\n isPushedResource,\n networkDuration,\n processingDuration,\n proxyNegotiation,\n queueing,\n redirectionDuration,\n requestSent,\n sendStartTime,\n ssl,\n stalled,\n totalTime,\n waiting,\n },\n // All fields below are from TraceEventsForNetworkRequest.\n decodedBodyLength,\n encodedDataLength,\n frame,\n fromServiceWorker: request.receiveResponse.args.data.fromServiceWorker,\n isLinkPreload: finalSendRequest.args.data.isLinkPreload || false,\n mimeType: request.receiveResponse.args.data.mimeType,\n priority: finalPriority,\n initialPriority,\n protocol: request.receiveResponse.args.data.protocol ?? 'unknown',\n redirects,\n // In the event the property isn't set, assume non-blocking.\n renderBlocking: renderBlocking ?? 'non_blocking',\n requestId,\n requestingFrameUrl,\n requestMethod: finalSendRequest.args.data.requestMethod,\n resourceType: finalSendRequest.args.data.resourceType ?? Protocol.Network.ResourceType.Other,\n statusCode: request.receiveResponse.args.data.statusCode,\n responseHeaders: request.receiveResponse.args.data.headers || [],\n fetchPriorityHint: finalSendRequest.args.data.fetchPriorityHint ?? 'auto',\n initiator: finalSendRequest.args.data.initiator,\n stackTrace: finalSendRequest.args.data.stackTrace,\n timing,\n url,\n failed: request.resourceFinish?.args.data.didFail ?? false,\n finished: Boolean(request.resourceFinish),\n connectionId: request.receiveResponse.args.data.connectionId,\n connectionReused: request.receiveResponse.args.data.connectionReused,\n },\n },\n cat: 'loading',\n name: Types.Events.Name.SYNTHETIC_NETWORK_REQUEST,\n ph: Types.Events.Phase.COMPLETE,\n dur: Types.Timing.Micro(endTime - startTime),\n tdur: Types.Timing.Micro(endTime - startTime),\n ts: Types.Timing.Micro(startTime),\n tts: Types.Timing.Micro(startTime),\n pid: finalSendRequest.pid,\n tid: finalSendRequest.tid,\n });\n\n const requests = Platform.MapUtilities.getWithDefault(requestsByOrigin, parsedUrl.host, () => {\n return {\n renderBlocking: [],\n nonRenderBlocking: [],\n all: [],\n };\n });\n\n // For ease of rendering we sometimes want to differentiate between\n // render-blocking and non-render-blocking, so we divide the data here.\n if (!Helpers.Network.isSyntheticNetworkRequestEventRenderBlocking(networkEvent)) {\n requests.nonRenderBlocking.push(networkEvent);\n } else {\n requests.renderBlocking.push(networkEvent);\n }\n\n // However, there are also times where we just want to loop through all\n // the captured requests, so here we store all of them together.\n requests.all.push(networkEvent);\n requestsByTime.push(networkEvent);\n requestsById.set(networkEvent.args.data.requestId, networkEvent);\n\n // Update entity relationships for network events\n HandlerHelpers.addNetworkRequestToEntityMapping(networkEvent, entityMappings, request);\n\n // Establish initiator relationships\n const initiatorUrl = networkEvent.args.data.initiator?.url ||\n Helpers.Trace.getZeroIndexedStackTraceInEventPayload(networkEvent)?.at(0)?.url;\n if (initiatorUrl) {\n const events = networkRequestEventByInitiatorUrl.get(initiatorUrl) ?? [];\n events.push(networkEvent);\n networkRequestEventByInitiatorUrl.set(initiatorUrl, events);\n }\n }\n\n for (const request of requestsByTime) {\n const initiatedEvents = networkRequestEventByInitiatorUrl.get(request.args.data.url);\n\n if (initiatedEvents) {\n for (const initiatedEvent of initiatedEvents) {\n eventToInitiatorMap.set(initiatedEvent, request);\n }\n }\n }\n finalizeWebSocketData();\n}\n\nexport function data(): NetworkRequestData {\n return {\n byId: requestsById,\n byOrigin: requestsByOrigin,\n byTime: requestsByTime,\n eventToInitiator: eventToInitiatorMap,\n webSocket: [...webSocketData.values()],\n entityMappings: {\n entityByEvent: new Map(entityMappings.entityByEvent),\n eventsByEntity: new Map(entityMappings.eventsByEntity),\n createdEntityCache: new Map(entityMappings.createdEntityCache),\n },\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['Meta'];\n}\n\nfunction finalizeWebSocketData(): void {\n // for each WebSocketTraceData in webSocketData map, we create a synthetic event\n // to represent the entire WebSocket connection. This is done by finding the start and end event\n // if they exist, and if they don't, we use the first event in the list for start, and the traceBounds.max\n // for the end. So each WebSocketTraceData will have\n // {\n // events: the list of WebSocket events\n // syntheticConnection: the synthetic event representing the entire WebSocket connection\n // }\n webSocketData.forEach(data => {\n let startEvent: Types.Events.WebSocketEvent|null = null;\n let endEvent: Types.Events.WebSocketDestroy|null = null;\n for (const event of data.events) {\n if (Types.Events.isWebSocketCreate(event)) {\n startEvent = event;\n }\n if (Types.Events.isWebSocketDestroy(event)) {\n endEvent = event;\n }\n }\n data.syntheticConnection = createSyntheticWebSocketConnection(startEvent, endEvent, data.events[0]);\n });\n}\n\nfunction createSyntheticWebSocketConnection(\n startEvent: Types.Events.WebSocketCreate|null, endEvent: Types.Events.WebSocketDestroy|null,\n firstRecordedEvent: Types.Events.WebSocketEvent): Types.Events.SyntheticWebSocketConnection {\n const {traceBounds} = metaHandlerData();\n const startTs = startEvent ? startEvent.ts : traceBounds.min;\n const endTs = endEvent ? endEvent.ts : traceBounds.max;\n const duration = endTs - startTs;\n const mainEvent = startEvent || endEvent || firstRecordedEvent;\n return {\n name: 'SyntheticWebSocketConnection',\n cat: mainEvent.cat,\n ph: Types.Events.Phase.COMPLETE,\n ts: startTs,\n dur: duration as Types.Timing.Micro,\n pid: mainEvent.pid,\n tid: mainEvent.tid,\n s: mainEvent.s,\n rawSourceEvent: mainEvent,\n _tag: 'SyntheticEntryTag',\n args: {\n data: {\n identifier: mainEvent.args.data.identifier,\n priority: Protocol.Network.ResourcePriority.Low,\n url: mainEvent.args.data.url || '',\n },\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"NetworkRequestsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/NetworkRequestsHandler.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,KAAK,cAAc,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAC,IAAI,IAAI,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAGzD,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAC1C,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAkCxC,MAAM,aAAa,GAAG,IAAI,GAAG,EAA8B,CAAC;AAC5D,MAAM,oBAAoB,GAAkC,EAAE,CAAC;AAgB/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwC,CAAC;AACnE,MAAM,YAAY,GAAG,IAAI,GAAG,EAAgD,CAAC;AAC7E,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAI5B,CAAC;AACL,MAAM,cAAc,GAA2C,EAAE,CAAC;AAElE,MAAM,iCAAiC,GAAG,IAAI,GAAG,EAAkD,CAAC;AACpG,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA8E,CAAC;AAElH;;;;GAIG;AACH,MAAM,cAAc,GAAkC;IACpD,cAAc,EAAE,IAAI,GAAG,EAA+C;IACtE,aAAa,EAAE,IAAI,GAAG,EAA6C;IACnE,kBAAkB,EAAE,IAAI,GAAG,EAAiC;CAC7D,CAAC;AAEF,SAAS,4BAA4B,CACjC,SAAiB,EAAE,GAAM,EAAE,KAAsC;IACnE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gDAAgD,SAAS,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAyB,CAAC;QACxD,MAAM,MAAM,GAAG,KAA6B,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,OAA2B;IAC3D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,oEAAoE;IACpE,uEAAuE;IACvE,oEAAoE;IACpE,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,YAAY,CAAC,KAAK,EAAE,CAAC;IACrB,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACzB,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,iCAAiC,CAAC,KAAK,EAAE,CAAC;IAC1C,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAC5B,aAAa,CAAC,KAAK,EAAE,CAAC;IACtB,cAAc,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IACtC,cAAc,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;IACrC,cAAc,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAC1C,oBAAoB,CAAC,MAAM,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,IAAI,KAAK,CAAC,MAAM,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACrF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;QAClF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,EAAE,KAAK,CAAC,CAAC;QACvF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC;QAC5E,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;QAC9C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC1B,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE;oBAC5B,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;oBAC5B,mBAAmB,EAAE,UAAU;oBAC/B,MAAM,EAAE,EAAE;oBACV,mBAAmB,EAAE,IAAI;iBAC1B,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACpC,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE;oBAC5B,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;oBAClC,mBAAmB,EAAE,UAAU;oBAC/B,MAAM,EAAE,EAAE;oBACV,mBAAmB,EAAE,IAAI;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,EAAC,wBAAwB,EAAC,GAAG,eAAe,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACxD,6EAA6E;QAC7E,8DAA8D;QAC9D,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QAED,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,gEAAgE;QAChE,0EAA0E;QAC1E,wEAAwE;QACxE,yEAAyE;QACzE,mEAAmE;QACnE,0EAA0E;QAC1E,gBAAgB;QAChB,MAAM,SAAS,GAA4C,EAAE,CAAC;QAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACzD,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAEpD,oEAAoE;YACpE,0EAA0E;YAC1E,iEAAiE;YACjE,IAAI,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;YACxB,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;YAClE,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrE,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;gBACpD,MAAM,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC5D,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;gBACxB,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;YACxE,CAAC;YAED,SAAS,CAAC,IAAI,CAAC;gBACb,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBAC9B,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;gBACxC,aAAa,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa;gBAClD,EAAE;gBACF,GAAG;aACJ,CAAC,CAAC;QACL,CAAC;QAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE/E,4FAA4F;QAC5F,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACvD,SAAS;QACX,CAAC;QAED,qEAAqE;QACrE,iEAAiE;QACjE,4DAA4D;QAC5D,MAAM,gBAAgB,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,CAAC;QACnF,+HAA+H;QAC/H,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;YACzF,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,gBAAgB,CAAC;QAC9E,yFAAyF;QACzF,0EAA0E;QAC1E,sEAAsE;QACtE,4EAA4E;QAC5E,qBAAqB;QACrB,EAAE;QACF,yEAAyE;QACzE,iCAAiC;QACjC,sEAAsE;QACtE,yEAAyE;QACzE,uEAAuE;QACvE,MAAM,cAAc,GAAG,OAAO,CAAC,oBAAoB,KAAK,SAAS,CAAC;QAClE,oFAAoF;QACpF,6GAA6G;QAC7G,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QACtF,iHAAiH;QACjH,IAAI,OAAO,CAAC,eAAe,IAAI,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAC1D,SAAS;QACX,CAAC;QAED,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC5D,IAAI,aAAa,GAAG,eAAe,CAAC;QACpC,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC3B,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC5D,CAAC;QAED,mCAAmC;QACnC,6JAA6J;QAE7J,aAAa;QACb,0BAA0B;QAC1B,gFAAgF;QAChF,+DAA+D;QAC/D,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAE/F,oBAAoB;QACpB,0BAA0B;QAC1B,iFAAiF;QACjF,2EAA2E;QAC3E,oEAAoE;QACpE,MAAM,eAAe,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;YACxD,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAE5C,2BAA2B;QAC3B,0BAA0B;QAC1B,yDAAyD;QACzD,0FAA0F;QAC1F,wEAAwE;QACxE,EAAE;QACF,8DAA8D;QAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;QACrF,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7D,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,uBAAuB,CAAC,CAAC,CAAC;YAC3F,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEhC,mBAAmB;QACnB,0BAA0B;QAC1B,6BAA6B;QAC7B,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,eAAe,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3G,sBAAsB;QACtB,0BAA0B;QAC1B,gCAAgC;QAChC,MAAM,kBAAkB,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC;QAEjF,uBAAuB;QACvB,0BAA0B;QAC1B,iGAAiG;QACjG,qGAAqG;QACrG,qDAAqD;QACrD,MAAM,mBAAmB,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;QAE5E,WAAW;QACX,0BAA0B;QAC1B,8FAA8F;QAC9F,kGAAkG;QAClG,qDAAqD;QACrD,MAAM,qBAAqB,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,GAAG,uBAAuB,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1G,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAEhH,UAAU;QACV,0BAA0B;QAC1B,8FAA8F;QAC9F,wBAAwB;QACxB,wFAAwF;QACxF,2FAA2F;QAC3F,wBAAwB;QACxB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC;YACpB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC;gBAC1C,MAAM,CAAC,QAAQ,GAAG,4BAA4B;gBAC9C,MAAM,CAAC,YAAY,GAAG,4BAA4B;gBAClD,MAAM,CAAC,SAAS,GAAG,4BAA4B;gBAC/C,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI;aAChF,CAAC,CAAC,CAAC,CAAC;YACL,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnH,uBAAuB;QACvB,0BAA0B;QAC1B,sCAAsC;QACtC,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,KAAK,CACd,MAAM,CAAC,WAAW,GAAG,uBAAuB,GAAG,MAAM,CAAC,SAAS,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACrG,SAAS,CAAC;QAEd,UAAU;QACV,0BAA0B;QAC1B,4EAA4E;QAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC;YACpB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAChG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE1B,WAAW;QACX,0BAA0B;QAC1B,mDAAmD;QACnD,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,KAAK,CACd,MAAM,CAAC,WAAW,GAAG,uBAAuB,GAAG,MAAM,CAAC,iBAAiB,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAC7G,SAAS,CAAC;QACd,MAAM,QAAQ,GAAG,MAAM,CAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,aAAa,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAC/F,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC1D,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEpD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,kBAAkB,CAAC,CAAC;QAE3E,6CAA6C;QAC7C,gGAAgG;QAChG,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACtF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC;YAC7B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAC1F,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YACxF,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC;YAC9B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,4BAA4B,CAAC,CAAC,CAAC;YAC9F,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE1B,8DAA8D;QAC9D,MAAM,EAAC,KAAK,EAAE,GAAG,EAAE,cAAc,EAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAChE,MAAM,EAAC,iBAAiB,EAAE,iBAAiB,EAAC,GACxC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAC,CAAC;QAC7G,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAAC;QAChD,MAAM,kBAAkB,GACpB,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,CAAC,EAAE,EAAE,wBAAwB,CAAC,IAAI,EAAE,CAAC;QACtG,8DAA8D;QAC9D,MAAM,YAAY,GACd,OAAO,CAAC,eAAe,CAAC,sBAAsB,CAAC,sBAAsB,CAAuC;YAC1G,cAAc,EAAE,gBAAgB;YAChC,IAAI,EAAE;gBACJ,IAAI,EAAE;oBACJ,2EAA2E;oBAC3E,aAAa,EAAE;wBACb,SAAS;wBACT,QAAQ;wBACR,aAAa;wBACb,UAAU;wBACV,iBAAiB;wBACjB,YAAY;wBACZ,OAAO;wBACP,cAAc;wBACd,gBAAgB;wBAChB,eAAe;wBACf,kBAAkB;wBAClB,gBAAgB;wBAChB,QAAQ;wBACR,mBAAmB;wBACnB,WAAW;wBACX,aAAa;wBACb,GAAG;wBACH,OAAO;wBACP,SAAS;wBACT,OAAO;qBACR;oBACD,0DAA0D;oBAC1D,iBAAiB;oBACjB,iBAAiB;oBACjB,KAAK;oBACL,iBAAiB,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB;oBACvE,aAAa,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,KAAK;oBAChE,QAAQ,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE;oBAC3D,QAAQ,EAAE,aAAa;oBACvB,eAAe;oBACf,QAAQ,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS;oBAClE,SAAS;oBACT,4DAA4D;oBAC5D,cAAc,EAAE,cAAc,IAAI,cAAc;oBAChD,SAAS;oBACT,kBAAkB;oBAClB,aAAa,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa;oBACvD,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,qDAAuC;oBAC5F,UAAU,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC;oBAC9D,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI;oBACnE,iBAAiB,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,MAAM;oBACzE,SAAS,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS;oBAC/C,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;oBACjD,MAAM;oBACN,GAAG;oBACH,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK;oBAC1D,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;oBACzC,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;oBAC7C,YAAY,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;oBAC7D,gBAAgB,EAAE,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB;iBACtE;aACF;YACD,GAAG,EAAE,SAAS;YACd,IAAI,6EAA6C;YACjD,EAAE,uCAA6B;YAC/B,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC5C,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC7C,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;YACjC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;YAClC,GAAG,EAAE,gBAAgB,CAAC,GAAG;YACzB,GAAG,EAAE,gBAAgB,CAAC,GAAG;SAC1B,CAAC,CAAC;QAEP,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,gBAAgB,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE;YAC3F,OAAO;gBACL,cAAc,EAAE,EAAE;gBAClB,iBAAiB,EAAE,EAAE;gBACrB,GAAG,EAAE,EAAE;aACR,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,mEAAmE;QACnE,uEAAuE;QACvE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,4CAA4C,CAAC,YAAY,CAAC,EAAE,CAAC;YAChF,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;QAED,uEAAuE;QACvE,gEAAgE;QAChE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAEjE,iDAAiD;QACjD,cAAc,CAAC,gCAAgC,CAAC,YAAY,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAEvF,oCAAoC;QACpC,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG;YACtD,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QACnF,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,iCAAiC,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YACzE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1B,iCAAiC,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,MAAM,eAAe,GAAG,iCAAiC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAErF,IAAI,eAAe,EAAE,CAAC;YACpB,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;gBAC7C,mBAAmB,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IACD,qBAAqB,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,gBAAgB;QAC1B,MAAM,EAAE,cAAc;QACtB,gBAAgB,EAAE,mBAAmB;QACrC,SAAS,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;QACtC,cAAc,EAAE;YACd,aAAa,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,aAAa,CAAC;YACpD,cAAc,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC;YACtD,kBAAkB,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,kBAAkB,CAAC;SAC/D;QACD,oBAAoB;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,qBAAqB;IAC5B,gFAAgF;IAChF,gGAAgG;IAChG,0GAA0G;IAC1G,oDAAoD;IACpD,IAAI;IACJ,2CAA2C;IAC3C,4FAA4F;IAC5F,IAAI;IACJ,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC3B,IAAI,UAAU,GAAqC,IAAI,CAAC;QACxD,IAAI,QAAQ,GAAuC,IAAI,CAAC;QACxD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1C,UAAU,GAAG,KAAK,CAAC;YACrB,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3C,QAAQ,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,mBAAmB,GAAG,kCAAkC,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kCAAkC,CACvC,UAA6C,EAAE,QAA4C,EAC3F,kBAA+C;IACjD,MAAM,EAAC,WAAW,EAAC,GAAG,eAAe,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC;IAC7D,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC;IACvD,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;IACjC,MAAM,SAAS,GAAG,UAAU,IAAI,QAAQ,IAAI,kBAAkB,CAAC;IAC/D,OAAO;QACL,IAAI,EAAE,8BAA8B;QACpC,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,EAAE,uCAA6B;QAC/B,EAAE,EAAE,OAAO;QACX,GAAG,EAAE,QAA8B;QACnC,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,cAAc,EAAE,SAAS;QACzB,IAAI,EAAE,mBAAmB;QACzB,IAAI,EAAE;YACJ,IAAI,EAAE;gBACJ,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU;gBAC1C,QAAQ,mDAAuC;gBAC/C,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE;aACnC;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Protocol from '../../../generated/protocol.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport * as HandlerHelpers from './helpers.js';\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport type {HandlerName} from './types.js';\n\nconst MILLISECONDS_TO_MICROSECONDS = 1000;\nconst SECONDS_TO_MICROSECONDS = 1000000;\n\n// Network requests from traces are actually formed of 5 trace records.\n// This handler tracks all trace records based on the request ID, and\n// then creates a new synthetic trace event for those network requests.\n//\n// This interface, then, defines the shape of the object we intend to\n// keep for each request in the trace. In the finalize we will convert\n// these 5 types of trace records to a synthetic complete event that\n// represents a composite of these trace records.\nexport interface TraceEventsForNetworkRequest {\n changePriority?: Types.Events.ResourceChangePriority;\n willSendRequests?: Types.Events.ResourceWillSendRequest[];\n sendRequests?: Types.Events.ResourceSendRequest[];\n receiveResponse?: Types.Events.ResourceReceiveResponse;\n resourceFinish?: Types.Events.ResourceFinish;\n receivedData?: Types.Events.ResourceReceivedData[];\n resourceMarkAsCached?: Types.Events.ResourceMarkAsCached;\n}\n\nexport interface WebSocketTraceDataForFrame {\n frame: string;\n webSocketIdentifier: number;\n events: Types.Events.WebSocketEvent[];\n syntheticConnection: Types.Events.SyntheticWebSocketConnection|null;\n}\nexport interface WebSocketTraceDataForWorker {\n workerId: string;\n webSocketIdentifier: number;\n events: Types.Events.WebSocketEvent[];\n syntheticConnection: Types.Events.SyntheticWebSocketConnection|null;\n}\nexport type WebSocketTraceData = WebSocketTraceDataForFrame|WebSocketTraceDataForWorker;\n\nconst webSocketData = new Map<number, WebSocketTraceData>();\nconst linkPreconnectEvents: Types.Events.LinkPreconnect[] = [];\n\ninterface NetworkRequestData {\n byId: Map<string, Types.Events.SyntheticNetworkRequest>;\n byOrigin: Map<string, {\n renderBlocking: Types.Events.SyntheticNetworkRequest[],\n nonRenderBlocking: Types.Events.SyntheticNetworkRequest[],\n all: Types.Events.SyntheticNetworkRequest[],\n }>;\n byTime: Types.Events.SyntheticNetworkRequest[];\n eventToInitiator: Map<Types.Events.SyntheticNetworkRequest, Types.Events.SyntheticNetworkRequest>;\n webSocket: WebSocketTraceData[];\n entityMappings: HandlerHelpers.EntityMappings;\n linkPreconnectEvents: Types.Events.LinkPreconnect[];\n}\n\nconst requestMap = new Map<string, TraceEventsForNetworkRequest>();\nconst requestsById = new Map<string, Types.Events.SyntheticNetworkRequest>();\nconst requestsByOrigin = new Map<string, {\n renderBlocking: Types.Events.SyntheticNetworkRequest[],\n nonRenderBlocking: Types.Events.SyntheticNetworkRequest[],\n all: Types.Events.SyntheticNetworkRequest[],\n}>();\nconst requestsByTime: Types.Events.SyntheticNetworkRequest[] = [];\n\nconst networkRequestEventByInitiatorUrl = new Map<string, Types.Events.SyntheticNetworkRequest[]>();\nconst eventToInitiatorMap = new Map<Types.Events.SyntheticNetworkRequest, Types.Events.SyntheticNetworkRequest>();\n\n/**\n * These are to store ThirdParty data relationships between entities and events. To reduce iterating through data\n * more than we have to, here we start building the caches. After this, the RendererHandler will update\n * the relationships. When handling ThirdParty references, use the one in the RendererHandler instead.\n */\nconst entityMappings: HandlerHelpers.EntityMappings = {\n eventsByEntity: new Map<HandlerHelpers.Entity, Types.Events.Event[]>(),\n entityByEvent: new Map<Types.Events.Event, HandlerHelpers.Entity>(),\n createdEntityCache: new Map<string, HandlerHelpers.Entity>(),\n};\n\nfunction storeTraceEventWithRequestId<K extends keyof TraceEventsForNetworkRequest>(\n requestId: string, key: K, value: TraceEventsForNetworkRequest[K]): void {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, {});\n }\n\n const traceEvents = requestMap.get(requestId);\n if (!traceEvents) {\n throw new Error(`Unable to locate trace events for request ID ${requestId}`);\n }\n\n if (Array.isArray(traceEvents[key])) {\n const target = traceEvents[key] as Types.Events.Event[];\n const values = value as Types.Events.Event[];\n target.push(...values);\n } else {\n traceEvents[key] = value;\n }\n}\n\nfunction firstPositiveValueInList(entries: Array<number|null>): number {\n for (const entry of entries) {\n if (entry && entry > 0) {\n return entry;\n }\n }\n\n // In the event we don't find a positive value, we return 0 so as to\n // be a mathematical noop. It's typically not correct to return – say –\n // a -1 here because it would affect the calculation of stats below.\n return 0;\n}\n\nexport function reset(): void {\n requestsById.clear();\n requestsByOrigin.clear();\n requestMap.clear();\n requestsByTime.length = 0;\n networkRequestEventByInitiatorUrl.clear();\n eventToInitiatorMap.clear();\n webSocketData.clear();\n entityMappings.eventsByEntity.clear();\n entityMappings.entityByEvent.clear();\n entityMappings.createdEntityCache.clear();\n linkPreconnectEvents.length = 0;\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (Types.Events.isResourceChangePriority(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'changePriority', event);\n return;\n }\n\n if (Types.Events.isResourceWillSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'willSendRequests', [event]);\n return;\n }\n\n if (Types.Events.isResourceSendRequest(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'sendRequests', [event]);\n return;\n }\n\n if (Types.Events.isResourceReceiveResponse(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receiveResponse', event);\n return;\n }\n\n if (Types.Events.isResourceReceivedData(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'receivedData', [event]);\n return;\n }\n\n if (Types.Events.isResourceFinish(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceFinish', event);\n return;\n }\n\n if (Types.Events.isResourceMarkAsCached(event)) {\n storeTraceEventWithRequestId(event.args.data.requestId, 'resourceMarkAsCached', event);\n return;\n }\n\n if (Types.Events.isWebSocketCreate(event) || Types.Events.isWebSocketInfo(event) ||\n Types.Events.isWebSocketTransfer(event)) {\n const identifier = event.args.data.identifier;\n if (!webSocketData.has(identifier)) {\n if (event.args.data.frame) {\n webSocketData.set(identifier, {\n frame: event.args.data.frame,\n webSocketIdentifier: identifier,\n events: [],\n syntheticConnection: null,\n });\n } else if (event.args.data.workerId) {\n webSocketData.set(identifier, {\n workerId: event.args.data.workerId,\n webSocketIdentifier: identifier,\n events: [],\n syntheticConnection: null,\n });\n }\n }\n\n webSocketData.get(identifier)?.events.push(event);\n }\n\n if (Types.Events.isLinkPreconnect(event)) {\n linkPreconnectEvents.push(event);\n return;\n }\n}\n\nexport async function finalize(): Promise<void> {\n const {rendererProcessesByFrame} = metaHandlerData();\n for (const [requestId, request] of requestMap.entries()) {\n // If we have an incomplete set of events here, we choose to drop the network\n // request rather than attempt to synthesize the missing data.\n if (!request.sendRequests) {\n continue;\n }\n\n // In the data we may get multiple willSendRequests and sendRequests, which\n // will indicate that there are redirects for a given (sub)resource. In the\n // case of a navigation, e.g., example.com/ we will get willSendRequests,\n // and we should use these to calculate time spent in redirects.\n // In the case of sub-resources, however, e.g., example.com/foo.js we will\n // *only* get sendRequests, and we use these instead of willSendRequests\n // to detect the time in redirects. We always use the sendRequest for the\n // url, priority etc since it contains those values, but we use the\n // willSendRequest (if it exists) to calculate the timestamp and durations\n // of redirects.\n const redirects: Types.Events.SyntheticNetworkRedirect[] = [];\n for (let i = 0; i < request.sendRequests.length - 1; i++) {\n const sendRequest = request.sendRequests[i];\n const nextSendRequest = request.sendRequests[i + 1];\n\n // Use the willSendRequests as the source for redirects if possible.\n // We default to those of the sendRequests, however, since willSendRequest\n // is not guaranteed to be present in the data for every request.\n let ts = sendRequest.ts;\n let dur = Types.Timing.Micro(nextSendRequest.ts - sendRequest.ts);\n if (request.willSendRequests?.[i] && request.willSendRequests[i + 1]) {\n const willSendRequest = request.willSendRequests[i];\n const nextWillSendRequest = request.willSendRequests[i + 1];\n ts = willSendRequest.ts;\n dur = Types.Timing.Micro(nextWillSendRequest.ts - willSendRequest.ts);\n }\n\n redirects.push({\n url: sendRequest.args.data.url,\n priority: sendRequest.args.data.priority,\n requestMethod: sendRequest.args.data.requestMethod,\n ts,\n dur,\n });\n }\n\n const firstSendRequest = request.sendRequests[0];\n const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];\n\n // We currently do not want to include data URI requests. We may revisit this in the future.\n if (finalSendRequest.args.data.url.startsWith('data:')) {\n continue;\n }\n\n // If a ResourceFinish event with an encoded data length is received,\n // then the resource was not cached; it was fetched before it was\n // requested, e.g. because it was pushed in this navigation.\n const isPushedResource = request.resourceFinish?.args.data.encodedDataLength !== 0;\n // This works around crbug.com/998397, which reports pushed resources, and resources served by a service worker as disk cached.\n const isDiskCached = !!request.receiveResponse && request.receiveResponse.args.data.fromCache &&\n !request.receiveResponse.args.data.fromServiceWorker && !isPushedResource;\n // If the request contains a resourceMarkAsCached event, it was served from memory cache.\n // The timing data returned is from the original (uncached) request, which\n // means that if we leave the above network record data as-is when the\n // request came from either the disk cache or memory cache, our calculations\n // will be incorrect.\n //\n // So we use this flag so when we calculate the timestamps of the various\n // events, we can overwrite them.\n // These timestamps may not be perfect (indeed they don't always match\n // the Network CDP domain exactly, which is likely an artifact of the way\n // the data is routed on the backend), but they're the closest we have.\n const isMemoryCached = request.resourceMarkAsCached !== undefined;\n // If a request has `resourceMarkAsCached` field, the `timing` field is not correct.\n // So let's discard it and override to 0 (which will be handled in later logic if timing field is undefined).\n const timing = isMemoryCached ? undefined : request.receiveResponse?.args.data.timing;\n // If a non-cached response has no |timing|, we ignore it. An example of this is chrome://new-page / about:blank.\n if (request.receiveResponse && !timing && !isMemoryCached) {\n continue;\n }\n\n const initialPriority = finalSendRequest.args.data.priority;\n let finalPriority = initialPriority;\n if (request.changePriority) {\n finalPriority = request.changePriority.args.data.priority;\n }\n\n // Network timings are complicated.\n // https://raw.githubusercontent.com/GoogleChrome/lighthouse/main/docs/Network-Timings.svg is generally correct, but.. less so for navigations/redirects/etc.\n\n // Start time\n // =======================\n // The time where the request started, which is either the first willSendRequest\n // event if there is one, or, if there is not, the sendRequest.\n const startTime = (request.willSendRequests?.length) ? Types.Timing.Micro(request.willSendRequests[0].ts) :\n Types.Timing.Micro(firstSendRequest.ts);\n\n // End redirect time\n // =======================\n // It's possible that when we start requesting data we will receive redirections.\n // Here we note the time of the *last* willSendRequest / sendRequest event,\n // which is used later on in the calculations for time queueing etc.\n const endRedirectTime = (request.willSendRequests?.length) ?\n Types.Timing.Micro(request.willSendRequests[request.willSendRequests.length - 1].ts) :\n Types.Timing.Micro(finalSendRequest.ts);\n\n // Finish time and end time\n // =======================\n // The finish time and the end time are subtly different.\n // - Finish time: records the point at which the network stack stopped receiving the data\n // - End time: the timestamp of the finish event itself (if one exists)\n //\n // The end time, then, will be slightly after the finish time.\n const endTime = request.resourceFinish ? request.resourceFinish.ts : endRedirectTime;\n const finishTime = request.resourceFinish?.args.data.finishTime ?\n Types.Timing.Micro(request.resourceFinish.args.data.finishTime * SECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(endTime);\n\n // Network duration\n // =======================\n // Time spent on the network.\n const networkDuration = Types.Timing.Micro(timing ? (finishTime || endRedirectTime) - endRedirectTime : 0);\n\n // Processing duration\n // =======================\n // Time spent from start to end.\n const processingDuration = Types.Timing.Micro(endTime - (finishTime || endTime));\n\n // Redirection duration\n // =======================\n // Time between the first willSendRequest / sendRequest and last. This we place in *front* of the\n // queueing, since the queueing time that we know about from the trace data is only the last request,\n // i.e., the one that occurs after all the redirects.\n const redirectionDuration = Types.Timing.Micro(endRedirectTime - startTime);\n\n // Queueing\n // =======================\n // The amount of time queueing is the time between the request's start time to the requestTime\n // arg recorded in the receiveResponse event. In the cases where the recorded start time is larger\n // that the requestTime we set queueing time to zero.\n const queueingFromTraceData = timing ? timing.requestTime * SECONDS_TO_MICROSECONDS - endRedirectTime : 0;\n const queueing = Types.Timing.Micro(Platform.NumberUtilities.clamp(queueingFromTraceData, 0, Number.MAX_VALUE));\n\n // Stalled\n // =======================\n // If the request is cached, the amount of time stalled is the time between the start time and\n // receiving a response.\n // Otherwise it is whichever positive number comes first from the following timing info:\n // DNS start, Connection start, Send Start, or the time duration between our start time and\n // receiving a response.\n const stalled = timing ?\n Types.Timing.Micro(firstPositiveValueInList([\n timing.dnsStart * MILLISECONDS_TO_MICROSECONDS,\n timing.connectStart * MILLISECONDS_TO_MICROSECONDS,\n timing.sendStart * MILLISECONDS_TO_MICROSECONDS,\n request.receiveResponse ? (request.receiveResponse.ts - endRedirectTime) : null,\n ])) :\n (request.receiveResponse ? Types.Timing.Micro(request.receiveResponse.ts - startTime) : Types.Timing.Micro(0));\n\n // Sending HTTP request\n // =======================\n // Time when the HTTP request is sent.\n const sendStartTime = timing ?\n Types.Timing.Micro(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.sendStart * MILLISECONDS_TO_MICROSECONDS) :\n startTime;\n\n // Waiting\n // =======================\n // Time from when the send finished going to when the headers were received.\n const waiting = timing ?\n Types.Timing.Micro((timing.receiveHeadersEnd - timing.sendEnd) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n\n // Download\n // =======================\n // Time from receipt of headers to the finish time.\n const downloadStart = timing ?\n Types.Timing.Micro(\n timing.requestTime * SECONDS_TO_MICROSECONDS + timing.receiveHeadersEnd * MILLISECONDS_TO_MICROSECONDS) :\n startTime;\n const download = timing ? Types.Timing.Micro(((finishTime || downloadStart) - downloadStart)) :\n request.receiveResponse ? Types.Timing.Micro(endTime - request.receiveResponse.ts) :\n Types.Timing.Micro(0);\n\n const totalTime = Types.Timing.Micro(networkDuration + processingDuration);\n\n // Collect a few values from the timing info.\n // If the Network request is cached, these fields will be zero, so the minus will zero out them.\n const dnsLookup = timing ? Types.Timing.Micro((timing.dnsEnd - timing.dnsStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const ssl = timing ? Types.Timing.Micro((timing.sslEnd - timing.sslStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const proxyNegotiation = timing ?\n Types.Timing.Micro((timing.proxyEnd - timing.proxyStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const requestSent = timing ?\n Types.Timing.Micro((timing.sendEnd - timing.sendStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n const initialConnection = timing ?\n Types.Timing.Micro((timing.connectEnd - timing.connectStart) * MILLISECONDS_TO_MICROSECONDS) :\n Types.Timing.Micro(0);\n\n // Finally get some of the general data from the trace events.\n const {frame, url, renderBlocking} = finalSendRequest.args.data;\n const {encodedDataLength, decodedBodyLength} =\n request.resourceFinish ? request.resourceFinish.args.data : {encodedDataLength: 0, decodedBodyLength: 0};\n const parsedUrl = new URL(url);\n const isHttps = parsedUrl.protocol === 'https:';\n const requestingFrameUrl =\n Helpers.Trace.activeURLForFrameAtTime(frame, finalSendRequest.ts, rendererProcessesByFrame) || '';\n // Construct a synthetic trace event for this network request.\n const networkEvent =\n Helpers.SyntheticEvents.SyntheticEventsManager.registerSyntheticEvent<Types.Events.SyntheticNetworkRequest>({\n rawSourceEvent: finalSendRequest,\n args: {\n data: {\n // All data we create from trace events should be added to |syntheticData|.\n syntheticData: {\n dnsLookup,\n download,\n downloadStart,\n finishTime,\n initialConnection,\n isDiskCached,\n isHttps,\n isMemoryCached,\n isPushedResource,\n networkDuration,\n processingDuration,\n proxyNegotiation,\n queueing,\n redirectionDuration,\n requestSent,\n sendStartTime,\n ssl,\n stalled,\n totalTime,\n waiting,\n },\n // All fields below are from TraceEventsForNetworkRequest.\n decodedBodyLength,\n encodedDataLength,\n frame,\n fromServiceWorker: request.receiveResponse?.args.data.fromServiceWorker,\n isLinkPreload: finalSendRequest.args.data.isLinkPreload || false,\n mimeType: request.receiveResponse?.args.data.mimeType ?? '',\n priority: finalPriority,\n initialPriority,\n protocol: request.receiveResponse?.args.data.protocol ?? 'unknown',\n redirects,\n // In the event the property isn't set, assume non-blocking.\n renderBlocking: renderBlocking ?? 'non_blocking',\n requestId,\n requestingFrameUrl,\n requestMethod: finalSendRequest.args.data.requestMethod,\n resourceType: finalSendRequest.args.data.resourceType ?? Protocol.Network.ResourceType.Other,\n statusCode: request.receiveResponse?.args.data.statusCode ?? 0,\n responseHeaders: request.receiveResponse?.args.data.headers ?? null,\n fetchPriorityHint: finalSendRequest.args.data.fetchPriorityHint ?? 'auto',\n initiator: finalSendRequest.args.data.initiator,\n stackTrace: finalSendRequest.args.data.stackTrace,\n timing,\n url,\n failed: request.resourceFinish?.args.data.didFail ?? false,\n finished: Boolean(request.resourceFinish),\n hasResponse: Boolean(request.receiveResponse),\n connectionId: request.receiveResponse?.args.data.connectionId,\n connectionReused: request.receiveResponse?.args.data.connectionReused,\n },\n },\n cat: 'loading',\n name: Types.Events.Name.SYNTHETIC_NETWORK_REQUEST,\n ph: Types.Events.Phase.COMPLETE,\n dur: Types.Timing.Micro(endTime - startTime),\n tdur: Types.Timing.Micro(endTime - startTime),\n ts: Types.Timing.Micro(startTime),\n tts: Types.Timing.Micro(startTime),\n pid: finalSendRequest.pid,\n tid: finalSendRequest.tid,\n });\n\n const requests = Platform.MapUtilities.getWithDefault(requestsByOrigin, parsedUrl.host, () => {\n return {\n renderBlocking: [],\n nonRenderBlocking: [],\n all: [],\n };\n });\n\n // For ease of rendering we sometimes want to differentiate between\n // render-blocking and non-render-blocking, so we divide the data here.\n if (!Helpers.Network.isSyntheticNetworkRequestEventRenderBlocking(networkEvent)) {\n requests.nonRenderBlocking.push(networkEvent);\n } else {\n requests.renderBlocking.push(networkEvent);\n }\n\n // However, there are also times where we just want to loop through all\n // the captured requests, so here we store all of them together.\n requests.all.push(networkEvent);\n requestsByTime.push(networkEvent);\n requestsById.set(networkEvent.args.data.requestId, networkEvent);\n\n // Update entity relationships for network events\n HandlerHelpers.addNetworkRequestToEntityMapping(networkEvent, entityMappings, request);\n\n // Establish initiator relationships\n const initiatorUrl = networkEvent.args.data.initiator?.url ||\n Helpers.Trace.getZeroIndexedStackTraceInEventPayload(networkEvent)?.at(0)?.url;\n if (initiatorUrl) {\n const events = networkRequestEventByInitiatorUrl.get(initiatorUrl) ?? [];\n events.push(networkEvent);\n networkRequestEventByInitiatorUrl.set(initiatorUrl, events);\n }\n }\n\n for (const request of requestsByTime) {\n const initiatedEvents = networkRequestEventByInitiatorUrl.get(request.args.data.url);\n\n if (initiatedEvents) {\n for (const initiatedEvent of initiatedEvents) {\n eventToInitiatorMap.set(initiatedEvent, request);\n }\n }\n }\n finalizeWebSocketData();\n}\n\nexport function data(): NetworkRequestData {\n return {\n byId: requestsById,\n byOrigin: requestsByOrigin,\n byTime: requestsByTime,\n eventToInitiator: eventToInitiatorMap,\n webSocket: [...webSocketData.values()],\n entityMappings: {\n entityByEvent: new Map(entityMappings.entityByEvent),\n eventsByEntity: new Map(entityMappings.eventsByEntity),\n createdEntityCache: new Map(entityMappings.createdEntityCache),\n },\n linkPreconnectEvents,\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['Meta'];\n}\n\nfunction finalizeWebSocketData(): void {\n // for each WebSocketTraceData in webSocketData map, we create a synthetic event\n // to represent the entire WebSocket connection. This is done by finding the start and end event\n // if they exist, and if they don't, we use the first event in the list for start, and the traceBounds.max\n // for the end. So each WebSocketTraceData will have\n // {\n // events: the list of WebSocket events\n // syntheticConnection: the synthetic event representing the entire WebSocket connection\n // }\n webSocketData.forEach(data => {\n let startEvent: Types.Events.WebSocketEvent|null = null;\n let endEvent: Types.Events.WebSocketDestroy|null = null;\n for (const event of data.events) {\n if (Types.Events.isWebSocketCreate(event)) {\n startEvent = event;\n }\n if (Types.Events.isWebSocketDestroy(event)) {\n endEvent = event;\n }\n }\n data.syntheticConnection = createSyntheticWebSocketConnection(startEvent, endEvent, data.events[0]);\n });\n}\n\nfunction createSyntheticWebSocketConnection(\n startEvent: Types.Events.WebSocketCreate|null, endEvent: Types.Events.WebSocketDestroy|null,\n firstRecordedEvent: Types.Events.WebSocketEvent): Types.Events.SyntheticWebSocketConnection {\n const {traceBounds} = metaHandlerData();\n const startTs = startEvent ? startEvent.ts : traceBounds.min;\n const endTs = endEvent ? endEvent.ts : traceBounds.max;\n const duration = endTs - startTs;\n const mainEvent = startEvent || endEvent || firstRecordedEvent;\n return {\n name: 'SyntheticWebSocketConnection',\n cat: mainEvent.cat,\n ph: Types.Events.Phase.COMPLETE,\n ts: startTs,\n dur: duration as Types.Timing.Micro,\n pid: mainEvent.pid,\n tid: mainEvent.tid,\n s: mainEvent.s,\n rawSourceEvent: mainEvent,\n _tag: 'SyntheticEntryTag',\n args: {\n data: {\n identifier: mainEvent.args.data.identifier,\n priority: Protocol.Network.ResourcePriority.Low,\n url: mainEvent.args.data.url || '',\n },\n },\n };\n}\n"]}
|
|
@@ -15,8 +15,12 @@ export interface Script {
|
|
|
15
15
|
url?: string;
|
|
16
16
|
sourceUrl?: string;
|
|
17
17
|
content?: string;
|
|
18
|
-
/** Note: this is the literal text given as the sourceMappingURL value. It has not been resolved relative to the script url.
|
|
18
|
+
/** Note: this is the literal text given as the sourceMappingURL value. It has not been resolved relative to the script url.
|
|
19
|
+
* Since M138, data urls are never set here.
|
|
20
|
+
*/
|
|
19
21
|
sourceMapUrl?: string;
|
|
22
|
+
/** If true, the source map url was a data URL, so it got removed from the trace event. */
|
|
23
|
+
sourceMapUrlElided?: boolean;
|
|
20
24
|
sourceMap?: any;
|
|
21
25
|
request?: Types.Events.SyntheticNetworkRequest;
|
|
22
26
|
/** Lazily generated - use getScriptGeneratedSizes to access. */
|
|
@@ -36,16 +36,23 @@ export function handleEvent(event) {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
if (Types.Events.isV8SourceRundownEvent(event)) {
|
|
39
|
-
const { isolate, scriptId, url, sourceUrl, sourceMapUrl,
|
|
39
|
+
const { isolate, scriptId, url, sourceUrl, sourceMapUrl, sourceMapUrlElided } = event.args.data;
|
|
40
40
|
const script = getOrMakeScript(isolate, scriptId);
|
|
41
41
|
script.url = url;
|
|
42
42
|
if (sourceUrl) {
|
|
43
43
|
script.sourceUrl = sourceUrl;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
// Older traces may have data source map urls. Those can be very large, so a change
|
|
46
|
+
// was made to elide them from the trace.
|
|
47
|
+
// If elided, a fresh trace will fetch the source map from the Script model
|
|
48
|
+
// (see TimelinePanel getExistingSourceMap). If not fresh, the source map is resolved
|
|
49
|
+
// instead in this handler via `findCachedRawSourceMap`.
|
|
50
|
+
if (sourceMapUrlElided) {
|
|
51
|
+
script.sourceMapUrlElided = true;
|
|
52
|
+
}
|
|
53
|
+
else if (sourceMapUrl) {
|
|
46
54
|
script.sourceMapUrl = sourceMapUrl;
|
|
47
55
|
}
|
|
48
|
-
script.inline = Boolean(startLine || startColumn);
|
|
49
56
|
return;
|
|
50
57
|
}
|
|
51
58
|
if (Types.Events.isV8SourceRundownSourcesScriptCatchupEvent(event)) {
|
|
@@ -148,15 +155,31 @@ export function getScriptGeneratedSizes(script) {
|
|
|
148
155
|
}
|
|
149
156
|
return script.sizes ?? null;
|
|
150
157
|
}
|
|
151
|
-
function findCachedRawSourceMap(
|
|
152
|
-
if (!
|
|
158
|
+
function findCachedRawSourceMap(script, options) {
|
|
159
|
+
if (options.isFreshRecording || !options.metadata?.sourceMaps) {
|
|
160
|
+
// Exit if this is not a loaded trace w/ source maps in the metadata.
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// For elided data url source maps, search the metadata source maps by script url.
|
|
164
|
+
if (script.sourceMapUrlElided) {
|
|
165
|
+
if (!script.url) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const cachedSourceMap = options.metadata.sourceMaps.find(m => m.url === script.url);
|
|
169
|
+
if (cachedSourceMap) {
|
|
170
|
+
return cachedSourceMap.sourceMap;
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (!script.sourceMapUrl) {
|
|
153
175
|
return;
|
|
154
176
|
}
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
177
|
+
// Otherwise, search by source map url.
|
|
178
|
+
// Note: early enhanced traces may have this field set for data urls. Ignore those,
|
|
179
|
+
// as they were never stored in metadata sourcemap.
|
|
180
|
+
const isDataUrl = script.sourceMapUrl.startsWith('data:');
|
|
181
|
+
if (!isDataUrl) {
|
|
182
|
+
const cachedSourceMap = options.metadata.sourceMaps.find(m => m.sourceMapUrl === script.sourceMapUrl);
|
|
160
183
|
if (cachedSourceMap) {
|
|
161
184
|
return cachedSourceMap.sourceMap;
|
|
162
185
|
}
|
|
@@ -164,20 +187,27 @@ function findCachedRawSourceMap(sourceMapUrl, options) {
|
|
|
164
187
|
return;
|
|
165
188
|
}
|
|
166
189
|
export async function finalize(options) {
|
|
190
|
+
const meta = metaHandlerData();
|
|
167
191
|
const networkRequests = [...networkRequestsHandlerData().byId.values()];
|
|
192
|
+
const documentUrls = new Set();
|
|
193
|
+
for (const frames of meta.frameByProcessId.values()) {
|
|
194
|
+
for (const frame of frames.values()) {
|
|
195
|
+
documentUrls.add(frame.url);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
168
198
|
for (const script of scriptById.values()) {
|
|
169
199
|
script.request = findNetworkRequest(networkRequests, script) ?? undefined;
|
|
200
|
+
script.inline = !!script.url && documentUrls.has(script.url);
|
|
170
201
|
}
|
|
171
202
|
if (!options.resolveSourceMap) {
|
|
172
203
|
return;
|
|
173
204
|
}
|
|
174
|
-
const meta = metaHandlerData();
|
|
175
205
|
const promises = [];
|
|
176
206
|
for (const script of scriptById.values()) {
|
|
177
207
|
// No frame or url means the script came from somewhere we don't care about.
|
|
178
208
|
// Note: scripts from inline <SCRIPT> elements use the url of the HTML document,
|
|
179
209
|
// so aren't ignored.
|
|
180
|
-
if (!script.frame || !script.url || !script.sourceMapUrl) {
|
|
210
|
+
if (!script.frame || !script.url || (!script.sourceMapUrl && !script.sourceMapUrlElided)) {
|
|
181
211
|
continue;
|
|
182
212
|
}
|
|
183
213
|
const frameUrl = findFrame(meta, script.frame)?.url;
|
|
@@ -190,26 +220,33 @@ export async function finalize(options) {
|
|
|
190
220
|
if (script.sourceUrl) {
|
|
191
221
|
sourceUrl = completeURL(frameUrl, script.sourceUrl) ?? script.sourceUrl;
|
|
192
222
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
223
|
+
let sourceMapUrl;
|
|
224
|
+
if (script.sourceMapUrl) {
|
|
225
|
+
// Resolve the source map url. The value given by v8 may be relative, so resolve it here.
|
|
226
|
+
// This process should match the one in `SourceMapManager.attachSourceMap`.
|
|
227
|
+
sourceMapUrl =
|
|
228
|
+
completeURL(sourceUrl, script.sourceMapUrl);
|
|
229
|
+
if (!sourceMapUrl) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
script.sourceMapUrl = sourceMapUrl;
|
|
198
233
|
}
|
|
199
|
-
script.sourceMapUrl = sourceMapUrl;
|
|
200
234
|
const params = {
|
|
201
235
|
scriptId: script.scriptId,
|
|
202
|
-
scriptUrl:
|
|
203
|
-
|
|
236
|
+
scriptUrl: script.url,
|
|
237
|
+
sourceUrl: sourceUrl,
|
|
238
|
+
sourceMapUrl: sourceMapUrl ?? '',
|
|
204
239
|
frame: script.frame,
|
|
205
|
-
cachedRawSourceMap: findCachedRawSourceMap(
|
|
240
|
+
cachedRawSourceMap: findCachedRawSourceMap(script, options),
|
|
206
241
|
};
|
|
207
242
|
const promise = options.resolveSourceMap(params).then(sourceMap => {
|
|
208
243
|
if (sourceMap) {
|
|
209
244
|
script.sourceMap = sourceMap;
|
|
210
245
|
}
|
|
211
246
|
});
|
|
212
|
-
promises.push(promise
|
|
247
|
+
promises.push(promise.catch(e => {
|
|
248
|
+
console.error('Uncaught error when resolving source map', params, e);
|
|
249
|
+
}));
|
|
213
250
|
}
|
|
214
251
|
await Promise.all(promises);
|
|
215
252
|
}
|