@dbx-tools/appkit-web-search 0.9.4 → 0.9.6

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/src/search.js CHANGED
@@ -21,9 +21,9 @@
21
21
  * @module
22
22
  */
23
23
  import { ConfigurationError, ConnectionError, ExecutionError, getExecutionContext, ValidationError, } from "@databricks/appkit";
24
- import { invoke, resolve, serving } from "@dbx-tools/model";
25
- import { log, object, string } from "@dbx-tools/shared-core";
26
- import { openaiChat, openaiResponses } from "@dbx-tools/shared-model";
24
+ import { invoke, resolve, modelCatalog } from "@dbx-tools/model";
25
+ import { log, object, stringUtils } from "@dbx-tools/shared-core";
26
+ import { openaiChat } from "@dbx-tools/shared-model";
27
27
  import { MODEL_ENV, SERVING_ENDPOINT_ENV } from "./config.js";
28
28
  import { toCallSettings, webSearchExecuteDefaults } from "./defaults.js";
29
29
  import { detectWebSearchProvider, supportsWebSearch, webSearchToolSpec } from "./provider.js";
@@ -31,7 +31,7 @@ import { executeRead, toWebSearchRuntime, } from "./runtime.js";
31
31
  import { runScrapeSearch } from "./scrape.js";
32
32
  const logger = log.logger("web-search/search");
33
33
  const { resolveModel } = resolve;
34
- const { listServingEndpoints } = serving;
34
+ const { listServingEndpoints } = modelCatalog;
35
35
  /**
36
36
  * How deep the grounding-metadata walk descends. Gemini nests its sources a
37
37
  * handful of levels down and the shape varies by model version, so the walk
@@ -52,7 +52,8 @@ const RATE_LIMITED_STATUS = 429;
52
52
  export async function resolveWebSearchContext() {
53
53
  const ctx = getExecutionContext();
54
54
  const host = (await ctx.client.config.getHost()).toString();
55
- return { client: ctx.client, host };
55
+ const cacheIdentity = "userId" in ctx ? ctx.userId : ctx.serviceUserId;
56
+ return { client: ctx.client, host, cacheIdentity };
56
57
  }
57
58
  /**
58
59
  * Resolve a web-search-capable model against the LIVE workspace catalogue - so
@@ -74,7 +75,9 @@ export async function resolveWebSearchContext() {
74
75
  * to the fallback order.
75
76
  */
76
77
  async function resolveWebSearchModel(ctx, config, requested) {
77
- const endpoints = await listServingEndpoints(ctx.client, ctx.host);
78
+ const endpoints = await listServingEndpoints(ctx.client, ctx.host, {
79
+ ...(ctx.cacheIdentity ? { cacheIdentity: ctx.cacheIdentity } : {}),
80
+ });
78
81
  // Only deployed, web-search-capable endpoints are candidates.
79
82
  const capable = endpoints.filter((e) => supportsWebSearch(e.name));
80
83
  const pinned = requested ?? config.model;
@@ -159,12 +162,40 @@ async function postServing(ctx, url, body, runtime, cacheKey, signal) {
159
162
  }
160
163
  /* --------------------------- response extraction --------------------------- */
161
164
  /**
162
- * Extract answer text and citations from an OpenAI Responses API payload through
163
- * the shared reader in `@dbx-tools/shared-model`.
165
+ * Extract answer text and citations from an OpenAI Responses API payload.
164
166
  */
165
167
  function fromResponsesPayload(payload) {
166
- const { text, citations } = openaiResponses.readResponsesOutput(payload);
167
- return { answer: text, citations };
168
+ const output = Array.isArray(payload.output) ? payload.output : [];
169
+ const texts = [];
170
+ const citations = [];
171
+ const seen = new Set();
172
+ for (const item of output) {
173
+ if (!object.isRecord(item))
174
+ continue;
175
+ const parts = openaiChat.chatContentParts(item.content);
176
+ if (!parts)
177
+ continue;
178
+ for (const part of parts) {
179
+ if (!object.isRecord(part))
180
+ continue;
181
+ const text = stringUtils.trimToEmpty(part.text);
182
+ if (text)
183
+ texts.push(text);
184
+ const annotations = Array.isArray(part.annotations) ? part.annotations : [];
185
+ for (const annotation of annotations) {
186
+ if (!object.isRecord(annotation))
187
+ continue;
188
+ const url = stringUtils.trimToEmpty(annotation.url);
189
+ if (!url || seen.has(url))
190
+ continue;
191
+ seen.add(url);
192
+ const title = stringUtils.trimToEmpty(annotation.title);
193
+ citations.push({ url, ...(title ? { title } : {}) });
194
+ }
195
+ }
196
+ }
197
+ const answer = stringUtils.trimToEmpty(payload.output_text) || texts.join("\n").trim();
198
+ return { answer, citations };
168
199
  }
169
200
  /**
170
201
  * Extract answer text + citations from a Chat Completions payload (Gemini via
@@ -183,10 +214,10 @@ function fromChatPayload(payload) {
183
214
  const visit = (v, depth) => {
184
215
  if (depth > MAX_GROUNDING_WALK_DEPTH || !object.isRecord(v))
185
216
  return;
186
- const url = string.trimToEmpty(v.url) || string.trimToEmpty(v.uri);
217
+ const url = stringUtils.trimToEmpty(v.url) || stringUtils.trimToEmpty(v.uri);
187
218
  if (url && !seen.has(url)) {
188
219
  seen.add(url);
189
- const title = string.trimToEmpty(v.title);
220
+ const title = stringUtils.trimToEmpty(v.title);
190
221
  citations.push({ url, ...(title ? { title } : {}) });
191
222
  }
192
223
  for (const val of Object.values(v)) {
@@ -251,4 +282,4 @@ export async function runWebSearch(request, runtimeOrConfig, ctx, signal) {
251
282
  });
252
283
  return { query: request.query, answer, citations: trimmed, model: modelId };
253
284
  }
254
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBRUgsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixlQUFlLEVBQ2YsY0FBYyxFQUNkLG1CQUFtQixFQUNuQixlQUFlLEdBQ2hCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDNUQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFnQyxNQUFNLGFBQWEsQ0FBQztBQUM1RixPQUFPLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM5RixPQUFPLEVBQ0wsV0FBVyxFQUNYLGtCQUFrQixHQUduQixNQUFNLGNBQWMsQ0FBQztBQUV0QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRzlDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQUMvQyxNQUFNLEVBQUUsWUFBWSxFQUFFLEdBQUcsT0FBTyxDQUFDO0FBQ2pDLE1BQU0sRUFBRSxvQkFBb0IsRUFBRSxHQUFHLE9BQU8sQ0FBQztBQUV6Qzs7Ozs7R0FLRztBQUNILE1BQU0sd0JBQXdCLEdBQUcsQ0FBQyxDQUFDO0FBRW5DLCtFQUErRTtBQUMvRSxNQUFNLG1CQUFtQixHQUFHLEdB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UyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDOUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogV2ViIHNlYXJjaCBiYWNrZWQgYnkgdGhlIERhdGFicmlja3MgTW9kZWwgU2VydmluZyBuYXRpdmUgd2ViLXNlYXJjaCB0b29sLlxuICpcbiAqIFVubGlrZSBhIHNjcmFwaW5nIGNsaWVudCwgdGhlIHNlYXJjaCBydW5zICppbnNpZGUqIGEgbW9kZWwgY2FsbDogd2UgUE9TVCB0aGVcbiAqIHF1ZXJ5IHRvIHRoZSB3b3Jrc3BhY2UncyBzZXJ2aW5nIGVuZHBvaW50IHdpdGggdGhlIHByb3ZpZGVyJ3Mgd2ViLXNlYXJjaFxuICogdG9vbCBzcGVjIGF0dGFjaGVkLCBhbmQgdGhlIG1vZGVsIHNlYXJjaGVzIHRoZSB3ZWIgYW5kIHdyaXRlcyB0aGUgYW5zd2VyLlxuICoge0BsaW5rIHJ1bldlYlNlYXJjaH06XG4gKlxuICogICAxLiBSZXNvbHZlcyBhIHdlYi1zZWFyY2gtY2FwYWJsZSBtb2RlbCBJTkRFUEVOREVOVExZIG9mIHRoZSBjYWxsaW5nXG4gKiAgICAgIGFnZW50J3MgY2hhdCBtb2RlbCAodGhlIGFnZW50IG1heSBydW4gb24gYSBtb2RlbCB3aXRob3V0IHdlYiBzZWFyY2gpLlxuICogICAgICBBIHBpbm5lZCBgbW9kZWxgIChyZXF1ZXN0IG9yIGNvbmZpZykgaXMgZnV6enktbWF0Y2hlZDsgb3RoZXJ3aXNlIHRoZVxuICogICAgICBjb25maWd1cmVkIGZhbGxiYWNrIG9yZGVyIChHZW1pbmksIHRoZW4gR1BUKSBpcyB3YWxrZWQgdG8gdGhlIGZpcnN0XG4gKiAgICAgIHdlYi1zZWFyY2gtY2FwYWJsZSBlbmRwb2ludCB0aGF0IGV4aXN0cy4gQW4gZXhwbGljaXQgYnV0IHVuc3VwcG9ydGVkXG4gKiAgICAgIG1vZGVsIGlzIGEgaGFyZCBlcnJvciwgbm90IGEgc2lsZW50IGZhbGxiYWNrLlxuICogICAyLiBQT1NUcyB0byB0aGUgcHJvdmlkZXIncyBSRVNUIHN1cmZhY2UgKGAvc2VydmluZy1lbmRwb2ludHMvcmVzcG9uc2VzYFxuICogICAgICBmb3IgT3BlbkFJLCBgL3NlcnZpbmctZW5kcG9pbnRzL2NoYXQvY29tcGxldGlvbnNgIGZvciBHZW1pbmkpIHdpdGggdGhlXG4gKiAgICAgIG1hcHBlZCB0b29sIHNwZWMsIGF1dGhlbnRpY2F0ZWQgYXMgdGhlIE9CTyBjYWxsZXIuXG4gKiAgIDMuIFJldHVybnMgdGhlIHN5bnRoZXNpemVkIGFuc3dlciBwbHVzIHRoZSBjaXRlZCBzb3VyY2VzLCB3aXRoIGNpdGF0aW9uc1xuICogICAgICBzaWxlbnRseSBmaWx0ZXJlZCB0aHJvdWdoIHRoZSBjb25maWd1cmVkIFVSTCBhbGxvdy1saXN0LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQge1xuICBDb25maWd1cmF0aW9uRXJyb3IsXG4gIENvbm5lY3Rpb25FcnJvcixcbiAgRXhlY3V0aW9uRXJyb3IsXG4gIGdldEV4ZWN1dGlvbkNvbnRleHQsXG4gIFZhbGlkYXRpb25FcnJvcixcbn0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHsgaW52b2tlLCByZXNvbHZlLCBzZXJ2aW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvbW9kZWxcIjtcbmltcG9ydCB7IGxvZywgb2JqZWN0LCBzdHJpbmcgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgb3BlbmFpQ2hhdCwgb3BlbmFpUmVzcG9uc2VzIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsXCI7XG5pbXBvcnQgeyBNT0RFTF9FTlYsIFNFUlZJTkdfRU5EUE9JTlRfRU5WLCB0eXBlIFJlc29sdmVkV2ViU2VhcmNoQ29uZmlnIH0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5pbXBvcnQgeyB0b0NhbGxTZXR0aW5ncywgd2ViU2VhcmNoRXhlY3V0ZURlZmF1bHRzIH0gZnJvbSBcIi4vZGVmYXVsdHMudHNcIjtcbmltcG9ydCB7IGRldGVjdFdlYlNlYXJjaFByb3ZpZGVyLCBzdXBwb3J0c1dlYlNlYXJjaCwgd2ViU2VhcmNoVG9vbFNwZWMgfSBmcm9tIFwiLi9wcm92aWRlci50c1wiO1xuaW1wb3J0IHtcbiAgZXhlY3V0ZVJlYWQsXG4gIHRvV2ViU2VhcmNoUnVudGltZSxcbiAgdHlwZSBXZWJTZWFyY2hSdW50aW1lLFxuICB0eXBlIFdlYlNlYXJjaFJ1bnRpbWVJbnB1dCxcbn0gZnJvbSBcIi4vcnVudGltZS50c1wiO1xuaW1wb3J0IHR5cGUgeyBXZWJTZWFyY2hDaXRhdGlvbiwgV2ViU2VhcmNoUmVxdWVzdCwgV2ViU2VhcmNoUmVzdWx0IH0gZnJvbSBcIi4vc2NoZW1hLnRzXCI7XG5pbXBvcnQgeyBydW5TY3JhcGVTZWFyY2ggfSBmcm9tIFwiLi9zY3JhcGUudHNcIjtcblxudHlwZSBXb3Jrc3BhY2VDbGllbnRMaWtlID0gc2VydmluZy5Xb3Jrc3BhY2VDbGllbnRMaWtlICYgaW52b2tlLkF1dGhlbnRpY2F0aW5nQ2xpZW50TGlrZTtcbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ3ZWItc2VhcmNoL3NlYXJjaFwiKTtcbmNvbnN0IHsgcmVzb2x2ZU1vZGVsIH0gPSByZXNvbHZlO1xuY29uc3QgeyBsaXN0U2VydmluZ0VuZHBvaW50cyB9ID0gc2VydmluZztcblxuLyoqXG4gKiBIb3cgZGVlcCB0aGUgZ3JvdW5kaW5nLW1ldGFkYXRhIHdhbGsgZGVzY2VuZHMuIEdlbWluaSBuZXN0cyBpdHMgc291cmNlcyBhXG4gKiBoYW5kZnVsIG9mIGxldmVscyBkb3duIGFuZCB0aGUgc2hhcGUgdmFyaWVzIGJ5IG1vZGVsIHZlcnNpb24sIHNvIHRoZSB3YWxrXG4gKiBpcyBnZW5lcmljOyB0aGUgYm91bmQgaXMgd2hhdCBrZWVwcyBhIHBhdGhvbG9naWNhbCBwYXlsb2FkIGZyb20gdHVybmluZyBpdFxuICogaW50byBhIGZ1bGwgdHJhdmVyc2FsIG9mIHRoZSByZXNwb25zZS5cbiAqL1xuY29uc3QgTUFYX0dST1VORElOR19XQUxLX0RFUFRIID0gNjtcblxuLyoqIExvd2VzdCBIVFRQIHN0YXR1cyB0cmVhdGVkIGFzIGEgc2VydmVyLXNpZGUgKHJldHJ5YWJsZSkgc2VydmluZyBmYWlsdXJlLiAqL1xuY29uc3QgU0VSVkVSX0VSUk9SX1NUQVRVUyA9IDUwMDtcblxuLyoqIFN0YXR1cyBNb2RlbCBTZXJ2aW5nIHVzZXMgdG8gc2hlZCBsb2FkOyByZXRyeWFibGUgbGlrZSBhIDV4eC4gKi9cbmNvbnN0IFJBVEVfTElNSVRFRF9TVEFUVVMgPSA0Mjk7XG5cbi8qKiBDb250ZXh0IGEgc2VhcmNoIG5lZWRzIGZyb20gdGhlIGNhbGxlcjogdGhlIE9CTyBjbGllbnQgKyB3b3Jrc3BhY2UgaG9zdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV2ViU2VhcmNoQ29udGV4dCB7XG4gIGNsaWVudDogV29ya3NwYWNlQ2xpZW50TGlrZTtcbiAgaG9zdDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIE9CTyB3b3Jrc3BhY2UgY2xpZW50ICsgaG9zdCBmcm9tIHRoZSBhY3RpdmUgQXBwS2l0IGV4ZWN1dGlvblxuICogY29udGV4dC4gSW5zaWRlIGBhZ2VudC5zdHJlYW1gJ3MgYGFzVXNlcihyZXEpYCBzY29wZSB0aGlzIGhpdHMgdGhlIHNlcnZpbmdcbiAqIGVuZHBvaW50IGFzIHRoZSByZXF1ZXN0aW5nIHVzZXI7IG91dHNpZGUgYSB1c2VyIGNvbnRleHQgQXBwS2l0IGZhbGxzIGJhY2sgdG9cbiAqIHRoZSBzZXJ2aWNlIHByaW5jaXBhbC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVXZWJTZWFyY2hDb250ZXh0KCk6IFByb21pc2U8V2ViU2VhcmNoQ29udGV4dD4ge1xuICBjb25zdCBjdHggPSBnZXRFeGVjdXRpb25Db250ZXh0KCk7XG4gIGNvbnN0IGhvc3QgPSAoYXdhaXQgY3R4LmNsaWVudC5jb25maWcuZ2V0SG9zdCgpKS50b1N0cmluZygpO1xuICByZXR1cm4geyBjbGllbnQ6IGN0eC5jbGllbnQsIGhvc3QgfTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgd2ViLXNlYXJjaC1jYXBhYmxlIG1vZGVsIGFnYWluc3QgdGhlIExJVkUgd29ya3NwYWNlIGNhdGFsb2d1ZSAtIHNvXG4gKiB3ZSBuZXZlciByZXR1cm4gYW4gZW5kcG9pbnQgaWQgdGhhdCBpc24ndCBhY3R1YWxseSBkZXBsb3llZCAodGhlIFwiZW5kcG9pbnRcbiAqIGRvZXMgbm90IGV4aXN0XCIgZmFpbHVyZSBhIGhhcmRjb2RlZCBmYWxsYmFjayBpZCB3b3VsZCBjYXVzZSkuIFJldXNlc1xuICogYEBkYngtdG9vbHMvbW9kZWxgJ3MgZXhpc3RpbmcgY2F0YWxvZ3VlICsgcmVzb2x2ZXIgcmF0aGVyIHRoYW4gYSBjdXN0b21cbiAqIGxvb2t1cDoge0BsaW5rIGxpc3RTZXJ2aW5nRW5kcG9pbnRzfSBsaXN0cyB0aGUgZW5kcG9pbnRzIChjYWNoZWQpLCBhbmQgd2VcbiAqIHJlc3RyaWN0IHRoZSBjYW5kaWRhdGUgc2V0IHRvIHRoZSB7QGxpbmsgc3VwcG9ydHNXZWJTZWFyY2h9IG9uZXMgYmVmb3JlXG4gKiB7QGxpbmsgcmVzb2x2ZU1vZGVsfSBmdXp6eS1waWNrcyB3aXRoaW4gaXQuXG4gKlxuICogUmV0dXJucyB0aGUgY2hvc2VuIGVuZHBvaW50IGlkLCBvciBgbnVsbGAgd2hlbiB0aGUgd29ya3NwYWNlIGhhcyBub1xuICogd2ViLXNlYXJjaC1jYXBhYmxlIG1vZGVsIGRlcGxveWVkICh0aGUgY2FsbGVyIHRoZW4gdXNlcyB0aGUgc2NyYXBlXG4gKiBmYWxsYmFjaykuIEEgcGluIHRoZSBjYWxsZXIgY2hvc2UgZGVsaWJlcmF0ZWx5IC0gdGhlIHJlcXVlc3QncyBgbW9kZWxgLCB0aGVcbiAqIHBsdWdpbidzIGBtb2RlbGAsIG9yIGBXRUJfU0VBUkNIX01PREVMYCAtIHRocm93cyB3aGVuIGl0IHJlc29sdmVzIHRvIGFuXG4gKiB1bnN1cHBvcnRlZCAvIGFic2VudCBlbmRwb2ludCwgc28gYSBiYWQgcGluIHN1cmZhY2VzIHJhdGhlciB0aGFuIHNpbGVudGx5XG4gKiBkZWdyYWRpbmcuIEEgcGluIGluaGVyaXRlZCBmcm9tIHRoZSBzaGFyZWQgYERBVEFCUklDS1NfU0VSVklOR19FTkRQT0lOVF9OQU1FYFxuICogYmluZGluZyBpcyBvbmx5IGEgcHJlZmVyZW5jZTogdGhhdCBlbmRwb2ludCBpcyB0aGUgYXBwJ3Mgc2VydmluZyBlbmRwb2ludCxcbiAqIG5vdCBuZWNlc3NhcmlseSBhIHdlYi1zZWFyY2gtY2FwYWJsZSBvbmUsIHNvIGFuIHVudXNhYmxlIHZhbHVlIGZhbGxzIHRocm91Z2hcbiAqIHRvIHRoZSBmYWxsYmFjayBvcmRlci5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZVdlYlNlYXJjaE1vZGVsKFxuICBjdHg6IFdlYlNlYXJjaENvbnRleHQsXG4gIGNvbmZpZzogUmVzb2x2ZWRXZWJTZWFyY2hDb25maWcsXG4gIHJlcXVlc3RlZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gIGNvbnN0IGVuZHBvaW50cyA9IGF3YWl0IGxpc3RTZXJ2aW5nRW5kcG9pbnRzKGN0eC5jbGllbnQsIGN0eC5ob3N0KTtcbiAgLy8gT25seSBkZXBsb3llZCwgd2ViLXNlYXJjaC1jYXBhYmxlIGVuZHBvaW50cyBhcmUgY2FuZGlkYXRlcy5cbiAgY29uc3QgY2FwYWJsZSA9IGVuZHBvaW50cy5maWx0ZXIoKGUpID0+IHN1cHBvcnRzV2ViU2VhcmNoKGUubmFtZSkpO1xuICBjb25zdCBwaW5uZWQgPSByZXF1ZXN0ZWQgPz8gY29uZmlnLm1vZGVsO1xuICBjb25zdCBwaW5Jc0RlbGliZXJhdGUgPVxuICAgIHJlcXVlc3RlZCAhPT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5tb2RlbFNvdXJjZSA9PT0gXCJjb25maWdcIiB8fCBjb25maWcubW9kZWxTb3VyY2UgPT09IE1PREVMX0VOVjtcblxuICBpZiAocGlubmVkKSB7XG4gICAgLy8gUmVzb2x2ZSB0aGUgZXhwbGljaXQgYXNrIHdpdGhpbiB0aGUgY2FwYWJsZSBzZXQgb25seS5cbiAgICBjb25zdCB7IG1vZGVsSWQgfSA9IHJlc29sdmVNb2RlbChjYXBhYmxlLCB7XG4gICAgICBleHBsaWNpdDogcGlubmVkLFxuICAgICAgZnV6enk6IGNvbmZpZy5mdXp6eSxcbiAgICAgIHRocmVzaG9sZDogY29uZmlnLmZ1enp5VGhyZXNob2xkLFxuICAgIH0pO1xuICAgIC8vIHJlc29sdmVNb2RlbCByZXR1cm5zIHRoZSBpbnB1dCB2ZXJiYXRpbSBvbiBubyBtYXRjaDsgcmVxdWlyZSBpdCB0byBiZSBhXG4gICAgLy8gcmVhbCBjYXBhYmxlIGVuZHBvaW50IHNvIGEgYmFkIHBpbiBpcyBhIGNsZWFyIGVycm9yLCBub3QgYSBwaGFudG9tIGNhbGwuXG4gICAgY29uc3QgdXNhYmxlID0gY2FwYWJsZS5zb21lKChlKSA9PiBlLm5hbWUgPT09IG1vZGVsSWQpICYmIHN1cHBvcnRzV2ViU2VhcmNoKG1vZGVsSWQpO1xuICAgIGlmICh1c2FibGUpIHJldHVybiBtb2RlbElkO1xuICAgIGNvbnN0IGRlcGxveWVkID0gY2FwYWJsZS5tYXAoKGUpID0+IGUubmFtZSkuam9pbihcIiwgXCIpIHx8IFwibm9uZVwiO1xuICAgIGlmICghcGluSXNEZWxpYmVyYXRlKSB7XG4gICAgICBsb2dnZXIuaW5mbyhcInNoYXJlZC1lbmRwb2ludC1ub3Qtd2ViLWNhcGFibGVcIiwge1xuICAgICAgICBlbnZWYXI6IFNFUlZJTkdfRU5EUE9JTlRfRU5WLFxuICAgICAgICBkZXBsb3llZCxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAocmVxdWVzdGVkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXG4gICAgICAgIFwibW9kZWxcIixcbiAgICAgICAgcGlubmVkLFxuICAgICAgICBgYSBkZXBsb3llZCB3ZWItc2VhcmNoLWNhcGFibGUgZW5kcG9pbnQgKGRlcGxveWVkOiAke2RlcGxveWVkfSlgLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgQ29uZmlndXJhdGlvbkVycm9yLnJlc291cmNlTm90Rm91bmQoXG4gICAgICAgIFwiV2ViLXNlYXJjaC1jYXBhYmxlIHNlcnZpbmcgZW5kcG9pbnRcIixcbiAgICAgICAgYERlcGxveWVkIHdlYi1zZWFyY2gtY2FwYWJsZSBlbmRwb2ludHM6ICR7ZGVwbG95ZWR9LiBTZXQgbW9kZWwgb3IgJHtNT0RFTF9FTlZ9IHRvIG9uZSBvZiB0aGVtLmAsXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGlmIChjYXBhYmxlLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XG5cbiAgLy8gTm90aGluZyB1c2FibGUgcGlubmVkOiBwcmVmZXIgdGhlIGNvbmZpZ3VyZWQgZmFsbGJhY2sgb3JkZXIgKEdlbWluaSwgdGhlblxuICAvLyBHUFQpIHdoZW4gdGhvc2UgaWRzIGFyZSBhY3R1YWxseSBkZXBsb3llZDsgZWxzZSB0YWtlIHRoZSBiZXN0IGNhcGFibGVcbiAgLy8gZW5kcG9pbnQuXG4gIGNvbnN0IHsgbW9kZWxJZCB9ID0gcmVzb2x2ZU1vZGVsKGNhcGFibGUsIHtcbiAgICBmYWxsYmFja3M6IGNvbmZpZy5tb2RlbEZhbGxiYWNrcyxcbiAgICBmdXp6eTogY29uZmlnLmZ1enp5LFxuICAgIHRocmVzaG9sZDogY29uZmlnLmZ1enp5VGhyZXNob2xkLFxuICB9KTtcbiAgcmV0dXJuIGNhcGFibGUuc29tZSgoZSkgPT4gZS5uYW1lID09PSBtb2RlbElkKSA/IG1vZGVsSWQgOiAoY2FwYWJsZVswXT8ubmFtZSA/PyBudWxsKTtcbn1cblxuLyoqXG4gKiBQT1NUIGEgc2VydmluZyByZXF1ZXN0IGFzIHRoZSBPQk8gY2FsbGVyIGFuZCByZXR1cm4gdGhlIHBhcnNlZCBKU09OIGJvZHkuXG4gKlxuICogQXV0aCBoZWFkZXJzIGFyZSBtaW50ZWQgcGVyIGNhbGwgZnJvbSB0aGUgT0JPIGNsaWVudCdzIFNESyBjb25maWcsIHdoaWNoXG4gKiByZWZyZXNoZXMgdGhlIHRva2VuIHdoZW4gaXQgaXMgY2xvc2UgdG8gZXhwaXJ5LCBzbyB0aGUgcmVxdWVzdCBjYXJyaWVzIHRoZVxuICogcmVxdWVzdGluZyB1c2VyJ3MgaWRlbnRpdHkuXG4gKlxuICogVGhpcyBpcyB0aGUgb25lIERhdGFicmlja3MgY2FsbCBpbiB0aGUgcmVwbyB0aGF0IGRvZXMgbm90IGdvIHRocm91Z2hcbiAqIGBhcGlDbGllbnQucmVxdWVzdGAgKyBgZGF0YWJyaWNrcy50b0NvbnRleHRgICh3aGljaCBkb2VzIGZvcndhcmRcbiAqIGNhbmNlbGxhdGlvbikuIFJldHJ5IGNsYXNzaWZpY2F0aW9uIGhlcmUgaGFzIHRvIGRpc3Rpbmd1aXNoIGEgbG9hZC1zaGVkIG9yXG4gKiBzZXJ2ZXIgZmF1bHQgZnJvbSB0aGlzIHJlcXVlc3QncyBvd24gNHh4LCBhbmQgYGZldGNoYCBleHBvc2VzIHRoZSBIVFRQIHN0YXR1c1xuICogZGlyZWN0bHk7IHRoZSBTREsgcmFpc2VzIGFuIGBBcGlFcnJvcmAgdGhhdCBjYXJyaWVzIHRoZSBzdGF0dXMgdW5kZXJcbiAqIGluY29uc2lzdGVudCBrZXlzLCB3aGljaCBpcyBndWVzc3dvcmsgYnkgY29tcGFyaXNvbi5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcG9zdFNlcnZpbmcoXG4gIGN0eDogV2ViU2VhcmNoQ29udGV4dCxcbiAgdXJsOiBzdHJpbmcsXG4gIGJvZHk6IHVua25vd24sXG4gIHJ1bnRpbWU6IFdlYlNlYXJjaFJ1bnRpbWUsXG4gIGNhY2hlS2V5OiByZWFkb25seSAoc3RyaW5nIHwgbnVtYmVyKVtdLFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgY29uc3QgeyBjb25maWcgfSA9IHJ1bnRpbWU7XG4gIGNvbnN0IHBheWxvYWQgPSBhd2FpdCBleGVjdXRlUmVhZChcbiAgICBydW50aW1lLFxuICAgIFwic2VydmluZy1yZXF1ZXN0XCIsXG4gICAgdG9DYWxsU2V0dGluZ3Mod2ViU2VhcmNoRXhlY3V0ZURlZmF1bHRzLCBjb25maWcudGltZW91dE1zLCBjYWNoZUtleSksXG4gICAgYXN5bmMgKGV4ZWN1dGVTaWduYWwpOiBQcm9taXNlPHVua25vd24+ID0+IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAuLi4oYXdhaXQgaW52b2tlLmF1dGhIZWFkZXJzKGN0eC5jbGllbnQpKSxcbiAgICAgICAgICBBY2NlcHQ6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICB9LFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShib2R5KSxcbiAgICAgICAgLi4uKGV4ZWN1dGVTaWduYWwgPyB7IHNpZ25hbDogZXhlY3V0ZVNpZ25hbCB9IDoge30pLFxuICAgICAgfSk7XG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIC8vIExvYWQtc2hlZGRpbmcgYW5kIHNlcnZlciBmYXVsdHMgYXJlIHdvcnRoIGFub3RoZXIgYXR0ZW1wdDsgYSA0eHggaXNcbiAgICAgICAgLy8gdGhpcyByZXF1ZXN0J3Mgb3duIHByb2JsZW0sIHNvIGl0IG11c3Qgbm90IGJlIHJldHJpZWQuXG4gICAgICAgIGNvbnN0IHJldHJ5YWJsZSA9XG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzID49IFNFUlZFUl9FUlJPUl9TVEFUVVMgfHwgcmVzcG9uc2Uuc3RhdHVzID09PSBSQVRFX0xJTUlURURfU1RBVFVTO1xuICAgICAgICBjb25zdCBtZXNzYWdlID0gYHdlYi1zZWFyY2g6IE1vZGVsIFNlcnZpbmcgcmVqZWN0ZWQgdGhlIHNlYXJjaCByZXF1ZXN0IChIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfSlgO1xuICAgICAgICB0aHJvdyByZXRyeWFibGVcbiAgICAgICAgICA/IG5ldyBDb25uZWN0aW9uRXJyb3IobWVzc2FnZSwgeyBjb250ZXh0OiB7IHN0YXR1czogcmVzcG9uc2Uuc3RhdHVzIH0gfSlcbiAgICAgICAgICA6IG5ldyBFeGVjdXRpb25FcnJvcihtZXNzYWdlLCB7IGNvbnRleHQ6IHsgc3RhdHVzOiByZXNwb25zZS5zdGF0dXMgfSB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gICAgfSxcbiAgICBzaWduYWwsXG4gICk7XG4gIHJldHVybiBvYmplY3QuaXNSZWNvcmQocGF5bG9hZCkgPyBwYXlsb2FkIDoge307XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSByZXNwb25zZSBleHRyYWN0aW9uIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIEV4dHJhY3QgYW5zd2VyIHRleHQgYW5kIGNpdGF0aW9ucyBmcm9tIGFuIE9wZW5BSSBSZXNwb25zZXMgQVBJIHBheWxvYWQgdGhyb3VnaFxuICogdGhlIHNoYXJlZCByZWFkZXIgaW4gYEBkYngtdG9vbHMvc2hhcmVkLW1vZGVsYC5cbiAqL1xuZnVuY3Rpb24gZnJvbVJlc3BvbnNlc1BheWxvYWQocGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiB7XG4gIGFuc3dlcjogc3RyaW5nO1xuICBjaXRhdGlvbnM6IFdlYlNlYXJjaENpdGF0aW9uW107XG59IHtcbiAgY29uc3QgeyB0ZXh0LCBjaXRhdGlvbnMgfSA9IG9wZW5haVJlc3BvbnNlcy5yZWFkUmVzcG9uc2VzT3V0cHV0KHBheWxvYWQpO1xuICByZXR1cm4geyBhbnN3ZXI6IHRleHQsIGNpdGF0aW9ucyB9O1xufVxuXG4vKipcbiAqIEV4dHJhY3QgYW5zd2VyIHRleHQgKyBjaXRhdGlvbnMgZnJvbSBhIENoYXQgQ29tcGxldGlvbnMgcGF5bG9hZCAoR2VtaW5pIHZpYVxuICogYGdvb2dsZV9zZWFyY2hgKS4gVGhlIGFuc3dlciBpcyBgY2hvaWNlc1swXS5tZXNzYWdlLmNvbnRlbnRgOyBncm91bmRpbmdcbiAqIHNvdXJjZXMsIHdoZW4gcHJlc2VudCwgc3VyZmFjZSB1bmRlciBgY2hvaWNlc1swXS5tZXNzYWdlYCBncm91bmRpbmdcbiAqIG1ldGFkYXRhIChiZXN0LWVmZm9ydCAtIHNoYXBlcyB2YXJ5LCBzbyB3ZSBzY2FuIGZvciB1cmwtYmVhcmluZyBlbnRyaWVzKS5cbiAqL1xuZnVuY3Rpb24gZnJvbUNoYXRQYXlsb2FkKHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KToge1xuICBhbnN3ZXI6IHN0cmluZztcbiAgY2l0YXRpb25zOiBXZWJTZWFyY2hDaXRhdGlvbltdO1xufSB7XG4gIGNvbnN0IGNob2ljZXMgPSBBcnJheS5pc0FycmF5KHBheWxvYWQuY2hvaWNlcykgPyBwYXlsb2FkLmNob2ljZXMgOiBbXTtcbiAgY29uc3QgZmlyc3QgPSBjaG9pY2VzWzBdO1xuICBjb25zdCBtZXNzYWdlID0gb2JqZWN0LmlzUmVjb3JkKGZpcnN0KSAmJiBvYmplY3QuaXNSZWNvcmQoZmlyc3QubWVzc2FnZSkgPyBmaXJzdC5tZXNzYWdlIDoge307XG4gIGNvbnN0IGFuc3dlciA9IG9wZW5haUNoYXQuY2hhdENvbnRlbnRUb1RleHQobWVzc2FnZS5jb250ZW50KTtcbiAgY29uc3QgY2l0YXRpb25zOiBXZWJTZWFyY2hDaXRhdGlvbltdID0gW107XG4gIC8vIEJlc3QtZWZmb3J0IGdyb3VuZGluZyBleHRyYWN0aW9uOiB3YWxrIGFueSBuZXN0ZWQgb2JqZWN0IGZvciB7dXJpfHVybCx0aXRsZX0uXG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3QgdmlzaXQgPSAodjogdW5rbm93biwgZGVwdGg6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgIGlmIChkZXB0aCA+IE1BWF9HUk9VTkRJTkdfV0FMS19ERVBUSCB8fCAhb2JqZWN0LmlzUmVjb3JkKHYpKSByZXR1cm47XG4gICAgY29uc3QgdXJsID0gc3RyaW5nLnRyaW1Ub0VtcHR5KHYudXJsKSB8fCBzdHJpbmcudHJpbVRvRW1wdHkodi51cmkpO1xuICAgIGlmICh1cmwgJiYgIXNlZW4uaGFzKHVybCkpIHtcbiAgICAgIHNlZW4uYWRkKHVybCk7XG4gICAgICBjb25zdCB0aXRsZSA9IHN0cmluZy50cmltVG9FbXB0eSh2LnRpdGxlKTtcbiAgICAgIGNpdGF0aW9ucy5wdXNoKHsgdXJsLCAuLi4odGl0bGUgPyB7IHRpdGxlIH0gOiB7fSkgfSk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgdmFsIG9mIE9iamVjdC52YWx1ZXModikpIHtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbCkpIHZhbC5mb3JFYWNoKCh4KSA9PiB2aXNpdCh4LCBkZXB0aCArIDEpKTtcbiAgICAgIGVsc2UgaWYgKHZhbCAmJiB0eXBlb2YgdmFsID09PSBcIm9iamVjdFwiKSB2aXNpdCh2YWwsIGRlcHRoICsgMSk7XG4gICAgfVxuICB9O1xuICB2aXNpdChtZXNzYWdlLmdyb3VuZGluZ19tZXRhZGF0YSA/PyBtZXNzYWdlLmdyb3VuZGluZ01ldGFkYXRhLCAwKTtcbiAgcmV0dXJuIHsgYW5zd2VyLCBjaXRhdGlvbnMgfTtcbn1cblxuLyoqXG4gKiBSdW4gYSB3ZWIgc2VhcmNoLiBQcmVmZXJzIHRoZSBEYXRhYnJpY2tzIG5hdGl2ZSB3ZWItc2VhcmNoIHRvb2wgb24gYVxuICogZGVwbG95ZWQgR1BUL0dlbWluaSBlbmRwb2ludCAoc3ludGhlc2l6ZWQgYW5zd2VyICsgY2l0YXRpb25zKTsgd2hlbiB0aGVcbiAqIHdvcmtzcGFjZSBoYXMgbm8gc3VjaCBlbmRwb2ludCBBTkQgdGhlIHNjcmFwZSBmYWxsYmFjayBpcyBlbmFibGVkLCBmYWxsc1xuICogYmFjayB0byBhIER1Y2tEdWNrR28gc2NyYXBlIHNvIHRoZSB0b29sIHN0aWxsIHJldHVybnMgcmVzdWx0cyBpbnN0ZWFkIG9mXG4gKiBlcnJvcmluZy4gQ2l0YXRpb25zIGFyZSBmaWx0ZXJlZCB0aHJvdWdoIHRoZSBjb25maWd1cmVkIFVSTCBhbGxvdy1saXN0LlxuICpcbiAqIGBzaWduYWxgIGNhbmNlbHMgdGhlIHdob2xlIGNhbGwsIGluY2x1ZGluZyB0aGUgaW4tZmxpZ2h0IHNlcnZpbmcgcmVxdWVzdC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bldlYlNlYXJjaChcbiAgcmVxdWVzdDogV2ViU2VhcmNoUmVxdWVzdCxcbiAgcnVudGltZU9yQ29uZmlnOiBXZWJTZWFyY2hSdW50aW1lSW5wdXQsXG4gIGN0eDogV2ViU2VhcmNoQ29udGV4dCxcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPFdlYlNlYXJjaFJlc3VsdD4ge1xuICBjb25zdCBydW50aW1lID0gdG9XZWJTZWFyY2hSdW50aW1lKHJ1bnRpbWVPckNvbmZpZyk7XG4gIGNvbnN0IHsgY29uZmlnIH0gPSBydW50aW1lO1xuICBjb25zdCBtb2RlbElkID0gYXdhaXQgcmVzb2x2ZVdlYlNlYXJjaE1vZGVsKGN0eCwgY29uZmlnLCByZXF1ZXN0Lm1vZGVsKTtcblxuICBpZiAobW9kZWxJZCA9PT0gbnVsbCkge1xuICAgIC8vIE5vIG5hdGl2ZSB3ZWItc2VhcmNoIG1vZGVsIGRlcGxveWVkIGluIHRoaXMgd29ya3NwYWNlLlxuICAgIGlmIChjb25maWcuc2NyYXBlRmFsbGJhY2spIHtcbiAgICAgIGxvZ2dlci5pbmZvKFwibm8tbmF0aXZlLW1vZGVsOnNjcmFwZS1mYWxsYmFja1wiLCB7IHF1ZXJ5OiByZXF1ZXN0LnF1ZXJ5IH0pO1xuICAgICAgcmV0dXJuIHJ1blNjcmFwZVNlYXJjaChyZXF1ZXN0LCBydW50aW1lLCBzaWduYWwpO1xuICAgIH1cbiAgICB0aHJvdyBDb25maWd1cmF0aW9uRXJyb3IucmVzb3VyY2VOb3RGb3VuZChcbiAgICAgIFwiV2ViLXNlYXJjaC1jYXBhYmxlIHNlcnZpbmcgZW5kcG9pbnRcIixcbiAgICAgIFwiTm8gR1BUL0dlbWluaSBlbmRwb2ludCBpcyBkZXBsb3llZCBpbiB0aGlzIHdvcmtzcGFjZSBhbmQgdGhlIHNjcmFwZSBmYWxsYmFjayBpcyBcIiArXG4gICAgICAgIGBkaXNhYmxlZC4gRGVwbG95IGEgc3VwcG9ydGVkIGVuZHBvaW50LCBzZXQgbW9kZWwgb3IgJHtNT0RFTF9FTlZ9LCBvciBlbmFibGUgdGhlIGAgK1xuICAgICAgICBcImZhbGxiYWNrIChXRUJfU0VBUkNIX1NDUkFQRV9GQUxMQkFDSz0xKS5cIixcbiAgICApO1xuICB9XG5cbiAgY29uc3QgcHJvdmlkZXIgPSBkZXRlY3RXZWJTZWFyY2hQcm92aWRlcihtb2RlbElkKSE7IC8vIGd1YXJhbnRlZWQgYnkgcmVzb2x2ZSBzdGVwXG4gIGNvbnN0IHNwZWMgPSB3ZWJTZWFyY2hUb29sU3BlYyhwcm92aWRlciwgY29uZmlnLndlYlNlYXJjaFRvb2xzKTtcblxuICBjb25zdCB1cmwgPVxuICAgIHNwZWMuYXBpID09PSBcInJlc3BvbnNlc1wiID8gaW52b2tlLnJlc3BvbnNlc1VybChjdHguaG9zdCkgOiBpbnZva2UuY2hhdENvbXBsZXRpb25zVXJsKGN0eC5ob3N0KTtcbiAgY29uc3QgYm9keSA9XG4gICAgc3BlYy5hcGkgPT09IFwicmVzcG9uc2VzXCJcbiAgICAgID8ge1xuICAgICAgICAgIG1vZGVsOiBtb2RlbElkLFxuICAgICAgICAgIGlucHV0OiBbeyByb2xlOiBcInVzZXJcIiwgY29udGVudDogcmVxdWVzdC5xdWVyeSB9XSxcbiAgICAgICAgICB0b29sczogW3NwZWMudG9vbF0sXG4gICAgICAgIH1cbiAgICAgIDoge1xuICAgICAgICAgIG1vZGVsOiBtb2RlbElkLFxuICAgICAgICAgIG1lc3NhZ2VzOiBbeyByb2xlOiBcInVzZXJcIiwgY29udGVudDogcmVxdWVzdC5xdWVyeSB9XSxcbiAgICAgICAgICB0b29sczogW3NwZWMudG9vbF0sXG4gICAgICAgIH07XG5cbiAgY29uc3QgcGF5bG9hZCA9IGF3YWl0IHBvc3RTZXJ2aW5nKFxuICAgIGN0eCxcbiAgICB1cmwsXG4gICAgYm9keSxcbiAgICBydW50aW1lLFxuICAgIFtcIndlYi1zZWFyY2hcIiwgXCJzZXJ2aW5nXCIsIHNwZWMuYXBpLCBtb2RlbElkLCByZXF1ZXN0LnF1ZXJ5XSxcbiAgICBzaWduYWwsXG4gICk7XG5cbiAgY29uc3QgeyBhbnN3ZXIsIGNpdGF0aW9ucyB9ID1cbiAgICBzcGVjLmFwaSA9PT0gXCJyZXNwb25zZXNcIiA/IGZyb21SZXNwb25zZXNQYXlsb2FkKHBheWxvYWQpIDogZnJvbUNoYXRQYXlsb2FkKHBheWxvYWQpO1xuXG4gIGNvbnN0IHBlcm1pdHRlZCA9IGNpdGF0aW9ucy5maWx0ZXIoKGMpID0+IGNvbmZpZy5hbGxvd0xpc3QuYWxsb3dzKGMudXJsKSk7XG4gIGNvbnN0IGRyb3BwZWQgPSBjaXRhdGlvbnMubGVuZ3RoIC0gcGVybWl0dGVkLmxlbmd0aDtcbiAgY29uc3QgdHJpbW1lZCA9IHBlcm1pdHRlZC5zbGljZSgwLCBjb25maWcubWF4Q2l0YXRpb25zKTtcbiAgbG9nZ2VyLmRlYnVnKFwic2VhcmNoZWRcIiwge1xuICAgIHF1ZXJ5OiByZXF1ZXN0LnF1ZXJ5LFxuICAgIG1vZGVsOiBtb2RlbElkLFxuICAgIHByb3ZpZGVyLFxuICAgIGNpdGF0aW9uczogY2l0YXRpb25zLmxlbmd0aCxcbiAgICAuLi4oZHJvcHBlZCA+IDAgPyB7IGZpbHRlcmVkOiBkcm9wcGVkIH0gOiB7fSksXG4gICAgcmV0dXJuZWQ6IHRyaW1tZWQubGVuZ3RoLFxuICB9KTtcblxuICByZXR1cm4geyBxdWVyeTogcmVxdWVzdC5xdWVyeSwgYW5zd2VyLCBjaXRhdGlvbnM6IHRyaW1tZWQsIG1vZGVsOiBtb2RlbElkIH07XG59XG4iXX0=
285
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBRUgsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixlQUFlLEVBQ2YsY0FBYyxFQUNkLG1CQUFtQixFQUNuQixlQUFlLEdBQ2hCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDakUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxTQUFTLEVBQUUsb0JBQW9CLEVBQWdDLE1BQU0sYUFBYSxDQUFDO0FBQzVGLE9BQU8sRUFBRSxjQUFjLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzlGLE9BQU8sRUFDTCxXQUFXLEVBQ1gsa0JBQWtCLEdBR25CLE1BQU0sY0FBYyxDQUFDO0FBRXRCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHOUMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBQy9DLE1BQU0sRUFBRSxZQUFZLEVBQUUsR0FBRyxPQUFPLENBQUM7QUFDakMsTUFBTSxFQUFFLG9CQUFvQixFQUFFLEdBQUcsWUFBWSxDQUFDO0FBRTlDOzs7OztHQUtHO0FBQ0gsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLENBQUM7QUFFbkMsK0VBQStFO0FBQy9FLE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxDQUFDO0FB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QUFDO0lBRXRGLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzFFLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQztJQUNwRCxNQUFNLE9BQU8sR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDeEQsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUU7UUFDdkIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1FBQ3BCLEtBQUssRUFBRSxPQUFPO1FBQ2QsUUFBUTtRQUNSLFNBQVMsRUFBRSxTQUFTLENBQUMsTUFBTTtRQUMzQixHQUFHLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM3QyxRQUFRLEVBQUUsT0FBTyxDQUFDLE1BQU07S0FDekIsQ0FBQyxDQUFDO0lBRUgsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQztBQUM5RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBXZWIgc2VhcmNoIGJhY2tlZCBieSB0aGUgRGF0YWJyaWNrcyBNb2RlbCBTZXJ2aW5nIG5hdGl2ZSB3ZWItc2VhcmNoIHRvb2wuXG4gKlxuICogVW5saWtlIGEgc2NyYXBpbmcgY2xpZW50LCB0aGUgc2VhcmNoIHJ1bnMgKmluc2lkZSogYSBtb2RlbCBjYWxsOiB3ZSBQT1NUIHRoZVxuICogcXVlcnkgdG8gdGhlIHdvcmtzcGFjZSdzIHNlcnZpbmcgZW5kcG9pbnQgd2l0aCB0aGUgcHJvdmlkZXIncyB3ZWItc2VhcmNoXG4gKiB0b29sIHNwZWMgYXR0YWNoZWQsIGFuZCB0aGUgbW9kZWwgc2VhcmNoZXMgdGhlIHdlYiBhbmQgd3JpdGVzIHRoZSBhbnN3ZXIuXG4gKiB7QGxpbmsgcnVuV2ViU2VhcmNofTpcbiAqXG4gKiAgIDEuIFJlc29sdmVzIGEgd2ViLXNlYXJjaC1jYXBhYmxlIG1vZGVsIElOREVQRU5ERU5UTFkgb2YgdGhlIGNhbGxpbmdcbiAqICAgICAgYWdlbnQncyBjaGF0IG1vZGVsICh0aGUgYWdlbnQgbWF5IHJ1biBvbiBhIG1vZGVsIHdpdGhvdXQgd2ViIHNlYXJjaCkuXG4gKiAgICAgIEEgcGlubmVkIGBtb2RlbGAgKHJlcXVlc3Qgb3IgY29uZmlnKSBpcyBmdXp6eS1tYXRjaGVkOyBvdGhlcndpc2UgdGhlXG4gKiAgICAgIGNvbmZpZ3VyZWQgZmFsbGJhY2sgb3JkZXIgKEdlbWluaSwgdGhlbiBHUFQpIGlzIHdhbGtlZCB0byB0aGUgZmlyc3RcbiAqICAgICAgd2ViLXNlYXJjaC1jYXBhYmxlIGVuZHBvaW50IHRoYXQgZXhpc3RzLiBBbiBleHBsaWNpdCBidXQgdW5zdXBwb3J0ZWRcbiAqICAgICAgbW9kZWwgaXMgYSBoYXJkIGVycm9yLCBub3QgYSBzaWxlbnQgZmFsbGJhY2suXG4gKiAgIDIuIFBPU1RzIHRvIHRoZSBwcm92aWRlcidzIFJFU1Qgc3VyZmFjZSAoYC9zZXJ2aW5nLWVuZHBvaW50cy9yZXNwb25zZXNgXG4gKiAgICAgIGZvciBPcGVuQUksIGAvc2VydmluZy1lbmRwb2ludHMvY2hhdC9jb21wbGV0aW9uc2AgZm9yIEdlbWluaSkgd2l0aCB0aGVcbiAqICAgICAgbWFwcGVkIHRvb2wgc3BlYywgYXV0aGVudGljYXRlZCBhcyB0aGUgT0JPIGNhbGxlci5cbiAqICAgMy4gUmV0dXJucyB0aGUgc3ludGhlc2l6ZWQgYW5zd2VyIHBsdXMgdGhlIGNpdGVkIHNvdXJjZXMsIHdpdGggY2l0YXRpb25zXG4gKiAgICAgIHNpbGVudGx5IGZpbHRlcmVkIHRocm91Z2ggdGhlIGNvbmZpZ3VyZWQgVVJMIGFsbG93LWxpc3QuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7XG4gIENvbmZpZ3VyYXRpb25FcnJvcixcbiAgQ29ubmVjdGlvbkVycm9yLFxuICBFeGVjdXRpb25FcnJvcixcbiAgZ2V0RXhlY3V0aW9uQ29udGV4dCxcbiAgVmFsaWRhdGlvbkVycm9yLFxufSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBpbnZva2UsIHJlc29sdmUsIG1vZGVsQ2F0YWxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL21vZGVsXCI7XG5pbXBvcnQgeyBsb2csIG9iamVjdCwgc3RyaW5nVXRpbHMgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgb3BlbmFpQ2hhdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbFwiO1xuaW1wb3J0IHsgTU9ERUxfRU5WLCBTRVJWSU5HX0VORFBPSU5UX0VOViwgdHlwZSBSZXNvbHZlZFdlYlNlYXJjaENvbmZpZyB9IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuaW1wb3J0IHsgdG9DYWxsU2V0dGluZ3MsIHdlYlNlYXJjaEV4ZWN1dGVEZWZhdWx0cyB9IGZyb20gXCIuL2RlZmF1bHRzLnRzXCI7XG5pbXBvcnQgeyBkZXRlY3RXZWJTZWFyY2hQcm92aWRlciwgc3VwcG9ydHNXZWJTZWFyY2gsIHdlYlNlYXJjaFRvb2xTcGVjIH0gZnJvbSBcIi4vcHJvdmlkZXIudHNcIjtcbmltcG9ydCB7XG4gIGV4ZWN1dGVSZWFkLFxuICB0b1dlYlNlYXJjaFJ1bnRpbWUsXG4gIHR5cGUgV2ViU2VhcmNoUnVudGltZSxcbiAgdHlwZSBXZWJTZWFyY2hSdW50aW1lSW5wdXQsXG59IGZyb20gXCIuL3J1bnRpbWUudHNcIjtcbmltcG9ydCB0eXBlIHsgV2ViU2VhcmNoQ2l0YXRpb24sIFdlYlNlYXJjaFJlcXVlc3QsIFdlYlNlYXJjaFJlc3VsdCB9IGZyb20gXCIuL3NjaGVtYS50c1wiO1xuaW1wb3J0IHsgcnVuU2NyYXBlU2VhcmNoIH0gZnJvbSBcIi4vc2NyYXBlLnRzXCI7XG5cbnR5cGUgV29ya3NwYWNlQ2xpZW50TGlrZSA9IG1vZGVsQ2F0YWxvZy5Xb3Jrc3BhY2VDbGllbnRMaWtlICYgaW52b2tlLkF1dGhlbnRpY2F0aW5nQ2xpZW50TGlrZTtcbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ3ZWItc2VhcmNoL3NlYXJjaFwiKTtcbmNvbnN0IHsgcmVzb2x2ZU1vZGVsIH0gPSByZXNvbHZlO1xuY29uc3QgeyBsaXN0U2VydmluZ0VuZHBvaW50cyB9ID0gbW9kZWxDYXRhbG9nO1xuXG4vKipcbiAqIEhvdyBkZWVwIHRoZSBncm91bmRpbmctbWV0YWRhdGEgd2FsayBkZXNjZW5kcy4gR2VtaW5pIG5lc3RzIGl0cyBzb3VyY2VzIGFcbiAqIGhhbmRmdWwgb2YgbGV2ZWxzIGRvd24gYW5kIHRoZSBzaGFwZSB2YXJpZXMgYnkgbW9kZWwgdmVyc2lvbiwgc28gdGhlIHdhbGtcbiAqIGlzIGdlbmVyaWM7IHRoZSBib3VuZCBpcyB3aGF0IGtlZXBzIGEgcGF0aG9sb2dpY2FsIHBheWxvYWQgZnJvbSB0dXJuaW5nIGl0XG4gKiBpbnRvIGEgZnVsbCB0cmF2ZXJzYWwgb2YgdGhlIHJlc3BvbnNlLlxuICovXG5jb25zdCBNQVhfR1JPVU5ESU5HX1dBTEtfREVQVEggPSA2O1xuXG4vKiogTG93ZXN0IEhUVFAgc3RhdHVzIHRyZWF0ZWQgYXMgYSBzZXJ2ZXItc2lkZSAocmV0cnlhYmxlKSBzZXJ2aW5nIGZhaWx1cmUuICovXG5jb25zdCBTRVJWRVJfRVJST1JfU1RBVFVTID0gNTAwO1xuXG4vKiogU3RhdHVzIE1vZGVsIFNlcnZpbmcgdXNlcyB0byBzaGVkIGxvYWQ7IHJldHJ5YWJsZSBsaWtlIGEgNXh4LiAqL1xuY29uc3QgUkFURV9MSU1JVEVEX1NUQVRVUyA9IDQyOTtcblxuLyoqIENvbnRleHQgYSBzZWFyY2ggbmVlZHMgZnJvbSB0aGUgY2FsbGVyOiB0aGUgT0JPIGNsaWVudCArIHdvcmtzcGFjZSBob3N0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBXZWJTZWFyY2hDb250ZXh0IHtcbiAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnRMaWtlO1xuICBob3N0OiBzdHJpbmc7XG4gIC8qKiBUcnVzdGVkIGlkZW50aXR5IG9mIHRoZSBjcmVkZW50aWFsIGNhcnJpZWQgYnkgYGNsaWVudGAuICovXG4gIGNhY2hlSWRlbnRpdHk/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgT0JPIHdvcmtzcGFjZSBjbGllbnQgKyBob3N0IGZyb20gdGhlIGFjdGl2ZSBBcHBLaXQgZXhlY3V0aW9uXG4gKiBjb250ZXh0LiBJbnNpZGUgYGFnZW50LnN0cmVhbWAncyBgYXNVc2VyKHJlcSlgIHNjb3BlIHRoaXMgaGl0cyB0aGUgc2VydmluZ1xuICogZW5kcG9pbnQgYXMgdGhlIHJlcXVlc3RpbmcgdXNlcjsgb3V0c2lkZSBhIHVzZXIgY29udGV4dCBBcHBLaXQgZmFsbHMgYmFjayB0b1xuICogdGhlIHNlcnZpY2UgcHJpbmNpcGFsLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZVdlYlNlYXJjaENvbnRleHQoKTogUHJvbWlzZTxXZWJTZWFyY2hDb250ZXh0PiB7XG4gIGNvbnN0IGN0eCA9IGdldEV4ZWN1dGlvbkNvbnRleHQoKTtcbiAgY29uc3QgaG9zdCA9IChhd2FpdCBjdHguY2xpZW50LmNvbmZpZy5nZXRIb3N0KCkpLnRvU3RyaW5nKCk7XG4gIGNvbnN0IGNhY2hlSWRlbnRpdHkgPSBcInVzZXJJZFwiIGluIGN0eCA/IGN0eC51c2VySWQgOiBjdHguc2VydmljZVVzZXJJZDtcbiAgcmV0dXJuIHsgY2xpZW50OiBjdHguY2xpZW50LCBob3N0LCBjYWNoZUlkZW50aXR5IH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHdlYi1zZWFyY2gtY2FwYWJsZSBtb2RlbCBhZ2FpbnN0IHRoZSBMSVZFIHdvcmtzcGFjZSBjYXRhbG9ndWUgLSBzb1xuICogd2UgbmV2ZXIgcmV0dXJuIGFuIGVuZHBvaW50IGlkIHRoYXQgaXNuJ3QgYWN0dWFsbHkgZGVwbG95ZWQgKHRoZSBcImVuZHBvaW50XG4gKiBkb2VzIG5vdCBleGlzdFwiIGZhaWx1cmUgYSBoYXJkY29kZWQgZmFsbGJhY2sgaWQgd291bGQgY2F1c2UpLiBSZXVzZXNcbiAqIGBAZGJ4LXRvb2xzL21vZGVsYCdzIGV4aXN0aW5nIGNhdGFsb2d1ZSArIHJlc29sdmVyIHJhdGhlciB0aGFuIGEgY3VzdG9tXG4gKiBsb29rdXA6IHtAbGluayBsaXN0U2VydmluZ0VuZHBvaW50c30gbGlzdHMgdGhlIGVuZHBvaW50cyAoY2FjaGVkKSwgYW5kIHdlXG4gKiByZXN0cmljdCB0aGUgY2FuZGlkYXRlIHNldCB0byB0aGUge0BsaW5rIHN1cHBvcnRzV2ViU2VhcmNofSBvbmVzIGJlZm9yZVxuICoge0BsaW5rIHJlc29sdmVNb2RlbH0gZnV6enktcGlja3Mgd2l0aGluIGl0LlxuICpcbiAqIFJldHVybnMgdGhlIGNob3NlbiBlbmRwb2ludCBpZCwgb3IgYG51bGxgIHdoZW4gdGhlIHdvcmtzcGFjZSBoYXMgbm9cbiAqIHdlYi1zZWFyY2gtY2FwYWJsZSBtb2RlbCBkZXBsb3llZCAodGhlIGNhbGxlciB0aGVuIHVzZXMgdGhlIHNjcmFwZVxuICogZmFsbGJhY2spLiBBIHBpbiB0aGUgY2FsbGVyIGNob3NlIGRlbGliZXJhdGVseSAtIHRoZSByZXF1ZXN0J3MgYG1vZGVsYCwgdGhlXG4gKiBwbHVnaW4ncyBgbW9kZWxgLCBvciBgV0VCX1NFQVJDSF9NT0RFTGAgLSB0aHJvd3Mgd2hlbiBpdCByZXNvbHZlcyB0byBhblxuICogdW5zdXBwb3J0ZWQgLyBhYnNlbnQgZW5kcG9pbnQsIHNvIGEgYmFkIHBpbiBzdXJmYWNlcyByYXRoZXIgdGhhbiBzaWxlbnRseVxuICogZGVncmFkaW5nLiBBIHBpbiBpbmhlcml0ZWQgZnJvbSB0aGUgc2hhcmVkIGBEQVRBQlJJQ0tTX1NFUlZJTkdfRU5EUE9JTlRfTkFNRWBcbiAqIGJpbmRpbmcgaXMgb25seSBhIHByZWZlcmVuY2U6IHRoYXQgZW5kcG9pbnQgaXMgdGhlIGFwcCdzIHNlcnZpbmcgZW5kcG9pbnQsXG4gKiBub3QgbmVjZXNzYXJpbHkgYSB3ZWItc2VhcmNoLWNhcGFibGUgb25lLCBzbyBhbiB1bnVzYWJsZSB2YWx1ZSBmYWxscyB0aHJvdWdoXG4gKiB0byB0aGUgZmFsbGJhY2sgb3JkZXIuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVXZWJTZWFyY2hNb2RlbChcbiAgY3R4OiBXZWJTZWFyY2hDb250ZXh0LFxuICBjb25maWc6IFJlc29sdmVkV2ViU2VhcmNoQ29uZmlnLFxuICByZXF1ZXN0ZWQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICBjb25zdCBlbmRwb2ludHMgPSBhd2FpdCBsaXN0U2VydmluZ0VuZHBvaW50cyhjdHguY2xpZW50LCBjdHguaG9zdCwge1xuICAgIC4uLihjdHguY2FjaGVJZGVudGl0eSA/IHsgY2FjaGVJZGVudGl0eTogY3R4LmNhY2hlSWRlbnRpdHkgfSA6IHt9KSxcbiAgfSk7XG4gIC8vIE9ubHkgZGVwbG95ZWQsIHdlYi1zZWFyY2gtY2FwYWJsZSBlbmRwb2ludHMgYXJlIGNhbmRpZGF0ZXMuXG4gIGNvbnN0IGNhcGFibGUgPSBlbmRwb2ludHMuZmlsdGVyKChlKSA9PiBzdXBwb3J0c1dlYlNlYXJjaChlLm5hbWUpKTtcbiAgY29uc3QgcGlubmVkID0gcmVxdWVzdGVkID8/IGNvbmZpZy5tb2RlbDtcbiAgY29uc3QgcGluSXNEZWxpYmVyYXRlID1cbiAgICByZXF1ZXN0ZWQgIT09IHVuZGVmaW5lZCB8fCBjb25maWcubW9kZWxTb3VyY2UgPT09IFwiY29uZmlnXCIgfHwgY29uZmlnLm1vZGVsU291cmNlID09PSBNT0RFTF9FTlY7XG5cbiAgaWYgKHBpbm5lZCkge1xuICAgIC8vIFJlc29sdmUgdGhlIGV4cGxpY2l0IGFzayB3aXRoaW4gdGhlIGNhcGFibGUgc2V0IG9ubHkuXG4gICAgY29uc3QgeyBtb2RlbElkIH0gPSByZXNvbHZlTW9kZWwoY2FwYWJsZSwge1xuICAgICAgZXhwbGljaXQ6IHBpbm5lZCxcbiAgICAgIGZ1enp5OiBjb25maWcuZnV6enksXG4gICAgICB0aHJlc2hvbGQ6IGNvbmZpZy5mdXp6eVRocmVzaG9sZCxcbiAgICB9KTtcbiAgICAvLyByZXNvbHZlTW9kZWwgcmV0dXJucyB0aGUgaW5wdXQgdmVyYmF0aW0gb24gbm8gbWF0Y2g7IHJlcXVpcmUgaXQgdG8gYmUgYVxuICAgIC8vIHJlYWwgY2FwYWJsZSBlbmRwb2ludCBzbyBhIGJhZCBwaW4gaXMgYSBjbGVhciBlcnJvciwgbm90IGEgcGhhbnRvbSBjYWxsLlxuICAgIGNvbnN0IHVzYWJsZSA9IGNhcGFibGUuc29tZSgoZSkgPT4gZS5uYW1lID09PSBtb2RlbElkKSAmJiBzdXBwb3J0c1dlYlNlYXJjaChtb2RlbElkKTtcbiAgICBpZiAodXNhYmxlKSByZXR1cm4gbW9kZWxJZDtcbiAgICBjb25zdCBkZXBsb3llZCA9IGNhcGFibGUubWFwKChlKSA9PiBlLm5hbWUpLmpvaW4oXCIsIFwiKSB8fCBcIm5vbmVcIjtcbiAgICBpZiAoIXBpbklzRGVsaWJlcmF0ZSkge1xuICAgICAgbG9nZ2VyLmluZm8oXCJzaGFyZWQtZW5kcG9pbnQtbm90LXdlYi1jYXBhYmxlXCIsIHtcbiAgICAgICAgZW52VmFyOiBTRVJWSU5HX0VORFBPSU5UX0VOVixcbiAgICAgICAgZGVwbG95ZWQsXG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKHJlcXVlc3RlZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBWYWxpZGF0aW9uRXJyb3IuaW52YWxpZFZhbHVlKFxuICAgICAgICBcIm1vZGVsXCIsXG4gICAgICAgIHBpbm5lZCxcbiAgICAgICAgYGEgZGVwbG95ZWQgd2ViLXNlYXJjaC1jYXBhYmxlIGVuZHBvaW50IChkZXBsb3llZDogJHtkZXBsb3llZH0pYCxcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5yZXNvdXJjZU5vdEZvdW5kKFxuICAgICAgICBcIldlYi1zZWFyY2gtY2FwYWJsZSBzZXJ2aW5nIGVuZHBvaW50XCIsXG4gICAgICAgIGBEZXBsb3llZCB3ZWItc2VhcmNoLWNhcGFibGUgZW5kcG9pbnRzOiAke2RlcGxveWVkfS4gU2V0IG1vZGVsIG9yICR7TU9ERUxfRU5WfSB0byBvbmUgb2YgdGhlbS5gLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBpZiAoY2FwYWJsZS5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuXG4gIC8vIE5vdGhpbmcgdXNhYmxlIHBpbm5lZDogcHJlZmVyIHRoZSBjb25maWd1cmVkIGZhbGxiYWNrIG9yZGVyIChHZW1pbmksIHRoZW5cbiAgLy8gR1BUKSB3aGVuIHRob3NlIGlkcyBhcmUgYWN0dWFsbHkgZGVwbG95ZWQ7IGVsc2UgdGFrZSB0aGUgYmVzdCBjYXBhYmxlXG4gIC8vIGVuZHBvaW50LlxuICBjb25zdCB7IG1vZGVsSWQgfSA9IHJlc29sdmVNb2RlbChjYXBhYmxlLCB7XG4gICAgZmFsbGJhY2tzOiBjb25maWcubW9kZWxGYWxsYmFja3MsXG4gICAgZnV6enk6IGNvbmZpZy5mdXp6eSxcbiAgICB0aHJlc2hvbGQ6IGNvbmZpZy5mdXp6eVRocmVzaG9sZCxcbiAgfSk7XG4gIHJldHVybiBjYXBhYmxlLnNvbWUoKGUpID0+IGUubmFtZSA9PT0gbW9kZWxJZCkgPyBtb2RlbElkIDogKGNhcGFibGVbMF0/Lm5hbWUgPz8gbnVsbCk7XG59XG5cbi8qKlxuICogUE9TVCBhIHNlcnZpbmcgcmVxdWVzdCBhcyB0aGUgT0JPIGNhbGxlciBhbmQgcmV0dXJuIHRoZSBwYXJzZWQgSlNPTiBib2R5LlxuICpcbiAqIEF1dGggaGVhZGVycyBhcmUgbWludGVkIHBlciBjYWxsIGZyb20gdGhlIE9CTyBjbGllbnQncyBTREsgY29uZmlnLCB3aGljaFxuICogcmVmcmVzaGVzIHRoZSB0b2tlbiB3aGVuIGl0IGlzIGNsb3NlIHRvIGV4cGlyeSwgc28gdGhlIHJlcXVlc3QgY2FycmllcyB0aGVcbiAqIHJlcXVlc3RpbmcgdXNlcidzIGlkZW50aXR5LlxuICpcbiAqIFRoaXMgaXMgdGhlIG9uZSBEYXRhYnJpY2tzIGNhbGwgaW4gdGhlIHJlcG8gdGhhdCBkb2VzIG5vdCBnbyB0aHJvdWdoXG4gKiBgYXBpQ2xpZW50LnJlcXVlc3RgICsgYGRhdGFicmlja3MudG9Db250ZXh0YCAod2hpY2ggZG9lcyBmb3J3YXJkXG4gKiBjYW5jZWxsYXRpb24pLiBSZXRyeSBjbGFzc2lmaWNhdGlvbiBoZXJlIGhhcyB0byBkaXN0aW5ndWlzaCBhIGxvYWQtc2hlZCBvclxuICogc2VydmVyIGZhdWx0IGZyb20gdGhpcyByZXF1ZXN0J3Mgb3duIDR4eCwgYW5kIGBmZXRjaGAgZXhwb3NlcyB0aGUgSFRUUCBzdGF0dXNcbiAqIGRpcmVjdGx5OyB0aGUgU0RLIHJhaXNlcyBhbiBgQXBpRXJyb3JgIHRoYXQgY2FycmllcyB0aGUgc3RhdHVzIHVuZGVyXG4gKiBpbmNvbnNpc3RlbnQga2V5cywgd2hpY2ggaXMgZ3Vlc3N3b3JrIGJ5IGNvbXBhcmlzb24uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHBvc3RTZXJ2aW5nKFxuICBjdHg6IFdlYlNlYXJjaENvbnRleHQsXG4gIHVybDogc3RyaW5nLFxuICBib2R5OiB1bmtub3duLFxuICBydW50aW1lOiBXZWJTZWFyY2hSdW50aW1lLFxuICBjYWNoZUtleTogcmVhZG9ubHkgKHN0cmluZyB8IG51bWJlcilbXSxcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIGNvbnN0IHsgY29uZmlnIH0gPSBydW50aW1lO1xuICBjb25zdCBwYXlsb2FkID0gYXdhaXQgZXhlY3V0ZVJlYWQoXG4gICAgcnVudGltZSxcbiAgICBcInNlcnZpbmctcmVxdWVzdFwiLFxuICAgIHRvQ2FsbFNldHRpbmdzKHdlYlNlYXJjaEV4ZWN1dGVEZWZhdWx0cywgY29uZmlnLnRpbWVvdXRNcywgY2FjaGVLZXkpLFxuICAgIGFzeW5jIChleGVjdXRlU2lnbmFsKTogUHJvbWlzZTx1bmtub3duPiA9PiB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgLi4uKGF3YWl0IGludm9rZS5hdXRoSGVhZGVycyhjdHguY2xpZW50KSksXG4gICAgICAgICAgQWNjZXB0OiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgfSxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSksXG4gICAgICAgIC4uLihleGVjdXRlU2lnbmFsID8geyBzaWduYWw6IGV4ZWN1dGVTaWduYWwgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICAvLyBMb2FkLXNoZWRkaW5nIGFuZCBzZXJ2ZXIgZmF1bHRzIGFyZSB3b3J0aCBhbm90aGVyIGF0dGVtcHQ7IGEgNHh4IGlzXG4gICAgICAgIC8vIHRoaXMgcmVxdWVzdCdzIG93biBwcm9ibGVtLCBzbyBpdCBtdXN0IG5vdCBiZSByZXRyaWVkLlxuICAgICAgICBjb25zdCByZXRyeWFibGUgPVxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyA+PSBTRVJWRVJfRVJST1JfU1RBVFVTIHx8IHJlc3BvbnNlLnN0YXR1cyA9PT0gUkFURV9MSU1JVEVEX1NUQVRVUztcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IGB3ZWItc2VhcmNoOiBNb2RlbCBTZXJ2aW5nIHJlamVjdGVkIHRoZSBzZWFyY2ggcmVxdWVzdCAoSFRUUCAke3Jlc3BvbnNlLnN0YXR1c30pYDtcbiAgICAgICAgdGhyb3cgcmV0cnlhYmxlXG4gICAgICAgICAgPyBuZXcgQ29ubmVjdGlvbkVycm9yKG1lc3NhZ2UsIHsgY29udGV4dDogeyBzdGF0dXM6IHJlc3BvbnNlLnN0YXR1cyB9IH0pXG4gICAgICAgICAgOiBuZXcgRXhlY3V0aW9uRXJyb3IobWVzc2FnZSwgeyBjb250ZXh0OiB7IHN0YXR1czogcmVzcG9uc2Uuc3RhdHVzIH0gfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpO1xuICAgIH0sXG4gICAgc2lnbmFsLFxuICApO1xuICByZXR1cm4gb2JqZWN0LmlzUmVjb3JkKHBheWxvYWQpID8gcGF5bG9hZCA6IHt9O1xufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gcmVzcG9uc2UgZXh0cmFjdGlvbiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBFeHRyYWN0IGFuc3dlciB0ZXh0IGFuZCBjaXRhdGlvbnMgZnJvbSBhbiBPcGVuQUkgUmVzcG9uc2VzIEFQSSBwYXlsb2FkLlxuICovXG5mdW5jdGlvbiBmcm9tUmVzcG9uc2VzUGF5bG9hZChwYXlsb2FkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHtcbiAgYW5zd2VyOiBzdHJpbmc7XG4gIGNpdGF0aW9uczogV2ViU2VhcmNoQ2l0YXRpb25bXTtcbn0ge1xuICBjb25zdCBvdXRwdXQgPSBBcnJheS5pc0FycmF5KHBheWxvYWQub3V0cHV0KSA/IHBheWxvYWQub3V0cHV0IDogW107XG4gIGNvbnN0IHRleHRzOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBjaXRhdGlvbnM6IFdlYlNlYXJjaENpdGF0aW9uW10gPSBbXTtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IgKGNvbnN0IGl0ZW0gb2Ygb3V0cHV0KSB7XG4gICAgaWYgKCFvYmplY3QuaXNSZWNvcmQoaXRlbSkpIGNvbnRpbnVlO1xuICAgIGNvbnN0IHBhcnRzID0gb3BlbmFpQ2hhdC5jaGF0Q29udGVudFBhcnRzKGl0ZW0uY29udGVudCk7XG4gICAgaWYgKCFwYXJ0cykgY29udGludWU7XG4gICAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgICBpZiAoIW9iamVjdC5pc1JlY29yZChwYXJ0KSkgY29udGludWU7XG4gICAgICBjb25zdCB0ZXh0ID0gc3RyaW5nVXRpbHMudHJpbVRvRW1wdHkocGFydC50ZXh0KTtcbiAgICAgIGlmICh0ZXh0KSB0ZXh0cy5wdXNoKHRleHQpO1xuICAgICAgY29uc3QgYW5ub3RhdGlvbnMgPSBBcnJheS5pc0FycmF5KHBhcnQuYW5ub3RhdGlvbnMpID8gcGFydC5hbm5vdGF0aW9ucyA6IFtdO1xuICAgICAgZm9yIChjb25zdCBhbm5vdGF0aW9uIG9mIGFubm90YXRpb25zKSB7XG4gICAgICAgIGlmICghb2JqZWN0LmlzUmVjb3JkKGFubm90YXRpb24pKSBjb250aW51ZTtcbiAgICAgICAgY29uc3QgdXJsID0gc3RyaW5nVXRpbHMudHJpbVRvRW1wdHkoYW5ub3RhdGlvbi51cmwpO1xuICAgICAgICBpZiAoIXVybCB8fCBzZWVuLmhhcyh1cmwpKSBjb250aW51ZTtcbiAgICAgICAgc2Vlbi5hZGQodXJsKTtcbiAgICAgICAgY29uc3QgdGl0bGUgPSBzdHJpbmdVdGlscy50cmltVG9FbXB0eShhbm5vdGF0aW9uLnRpdGxlKTtcbiAgICAgICAgY2l0YXRpb25zLnB1c2goeyB1cmwsIC4uLih0aXRsZSA/IHsgdGl0bGUgfSA6IHt9KSB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgY29uc3QgYW5zd2VyID0gc3RyaW5nVXRpbHMudHJpbVRvRW1wdHkocGF5bG9hZC5vdXRwdXRfdGV4dCkgfHwgdGV4dHMuam9pbihcIlxcblwiKS50cmltKCk7XG4gIHJldHVybiB7IGFuc3dlciwgY2l0YXRpb25zIH07XG59XG5cbi8qKlxuICogRXh0cmFjdCBhbnN3ZXIgdGV4dCArIGNpdGF0aW9ucyBmcm9tIGEgQ2hhdCBDb21wbGV0aW9ucyBwYXlsb2FkIChHZW1pbmkgdmlhXG4gKiBgZ29vZ2xlX3NlYXJjaGApLiBUaGUgYW5zd2VyIGlzIGBjaG9pY2VzWzBdLm1lc3NhZ2UuY29udGVudGA7IGdyb3VuZGluZ1xuICogc291cmNlcywgd2hlbiBwcmVzZW50LCBzdXJmYWNlIHVuZGVyIGBjaG9pY2VzWzBdLm1lc3NhZ2VgIGdyb3VuZGluZ1xuICogbWV0YWRhdGEgKGJlc3QtZWZmb3J0IC0gc2hhcGVzIHZhcnksIHNvIHdlIHNjYW4gZm9yIHVybC1iZWFyaW5nIGVudHJpZXMpLlxuICovXG5mdW5jdGlvbiBmcm9tQ2hhdFBheWxvYWQocGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiB7XG4gIGFuc3dlcjogc3RyaW5nO1xuICBjaXRhdGlvbnM6IFdlYlNlYXJjaENpdGF0aW9uW107XG59IHtcbiAgY29uc3QgY2hvaWNlcyA9IEFycmF5LmlzQXJyYXkocGF5bG9hZC5jaG9pY2VzKSA/IHBheWxvYWQuY2hvaWNlcyA6IFtdO1xuICBjb25zdCBmaXJzdCA9IGNob2ljZXNbMF07XG4gIGNvbnN0IG1lc3NhZ2UgPSBvYmplY3QuaXNSZWNvcmQoZmlyc3QpICYmIG9iamVjdC5pc1JlY29yZChmaXJzdC5tZXNzYWdlKSA/IGZpcnN0Lm1lc3NhZ2UgOiB7fTtcbiAgY29uc3QgYW5zd2VyID0gb3BlbmFpQ2hhdC5jaGF0Q29udGVudFRvVGV4dChtZXNzYWdlLmNvbnRlbnQpO1xuICBjb25zdCBjaXRhdGlvbnM6IFdlYlNlYXJjaENpdGF0aW9uW10gPSBbXTtcbiAgLy8gQmVzdC1lZmZvcnQgZ3JvdW5kaW5nIGV4dHJhY3Rpb246IHdhbGsgYW55IG5lc3RlZCBvYmplY3QgZm9yIHt1cml8dXJsLHRpdGxlfS5cbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCB2aXNpdCA9ICh2OiB1bmtub3duLCBkZXB0aDogbnVtYmVyKTogdm9pZCA9PiB7XG4gICAgaWYgKGRlcHRoID4gTUFYX0dST1VORElOR19XQUxLX0RFUFRIIHx8ICFvYmplY3QuaXNSZWNvcmQodikpIHJldHVybjtcbiAgICBjb25zdCB1cmwgPSBzdHJpbmdVdGlscy50cmltVG9FbXB0eSh2LnVybCkgfHwgc3RyaW5nVXRpbHMudHJpbVRvRW1wdHkodi51cmkpO1xuICAgIGlmICh1cmwgJiYgIXNlZW4uaGFzKHVybCkpIHtcbiAgICAgIHNlZW4uYWRkKHVybCk7XG4gICAgICBjb25zdCB0aXRsZSA9IHN0cmluZ1V0aWxzLnRyaW1Ub0VtcHR5KHYudGl0bGUpO1xuICAgICAgY2l0YXRpb25zLnB1c2goeyB1cmwsIC4uLih0aXRsZSA/IHsgdGl0bGUgfSA6IHt9KSB9KTtcbiAgICB9XG4gICAgZm9yIChjb25zdCB2YWwgb2YgT2JqZWN0LnZhbHVlcyh2KSkge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodmFsKSkgdmFsLmZvckVhY2goKHgpID0+IHZpc2l0KHgsIGRlcHRoICsgMSkpO1xuICAgICAgZWxzZSBpZiAodmFsICYmIHR5cGVvZiB2YWwgPT09IFwib2JqZWN0XCIpIHZpc2l0KHZhbCwgZGVwdGggKyAxKTtcbiAgICB9XG4gIH07XG4gIHZpc2l0KG1lc3NhZ2UuZ3JvdW5kaW5nX21ldGFkYXRhID8/IG1lc3NhZ2UuZ3JvdW5kaW5nTWV0YWRhdGEsIDApO1xuICByZXR1cm4geyBhbnN3ZXIsIGNpdGF0aW9ucyB9O1xufVxuXG4vKipcbiAqIFJ1biBhIHdlYiBzZWFyY2guIFByZWZlcnMgdGhlIERhdGFicmlja3MgbmF0aXZlIHdlYi1zZWFyY2ggdG9vbCBvbiBhXG4gKiBkZXBsb3llZCBHUFQvR2VtaW5pIGVuZHBvaW50IChzeW50aGVzaXplZCBhbnN3ZXIgKyBjaXRhdGlvbnMpOyB3aGVuIHRoZVxuICogd29ya3NwYWNlIGhhcyBubyBzdWNoIGVuZHBvaW50IEFORCB0aGUgc2NyYXBlIGZhbGxiYWNrIGlzIGVuYWJsZWQsIGZhbGxzXG4gKiBiYWNrIHRvIGEgRHVja0R1Y2tHbyBzY3JhcGUgc28gdGhlIHRvb2wgc3RpbGwgcmV0dXJucyByZXN1bHRzIGluc3RlYWQgb2ZcbiAqIGVycm9yaW5nLiBDaXRhdGlvbnMgYXJlIGZpbHRlcmVkIHRocm91Z2ggdGhlIGNvbmZpZ3VyZWQgVVJMIGFsbG93LWxpc3QuXG4gKlxuICogYHNpZ25hbGAgY2FuY2VscyB0aGUgd2hvbGUgY2FsbCwgaW5jbHVkaW5nIHRoZSBpbi1mbGlnaHQgc2VydmluZyByZXF1ZXN0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuV2ViU2VhcmNoKFxuICByZXF1ZXN0OiBXZWJTZWFyY2hSZXF1ZXN0LFxuICBydW50aW1lT3JDb25maWc6IFdlYlNlYXJjaFJ1bnRpbWVJbnB1dCxcbiAgY3R4OiBXZWJTZWFyY2hDb250ZXh0LFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8V2ViU2VhcmNoUmVzdWx0PiB7XG4gIGNvbnN0IHJ1bnRpbWUgPSB0b1dlYlNlYXJjaFJ1bnRpbWUocnVudGltZU9yQ29uZmlnKTtcbiAgY29uc3QgeyBjb25maWcgfSA9IHJ1bnRpbWU7XG4gIGNvbnN0IG1vZGVsSWQgPSBhd2FpdCByZXNvbHZlV2ViU2VhcmNoTW9kZWwoY3R4LCBjb25maWcsIHJlcXVlc3QubW9kZWwpO1xuXG4gIGlmIChtb2RlbElkID09PSBudWxsKSB7XG4gICAgLy8gTm8gbmF0aXZlIHdlYi1zZWFyY2ggbW9kZWwgZGVwbG95ZWQgaW4gdGhpcyB3b3Jrc3BhY2UuXG4gICAgaWYgKGNvbmZpZy5zY3JhcGVGYWxsYmFjaykge1xuICAgICAgbG9nZ2VyLmluZm8oXCJuby1uYXRpdmUtbW9kZWw6c2NyYXBlLWZhbGxiYWNrXCIsIHsgcXVlcnk6IHJlcXVlc3QucXVlcnkgfSk7XG4gICAgICByZXR1cm4gcnVuU2NyYXBlU2VhcmNoKHJlcXVlc3QsIHJ1bnRpbWUsIHNpZ25hbCk7XG4gICAgfVxuICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5yZXNvdXJjZU5vdEZvdW5kKFxuICAgICAgXCJXZWItc2VhcmNoLWNhcGFibGUgc2VydmluZyBlbmRwb2ludFwiLFxuICAgICAgXCJObyBHUFQvR2VtaW5pIGVuZHBvaW50IGlzIGRlcGxveWVkIGluIHRoaXMgd29ya3NwYWNlIGFuZCB0aGUgc2NyYXBlIGZhbGxiYWNrIGlzIFwiICtcbiAgICAgICAgYGRpc2FibGVkLiBEZXBsb3kgYSBzdXBwb3J0ZWQgZW5kcG9pbnQsIHNldCBtb2RlbCBvciAke01PREVMX0VOVn0sIG9yIGVuYWJsZSB0aGUgYCArXG4gICAgICAgIFwiZmFsbGJhY2sgKFdFQl9TRUFSQ0hfU0NSQVBFX0ZBTExCQUNLPTEpLlwiLFxuICAgICk7XG4gIH1cblxuICBjb25zdCBwcm92aWRlciA9IGRldGVjdFdlYlNlYXJjaFByb3ZpZGVyKG1vZGVsSWQpITsgLy8gZ3VhcmFudGVlZCBieSByZXNvbHZlIHN0ZXBcbiAgY29uc3Qgc3BlYyA9IHdlYlNlYXJjaFRvb2xTcGVjKHByb3ZpZGVyLCBjb25maWcud2ViU2VhcmNoVG9vbHMpO1xuXG4gIGNvbnN0IHVybCA9XG4gICAgc3BlYy5hcGkgPT09IFwicmVzcG9uc2VzXCIgPyBpbnZva2UucmVzcG9uc2VzVXJsKGN0eC5ob3N0KSA6IGludm9rZS5jaGF0Q29tcGxldGlvbnNVcmwoY3R4Lmhvc3QpO1xuICBjb25zdCBib2R5ID1cbiAgICBzcGVjLmFwaSA9PT0gXCJyZXNwb25zZXNcIlxuICAgICAgPyB7XG4gICAgICAgICAgbW9kZWw6IG1vZGVsSWQsXG4gICAgICAgICAgaW5wdXQ6IFt7IHJvbGU6IFwidXNlclwiLCBjb250ZW50OiByZXF1ZXN0LnF1ZXJ5IH1dLFxuICAgICAgICAgIHRvb2xzOiBbc3BlYy50b29sXSxcbiAgICAgICAgfVxuICAgICAgOiB7XG4gICAgICAgICAgbW9kZWw6IG1vZGVsSWQsXG4gICAgICAgICAgbWVzc2FnZXM6IFt7IHJvbGU6IFwidXNlclwiLCBjb250ZW50OiByZXF1ZXN0LnF1ZXJ5IH1dLFxuICAgICAgICAgIHRvb2xzOiBbc3BlYy50b29sXSxcbiAgICAgICAgfTtcblxuICBjb25zdCBwYXlsb2FkID0gYXdhaXQgcG9zdFNlcnZpbmcoXG4gICAgY3R4LFxuICAgIHVybCxcbiAgICBib2R5LFxuICAgIHJ1bnRpbWUsXG4gICAgW1wid2ViLXNlYXJjaFwiLCBcInNlcnZpbmdcIiwgc3BlYy5hcGksIG1vZGVsSWQsIHJlcXVlc3QucXVlcnldLFxuICAgIHNpZ25hbCxcbiAgKTtcblxuICBjb25zdCB7IGFuc3dlciwgY2l0YXRpb25zIH0gPVxuICAgIHNwZWMuYXBpID09PSBcInJlc3BvbnNlc1wiID8gZnJvbVJlc3BvbnNlc1BheWxvYWQocGF5bG9hZCkgOiBmcm9tQ2hhdFBheWxvYWQocGF5bG9hZCk7XG5cbiAgY29uc3QgcGVybWl0dGVkID0gY2l0YXRpb25zLmZpbHRlcigoYykgPT4gY29uZmlnLmFsbG93TGlzdC5hbGxvd3MoYy51cmwpKTtcbiAgY29uc3QgZHJvcHBlZCA9IGNpdGF0aW9ucy5sZW5ndGggLSBwZXJtaXR0ZWQubGVuZ3RoO1xuICBjb25zdCB0cmltbWVkID0gcGVybWl0dGVkLnNsaWNlKDAsIGNvbmZpZy5tYXhDaXRhdGlvbnMpO1xuICBsb2dnZXIuZGVidWcoXCJzZWFyY2hlZFwiLCB7XG4gICAgcXVlcnk6IHJlcXVlc3QucXVlcnksXG4gICAgbW9kZWw6IG1vZGVsSWQsXG4gICAgcHJvdmlkZXIsXG4gICAgY2l0YXRpb25zOiBjaXRhdGlvbnMubGVuZ3RoLFxuICAgIC4uLihkcm9wcGVkID4gMCA/IHsgZmlsdGVyZWQ6IGRyb3BwZWQgfSA6IHt9KSxcbiAgICByZXR1cm5lZDogdHJpbW1lZC5sZW5ndGgsXG4gIH0pO1xuXG4gIHJldHVybiB7IHF1ZXJ5OiByZXF1ZXN0LnF1ZXJ5LCBhbnN3ZXIsIGNpdGF0aW9uczogdHJpbW1lZCwgbW9kZWw6IG1vZGVsSWQgfTtcbn1cbiJdfQ==
package/package.json CHANGED
@@ -28,11 +28,12 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@databricks/appkit": "0.81.0",
31
- "@dbx-tools/core": "^0.9.4",
32
- "@dbx-tools/model": "^0.9.4",
33
- "@dbx-tools/path": "^0.9.4",
34
- "@dbx-tools/shared-core": "^0.9.4",
35
- "@dbx-tools/shared-model": "^0.9.4",
31
+ "@dbx-tools/appkit": "^0.9.6",
32
+ "@dbx-tools/core": "^0.9.6",
33
+ "@dbx-tools/model": "^0.9.6",
34
+ "@dbx-tools/path": "^0.9.6",
35
+ "@dbx-tools/shared-core": "^0.9.6",
36
+ "@dbx-tools/shared-model": "^0.9.6",
36
37
  "@mastra/core": "1.71.0",
37
38
  "cheerio": "^1.2.0",
38
39
  "entities": "^4.5.0",
@@ -54,7 +55,7 @@
54
55
  "./package.json": "./package.json"
55
56
  }
56
57
  },
57
- "version": "0.9.4",
58
+ "version": "0.9.6",
58
59
  "types": "./lib/index.d.ts",
59
60
  "type": "module",
60
61
  "exports": {
package/src/allowlist.ts CHANGED
@@ -31,7 +31,7 @@
31
31
 
32
32
  import { ValidationError } from "@databricks/appkit";
33
33
  import { match, type PathMatcher } from "@dbx-tools/path";
34
- import { string } from "@dbx-tools/shared-core";
34
+ import { stringUtils } from "@dbx-tools/shared-core";
35
35
 
36
36
  /** A compiled URL allow-list. Build one with {@link toUrlAllowList}. */
37
37
  export interface UrlAllowList {
@@ -65,7 +65,7 @@ export function normalizeUrlPattern(pattern: string): string {
65
65
  * identically.
66
66
  */
67
67
  export function parseAllowedUrls(raw: string | string[] | undefined): string[] {
68
- return string.parseList(raw, normalizeUrlPattern);
68
+ return stringUtils.parseList(raw, normalizeUrlPattern);
69
69
  }
70
70
 
71
71
  /** One compiled entry: which URL slice it tests, and the matcher for it. */
package/src/config.ts CHANGED
@@ -45,9 +45,9 @@
45
45
  */
46
46
 
47
47
  import { ConfigurationError, type BasePluginConfig } from "@databricks/appkit";
48
- import { config as coreConfig } from "@dbx-tools/core";
49
- import { serving } from "@dbx-tools/model";
50
- import { json, object, type OneOrMany, string } from "@dbx-tools/shared-core";
48
+ import { configUtils } from "@dbx-tools/core";
49
+ import { modelCatalog } from "@dbx-tools/model";
50
+ import { json, object, type OneOrMany, stringUtils } from "@dbx-tools/shared-core";
51
51
  import type { JSONSchema7 } from "json-schema";
52
52
  import { parseAllowedUrls, toUrlAllowList, type UrlAllowList } from "./allowlist.ts";
53
53
 
@@ -307,7 +307,7 @@ export const WEB_SEARCH_CONFIG_SCHEMA: JSONSchema7 = {
307
307
  * silently leave the built-in tool specs in place, so it throws.
308
308
  */
309
309
  function parseToolsEnv(): Record<string, unknown> {
310
- const raw = coreConfig.text("WEB_SEARCH_TOOLS", coreConfig.ENV_ONLY);
310
+ const raw = configUtils.text("WEB_SEARCH_TOOLS", configUtils.ENV_ONLY);
311
311
  if (raw === undefined) return {};
312
312
  const parsed = json.parseRecord(raw);
313
313
  if (!parsed) {
@@ -321,11 +321,11 @@ function parseToolsEnv(): Record<string, unknown> {
321
321
 
322
322
  /** Read the pinned endpoint id and record which source supplied it. */
323
323
  function resolveModelPin(config: WebSearchPluginConfig): { model?: string; source: ModelSource } {
324
- const fromConfig = string.trimToNull(config.model);
324
+ const fromConfig = stringUtils.trimToNull(config.model);
325
325
  if (fromConfig !== null) return { model: fromConfig, source: "config" };
326
- const fromModelEnv = coreConfig.text(MODEL_ENV, coreConfig.ENV_ONLY);
326
+ const fromModelEnv = configUtils.text(MODEL_ENV, configUtils.ENV_ONLY);
327
327
  if (fromModelEnv !== undefined) return { model: fromModelEnv, source: MODEL_ENV };
328
- const fromResourceEnv = coreConfig.text(SERVING_ENDPOINT_ENV, coreConfig.ENV_ONLY);
328
+ const fromResourceEnv = configUtils.text(SERVING_ENDPOINT_ENV, configUtils.ENV_ONLY);
329
329
  if (fromResourceEnv !== undefined) {
330
330
  return { model: fromResourceEnv, source: SERVING_ENDPOINT_ENV };
331
331
  }
@@ -340,7 +340,7 @@ function resolveUrlPolicy(
340
340
  configured: UrlPolicyMode | undefined,
341
341
  patterns: readonly string[],
342
342
  ): UrlPolicyMode {
343
- const raw = configured ?? coreConfig.text("WEB_SEARCH_URL_POLICY", coreConfig.ENV_ONLY);
343
+ const raw = configured ?? configUtils.text("WEB_SEARCH_URL_POLICY", configUtils.ENV_ONLY);
344
344
  if (raw === undefined) return patterns.length > 0 ? "allowlist" : "unrestricted";
345
345
  if (raw !== "allowlist" && raw !== "unrestricted") {
346
346
  throw new ConfigurationError(
@@ -398,15 +398,15 @@ export function resolveWebSearchConfig(
398
398
  config: WebSearchPluginConfig = {},
399
399
  ): ResolvedWebSearchConfig {
400
400
  const patterns = parseAllowedUrls(
401
- config.allowedUrls ?? coreConfig.text("WEB_SEARCH_ALLOWED_URLS", coreConfig.ENV_ONLY),
401
+ config.allowedUrls ?? configUtils.text("WEB_SEARCH_ALLOWED_URLS", configUtils.ENV_ONLY),
402
402
  );
403
403
  const urlPolicy = resolveUrlPolicy(config.urlPolicy, patterns);
404
404
  const { model, source } = resolveModelPin(config);
405
- const fallbacks = coreConfig.list(
405
+ const fallbacks = configUtils.list(
406
406
  config.modelFallbacks,
407
407
  "WEB_SEARCH_MODEL_FALLBACKS",
408
408
  undefined,
409
- coreConfig.ENV_ONLY,
409
+ configUtils.ENV_ONLY,
410
410
  );
411
411
  return {
412
412
  ...(model ? { model } : {}),
@@ -414,36 +414,36 @@ export function resolveWebSearchConfig(
414
414
  modelFallbacks: fallbacks.length > 0 ? fallbacks : DEFAULT_MODEL_FALLBACKS,
415
415
  webSearchTools: { ...parseToolsEnv(), ...(config.webSearchTools ?? {}) },
416
416
  fuzzy:
417
- coreConfig.boolean(config.modelFuzzyMatch, "WEB_SEARCH_FUZZY", coreConfig.ENV_ONLY) ?? true,
418
- fuzzyThreshold: coreConfig.positiveNumber(
417
+ configUtils.boolean(config.modelFuzzyMatch, "WEB_SEARCH_FUZZY", configUtils.ENV_ONLY) ?? true,
418
+ fuzzyThreshold: configUtils.positiveNumber(
419
419
  config.modelFuzzyThreshold,
420
420
  "WEB_SEARCH_FUZZY_THRESHOLD",
421
- serving.DEFAULT_FUZZY_THRESHOLD,
422
- coreConfig.ENV_ONLY,
421
+ modelCatalog.DEFAULT_FUZZY_THRESHOLD,
422
+ configUtils.ENV_ONLY,
423
423
  ),
424
- maxCitations: coreConfig.positiveInt(
424
+ maxCitations: configUtils.positiveInt(
425
425
  config.maxCitations,
426
426
  "WEB_SEARCH_MAX_CITATIONS",
427
427
  DEFAULT_MAX_CITATIONS,
428
- coreConfig.ENV_ONLY,
428
+ configUtils.ENV_ONLY,
429
429
  ),
430
- fetchMaxLength: coreConfig.positiveInt(
430
+ fetchMaxLength: configUtils.positiveInt(
431
431
  config.fetchMaxLength,
432
432
  "WEB_SEARCH_FETCH_MAX_LENGTH",
433
433
  DEFAULT_FETCH_MAX_LENGTH,
434
- coreConfig.ENV_ONLY,
434
+ configUtils.ENV_ONLY,
435
435
  ),
436
- timeoutMs: coreConfig.positiveInt(
436
+ timeoutMs: configUtils.positiveInt(
437
437
  config.timeoutMs,
438
438
  "WEB_SEARCH_TIMEOUT_MS",
439
439
  DEFAULT_TIMEOUT_MS,
440
- coreConfig.ENV_ONLY,
440
+ configUtils.ENV_ONLY,
441
441
  ),
442
442
  scrapeFallback:
443
- coreConfig.boolean(
443
+ configUtils.boolean(
444
444
  config.scrapeFallback,
445
445
  "WEB_SEARCH_SCRAPE_FALLBACK",
446
- coreConfig.ENV_ONLY,
446
+ configUtils.ENV_ONLY,
447
447
  ) ?? true,
448
448
  urlPolicy,
449
449
  allowList: toUrlAllowList(urlPolicy === "allowlist" ? patterns : []),
package/src/plugin.ts CHANGED
@@ -16,21 +16,14 @@
16
16
  */
17
17
 
18
18
  import {
19
- Plugin,
20
19
  ResourceType,
21
20
  toPlugin,
22
21
  type PluginManifest,
23
22
  type ResourceRequirement,
24
23
  } from "@databricks/appkit";
25
- import {
26
- defineTool,
27
- executeFromRegistry,
28
- toolsFromRegistry,
29
- type AgentToolDefinition,
30
- type ToolProvider,
31
- type ToolRegistry,
32
- } from "@databricks/appkit/beta";
33
- import { log, string } from "@dbx-tools/shared-core";
24
+ import { defineTool, type ToolRegistry } from "@databricks/appkit/beta";
25
+ import { ToolRegistryPlugin } from "@dbx-tools/appkit";
26
+ import { log, stringUtils } from "@dbx-tools/shared-core";
34
27
  import {
35
28
  MODEL_ENV,
36
29
  SERVING_ENDPOINT_ENV,
@@ -90,12 +83,12 @@ const SERVING_ENDPOINT_RESOURCE = {
90
83
  * @example
91
84
  * ```ts
92
85
  * import { createApp, server } from "@databricks/appkit";
93
- * import { plugin as webSearchPlugin } from "@dbx-tools/appkit-web-search";
86
+ * import { webSearch } from "@dbx-tools/appkit-web-search";
94
87
  *
95
88
  * await createApp({
96
89
  * plugins: [
97
90
  * server(),
98
- * webSearchPlugin.webSearch({
91
+ * webSearch({
99
92
  * model: "gemini",
100
93
  * urlPolicy: "allowlist",
101
94
  * allowedUrls: ["*.databricks.com"],
@@ -104,7 +97,7 @@ const SERVING_ENDPOINT_RESOURCE = {
104
97
  * });
105
98
  * ```
106
99
  */
107
- export class WebSearchPlugin extends Plugin<WebSearchPluginConfig> implements ToolProvider {
100
+ export class WebSearchPlugin extends ToolRegistryPlugin<WebSearchPluginConfig> {
108
101
  static manifest = {
109
102
  name: "web-search",
110
103
  displayName: "Web Search",
@@ -133,9 +126,9 @@ export class WebSearchPlugin extends Plugin<WebSearchPluginConfig> implements To
133
126
  */
134
127
  static getResourceRequirements(config: WebSearchPluginConfig): ResourceRequirement[] {
135
128
  const pinned =
136
- string.trimToNull(config.model) ??
137
- string.trimToNull(process.env[MODEL_ENV]) ??
138
- string.trimToNull(process.env[SERVING_ENDPOINT_ENV]);
129
+ stringUtils.trimToNull(config.model) ??
130
+ stringUtils.trimToNull(process.env[MODEL_ENV]) ??
131
+ stringUtils.trimToNull(process.env[SERVING_ENDPOINT_ENV]);
139
132
  return pinned === null ? [] : [{ ...SERVING_ENDPOINT_RESOURCE, required: true }];
140
133
  }
141
134
 
@@ -153,7 +146,7 @@ export class WebSearchPlugin extends Plugin<WebSearchPluginConfig> implements To
153
146
  * against the same schema first, but re-parsing is what gives the body typed
154
147
  * arguments instead of `unknown`.
155
148
  */
156
- private readonly tools: ToolRegistry = {
149
+ protected readonly toolRegistry: ToolRegistry = {
157
150
  web_search: defineTool({
158
151
  description: WEB_SEARCH_TOOL_DESCRIPTION,
159
152
  schema: webSearchRequestSchema,
@@ -202,20 +195,6 @@ export class WebSearchPlugin extends Plugin<WebSearchPluginConfig> implements To
202
195
  super.abortActiveOperations();
203
196
  }
204
197
 
205
- /** AppKit `ToolProvider`: the tool definitions offered to an agent. */
206
- getAgentTools(): AgentToolDefinition[] {
207
- return toolsFromRegistry(this.tools);
208
- }
209
-
210
- /**
211
- * AppKit `ToolProvider`: run one tool call. Arguments are validated against
212
- * the tool's schema first, and a validation failure comes back as an
213
- * LLM-friendly string so the model can correct itself on the next turn.
214
- */
215
- async executeAgentTool(name: string, args: unknown, signal?: AbortSignal): Promise<unknown> {
216
- return executeFromRegistry(this.tools, name, args, signal);
217
- }
218
-
219
198
  override exports() {
220
199
  return {
221
200
  /**
@@ -249,8 +228,8 @@ export class WebSearchPlugin extends Plugin<WebSearchPluginConfig> implements To
249
228
  * @example
250
229
  * ```ts
251
230
  * import { createApp, server } from "@databricks/appkit";
252
- * import { plugin as webSearchPlugin } from "@dbx-tools/appkit-web-search";
253
- * import { agents, plugin as mastraPlugin } from "@dbx-tools/appkit-mastra";
231
+ * import { webSearch } from "@dbx-tools/appkit-web-search";
232
+ * import { agents, mastra } from "@dbx-tools/appkit-mastra";
254
233
  *
255
234
  * const researcher = agents.createAgent({
256
235
  * instructions: "Research questions with web_search, then read sources with web_fetch.",
@@ -262,8 +241,8 @@ export class WebSearchPlugin extends Plugin<WebSearchPluginConfig> implements To
262
241
  * await createApp({
263
242
  * plugins: [
264
243
  * server(),
265
- * webSearchPlugin.webSearch({ model: "gemini" }),
266
- * mastraPlugin.mastra({ agents: researcher }),
244
+ * webSearch({ model: "gemini" }),
245
+ * mastra({ agents: researcher }),
267
246
  * ],
268
247
  * });
269
248
  * ```
package/src/runtime.ts CHANGED
@@ -8,7 +8,8 @@
8
8
  * @module
9
9
  */
10
10
 
11
- import { ExecutionError, type ExecutionResult } from "@databricks/appkit";
11
+ import type { ExecutionResult } from "@databricks/appkit";
12
+ import { pluginExecution } from "@dbx-tools/appkit";
12
13
  import { execution, log } from "@dbx-tools/shared-core";
13
14
  import {
14
15
  resolveWebSearchConfig,
@@ -66,43 +67,9 @@ export function toWebSearchRuntime(input: WebSearchRuntimeInput): WebSearchRunti
66
67
  return "execute" in input ? input : createResolvedWebSearchRuntime(input);
67
68
  }
68
69
 
69
- /**
70
- * Build an isolated standalone runtime.
71
- *
72
- * @deprecated Use {@link createWebSearchRuntime}. This compatibility helper
73
- * returns a new runtime on every call and never reads or updates plugin state.
74
- */
75
- export function getWebSearchRuntime(overrides?: WebSearchPluginConfig): WebSearchRuntime {
76
- return createWebSearchRuntime(overrides);
77
- }
78
-
79
70
  /** Install an executor on an explicit runtime. */
80
- export function setWebSearchExecutor(runtime: WebSearchRuntime, execute: WebSearchExecutor): void;
81
- /**
82
- * @deprecated Process-global executor registration is no longer supported.
83
- * Pass a runtime as the first argument or provide the executor to
84
- * {@link createWebSearchRuntime}.
85
- */
86
- export function setWebSearchExecutor(execute: WebSearchExecutor): never;
87
- export function setWebSearchExecutor(
88
- runtimeOrExecute: WebSearchRuntime | WebSearchExecutor,
89
- execute?: WebSearchExecutor,
90
- ): void {
91
- if (typeof runtimeOrExecute === "function") {
92
- throw new TypeError(
93
- "setWebSearchExecutor requires an explicit runtime; use createWebSearchRuntime(config, executor)",
94
- );
95
- }
96
- if (!execute) throw new TypeError("setWebSearchExecutor requires an executor");
97
- runtimeOrExecute.execute = execute;
98
- }
99
-
100
- /**
101
- * @deprecated Plugin runtimes are instance-owned and need no global reset.
102
- * This compatibility helper is intentionally a no-op.
103
- */
104
- export function resetWebSearchRuntime(): void {
105
- return;
71
+ export function setWebSearchExecutor(runtime: WebSearchRuntime, execute: WebSearchExecutor): void {
72
+ runtime.execute = execute;
106
73
  }
107
74
 
108
75
  /**
@@ -122,22 +89,13 @@ export async function executeRead<T>(
122
89
  fn: (signal?: AbortSignal) => Promise<T>,
123
90
  signal?: AbortSignal,
124
91
  ): Promise<T> {
125
- return execution.run({
92
+ return pluginExecution.runPluginExecution({
93
+ plugin: "web-search",
94
+ logger,
126
95
  operation,
127
96
  settings,
128
97
  execute: runtime.execute,
129
98
  fn,
130
99
  signal,
131
- canceled: ExecutionError.canceled,
132
- failed: (failure) => {
133
- logger.warn("execution-failed", {
134
- operation: failure.operation,
135
- status: failure.status,
136
- error: failure.message,
137
- });
138
- return new ExecutionError(`web-search: ${failure.operation} failed`, {
139
- context: { operation: failure.operation, status: failure.status },
140
- });
141
- },
142
100
  });
143
101
  }
package/src/schema.ts CHANGED
@@ -17,14 +17,14 @@
17
17
  * @module
18
18
  */
19
19
 
20
- import { string } from "@dbx-tools/shared-core";
20
+ import { stringUtils } from "@dbx-tools/shared-core";
21
21
  import { z } from "zod";
22
22
 
23
23
  /**
24
24
  * Description the model reads for `web_search`. Shared by the Mastra tool and
25
25
  * the AppKit tool provider so both hosts describe the tool identically.
26
26
  */
27
- export const WEB_SEARCH_TOOL_DESCRIPTION = string.toDescription(`
27
+ export const WEB_SEARCH_TOOL_DESCRIPTION = stringUtils.toDescription(`
28
28
  Search the web for current information and get an answer synthesized from
29
29
  live results, with the sources it used. Pass a natural-language query;
30
30
  the search runs inside a web-search-capable model (chosen independently
@@ -34,7 +34,7 @@ export const WEB_SEARCH_TOOL_DESCRIPTION = string.toDescription(`
34
34
  `);
35
35
 
36
36
  /** Description the model reads for `web_fetch`. Shared like {@link WEB_SEARCH_TOOL_DESCRIPTION}. */
37
- export const WEB_FETCH_TOOL_DESCRIPTION = string.toDescription(`
37
+ export const WEB_FETCH_TOOL_DESCRIPTION = stringUtils.toDescription(`
38
38
  Fetch a single web page and return its readable contents. Pass an
39
39
  absolute URL (including https://); set format to "html" for raw markup
40
40
  instead of extracted text. Use it to read a page returned by web_search
@@ -53,7 +53,7 @@ export const webSearchRequestSchema = z.object({
53
53
  .string()
54
54
  .optional()
55
55
  .describe(
56
- string.toDescription(`
56
+ stringUtils.toDescription(`
57
57
  Optional web-search-capable model to use (a Databricks serving
58
58
  endpoint name like "databricks-gemini-3-pro", a loose name like "gpt"
59
59
  or "gemini", or a capability class). Defaults to the plugin's
@@ -103,7 +103,7 @@ export const webFetchRequestSchema = z.object({
103
103
  .enum(["text", "html"])
104
104
  .optional()
105
105
  .describe(
106
- string.toDescription(`
106
+ stringUtils.toDescription(`
107
107
  Return format: "text" (default) strips the page to readable plain
108
108
  text; "html" returns the raw response body. Prefer "text" unless you
109
109
  need the markup.