@devtune/ai-traffic 0.10.0 → 0.12.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/README.md +57 -2
- package/dist/cjs/client.js +208 -10
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/express.js +56 -4
- package/dist/cjs/express.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/node.js +53 -4
- package/dist/cjs/node.js.map +1 -1
- package/dist/cjs/vercel-oidc.js +159 -0
- package/dist/cjs/vercel-oidc.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/web-bot-auth.js +238 -0
- package/dist/cjs/web-bot-auth.js.map +1 -0
- package/dist/client.d.ts +95 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +208 -10
- package/dist/client.js.map +1 -1
- package/dist/express.d.ts +2 -1
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +56 -4
- package/dist/express.js.map +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/node.d.ts +1 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +53 -4
- package/dist/node.js.map +1 -1
- package/dist/vercel-oidc.d.ts +53 -0
- package/dist/vercel-oidc.d.ts.map +1 -0
- package/dist/vercel-oidc.js +152 -0
- package/dist/vercel-oidc.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-bot-auth.d.ts +56 -0
- package/dist/web-bot-auth.d.ts.map +1 -0
- package/dist/web-bot-auth.js +233 -0
- package/dist/web-bot-auth.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ABOUTME: Collects the Web Bot Auth signature material DevTune needs to verify a signed agent request.
|
|
3
|
+
* Forwards the signature headers verbatim with the request line and covered fields; never verifies, logs or stores them.
|
|
4
|
+
*/
|
|
5
|
+
const MAX_SIGNATURE_LENGTH = 4096;
|
|
6
|
+
const MAX_SIGNATURE_INPUT_LENGTH = 4096;
|
|
7
|
+
const MAX_SIGNATURE_AGENT_LENGTH = 2048;
|
|
8
|
+
const MAX_METHOD_LENGTH = 16;
|
|
9
|
+
const MAX_TARGET_URI_LENGTH = 8192;
|
|
10
|
+
const MAX_HEADER_VALUE_LENGTH = 4096;
|
|
11
|
+
const SIGNATURE_HEADERS = new Set(["signature", "signature-input", "signature-agent"]);
|
|
12
|
+
/**
|
|
13
|
+
* Derived components that depend on the path, query or scheme, which a Fetch
|
|
14
|
+
* runtime may have rewritten: it normalises the path, and behind a
|
|
15
|
+
* TLS-terminating proxy its `request.url` can be `http:` for an `https:`
|
|
16
|
+
* request.
|
|
17
|
+
*/
|
|
18
|
+
const FETCH_REWRITTEN_COMPONENTS = new Set([
|
|
19
|
+
"@path",
|
|
20
|
+
"@query",
|
|
21
|
+
"@request-target",
|
|
22
|
+
"@scheme",
|
|
23
|
+
"@target-uri",
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* The only header fields ever forwarded with a signature: non-sensitive
|
|
27
|
+
* request headers. A request whose signature covers any other field, besides
|
|
28
|
+
* the three signature headers, forwards no signature material at all, since
|
|
29
|
+
* an unknown field may carry a credential and dropping just that field would
|
|
30
|
+
* leave a signature that can never verify. Short enough to stay within
|
|
31
|
+
* ingest's limits of 16 fields and 128-character names.
|
|
32
|
+
*/
|
|
33
|
+
export const WEB_BOT_AUTH_FORWARDED_HEADERS = [
|
|
34
|
+
"accept",
|
|
35
|
+
"accept-encoding",
|
|
36
|
+
"accept-language",
|
|
37
|
+
"cache-control",
|
|
38
|
+
"content-length",
|
|
39
|
+
"content-type",
|
|
40
|
+
"date",
|
|
41
|
+
"from",
|
|
42
|
+
"host",
|
|
43
|
+
"user-agent",
|
|
44
|
+
];
|
|
45
|
+
const FORWARDED_HEADERS = new Set(WEB_BOT_AUTH_FORWARDED_HEADERS);
|
|
46
|
+
/** RFC 9110 field-value characters: visible ASCII, SP and HTAB. */
|
|
47
|
+
const FIELD_VALUE = /^[\t\x20-\x7e]*$/u;
|
|
48
|
+
/** RFC 9110 method token. */
|
|
49
|
+
const METHOD = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/u;
|
|
50
|
+
/** An absolute URI as sent on the wire: visible ASCII, no whitespace. */
|
|
51
|
+
const TARGET_URI = /^[\x21-\x7e]+$/u;
|
|
52
|
+
/**
|
|
53
|
+
* Reads the material for a request that carries all three of `Signature`,
|
|
54
|
+
* `Signature-Input` and `Signature-Agent`, or returns null.
|
|
55
|
+
*
|
|
56
|
+
* Also returns null when anything would exceed ingest's limits or is not a
|
|
57
|
+
* value the site could have received, rather than truncating: a truncated
|
|
58
|
+
* signature can never verify, and the event is then sent exactly as an
|
|
59
|
+
* unsigned one would be.
|
|
60
|
+
*
|
|
61
|
+
* `targetUri` must carry the authority and target the agent sent. A target
|
|
62
|
+
* that differs from the event's `url` only makes DevTune's check
|
|
63
|
+
* inconclusive, but a rewritten one that happens to match `url` turns a
|
|
64
|
+
* genuine signature into a failed one.
|
|
65
|
+
*
|
|
66
|
+
* A target with a query, even a bare `?`, forwards nothing. The query can
|
|
67
|
+
* carry a reset token, an OAuth code or search terms, and DevTune could not
|
|
68
|
+
* verify the signature anyway: the event's `url` never has a query, so the
|
|
69
|
+
* target would not match it.
|
|
70
|
+
*/
|
|
71
|
+
export function readWebBotAuth(request) {
|
|
72
|
+
if (!hasWebBotAuthHeaders(request)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const signature = request.headers.get("signature");
|
|
76
|
+
const signatureInput = request.headers.get("signature-input");
|
|
77
|
+
const signatureAgent = request.headers.get("signature-agent");
|
|
78
|
+
const { method } = request;
|
|
79
|
+
const targetUri = request.targetUri === undefined ? readFetchTargetUri(request) : request.targetUri;
|
|
80
|
+
if (targetUri === null ||
|
|
81
|
+
targetUri.includes("?") ||
|
|
82
|
+
!isFieldValue(signature, MAX_SIGNATURE_LENGTH) ||
|
|
83
|
+
!isFieldValue(signatureInput, MAX_SIGNATURE_INPUT_LENGTH) ||
|
|
84
|
+
!isFieldValue(signatureAgent, MAX_SIGNATURE_AGENT_LENGTH) ||
|
|
85
|
+
!method ||
|
|
86
|
+
method.length > MAX_METHOD_LENGTH ||
|
|
87
|
+
!METHOD.test(method) ||
|
|
88
|
+
targetUri.length > MAX_TARGET_URI_LENGTH ||
|
|
89
|
+
!TARGET_URI.test(targetUri)) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const components = readCoveredComponents(signatureInput);
|
|
93
|
+
// A Fetch runtime has already normalised the path (`/a/../guide` arrives as
|
|
94
|
+
// `/guide`) and may report a proxied `https:` request as `http:`. The raw
|
|
95
|
+
// forms are gone, so a signature over them would be checked against a
|
|
96
|
+
// rewritten base and fail. Signatures over `@authority` and
|
|
97
|
+
// `signature-agent` alone depend on neither and still forward.
|
|
98
|
+
if (request.targetUri === undefined &&
|
|
99
|
+
components.some((component) => FETCH_REWRITTEN_COMPONENTS.has(component))) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const coveredNames = components.filter((component) => !component.startsWith("@") && !SIGNATURE_HEADERS.has(component));
|
|
103
|
+
if (coveredNames.some((name) => !FORWARDED_HEADERS.has(name))) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const headers = new Map();
|
|
107
|
+
for (const name of coveredNames) {
|
|
108
|
+
if (headers.has(name)) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const value = request.headers.getCombined
|
|
112
|
+
? request.headers.getCombined(name)
|
|
113
|
+
: request.headers.get(name);
|
|
114
|
+
if (value === null) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!isFieldValue(value, MAX_HEADER_VALUE_LENGTH, true)) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
headers.set(name, value);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
signature,
|
|
124
|
+
signatureInput,
|
|
125
|
+
signatureAgent,
|
|
126
|
+
method,
|
|
127
|
+
targetUri,
|
|
128
|
+
...(headers.size === 0 ? {} : { headers: Object.fromEntries(headers) }),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The signed target for a Fetch-compatible runtime, which hands over
|
|
133
|
+
* `request.url` already normalised: `https://DOCS.example.com:443/guide`
|
|
134
|
+
* arrives as `https://docs.example.com/guide`. The authority is put back
|
|
135
|
+
* from the raw header the runtime built `url` from, `X-Forwarded-Host` or
|
|
136
|
+
* `Host`, and falls back to the raw `Host` when neither matches, so it is
|
|
137
|
+
* never a rewritten one. The scheme and path still come from `url`, which is
|
|
138
|
+
* why a signature covering a component that depends on them is not
|
|
139
|
+
* forwarded from here. Null without a `Host` header, or when `url` has a
|
|
140
|
+
* query, which `url.search` would hide when it is a bare `?`.
|
|
141
|
+
*/
|
|
142
|
+
function readFetchTargetUri(request) {
|
|
143
|
+
const host = request.headers.get("host");
|
|
144
|
+
let url;
|
|
145
|
+
try {
|
|
146
|
+
url = new URL(request.url);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (!host || request.url.split("#", 1)[0]?.includes("?")) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
const forwardedHost = request.headers.get("x-forwarded-host")?.split(",", 1)[0]?.trim();
|
|
155
|
+
const authority = [forwardedHost, host].find((candidate) => candidate && normalizeHost(url.protocol, candidate) === url.host) ?? host;
|
|
156
|
+
return `${url.protocol}//${authority}${url.pathname}`;
|
|
157
|
+
}
|
|
158
|
+
function normalizeHost(protocol, host) {
|
|
159
|
+
try {
|
|
160
|
+
return new URL(`${protocol}//${host}`).host;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Whether a request carries all three Web Bot Auth signature headers, the
|
|
168
|
+
* only requests whose arrival time or signature material is worth reading.
|
|
169
|
+
*/
|
|
170
|
+
export function hasWebBotAuthHeaders(request) {
|
|
171
|
+
return (request.headers.get("signature") !== null &&
|
|
172
|
+
request.headers.get("signature-input") !== null &&
|
|
173
|
+
request.headers.get("signature-agent") !== null);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Component identifiers a `Signature-Input` covers, across every signature it
|
|
177
|
+
* labels: header field names and derived components such as `@path`. This is
|
|
178
|
+
* just enough of RFC 8941 to find the strings that start an inner-list item:
|
|
179
|
+
* quoted strings are skipped whole, so a parameter value such as `key="a"` or
|
|
180
|
+
* `keyid="x (y)"` is never mistaken for one. Anything odd in the input is left
|
|
181
|
+
* for the caller or DevTune's parser to reject.
|
|
182
|
+
*/
|
|
183
|
+
function readCoveredComponents(signatureInput) {
|
|
184
|
+
const names = [];
|
|
185
|
+
let inInnerList = false;
|
|
186
|
+
let previous = "";
|
|
187
|
+
for (let index = 0; index < signatureInput.length; index += 1) {
|
|
188
|
+
const char = signatureInput[index];
|
|
189
|
+
if (char === '"') {
|
|
190
|
+
const end = findStringEnd(signatureInput, index + 1);
|
|
191
|
+
if (end === -1) {
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
if (inInnerList && (previous === "(" || previous === " ")) {
|
|
195
|
+
names.push(signatureInput.slice(index + 1, end).replace(/\\(["\\])/gu, "$1"));
|
|
196
|
+
}
|
|
197
|
+
index = end;
|
|
198
|
+
previous = '"';
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (char === "(") {
|
|
202
|
+
inInnerList = true;
|
|
203
|
+
}
|
|
204
|
+
else if (char === ")") {
|
|
205
|
+
inInnerList = false;
|
|
206
|
+
}
|
|
207
|
+
previous = char ?? "";
|
|
208
|
+
}
|
|
209
|
+
return names;
|
|
210
|
+
}
|
|
211
|
+
/** Index of the quote closing an sf-string that opened before `start`, or -1. */
|
|
212
|
+
function findStringEnd(value, start) {
|
|
213
|
+
for (let index = start; index < value.length; index += 1) {
|
|
214
|
+
if (value[index] === "\\") {
|
|
215
|
+
index += 1;
|
|
216
|
+
}
|
|
217
|
+
else if (value[index] === '"') {
|
|
218
|
+
return index;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return -1;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Also rejects a non-string, which a hand-written `HeadersLike` can return
|
|
225
|
+
* for a repeated field and which ingest's schema would refuse.
|
|
226
|
+
*/
|
|
227
|
+
function isFieldValue(value, maxLength, allowEmpty = false) {
|
|
228
|
+
return (typeof value === "string" &&
|
|
229
|
+
(allowEmpty || value.length > 0) &&
|
|
230
|
+
value.length <= maxLength &&
|
|
231
|
+
FIELD_VALUE.test(value));
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=web-bot-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-bot-auth.js","sourceRoot":"","sources":["../src/web-bot-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AACxC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AACxC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAErC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC;AACvF;;;;;GAKG;AACH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,OAAO;IACP,QAAQ;IACR,iBAAiB;IACjB,SAAS;IACT,aAAa;CACd,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAsB;IAC/D,QAAQ;IACR,iBAAiB;IACjB,iBAAiB;IACjB,eAAe;IACf,gBAAgB;IAChB,cAAc;IACd,MAAM;IACN,MAAM;IACN,MAAM;IACN,YAAY;CACb,CAAC;AAEF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,8BAA8B,CAAC,CAAC;AAElE,mEAAmE;AACnE,MAAM,WAAW,GAAG,mBAAmB,CAAC;AACxC,6BAA6B;AAC7B,MAAM,MAAM,GAAG,iCAAiC,CAAC;AACjD,yEAAyE;AACzE,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAsE;IAEtE,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,MAAM,SAAS,GACb,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAEpF,IACE,SAAS,KAAK,IAAI;QAClB,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QACvB,CAAC,YAAY,CAAC,SAAS,EAAE,oBAAoB,CAAC;QAC9C,CAAC,YAAY,CAAC,cAAc,EAAE,0BAA0B,CAAC;QACzD,CAAC,YAAY,CAAC,cAAc,EAAE,0BAA0B,CAAC;QACzD,CAAC,MAAM;QACP,MAAM,CAAC,MAAM,GAAG,iBAAiB;QACjC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACpB,SAAS,CAAC,MAAM,GAAG,qBAAqB;QACxC,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;IAEzD,4EAA4E;IAC5E,0EAA0E;IAC1E,sEAAsE;IACtE,4DAA4D;IAC5D,+DAA+D;IAC/D,IACE,OAAO,CAAC,SAAS,KAAK,SAAS;QAC/B,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,0BAA0B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EACzE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CACpC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAC/E,CAAC;IAEF,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW;YACvC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;YACnC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAE9B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,uBAAuB,EAAE,IAAI,CAAC,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,SAAS;QACT,cAAc;QACd,cAAc;QACd,MAAM;QACN,SAAS;QACT,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;KACxE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAAC,OAA6C;IACvE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,GAAQ,CAAC;IAEb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACxF,MAAM,SAAS,GACb,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,IAAI,CACxB,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,CAAC,IAAI,CAChF,IAAI,IAAI,CAAC;IAEZ,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,SAAS,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB,EAAE,IAAY;IACnD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,QAAQ,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAqC;IACxE,OAAO,CACL,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,IAAI;QACzC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,IAAI;QAC/C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAChD,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,cAAsB;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,QAAQ,GAAG,EAAE,CAAC;IAElB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAEnC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,aAAa,CAAC,cAAc,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAErD,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,MAAM;YACR,CAAC;YAED,IAAI,WAAW,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,QAAQ,KAAK,GAAG,CAAC,EAAE,CAAC;gBAC1D,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC;YAChF,CAAC;YAED,KAAK,GAAG,GAAG,CAAC;YACZ,QAAQ,GAAG,GAAG,CAAC;YAEf,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,WAAW,GAAG,KAAK,CAAC;QACtB,CAAC;QAED,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iFAAiF;AACjF,SAAS,aAAa,CAAC,KAAa,EAAE,KAAa;IACjD,KAAK,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACzD,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1B,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;aAAM,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CACnB,KAAoB,EACpB,SAAiB,EACjB,UAAU,GAAG,KAAK;IAElB,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,UAAU,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QAChC,KAAK,CAAC,MAAM,IAAI,SAAS;QACzB,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CACxB,CAAC;AACJ,CAAC"}
|