@jobshimo/browser-link 0.27.1 → 0.28.0
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/dist/activity/db.d.ts +27 -0
- package/dist/activity/db.js +98 -0
- package/dist/activity/db.js.map +1 -0
- package/dist/activity/extract.d.ts +32 -0
- package/dist/activity/extract.js +126 -0
- package/dist/activity/extract.js.map +1 -0
- package/dist/activity/paths.d.ts +16 -0
- package/dist/activity/paths.js +24 -0
- package/dist/activity/paths.js.map +1 -0
- package/dist/activity/queries.d.ts +100 -0
- package/dist/activity/queries.js +286 -0
- package/dist/activity/queries.js.map +1 -0
- package/dist/activity/types.d.ts +119 -0
- package/dist/activity/types.js +41 -0
- package/dist/activity/types.js.map +1 -0
- package/dist/bridge/ws-bridge.d.ts +18 -1
- package/dist/bridge/ws-bridge.js +107 -0
- package/dist/bridge/ws-bridge.js.map +1 -1
- package/dist/cdp/inpage/deep-query.d.ts +1 -1
- package/dist/cdp/inpage/deep-query.js +1 -1
- package/dist/cdp/inpage/dom-helpers.d.ts +1 -1
- package/dist/cdp/inpage/dom-helpers.js +1 -1
- package/dist/cli.js +24 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/activity.d.ts +11 -0
- package/dist/commands/activity.js +347 -0
- package/dist/commands/activity.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js.map +1 -1
- package/dist/extension/activity.d.ts +201 -0
- package/dist/extension/activity.html +662 -0
- package/dist/extension/activity.js +555 -0
- package/dist/extension/activity.js.map +1 -0
- package/dist/extension/background.js +146 -0
- package/dist/extension/background.js.map +1 -1
- package/dist/extension/inpage/deep-query.d.ts +1 -1
- package/dist/extension/inpage/deep-query.js +1 -1
- package/dist/extension/inpage/dom-helpers.d.ts +1 -1
- package/dist/extension/inpage/dom-helpers.js +1 -1
- package/dist/extension/manifest.json +3 -2
- package/dist/extension/popup.html +58 -0
- package/dist/extension/popup.js +11 -0
- package/dist/extension/popup.js.map +1 -1
- package/dist/messages.d.ts +80 -2
- package/dist/server.js +30 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/browser-definitions.js +50 -2
- package/dist/tools/browser-definitions.js.map +1 -1
- package/dist/tools/browser-dispatch.d.ts +34 -7
- package/dist/tools/browser-dispatch.js +107 -1
- package/dist/tools/browser-dispatch.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The Activity window.
|
|
4
|
+
*
|
|
5
|
+
* A dedicated extension page rather than a section of the 320px popup, for one
|
|
6
|
+
* reason that is not cosmetic: a Chrome action popup closes the moment it loses
|
|
7
|
+
* focus, so it physically cannot be watched while an agent works. This window
|
|
8
|
+
* stays open, and can be parked on a second monitor while the agent runs.
|
|
9
|
+
*
|
|
10
|
+
* It owns no data. Every row comes from the server's `activity.db` through the
|
|
11
|
+
* background service worker (`activityQuery` → WS `activity.query`), so what
|
|
12
|
+
* this page shows survives closing the browser, and closing this page loses
|
|
13
|
+
* nothing.
|
|
14
|
+
*/
|
|
15
|
+
/** How often the live tail asks for new rows. Two seconds reads as immediate
|
|
16
|
+
* to a human watching an agent work, and costs one small indexed SELECT — far
|
|
17
|
+
* cheaper than the render it usually skips because nothing changed. */
|
|
18
|
+
const TAIL_INTERVAL_MS = 2_000;
|
|
19
|
+
/** Rows held in the page. Beyond this the oldest are dropped from the DOM (not
|
|
20
|
+
* from the trail — they are still on disk and in any export). A table that
|
|
21
|
+
* grows without bound is how a panel left open overnight eats a gigabyte. */
|
|
22
|
+
const MAX_ROWS_IN_VIEW = 1_000;
|
|
23
|
+
/** Resolve a required element, failing loudly at load rather than producing a
|
|
24
|
+
* page that silently does nothing when the template and this script drift. */
|
|
25
|
+
const el = (id) => {
|
|
26
|
+
const node = document.getElementById(id);
|
|
27
|
+
if (!node)
|
|
28
|
+
throw new Error(`activity: missing #${id}`);
|
|
29
|
+
return node;
|
|
30
|
+
};
|
|
31
|
+
const ui = {
|
|
32
|
+
live: el('live'),
|
|
33
|
+
refresh: el('refresh'),
|
|
34
|
+
exportBtn: el('export'),
|
|
35
|
+
agent: el('filter-agent'),
|
|
36
|
+
tool: el('filter-tool'),
|
|
37
|
+
failed: el('filter-failed'),
|
|
38
|
+
text: el('filter-text'),
|
|
39
|
+
reset: el('filter-reset'),
|
|
40
|
+
count: el('count'),
|
|
41
|
+
table: el('table'),
|
|
42
|
+
rows: el('rows'),
|
|
43
|
+
state: el('state'),
|
|
44
|
+
stateTitle: el('state-title'),
|
|
45
|
+
stateDetail: el('state-detail'),
|
|
46
|
+
status: el('status'),
|
|
47
|
+
usageRows: el('usage-rows'),
|
|
48
|
+
usageSize: el('usage-size'),
|
|
49
|
+
usageSpan: el('usage-span'),
|
|
50
|
+
usageMeter: el('usage-fill').parentElement,
|
|
51
|
+
usageFill: el('usage-fill'),
|
|
52
|
+
usageCap: el('usage-cap'),
|
|
53
|
+
purgeToggle: el('purge-toggle'),
|
|
54
|
+
purgePanel: el('purge-panel'),
|
|
55
|
+
purgeFrom: el('purge-from'),
|
|
56
|
+
purgeTo: el('purge-to'),
|
|
57
|
+
purgeSummary: el('purge-summary'),
|
|
58
|
+
purgeCheck: el('purge-check'),
|
|
59
|
+
purgeRun: el('purge-run'),
|
|
60
|
+
purgeCancel: el('purge-cancel'),
|
|
61
|
+
preset30d: el('purge-preset-30d'),
|
|
62
|
+
preset7d: el('purge-preset-7d'),
|
|
63
|
+
presetAll: el('purge-preset-all'),
|
|
64
|
+
};
|
|
65
|
+
let records = [];
|
|
66
|
+
let lastStats = null;
|
|
67
|
+
/** Rows the last dry run said the current range would delete. Cleared whenever
|
|
68
|
+
* the range changes, so the red button can never act on a stale count — the
|
|
69
|
+
* user must always be shown a number for the range they are actually about to
|
|
70
|
+
* purge. */
|
|
71
|
+
let pendingPurgeCount = null;
|
|
72
|
+
let live = true;
|
|
73
|
+
let tailTimer = null;
|
|
74
|
+
/** Tools seen so far, so the filter offers exactly what exists rather than a
|
|
75
|
+
* hardcoded list that goes stale when a tool is added. */
|
|
76
|
+
const knownTools = new Set();
|
|
77
|
+
function ask(query) {
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
chrome.runtime.sendMessage({ action: 'activityQuery', query }, (reply) => {
|
|
80
|
+
if (chrome.runtime.lastError) {
|
|
81
|
+
resolve({ ok: false, error: chrome.runtime.lastError.message ?? 'unreachable' });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
resolve(reply);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/** Server-side filters. The free-text box is deliberately NOT one of them: it
|
|
89
|
+
* filters what is already loaded, so typing feels instant and never costs a
|
|
90
|
+
* round trip. The dropdowns are, because they change which rows exist. */
|
|
91
|
+
function serverFilters() {
|
|
92
|
+
const filters = { limit: 300 };
|
|
93
|
+
if (ui.agent.value)
|
|
94
|
+
filters.agent = ui.agent.value;
|
|
95
|
+
if (ui.tool.value)
|
|
96
|
+
filters.tool = ui.tool.value;
|
|
97
|
+
if (ui.failed.getAttribute('aria-pressed') === 'true')
|
|
98
|
+
filters.outcome = 'error';
|
|
99
|
+
return filters;
|
|
100
|
+
}
|
|
101
|
+
/* ------------------------------------------------------------- time ------
|
|
102
|
+
*
|
|
103
|
+
* ONE RULE, no exceptions:
|
|
104
|
+
*
|
|
105
|
+
* The trail stores UTC. The user only ever sees, and only ever types,
|
|
106
|
+
* their own local time.
|
|
107
|
+
*
|
|
108
|
+
* Everything the user reads goes through `toLocale*`. Everything the user
|
|
109
|
+
* types is a local calendar day and is converted to a UTC instant here, at
|
|
110
|
+
* this boundary, before it reaches the server. Nothing downstream of this
|
|
111
|
+
* file thinks about timezones at all.
|
|
112
|
+
*
|
|
113
|
+
* Exports are the one deliberate exception and are NOT a display surface:
|
|
114
|
+
* they keep raw UTC, because a file handed to another machine or another
|
|
115
|
+
* agent must not carry this browser's timezone baked into it.
|
|
116
|
+
*/
|
|
117
|
+
/** A local calendar day (`2026-07-31` from an `<input type="date">`) widened
|
|
118
|
+
* to the UTC instant at that day's local start or local end.
|
|
119
|
+
*
|
|
120
|
+
* Widening matters: without it, a purge "to Jul 31" would resolve to midnight
|
|
121
|
+
* and silently spare everything that happened during Jul 31. */
|
|
122
|
+
function localDayToUtc(day, edge) {
|
|
123
|
+
// No `Z` and no offset — the runtime parses this as LOCAL time, which is
|
|
124
|
+
// exactly what the date picker meant.
|
|
125
|
+
const suffix = edge === 'start' ? 'T00:00:00.000' : 'T23:59:59.999';
|
|
126
|
+
return new Date(`${day}${suffix}`).toISOString();
|
|
127
|
+
}
|
|
128
|
+
/** A Date as the local calendar day the picker expects (`YYYY-MM-DD`).
|
|
129
|
+
* NOT `toISOString().slice(0, 10)` — that is the UTC day, which is the wrong
|
|
130
|
+
* one for anybody whose offset has already rolled the date over. */
|
|
131
|
+
function toLocalDay(date) {
|
|
132
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
133
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
134
|
+
}
|
|
135
|
+
/** Full local timestamp, for the hover on a relative time. */
|
|
136
|
+
function formatExact(iso) {
|
|
137
|
+
return new Date(iso).toLocaleString();
|
|
138
|
+
}
|
|
139
|
+
/** Bytes as a human reads them. Binary units because that is what a file
|
|
140
|
+
* manager will show for the same file, and two numbers that disagree about the
|
|
141
|
+
* same thing are worse than either alone. */
|
|
142
|
+
function formatBytes(bytes) {
|
|
143
|
+
if (bytes < 1024)
|
|
144
|
+
return `${bytes} B`;
|
|
145
|
+
const units = ['KB', 'MB', 'GB'];
|
|
146
|
+
let value = bytes / 1024;
|
|
147
|
+
let unit = 0;
|
|
148
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
149
|
+
value /= 1024;
|
|
150
|
+
unit += 1;
|
|
151
|
+
}
|
|
152
|
+
return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${units[unit]}`;
|
|
153
|
+
}
|
|
154
|
+
function formatDay(iso) {
|
|
155
|
+
if (iso === null)
|
|
156
|
+
return '—';
|
|
157
|
+
return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Repaint the always-visible usage strip.
|
|
161
|
+
*
|
|
162
|
+
* Called from every reply — reads and purges alike — so the numbers can never
|
|
163
|
+
* be stale relative to what is on screen beneath them.
|
|
164
|
+
*/
|
|
165
|
+
function renderStats(stats) {
|
|
166
|
+
lastStats = stats;
|
|
167
|
+
ui.usageRows.textContent = stats.rows.toLocaleString();
|
|
168
|
+
ui.usageSize.textContent = formatBytes(stats.bytes);
|
|
169
|
+
ui.usageSpan.textContent = formatDay(stats.oldest_at);
|
|
170
|
+
const ratio = stats.max_rows > 0 ? stats.rows / stats.max_rows : 0;
|
|
171
|
+
ui.usageFill.style.width = `${Math.min(100, Math.round(ratio * 100))}%`;
|
|
172
|
+
ui.usageCap.textContent = `${stats.rows.toLocaleString()} / ${stats.max_rows.toLocaleString()}`;
|
|
173
|
+
// Amber past 80%: the trail is close to dropping its oldest entries, which
|
|
174
|
+
// is the one moment the user genuinely needs to decide between purging and
|
|
175
|
+
// exporting first.
|
|
176
|
+
ui.usageMeter.classList.toggle('warn', ratio >= 0.8);
|
|
177
|
+
}
|
|
178
|
+
function formatTime(iso) {
|
|
179
|
+
const then = new Date(iso).getTime();
|
|
180
|
+
const secondsAgo = Math.round((Date.now() - then) / 1000);
|
|
181
|
+
if (secondsAgo < 5)
|
|
182
|
+
return 'just now';
|
|
183
|
+
if (secondsAgo < 60)
|
|
184
|
+
return `${secondsAgo}s ago`;
|
|
185
|
+
if (secondsAgo < 3600)
|
|
186
|
+
return `${Math.floor(secondsAgo / 60)}m ago`;
|
|
187
|
+
return new Date(iso).toLocaleTimeString();
|
|
188
|
+
}
|
|
189
|
+
/** What the action acted on, in priority order. A selector says the most; a
|
|
190
|
+
* payload is next; the URL is the fallback for tools that take neither. */
|
|
191
|
+
function targetOf(record) {
|
|
192
|
+
return record.selector ?? record.payload ?? record.url ?? '—';
|
|
193
|
+
}
|
|
194
|
+
function matchesText(record, needle) {
|
|
195
|
+
if (needle === '')
|
|
196
|
+
return true;
|
|
197
|
+
const hay = [record.tool, record.selector, record.url, record.payload, record.error, record.agent]
|
|
198
|
+
.filter((v) => typeof v === 'string')
|
|
199
|
+
.join(' ')
|
|
200
|
+
.toLowerCase();
|
|
201
|
+
return hay.includes(needle);
|
|
202
|
+
}
|
|
203
|
+
function buildRow(record) {
|
|
204
|
+
const tr = document.createElement('tr');
|
|
205
|
+
if (record.outcome === 'error')
|
|
206
|
+
tr.className = 'failed';
|
|
207
|
+
const when = document.createElement('td');
|
|
208
|
+
when.className = 'when';
|
|
209
|
+
when.textContent = formatTime(record.at);
|
|
210
|
+
when.title = formatExact(record.at);
|
|
211
|
+
const agent = document.createElement('td');
|
|
212
|
+
if (record.agent) {
|
|
213
|
+
const badge = document.createElement('span');
|
|
214
|
+
badge.className = 'agent';
|
|
215
|
+
badge.textContent = record.agent;
|
|
216
|
+
if (record.agentPid !== null)
|
|
217
|
+
badge.title = `pid ${record.agentPid}`;
|
|
218
|
+
agent.append(badge);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
agent.textContent = '—';
|
|
222
|
+
}
|
|
223
|
+
const tool = document.createElement('td');
|
|
224
|
+
tool.className = 'tool';
|
|
225
|
+
tool.textContent = record.tool;
|
|
226
|
+
if (record.flowId) {
|
|
227
|
+
const tag = document.createElement('span');
|
|
228
|
+
tag.className = 'flow-tag';
|
|
229
|
+
tag.textContent = 'flow';
|
|
230
|
+
tag.title = record.flowId;
|
|
231
|
+
tool.append(tag);
|
|
232
|
+
}
|
|
233
|
+
const target = document.createElement('td');
|
|
234
|
+
const main = document.createElement('span');
|
|
235
|
+
main.className = 'target';
|
|
236
|
+
main.textContent = targetOf(record);
|
|
237
|
+
target.append(main);
|
|
238
|
+
// Show the payload as a second line only when it is not already the target,
|
|
239
|
+
// so a `type` row reads "#search / hunter2" without repeating itself.
|
|
240
|
+
if (record.payload !== null && record.payload !== targetOf(record)) {
|
|
241
|
+
const payload = document.createElement('span');
|
|
242
|
+
payload.className = 'payload';
|
|
243
|
+
payload.textContent = record.payload;
|
|
244
|
+
target.append(payload);
|
|
245
|
+
}
|
|
246
|
+
if (record.url !== null && record.url !== targetOf(record)) {
|
|
247
|
+
const url = document.createElement('span');
|
|
248
|
+
url.className = 'url';
|
|
249
|
+
url.textContent = record.url;
|
|
250
|
+
target.append(url);
|
|
251
|
+
}
|
|
252
|
+
const outcome = document.createElement('td');
|
|
253
|
+
outcome.className = `outcome ${record.outcome}`;
|
|
254
|
+
outcome.textContent =
|
|
255
|
+
record.outcome === 'ok' ? `ok · ${record.durationMs}ms` : (record.error ?? 'error');
|
|
256
|
+
if (record.outcome === 'error' && record.error)
|
|
257
|
+
outcome.title = record.error;
|
|
258
|
+
tr.append(when, agent, tool, target, outcome);
|
|
259
|
+
return tr;
|
|
260
|
+
}
|
|
261
|
+
function showState(title, detail = '') {
|
|
262
|
+
ui.stateTitle.textContent = title;
|
|
263
|
+
ui.stateDetail.textContent = detail;
|
|
264
|
+
ui.state.classList.remove('hidden');
|
|
265
|
+
ui.table.classList.add('hidden');
|
|
266
|
+
}
|
|
267
|
+
function render() {
|
|
268
|
+
const needle = ui.text.value.trim().toLowerCase();
|
|
269
|
+
const visible = records.filter((r) => matchesText(r, needle));
|
|
270
|
+
if (visible.length === 0) {
|
|
271
|
+
showState(records.length === 0 ? 'No activity yet' : 'Nothing matches this filter', records.length === 0
|
|
272
|
+
? 'Actions appear here the moment an agent touches a connected tab.'
|
|
273
|
+
: 'Try clearing the search box or the dropdowns.');
|
|
274
|
+
ui.count.textContent = records.length === 0 ? '' : `0 of ${records.length} shown`;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
ui.state.classList.add('hidden');
|
|
278
|
+
ui.table.classList.remove('hidden');
|
|
279
|
+
const fragment = document.createDocumentFragment();
|
|
280
|
+
for (const record of visible)
|
|
281
|
+
fragment.append(buildRow(record));
|
|
282
|
+
ui.rows.replaceChildren(fragment);
|
|
283
|
+
ui.count.textContent =
|
|
284
|
+
visible.length === records.length
|
|
285
|
+
? `${visible.length} actions`
|
|
286
|
+
: `${visible.length} of ${records.length} shown`;
|
|
287
|
+
}
|
|
288
|
+
function refreshAgentOptions(agents) {
|
|
289
|
+
const current = ui.agent.value;
|
|
290
|
+
const options = ['<option value="">All agents</option>'];
|
|
291
|
+
for (const { agent, count } of agents) {
|
|
292
|
+
options.push(`<option value="${escapeAttr(agent)}">${escapeHtml(agent)} (${count})</option>`);
|
|
293
|
+
}
|
|
294
|
+
ui.agent.innerHTML = options.join('');
|
|
295
|
+
ui.agent.value = current;
|
|
296
|
+
}
|
|
297
|
+
function refreshToolOptions() {
|
|
298
|
+
const current = ui.tool.value;
|
|
299
|
+
const options = ['<option value="">All tools</option>'];
|
|
300
|
+
for (const tool of [...knownTools].sort()) {
|
|
301
|
+
options.push(`<option value="${escapeAttr(tool)}">${escapeHtml(tool)}</option>`);
|
|
302
|
+
}
|
|
303
|
+
ui.tool.innerHTML = options.join('');
|
|
304
|
+
ui.tool.value = current;
|
|
305
|
+
}
|
|
306
|
+
/** The two option lists are the only place this page builds markup from a
|
|
307
|
+
* string, and both values are server-owned. Escaped anyway: an agent label is
|
|
308
|
+
* self-declared text, and "it cannot contain a quote today" is not a security
|
|
309
|
+
* boundary. */
|
|
310
|
+
function escapeHtml(value) {
|
|
311
|
+
return value.replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' })[c] ?? c);
|
|
312
|
+
}
|
|
313
|
+
function escapeAttr(value) {
|
|
314
|
+
return escapeHtml(value).replace(/"/g, '"');
|
|
315
|
+
}
|
|
316
|
+
async function load() {
|
|
317
|
+
const reply = await ask(serverFilters());
|
|
318
|
+
if (!reply.ok) {
|
|
319
|
+
if (reply.error === 'not-connected') {
|
|
320
|
+
showState('No connected tab', 'The trail lives in the browser-link server. Connect a tab from the popup to read it.');
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
showState('Could not read the trail', reply.error);
|
|
324
|
+
}
|
|
325
|
+
ui.status.textContent = `error: ${reply.error}`;
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
records = reply.records;
|
|
329
|
+
renderStats(reply.stats);
|
|
330
|
+
for (const record of records)
|
|
331
|
+
knownTools.add(record.tool);
|
|
332
|
+
refreshAgentOptions(reply.agents);
|
|
333
|
+
refreshToolOptions();
|
|
334
|
+
ui.status.textContent = `${reply.total} actions recorded`;
|
|
335
|
+
render();
|
|
336
|
+
}
|
|
337
|
+
/** Tail: ask only for what is newer than the newest row we hold, then prepend.
|
|
338
|
+
* Cheaper than reloading the page of 300 on every tick, and it keeps the
|
|
339
|
+
* user's scroll position where they left it. */
|
|
340
|
+
async function tail() {
|
|
341
|
+
const newest = records.at(0)?.id;
|
|
342
|
+
if (newest === undefined) {
|
|
343
|
+
await load();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const reply = await ask({ ...serverFilters(), since_id: newest });
|
|
347
|
+
if (!reply.ok)
|
|
348
|
+
return;
|
|
349
|
+
renderStats(reply.stats);
|
|
350
|
+
if (reply.records.length === 0)
|
|
351
|
+
return;
|
|
352
|
+
for (const record of reply.records)
|
|
353
|
+
knownTools.add(record.tool);
|
|
354
|
+
records = [...reply.records, ...records].slice(0, MAX_ROWS_IN_VIEW);
|
|
355
|
+
refreshAgentOptions(reply.agents);
|
|
356
|
+
refreshToolOptions();
|
|
357
|
+
ui.status.textContent = `${reply.total} actions recorded`;
|
|
358
|
+
render();
|
|
359
|
+
}
|
|
360
|
+
function setLive(next) {
|
|
361
|
+
live = next;
|
|
362
|
+
ui.live.setAttribute('aria-pressed', String(live));
|
|
363
|
+
if (tailTimer !== null)
|
|
364
|
+
clearInterval(tailTimer);
|
|
365
|
+
tailTimer = live ? setInterval(() => void tail(), TAIL_INTERVAL_MS) : null;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Download what is on screen as NDJSON.
|
|
369
|
+
*
|
|
370
|
+
* NDJSON rather than JSON because a trail is append-only and line-oriented:
|
|
371
|
+
* it greps, it tails, it diffs, and another agent can stream it without
|
|
372
|
+
* parsing the whole file. Exports exactly the filtered view, because the
|
|
373
|
+
* filter is how the user said what they wanted.
|
|
374
|
+
*
|
|
375
|
+
* Note this is the VISIBLE page. `browser-link activity export` is the tool
|
|
376
|
+
* for the complete trail — and the one with `--redact`.
|
|
377
|
+
*/
|
|
378
|
+
function exportVisible() {
|
|
379
|
+
const needle = ui.text.value.trim().toLowerCase();
|
|
380
|
+
const visible = records.filter((r) => matchesText(r, needle));
|
|
381
|
+
const body = visible.map((r) => JSON.stringify(r)).join('\n');
|
|
382
|
+
const blob = new Blob([`${body}\n`], { type: 'application/x-ndjson' });
|
|
383
|
+
const url = URL.createObjectURL(blob);
|
|
384
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
385
|
+
chrome.downloads.download({ url, filename: `browser-link-activity-${stamp}.ndjson` }, () => {
|
|
386
|
+
// Revoke once Chrome has taken the bytes; leaking the object URL would
|
|
387
|
+
// pin the whole export in memory for the life of the window.
|
|
388
|
+
URL.revokeObjectURL(url);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
/* ---------------------------------------------------------------- purge --
|
|
392
|
+
*
|
|
393
|
+
* Two-step by construction: the red button stays disabled until a dry run has
|
|
394
|
+
* put a real number in front of the user for the exact range they picked.
|
|
395
|
+
* Changing either date wipes that number and disables it again.
|
|
396
|
+
*/
|
|
397
|
+
function purgeAsk(input) {
|
|
398
|
+
return new Promise((resolve) => {
|
|
399
|
+
chrome.runtime.sendMessage({ action: 'activityPurge', ...input }, (reply) => {
|
|
400
|
+
if (chrome.runtime.lastError) {
|
|
401
|
+
resolve({ ok: false, error: chrome.runtime.lastError.message ?? 'unreachable' });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
resolve(reply);
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
/** A `<input type="date">` gives a local calendar day; the trail stores UTC
|
|
409
|
+
* instants. Widen each end to cover the whole day the user pointed at, or a
|
|
410
|
+
* purge "to Aug 14" would silently spare everything that happened on Aug 14. */
|
|
411
|
+
function rangeFromInputs() {
|
|
412
|
+
const from = ui.purgeFrom.value;
|
|
413
|
+
const to = ui.purgeTo.value;
|
|
414
|
+
return {
|
|
415
|
+
...(from ? { from: localDayToUtc(from, 'start') } : {}),
|
|
416
|
+
...(to ? { to: localDayToUtc(to, 'end') } : {}),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function describeRange() {
|
|
420
|
+
const from = ui.purgeFrom.value;
|
|
421
|
+
const to = ui.purgeTo.value;
|
|
422
|
+
if (!from && !to)
|
|
423
|
+
return 'the entire trail';
|
|
424
|
+
if (from && to)
|
|
425
|
+
return `${from} → ${to}`;
|
|
426
|
+
if (from)
|
|
427
|
+
return `everything from ${from} onwards`;
|
|
428
|
+
return `everything up to ${to}`;
|
|
429
|
+
}
|
|
430
|
+
/** Invalidate any resolved count. Called on every change to the range. */
|
|
431
|
+
function resetPurgeConfirmation() {
|
|
432
|
+
pendingPurgeCount = null;
|
|
433
|
+
ui.purgeRun.disabled = true;
|
|
434
|
+
ui.purgeRun.textContent = 'Delete permanently';
|
|
435
|
+
// Restate what is currently stored next to the range being chosen — deciding
|
|
436
|
+
// what to delete is much easier with the total in the same sentence.
|
|
437
|
+
const current = lastStats === null
|
|
438
|
+
? ''
|
|
439
|
+
: ` Currently ${lastStats.rows.toLocaleString()} actions, ${formatBytes(lastStats.bytes)}.`;
|
|
440
|
+
ui.purgeSummary.textContent = `Ready to check: ${describeRange()}.${current}`;
|
|
441
|
+
}
|
|
442
|
+
function setDaysAgo(days) {
|
|
443
|
+
const cutoff = new Date(Date.now() - days * 86_400_000);
|
|
444
|
+
ui.purgeFrom.value = '';
|
|
445
|
+
// Purging "older than N days" is an open-ended range with only an upper
|
|
446
|
+
// bound — the oldest row is wherever the trail happens to start.
|
|
447
|
+
ui.purgeTo.value = toLocalDay(cutoff);
|
|
448
|
+
resetPurgeConfirmation();
|
|
449
|
+
}
|
|
450
|
+
ui.purgeToggle.addEventListener('click', () => {
|
|
451
|
+
const opening = ui.purgePanel.hasAttribute('hidden');
|
|
452
|
+
if (opening)
|
|
453
|
+
ui.purgePanel.removeAttribute('hidden');
|
|
454
|
+
else
|
|
455
|
+
ui.purgePanel.setAttribute('hidden', '');
|
|
456
|
+
resetPurgeConfirmation();
|
|
457
|
+
});
|
|
458
|
+
ui.purgeCancel.addEventListener('click', () => {
|
|
459
|
+
ui.purgePanel.setAttribute('hidden', '');
|
|
460
|
+
});
|
|
461
|
+
ui.preset30d.addEventListener('click', () => {
|
|
462
|
+
setDaysAgo(30);
|
|
463
|
+
});
|
|
464
|
+
ui.preset7d.addEventListener('click', () => {
|
|
465
|
+
setDaysAgo(7);
|
|
466
|
+
});
|
|
467
|
+
ui.presetAll.addEventListener('click', () => {
|
|
468
|
+
ui.purgeFrom.value = '';
|
|
469
|
+
ui.purgeTo.value = '';
|
|
470
|
+
resetPurgeConfirmation();
|
|
471
|
+
});
|
|
472
|
+
ui.purgeFrom.addEventListener('change', resetPurgeConfirmation);
|
|
473
|
+
ui.purgeTo.addEventListener('change', resetPurgeConfirmation);
|
|
474
|
+
ui.purgeCheck.addEventListener('click', () => {
|
|
475
|
+
ui.purgeCheck.disabled = true;
|
|
476
|
+
ui.purgeSummary.textContent = 'Counting…';
|
|
477
|
+
void purgeAsk({ ...rangeFromInputs(), dryRun: true }).then((reply) => {
|
|
478
|
+
ui.purgeCheck.disabled = false;
|
|
479
|
+
if (!reply.ok) {
|
|
480
|
+
ui.purgeSummary.textContent = `Could not check: ${reply.error}`;
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
renderStats(reply.stats);
|
|
484
|
+
pendingPurgeCount = reply.removed;
|
|
485
|
+
if (reply.removed === 0) {
|
|
486
|
+
ui.purgeSummary.textContent = `Nothing to delete in ${describeRange()}.`;
|
|
487
|
+
ui.purgeRun.disabled = true;
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
ui.purgeSummary.textContent = `This will permanently delete ${reply.removed.toLocaleString()} of ${reply.stats.rows.toLocaleString()} actions (${describeRange()}).`;
|
|
491
|
+
ui.purgeRun.disabled = false;
|
|
492
|
+
ui.purgeRun.textContent = `Delete ${reply.removed.toLocaleString()} permanently`;
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
ui.purgeRun.addEventListener('click', () => {
|
|
496
|
+
if (pendingPurgeCount === null || pendingPurgeCount === 0)
|
|
497
|
+
return;
|
|
498
|
+
// Native confirm on purpose: it is modal, it cannot be missed, and this is
|
|
499
|
+
// the last moment before rows stop existing.
|
|
500
|
+
const ok = window.confirm(`Permanently delete ${pendingPurgeCount.toLocaleString()} actions (${describeRange()})?\n\nThis cannot be undone.`);
|
|
501
|
+
if (!ok)
|
|
502
|
+
return;
|
|
503
|
+
ui.purgeRun.disabled = true;
|
|
504
|
+
ui.purgeRun.textContent = 'Deleting…';
|
|
505
|
+
ui.purgeSummary.textContent = 'Deleting and reclaiming disk space…';
|
|
506
|
+
void purgeAsk(rangeFromInputs()).then((reply) => {
|
|
507
|
+
ui.purgeRun.textContent = 'Delete permanently';
|
|
508
|
+
if (!reply.ok) {
|
|
509
|
+
ui.purgeSummary.textContent = `Purge failed: ${reply.error}`;
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
renderStats(reply.stats);
|
|
513
|
+
ui.purgeSummary.textContent = `Deleted ${reply.removed.toLocaleString()} actions. ${reply.stats.rows.toLocaleString()} left, ${formatBytes(reply.stats.bytes)} on disk.`;
|
|
514
|
+
resetPurgeConfirmation();
|
|
515
|
+
// The rows on screen may no longer exist — reload rather than leave the
|
|
516
|
+
// table showing what was just deleted.
|
|
517
|
+
records = [];
|
|
518
|
+
void load();
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
ui.live.addEventListener('click', () => {
|
|
522
|
+
setLive(ui.live.getAttribute('aria-pressed') !== 'true');
|
|
523
|
+
});
|
|
524
|
+
ui.refresh.addEventListener('click', () => void load());
|
|
525
|
+
ui.exportBtn.addEventListener('click', exportVisible);
|
|
526
|
+
ui.failed.addEventListener('click', () => {
|
|
527
|
+
ui.failed.setAttribute('aria-pressed', String(ui.failed.getAttribute('aria-pressed') !== 'true'));
|
|
528
|
+
void load();
|
|
529
|
+
});
|
|
530
|
+
ui.agent.addEventListener('change', () => void load());
|
|
531
|
+
ui.tool.addEventListener('change', () => void load());
|
|
532
|
+
ui.text.addEventListener('input', render);
|
|
533
|
+
ui.reset.addEventListener('click', () => {
|
|
534
|
+
ui.agent.value = '';
|
|
535
|
+
ui.tool.value = '';
|
|
536
|
+
ui.text.value = '';
|
|
537
|
+
ui.failed.setAttribute('aria-pressed', 'false');
|
|
538
|
+
void load();
|
|
539
|
+
});
|
|
540
|
+
// Stop tailing while the window is hidden. A background window polling every
|
|
541
|
+
// two seconds forever is a battery cost with no reader.
|
|
542
|
+
document.addEventListener('visibilitychange', () => {
|
|
543
|
+
if (document.hidden) {
|
|
544
|
+
if (tailTimer !== null)
|
|
545
|
+
clearInterval(tailTimer);
|
|
546
|
+
tailTimer = null;
|
|
547
|
+
}
|
|
548
|
+
else if (live) {
|
|
549
|
+
setLive(true);
|
|
550
|
+
void tail();
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
setLive(true);
|
|
554
|
+
void load();
|
|
555
|
+
//# sourceMappingURL=activity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;AA6CH;;uEAEuE;AACvE,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;6EAE6E;AAC7E,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;8EAC8E;AAC9E,MAAM,EAAE,GAAG,CAAC,EAAU,EAAe,EAAE;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,EAAE,GAAG;IACT,IAAI,EAAE,EAAE,CAAC,MAAM,CAAsB;IACrC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAsB;IAC3C,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAsB;IAC5C,KAAK,EAAE,EAAE,CAAC,cAAc,CAAsB;IAC9C,IAAI,EAAE,EAAE,CAAC,aAAa,CAAsB;IAC5C,MAAM,EAAE,EAAE,CAAC,eAAe,CAAsB;IAChD,IAAI,EAAE,EAAE,CAAC,aAAa,CAAqB;IAC3C,KAAK,EAAE,EAAE,CAAC,cAAc,CAAsB;IAC9C,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC;IAClB,KAAK,EAAE,EAAE,CAAC,OAAO,CAAqB;IACtC,IAAI,EAAE,EAAE,CAAC,MAAM,CAA4B;IAC3C,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC;IAClB,UAAU,EAAE,EAAE,CAAC,aAAa,CAAC;IAC7B,WAAW,EAAE,EAAE,CAAC,cAAc,CAAC;IAC/B,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC;IACpB,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC;IAC3B,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC;IAC3B,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC;IAC3B,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,aAA4B;IACzD,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC;IAC3B,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC;IACzB,WAAW,EAAE,EAAE,CAAC,cAAc,CAAsB;IACpD,UAAU,EAAE,EAAE,CAAC,aAAa,CAAC;IAC7B,SAAS,EAAE,EAAE,CAAC,YAAY,CAAqB;IAC/C,OAAO,EAAE,EAAE,CAAC,UAAU,CAAqB;IAC3C,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC;IACjC,UAAU,EAAE,EAAE,CAAC,aAAa,CAAsB;IAClD,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAsB;IAC9C,WAAW,EAAE,EAAE,CAAC,cAAc,CAAsB;IACpD,SAAS,EAAE,EAAE,CAAC,kBAAkB,CAAsB;IACtD,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAsB;IACpD,SAAS,EAAE,EAAE,CAAC,kBAAkB,CAAsB;CACvD,CAAC;AAEF,IAAI,OAAO,GAAqB,EAAE,CAAC;AACnC,IAAI,SAAS,GAAyB,IAAI,CAAC;AAC3C;;;YAGY;AACZ,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAC5C,IAAI,IAAI,GAAG,IAAI,CAAC;AAChB,IAAI,SAAS,GAA0C,IAAI,CAAC;AAC5D;0DAC0D;AAC1D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;AAErC,SAAS,GAAG,CAAC,KAA8B;IACzC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,CAAC,KAAiB,EAAE,EAAE;YACnF,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC7B,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC;gBACjF,OAAO;YACT,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;0EAE0E;AAC1E,SAAS,aAAa;IACpB,MAAM,OAAO,GAA4B,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACxD,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;IACnD,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;IAChD,IAAI,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,cAAc,CAAC,KAAK,MAAM;QAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;IACjF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AAEH;;;;gEAIgE;AAChE,SAAS,aAAa,CAAC,GAAW,EAAE,IAAqB;IACvD,yEAAyE;IACzE,sCAAsC;IACtC,MAAM,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC;IACpE,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACnD,CAAC;AAED;;oEAEoE;AACpE,SAAS,UAAU,CAAC,IAAU;IAC5B,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9D,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;AACpF,CAAC;AAED,8DAA8D;AAC9D,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC;AACxC,CAAC;AAED;;6CAE6C;AAC7C,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;IACzB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,KAAK,IAAI,IAAI,CAAC;QACd,IAAI,IAAI,CAAC,CAAC;IACZ,CAAC;IACD,OAAO,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,SAAS,SAAS,CAAC,GAAkB;IACnC,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IAC7B,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;AACzF,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAoB;IACvC,SAAS,GAAG,KAAK,CAAC;IAClB,EAAE,CAAC,SAAS,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;IACvD,EAAE,CAAC,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpD,EAAE,CAAC,SAAS,CAAC,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEtD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;IACxE,EAAE,CAAC,QAAQ,CAAC,WAAW,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;IAChG,2EAA2E;IAC3E,2EAA2E;IAC3E,mBAAmB;IACnB,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1D,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IACtC,IAAI,UAAU,GAAG,EAAE;QAAE,OAAO,GAAG,UAAU,OAAO,CAAC;IACjD,IAAI,UAAU,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC;IACpE,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,EAAE,CAAC;AAC5C,CAAC;AAED;2EAC2E;AAC3E,SAAS,QAAQ,CAAC,MAAsB;IACtC,OAAO,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,MAAsB,EAAE,MAAc;IACzD,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SAC/F,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;SACjD,IAAI,CAAC,GAAG,CAAC;SACT,WAAW,EAAE,CAAC;IACjB,OAAO,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,QAAQ,CAAC,MAAsB;IACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;QAAE,EAAE,CAAC,SAAS,GAAG,QAAQ,CAAC;IAExD,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC;IACxB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC7C,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC;QAC1B,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;QACjC,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI;YAAE,KAAK,CAAC,KAAK,GAAG,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC;IACxB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC;IAC/B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,GAAG,CAAC,SAAS,GAAG,UAAU,CAAC;QAC3B,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;QACzB,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC1B,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpB,4EAA4E;IAC5E,sEAAsE;IACtE,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QAC9B,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,MAAM,CAAC,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;QACtB,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,SAAS,GAAG,WAAW,MAAM,CAAC,OAAO,EAAE,CAAC;IAChD,OAAO,CAAC,WAAW;QACjB,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC;IACtF,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAE7E,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,SAAS,CAAC,KAAa,EAAE,MAAM,GAAG,EAAE;IAC3C,EAAE,CAAC,UAAU,CAAC,WAAW,GAAG,KAAK,CAAC;IAClC,EAAE,CAAC,WAAW,CAAC,WAAW,GAAG,MAAM,CAAC;IACpC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,MAAM;IACb,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAE9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,SAAS,CACP,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,6BAA6B,EACxE,OAAO,CAAC,MAAM,KAAK,CAAC;YAClB,CAAC,CAAC,kEAAkE;YACpE,CAAC,CAAC,+CAA+C,CACpD,CAAC;QACF,EAAE,CAAC,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,MAAM,QAAQ,CAAC;QAClF,OAAO;IACT,CAAC;IAED,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;IACnD,KAAK,MAAM,MAAM,IAAI,OAAO;QAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClC,EAAE,CAAC,KAAK,CAAC,WAAW;QAClB,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;YAC/B,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU;YAC7B,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,QAAQ,CAAC;AACvD,CAAC;AAED,SAAS,mBAAmB,CAAC,MAA0C;IACrE,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;IAC/B,MAAM,OAAO,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACzD,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,kBAAkB,UAAU,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,KAAK,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC;IAChG,CAAC;IACD,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtC,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC;AAC3B,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;IAC9B,MAAM,OAAO,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,kBAAkB,UAAU,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnF,CAAC;IACD,EAAE,CAAC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrC,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;AAC1B,CAAC;AAED;;;eAGe;AACf,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9F,CAAC;AACD,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;YACpC,SAAS,CACP,kBAAkB,EAClB,sFAAsF,CACvF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,0BAA0B,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,WAAW,GAAG,UAAU,KAAK,CAAC,KAAK,EAAE,CAAC;QAChD,OAAO;IACT,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IACxB,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzB,KAAK,MAAM,MAAM,IAAI,OAAO;QAAE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClC,kBAAkB,EAAE,CAAC;IACrB,EAAE,CAAC,MAAM,CAAC,WAAW,GAAG,GAAG,KAAK,CAAC,KAAK,mBAAmB,CAAC;IAC1D,MAAM,EAAE,CAAC;AACX,CAAC;AAED;;gDAEgD;AAChD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACjC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO;IACtB,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACvC,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO;QAAE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACpE,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClC,kBAAkB,EAAE,CAAC;IACrB,EAAE,CAAC,MAAM,CAAC,WAAW,GAAG,GAAG,KAAK,CAAC,KAAK,mBAAmB,CAAC;IAC1D,MAAM,EAAE,CAAC;AACX,CAAC;AAED,SAAS,OAAO,CAAC,IAAa;IAC5B,IAAI,GAAG,IAAI,CAAC;IACZ,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,IAAI,SAAS,KAAK,IAAI;QAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACjD,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,aAAa;IACpB,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC7D,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,yBAAyB,KAAK,SAAS,EAAE,EAAE,GAAG,EAAE;QACzF,uEAAuE;QACvE,6DAA6D;QAC7D,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AAEH,SAAS,QAAQ,CAAC,KAAuD;IACvE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,KAAK,EAAE,EAAE,CAAC,KAAiB,EAAE,EAAE;YACtF,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC7B,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC;gBACjF,OAAO;YACT,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;gFAEgF;AAChF,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;IAChC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC5B,OAAO;QACL,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;IAChC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE;QAAE,OAAO,kBAAkB,CAAC;IAC5C,IAAI,IAAI,IAAI,EAAE;QAAE,OAAO,GAAG,IAAI,MAAM,EAAE,EAAE,CAAC;IACzC,IAAI,IAAI;QAAE,OAAO,mBAAmB,IAAI,UAAU,CAAC;IACnD,OAAO,oBAAoB,EAAE,EAAE,CAAC;AAClC,CAAC;AAED,0EAA0E;AAC1E,SAAS,sBAAsB;IAC7B,iBAAiB,GAAG,IAAI,CAAC;IACzB,EAAE,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC5B,EAAE,CAAC,QAAQ,CAAC,WAAW,GAAG,oBAAoB,CAAC;IAC/C,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,OAAO,GACX,SAAS,KAAK,IAAI;QAChB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,cAAc,SAAS,CAAC,IAAI,CAAC,cAAc,EAAE,aAAa,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC;IAChG,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,mBAAmB,aAAa,EAAE,IAAI,OAAO,EAAE,CAAC;AAChF,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,UAAU,CAAC,CAAC;IACxD,EAAE,CAAC,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;IACxB,wEAAwE;IACxE,iEAAiE;IACjE,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,sBAAsB,EAAE,CAAC;AAC3B,CAAC;AAED,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACrD,IAAI,OAAO;QAAE,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;;QAChD,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC9C,sBAAsB,EAAE,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IAC1C,UAAU,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC;AACH,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IACzC,UAAU,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC,CAAC,CAAC;AACH,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;IACxB,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;IACtB,sBAAsB,EAAE,CAAC;AAC3B,CAAC,CAAC,CAAC;AACH,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;AAChE,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;AAE9D,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,UAAU,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC9B,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,WAAW,CAAC;IAC1C,KAAK,QAAQ,CAAC,EAAE,GAAG,eAAe,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QACnE,EAAE,CAAC,UAAU,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;YACd,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,oBAAoB,KAAK,CAAC,KAAK,EAAE,CAAC;YAChE,OAAO;QACT,CAAC;QACD,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,iBAAiB,GAAG,KAAK,CAAC,OAAO,CAAC;QAClC,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,wBAAwB,aAAa,EAAE,GAAG,CAAC;YACzE,EAAE,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,gCAAgC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,aAAa,aAAa,EAAE,IAAI,CAAC;QACrK,EAAE,CAAC,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC7B,EAAE,CAAC,QAAQ,CAAC,WAAW,GAAG,UAAU,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC;IACnF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IACzC,IAAI,iBAAiB,KAAK,IAAI,IAAI,iBAAiB,KAAK,CAAC;QAAE,OAAO;IAClE,2EAA2E;IAC3E,6CAA6C;IAC7C,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CACvB,sBAAsB,iBAAiB,CAAC,cAAc,EAAE,aAAa,aAAa,EAAE,8BAA8B,CACnH,CAAC;IACF,IAAI,CAAC,EAAE;QAAE,OAAO;IAEhB,EAAE,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC5B,EAAE,CAAC,QAAQ,CAAC,WAAW,GAAG,WAAW,CAAC;IACtC,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,qCAAqC,CAAC;IACpE,KAAK,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9C,EAAE,CAAC,QAAQ,CAAC,WAAW,GAAG,oBAAoB,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;YACd,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,iBAAiB,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7D,OAAO;QACT,CAAC;QACD,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,EAAE,CAAC,YAAY,CAAC,WAAW,GAAG,WAAW,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,aAAa,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;QACzK,sBAAsB,EAAE,CAAC;QACzB,wEAAwE;QACxE,uCAAuC;QACvC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,IAAI,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IACrC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,KAAK,MAAM,CAAC,CAAC;AAC3D,CAAC,CAAC,CAAC;AACH,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AACxD,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AACtD,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,cAAc,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;IAClG,KAAK,IAAI,EAAE,CAAC;AACd,CAAC,CAAC,CAAC;AACH,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AACvD,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AACtD,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1C,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;IACpB,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IACnB,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IACnB,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAChD,KAAK,IAAI,EAAE,CAAC;AACd,CAAC,CAAC,CAAC;AAEH,6EAA6E;AAC7E,wDAAwD;AACxD,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IACjD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,IAAI,SAAS,KAAK,IAAI;YAAE,aAAa,CAAC,SAAS,CAAC,CAAC;QACjD,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;SAAM,IAAI,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,IAAI,CAAC,CAAC;AACd,KAAK,IAAI,EAAE,CAAC"}
|