@dbx-tools/appkit-web-search 0.3.44 → 0.4.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/lib/index.d.ts +32 -0
- package/lib/index.js +28 -0
- package/lib/src/allowlist.d.ts +66 -0
- package/lib/src/allowlist.js +113 -0
- package/lib/src/config.d.ts +233 -0
- package/lib/src/config.js +269 -0
- package/lib/src/defaults.d.ts +98 -0
- package/lib/src/defaults.js +96 -0
- package/lib/src/fetch.d.ts +27 -0
- package/lib/src/fetch.js +86 -0
- package/lib/src/html-text.d.ts +30 -0
- package/lib/src/html-text.js +66 -0
- package/lib/src/plugin.d.ts +162 -0
- package/lib/src/plugin.js +225 -0
- package/lib/src/provider.d.ts +62 -0
- package/lib/src/provider.js +89 -0
- package/lib/src/runtime.d.ts +61 -0
- package/lib/src/runtime.js +95 -0
- package/lib/src/schema.d.ts +76 -0
- package/lib/src/schema.js +102 -0
- package/lib/src/scrape.d.ts +29 -0
- package/lib/src/scrape.js +113 -0
- package/lib/src/search.d.ts +49 -0
- package/lib/src/search.js +252 -0
- package/lib/src/tool.d.ts +85 -0
- package/lib/src/tool.js +113 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +13 -9
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the web-search plugin: the typed
|
|
3
|
+
* {@link WebSearchPluginConfig} (the plugin's slice of AppKit config), the
|
|
4
|
+
* JSON Schema the manifest publishes for it, and {@link resolveWebSearchConfig}
|
|
5
|
+
* which layers that config over environment defaults into the concrete
|
|
6
|
+
* {@link ResolvedWebSearchConfig} the runtime + tools read.
|
|
7
|
+
*
|
|
8
|
+
* `web_search` runs on the Databricks Model Serving native web-search tool
|
|
9
|
+
* (see `provider.ts` / `search.ts`), so the key knob is which web-search-
|
|
10
|
+
* capable model to use. It resolves independently of the calling agent's chat
|
|
11
|
+
* model: `model` (a name, loose name, or capability class) is fuzzy-matched
|
|
12
|
+
* against the workspace catalogue, and when nothing is pinned the
|
|
13
|
+
* {@link WebSearchPluginConfig.modelFallbacks} order (Gemini, then GPT, then a
|
|
14
|
+
* repo floor) picks the first web-search-capable endpoint that exists.
|
|
15
|
+
*
|
|
16
|
+
* Which endpoint id is used follows the standard precedence - explicit plugin
|
|
17
|
+
* config, then environment, then a default - with two environment sources:
|
|
18
|
+
*
|
|
19
|
+
* 1. `model` in plugin config;
|
|
20
|
+
* 2. `WEB_SEARCH_MODEL`, the dedicated override, so a deployment can point
|
|
21
|
+
* web search at a different endpoint than the agent's chat model;
|
|
22
|
+
* 3. `DATABRICKS_SERVING_ENDPOINT_NAME`, AppKit's standard name for a
|
|
23
|
+
* Model Serving binding, honored so the resource declared in the manifest
|
|
24
|
+
* wires this plugin up like any other. Because that binding is shared
|
|
25
|
+
* with whatever else the app serves, it is treated as a preference: an
|
|
26
|
+
* endpoint that cannot run the native web-search tool is skipped in
|
|
27
|
+
* favor of {@link WebSearchPluginConfig.modelFallbacks} rather than
|
|
28
|
+
* failing the call. A pin from (1) or (2) is explicit and DOES fail;
|
|
29
|
+
* 4. otherwise the fallback order, resolved against the live catalogue.
|
|
30
|
+
*
|
|
31
|
+
* Which model wins is decided lazily, at call time, against the live
|
|
32
|
+
* catalogue. Resolution here is eager about everything else and fails loudly
|
|
33
|
+
* on a contradiction: an unparseable `WEB_SEARCH_TOOLS`, an unknown
|
|
34
|
+
* {@link UrlPolicyMode}, or a URL policy that disagrees with the allow-list it
|
|
35
|
+
* was given.
|
|
36
|
+
*
|
|
37
|
+
* Env fallbacks: `WEB_SEARCH_MODEL`, `DATABRICKS_SERVING_ENDPOINT_NAME`,
|
|
38
|
+
* `WEB_SEARCH_MODEL_FALLBACKS`, `WEB_SEARCH_TOOLS` (JSON),
|
|
39
|
+
* `WEB_SEARCH_URL_POLICY`, `WEB_SEARCH_ALLOWED_URLS`,
|
|
40
|
+
* `WEB_SEARCH_MAX_CITATIONS`, `WEB_SEARCH_FETCH_MAX_LENGTH`,
|
|
41
|
+
* `WEB_SEARCH_TIMEOUT_MS`, `WEB_SEARCH_SCRAPE_FALLBACK`, `WEB_SEARCH_FUZZY`,
|
|
42
|
+
* `WEB_SEARCH_FUZZY_THRESHOLD`.
|
|
43
|
+
*
|
|
44
|
+
* @module
|
|
45
|
+
*/
|
|
46
|
+
import { ConfigurationError } from "@databricks/appkit";
|
|
47
|
+
import { serving } from "@dbx-tools/model";
|
|
48
|
+
import { json, object, string } from "@dbx-tools/shared-core";
|
|
49
|
+
import { parseAllowedUrls, toUrlAllowList } from "./allowlist.js";
|
|
50
|
+
/** Dedicated override for the web-search endpoint id. */
|
|
51
|
+
export const MODEL_ENV = "WEB_SEARCH_MODEL";
|
|
52
|
+
/** AppKit's standard environment name for a Model Serving endpoint binding. */
|
|
53
|
+
export const SERVING_ENDPOINT_ENV = "DATABRICKS_SERVING_ENDPOINT_NAME";
|
|
54
|
+
/**
|
|
55
|
+
* Default web-search model preference, tried in order when no model is
|
|
56
|
+
* pinned. Gemini first, then GPT - both support the native web-search tool;
|
|
57
|
+
* a workspace typically has at least one. Each is fuzzy-matched against the
|
|
58
|
+
* live catalogue, so a close variant (e.g. `databricks-gemini-3-1-pro`) is
|
|
59
|
+
* picked when the exact id isn't present.
|
|
60
|
+
*/
|
|
61
|
+
export const DEFAULT_MODEL_FALLBACKS = [
|
|
62
|
+
"databricks-gemini-3-pro",
|
|
63
|
+
"databricks-gemini-2-5-pro",
|
|
64
|
+
"databricks-gpt-5",
|
|
65
|
+
"databricks-gpt-5-mini",
|
|
66
|
+
];
|
|
67
|
+
/** Default cap on the number of citations returned from a single search. */
|
|
68
|
+
export const DEFAULT_MAX_CITATIONS = 10;
|
|
69
|
+
/** Default cap on characters returned from a single `web_fetch`. */
|
|
70
|
+
export const DEFAULT_FETCH_MAX_LENGTH = 50_000;
|
|
71
|
+
/** Default per-request network timeout (ms) for search + fetch. */
|
|
72
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
73
|
+
/** JSON Schema published on the manifest's `config.schema`. */
|
|
74
|
+
export const WEB_SEARCH_CONFIG_SCHEMA = {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
model: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Default web-search model (endpoint name, loose name, or class). Fuzzy-matched. Env: WEB_SEARCH_MODEL, then DATABRICKS_SERVING_ENDPOINT_NAME.",
|
|
80
|
+
},
|
|
81
|
+
modelFallbacks: {
|
|
82
|
+
type: "array",
|
|
83
|
+
items: { type: "string" },
|
|
84
|
+
description: "Ordered web-search model candidates when `model` is unset (Gemini, then GPT). Env: WEB_SEARCH_MODEL_FALLBACKS.",
|
|
85
|
+
},
|
|
86
|
+
webSearchTools: {
|
|
87
|
+
type: "object",
|
|
88
|
+
description: 'Provider -> tool-spec override map merged over the built-in defaults (openai -> {"type":"web_search"}, gemini -> {"google_search":{}}). Env: WEB_SEARCH_TOOLS (JSON).',
|
|
89
|
+
},
|
|
90
|
+
modelFuzzyMatch: {
|
|
91
|
+
type: "boolean",
|
|
92
|
+
description: "Fuzzy-match loose model names against the live catalogue. Default true (env: WEB_SEARCH_FUZZY).",
|
|
93
|
+
},
|
|
94
|
+
modelFuzzyThreshold: {
|
|
95
|
+
type: "number",
|
|
96
|
+
description: "Fuse.js score threshold below which a fuzzy model match is accepted (env: WEB_SEARCH_FUZZY_THRESHOLD).",
|
|
97
|
+
},
|
|
98
|
+
maxCitations: {
|
|
99
|
+
type: "number",
|
|
100
|
+
description: "Hard cap on citations returned (env: WEB_SEARCH_MAX_CITATIONS).",
|
|
101
|
+
},
|
|
102
|
+
fetchMaxLength: {
|
|
103
|
+
type: "number",
|
|
104
|
+
description: "Hard cap on web_fetch content length (env: WEB_SEARCH_FETCH_MAX_LENGTH).",
|
|
105
|
+
},
|
|
106
|
+
timeoutMs: {
|
|
107
|
+
type: "number",
|
|
108
|
+
description: "Per-request network timeout in ms (env: WEB_SEARCH_TIMEOUT_MS).",
|
|
109
|
+
},
|
|
110
|
+
scrapeFallback: {
|
|
111
|
+
type: "boolean",
|
|
112
|
+
description: "Fall back to a DuckDuckGo scrape when no web-search-capable model is deployed. Default true (env: WEB_SEARCH_SCRAPE_FALLBACK).",
|
|
113
|
+
},
|
|
114
|
+
urlPolicy: {
|
|
115
|
+
type: "string",
|
|
116
|
+
enum: ["unrestricted", "allowlist"],
|
|
117
|
+
description: "Which URLs the tools may reach. Defaults to allowlist when allowedUrls has entries, else unrestricted (env: WEB_SEARCH_URL_POLICY).",
|
|
118
|
+
},
|
|
119
|
+
allowedUrls: {
|
|
120
|
+
type: "array",
|
|
121
|
+
items: { type: "string" },
|
|
122
|
+
description: 'URL allow-list of globs / bare hosts (e.g. "*.databricks.com", "docs.example.com"). Also accepts a comma/space-separated string. Falls back to WEB_SEARCH_ALLOWED_URLS. Empty = unrestricted.',
|
|
123
|
+
},
|
|
124
|
+
approval: {
|
|
125
|
+
description: 'Approval gate for both tools: true gates every call, a glob (or list of globs) gates only matching URLs, or state the mode directly as {"mode":"none"|"always"|"urls"}. Default none.',
|
|
126
|
+
oneOf: [
|
|
127
|
+
{ type: "boolean" },
|
|
128
|
+
{ type: "string" },
|
|
129
|
+
{ type: "array", items: { type: "string" } },
|
|
130
|
+
{
|
|
131
|
+
type: "object",
|
|
132
|
+
properties: {
|
|
133
|
+
mode: { type: "string", enum: ["none", "always", "urls"] },
|
|
134
|
+
patterns: { type: "array", items: { type: "string" } },
|
|
135
|
+
},
|
|
136
|
+
required: ["mode"],
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
/** Parse a positive integer env/config value, else the fallback. */
|
|
143
|
+
function resolvePositiveInt(value, envKey, fallback) {
|
|
144
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0)
|
|
145
|
+
return Math.floor(value);
|
|
146
|
+
const env = Number(process.env[envKey]);
|
|
147
|
+
return Number.isFinite(env) && env > 0 ? Math.floor(env) : fallback;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Parse the `WEB_SEARCH_TOOLS` env var (JSON object), else `{}`. A value that
|
|
151
|
+
* is set but not a JSON object is a deployment mistake that would otherwise
|
|
152
|
+
* silently leave the built-in tool specs in place, so it throws.
|
|
153
|
+
*/
|
|
154
|
+
function parseToolsEnv() {
|
|
155
|
+
const raw = string.trimToNull(process.env.WEB_SEARCH_TOOLS);
|
|
156
|
+
if (raw === null)
|
|
157
|
+
return {};
|
|
158
|
+
const parsed = json.parseRecord(raw);
|
|
159
|
+
if (!parsed) {
|
|
160
|
+
throw new ConfigurationError("WEB_SEARCH_TOOLS must be a JSON object mapping a provider family to its tool spec", { context: { envVar: "WEB_SEARCH_TOOLS" } });
|
|
161
|
+
}
|
|
162
|
+
return parsed;
|
|
163
|
+
}
|
|
164
|
+
/** Read the pinned endpoint id and record which source supplied it. */
|
|
165
|
+
function resolveModelPin(config) {
|
|
166
|
+
const fromConfig = string.trimToNull(config.model);
|
|
167
|
+
if (fromConfig !== null)
|
|
168
|
+
return { model: fromConfig, source: "config" };
|
|
169
|
+
const fromModelEnv = string.trimToNull(process.env[MODEL_ENV]);
|
|
170
|
+
if (fromModelEnv !== null)
|
|
171
|
+
return { model: fromModelEnv, source: MODEL_ENV };
|
|
172
|
+
const fromResourceEnv = string.trimToNull(process.env[SERVING_ENDPOINT_ENV]);
|
|
173
|
+
if (fromResourceEnv !== null)
|
|
174
|
+
return { model: fromResourceEnv, source: SERVING_ENDPOINT_ENV };
|
|
175
|
+
return { source: "none" };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Resolve the named {@link UrlPolicyMode}, failing on a stated mode that
|
|
179
|
+
* contradicts the allow-list entries it was given.
|
|
180
|
+
*/
|
|
181
|
+
function resolveUrlPolicy(configured, patterns) {
|
|
182
|
+
const raw = configured ?? string.trimToNull(process.env.WEB_SEARCH_URL_POLICY) ?? undefined;
|
|
183
|
+
if (raw === undefined)
|
|
184
|
+
return patterns.length > 0 ? "allowlist" : "unrestricted";
|
|
185
|
+
if (raw !== "allowlist" && raw !== "unrestricted") {
|
|
186
|
+
throw new ConfigurationError('urlPolicy must be "allowlist" or "unrestricted" (env: WEB_SEARCH_URL_POLICY)', { context: { field: "urlPolicy", envVar: "WEB_SEARCH_URL_POLICY" } });
|
|
187
|
+
}
|
|
188
|
+
if (raw === "allowlist" && patterns.length === 0) {
|
|
189
|
+
throw new ConfigurationError('urlPolicy "allowlist" needs at least one entry in allowedUrls (env: WEB_SEARCH_ALLOWED_URLS)', { context: { field: "allowedUrls", envVar: "WEB_SEARCH_ALLOWED_URLS" } });
|
|
190
|
+
}
|
|
191
|
+
if (raw === "unrestricted" && patterns.length > 0) {
|
|
192
|
+
throw new ConfigurationError('urlPolicy "unrestricted" cannot be combined with allowedUrls entries; drop the entries or set urlPolicy to "allowlist"', { context: { field: "allowedUrls", envVar: "WEB_SEARCH_ALLOWED_URLS" } });
|
|
193
|
+
}
|
|
194
|
+
return raw;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Normalize any accepted approval spelling into an {@link ApprovalPolicy}.
|
|
198
|
+
* A pattern gate with no usable patterns collapses to `"none"` rather than
|
|
199
|
+
* gating everything, so a blank env var can never wedge the tools behind an
|
|
200
|
+
* approval nobody configured.
|
|
201
|
+
*/
|
|
202
|
+
export function toApprovalPolicy(gate) {
|
|
203
|
+
if (gate === undefined || gate === false)
|
|
204
|
+
return { mode: "none" };
|
|
205
|
+
if (gate === true)
|
|
206
|
+
return { mode: "always" };
|
|
207
|
+
if (object.isRecord(gate) && "mode" in gate) {
|
|
208
|
+
if (gate.mode === "urls") {
|
|
209
|
+
const patterns = parseAllowedUrls([...gate.patterns]);
|
|
210
|
+
return patterns.length > 0 ? { mode: "urls", patterns } : { mode: "none" };
|
|
211
|
+
}
|
|
212
|
+
if (gate.mode === "always" || gate.mode === "none")
|
|
213
|
+
return { mode: gate.mode };
|
|
214
|
+
throw new ConfigurationError('approval mode must be "none", "always" or "urls"', {
|
|
215
|
+
context: { field: "approval" },
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const patterns = parseAllowedUrls(typeof gate === "string" ? gate : [...gate]);
|
|
219
|
+
return patterns.length > 0 ? { mode: "urls", patterns } : { mode: "none" };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Resolve plugin config over environment defaults into the concrete
|
|
223
|
+
* {@link ResolvedWebSearchConfig}. Which model is used stays lazy - it is
|
|
224
|
+
* picked at call time against the live catalogue - but everything else is
|
|
225
|
+
* settled here, and a contradiction (unparseable `WEB_SEARCH_TOOLS`, an
|
|
226
|
+
* unknown URL policy, a policy that disagrees with its allow-list) throws a
|
|
227
|
+
* {@link ConfigurationError} naming the field and the environment variable.
|
|
228
|
+
*/
|
|
229
|
+
export function resolveWebSearchConfig(config = {}) {
|
|
230
|
+
const patterns = parseAllowedUrls(config.allowedUrls ?? process.env.WEB_SEARCH_ALLOWED_URLS);
|
|
231
|
+
const urlPolicy = resolveUrlPolicy(config.urlPolicy, patterns);
|
|
232
|
+
const { model, source } = resolveModelPin(config);
|
|
233
|
+
const fallbacks = string.parseList(config.modelFallbacks ?? process.env.WEB_SEARCH_MODEL_FALLBACKS);
|
|
234
|
+
const fuzzyThresholdRaw = config.modelFuzzyThreshold ?? Number(process.env.WEB_SEARCH_FUZZY_THRESHOLD);
|
|
235
|
+
return {
|
|
236
|
+
...(model ? { model } : {}),
|
|
237
|
+
modelSource: source,
|
|
238
|
+
modelFallbacks: fallbacks.length > 0 ? fallbacks : DEFAULT_MODEL_FALLBACKS,
|
|
239
|
+
webSearchTools: { ...parseToolsEnv(), ...(config.webSearchTools ?? {}) },
|
|
240
|
+
fuzzy: config.modelFuzzyMatch ?? object.toBoolean(process.env.WEB_SEARCH_FUZZY) ?? true,
|
|
241
|
+
fuzzyThreshold: Number.isFinite(fuzzyThresholdRaw) && fuzzyThresholdRaw
|
|
242
|
+
? Number(fuzzyThresholdRaw)
|
|
243
|
+
: serving.DEFAULT_FUZZY_THRESHOLD,
|
|
244
|
+
maxCitations: resolvePositiveInt(config.maxCitations, "WEB_SEARCH_MAX_CITATIONS", DEFAULT_MAX_CITATIONS),
|
|
245
|
+
fetchMaxLength: resolvePositiveInt(config.fetchMaxLength, "WEB_SEARCH_FETCH_MAX_LENGTH", DEFAULT_FETCH_MAX_LENGTH),
|
|
246
|
+
timeoutMs: resolvePositiveInt(config.timeoutMs, "WEB_SEARCH_TIMEOUT_MS", DEFAULT_TIMEOUT_MS),
|
|
247
|
+
scrapeFallback: config.scrapeFallback ?? object.toBoolean(process.env.WEB_SEARCH_SCRAPE_FALLBACK) ?? true,
|
|
248
|
+
urlPolicy,
|
|
249
|
+
allowList: toUrlAllowList(urlPolicy === "allowlist" ? patterns : []),
|
|
250
|
+
approval: toApprovalPolicy(config.approval),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Resolve an approval gate against a set of candidate URLs into a concrete
|
|
255
|
+
* boolean: `"none"` / `"always"` pass straight through; a `"urls"` policy
|
|
256
|
+
* gates when ANY candidate matches. Empty candidates with a pattern gate
|
|
257
|
+
* never match (nothing to approve). Reuses the allow-list matcher so approval
|
|
258
|
+
* globs read exactly like allow-list globs.
|
|
259
|
+
*/
|
|
260
|
+
export function approvalMatches(gate, urls) {
|
|
261
|
+
const policy = toApprovalPolicy(gate);
|
|
262
|
+
if (policy.mode === "none")
|
|
263
|
+
return false;
|
|
264
|
+
if (policy.mode === "always")
|
|
265
|
+
return true;
|
|
266
|
+
const list = toUrlAllowList(policy.patterns);
|
|
267
|
+
return urls.some((url) => list.allows(url));
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0Q0c7QUFFSCxPQUFPLEVBQUUsa0JBQWtCLEVBQXlCLE1BQU0sb0JBQW9CLENBQUM7QUFDL0UsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFrQixNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUU5RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFxQixNQUFNLGFBQWEsQ0FBQztBQTZCbEYseURBQXlEO0FBQ3pELE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxrQkFBa0IsQ0FBQztBQUU1QywrRUFBK0U7QUFDL0UsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsa0NBQWtDLENBQUM7QUFLdkU7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQXNCO0lBQ3hELHlCQUF5QjtJQUN6QiwyQkFBMkI7SUFDM0Isa0JBQWtCO0lBQ2xCLHVCQUF1QjtDQUN4QixDQUFDO0FBRUYsNEVBQTRFO0FBQzVFLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLEVBQUUsQ0FBQztBQUV4QyxvRUFBb0U7QUFDcEUsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsTUFBTSxDQUFDO0FBRS9DLG1FQUFtRTtBQUNuRSxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLENBQUM7QUFrSHpDLCtEQUErRDtBQUMvRCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBZ0I7SUFDbkQsSUFBSSxFQUFFLFFBQVE7SUFDZCxVQUFVLEVBQUU7UUFDVixLQUFLLEVBQUU7WUFDTCxJQUFJLEVBQUUsUUFBUTtZQUNkLFdBQVcsRUFDVCw4SUFBOEk7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Q0FBQyxDQUFDO0FBQzlDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHRoZSB3ZWItc2VhcmNoIHBsdWdpbjogdGhlIHR5cGVkXG4gKiB7QGxpbmsgV2ViU2VhcmNoUGx1Z2luQ29uZmlnfSAodGhlIHBsdWdpbidzIHNsaWNlIG9mIEFwcEtpdCBjb25maWcpLCB0aGVcbiAqIEpTT04gU2NoZW1hIHRoZSBtYW5pZmVzdCBwdWJsaXNoZXMgZm9yIGl0LCBhbmQge0BsaW5rIHJlc29sdmVXZWJTZWFyY2hDb25maWd9XG4gKiB3aGljaCBsYXllcnMgdGhhdCBjb25maWcgb3ZlciBlbnZpcm9ubWVudCBkZWZhdWx0cyBpbnRvIHRoZSBjb25jcmV0ZVxuICoge0BsaW5rIFJlc29sdmVkV2ViU2VhcmNoQ29uZmlnfSB0aGUgcnVudGltZSArIHRvb2xzIHJlYWQuXG4gKlxuICogYHdlYl9zZWFyY2hgIHJ1bnMgb24gdGhlIERhdGFicmlja3MgTW9kZWwgU2VydmluZyBuYXRpdmUgd2ViLXNlYXJjaCB0b29sXG4gKiAoc2VlIGBwcm92aWRlci50c2AgLyBgc2VhcmNoLnRzYCksIHNvIHRoZSBrZXkga25vYiBpcyB3aGljaCB3ZWItc2VhcmNoLVxuICogY2FwYWJsZSBtb2RlbCB0byB1c2UuIEl0IHJlc29sdmVzIGluZGVwZW5kZW50bHkgb2YgdGhlIGNhbGxpbmcgYWdlbnQncyBjaGF0XG4gKiBtb2RlbDogYG1vZGVsYCAoYSBuYW1lLCBsb29zZSBuYW1lLCBvciBjYXBhYmlsaXR5IGNsYXNzKSBpcyBmdXp6eS1tYXRjaGVkXG4gKiBhZ2FpbnN0IHRoZSB3b3Jrc3BhY2UgY2F0YWxvZ3VlLCBhbmQgd2hlbiBub3RoaW5nIGlzIHBpbm5lZCB0aGVcbiAqIHtAbGluayBXZWJTZWFyY2hQbHVnaW5Db25maWcubW9kZWxGYWxsYmFja3N9IG9yZGVyIChHZW1pbmksIHRoZW4gR1BULCB0aGVuIGFcbiAqIHJlcG8gZmxvb3IpIHBpY2tzIHRoZSBmaXJzdCB3ZWItc2VhcmNoLWNhcGFibGUgZW5kcG9pbnQgdGhhdCBleGlzdHMuXG4gKlxuICogV2hpY2ggZW5kcG9pbnQgaWQgaXMgdXNlZCBmb2xsb3dzIHRoZSBzdGFuZGFyZCBwcmVjZWRlbmNlIC0gZXhwbGljaXQgcGx1Z2luXG4gKiBjb25maWcsIHRoZW4gZW52aXJvbm1lbnQsIHRoZW4gYSBkZWZhdWx0IC0gd2l0aCB0d28gZW52aXJvbm1lbnQgc291cmNlczpcbiAqXG4gKiAgIDEuIGBtb2RlbGAgaW4gcGx1Z2luIGNvbmZpZztcbiAqICAgMi4gYFdFQl9TRUFSQ0hfTU9ERUxgLCB0aGUgZGVkaWNhdGVkIG92ZXJyaWRlLCBzbyBhIGRlcGxveW1lbnQgY2FuIHBvaW50XG4gKiAgICAgIHdlYiBzZWFyY2ggYXQgYSBkaWZmZXJlbnQgZW5kcG9pbnQgdGhhbiB0aGUgYWdlbnQncyBjaGF0IG1vZGVsO1xuICogICAzLiBgREFUQUJSSUNLU19TRVJWSU5HX0VORFBPSU5UX05BTUVgLCBBcHBLaXQncyBzdGFuZGFyZCBuYW1lIGZvciBhXG4gKiAgICAgIE1vZGVsIFNlcnZpbmcgYmluZGluZywgaG9ub3JlZCBzbyB0aGUgcmVzb3VyY2UgZGVjbGFyZWQgaW4gdGhlIG1hbmlmZXN0XG4gKiAgICAgIHdpcmVzIHRoaXMgcGx1Z2luIHVwIGxpa2UgYW55IG90aGVyLiBCZWNhdXNlIHRoYXQgYmluZGluZyBpcyBzaGFyZWRcbiAqICAgICAgd2l0aCB3aGF0ZXZlciBlbHNlIHRoZSBhcHAgc2VydmVzLCBpdCBpcyB0cmVhdGVkIGFzIGEgcHJlZmVyZW5jZTogYW5cbiAqICAgICAgZW5kcG9pbnQgdGhhdCBjYW5ub3QgcnVuIHRoZSBuYXRpdmUgd2ViLXNlYXJjaCB0b29sIGlzIHNraXBwZWQgaW5cbiAqICAgICAgZmF2b3Igb2Yge0BsaW5rIFdlYlNlYXJjaFBsdWdpbkNvbmZpZy5tb2RlbEZhbGxiYWNrc30gcmF0aGVyIHRoYW5cbiAqICAgICAgZmFpbGluZyB0aGUgY2FsbC4gQSBwaW4gZnJvbSAoMSkgb3IgKDIpIGlzIGV4cGxpY2l0IGFuZCBET0VTIGZhaWw7XG4gKiAgIDQuIG90aGVyd2lzZSB0aGUgZmFsbGJhY2sgb3JkZXIsIHJlc29sdmVkIGFnYWluc3QgdGhlIGxpdmUgY2F0YWxvZ3VlLlxuICpcbiAqIFdoaWNoIG1vZGVsIHdpbnMgaXMgZGVjaWRlZCBsYXppbHksIGF0IGNhbGwgdGltZSwgYWdhaW5zdCB0aGUgbGl2ZVxuICogY2F0YWxvZ3VlLiBSZXNvbHV0aW9uIGhlcmUgaXMgZWFnZXIgYWJvdXQgZXZlcnl0aGluZyBlbHNlIGFuZCBmYWlscyBsb3VkbHlcbiAqIG9uIGEgY29udHJhZGljdGlvbjogYW4gdW5wYXJzZWFibGUgYFdFQl9TRUFSQ0hfVE9PTFNgLCBhbiB1bmtub3duXG4gKiB7QGxpbmsgVXJsUG9saWN5TW9kZX0sIG9yIGEgVVJMIHBvbGljeSB0aGF0IGRpc2FncmVlcyB3aXRoIHRoZSBhbGxvdy1saXN0IGl0XG4gKiB3YXMgZ2l2ZW4uXG4gKlxuICogRW52IGZhbGxiYWNrczogYFdFQl9TRUFSQ0hfTU9ERUxgLCBgREFUQUJSSUNLU19TRVJWSU5HX0VORFBPSU5UX05BTUVgLFxuICogYFdFQl9TRUFSQ0hfTU9ERUxfRkFMTEJBQ0tTYCwgYFdFQl9TRUFSQ0hfVE9PTFNgIChKU09OKSxcbiAqIGBXRUJfU0VBUkNIX1VSTF9QT0xJQ1lgLCBgV0VCX1NFQVJDSF9BTExPV0VEX1VSTFNgLFxuICogYFdFQl9TRUFSQ0hfTUFYX0NJVEFUSU9OU2AsIGBXRUJfU0VBUkNIX0ZFVENIX01BWF9MRU5HVEhgLFxuICogYFdFQl9TRUFSQ0hfVElNRU9VVF9NU2AsIGBXRUJfU0VBUkNIX1NDUkFQRV9GQUxMQkFDS2AsIGBXRUJfU0VBUkNIX0ZVWlpZYCxcbiAqIGBXRUJfU0VBUkNIX0ZVWlpZX1RIUkVTSE9MRGAuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IENvbmZpZ3VyYXRpb25FcnJvciwgdHlwZSBCYXNlUGx1Z2luQ29uZmlnIH0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHsgc2VydmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL21vZGVsXCI7XG5pbXBvcnQgeyBqc29uLCBvYmplY3QsIHR5cGUgT25lT3JNYW55LCBzdHJpbmcgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBKU09OU2NoZW1hNyB9IGZyb20gXCJqc29uLXNjaGVtYVwiO1xuaW1wb3J0IHsgcGFyc2VBbGxvd2VkVXJscywgdG9VcmxBbGxvd0xpc3QsIHR5cGUgVXJsQWxsb3dMaXN0IH0gZnJvbSBcIi4vYWxsb3dsaXN0XCI7XG5cbi8qKlxuICogQSBVUkwtcGF0dGVybiBnYXRlIGZvciBwZXItdG9vbCBhcHByb3ZhbC4gYHRydWVgIGdhdGVzIGV2ZXJ5IGNhbGw7IGFcbiAqIHBhdHRlcm4gKG9yIGxpc3Qgb2YgcGF0dGVybnMsIGluIHRoZSB7QGxpbmsgT25lT3JNYW55fSBzaGFwZSB1c2VkIGFjcm9zc1xuICogdGhlIHJlcG8pIGdhdGVzIG9ubHkgY2FsbHMgd2hvc2UgVVJMIG1hdGNoZXMuIFBhdHRlcm5zIHVzZSB0aGUgc2FtZSBnbG9iXG4gKiBzeW50YXggYXMgdGhlIGFsbG93LWxpc3QgKHNlZSBgYWxsb3dsaXN0LnRzYCkuIE9taXQgLyBgZmFsc2VgIGZvciBub1xuICogYXBwcm92YWwuIE5vcm1hbGl6ZWQgdG8gYW4ge0BsaW5rIEFwcHJvdmFsUG9saWN5fSBiZWZvcmUgdXNlLlxuICovXG5leHBvcnQgdHlwZSBBcHByb3ZhbEdhdGUgPSBib29sZWFuIHwgT25lT3JNYW55PHN0cmluZz4gfCBzdHJpbmc7XG5cbi8qKlxuICogVGhlIG5vcm1hbGl6ZWQgZm9ybSBvZiBhbiB7QGxpbmsgQXBwcm92YWxHYXRlfTogd2hpY2ggY2FsbHMgcGF1c2UgZm9yIGFcbiAqIGh1bWFuLiBgXCJub25lXCJgIHJ1bnMgZXZlcnkgY2FsbCBzdHJhaWdodCB0aHJvdWdoLCBgXCJhbHdheXNcImAgZ2F0ZXMgYWxsIG9mXG4gKiB0aGVtLCBhbmQgYFwidXJsc1wiYCBnYXRlcyBvbmx5IGNhbGxzIHdob3NlIFVSTCBtYXRjaGVzIG9uZSBvZiBgcGF0dGVybnNgLlxuICovXG5leHBvcnQgdHlwZSBBcHByb3ZhbFBvbGljeSA9XG4gIHwgeyByZWFkb25seSBtb2RlOiBcIm5vbmVcIiB9XG4gIHwgeyByZWFkb25seSBtb2RlOiBcImFsd2F5c1wiIH1cbiAgfCB7IHJlYWRvbmx5IG1vZGU6IFwidXJsc1wiOyByZWFkb25seSBwYXR0ZXJuczogcmVhZG9ubHkgc3RyaW5nW10gfTtcblxuLyoqXG4gKiBXaGljaCBVUkxzIHRoZSB0b29scyBtYXkgcmVhY2guIGBcImFsbG93bGlzdFwiYCBwZXJtaXRzIG9ubHkgdGhlIGNvbmZpZ3VyZWRcbiAqIGVudHJpZXM7IGBcInVucmVzdHJpY3RlZFwiYCBuYW1lcyB0aGUgcGVybWlzc2l2ZSBtb2RlIGV4cGxpY2l0bHksIHNvIGFuXG4gKiB1bnJlc3RyaWN0ZWQgZGVwbG95bWVudCBpcyBhIHN0YXRlZCBjaG9pY2UgdmlzaWJsZSBpbiB0aGUgYm9vdCBsb2cgcmF0aGVyXG4gKiB0aGFuIGFuIGVtcHR5IGxpc3Qgbm9ib2R5IG5vdGljZWQuXG4gKi9cbmV4cG9ydCB0eXBlIFVybFBvbGljeU1vZGUgPSBcInVucmVzdHJpY3RlZFwiIHwgXCJhbGxvd2xpc3RcIjtcblxuLyoqIERlZGljYXRlZCBvdmVycmlkZSBmb3IgdGhlIHdlYi1zZWFyY2ggZW5kcG9pbnQgaWQuICovXG5leHBvcnQgY29uc3QgTU9ERUxfRU5WID0gXCJXRUJfU0VBUkNIX01PREVMXCI7XG5cbi8qKiBBcHBLaXQncyBzdGFuZGFyZCBlbnZpcm9ubWVudCBuYW1lIGZvciBhIE1vZGVsIFNlcnZpbmcgZW5kcG9pbnQgYmluZGluZy4gKi9cbmV4cG9ydCBjb25zdCBTRVJWSU5HX0VORFBPSU5UX0VOViA9IFwiREFUQUJSSUNLU19TRVJWSU5HX0VORFBPSU5UX05BTUVcIjtcblxuLyoqIFdoZXJlIHRoZSBwaW5uZWQgd2ViLXNlYXJjaCBlbmRwb2ludCBpZCBjYW1lIGZyb20sIG9yIGBcIm5vbmVcImAgd2hlbiB1bnBpbm5lZC4gKi9cbmV4cG9ydCB0eXBlIE1vZGVsU291cmNlID0gXCJjb25maWdcIiB8IHR5cGVvZiBNT0RFTF9FTlYgfCB0eXBlb2YgU0VSVklOR19FTkRQT0lOVF9FTlYgfCBcIm5vbmVcIjtcblxuLyoqXG4gKiBEZWZhdWx0IHdlYi1zZWFyY2ggbW9kZWwgcHJlZmVyZW5jZSwgdHJpZWQgaW4gb3JkZXIgd2hlbiBubyBtb2RlbCBpc1xuICogcGlubmVkLiBHZW1pbmkgZmlyc3QsIHRoZW4gR1BUIC0gYm90aCBzdXBwb3J0IHRoZSBuYXRpdmUgd2ViLXNlYXJjaCB0b29sO1xuICogYSB3b3Jrc3BhY2UgdHlwaWNhbGx5IGhhcyBhdCBsZWFzdCBvbmUuIEVhY2ggaXMgZnV6enktbWF0Y2hlZCBhZ2FpbnN0IHRoZVxuICogbGl2ZSBjYXRhbG9ndWUsIHNvIGEgY2xvc2UgdmFyaWFudCAoZS5nLiBgZGF0YWJyaWNrcy1nZW1pbmktMy0xLXByb2ApIGlzXG4gKiBwaWNrZWQgd2hlbiB0aGUgZXhhY3QgaWQgaXNuJ3QgcHJlc2VudC5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfTU9ERUxfRkFMTEJBQ0tTOiByZWFkb25seSBzdHJpbmdbXSA9IFtcbiAgXCJkYXRhYnJpY2tzLWdlbWluaS0zLXByb1wiLFxuICBcImRhdGFicmlja3MtZ2VtaW5pLTItNS1wcm9cIixcbiAgXCJkYXRhYnJpY2tzLWdwdC01XCIsXG4gIFwiZGF0YWJyaWNrcy1ncHQtNS1taW5pXCIsXG5dO1xuXG4vKiogRGVmYXVsdCBjYXAgb24gdGhlIG51bWJlciBvZiBjaXRhdGlvbnMgcmV0dXJuZWQgZnJvbSBhIHNpbmdsZSBzZWFyY2guICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9NQVhfQ0lUQVRJT05TID0gMTA7XG5cbi8qKiBEZWZhdWx0IGNhcCBvbiBjaGFyYWN0ZXJzIHJldHVybmVkIGZyb20gYSBzaW5nbGUgYHdlYl9mZXRjaGAuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9GRVRDSF9NQVhfTEVOR1RIID0gNTBfMDAwO1xuXG4vKiogRGVmYXVsdCBwZXItcmVxdWVzdCBuZXR3b3JrIHRpbWVvdXQgKG1zKSBmb3Igc2VhcmNoICsgZmV0Y2guICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9USU1FT1VUX01TID0gMzBfMDAwO1xuXG4vKiogQXBwS2l0IGNvbmZpZyBhY2NlcHRlZCBieSB0aGUgd2ViLXNlYXJjaCBwbHVnaW4uICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYlNlYXJjaFBsdWdpbkNvbmZpZyBleHRlbmRzIEJhc2VQbHVnaW5Db25maWcge1xuICAvKipcbiAgICogVGhlIHdlYi1zZWFyY2ggbW9kZWwgdG8gdXNlIGJ5IGRlZmF1bHQ6IGEgRGF0YWJyaWNrcyBzZXJ2aW5nIGVuZHBvaW50XG4gICAqIG5hbWUgKGBcImRhdGFicmlja3MtZ2VtaW5pLTMtcHJvXCJgKSwgYSBsb29zZSBuYW1lIChgXCJnZW1pbmlcImAsIGBcImdwdFwiYCksXG4gICAqIG9yIGEgY2FwYWJpbGl0eSBjbGFzcy4gRnV6enktbWF0Y2hlZCBhZ2FpbnN0IHRoZSBsaXZlIGNhdGFsb2d1ZS4gRmFsbHNcbiAgICogYmFjayB0byBgV0VCX1NFQVJDSF9NT0RFTGAsIHRoZW4gYERBVEFCUklDS1NfU0VSVklOR19FTkRQT0lOVF9OQU1FYCwgdGhlblxuICAgKiB0aGUge0BsaW5rIG1vZGVsRmFsbGJhY2tzfSBvcmRlci4gQ2hvc2VuIGluZGVwZW5kZW50bHkgb2YgdGhlIGNhbGxpbmdcbiAgICogYWdlbnQncyBjaGF0IG1vZGVsLlxuICAgKi9cbiAgbW9kZWw/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBQcmlvcml0eS1vcmRlcmVkIHdlYi1zZWFyY2ggbW9kZWwgY2FuZGlkYXRlcyB0cmllZCB3aGVuIHtAbGluayBtb2RlbH0gaXNcbiAgICogdW5zZXQsIGVhY2ggZnV6enktbWF0Y2hlZCBhbmQgY2hlY2tlZCBmb3Igd2ViLXNlYXJjaCBzdXBwb3J0LiBGYWxscyBiYWNrXG4gICAqIHRvIGBXRUJfU0VBUkNIX01PREVMX0ZBTExCQUNLU2AgKGNvbW1hL3NwYWNlLXNlcGFyYXRlZCksIHRoZW5cbiAgICoge0BsaW5rIERFRkFVTFRfTU9ERUxfRkFMTEJBQ0tTfSAoR2VtaW5pLCB0aGVuIEdQVCkuXG4gICAqL1xuICBtb2RlbEZhbGxiYWNrcz86IHN0cmluZyB8IHN0cmluZ1tdO1xuICAvKipcbiAgICogUHJvdmlkZXIgLT4gdG9vbC1zcGVjIG92ZXJyaWRlIG1hcCwgbWVyZ2VkIG92ZXIgdGhlIGJ1aWx0LWluXG4gICAqIHtAbGluayBXRUJfU0VBUkNIX1BST1ZJREVSU30gZGVmYXVsdHMuIEtleWVkIGJ5IHByb3ZpZGVyIGZhbWlseVxuICAgKiAoYFwib3BlbmFpXCJgLCBgXCJnZW1pbmlcImApOyBlYWNoIHZhbHVlIG1heSBvdmVycmlkZSB0aGUgYHRvb2xgIGVudHJ5XG4gICAqIGFuZC9vciB0aGUgYGFwaWAgc3VyZmFjZS4gVXNlIHRvIGNoYW5nZSB0aGUgdG9vbCBzaGFwZSBhcyB0aGUgcGxhdGZvcm1cbiAgICogZXZvbHZlcyB3aXRob3V0IGEgY29kZSBjaGFuZ2UuIEZhbGxzIGJhY2sgdG8gYFdFQl9TRUFSQ0hfVE9PTFNgIHBhcnNlZCBhc1xuICAgKiBKU09OLiBUaGlzIGlzIHRoZSBgV0VCX1NFQVJDSF9UT09MU2Agc2V0dGluZy5cbiAgICovXG4gIHdlYlNlYXJjaFRvb2xzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIC8qKlxuICAgKiBFbmFibGUgZnV6enkgbWF0Y2hpbmcgb2YgbG9vc2UgbW9kZWwgbmFtZXMgYWdhaW5zdCB0aGUgY2F0YWxvZ3VlLlxuICAgKiBEZWZhdWx0cyB0byBgdHJ1ZWA7IGZhbGxzIGJhY2sgdG8gYFdFQl9TRUFSQ0hfRlVaWllgLlxuICAgKi9cbiAgbW9kZWxGdXp6eU1hdGNoPzogYm9vbGVhbjtcbiAgLyoqIEZ1c2UuanMgZnV6enkgdGhyZXNob2xkLiBGYWxscyBiYWNrIHRvIGBXRUJfU0VBUkNIX0ZVWlpZX1RIUkVTSE9MRGAsIHRoZW4gdGhlIHNoYXJlZCBkZWZhdWx0LiAqL1xuICBtb2RlbEZ1enp5VGhyZXNob2xkPzogbnVtYmVyO1xuICAvKipcbiAgICogSGFyZCBjYXAgb24gdGhlIG51bWJlciBvZiBjaXRhdGlvbnMgYSBzaW5nbGUgc2VhcmNoIHJldHVybnMuIEZhbGxzIGJhY2tcbiAgICogdG8gYFdFQl9TRUFSQ0hfTUFYX0NJVEFUSU9OU2AsIHRoZW4ge0BsaW5rIERFRkFVTFRfTUFYX0NJVEFUSU9OU30uXG4gICAqL1xuICBtYXhDaXRhdGlvbnM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBIYXJkIGNhcCBvbiB0aGUgY2hhcmFjdGVyIGxlbmd0aCBvZiBhIHNpbmdsZSBgd2ViX2ZldGNoYCByZXN1bHQuIEZhbGxzXG4gICAqIGJhY2sgdG8gYFdFQl9TRUFSQ0hfRkVUQ0hfTUFYX0xFTkdUSGAsIHRoZW4ge0BsaW5rIERFRkFVTFRfRkVUQ0hfTUFYX0xFTkdUSH0uXG4gICAqL1xuICBmZXRjaE1heExlbmd0aD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFBlci1yZXF1ZXN0IG5ldHdvcmsgdGltZW91dCBpbiBtcyBmb3Igc2VhcmNoICsgZmV0Y2guIEZhbGxzIGJhY2sgdG9cbiAgICogYFdFQl9TRUFSQ0hfVElNRU9VVF9NU2AsIHRoZW4ge0BsaW5rIERFRkFVTFRfVElNRU9VVF9NU30uXG4gICAqL1xuICB0aW1lb3V0TXM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBGYWxsIGJhY2sgdG8gYSBEdWNrRHVja0dvIHNjcmFwZSB3aGVuIHRoZSB3b3Jrc3BhY2UgaGFzIE5PIGRlcGxveWVkXG4gICAqIHdlYi1zZWFyY2gtY2FwYWJsZSBtb2RlbCAobm8gR1BUIC8gR2VtaW5pIHNlcnZpbmcgZW5kcG9pbnQpLiBUaGUgbmF0aXZlXG4gICAqIERhdGFicmlja3MgdG9vbCBpcyBhbHdheXMgcHJlZmVycmVkOyB0aGlzIG9ubHkga2lja3MgaW4gd2hlbiB0aGVyZSBpcyBub1xuICAgKiBuYXRpdmUgb3B0aW9uLCBzbyB0aGUgdG9vbCBzdGlsbCByZXR1cm5zIHJlc3VsdHMgaW5zdGVhZCBvZiBlcnJvcmluZy5cbiAgICogRGVmYXVsdHMgdG8gYHRydWVgOyBzZXQgYGZhbHNlYCAob3IgYFdFQl9TRUFSQ0hfU0NSQVBFX0ZBTExCQUNLPTBgKSB0b1xuICAgKiByZXF1aXJlIGEgbmF0aXZlIG1vZGVsIGFuZCBlcnJvciBvdGhlcndpc2UuXG4gICAqL1xuICBzY3JhcGVGYWxsYmFjaz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBXaGljaCBVUkxzIHRoZSB0b29scyBtYXkgcmVhY2ggKHtAbGluayBVcmxQb2xpY3lNb2RlfSkuIEZhbGxzIGJhY2sgdG9cbiAgICogYFdFQl9TRUFSQ0hfVVJMX1BPTElDWWAsIHRoZW4gdG8gYFwiYWxsb3dsaXN0XCJgIHdoZW4ge0BsaW5rIGFsbG93ZWRVcmxzfVxuICAgKiBoYXMgZW50cmllcyBhbmQgYFwidW5yZXN0cmljdGVkXCJgIHdoZW4gaXQgZG9lcyBub3QuIE5hbWluZyB0aGUgbW9kZVxuICAgKiBleHBsaWNpdGx5IGlzIHRoZSB3YXkgdG8gc3RhdGUgdGhhdCBhbiBvcGVuIGRlcGxveW1lbnQgaXMgaW50ZW5kZWQ7XG4gICAqIGBcImFsbG93bGlzdFwiYCB3aXRoIG5vIGVudHJpZXMsIG9yIGBcInVucmVzdHJpY3RlZFwiYCBhbG9uZ3NpZGUgZW50cmllcywgaXNcbiAgICogYSBjb250cmFkaWN0aW9uIGFuZCBmYWlscyBhdCByZXNvbHV0aW9uLlxuICAgKi9cbiAgdXJsUG9saWN5PzogVXJsUG9saWN5TW9kZTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIFVSTCBhbGxvdy1saXN0LiBFYWNoIGVudHJ5IGlzIGEgZ2xvYiAob3IgYmFyZSBob3N0KSB0ZXN0ZWRcbiAgICogYWdhaW5zdCBhIFVSTCdzIGZ1bGwgYGhyZWZgLiBXaGVuIHNldCwgYHdlYl9zZWFyY2hgIHNpbGVudGx5IGZpbHRlcnNcbiAgICogY2l0YXRpb25zIHRvIHRoZSBwZXJtaXR0ZWQgc2V0IGFuZCBgd2ViX2ZldGNoYCByZWZ1c2VzIGEgZGlzYWxsb3dlZCBVUkwuXG4gICAqIEFjY2VwdHMgYSBgc3RyaW5nW11gIG9yIGEgY29tbWEtL3doaXRlc3BhY2Utc2VwYXJhdGVkIHN0cmluZzsgZmFsbHMgYmFja1xuICAgKiB0byBgV0VCX1NFQVJDSF9BTExPV0VEX1VSTFNgLiBPbWl0IChvciBsZWF2ZSBlbXB0eSkgZm9yIG5vIHJlc3RyaWN0aW9uLlxuICAgKiBTZWUgYGFsbG93bGlzdC50c2AuXG4gICAqL1xuICBhbGxvd2VkVXJscz86IHN0cmluZyB8IHN0cmluZ1tdO1xuICAvKipcbiAgICogQXBwcm92YWwgZ2F0ZSBhcHBsaWVkIHRvIEJPVEggdG9vbHMgKHBlci10b29sIG92ZXJyaWRlcyB2aWFcbiAgICoge0BsaW5rIFdlYlNlYXJjaFRvb2xPcHRpb25zLmFwcHJvdmFsfSB3aW4pLiBgdHJ1ZWAgZ2F0ZXMgZXZlcnkgY2FsbDtcbiAgICogYSBVUkwtcGF0dGVybiAob3IgbGlzdCkgZ2F0ZXMgb25seSBtYXRjaGluZyBjYWxsczsgYW5cbiAgICoge0BsaW5rIEFwcHJvdmFsUG9saWN5fSBzdGF0ZXMgdGhlIG1vZGUgZGlyZWN0bHkuIE9taXQgZm9yIG5vIGFwcHJvdmFsLlxuICAgKi9cbiAgYXBwcm92YWw/OiBBcHByb3ZhbEdhdGUgfCBBcHByb3ZhbFBvbGljeTtcbn1cblxuLyoqIENvbmNyZXRlLCB2YWxpZGF0ZWQgY29uZmlnIHRoZSBydW50aW1lICsgdG9vbHMgcmVhZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZWRXZWJTZWFyY2hDb25maWcge1xuICAvKiogUGlubmVkIHdlYi1zZWFyY2ggbW9kZWwsIHdoZW4gY29uZmlndXJlZCAoZWxzZSB1bmRlZmluZWQgLSB1c2UgZmFsbGJhY2tzKS4gKi9cbiAgbW9kZWw/OiBzdHJpbmc7XG4gIC8qKiBXaGVyZSB7QGxpbmsgbW9kZWx9IGNhbWUgZnJvbSwgd2hpY2ggZGVjaWRlcyB3aGV0aGVyIGFuIHVuc3VwcG9ydGVkIHBpbiBpcyBmYXRhbC4gKi9cbiAgbW9kZWxTb3VyY2U6IE1vZGVsU291cmNlO1xuICAvKiogT3JkZXJlZCBmYWxsYmFjayBtb2RlbCBjYW5kaWRhdGVzIChHZW1pbmksIHRoZW4gR1BULCB0aGVuIGEgZmxvb3IpLiAqL1xuICBtb2RlbEZhbGxiYWNrczogcmVhZG9ubHkgc3RyaW5nW107XG4gIC8qKiBQcm92aWRlciAtPiB0b29sLXNwZWMgb3ZlcnJpZGUgbWFwLCBtZXJnZWQgb3ZlciB0aGUgYnVpbHQtaW4gZGVmYXVsdHMuICovXG4gIHdlYlNlYXJjaFRvb2xzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgLyoqIFdoZXRoZXIgdG8gZnV6enktbWF0Y2ggbG9vc2UgbW9kZWwgbmFtZXMuICovXG4gIGZ1enp5OiBib29sZWFuO1xuICAvKiogRnVzZS5qcyBmdXp6eSB0aHJlc2hvbGQuICovXG4gIGZ1enp5VGhyZXNob2xkOiBudW1iZXI7XG4gIG1heENpdGF0aW9uczogbnVtYmVyO1xuICBmZXRjaE1heExlbmd0aDogbnVtYmVyO1xuICB0aW1lb3V0TXM6IG51bWJlcjtcbiAgLyoqIFdoZXRoZXIgdG8gc2NyYXBlLWZhbGxiYWNrIHdoZW4gbm8gbmF0aXZlIHdlYi1zZWFyY2ggbW9kZWwgaXMgZGVwbG95ZWQuICovXG4gIHNjcmFwZUZhbGxiYWNrOiBib29sZWFuO1xuICAvKiogVGhlIG5hbWVkIFVSTCBwb2xpY3kgaW4gZm9yY2UuICovXG4gIHVybFBvbGljeTogVXJsUG9saWN5TW9kZTtcbiAgLyoqIENvbXBpbGVkIGFsbG93LWxpc3QgKHBlcm1pdC1hbGwgdW5kZXIgdGhlIGB1bnJlc3RyaWN0ZWRgIHBvbGljeSkuICovXG4gIGFsbG93TGlzdDogVXJsQWxsb3dMaXN0O1xuICAvKiogRGVmYXVsdCBwZXItdG9vbCBhcHByb3ZhbCBwb2xpY3kuICovXG4gIGFwcHJvdmFsOiBBcHByb3ZhbFBvbGljeTtcbn1cblxuLyoqIEpTT04gU2NoZW1hIHB1Ymxpc2hlZCBvbiB0aGUgbWFuaWZlc3QncyBgY29uZmlnLnNjaGVtYWAuICovXG5leHBvcnQgY29uc3QgV0VCX1NFQVJDSF9DT05GSUdfU0NIRU1BOiBKU09OU2NoZW1hNyA9IHtcbiAgdHlwZTogXCJvYmplY3RcIixcbiAgcHJvcGVydGllczoge1xuICAgIG1vZGVsOiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRGVmYXVsdCB3ZWItc2VhcmNoIG1vZGVsIChlbmRwb2ludCBuYW1lLCBsb29zZSBuYW1lLCBvciBjbGFzcykuIEZ1enp5LW1hdGNoZWQuIEVudjogV0VCX1NFQVJDSF9NT0RFTCwgdGhlbiBEQVRBQlJJQ0tTX1NFUlZJTkdfRU5EUE9JTlRfTkFNRS5cIixcbiAgICB9LFxuICAgIG1vZGVsRmFsbGJhY2tzOiB7XG4gICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICBpdGVtczogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJPcmRlcmVkIHdlYi1zZWFyY2ggbW9kZWwgY2FuZGlkYXRlcyB3aGVuIGBtb2RlbGAgaXMgdW5zZXQgKEdlbWluaSwgdGhlbiBHUFQpLiBFbnY6IFdFQl9TRUFSQ0hfTU9ERUxfRkFMTEJBQ0tTLlwiLFxuICAgIH0sXG4gICAgd2ViU2VhcmNoVG9vbHM6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1Byb3ZpZGVyIC0+IHRvb2wtc3BlYyBvdmVycmlkZSBtYXAgbWVyZ2VkIG92ZXIgdGhlIGJ1aWx0LWluIGRlZmF1bHRzIChvcGVuYWkgLT4ge1widHlwZVwiOlwid2ViX3NlYXJjaFwifSwgZ2VtaW5pIC0+IHtcImdvb2dsZV9zZWFyY2hcIjp7fX0pLiBFbnY6IFdFQl9TRUFSQ0hfVE9PTFMgKEpTT04pLicsXG4gICAgfSxcbiAgICBtb2RlbEZ1enp5TWF0Y2g6IHtcbiAgICAgIHR5cGU6IFwiYm9vbGVhblwiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRnV6enktbWF0Y2ggbG9vc2UgbW9kZWwgbmFtZXMgYWdhaW5zdCB0aGUgbGl2ZSBjYXRhbG9ndWUuIERlZmF1bHQgdHJ1ZSAoZW52OiBXRUJfU0VBUkNIX0ZVWlpZKS5cIixcbiAgICB9LFxuICAgIG1vZGVsRnV6enlUaHJlc2hvbGQ6IHtcbiAgICAgIHR5cGU6IFwibnVtYmVyXCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJGdXNlLmpzIHNjb3JlIHRocmVzaG9sZCBiZWxvdyB3aGljaCBhIGZ1enp5IG1vZGVsIG1hdGNoIGlzIGFjY2VwdGVkIChlbnY6IFdFQl9TRUFSQ0hfRlVaWllfVEhSRVNIT0xEKS5cIixcbiAgICB9LFxuICAgIG1heENpdGF0aW9uczoge1xuICAgICAgdHlwZTogXCJudW1iZXJcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkhhcmQgY2FwIG9uIGNpdGF0aW9ucyByZXR1cm5lZCAoZW52OiBXRUJfU0VBUkNIX01BWF9DSVRBVElPTlMpLlwiLFxuICAgIH0sXG4gICAgZmV0Y2hNYXhMZW5ndGg6IHtcbiAgICAgIHR5cGU6IFwibnVtYmVyXCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJIYXJkIGNhcCBvbiB3ZWJfZmV0Y2ggY29udGVudCBsZW5ndGggKGVudjogV0VCX1NFQVJDSF9GRVRDSF9NQVhfTEVOR1RIKS5cIixcbiAgICB9LFxuICAgIHRpbWVvdXRNczoge1xuICAgICAgdHlwZTogXCJudW1iZXJcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlBlci1yZXF1ZXN0IG5ldHdvcmsgdGltZW91dCBpbiBtcyAoZW52OiBXRUJfU0VBUkNIX1RJTUVPVVRfTVMpLlwiLFxuICAgIH0sXG4gICAgc2NyYXBlRmFsbGJhY2s6IHtcbiAgICAgIHR5cGU6IFwiYm9vbGVhblwiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRmFsbCBiYWNrIHRvIGEgRHVja0R1Y2tHbyBzY3JhcGUgd2hlbiBubyB3ZWItc2VhcmNoLWNhcGFibGUgbW9kZWwgaXMgZGVwbG95ZWQuIERlZmF1bHQgdHJ1ZSAoZW52OiBXRUJfU0VBUkNIX1NDUkFQRV9GQUxMQkFDSykuXCIsXG4gICAgfSxcbiAgICB1cmxQb2xpY3k6IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBlbnVtOiBbXCJ1bnJlc3RyaWN0ZWRcIiwgXCJhbGxvd2xpc3RcIl0sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJXaGljaCBVUkxzIHRoZSB0b29scyBtYXkgcmVhY2guIERlZmF1bHRzIHRvIGFsbG93bGlzdCB3aGVuIGFsbG93ZWRVcmxzIGhhcyBlbnRyaWVzLCBlbHNlIHVucmVzdHJpY3RlZCAoZW52OiBXRUJfU0VBUkNIX1VSTF9QT0xJQ1kpLlwiLFxuICAgIH0sXG4gICAgYWxsb3dlZFVybHM6IHtcbiAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgIGl0ZW1zOiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVVJMIGFsbG93LWxpc3Qgb2YgZ2xvYnMgLyBiYXJlIGhvc3RzIChlLmcuIFwiKi5kYXRhYnJpY2tzLmNvbVwiLCBcImRvY3MuZXhhbXBsZS5jb21cIikuIEFsc28gYWNjZXB0cyBhIGNvbW1hL3NwYWNlLXNlcGFyYXRlZCBzdHJpbmcuIEZhbGxzIGJhY2sgdG8gV0VCX1NFQVJDSF9BTExPV0VEX1VSTFMuIEVtcHR5ID0gdW5yZXN0cmljdGVkLicsXG4gICAgfSxcbiAgICBhcHByb3ZhbDoge1xuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBcHByb3ZhbCBnYXRlIGZvciBib3RoIHRvb2xzOiB0cnVlIGdhdGVzIGV2ZXJ5IGNhbGwsIGEgZ2xvYiAob3IgbGlzdCBvZiBnbG9icykgZ2F0ZXMgb25seSBtYXRjaGluZyBVUkxzLCBvciBzdGF0ZSB0aGUgbW9kZSBkaXJlY3RseSBhcyB7XCJtb2RlXCI6XCJub25lXCJ8XCJhbHdheXNcInxcInVybHNcIn0uIERlZmF1bHQgbm9uZS4nLFxuICAgICAgb25lT2Y6IFtcbiAgICAgICAgeyB0eXBlOiBcImJvb2xlYW5cIiB9LFxuICAgICAgICB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgeyB0eXBlOiBcImFycmF5XCIsIGl0ZW1zOiB7IHR5cGU6IFwic3RyaW5nXCIgfSB9LFxuICAgICAgICB7XG4gICAgICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBtb2RlOiB7IHR5cGU6IFwic3RyaW5nXCIsIGVudW06IFtcIm5vbmVcIiwgXCJhbHdheXNcIiwgXCJ1cmxzXCJdIH0sXG4gICAgICAgICAgICBwYXR0ZXJuczogeyB0eXBlOiBcImFycmF5XCIsIGl0ZW1zOiB7IHR5cGU6IFwic3RyaW5nXCIgfSB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgcmVxdWlyZWQ6IFtcIm1vZGVcIl0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0sXG4gIH0sXG59O1xuXG4vKiogUGFyc2UgYSBwb3NpdGl2ZSBpbnRlZ2VyIGVudi9jb25maWcgdmFsdWUsIGVsc2UgdGhlIGZhbGxiYWNrLiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVBvc2l0aXZlSW50KHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQsIGVudktleTogc3RyaW5nLCBmYWxsYmFjazogbnVtYmVyKTogbnVtYmVyIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIiAmJiBOdW1iZXIuaXNGaW5pdGUodmFsdWUpICYmIHZhbHVlID4gMCkgcmV0dXJuIE1hdGguZmxvb3IodmFsdWUpO1xuICBjb25zdCBlbnYgPSBOdW1iZXIocHJvY2Vzcy5lbnZbZW52S2V5XSk7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUoZW52KSAmJiBlbnYgPiAwID8gTWF0aC5mbG9vcihlbnYpIDogZmFsbGJhY2s7XG59XG5cbi8qKlxuICogUGFyc2UgdGhlIGBXRUJfU0VBUkNIX1RPT0xTYCBlbnYgdmFyIChKU09OIG9iamVjdCksIGVsc2UgYHt9YC4gQSB2YWx1ZSB0aGF0XG4gKiBpcyBzZXQgYnV0IG5vdCBhIEpTT04gb2JqZWN0IGlzIGEgZGVwbG95bWVudCBtaXN0YWtlIHRoYXQgd291bGQgb3RoZXJ3aXNlXG4gKiBzaWxlbnRseSBsZWF2ZSB0aGUgYnVpbHQtaW4gdG9vbCBzcGVjcyBpbiBwbGFjZSwgc28gaXQgdGhyb3dzLlxuICovXG5mdW5jdGlvbiBwYXJzZVRvb2xzRW52KCk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgY29uc3QgcmF3ID0gc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuV0VCX1NFQVJDSF9UT09MUyk7XG4gIGlmIChyYXcgPT09IG51bGwpIHJldHVybiB7fTtcbiAgY29uc3QgcGFyc2VkID0ganNvbi5wYXJzZVJlY29yZChyYXcpO1xuICBpZiAoIXBhcnNlZCkge1xuICAgIHRocm93IG5ldyBDb25maWd1cmF0aW9uRXJyb3IoXG4gICAgICBcIldFQl9TRUFSQ0hfVE9PTFMgbXVzdCBiZSBhIEpTT04gb2JqZWN0IG1hcHBpbmcgYSBwcm92aWRlciBmYW1pbHkgdG8gaXRzIHRvb2wgc3BlY1wiLFxuICAgICAgeyBjb250ZXh0OiB7IGVudlZhcjogXCJXRUJfU0VBUkNIX1RPT0xTXCIgfSB9LFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHBhcnNlZDtcbn1cblxuLyoqIFJlYWQgdGhlIHBpbm5lZCBlbmRwb2ludCBpZCBhbmQgcmVjb3JkIHdoaWNoIHNvdXJjZSBzdXBwbGllZCBpdC4gKi9cbmZ1bmN0aW9uIHJlc29sdmVNb2RlbFBpbihjb25maWc6IFdlYlNlYXJjaFBsdWdpbkNvbmZpZyk6IHsgbW9kZWw/OiBzdHJpbmc7IHNvdXJjZTogTW9kZWxTb3VyY2UgfSB7XG4gIGNvbnN0IGZyb21Db25maWcgPSBzdHJpbmcudHJpbVRvTnVsbChjb25maWcubW9kZWwpO1xuICBpZiAoZnJvbUNvbmZpZyAhPT0gbnVsbCkgcmV0dXJuIHsgbW9kZWw6IGZyb21Db25maWcsIHNvdXJjZTogXCJjb25maWdcIiB9O1xuICBjb25zdCBmcm9tTW9kZWxFbnYgPSBzdHJpbmcudHJpbVRvTnVsbChwcm9jZXNzLmVudltNT0RFTF9FTlZdKTtcbiAgaWYgKGZyb21Nb2RlbEVudiAhPT0gbnVsbCkgcmV0dXJuIHsgbW9kZWw6IGZyb21Nb2RlbEVudiwgc291cmNlOiBNT0RFTF9FTlYgfTtcbiAgY29uc3QgZnJvbVJlc291cmNlRW52ID0gc3RyaW5nLnRyaW1Ub051bGwocHJvY2Vzcy5lbnZbU0VSVklOR19FTkRQT0lOVF9FTlZdKTtcbiAgaWYgKGZyb21SZXNvdXJjZUVudiAhPT0gbnVsbCkgcmV0dXJuIHsgbW9kZWw6IGZyb21SZXNvdXJjZUVudiwgc291cmNlOiBTRVJWSU5HX0VORFBPSU5UX0VOViB9O1xuICByZXR1cm4geyBzb3VyY2U6IFwibm9uZVwiIH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgbmFtZWQge0BsaW5rIFVybFBvbGljeU1vZGV9LCBmYWlsaW5nIG9uIGEgc3RhdGVkIG1vZGUgdGhhdFxuICogY29udHJhZGljdHMgdGhlIGFsbG93LWxpc3QgZW50cmllcyBpdCB3YXMgZ2l2ZW4uXG4gKi9cbmZ1bmN0aW9uIHJlc29sdmVVcmxQb2xpY3koXG4gIGNvbmZpZ3VyZWQ6IFVybFBvbGljeU1vZGUgfCB1bmRlZmluZWQsXG4gIHBhdHRlcm5zOiByZWFkb25seSBzdHJpbmdbXSxcbik6IFVybFBvbGljeU1vZGUge1xuICBjb25zdCByYXcgPSBjb25maWd1cmVkID8/IHN0cmluZy50cmltVG9OdWxsKHByb2Nlc3MuZW52LldFQl9TRUFSQ0hfVVJMX1BPTElDWSkgPz8gdW5kZWZpbmVkO1xuICBpZiAocmF3ID09PSB1bmRlZmluZWQpIHJldHVybiBwYXR0ZXJucy5sZW5ndGggPiAwID8gXCJhbGxvd2xpc3RcIiA6IFwidW5yZXN0cmljdGVkXCI7XG4gIGlmIChyYXcgIT09IFwiYWxsb3dsaXN0XCIgJiYgcmF3ICE9PSBcInVucmVzdHJpY3RlZFwiKSB7XG4gICAgdGhyb3cgbmV3IENvbmZpZ3VyYXRpb25FcnJvcihcbiAgICAgICd1cmxQb2xpY3kgbXVzdCBiZSBcImFsbG93bGlzdFwiIG9yIFwidW5yZXN0cmljdGVkXCIgKGVudjogV0VCX1NFQVJDSF9VUkxfUE9MSUNZKScsXG4gICAgICB7IGNvbnRleHQ6IHsgZmllbGQ6IFwidXJsUG9saWN5XCIsIGVudlZhcjogXCJXRUJfU0VBUkNIX1VSTF9QT0xJQ1lcIiB9IH0sXG4gICAgKTtcbiAgfVxuICBpZiAocmF3ID09PSBcImFsbG93bGlzdFwiICYmIHBhdHRlcm5zLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBDb25maWd1cmF0aW9uRXJyb3IoXG4gICAgICAndXJsUG9saWN5IFwiYWxsb3dsaXN0XCIgbmVlZHMgYXQgbGVhc3Qgb25lIGVudHJ5IGluIGFsbG93ZWRVcmxzIChlbnY6IFdFQl9TRUFSQ0hfQUxMT1dFRF9VUkxTKScsXG4gICAgICB7IGNvbnRleHQ6IHsgZmllbGQ6IFwiYWxsb3dlZFVybHNcIiwgZW52VmFyOiBcIldFQl9TRUFSQ0hfQUxMT1dFRF9VUkxTXCIgfSB9LFxuICAgICk7XG4gIH1cbiAgaWYgKHJhdyA9PT0gXCJ1bnJlc3RyaWN0ZWRcIiAmJiBwYXR0ZXJucy5sZW5ndGggPiAwKSB7XG4gICAgdGhyb3cgbmV3IENvbmZpZ3VyYXRpb25FcnJvcihcbiAgICAgICd1cmxQb2xpY3kgXCJ1bnJlc3RyaWN0ZWRcIiBjYW5ub3QgYmUgY29tYmluZWQgd2l0aCBhbGxvd2VkVXJscyBlbnRyaWVzOyBkcm9wIHRoZSBlbnRyaWVzIG9yIHNldCB1cmxQb2xpY3kgdG8gXCJhbGxvd2xpc3RcIicsXG4gICAgICB7IGNvbnRleHQ6IHsgZmllbGQ6IFwiYWxsb3dlZFVybHNcIiwgZW52VmFyOiBcIldFQl9TRUFSQ0hfQUxMT1dFRF9VUkxTXCIgfSB9LFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHJhdztcbn1cblxuLyoqXG4gKiBOb3JtYWxpemUgYW55IGFjY2VwdGVkIGFwcHJvdmFsIHNwZWxsaW5nIGludG8gYW4ge0BsaW5rIEFwcHJvdmFsUG9saWN5fS5cbiAqIEEgcGF0dGVybiBnYXRlIHdpdGggbm8gdXNhYmxlIHBhdHRlcm5zIGNvbGxhcHNlcyB0byBgXCJub25lXCJgIHJhdGhlciB0aGFuXG4gKiBnYXRpbmcgZXZlcnl0aGluZywgc28gYSBibGFuayBlbnYgdmFyIGNhbiBuZXZlciB3ZWRnZSB0aGUgdG9vbHMgYmVoaW5kIGFuXG4gKiBhcHByb3ZhbCBub2JvZHkgY29uZmlndXJlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvQXBwcm92YWxQb2xpY3koZ2F0ZTogQXBwcm92YWxHYXRlIHwgQXBwcm92YWxQb2xpY3kgfCB1bmRlZmluZWQpOiBBcHByb3ZhbFBvbGljeSB7XG4gIGlmIChnYXRlID09PSB1bmRlZmluZWQgfHwgZ2F0ZSA9PT0gZmFsc2UpIHJldHVybiB7IG1vZGU6IFwibm9uZVwiIH07XG4gIGlmIChnYXRlID09PSB0cnVlKSByZXR1cm4geyBtb2RlOiBcImFsd2F5c1wiIH07XG4gIGlmIChvYmplY3QuaXNSZWNvcmQoZ2F0ZSkgJiYgXCJtb2RlXCIgaW4gZ2F0ZSkge1xuICAgIGlmIChnYXRlLm1vZGUgPT09IFwidXJsc1wiKSB7XG4gICAgICBjb25zdCBwYXR0ZXJucyA9IHBhcnNlQWxsb3dlZFVybHMoWy4uLmdhdGUucGF0dGVybnNdKTtcbiAgICAgIHJldHVybiBwYXR0ZXJucy5sZW5ndGggPiAwID8geyBtb2RlOiBcInVybHNcIiwgcGF0dGVybnMgfSA6IHsgbW9kZTogXCJub25lXCIgfTtcbiAgICB9XG4gICAgaWYgKGdhdGUubW9kZSA9PT0gXCJhbHdheXNcIiB8fCBnYXRlLm1vZGUgPT09IFwibm9uZVwiKSByZXR1cm4geyBtb2RlOiBnYXRlLm1vZGUgfTtcbiAgICB0aHJvdyBuZXcgQ29uZmlndXJhdGlvbkVycm9yKCdhcHByb3ZhbCBtb2RlIG11c3QgYmUgXCJub25lXCIsIFwiYWx3YXlzXCIgb3IgXCJ1cmxzXCInLCB7XG4gICAgICBjb250ZXh0OiB7IGZpZWxkOiBcImFwcHJvdmFsXCIgfSxcbiAgICB9KTtcbiAgfVxuICBjb25zdCBwYXR0ZXJucyA9IHBhcnNlQWxsb3dlZFVybHModHlwZW9mIGdhdGUgPT09IFwic3RyaW5nXCIgPyBnYXRlIDogWy4uLmdhdGVdKTtcbiAgcmV0dXJuIHBhdHRlcm5zLmxlbmd0aCA+IDAgPyB7IG1vZGU6IFwidXJsc1wiLCBwYXR0ZXJucyB9IDogeyBtb2RlOiBcIm5vbmVcIiB9O1xufVxuXG4vKipcbiAqIFJlc29sdmUgcGx1Z2luIGNvbmZpZyBvdmVyIGVudmlyb25tZW50IGRlZmF1bHRzIGludG8gdGhlIGNvbmNyZXRlXG4gKiB7QGxpbmsgUmVzb2x2ZWRXZWJTZWFyY2hDb25maWd9LiBXaGljaCBtb2RlbCBpcyB1c2VkIHN0YXlzIGxhenkgLSBpdCBpc1xuICogcGlja2VkIGF0IGNhbGwgdGltZSBhZ2FpbnN0IHRoZSBsaXZlIGNhdGFsb2d1ZSAtIGJ1dCBldmVyeXRoaW5nIGVsc2UgaXNcbiAqIHNldHRsZWQgaGVyZSwgYW5kIGEgY29udHJhZGljdGlvbiAodW5wYXJzZWFibGUgYFdFQl9TRUFSQ0hfVE9PTFNgLCBhblxuICogdW5rbm93biBVUkwgcG9saWN5LCBhIHBvbGljeSB0aGF0IGRpc2FncmVlcyB3aXRoIGl0cyBhbGxvdy1saXN0KSB0aHJvd3MgYVxuICoge0BsaW5rIENvbmZpZ3VyYXRpb25FcnJvcn0gbmFtaW5nIHRoZSBmaWVsZCBhbmQgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVdlYlNlYXJjaENvbmZpZyhcbiAgY29uZmlnOiBXZWJTZWFyY2hQbHVnaW5Db25maWcgPSB7fSxcbik6IFJlc29sdmVkV2ViU2VhcmNoQ29uZmlnIHtcbiAgY29uc3QgcGF0dGVybnMgPSBwYXJzZUFsbG93ZWRVcmxzKGNvbmZpZy5hbGxvd2VkVXJscyA/PyBwcm9jZXNzLmVudi5XRUJfU0VBUkNIX0FMTE9XRURfVVJMUyk7XG4gIGNvbnN0IHVybFBvbGljeSA9IHJlc29sdmVVcmxQb2xpY3koY29uZmlnLnVybFBvbGljeSwgcGF0dGVybnMpO1xuICBjb25zdCB7IG1vZGVsLCBzb3VyY2UgfSA9IHJlc29sdmVNb2RlbFBpbihjb25maWcpO1xuICBjb25zdCBmYWxsYmFja3MgPSBzdHJpbmcucGFyc2VMaXN0KFxuICAgIGNvbmZpZy5tb2RlbEZhbGxiYWNrcyA/PyBwcm9jZXNzLmVudi5XRUJfU0VBUkNIX01PREVMX0ZBTExCQUNLUyxcbiAgKTtcbiAgY29uc3QgZnV6enlUaHJlc2hvbGRSYXcgPVxuICAgIGNvbmZpZy5tb2RlbEZ1enp5VGhyZXNob2xkID8/IE51bWJlcihwcm9jZXNzLmVudi5XRUJfU0VBUkNIX0ZVWlpZX1RIUkVTSE9MRCk7XG4gIHJldHVybiB7XG4gICAgLi4uKG1vZGVsID8geyBtb2RlbCB9IDoge30pLFxuICAgIG1vZGVsU291cmNlOiBzb3VyY2UsXG4gICAgbW9kZWxGYWxsYmFja3M6IGZhbGxiYWNrcy5sZW5ndGggPiAwID8gZmFsbGJhY2tzIDogREVGQVVMVF9NT0RFTF9GQUxMQkFDS1MsXG4gICAgd2ViU2VhcmNoVG9vbHM6IHsgLi4ucGFyc2VUb29sc0VudigpLCAuLi4oY29uZmlnLndlYlNlYXJjaFRvb2xzID8/IHt9KSB9LFxuICAgIGZ1enp5OiBjb25maWcubW9kZWxGdXp6eU1hdGNoID8/IG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuV0VCX1NFQVJDSF9GVVpaWSkgPz8gdHJ1ZSxcbiAgICBmdXp6eVRocmVzaG9sZDpcbiAgICAgIE51bWJlci5pc0Zpbml0ZShmdXp6eVRocmVzaG9sZFJhdykgJiYgZnV6enlUaHJlc2hvbGRSYXdcbiAgICAgICAgPyBOdW1iZXIoZnV6enlUaHJlc2hvbGRSYXcpXG4gICAgICAgIDogc2VydmluZy5ERUZBVUxUX0ZVWlpZX1RIUkVTSE9MRCxcbiAgICBtYXhDaXRhdGlvbnM6IHJlc29sdmVQb3NpdGl2ZUludChcbiAgICAgIGNvbmZpZy5tYXhDaXRhdGlvbnMsXG4gICAgICBcIldFQl9TRUFSQ0hfTUFYX0NJVEFUSU9OU1wiLFxuICAgICAgREVGQVVMVF9NQVhfQ0lUQVRJT05TLFxuICAgICksXG4gICAgZmV0Y2hNYXhMZW5ndGg6IHJlc29sdmVQb3NpdGl2ZUludChcbiAgICAgIGNvbmZpZy5mZXRjaE1heExlbmd0aCxcbiAgICAgIFwiV0VCX1NFQVJDSF9GRVRDSF9NQVhfTEVOR1RIXCIsXG4gICAgICBERUZBVUxUX0ZFVENIX01BWF9MRU5HVEgsXG4gICAgKSxcbiAgICB0aW1lb3V0TXM6IHJlc29sdmVQb3NpdGl2ZUludChjb25maWcudGltZW91dE1zLCBcIldFQl9TRUFSQ0hfVElNRU9VVF9NU1wiLCBERUZBVUxUX1RJTUVPVVRfTVMpLFxuICAgIHNjcmFwZUZhbGxiYWNrOlxuICAgICAgY29uZmlnLnNjcmFwZUZhbGxiYWNrID8/IG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuV0VCX1NFQVJDSF9TQ1JBUEVfRkFMTEJBQ0spID8/IHRydWUsXG4gICAgdXJsUG9saWN5LFxuICAgIGFsbG93TGlzdDogdG9VcmxBbGxvd0xpc3QodXJsUG9saWN5ID09PSBcImFsbG93bGlzdFwiID8gcGF0dGVybnMgOiBbXSksXG4gICAgYXBwcm92YWw6IHRvQXBwcm92YWxQb2xpY3koY29uZmlnLmFwcHJvdmFsKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGFuIGFwcHJvdmFsIGdhdGUgYWdhaW5zdCBhIHNldCBvZiBjYW5kaWRhdGUgVVJMcyBpbnRvIGEgY29uY3JldGVcbiAqIGJvb2xlYW46IGBcIm5vbmVcImAgLyBgXCJhbHdheXNcImAgcGFzcyBzdHJhaWdodCB0aHJvdWdoOyBhIGBcInVybHNcImAgcG9saWN5XG4gKiBnYXRlcyB3aGVuIEFOWSBjYW5kaWRhdGUgbWF0Y2hlcy4gRW1wdHkgY2FuZGlkYXRlcyB3aXRoIGEgcGF0dGVybiBnYXRlXG4gKiBuZXZlciBtYXRjaCAobm90aGluZyB0byBhcHByb3ZlKS4gUmV1c2VzIHRoZSBhbGxvdy1saXN0IG1hdGNoZXIgc28gYXBwcm92YWxcbiAqIGdsb2JzIHJlYWQgZXhhY3RseSBsaWtlIGFsbG93LWxpc3QgZ2xvYnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHByb3ZhbE1hdGNoZXMoXG4gIGdhdGU6IEFwcHJvdmFsR2F0ZSB8IEFwcHJvdmFsUG9saWN5LFxuICB1cmxzOiByZWFkb25seSBzdHJpbmdbXSxcbik6IGJvb2xlYW4ge1xuICBjb25zdCBwb2xpY3kgPSB0b0FwcHJvdmFsUG9saWN5KGdhdGUpO1xuICBpZiAocG9saWN5Lm1vZGUgPT09IFwibm9uZVwiKSByZXR1cm4gZmFsc2U7XG4gIGlmIChwb2xpY3kubW9kZSA9PT0gXCJhbHdheXNcIikgcmV0dXJuIHRydWU7XG4gIGNvbnN0IGxpc3QgPSB0b1VybEFsbG93TGlzdChwb2xpY3kucGF0dGVybnMpO1xuICByZXR1cm4gdXJscy5zb21lKCh1cmwpID0+IGxpc3QuYWxsb3dzKHVybCkpO1xufVxuIl19
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interceptor settings for the add-on's three outbound calls: the native
|
|
3
|
+
* web-search POST to Model Serving, the `web_fetch` page read, and the
|
|
4
|
+
* DuckDuckGo scrape fallback. They live here, in the sibling `defaults.ts`
|
|
5
|
+
* AppKit plugins keep, so a TTL or retry budget is tuned in one place instead
|
|
6
|
+
* of at a call site.
|
|
7
|
+
*
|
|
8
|
+
* All three are idempotent READS: none of them create or mutate anything, so
|
|
9
|
+
* both caching and retrying are safe. Each constant below records why its
|
|
10
|
+
* numbers were chosen.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The `PluginExecuteConfig` slice this package sets. Mirrored structurally
|
|
16
|
+
* because AppKit's `PluginExecuteConfig` lives behind a subpath its `exports`
|
|
17
|
+
* map does not publish, so the nominal type cannot be imported.
|
|
18
|
+
*/
|
|
19
|
+
export type WebSearchExecuteConfig = {
|
|
20
|
+
cache?: {
|
|
21
|
+
enabled?: boolean;
|
|
22
|
+
ttl?: number;
|
|
23
|
+
cacheKey?: (string | number | object)[];
|
|
24
|
+
};
|
|
25
|
+
retry?: {
|
|
26
|
+
enabled?: boolean;
|
|
27
|
+
attempts?: number;
|
|
28
|
+
initialDelay?: number;
|
|
29
|
+
maxDelay?: number;
|
|
30
|
+
};
|
|
31
|
+
timeout?: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The `PluginExecutionSettings` shape accepted by AppKit's `Plugin.execute()`.
|
|
35
|
+
* Mirrored structurally for the same reason as {@link WebSearchExecuteConfig}.
|
|
36
|
+
*/
|
|
37
|
+
export type WebSearchExecutionSettings = {
|
|
38
|
+
default: WebSearchExecuteConfig;
|
|
39
|
+
user?: WebSearchExecuteConfig;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Cache lifetime for a native web-search answer. Long enough that a model
|
|
43
|
+
* re-asking the same question inside one conversation does not pay for a
|
|
44
|
+
* second serving call, short enough that "current information" stays current.
|
|
45
|
+
*/
|
|
46
|
+
export declare const SEARCH_CACHE_TTL_SECONDS = 300;
|
|
47
|
+
/**
|
|
48
|
+
* Cache lifetime for a fetched page. Pages move more slowly than search
|
|
49
|
+
* results, and an agent commonly re-reads the same source across turns.
|
|
50
|
+
*/
|
|
51
|
+
export declare const FETCH_CACHE_TTL_SECONDS = 900;
|
|
52
|
+
/**
|
|
53
|
+
* Attempts for a serving call. Model Serving sheds load with 429 / 503 under
|
|
54
|
+
* contention; three attempts with AppKit's exponential backoff and full jitter
|
|
55
|
+
* clears that without turning a genuine outage into a long stall.
|
|
56
|
+
*/
|
|
57
|
+
export declare const SERVING_RETRY_ATTEMPTS = 3;
|
|
58
|
+
/**
|
|
59
|
+
* Attempts for an open-web request. Kept lower than the serving budget: a
|
|
60
|
+
* remote site that refuses once usually refuses again, and the caller is
|
|
61
|
+
* waiting on an interactive tool call.
|
|
62
|
+
*/
|
|
63
|
+
export declare const WEB_RETRY_ATTEMPTS = 2;
|
|
64
|
+
/**
|
|
65
|
+
* Settings for the native web-search POST to Model Serving.
|
|
66
|
+
*
|
|
67
|
+
* Cache enabled: the POST is a pure read of the model's answer for one query,
|
|
68
|
+
* and repeat asks of the same question are common in a multi-turn agent.
|
|
69
|
+
* Retry enabled: the POST creates no conversation or state, so replaying it
|
|
70
|
+
* after a transient 429 / 5xx is safe.
|
|
71
|
+
*/
|
|
72
|
+
export declare const webSearchExecuteDefaults: WebSearchExecutionSettings;
|
|
73
|
+
/**
|
|
74
|
+
* Settings for a `web_fetch` page read.
|
|
75
|
+
*
|
|
76
|
+
* Cache enabled: fetching a URL is a read, and an agent that searches then
|
|
77
|
+
* reads its own citations hits the same page repeatedly.
|
|
78
|
+
* Retry enabled: a GET is idempotent, so a dropped connection is worth one
|
|
79
|
+
* more attempt.
|
|
80
|
+
*/
|
|
81
|
+
export declare const webFetchExecuteDefaults: WebSearchExecutionSettings;
|
|
82
|
+
/**
|
|
83
|
+
* Settings for the DuckDuckGo scrape fallback. Same read semantics as the
|
|
84
|
+
* native search, and the shorter cache lifetime applies for the same reason,
|
|
85
|
+
* but the retry budget follows the open-web one: DuckDuckGo answers a repeat
|
|
86
|
+
* request with a bot challenge rather than results.
|
|
87
|
+
*/
|
|
88
|
+
export declare const scrapeSearchExecuteDefaults: WebSearchExecutionSettings;
|
|
89
|
+
/**
|
|
90
|
+
* Bind one of the named defaults to a single call: the configured network
|
|
91
|
+
* timeout and the cache key for this request.
|
|
92
|
+
*
|
|
93
|
+
* AppKit only installs the cache interceptor when a non-empty `cacheKey` is
|
|
94
|
+
* present, so every cached call has to name its own key parts. The per-user
|
|
95
|
+
* half of the key is added by `execute()` from the active execution context,
|
|
96
|
+
* which is what keeps an OBO result from leaking across identities.
|
|
97
|
+
*/
|
|
98
|
+
export declare function toCallSettings(base: WebSearchExecutionSettings, timeoutMs: number, cacheKey: readonly (string | number)[]): WebSearchExecutionSettings;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interceptor settings for the add-on's three outbound calls: the native
|
|
3
|
+
* web-search POST to Model Serving, the `web_fetch` page read, and the
|
|
4
|
+
* DuckDuckGo scrape fallback. They live here, in the sibling `defaults.ts`
|
|
5
|
+
* AppKit plugins keep, so a TTL or retry budget is tuned in one place instead
|
|
6
|
+
* of at a call site.
|
|
7
|
+
*
|
|
8
|
+
* All three are idempotent READS: none of them create or mutate anything, so
|
|
9
|
+
* both caching and retrying are safe. Each constant below records why its
|
|
10
|
+
* numbers were chosen.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Cache lifetime for a native web-search answer. Long enough that a model
|
|
16
|
+
* re-asking the same question inside one conversation does not pay for a
|
|
17
|
+
* second serving call, short enough that "current information" stays current.
|
|
18
|
+
*/
|
|
19
|
+
export const SEARCH_CACHE_TTL_SECONDS = 300;
|
|
20
|
+
/**
|
|
21
|
+
* Cache lifetime for a fetched page. Pages move more slowly than search
|
|
22
|
+
* results, and an agent commonly re-reads the same source across turns.
|
|
23
|
+
*/
|
|
24
|
+
export const FETCH_CACHE_TTL_SECONDS = 900;
|
|
25
|
+
/**
|
|
26
|
+
* Attempts for a serving call. Model Serving sheds load with 429 / 503 under
|
|
27
|
+
* contention; three attempts with AppKit's exponential backoff and full jitter
|
|
28
|
+
* clears that without turning a genuine outage into a long stall.
|
|
29
|
+
*/
|
|
30
|
+
export const SERVING_RETRY_ATTEMPTS = 3;
|
|
31
|
+
/**
|
|
32
|
+
* Attempts for an open-web request. Kept lower than the serving budget: a
|
|
33
|
+
* remote site that refuses once usually refuses again, and the caller is
|
|
34
|
+
* waiting on an interactive tool call.
|
|
35
|
+
*/
|
|
36
|
+
export const WEB_RETRY_ATTEMPTS = 2;
|
|
37
|
+
/**
|
|
38
|
+
* Settings for the native web-search POST to Model Serving.
|
|
39
|
+
*
|
|
40
|
+
* Cache enabled: the POST is a pure read of the model's answer for one query,
|
|
41
|
+
* and repeat asks of the same question are common in a multi-turn agent.
|
|
42
|
+
* Retry enabled: the POST creates no conversation or state, so replaying it
|
|
43
|
+
* after a transient 429 / 5xx is safe.
|
|
44
|
+
*/
|
|
45
|
+
export const webSearchExecuteDefaults = {
|
|
46
|
+
default: {
|
|
47
|
+
cache: { enabled: true, ttl: SEARCH_CACHE_TTL_SECONDS },
|
|
48
|
+
retry: { enabled: true, attempts: SERVING_RETRY_ATTEMPTS },
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Settings for a `web_fetch` page read.
|
|
53
|
+
*
|
|
54
|
+
* Cache enabled: fetching a URL is a read, and an agent that searches then
|
|
55
|
+
* reads its own citations hits the same page repeatedly.
|
|
56
|
+
* Retry enabled: a GET is idempotent, so a dropped connection is worth one
|
|
57
|
+
* more attempt.
|
|
58
|
+
*/
|
|
59
|
+
export const webFetchExecuteDefaults = {
|
|
60
|
+
default: {
|
|
61
|
+
cache: { enabled: true, ttl: FETCH_CACHE_TTL_SECONDS },
|
|
62
|
+
retry: { enabled: true, attempts: WEB_RETRY_ATTEMPTS },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Settings for the DuckDuckGo scrape fallback. Same read semantics as the
|
|
67
|
+
* native search, and the shorter cache lifetime applies for the same reason,
|
|
68
|
+
* but the retry budget follows the open-web one: DuckDuckGo answers a repeat
|
|
69
|
+
* request with a bot challenge rather than results.
|
|
70
|
+
*/
|
|
71
|
+
export const scrapeSearchExecuteDefaults = {
|
|
72
|
+
default: {
|
|
73
|
+
cache: { enabled: true, ttl: SEARCH_CACHE_TTL_SECONDS },
|
|
74
|
+
retry: { enabled: true, attempts: WEB_RETRY_ATTEMPTS },
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Bind one of the named defaults to a single call: the configured network
|
|
79
|
+
* timeout and the cache key for this request.
|
|
80
|
+
*
|
|
81
|
+
* AppKit only installs the cache interceptor when a non-empty `cacheKey` is
|
|
82
|
+
* present, so every cached call has to name its own key parts. The per-user
|
|
83
|
+
* half of the key is added by `execute()` from the active execution context,
|
|
84
|
+
* which is what keeps an OBO result from leaking across identities.
|
|
85
|
+
*/
|
|
86
|
+
export function toCallSettings(base, timeoutMs, cacheKey) {
|
|
87
|
+
return {
|
|
88
|
+
default: {
|
|
89
|
+
...base.default,
|
|
90
|
+
cache: { ...base.default.cache, cacheKey: [...cacheKey] },
|
|
91
|
+
timeout: timeoutMs,
|
|
92
|
+
},
|
|
93
|
+
...(base.user ? { user: base.user } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGVmYXVsdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBc0JIOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLENBQUM7QUFFNUM7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsR0FBRyxDQUFDO0FBRTNDOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLENBQUM7QUFFeEM7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQztBQUVwQzs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQStCO0lBQ2xFLE9BQU8sRUFBRTtRQUNQLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLHdCQUF3QixFQUFFO1FBQ3ZELEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLHNCQUFzQixFQUFFO0tBQzNEO0NBQ0YsQ0FBQztBQUVGOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBK0I7SUFDakUsT0FBTyxFQUFFO1FBQ1AsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsdUJBQXVCLEVBQUU7UUFDdEQsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsa0JBQWtCLEVBQUU7S0FDdkQ7Q0FDRixDQUFDO0FBRUY7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSwyQkFBMkIsR0FBK0I7SUFDckUsT0FBTyxFQUFFO1FBQ1AsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsd0JBQXdCLEVBQUU7UUFDdkQsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsa0JBQWtCLEVBQUU7S0FDdkQ7Q0FDRixDQUFDO0FBRUY7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUM1QixJQUFnQyxFQUNoQyxTQUFpQixFQUNqQixRQUFzQztJQUV0QyxPQUFPO1FBQ0wsT0FBTyxFQUFFO1lBQ1AsR0FBRyxJQUFJLENBQUMsT0FBTztZQUNmLEtBQUssRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsRUFBRTtZQUN6RCxPQUFPLEVBQUUsU0FBUztTQUNuQjtRQUNELEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUMxQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogSW50ZXJjZXB0b3Igc2V0dGluZ3MgZm9yIHRoZSBhZGQtb24ncyB0aHJlZSBvdXRib3VuZCBjYWxsczogdGhlIG5hdGl2ZVxuICogd2ViLXNlYXJjaCBQT1NUIHRvIE1vZGVsIFNlcnZpbmcsIHRoZSBgd2ViX2ZldGNoYCBwYWdlIHJlYWQsIGFuZCB0aGVcbiAqIER1Y2tEdWNrR28gc2NyYXBlIGZhbGxiYWNrLiBUaGV5IGxpdmUgaGVyZSwgaW4gdGhlIHNpYmxpbmcgYGRlZmF1bHRzLnRzYFxuICogQXBwS2l0IHBsdWdpbnMga2VlcCwgc28gYSBUVEwgb3IgcmV0cnkgYnVkZ2V0IGlzIHR1bmVkIGluIG9uZSBwbGFjZSBpbnN0ZWFkXG4gKiBvZiBhdCBhIGNhbGwgc2l0ZS5cbiAqXG4gKiBBbGwgdGhyZWUgYXJlIGlkZW1wb3RlbnQgUkVBRFM6IG5vbmUgb2YgdGhlbSBjcmVhdGUgb3IgbXV0YXRlIGFueXRoaW5nLCBzb1xuICogYm90aCBjYWNoaW5nIGFuZCByZXRyeWluZyBhcmUgc2FmZS4gRWFjaCBjb25zdGFudCBiZWxvdyByZWNvcmRzIHdoeSBpdHNcbiAqIG51bWJlcnMgd2VyZSBjaG9zZW4uXG4gKlxuICogQG1vZHVsZVxuICovXG5cbi8qKlxuICogVGhlIGBQbHVnaW5FeGVjdXRlQ29uZmlnYCBzbGljZSB0aGlzIHBhY2thZ2Ugc2V0cy4gTWlycm9yZWQgc3RydWN0dXJhbGx5XG4gKiBiZWNhdXNlIEFwcEtpdCdzIGBQbHVnaW5FeGVjdXRlQ29uZmlnYCBsaXZlcyBiZWhpbmQgYSBzdWJwYXRoIGl0cyBgZXhwb3J0c2BcbiAqIG1hcCBkb2VzIG5vdCBwdWJsaXNoLCBzbyB0aGUgbm9taW5hbCB0eXBlIGNhbm5vdCBiZSBpbXBvcnRlZC5cbiAqL1xuZXhwb3J0IHR5cGUgV2ViU2VhcmNoRXhlY3V0ZUNvbmZpZyA9IHtcbiAgY2FjaGU/OiB7IGVuYWJsZWQ/OiBib29sZWFuOyB0dGw/OiBudW1iZXI7IGNhY2hlS2V5PzogKHN0cmluZyB8IG51bWJlciB8IG9iamVjdClbXSB9O1xuICByZXRyeT86IHsgZW5hYmxlZD86IGJvb2xlYW47IGF0dGVtcHRzPzogbnVtYmVyOyBpbml0aWFsRGVsYXk/OiBudW1iZXI7IG1heERlbGF5PzogbnVtYmVyIH07XG4gIHRpbWVvdXQ/OiBudW1iZXI7XG59O1xuXG4vKipcbiAqIFRoZSBgUGx1Z2luRXhlY3V0aW9uU2V0dGluZ3NgIHNoYXBlIGFjY2VwdGVkIGJ5IEFwcEtpdCdzIGBQbHVnaW4uZXhlY3V0ZSgpYC5cbiAqIE1pcnJvcmVkIHN0cnVjdHVyYWxseSBmb3IgdGhlIHNhbWUgcmVhc29uIGFzIHtAbGluayBXZWJTZWFyY2hFeGVjdXRlQ29uZmlnfS5cbiAqL1xuZXhwb3J0IHR5cGUgV2ViU2VhcmNoRXhlY3V0aW9uU2V0dGluZ3MgPSB7XG4gIGRlZmF1bHQ6IFdlYlNlYXJjaEV4ZWN1dGVDb25maWc7XG4gIHVzZXI/OiBXZWJTZWFyY2hFeGVjdXRlQ29uZmlnO1xufTtcblxuLyoqXG4gKiBDYWNoZSBsaWZldGltZSBmb3IgYSBuYXRpdmUgd2ViLXNlYXJjaCBhbnN3ZXIuIExvbmcgZW5vdWdoIHRoYXQgYSBtb2RlbFxuICogcmUtYXNraW5nIHRoZSBzYW1lIHF1ZXN0aW9uIGluc2lkZSBvbmUgY29udmVyc2F0aW9uIGRvZXMgbm90IHBheSBmb3IgYVxuICogc2Vjb25kIHNlcnZpbmcgY2FsbCwgc2hvcnQgZW5vdWdoIHRoYXQgXCJjdXJyZW50IGluZm9ybWF0aW9uXCIgc3RheXMgY3VycmVudC5cbiAqL1xuZXhwb3J0IGNvbnN0IFNFQVJDSF9DQUNIRV9UVExfU0VDT05EUyA9IDMwMDtcblxuLyoqXG4gKiBDYWNoZSBsaWZldGltZSBmb3IgYSBmZXRjaGVkIHBhZ2UuIFBhZ2VzIG1vdmUgbW9yZSBzbG93bHkgdGhhbiBzZWFyY2hcbiAqIHJlc3VsdHMsIGFuZCBhbiBhZ2VudCBjb21tb25seSByZS1yZWFkcyB0aGUgc2FtZSBzb3VyY2UgYWNyb3NzIHR1cm5zLlxuICovXG5leHBvcnQgY29uc3QgRkVUQ0hfQ0FDSEVfVFRMX1NFQ09ORFMgPSA5MDA7XG5cbi8qKlxuICogQXR0ZW1wdHMgZm9yIGEgc2VydmluZyBjYWxsLiBNb2RlbCBTZXJ2aW5nIHNoZWRzIGxvYWQgd2l0aCA0MjkgLyA1MDMgdW5kZXJcbiAqIGNvbnRlbnRpb247IHRocmVlIGF0dGVtcHRzIHdpdGggQXBwS2l0J3MgZXhwb25lbnRpYWwgYmFja29mZiBhbmQgZnVsbCBqaXR0ZXJcbiAqIGNsZWFycyB0aGF0IHdpdGhvdXQgdHVybmluZyBhIGdlbnVpbmUgb3V0YWdlIGludG8gYSBsb25nIHN0YWxsLlxuICovXG5leHBvcnQgY29uc3QgU0VSVklOR19SRVRSWV9BVFRFTVBUUyA9IDM7XG5cbi8qKlxuICogQXR0ZW1wdHMgZm9yIGFuIG9wZW4td2ViIHJlcXVlc3QuIEtlcHQgbG93ZXIgdGhhbiB0aGUgc2VydmluZyBidWRnZXQ6IGFcbiAqIHJlbW90ZSBzaXRlIHRoYXQgcmVmdXNlcyBvbmNlIHVzdWFsbHkgcmVmdXNlcyBhZ2FpbiwgYW5kIHRoZSBjYWxsZXIgaXNcbiAqIHdhaXRpbmcgb24gYW4gaW50ZXJhY3RpdmUgdG9vbCBjYWxsLlxuICovXG5leHBvcnQgY29uc3QgV0VCX1JFVFJZX0FUVEVNUFRTID0gMjtcblxuLyoqXG4gKiBTZXR0aW5ncyBmb3IgdGhlIG5hdGl2ZSB3ZWItc2VhcmNoIFBPU1QgdG8gTW9kZWwgU2VydmluZy5cbiAqXG4gKiBDYWNoZSBlbmFibGVkOiB0aGUgUE9TVCBpcyBhIHB1cmUgcmVhZCBvZiB0aGUgbW9kZWwncyBhbnN3ZXIgZm9yIG9uZSBxdWVyeSxcbiAqIGFuZCByZXBlYXQgYXNrcyBvZiB0aGUgc2FtZSBxdWVzdGlvbiBhcmUgY29tbW9uIGluIGEgbXVsdGktdHVybiBhZ2VudC5cbiAqIFJldHJ5IGVuYWJsZWQ6IHRoZSBQT1NUIGNyZWF0ZXMgbm8gY29udmVyc2F0aW9uIG9yIHN0YXRlLCBzbyByZXBsYXlpbmcgaXRcbiAqIGFmdGVyIGEgdHJhbnNpZW50IDQyOSAvIDV4eCBpcyBzYWZlLlxuICovXG5leHBvcnQgY29uc3Qgd2ViU2VhcmNoRXhlY3V0ZURlZmF1bHRzOiBXZWJTZWFyY2hFeGVjdXRpb25TZXR0aW5ncyA9IHtcbiAgZGVmYXVsdDoge1xuICAgIGNhY2hlOiB7IGVuYWJsZWQ6IHRydWUsIHR0bDogU0VBUkNIX0NBQ0hFX1RUTF9TRUNPTkRTIH0sXG4gICAgcmV0cnk6IHsgZW5hYmxlZDogdHJ1ZSwgYXR0ZW1wdHM6IFNFUlZJTkdfUkVUUllfQVRURU1QVFMgfSxcbiAgfSxcbn07XG5cbi8qKlxuICogU2V0dGluZ3MgZm9yIGEgYHdlYl9mZXRjaGAgcGFnZSByZWFkLlxuICpcbiAqIENhY2hlIGVuYWJsZWQ6IGZldGNoaW5nIGEgVVJMIGlzIGEgcmVhZCwgYW5kIGFuIGFnZW50IHRoYXQgc2VhcmNoZXMgdGhlblxuICogcmVhZHMgaXRzIG93biBjaXRhdGlvbnMgaGl0cyB0aGUgc2FtZSBwYWdlIHJlcGVhdGVkbHkuXG4gKiBSZXRyeSBlbmFibGVkOiBhIEdFVCBpcyBpZGVtcG90ZW50LCBzbyBhIGRyb3BwZWQgY29ubmVjdGlvbiBpcyB3b3J0aCBvbmVcbiAqIG1vcmUgYXR0ZW1wdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHdlYkZldGNoRXhlY3V0ZURlZmF1bHRzOiBXZWJTZWFyY2hFeGVjdXRpb25TZXR0aW5ncyA9IHtcbiAgZGVmYXVsdDoge1xuICAgIGNhY2hlOiB7IGVuYWJsZWQ6IHRydWUsIHR0bDogRkVUQ0hfQ0FDSEVfVFRMX1NFQ09ORFMgfSxcbiAgICByZXRyeTogeyBlbmFibGVkOiB0cnVlLCBhdHRlbXB0czogV0VCX1JFVFJZX0FUVEVNUFRTIH0sXG4gIH0sXG59O1xuXG4vKipcbiAqIFNldHRpbmdzIGZvciB0aGUgRHVja0R1Y2tHbyBzY3JhcGUgZmFsbGJhY2suIFNhbWUgcmVhZCBzZW1hbnRpY3MgYXMgdGhlXG4gKiBuYXRpdmUgc2VhcmNoLCBhbmQgdGhlIHNob3J0ZXIgY2FjaGUgbGlmZXRpbWUgYXBwbGllcyBmb3IgdGhlIHNhbWUgcmVhc29uLFxuICogYnV0IHRoZSByZXRyeSBidWRnZXQgZm9sbG93cyB0aGUgb3Blbi13ZWIgb25lOiBEdWNrRHVja0dvIGFuc3dlcnMgYSByZXBlYXRcbiAqIHJlcXVlc3Qgd2l0aCBhIGJvdCBjaGFsbGVuZ2UgcmF0aGVyIHRoYW4gcmVzdWx0cy5cbiAqL1xuZXhwb3J0IGNvbnN0IHNjcmFwZVNlYXJjaEV4ZWN1dGVEZWZhdWx0czogV2ViU2VhcmNoRXhlY3V0aW9uU2V0dGluZ3MgPSB7XG4gIGRlZmF1bHQ6IHtcbiAgICBjYWNoZTogeyBlbmFibGVkOiB0cnVlLCB0dGw6IFNFQVJDSF9DQUNIRV9UVExfU0VDT05EUyB9LFxuICAgIHJldHJ5OiB7IGVuYWJsZWQ6IHRydWUsIGF0dGVtcHRzOiBXRUJfUkVUUllfQVRURU1QVFMgfSxcbiAgfSxcbn07XG5cbi8qKlxuICogQmluZCBvbmUgb2YgdGhlIG5hbWVkIGRlZmF1bHRzIHRvIGEgc2luZ2xlIGNhbGw6IHRoZSBjb25maWd1cmVkIG5ldHdvcmtcbiAqIHRpbWVvdXQgYW5kIHRoZSBjYWNoZSBrZXkgZm9yIHRoaXMgcmVxdWVzdC5cbiAqXG4gKiBBcHBLaXQgb25seSBpbnN0YWxscyB0aGUgY2FjaGUgaW50ZXJjZXB0b3Igd2hlbiBhIG5vbi1lbXB0eSBgY2FjaGVLZXlgIGlzXG4gKiBwcmVzZW50LCBzbyBldmVyeSBjYWNoZWQgY2FsbCBoYXMgdG8gbmFtZSBpdHMgb3duIGtleSBwYXJ0cy4gVGhlIHBlci11c2VyXG4gKiBoYWxmIG9mIHRoZSBrZXkgaXMgYWRkZWQgYnkgYGV4ZWN1dGUoKWAgZnJvbSB0aGUgYWN0aXZlIGV4ZWN1dGlvbiBjb250ZXh0LFxuICogd2hpY2ggaXMgd2hhdCBrZWVwcyBhbiBPQk8gcmVzdWx0IGZyb20gbGVha2luZyBhY3Jvc3MgaWRlbnRpdGllcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvQ2FsbFNldHRpbmdzKFxuICBiYXNlOiBXZWJTZWFyY2hFeGVjdXRpb25TZXR0aW5ncyxcbiAgdGltZW91dE1zOiBudW1iZXIsXG4gIGNhY2hlS2V5OiByZWFkb25seSAoc3RyaW5nIHwgbnVtYmVyKVtdLFxuKTogV2ViU2VhcmNoRXhlY3V0aW9uU2V0dGluZ3Mge1xuICByZXR1cm4ge1xuICAgIGRlZmF1bHQ6IHtcbiAgICAgIC4uLmJhc2UuZGVmYXVsdCxcbiAgICAgIGNhY2hlOiB7IC4uLmJhc2UuZGVmYXVsdC5jYWNoZSwgY2FjaGVLZXk6IFsuLi5jYWNoZUtleV0gfSxcbiAgICAgIHRpbWVvdXQ6IHRpbWVvdXRNcyxcbiAgICB9LFxuICAgIC4uLihiYXNlLnVzZXIgPyB7IHVzZXI6IGJhc2UudXNlciB9IDoge30pLFxuICB9O1xufVxuIl19
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page fetching over {@link https://www.npmjs.com/package/got-scraping | got-scraping}
|
|
3
|
+
* - a `got` wrapper that generates browser-like TLS + header fingerprints, so
|
|
4
|
+
* fetches survive the bot walls a plain `fetch` trips. {@link runWebFetch}
|
|
5
|
+
* enforces the URL allow-list (an explicit fetch of a disallowed URL is
|
|
6
|
+
* refused, not silently emptied), fetches with the plugin's timeout, and
|
|
7
|
+
* returns either the raw HTML or a readable plain-text reduction, capped at
|
|
8
|
+
* the configured length.
|
|
9
|
+
*
|
|
10
|
+
* The HTML-to-text reduction is deliberately dependency-free (strip
|
|
11
|
+
* script/style, unwrap tags, decode a handful of entities, collapse
|
|
12
|
+
* whitespace): good enough to feed a model, and it keeps the add-on's
|
|
13
|
+
* dependency surface to the two libraries the task called for.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import type { ResolvedWebSearchConfig } from "./config.js";
|
|
18
|
+
import type { WebFetchRequest, WebFetchResult } from "./schema.js";
|
|
19
|
+
/**
|
|
20
|
+
* Fetch a single URL and return its content in the requested format.
|
|
21
|
+
*
|
|
22
|
+
* Throws when the URL is not permitted by the allow-list (the visible,
|
|
23
|
+
* correctable failure the design calls for on the fetch path). The request's
|
|
24
|
+
* `maxLength` narrows (never widens) the plugin's `fetchMaxLength` cap.
|
|
25
|
+
* `signal` cancels the in-flight fetch.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runWebFetch(request: WebFetchRequest, config: ResolvedWebSearchConfig, signal?: AbortSignal): Promise<WebFetchResult>;
|