@vforsh/argus-core 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/protocol/http/dom.d.ts +4 -1
- package/dist/protocol/http/dom.d.ts.map +1 -1
- package/dist/protocol/http/dom.js +2 -0
- package/dist/protocol/http/dom.js.map +1 -1
- package/dist/protocol/http/domInteraction.d.ts +4 -1
- package/dist/protocol/http/domInteraction.d.ts.map +1 -1
- package/dist/protocol/http/domInteraction.js +9 -0
- package/dist/protocol/http/domInteraction.js.map +1 -1
- package/dist/protocol/http/errors.d.ts +1 -1
- package/dist/protocol/http/errors.d.ts.map +1 -1
- package/dist/protocol/http/errors.js +3 -0
- package/dist/protocol/http/errors.js.map +1 -1
- package/dist/protocol/http/navigation.d.ts +128 -0
- package/dist/protocol/http/navigation.d.ts.map +1 -0
- package/dist/protocol/http/navigation.js +66 -0
- package/dist/protocol/http/navigation.js.map +1 -0
- package/dist/protocol/http/record.d.ts +87 -5
- package/dist/protocol/http/record.d.ts.map +1 -1
- package/dist/protocol/http/record.js +28 -5
- package/dist/protocol/http/record.js.map +1 -1
- package/dist/protocol/http/status.d.ts +9 -0
- package/dist/protocol/http/status.d.ts.map +1 -1
- package/dist/protocol/http/status.js.map +1 -1
- package/dist/protocol/http.d.ts +1 -0
- package/dist/protocol/http.d.ts.map +1 -1
- package/dist/protocol/http.js +1 -0
- package/dist/protocol/http.js.map +1 -1
- package/dist/protocol/scenario.d.ts +31 -0
- package/dist/protocol/scenario.d.ts.map +1 -1
- package/dist/url/queryParams.d.ts +82 -0
- package/dist/url/queryParams.d.ts.map +1 -0
- package/dist/url/queryParams.js +146 -0
- package/dist/url/queryParams.js.map +1 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { LogEpoch, LogEvent, LogLevel } from './logs.js';
|
|
9
9
|
import type { ScreenshotClipRegion, ScreenshotResponse } from './http/screenshot.js';
|
|
10
|
+
import type { RecordFormat, RecordStartResponse, RecordStopResponse } from './http/record.js';
|
|
10
11
|
/** Page-side screenshot options accepted by scenario artifact helpers. */
|
|
11
12
|
export type ArgusScenarioScreenshotOptions = {
|
|
12
13
|
/** Crop to the first matching element. */
|
|
@@ -14,6 +15,34 @@ export type ArgusScenarioScreenshotOptions = {
|
|
|
14
15
|
/** Crop to a viewport-relative rectangle. Mutually exclusive with `selector`. */
|
|
15
16
|
clip?: ScreenshotClipRegion;
|
|
16
17
|
};
|
|
18
|
+
/** Page-side options accepted by `ctx.record.start`. */
|
|
19
|
+
export type ArgusScenarioRecordOptions = {
|
|
20
|
+
/** Crop to the first matching element. */
|
|
21
|
+
selector?: string;
|
|
22
|
+
/** Crop to a viewport-relative rectangle. Mutually exclusive with `selector`. */
|
|
23
|
+
clip?: ScreenshotClipRegion;
|
|
24
|
+
/** Output frames per second. Defaults to 30 (12 for GIF). */
|
|
25
|
+
fps?: number;
|
|
26
|
+
/** Output container. Defaults to mp4. */
|
|
27
|
+
format?: RecordFormat;
|
|
28
|
+
/** JPEG quality (1-100) of the intermediate screencast frames. */
|
|
29
|
+
quality?: number;
|
|
30
|
+
/** Auto-stop deadline in milliseconds, so an unstopped scenario cannot leak an encoder. */
|
|
31
|
+
maxDurationMs?: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Video recording from inside a bundled scenario.
|
|
35
|
+
*
|
|
36
|
+
* Unlike the CLI, a scenario names its clip rather than its path: the file always lands under
|
|
37
|
+
* `scenarios/recordings/` in the watcher artifact directory, the same way `checkpoint` owns its
|
|
38
|
+
* own naming. A scenario runs on the watcher host with no idea what the caller's cwd looks like.
|
|
39
|
+
*/
|
|
40
|
+
export type ArgusScenarioRecord = {
|
|
41
|
+
/** Start recording into `scenarios/recordings/<name>.<format>`. */
|
|
42
|
+
start: (name: string, options?: ArgusScenarioRecordOptions) => Promise<RecordStartResponse>;
|
|
43
|
+
/** Stop the active recording and resolve once the file is encoded. */
|
|
44
|
+
stop: () => Promise<RecordStopResponse>;
|
|
45
|
+
};
|
|
17
46
|
/** Filters for reading watcher logs from a scenario cursor. */
|
|
18
47
|
export type ArgusScenarioLogOptions = {
|
|
19
48
|
/** Only include these severity levels. */
|
|
@@ -59,5 +88,7 @@ export type ArgusScenarioContext = {
|
|
|
59
88
|
checkpoint: (name: string, options?: ArgusScenarioScreenshotOptions) => Promise<ScreenshotResponse>;
|
|
60
89
|
/** Cursor and session helpers for logs produced during the scenario. */
|
|
61
90
|
readonly logs: ArgusScenarioLogs;
|
|
91
|
+
/** Start and stop a silent video recording for part of the scenario. */
|
|
92
|
+
readonly record: ArgusScenarioRecord;
|
|
62
93
|
};
|
|
63
94
|
//# sourceMappingURL=scenario.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../src/protocol/scenario.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../src/protocol/scenario.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL rewriting shared by every command that navigates or reloads a page.
|
|
3
|
+
*
|
|
4
|
+
* `page reload --param` (which drives Chrome directly over a target's WebSocket) and
|
|
5
|
+
* `POST /navigate` (which runs inside the watcher) have to agree on what `--param foo=bar`
|
|
6
|
+
* means, and on what `/settings` resolves to. Both once lived only in the CLI, so the
|
|
7
|
+
* watcher had no way to reach them; keeping the rules here — in the dependency-free core —
|
|
8
|
+
* is what lets the two paths stay identical.
|
|
9
|
+
*/
|
|
10
|
+
/** One parsed `key=value` pair, or the reason the input was rejected. */
|
|
11
|
+
export type ParamPairResult = {
|
|
12
|
+
key: string;
|
|
13
|
+
value: string;
|
|
14
|
+
} | {
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Parse a single `--param key=value` argument.
|
|
19
|
+
*
|
|
20
|
+
* The value may contain `=`; only the first one separates key from value. An empty key is
|
|
21
|
+
* rejected rather than silently written as `""`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const parseParamPair: (value: string) => ParamPairResult;
|
|
24
|
+
/**
|
|
25
|
+
* Parse a `--params "a=b&c=d"` argument into search params.
|
|
26
|
+
*
|
|
27
|
+
* Keys and values are percent-decoded, matching what a user would have typed into an
|
|
28
|
+
* address bar. An empty string yields empty params rather than an error.
|
|
29
|
+
*/
|
|
30
|
+
export declare const parseParamsString: (value: string) => URLSearchParams | {
|
|
31
|
+
error: string;
|
|
32
|
+
};
|
|
33
|
+
/** True when the URL uses a scheme whose query string Argus is willing to rewrite. */
|
|
34
|
+
export declare const isHttpUrl: (url: string) => boolean;
|
|
35
|
+
/** Query overrides accepted by {@link applyQueryParams}. Both are optional and compose. */
|
|
36
|
+
export type QueryParamOverrides = {
|
|
37
|
+
/** Repeatable `key=value` pairs, applied last so an explicit flag wins. */
|
|
38
|
+
param?: readonly string[];
|
|
39
|
+
/** A single `a=b&c=d` string. */
|
|
40
|
+
params?: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Rewrite a URL's query string with overwrite semantics.
|
|
44
|
+
*
|
|
45
|
+
* Existing params the caller did not mention are preserved; ones it did are replaced, never
|
|
46
|
+
* appended. `params` is applied before `param` so a repeated `--param` flag wins over the
|
|
47
|
+
* bulk string when both name the same key.
|
|
48
|
+
*
|
|
49
|
+
* @param baseUrl Absolute http/https URL to rewrite.
|
|
50
|
+
* @param overrides Query overrides. When neither is present, `baseUrl` is returned unchanged.
|
|
51
|
+
* @returns The rewritten URL, or the reason the rewrite was refused (non-http scheme,
|
|
52
|
+
* unparseable URL, malformed pair).
|
|
53
|
+
*/
|
|
54
|
+
export declare const applyQueryParams: (baseUrl: string, overrides: QueryParamOverrides) => {
|
|
55
|
+
url: string;
|
|
56
|
+
} | {
|
|
57
|
+
error: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Resolve what the user typed into an absolute URL to navigate to.
|
|
61
|
+
*
|
|
62
|
+
* Three shapes reach this, and only one of them is a URL already:
|
|
63
|
+
* - relative — anything starting with `/`, `?`, `#`, `./` or `../` is resolved against
|
|
64
|
+
* `currentUrl`. This is why resolution runs in the watcher: it owns the authoritative URL.
|
|
65
|
+
* - absolute (`https://x/y`, `about:blank`) — used verbatim.
|
|
66
|
+
* - scheme-less (`localhost:3000`, `example.com/x`) — gets `http://`, matching what a browser
|
|
67
|
+
* address bar does.
|
|
68
|
+
*
|
|
69
|
+
* The leading character decides, deliberately: a bare token like `settings` becomes
|
|
70
|
+
* `http://settings/` rather than being guessed at, so `argus goto app /settings` and
|
|
71
|
+
* `argus goto app settings` never silently mean the same thing.
|
|
72
|
+
*
|
|
73
|
+
* @param input What the user typed. Whitespace is trimmed.
|
|
74
|
+
* @param currentUrl The page's current top-frame URL, or `null` when nothing is attached.
|
|
75
|
+
* @returns The absolute URL, or the reason it could not be resolved.
|
|
76
|
+
*/
|
|
77
|
+
export declare const resolveNavigationUrl: (input: string, currentUrl: string | null) => {
|
|
78
|
+
url: string;
|
|
79
|
+
} | {
|
|
80
|
+
error: string;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=queryParams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryParams.d.ts","sourceRoot":"","sources":["../../src/url/queryParams.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yEAAyE;AACzE,MAAM,MAAM,eAAe,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,eAU9C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAmBlF,CAAA;AAED,sFAAsF;AACtF,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,KAAG,OAAkE,CAAA;AAE1G,2FAA2F;AAC3F,MAAM,MAAM,mBAAmB,GAAG;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,WAAW,mBAAmB,KAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAqCnH,CAAA;AASD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,EAAE,YAAY,MAAM,GAAG,IAAI,KAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAuBhH,CAAA"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL rewriting shared by every command that navigates or reloads a page.
|
|
3
|
+
*
|
|
4
|
+
* `page reload --param` (which drives Chrome directly over a target's WebSocket) and
|
|
5
|
+
* `POST /navigate` (which runs inside the watcher) have to agree on what `--param foo=bar`
|
|
6
|
+
* means, and on what `/settings` resolves to. Both once lived only in the CLI, so the
|
|
7
|
+
* watcher had no way to reach them; keeping the rules here — in the dependency-free core —
|
|
8
|
+
* is what lets the two paths stay identical.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Parse a single `--param key=value` argument.
|
|
12
|
+
*
|
|
13
|
+
* The value may contain `=`; only the first one separates key from value. An empty key is
|
|
14
|
+
* rejected rather than silently written as `""`.
|
|
15
|
+
*/
|
|
16
|
+
export const parseParamPair = (value) => {
|
|
17
|
+
const eqIdx = value.indexOf('=');
|
|
18
|
+
if (eqIdx === -1) {
|
|
19
|
+
return { error: `Invalid --param "${value}": missing "=".` };
|
|
20
|
+
}
|
|
21
|
+
const key = value.slice(0, eqIdx);
|
|
22
|
+
if (key === '') {
|
|
23
|
+
return { error: `Invalid --param "${value}": empty key.` };
|
|
24
|
+
}
|
|
25
|
+
return { key, value: value.slice(eqIdx + 1) };
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Parse a `--params "a=b&c=d"` argument into search params.
|
|
29
|
+
*
|
|
30
|
+
* Keys and values are percent-decoded, matching what a user would have typed into an
|
|
31
|
+
* address bar. An empty string yields empty params rather than an error.
|
|
32
|
+
*/
|
|
33
|
+
export const parseParamsString = (value) => {
|
|
34
|
+
const params = new URLSearchParams();
|
|
35
|
+
if (value.trim() === '') {
|
|
36
|
+
return params;
|
|
37
|
+
}
|
|
38
|
+
const pairs = value.split('&');
|
|
39
|
+
for (const pair of pairs) {
|
|
40
|
+
const eqIdx = pair.indexOf('=');
|
|
41
|
+
if (eqIdx === -1) {
|
|
42
|
+
return { error: `Invalid --params "${pair}": missing "=".` };
|
|
43
|
+
}
|
|
44
|
+
const key = pair.slice(0, eqIdx);
|
|
45
|
+
if (key === '') {
|
|
46
|
+
return { error: `Invalid --params "${pair}": empty key.` };
|
|
47
|
+
}
|
|
48
|
+
params.set(decodeURIComponent(key), decodeURIComponent(pair.slice(eqIdx + 1)));
|
|
49
|
+
}
|
|
50
|
+
return params;
|
|
51
|
+
};
|
|
52
|
+
/** True when the URL uses a scheme whose query string Argus is willing to rewrite. */
|
|
53
|
+
export const isHttpUrl = (url) => url.startsWith('http://') || url.startsWith('https://');
|
|
54
|
+
/**
|
|
55
|
+
* Rewrite a URL's query string with overwrite semantics.
|
|
56
|
+
*
|
|
57
|
+
* Existing params the caller did not mention are preserved; ones it did are replaced, never
|
|
58
|
+
* appended. `params` is applied before `param` so a repeated `--param` flag wins over the
|
|
59
|
+
* bulk string when both name the same key.
|
|
60
|
+
*
|
|
61
|
+
* @param baseUrl Absolute http/https URL to rewrite.
|
|
62
|
+
* @param overrides Query overrides. When neither is present, `baseUrl` is returned unchanged.
|
|
63
|
+
* @returns The rewritten URL, or the reason the rewrite was refused (non-http scheme,
|
|
64
|
+
* unparseable URL, malformed pair).
|
|
65
|
+
*/
|
|
66
|
+
export const applyQueryParams = (baseUrl, overrides) => {
|
|
67
|
+
const hasParam = (overrides.param?.length ?? 0) > 0;
|
|
68
|
+
const hasParams = overrides.params != null;
|
|
69
|
+
if (!hasParam && !hasParams) {
|
|
70
|
+
return { url: baseUrl };
|
|
71
|
+
}
|
|
72
|
+
if (!isHttpUrl(baseUrl)) {
|
|
73
|
+
return { error: `URL "${baseUrl}" is not http/https. Cannot update query params.` };
|
|
74
|
+
}
|
|
75
|
+
let parsed;
|
|
76
|
+
try {
|
|
77
|
+
parsed = new URL(baseUrl);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return { error: `Invalid URL "${baseUrl}".` };
|
|
81
|
+
}
|
|
82
|
+
if (hasParams) {
|
|
83
|
+
const fromString = parseParamsString(overrides.params);
|
|
84
|
+
if ('error' in fromString) {
|
|
85
|
+
return fromString;
|
|
86
|
+
}
|
|
87
|
+
for (const [key, value] of fromString.entries()) {
|
|
88
|
+
parsed.searchParams.set(key, value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const pair of overrides.param ?? []) {
|
|
92
|
+
const parsedPair = parseParamPair(pair);
|
|
93
|
+
if ('error' in parsedPair) {
|
|
94
|
+
return parsedPair;
|
|
95
|
+
}
|
|
96
|
+
parsed.searchParams.set(parsedPair.key, parsedPair.value);
|
|
97
|
+
}
|
|
98
|
+
return { url: parsed.toString() };
|
|
99
|
+
};
|
|
100
|
+
/** A scheme followed by `//`, or any other scheme (`about:`, `data:`, `mailto:`). */
|
|
101
|
+
const SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
102
|
+
/** `host:port` — the one shape that also matches {@link SCHEME_PATTERN} but is not a scheme. */
|
|
103
|
+
const HOST_PORT_PATTERN = /^[^/?#:]+:\d+(?:[/?#]|$)/;
|
|
104
|
+
/** Leading forms that are unambiguously relative to the current document. */
|
|
105
|
+
const RELATIVE_PATTERN = /^[/?#]|^\.\.?(?:[/?#]|$)/;
|
|
106
|
+
/**
|
|
107
|
+
* Resolve what the user typed into an absolute URL to navigate to.
|
|
108
|
+
*
|
|
109
|
+
* Three shapes reach this, and only one of them is a URL already:
|
|
110
|
+
* - relative — anything starting with `/`, `?`, `#`, `./` or `../` is resolved against
|
|
111
|
+
* `currentUrl`. This is why resolution runs in the watcher: it owns the authoritative URL.
|
|
112
|
+
* - absolute (`https://x/y`, `about:blank`) — used verbatim.
|
|
113
|
+
* - scheme-less (`localhost:3000`, `example.com/x`) — gets `http://`, matching what a browser
|
|
114
|
+
* address bar does.
|
|
115
|
+
*
|
|
116
|
+
* The leading character decides, deliberately: a bare token like `settings` becomes
|
|
117
|
+
* `http://settings/` rather than being guessed at, so `argus goto app /settings` and
|
|
118
|
+
* `argus goto app settings` never silently mean the same thing.
|
|
119
|
+
*
|
|
120
|
+
* @param input What the user typed. Whitespace is trimmed.
|
|
121
|
+
* @param currentUrl The page's current top-frame URL, or `null` when nothing is attached.
|
|
122
|
+
* @returns The absolute URL, or the reason it could not be resolved.
|
|
123
|
+
*/
|
|
124
|
+
export const resolveNavigationUrl = (input, currentUrl) => {
|
|
125
|
+
const trimmed = input.trim();
|
|
126
|
+
if (trimmed === '') {
|
|
127
|
+
return { error: 'URL must be a non-empty string.' };
|
|
128
|
+
}
|
|
129
|
+
if (RELATIVE_PATTERN.test(trimmed)) {
|
|
130
|
+
if (!currentUrl) {
|
|
131
|
+
return { error: `Cannot resolve relative URL "${trimmed}": the page has no current URL.` };
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
return { url: new URL(trimmed, currentUrl).toString() };
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return { error: `Cannot resolve "${trimmed}" against "${currentUrl}".` };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// `localhost:3000` also matches SCHEME_PATTERN, so the host:port shape is checked first.
|
|
141
|
+
if (HOST_PORT_PATTERN.test(trimmed) || !SCHEME_PATTERN.test(trimmed)) {
|
|
142
|
+
return { url: `http://${trimmed}` };
|
|
143
|
+
}
|
|
144
|
+
return { url: trimmed };
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=queryParams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryParams.js","sourceRoot":"","sources":["../../src/url/queryParams.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAa,EAAmB,EAAE;IAChE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,KAAK,EAAE,oBAAoB,KAAK,iBAAiB,EAAE,CAAA;IAC7D,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACjC,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,oBAAoB,KAAK,eAAe,EAAE,CAAA;IAC3D,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAA;AAC9C,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAuC,EAAE;IACvF,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;IACpC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACzB,OAAO,MAAM,CAAA;IACd,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,EAAE,KAAK,EAAE,qBAAqB,IAAI,iBAAiB,EAAE,CAAA;QAC7D,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;QAChC,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YAChB,OAAO,EAAE,KAAK,EAAE,qBAAqB,IAAI,eAAe,EAAE,CAAA;QAC3D,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/E,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC,CAAA;AAED,sFAAsF;AACtF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAW,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;AAU1G;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAE,SAA8B,EAAuC,EAAE;IACxH,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,IAAI,IAAI,CAAA;IAC1C,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7B,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;IACxB,CAAC;IAED,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,QAAQ,OAAO,kDAAkD,EAAE,CAAA;IACpF,CAAC;IAED,IAAI,MAAW,CAAA;IACf,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,KAAK,EAAE,gBAAgB,OAAO,IAAI,EAAE,CAAA;IAC9C,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,CAAC,MAAO,CAAC,CAAA;QACvD,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;YAC3B,OAAO,UAAU,CAAA;QAClB,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;YACjD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACpC,CAAC;IACF,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;YAC3B,OAAO,UAAU,CAAA;QAClB,CAAC;QACD,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC1D,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAA;AAClC,CAAC,CAAA;AAED,qFAAqF;AACrF,MAAM,cAAc,GAAG,2BAA2B,CAAA;AAClD,gGAAgG;AAChG,MAAM,iBAAiB,GAAG,0BAA0B,CAAA;AACpD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,0BAA0B,CAAA;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAAE,UAAyB,EAAuC,EAAE;IACrH,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAA;IACpD,CAAC;IAED,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,EAAE,KAAK,EAAE,gCAAgC,OAAO,iCAAiC,EAAE,CAAA;QAC3F,CAAC;QACD,IAAI,CAAC;YACJ,OAAO,EAAE,GAAG,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAA;QACxD,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,KAAK,EAAE,mBAAmB,OAAO,cAAc,UAAU,IAAI,EAAE,CAAA;QACzE,CAAC;IACF,CAAC;IAED,yFAAyF;IACzF,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACtE,OAAO,EAAE,GAAG,EAAE,UAAU,OAAO,EAAE,EAAE,CAAA;IACpC,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AACxB,CAAC,CAAA"}
|