@dbx-tools/teams 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.
@@ -0,0 +1,430 @@
1
+ /**
2
+ * AppKit plugin (registered name: `teams`) that owns the Teams Adaptive Card
3
+ * runtime - the resolved card version and the optional incoming-webhook URL the
4
+ * {@link teamsCardTool} and the AppKit `teams.createCard` tool read. Registering
5
+ * it resolves and logs the effective config (which card version is in force,
6
+ * whether a webhook is wired up) so a misconfiguration is visible in the boot
7
+ * logs rather than on the first card, and installs the plugin's `execute()` as
8
+ * the runtime's executor so every build / post picks up AppKit's cache / retry /
9
+ * timeout / telemetry chain.
10
+ *
11
+ * The plugin is also a `ToolProvider`, so an AppKit agent can reach a
12
+ * `teams.createCard` tool directly; the {@link teamsCardTool} export is the same
13
+ * capability for a Mastra agent. Both share the runtime primed here.
14
+ *
15
+ * The plugin mounts four routes under its base path (`/api/teams`):
16
+ *
17
+ * - `POST /messages` is the REAL Microsoft Teams messaging endpoint - the URL
18
+ * an Azure Bot registration points at. It validates the Bot Service JWT,
19
+ * acknowledges immediately, and delivers the agent's card back over the
20
+ * Connector API. This is the route that makes a Teams channel able to chat
21
+ * with the app's agents, the same way the Mastra plugin exposes MCP at a
22
+ * path.
23
+ * - `POST /activity` runs the same turn SYNCHRONOUSLY, answering with the
24
+ * reply activities in the response body. It needs no bot registration, so
25
+ * it is what a local client (the in-repo preview chat), a test, or any
26
+ * non-Teams caller uses.
27
+ * - `POST /card` compiles a {@link card.CardSpec} into an Adaptive Card
28
+ * document (the preview page posts here).
29
+ * - `POST /post` pushes a compiled card to the configured Teams incoming
30
+ * webhook when one is set.
31
+ *
32
+ * Mirrors the node-email add-on's shape.
33
+ *
34
+ * @module
35
+ */
36
+ import { Plugin, toPlugin, } from "@databricks/appkit";
37
+ import { defineTool, executeFromRegistry, toolsFromRegistry, } from "@databricks/appkit/beta";
38
+ import { error, log, object, string } from "@dbx-tools/shared-core";
39
+ import { activity as activityContract, card } from "@dbx-tools/shared-teams";
40
+ import { verifyBotToken } from "./auth.js";
41
+ import { TEAMS_CONFIG_SCHEMA } from "./config.js";
42
+ import { promptOf, resolveCardAgent, resolveCardContextFactory, runCardTurn } from "./conversation.js";
43
+ import { TEAMS_BUILD_SETTINGS, TEAMS_POST_SETTINGS, TEAMS_TURN_SETTINGS } from "./defaults.js";
44
+ import { deliverTurn, resolveServiceUrl } from "./messaging.js";
45
+ import { buildCard, getTeamsRuntime, postCard, resetTeamsRuntime, setTeamsExecutor, } from "./runtime.js";
46
+ import { CREATE_CARD_DESCRIPTION } from "./tool.js";
47
+ /** Mount-relative route (under `/api/teams`) for compiling a card. */
48
+ const CARD_ROUTE = "/card";
49
+ /** Mount-relative route (under `/api/teams`) for posting a card to a webhook. */
50
+ const POST_ROUTE = "/post";
51
+ /**
52
+ * Mount-relative route (under `/api/teams`) for one conversation turn: a Bot
53
+ * Framework activity in, activities carrying Adaptive Cards back.
54
+ */
55
+ const ACTIVITY_ROUTE = "/activity";
56
+ /**
57
+ * Mount-relative route (under `/api/teams`) for the Teams messaging endpoint.
58
+ * This is the path a bot registration's messaging endpoint points at, i.e.
59
+ * `https://<host>/api/teams/messages`.
60
+ */
61
+ const MESSAGES_ROUTE = "/messages";
62
+ /** Registry key of the agent tool, which agents address as `teams.createCard`. */
63
+ const CREATE_TOOL = "createCard";
64
+ const logger = log.logger("teams");
65
+ /**
66
+ * AppKit plugin that configures the Adaptive Card builder used by the
67
+ * `create_teams_card` tool, and exposes card building as an AppKit agent tool.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { createApp, server } from "@databricks/appkit";
72
+ * import { plugin as teamsPlugin } from "@dbx-tools/teams";
73
+ *
74
+ * await createApp({
75
+ * plugins: [
76
+ * server(),
77
+ * teamsPlugin.teams({ webhookUrl: process.env.TEAMS_WEBHOOK_URL }),
78
+ * ],
79
+ * });
80
+ * ```
81
+ */
82
+ export class TeamsPlugin extends Plugin {
83
+ static manifest = {
84
+ name: "teams",
85
+ displayName: "Teams",
86
+ description: "Answers chat turns as Microsoft Teams Adaptive Cards over a Bot " +
87
+ "Framework activity endpoint, builds cards from a small structured card " +
88
+ "description, and optionally posts them to a Teams incoming webhook.",
89
+ stability: "beta",
90
+ resources: {
91
+ required: [],
92
+ optional: [],
93
+ },
94
+ config: { schema: TEAMS_CONFIG_SCHEMA },
95
+ };
96
+ /**
97
+ * The tool this plugin offers to an AppKit agent.
98
+ *
99
+ * Marked `autoInheritable`: building a card is a pure, side-effect-free
100
+ * transform (nothing leaves the building), so it is safe to hand to any
101
+ * agent by default - unlike a send.
102
+ *
103
+ * `execute` re-parses its arguments with the local schema: AppKit validates
104
+ * against the same schema first, but re-parsing is what gives the body typed
105
+ * arguments instead of `unknown`.
106
+ */
107
+ tools = {
108
+ [CREATE_TOOL]: defineTool({
109
+ description: CREATE_CARD_DESCRIPTION,
110
+ schema: card.cardSpecSchema,
111
+ annotations: { effect: "read" },
112
+ autoInheritable: true,
113
+ execute: async (args, signal) => buildCard(card.cardSpecSchema.parse(args), signal),
114
+ }),
115
+ };
116
+ /**
117
+ * Prime the shared runtime from this plugin's config (over env), route the
118
+ * tool's builds through this plugin's interceptor chain, and log the
119
+ * effective config so the resolved card version and whether a webhook is
120
+ * wired up are obvious at boot.
121
+ */
122
+ async setup() {
123
+ const { config } = getTeamsRuntime(this.config);
124
+ setTeamsExecutor((fn, settings) => this.execute(fn, settings));
125
+ logger.info("ready", {
126
+ cardVersion: config.cardVersion,
127
+ webhook: config.webhookUrl ? "configured" : "disabled",
128
+ messaging: config.allowUnauthenticated
129
+ ? "UNAUTHENTICATED (development)"
130
+ : config.appId && config.appPassword
131
+ ? "bot registration configured"
132
+ : "disabled (no appId/appPassword)",
133
+ });
134
+ // An endpoint serving agent turns with no auth is worth a warning on every
135
+ // boot, not a line buried in an info payload.
136
+ if (config.allowUnauthenticated) {
137
+ logger.warn("POST /messages is serving UNAUTHENTICATED turns - any caller that can " +
138
+ "reach this route can drive the agent. Development only; never expose this.");
139
+ }
140
+ }
141
+ /** Drop the shared runtime. Idempotent. */
142
+ async shutdown() {
143
+ resetTeamsRuntime();
144
+ }
145
+ /**
146
+ * Mount the card-building and card-posting routes under the plugin base
147
+ * path (`/api/teams`). `POST /card` is what the dev display page calls to
148
+ * preview a card live; `POST /post` pushes a compiled card to the configured
149
+ * Teams incoming webhook.
150
+ *
151
+ * Neither route is wrapped in `asUser(req)`: compiling a card is a pure
152
+ * transform of the request body and posting goes to a preconfigured webhook,
153
+ * so neither reads workspace data on the caller's behalf and neither needs an
154
+ * OBO token. Wrapping them would make the routes throw
155
+ * `AuthenticationError` whenever the user-token header is absent (a local
156
+ * `curl`, a health probe), which - since AppKit does not catch a rejection
157
+ * raised inside the handler - takes the process down rather than answering
158
+ * 401.
159
+ */
160
+ injectRoutes(router) {
161
+ this.route(router, {
162
+ name: "buildCard",
163
+ method: "post",
164
+ path: CARD_ROUTE,
165
+ handler: async (req, res) => {
166
+ const result = await this.executeBuild(req.body);
167
+ if (!result.ok) {
168
+ res.status(result.status).json({ error: result.message });
169
+ return;
170
+ }
171
+ res.json(result.data);
172
+ },
173
+ });
174
+ this.route(router, {
175
+ name: "activity",
176
+ method: "post",
177
+ path: ACTIVITY_ROUTE,
178
+ handler: async (req, res) => {
179
+ const result = await this.executeTurn(req.body);
180
+ if (!result.ok) {
181
+ res.status(result.status).json({ error: result.message });
182
+ return;
183
+ }
184
+ res.json(result.data);
185
+ },
186
+ });
187
+ this.route(router, {
188
+ name: "postCard",
189
+ method: "post",
190
+ path: POST_ROUTE,
191
+ handler: async (req, res) => {
192
+ const result = await this.executePost(req.body);
193
+ if (!result.ok) {
194
+ res.status(result.status).json({ error: result.message });
195
+ return;
196
+ }
197
+ res.json({ ok: true });
198
+ },
199
+ });
200
+ // The real Teams messaging endpoint. Unlike every other route here it is
201
+ // called by Azure Bot Service over the public internet, so it authenticates
202
+ // itself from the inbound JWT and answers `200` before the agent has run.
203
+ this.route(router, {
204
+ name: "messages",
205
+ method: "post",
206
+ path: MESSAGES_ROUTE,
207
+ handler: async (req, res) => {
208
+ await this.handleMessage(req, res);
209
+ },
210
+ });
211
+ }
212
+ exports() {
213
+ return {
214
+ /**
215
+ * Compile a card spec into an Adaptive Card document. For agent-driven
216
+ * builds use {@link teamsCardTool} instead.
217
+ */
218
+ buildCard: (spec, signal) => buildCard(spec, signal),
219
+ /**
220
+ * Post a compiled card to the configured Teams incoming webhook. Throws
221
+ * when no webhook is configured.
222
+ */
223
+ postCard: (cardDocument, signal) => postCard(cardDocument, signal),
224
+ };
225
+ }
226
+ /** AppKit `ToolProvider`: the tool definitions offered to an agent. */
227
+ getAgentTools() {
228
+ return toolsFromRegistry(this.tools);
229
+ }
230
+ /**
231
+ * AppKit `ToolProvider`: run one tool call. Arguments are validated against
232
+ * the tool's schema first, and a validation failure comes back as an
233
+ * LLM-friendly string so the model can correct itself on the next turn.
234
+ */
235
+ async executeAgentTool(name, args, signal) {
236
+ return executeFromRegistry(this.tools, name, args, signal);
237
+ }
238
+ /**
239
+ * Handle one inbound request from Azure Bot Service on `POST /messages`.
240
+ *
241
+ * The order of operations is dictated by how Bot Service behaves, not by
242
+ * convenience:
243
+ *
244
+ * 1. **Refuse when unconfigured.** With no `appId` there is no audience to
245
+ * validate a token against, so the endpoint cannot be operated safely;
246
+ * it answers 503 rather than processing an unauthenticated activity.
247
+ * 2. **Validate the JWT before parsing the body.** The token is the only
248
+ * trust boundary this endpoint has.
249
+ * 3. **Pin the reply destination to the token.** `serviceUrl` arrives in the
250
+ * body, and replies carry the bot's credentials, so it is only honored
251
+ * when it matches the verified token.
252
+ * 4. **Answer 200 immediately, then run the agent.** Bot Service times out
253
+ * an unacknowledged activity in seconds and RETRIES it; a card takes far
254
+ * longer than that, and a retry would post a duplicate card.
255
+ *
256
+ * Activities that carry no prompt (`typing`, `conversationUpdate`, an
257
+ * attachment-only message) are acknowledged and dropped - exactly what a bot
258
+ * does with them.
259
+ */
260
+ async handleMessage(req, res) {
261
+ const { config } = getTeamsRuntime(this.config);
262
+ // Local development mode: no bot registration, no token, and the reply comes
263
+ // back in the HTTP response rather than through the Connector API (there is
264
+ // no `serviceUrl` to call back to). This is what lets the in-repo preview
265
+ // chat and the Bot Framework Emulator drive the same route Teams uses.
266
+ if (config.allowUnauthenticated) {
267
+ // Accept both envelopes: a bare activity (what Bot Service and the
268
+ // emulator POST) and the `{ activity, agentId }` request shape the
269
+ // `/activity` route takes, so a local client can still choose an agent.
270
+ const body = object.isRecord(req.body) && object.isRecord(req.body.activity)
271
+ ? req.body
272
+ : { activity: req.body };
273
+ const result = await this.executeTurn(body);
274
+ if (!result.ok) {
275
+ res.status(result.status).json({ error: result.message });
276
+ return;
277
+ }
278
+ res.json(result.data);
279
+ return;
280
+ }
281
+ if (!config.appId || !config.appPassword) {
282
+ res.status(503).json({
283
+ error: "teams: messaging endpoint is not configured - set appId/appPassword " +
284
+ "(TEAMS_APP_ID / TEAMS_APP_PASSWORD) from the Azure Bot registration",
285
+ });
286
+ return;
287
+ }
288
+ const authorization = readHeader(req.headers, "authorization");
289
+ let verified;
290
+ try {
291
+ verified = await verifyBotToken(authorization, {
292
+ appId: config.appId,
293
+ ...(config.appTenantId ? { appTenantId: config.appTenantId } : {}),
294
+ });
295
+ }
296
+ catch (err) {
297
+ // Deliberately terse: a caller failing authentication learns only that it
298
+ // failed, while the reason goes to the logs.
299
+ logger.warn("rejected an unauthenticated request", { error: error.errorMessage(err) });
300
+ res.status(401).json({ error: "unauthorized" });
301
+ return;
302
+ }
303
+ const parsed = activityContract.activitySchema.safeParse(req.body);
304
+ if (!parsed.success) {
305
+ res.status(400).json({ error: parsed.error.message });
306
+ return;
307
+ }
308
+ const inbound = parsed.data;
309
+ const serviceUrl = resolveServiceUrl(inbound, verified.serviceUrl);
310
+ if (!serviceUrl) {
311
+ logger.warn("rejected an activity with no usable serviceUrl", {
312
+ type: inbound.type,
313
+ });
314
+ res.status(400).json({ error: "activity carried no acceptable serviceUrl" });
315
+ return;
316
+ }
317
+ const agent = resolveCardAgent(this.context?.getPlugins(), config.agentPlugin);
318
+ if (!agent) {
319
+ logger.error("no agent available to answer a Teams turn", {
320
+ agentPlugin: config.agentPlugin,
321
+ });
322
+ res.status(503).json({ error: "no agent available" });
323
+ return;
324
+ }
325
+ // Acknowledge FIRST. Everything after this point is out-of-band work whose
326
+ // result reaches the user through the Connector API, not this response.
327
+ res.status(200).json({});
328
+ if (!promptOf(inbound))
329
+ return;
330
+ const createRequestContext = resolveCardContextFactory(this.context?.getPlugins(), config.agentPlugin);
331
+ void deliverTurn({
332
+ agent,
333
+ activity: inbound,
334
+ serviceUrl,
335
+ ...(createRequestContext ? { createRequestContext } : {}),
336
+ credentials: {
337
+ appId: config.appId,
338
+ appPassword: config.appPassword,
339
+ ...(config.appTenantId ? { appTenantId: config.appTenantId } : {}),
340
+ },
341
+ });
342
+ }
343
+ /** Compile a card, validating the request body against the spec schema. */
344
+ async executeBuild(body) {
345
+ const parsed = card.cardSpecSchema.safeParse(body);
346
+ if (!parsed.success) {
347
+ return { ok: false, status: 400, message: parsed.error.message };
348
+ }
349
+ return this.execute(async (signal) => buildCard(parsed.data, signal), TEAMS_BUILD_SETTINGS);
350
+ }
351
+ /**
352
+ * Run one conversation turn: validate the inbound activity, resolve the agent
353
+ * from the sibling agent plugin, and answer with card-carrying activities.
354
+ *
355
+ * Resolution failures are reported distinctly because they have different
356
+ * fixes: 503 when no agent plugin is mounted at all (a wiring problem), 404
357
+ * when the caller named an `agentId` that is not registered (a request
358
+ * problem).
359
+ */
360
+ async executeTurn(body) {
361
+ const parsed = activityContract.activityRequestSchema.safeParse(body);
362
+ if (!parsed.success) {
363
+ return { ok: false, status: 400, message: parsed.error.message };
364
+ }
365
+ const { activity, agentId } = parsed.data;
366
+ const { config } = getTeamsRuntime(this.config);
367
+ const agent = resolveCardAgent(this.context?.getPlugins(), config.agentPlugin, agentId);
368
+ if (!agent) {
369
+ return agentId
370
+ ? { ok: false, status: 404, message: `teams: unknown agent '${agentId}'` }
371
+ : {
372
+ ok: false,
373
+ status: 503,
374
+ message: `teams: no agent available - is the '${config.agentPlugin}' plugin registered?`,
375
+ };
376
+ }
377
+ const createRequestContext = resolveCardContextFactory(this.context?.getPlugins(), config.agentPlugin);
378
+ return this.execute(async (signal) => {
379
+ const activities = await runCardTurn(agent, activity, {
380
+ ...(createRequestContext ? { createRequestContext } : {}),
381
+ ...(signal ? { signal } : {}),
382
+ });
383
+ return { activities };
384
+ }, TEAMS_TURN_SETTINGS);
385
+ }
386
+ /**
387
+ * Compile then post a card, validating the request body against the spec
388
+ * schema. The compile is folded INTO the executed callback so a throw from
389
+ * either half (a build failure, or `postCard` refusing because no webhook is
390
+ * configured) comes back as a failed {@link ExecutionResult} the route can
391
+ * answer with, rather than escaping the handler as an unhandled rejection.
392
+ */
393
+ async executePost(body) {
394
+ const parsed = card.cardSpecSchema.safeParse(body);
395
+ if (!parsed.success) {
396
+ return { ok: false, status: 400, message: parsed.error.message };
397
+ }
398
+ return this.execute(async (signal) => {
399
+ const built = await buildCard(parsed.data, signal);
400
+ await postCard(built.card, signal);
401
+ }, TEAMS_POST_SETTINGS);
402
+ }
403
+ }
404
+ /**
405
+ * Register the Teams plugin.
406
+ *
407
+ * @example
408
+ * ```ts
409
+ * import { createApp, server } from "@databricks/appkit";
410
+ * import { plugin as teamsPlugin } from "@dbx-tools/teams";
411
+ *
412
+ * await createApp({
413
+ * plugins: [server(), teamsPlugin.teams()],
414
+ * });
415
+ * ```
416
+ */
417
+ export const teams = toPlugin(TeamsPlugin);
418
+ /**
419
+ * Read one header value, normalizing Node's `string | string[]` shape.
420
+ *
421
+ * Express lower-cases incoming header names, but this is written against a
422
+ * structural `headers` record (so the handler stays testable without an Express
423
+ * request), hence the explicit case-insensitive lookup.
424
+ */
425
+ function readHeader(headers, name) {
426
+ const direct = headers[name] ?? headers[name.toLowerCase()];
427
+ const value = Array.isArray(direct) ? direct[0] : direct;
428
+ return typeof value === "string" ? (string.trimToNull(value) ?? undefined) : undefined;
429
+ }
430
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtDRztBQUVILE9BQU8sRUFDTCxNQUFNLEVBQ04sUUFBUSxHQUlULE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUNMLFVBQVUsRUFDVixtQkFBbUIsRUFDbkIsaUJBQWlCLEdBSWxCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxRQUFRLElBQUksZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDN0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN4QyxPQUFPLEVBQUUsbUJBQW1CLEVBQTBCLE1BQU0sVUFBVSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLEVBQUUseUJBQXlCLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDcEcsT0FBTyxFQUFFLG9CQUFvQixFQUFFLG1CQUFtQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzVGLE9BQU8sRUFBRSxXQUFXLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDN0QsT0FBTyxFQUNMLFNBQVMsRUFDVCxlQUFlLEVBQ2YsUUFBUSxFQUNSLGlCQUFpQixFQUNqQixnQkFBZ0IsR0FDakIsTUFBTSxXQUFXLENBQUM7QUFDbkIsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRWpELHNFQUFzRTtBQUN0RSxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUM7QUFFM0IsaUZBQWlGO0FBQ2pGLE1BQU0sVUFBVSxHQUFHLE9B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RSxJQUFZO0lBQ2hFLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDNUQsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDekQsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ3pGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEFwcEtpdCBwbHVnaW4gKHJlZ2lzdGVyZWQgbmFtZTogYHRlYW1zYCkgdGhhdCBvd25zIHRoZSBUZWFtcyBBZGFwdGl2ZSBDYXJkXG4gKiBydW50aW1lIC0gdGhlIHJlc29sdmVkIGNhcmQgdmVyc2lvbiBhbmQgdGhlIG9wdGlvbmFsIGluY29taW5nLXdlYmhvb2sgVVJMIHRoZVxuICoge0BsaW5rIHRlYW1zQ2FyZFRvb2x9IGFuZCB0aGUgQXBwS2l0IGB0ZWFtcy5jcmVhdGVDYXJkYCB0b29sIHJlYWQuIFJlZ2lzdGVyaW5nXG4gKiBpdCByZXNvbHZlcyBhbmQgbG9ncyB0aGUgZWZmZWN0aXZlIGNvbmZpZyAod2hpY2ggY2FyZCB2ZXJzaW9uIGlzIGluIGZvcmNlLFxuICogd2hldGhlciBhIHdlYmhvb2sgaXMgd2lyZWQgdXApIHNvIGEgbWlzY29uZmlndXJhdGlvbiBpcyB2aXNpYmxlIGluIHRoZSBib290XG4gKiBsb2dzIHJhdGhlciB0aGFuIG9uIHRoZSBmaXJzdCBjYXJkLCBhbmQgaW5zdGFsbHMgdGhlIHBsdWdpbidzIGBleGVjdXRlKClgIGFzXG4gKiB0aGUgcnVudGltZSdzIGV4ZWN1dG9yIHNvIGV2ZXJ5IGJ1aWxkIC8gcG9zdCBwaWNrcyB1cCBBcHBLaXQncyBjYWNoZSAvIHJldHJ5IC9cbiAqIHRpbWVvdXQgLyB0ZWxlbWV0cnkgY2hhaW4uXG4gKlxuICogVGhlIHBsdWdpbiBpcyBhbHNvIGEgYFRvb2xQcm92aWRlcmAsIHNvIGFuIEFwcEtpdCBhZ2VudCBjYW4gcmVhY2ggYVxuICogYHRlYW1zLmNyZWF0ZUNhcmRgIHRvb2wgZGlyZWN0bHk7IHRoZSB7QGxpbmsgdGVhbXNDYXJkVG9vbH0gZXhwb3J0IGlzIHRoZSBzYW1lXG4gKiBjYXBhYmlsaXR5IGZvciBhIE1hc3RyYSBhZ2VudC4gQm90aCBzaGFyZSB0aGUgcnVudGltZSBwcmltZWQgaGVyZS5cbiAqXG4gKiBUaGUgcGx1Z2luIG1vdW50cyBmb3VyIHJvdXRlcyB1bmRlciBpdHMgYmFzZSBwYXRoIChgL2FwaS90ZWFtc2ApOlxuICpcbiAqICAgLSBgUE9TVCAvbWVzc2FnZXNgIGlzIHRoZSBSRUFMIE1pY3Jvc29mdCBUZWFtcyBtZXNzYWdpbmcgZW5kcG9pbnQgLSB0aGUgVVJMXG4gKiAgICAgYW4gQXp1cmUgQm90IHJlZ2lzdHJhdGlvbiBwb2ludHMgYXQuIEl0IHZhbGlkYXRlcyB0aGUgQm90IFNlcnZpY2UgSldULFxuICogICAgIGFja25vd2xlZGdlcyBpbW1lZGlhdGVseSwgYW5kIGRlbGl2ZXJzIHRoZSBhZ2VudCdzIGNhcmQgYmFjayBvdmVyIHRoZVxuICogICAgIENvbm5lY3RvciBBUEkuIFRoaXMgaXMgdGhlIHJvdXRlIHRoYXQgbWFrZXMgYSBUZWFtcyBjaGFubmVsIGFibGUgdG8gY2hhdFxuICogICAgIHdpdGggdGhlIGFwcCdzIGFnZW50cywgdGhlIHNhbWUgd2F5IHRoZSBNYXN0cmEgcGx1Z2luIGV4cG9zZXMgTUNQIGF0IGFcbiAqICAgICBwYXRoLlxuICogICAtIGBQT1NUIC9hY3Rpdml0eWAgcnVucyB0aGUgc2FtZSB0dXJuIFNZTkNIUk9OT1VTTFksIGFuc3dlcmluZyB3aXRoIHRoZVxuICogICAgIHJlcGx5IGFjdGl2aXRpZXMgaW4gdGhlIHJlc3BvbnNlIGJvZHkuIEl0IG5lZWRzIG5vIGJvdCByZWdpc3RyYXRpb24sIHNvXG4gKiAgICAgaXQgaXMgd2hhdCBhIGxvY2FsIGNsaWVudCAodGhlIGluLXJlcG8gcHJldmlldyBjaGF0KSwgYSB0ZXN0LCBvciBhbnlcbiAqICAgICBub24tVGVhbXMgY2FsbGVyIHVzZXMuXG4gKiAgIC0gYFBPU1QgL2NhcmRgIGNvbXBpbGVzIGEge0BsaW5rIGNhcmQuQ2FyZFNwZWN9IGludG8gYW4gQWRhcHRpdmUgQ2FyZFxuICogICAgIGRvY3VtZW50ICh0aGUgcHJldmlldyBwYWdlIHBvc3RzIGhlcmUpLlxuICogICAtIGBQT1NUIC9wb3N0YCBwdXNoZXMgYSBjb21waWxlZCBjYXJkIHRvIHRoZSBjb25maWd1cmVkIFRlYW1zIGluY29taW5nXG4gKiAgICAgd2ViaG9vayB3aGVuIG9uZSBpcyBzZXQuXG4gKlxuICogTWlycm9ycyB0aGUgbm9kZS1lbWFpbCBhZGQtb24ncyBzaGFwZS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHtcbiAgUGx1Z2luLFxuICB0b1BsdWdpbixcbiAgdHlwZSBFeGVjdXRpb25SZXN1bHQsXG4gIHR5cGUgSUFwcFJvdXRlcixcbiAgdHlwZSBQbHVnaW5NYW5pZmVzdCxcbn0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHtcbiAgZGVmaW5lVG9vbCxcbiAgZXhlY3V0ZUZyb21SZWdpc3RyeSxcbiAgdG9vbHNGcm9tUmVnaXN0cnksXG4gIHR5cGUgQWdlbnRUb29sRGVmaW5pdGlvbixcbiAgdHlwZSBUb29sUHJvdmlkZXIsXG4gIHR5cGUgVG9vbFJlZ2lzdHJ5LFxufSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0L2JldGFcIjtcbmltcG9ydCB7IGVycm9yLCBsb2csIG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGFjdGl2aXR5IGFzIGFjdGl2aXR5Q29udHJhY3QsIGNhcmQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtdGVhbXNcIjtcbmltcG9ydCB7IHZlcmlmeUJvdFRva2VuIH0gZnJvbSBcIi4vYXV0aFwiO1xuaW1wb3J0IHsgVEVBTVNfQ09ORklHX1NDSEVNQSwgdHlwZSBUZWFtc1BsdWdpbkNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgcHJvbXB0T2YsIHJlc29sdmVDYXJkQWdlbnQsIHJlc29sdmVDYXJkQ29udGV4dEZhY3RvcnksIHJ1bkNhcmRUdXJuIH0gZnJvbSBcIi4vY29udmVyc2F0aW9uXCI7XG5pbXBvcnQgeyBURUFNU19CVUlMRF9TRVRUSU5HUywgVEVBTVNfUE9TVF9TRVRUSU5HUywgVEVBTVNfVFVSTl9TRVRUSU5HUyB9IGZyb20gXCIuL2RlZmF1bHRzXCI7XG5pbXBvcnQgeyBkZWxpdmVyVHVybiwgcmVzb2x2ZVNlcnZpY2VVcmwgfSBmcm9tIFwiLi9tZXNzYWdpbmdcIjtcbmltcG9ydCB7XG4gIGJ1aWxkQ2FyZCxcbiAgZ2V0VGVhbXNSdW50aW1lLFxuICBwb3N0Q2FyZCxcbiAgcmVzZXRUZWFtc1J1bnRpbWUsXG4gIHNldFRlYW1zRXhlY3V0b3IsXG59IGZyb20gXCIuL3J1bnRpbWVcIjtcbmltcG9ydCB7IENSRUFURV9DQVJEX0RFU0NSSVBUSU9OIH0gZnJvbSBcIi4vdG9vbFwiO1xuXG4vKiogTW91bnQtcmVsYXRpdmUgcm91dGUgKHVuZGVyIGAvYXBpL3RlYW1zYCkgZm9yIGNvbXBpbGluZyBhIGNhcmQuICovXG5jb25zdCBDQVJEX1JPVVRFID0gXCIvY2FyZFwiO1xuXG4vKiogTW91bnQtcmVsYXRpdmUgcm91dGUgKHVuZGVyIGAvYXBpL3RlYW1zYCkgZm9yIHBvc3RpbmcgYSBjYXJkIHRvIGEgd2ViaG9vay4gKi9cbmNvbnN0IFBPU1RfUk9VVEUgPSBcIi9wb3N0XCI7XG5cbi8qKlxuICogTW91bnQtcmVsYXRpdmUgcm91dGUgKHVuZGVyIGAvYXBpL3RlYW1zYCkgZm9yIG9uZSBjb252ZXJzYXRpb24gdHVybjogYSBCb3RcbiAqIEZyYW1ld29yayBhY3Rpdml0eSBpbiwgYWN0aXZpdGllcyBjYXJyeWluZyBBZGFwdGl2ZSBDYXJkcyBiYWNrLlxuICovXG5jb25zdCBBQ1RJVklUWV9ST1VURSA9IFwiL2FjdGl2aXR5XCI7XG5cbi8qKlxuICogTW91bnQtcmVsYXRpdmUgcm91dGUgKHVuZGVyIGAvYXBpL3RlYW1zYCkgZm9yIHRoZSBUZWFtcyBtZXNzYWdpbmcgZW5kcG9pbnQuXG4gKiBUaGlzIGlzIHRoZSBwYXRoIGEgYm90IHJlZ2lzdHJhdGlvbidzIG1lc3NhZ2luZyBlbmRwb2ludCBwb2ludHMgYXQsIGkuZS5cbiAqIGBodHRwczovLzxob3N0Pi9hcGkvdGVhbXMvbWVzc2FnZXNgLlxuICovXG5jb25zdCBNRVNTQUdFU19ST1VURSA9IFwiL21lc3NhZ2VzXCI7XG5cbi8qKiBSZWdpc3RyeSBrZXkgb2YgdGhlIGFnZW50IHRvb2wsIHdoaWNoIGFnZW50cyBhZGRyZXNzIGFzIGB0ZWFtcy5jcmVhdGVDYXJkYC4gKi9cbmNvbnN0IENSRUFURV9UT09MID0gXCJjcmVhdGVDYXJkXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ0ZWFtc1wiKTtcblxuLyoqXG4gKiBBcHBLaXQgcGx1Z2luIHRoYXQgY29uZmlndXJlcyB0aGUgQWRhcHRpdmUgQ2FyZCBidWlsZGVyIHVzZWQgYnkgdGhlXG4gKiBgY3JlYXRlX3RlYW1zX2NhcmRgIHRvb2wsIGFuZCBleHBvc2VzIGNhcmQgYnVpbGRpbmcgYXMgYW4gQXBwS2l0IGFnZW50IHRvb2wuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjcmVhdGVBcHAsIHNlcnZlciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbiAqIGltcG9ydCB7IHBsdWdpbiBhcyB0ZWFtc1BsdWdpbiB9IGZyb20gXCJAZGJ4LXRvb2xzL3RlYW1zXCI7XG4gKlxuICogYXdhaXQgY3JlYXRlQXBwKHtcbiAqICAgcGx1Z2luczogW1xuICogICAgIHNlcnZlcigpLFxuICogICAgIHRlYW1zUGx1Z2luLnRlYW1zKHsgd2ViaG9va1VybDogcHJvY2Vzcy5lbnYuVEVBTVNfV0VCSE9PS19VUkwgfSksXG4gKiAgIF0sXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgVGVhbXNQbHVnaW4gZXh0ZW5kcyBQbHVnaW48VGVhbXNQbHVnaW5Db25maWc+IGltcGxlbWVudHMgVG9vbFByb3ZpZGVyIHtcbiAgc3RhdGljIG1hbmlmZXN0ID0ge1xuICAgIG5hbWU6IFwidGVhbXNcIixcbiAgICBkaXNwbGF5TmFtZTogXCJUZWFtc1wiLFxuICAgIGRlc2NyaXB0aW9uOlxuICAgICAgXCJBbnN3ZXJzIGNoYXQgdHVybnMgYXMgTWljcm9zb2Z0IFRlYW1zIEFkYXB0aXZlIENhcmRzIG92ZXIgYSBCb3QgXCIgK1xuICAgICAgXCJGcmFtZXdvcmsgYWN0aXZpdHkgZW5kcG9pbnQsIGJ1aWxkcyBjYXJkcyBmcm9tIGEgc21hbGwgc3RydWN0dXJlZCBjYXJkIFwiICtcbiAgICAgIFwiZGVzY3JpcHRpb24sIGFuZCBvcHRpb25hbGx5IHBvc3RzIHRoZW0gdG8gYSBUZWFtcyBpbmNvbWluZyB3ZWJob29rLlwiLFxuICAgIHN0YWJpbGl0eTogXCJiZXRhXCIsXG4gICAgcmVzb3VyY2VzOiB7XG4gICAgICByZXF1aXJlZDogW10sXG4gICAgICBvcHRpb25hbDogW10sXG4gICAgfSxcbiAgICBjb25maWc6IHsgc2NoZW1hOiBURUFNU19DT05GSUdfU0NIRU1BIH0sXG4gIH0gc2F0aXNmaWVzIFBsdWdpbk1hbmlmZXN0PFwidGVhbXNcIj47XG5cbiAgLyoqXG4gICAqIFRoZSB0b29sIHRoaXMgcGx1Z2luIG9mZmVycyB0byBhbiBBcHBLaXQgYWdlbnQuXG4gICAqXG4gICAqIE1hcmtlZCBgYXV0b0luaGVyaXRhYmxlYDogYnVpbGRpbmcgYSBjYXJkIGlzIGEgcHVyZSwgc2lkZS1lZmZlY3QtZnJlZVxuICAgKiB0cmFuc2Zvcm0gKG5vdGhpbmcgbGVhdmVzIHRoZSBidWlsZGluZyksIHNvIGl0IGlzIHNhZmUgdG8gaGFuZCB0byBhbnlcbiAgICogYWdlbnQgYnkgZGVmYXVsdCAtIHVubGlrZSBhIHNlbmQuXG4gICAqXG4gICAqIGBleGVjdXRlYCByZS1wYXJzZXMgaXRzIGFyZ3VtZW50cyB3aXRoIHRoZSBsb2NhbCBzY2hlbWE6IEFwcEtpdCB2YWxpZGF0ZXNcbiAgICogYWdhaW5zdCB0aGUgc2FtZSBzY2hlbWEgZmlyc3QsIGJ1dCByZS1wYXJzaW5nIGlzIHdoYXQgZ2l2ZXMgdGhlIGJvZHkgdHlwZWRcbiAgICogYXJndW1lbnRzIGluc3RlYWQgb2YgYHVua25vd25gLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSB0b29sczogVG9vbFJlZ2lzdHJ5ID0ge1xuICAgIFtDUkVBVEVfVE9PTF06IGRlZmluZVRvb2woe1xuICAgICAgZGVzY3JpcHRpb246IENSRUFURV9DQVJEX0RFU0NSSVBUSU9OLFxuICAgICAgc2NoZW1hOiBjYXJkLmNhcmRTcGVjU2NoZW1hLFxuICAgICAgYW5ub3RhdGlvbnM6IHsgZWZmZWN0OiBcInJlYWRcIiB9LFxuICAgICAgYXV0b0luaGVyaXRhYmxlOiB0cnVlLFxuICAgICAgZXhlY3V0ZTogYXN5bmMgKGFyZ3MsIHNpZ25hbCkgPT4gYnVpbGRDYXJkKGNhcmQuY2FyZFNwZWNTY2hlbWEucGFyc2UoYXJncyksIHNpZ25hbCksXG4gICAgfSksXG4gIH07XG5cbiAgLyoqXG4gICAqIFByaW1lIHRoZSBzaGFyZWQgcnVudGltZSBmcm9tIHRoaXMgcGx1Z2luJ3MgY29uZmlnIChvdmVyIGVudiksIHJvdXRlIHRoZVxuICAgKiB0b29sJ3MgYnVpbGRzIHRocm91Z2ggdGhpcyBwbHVnaW4ncyBpbnRlcmNlcHRvciBjaGFpbiwgYW5kIGxvZyB0aGVcbiAgICogZWZmZWN0aXZlIGNvbmZpZyBzbyB0aGUgcmVzb2x2ZWQgY2FyZCB2ZXJzaW9uIGFuZCB3aGV0aGVyIGEgd2ViaG9vayBpc1xuICAgKiB3aXJlZCB1cCBhcmUgb2J2aW91cyBhdCBib290LlxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgc2V0dXAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBjb25maWcgfSA9IGdldFRlYW1zUnVudGltZSh0aGlzLmNvbmZpZyk7XG4gICAgc2V0VGVhbXNFeGVjdXRvcigoZm4sIHNldHRpbmdzKSA9PiB0aGlzLmV4ZWN1dGUoZm4sIHNldHRpbmdzKSk7XG4gICAgbG9nZ2VyLmluZm8oXCJyZWFkeVwiLCB7XG4gICAgICBjYXJkVmVyc2lvbjogY29uZmlnLmNhcmRWZXJzaW9uLFxuICAgICAgd2ViaG9vazogY29uZmlnLndlYmhvb2tVcmwgPyBcImNvbmZpZ3VyZWRcIiA6IFwiZGlzYWJsZWRcIixcbiAgICAgIG1lc3NhZ2luZzogY29uZmlnLmFsbG93VW5hdXRoZW50aWNhdGVkXG4gICAgICAgID8gXCJVTkFVVEhFTlRJQ0FURUQgKGRldmVsb3BtZW50KVwiXG4gICAgICAgIDogY29uZmlnLmFwcElkICYmIGNvbmZpZy5hcHBQYXNzd29yZFxuICAgICAgICAgID8gXCJib3QgcmVnaXN0cmF0aW9uIGNvbmZpZ3VyZWRcIlxuICAgICAgICAgIDogXCJkaXNhYmxlZCAobm8gYXBwSWQvYXBwUGFzc3dvcmQpXCIsXG4gICAgfSk7XG4gICAgLy8gQW4gZW5kcG9pbnQgc2VydmluZyBhZ2VudCB0dXJucyB3aXRoIG5vIGF1dGggaXMgd29ydGggYSB3YXJuaW5nIG9uIGV2ZXJ5XG4gICAgLy8gYm9vdCwgbm90IGEgbGluZSBidXJpZWQgaW4gYW4gaW5mbyBwYXlsb2FkLlxuICAgIGlmIChjb25maWcuYWxsb3dVbmF1dGhlbnRpY2F0ZWQpIHtcbiAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICBcIlBPU1QgL21lc3NhZ2VzIGlzIHNlcnZpbmcgVU5BVVRIRU5USUNBVEVEIHR1cm5zIC0gYW55IGNhbGxlciB0aGF0IGNhbiBcIiArXG4gICAgICAgICAgXCJyZWFjaCB0aGlzIHJvdXRlIGNhbiBkcml2ZSB0aGUgYWdlbnQuIERldmVsb3BtZW50IG9ubHk7IG5ldmVyIGV4cG9zZSB0aGlzLlwiLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKiogRHJvcCB0aGUgc2hhcmVkIHJ1bnRpbWUuIElkZW1wb3RlbnQuICovXG4gIGFzeW5jIHNodXRkb3duKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJlc2V0VGVhbXNSdW50aW1lKCk7XG4gIH1cblxuICAvKipcbiAgICogTW91bnQgdGhlIGNhcmQtYnVpbGRpbmcgYW5kIGNhcmQtcG9zdGluZyByb3V0ZXMgdW5kZXIgdGhlIHBsdWdpbiBiYXNlXG4gICAqIHBhdGggKGAvYXBpL3RlYW1zYCkuIGBQT1NUIC9jYXJkYCBpcyB3aGF0IHRoZSBkZXYgZGlzcGxheSBwYWdlIGNhbGxzIHRvXG4gICAqIHByZXZpZXcgYSBjYXJkIGxpdmU7IGBQT1NUIC9wb3N0YCBwdXNoZXMgYSBjb21waWxlZCBjYXJkIHRvIHRoZSBjb25maWd1cmVkXG4gICAqIFRlYW1zIGluY29taW5nIHdlYmhvb2suXG4gICAqXG4gICAqIE5laXRoZXIgcm91dGUgaXMgd3JhcHBlZCBpbiBgYXNVc2VyKHJlcSlgOiBjb21waWxpbmcgYSBjYXJkIGlzIGEgcHVyZVxuICAgKiB0cmFuc2Zvcm0gb2YgdGhlIHJlcXVlc3QgYm9keSBhbmQgcG9zdGluZyBnb2VzIHRvIGEgcHJlY29uZmlndXJlZCB3ZWJob29rLFxuICAgKiBzbyBuZWl0aGVyIHJlYWRzIHdvcmtzcGFjZSBkYXRhIG9uIHRoZSBjYWxsZXIncyBiZWhhbGYgYW5kIG5laXRoZXIgbmVlZHMgYW5cbiAgICogT0JPIHRva2VuLiBXcmFwcGluZyB0aGVtIHdvdWxkIG1ha2UgdGhlIHJvdXRlcyB0aHJvd1xuICAgKiBgQXV0aGVudGljYXRpb25FcnJvcmAgd2hlbmV2ZXIgdGhlIHVzZXItdG9rZW4gaGVhZGVyIGlzIGFic2VudCAoYSBsb2NhbFxuICAgKiBgY3VybGAsIGEgaGVhbHRoIHByb2JlKSwgd2hpY2ggLSBzaW5jZSBBcHBLaXQgZG9lcyBub3QgY2F0Y2ggYSByZWplY3Rpb25cbiAgICogcmFpc2VkIGluc2lkZSB0aGUgaGFuZGxlciAtIHRha2VzIHRoZSBwcm9jZXNzIGRvd24gcmF0aGVyIHRoYW4gYW5zd2VyaW5nXG4gICAqIDQwMS5cbiAgICovXG4gIG92ZXJyaWRlIGluamVjdFJvdXRlcyhyb3V0ZXI6IElBcHBSb3V0ZXIpOiB2b2lkIHtcbiAgICB0aGlzLnJvdXRlKHJvdXRlciwge1xuICAgICAgbmFtZTogXCJidWlsZENhcmRcIixcbiAgICAgIG1ldGhvZDogXCJwb3N0XCIsXG4gICAgICBwYXRoOiBDQVJEX1JPVVRFLFxuICAgICAgaGFuZGxlcjogYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZXhlY3V0ZUJ1aWxkKHJlcS5ib2R5KTtcbiAgICAgICAgaWYgKCFyZXN1bHQub2spIHtcbiAgICAgICAgICByZXMuc3RhdHVzKHJlc3VsdC5zdGF0dXMpLmpzb24oeyBlcnJvcjogcmVzdWx0Lm1lc3NhZ2UgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHJlcy5qc29uKHJlc3VsdC5kYXRhKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdGhpcy5yb3V0ZShyb3V0ZXIsIHtcbiAgICAgIG5hbWU6IFwiYWN0aXZpdHlcIixcbiAgICAgIG1ldGhvZDogXCJwb3N0XCIsXG4gICAgICBwYXRoOiBBQ1RJVklUWV9ST1VURSxcbiAgICAgIGhhbmRsZXI6IGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmV4ZWN1dGVUdXJuKHJlcS5ib2R5KTtcbiAgICAgICAgaWYgKCFyZXN1bHQub2spIHtcbiAgICAgICAgICByZXMuc3RhdHVzKHJlc3VsdC5zdGF0dXMpLmpzb24oeyBlcnJvcjogcmVzdWx0Lm1lc3NhZ2UgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHJlcy5qc29uKHJlc3VsdC5kYXRhKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdGhpcy5yb3V0ZShyb3V0ZXIsIHtcbiAgICAgIG5hbWU6IFwicG9zdENhcmRcIixcbiAgICAgIG1ldGhvZDogXCJwb3N0XCIsXG4gICAgICBwYXRoOiBQT1NUX1JPVVRFLFxuICAgICAgaGFuZGxlcjogYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZXhlY3V0ZVBvc3QocmVxLmJvZHkpO1xuICAgICAgICBpZiAoIXJlc3VsdC5vaykge1xuICAgICAgICAgIHJlcy5zdGF0dXMocmVzdWx0LnN0YXR1cykuanNvbih7IGVycm9yOiByZXN1bHQubWVzc2FnZSB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcmVzLmpzb24oeyBvazogdHJ1ZSB9KTtcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgLy8gVGhlIHJlYWwgVGVhbXMgbWVzc2FnaW5nIGVuZHBvaW50LiBVbmxpa2UgZXZlcnkgb3RoZXIgcm91dGUgaGVyZSBpdCBpc1xuICAgIC8vIGNhbGxlZCBieSBBenVyZSBCb3QgU2VydmljZSBvdmVyIHRoZSBwdWJsaWMgaW50ZXJuZXQsIHNvIGl0IGF1dGhlbnRpY2F0ZXNcbiAgICAvLyBpdHNlbGYgZnJvbSB0aGUgaW5ib3VuZCBKV1QgYW5kIGFuc3dlcnMgYDIwMGAgYmVmb3JlIHRoZSBhZ2VudCBoYXMgcnVuLlxuICAgIHRoaXMucm91dGUocm91dGVyLCB7XG4gICAgICBuYW1lOiBcIm1lc3NhZ2VzXCIsXG4gICAgICBtZXRob2Q6IFwicG9zdFwiLFxuICAgICAgcGF0aDogTUVTU0FHRVNfUk9VVEUsXG4gICAgICBoYW5kbGVyOiBhc3luYyAocmVxLCByZXMpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5oYW5kbGVNZXNzYWdlKHJlcSwgcmVzKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBvdmVycmlkZSBleHBvcnRzKCkge1xuICAgIHJldHVybiB7XG4gICAgICAvKipcbiAgICAgICAqIENvbXBpbGUgYSBjYXJkIHNwZWMgaW50byBhbiBBZGFwdGl2ZSBDYXJkIGRvY3VtZW50LiBGb3IgYWdlbnQtZHJpdmVuXG4gICAgICAgKiBidWlsZHMgdXNlIHtAbGluayB0ZWFtc0NhcmRUb29sfSBpbnN0ZWFkLlxuICAgICAgICovXG4gICAgICBidWlsZENhcmQ6IChzcGVjOiBjYXJkLkNhcmRTcGVjLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8Y2FyZC5DYXJkUmVzdWx0PiA9PlxuICAgICAgICBidWlsZENhcmQoc3BlYywgc2lnbmFsKSxcbiAgICAgIC8qKlxuICAgICAgICogUG9zdCBhIGNvbXBpbGVkIGNhcmQgdG8gdGhlIGNvbmZpZ3VyZWQgVGVhbXMgaW5jb21pbmcgd2ViaG9vay4gVGhyb3dzXG4gICAgICAgKiB3aGVuIG5vIHdlYmhvb2sgaXMgY29uZmlndXJlZC5cbiAgICAgICAqL1xuICAgICAgcG9zdENhcmQ6IChjYXJkRG9jdW1lbnQ6IGNhcmQuQWRhcHRpdmVDYXJkLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8dm9pZD4gPT5cbiAgICAgICAgcG9zdENhcmQoY2FyZERvY3VtZW50LCBzaWduYWwpLFxuICAgIH07XG4gIH1cblxuICAvKiogQXBwS2l0IGBUb29sUHJvdmlkZXJgOiB0aGUgdG9vbCBkZWZpbml0aW9ucyBvZmZlcmVkIHRvIGFuIGFnZW50LiAqL1xuICBnZXRBZ2VudFRvb2xzKCk6IEFnZW50VG9vbERlZmluaXRpb25bXSB7XG4gICAgcmV0dXJuIHRvb2xzRnJvbVJlZ2lzdHJ5KHRoaXMudG9vbHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcEtpdCBgVG9vbFByb3ZpZGVyYDogcnVuIG9uZSB0b29sIGNhbGwuIEFyZ3VtZW50cyBhcmUgdmFsaWRhdGVkIGFnYWluc3RcbiAgICogdGhlIHRvb2wncyBzY2hlbWEgZmlyc3QsIGFuZCBhIHZhbGlkYXRpb24gZmFpbHVyZSBjb21lcyBiYWNrIGFzIGFuXG4gICAqIExMTS1mcmllbmRseSBzdHJpbmcgc28gdGhlIG1vZGVsIGNhbiBjb3JyZWN0IGl0c2VsZiBvbiB0aGUgbmV4dCB0dXJuLlxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZUFnZW50VG9vbChuYW1lOiBzdHJpbmcsIGFyZ3M6IHVua25vd24sIHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgcmV0dXJuIGV4ZWN1dGVGcm9tUmVnaXN0cnkodGhpcy50b29scywgbmFtZSwgYXJncywgc2lnbmFsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGUgb25lIGluYm91bmQgcmVxdWVzdCBmcm9tIEF6dXJlIEJvdCBTZXJ2aWNlIG9uIGBQT1NUIC9tZXNzYWdlc2AuXG4gICAqXG4gICAqIFRoZSBvcmRlciBvZiBvcGVyYXRpb25zIGlzIGRpY3RhdGVkIGJ5IGhvdyBCb3QgU2VydmljZSBiZWhhdmVzLCBub3QgYnlcbiAgICogY29udmVuaWVuY2U6XG4gICAqXG4gICAqICAgMS4gKipSZWZ1c2Ugd2hlbiB1bmNvbmZpZ3VyZWQuKiogV2l0aCBubyBgYXBwSWRgIHRoZXJlIGlzIG5vIGF1ZGllbmNlIHRvXG4gICAqICAgICAgdmFsaWRhdGUgYSB0b2tlbiBhZ2FpbnN0LCBzbyB0aGUgZW5kcG9pbnQgY2Fubm90IGJlIG9wZXJhdGVkIHNhZmVseTtcbiAgICogICAgICBpdCBhbnN3ZXJzIDUwMyByYXRoZXIgdGhhbiBwcm9jZXNzaW5nIGFuIHVuYXV0aGVudGljYXRlZCBhY3Rpdml0eS5cbiAgICogICAyLiAqKlZhbGlkYXRlIHRoZSBKV1QgYmVmb3JlIHBhcnNpbmcgdGhlIGJvZHkuKiogVGhlIHRva2VuIGlzIHRoZSBvbmx5XG4gICAqICAgICAgdHJ1c3QgYm91bmRhcnkgdGhpcyBlbmRwb2ludCBoYXMuXG4gICAqICAgMy4gKipQaW4gdGhlIHJlcGx5IGRlc3RpbmF0aW9uIHRvIHRoZSB0b2tlbi4qKiBgc2VydmljZVVybGAgYXJyaXZlcyBpbiB0aGVcbiAgICogICAgICBib2R5LCBhbmQgcmVwbGllcyBjYXJyeSB0aGUgYm90J3MgY3JlZGVudGlhbHMsIHNvIGl0IGlzIG9ubHkgaG9ub3JlZFxuICAgKiAgICAgIHdoZW4gaXQgbWF0Y2hlcyB0aGUgdmVyaWZpZWQgdG9rZW4uXG4gICAqICAgNC4gKipBbnN3ZXIgMjAwIGltbWVkaWF0ZWx5LCB0aGVuIHJ1biB0aGUgYWdlbnQuKiogQm90IFNlcnZpY2UgdGltZXMgb3V0XG4gICAqICAgICAgYW4gdW5hY2tub3dsZWRnZWQgYWN0aXZpdHkgaW4gc2Vjb25kcyBhbmQgUkVUUklFUyBpdDsgYSBjYXJkIHRha2VzIGZhclxuICAgKiAgICAgIGxvbmdlciB0aGFuIHRoYXQsIGFuZCBhIHJldHJ5IHdvdWxkIHBvc3QgYSBkdXBsaWNhdGUgY2FyZC5cbiAgICpcbiAgICogQWN0aXZpdGllcyB0aGF0IGNhcnJ5IG5vIHByb21wdCAoYHR5cGluZ2AsIGBjb252ZXJzYXRpb25VcGRhdGVgLCBhblxuICAgKiBhdHRhY2htZW50LW9ubHkgbWVzc2FnZSkgYXJlIGFja25vd2xlZGdlZCBhbmQgZHJvcHBlZCAtIGV4YWN0bHkgd2hhdCBhIGJvdFxuICAgKiBkb2VzIHdpdGggdGhlbS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlTWVzc2FnZShcbiAgICByZXE6IHsgaGVhZGVyczogUmVjb3JkPHN0cmluZywgdW5rbm93bj47IGJvZHk6IHVua25vd24gfSxcbiAgICByZXM6IHtcbiAgICAgIHN0YXR1cyhjb2RlOiBudW1iZXIpOiB7IGpzb24oYm9keTogdW5rbm93bik6IHZvaWQgfTtcbiAgICAgIGpzb24oYm9keTogdW5rbm93bik6IHZvaWQ7XG4gICAgICBoZWFkZXJzU2VudD86IGJvb2xlYW47XG4gICAgfSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBjb25maWcgfSA9IGdldFRlYW1zUnVudGltZSh0aGlzLmNvbmZpZyk7XG5cbiAgICAvLyBMb2NhbCBkZXZlbG9wbWVudCBtb2RlOiBubyBib3QgcmVnaXN0cmF0aW9uLCBubyB0b2tlbiwgYW5kIHRoZSByZXBseSBjb21lc1xuICAgIC8vIGJhY2sgaW4gdGhlIEhUVFAgcmVzcG9uc2UgcmF0aGVyIHRoYW4gdGhyb3VnaCB0aGUgQ29ubmVjdG9yIEFQSSAodGhlcmUgaXNcbiAgICAvLyBubyBgc2VydmljZVVybGAgdG8gY2FsbCBiYWNrIHRvKS4gVGhpcyBpcyB3aGF0IGxldHMgdGhlIGluLXJlcG8gcHJldmlld1xuICAgIC8vIGNoYXQgYW5kIHRoZSBCb3QgRnJhbWV3b3JrIEVtdWxhdG9yIGRyaXZlIHRoZSBzYW1lIHJvdXRlIFRlYW1zIHVzZXMuXG4gICAgaWYgKGNvbmZpZy5hbGxvd1VuYXV0aGVudGljYXRlZCkge1xuICAgICAgLy8gQWNjZXB0IGJvdGggZW52ZWxvcGVzOiBhIGJhcmUgYWN0aXZpdHkgKHdoYXQgQm90IFNlcnZpY2UgYW5kIHRoZVxuICAgICAgLy8gZW11bGF0b3IgUE9TVCkgYW5kIHRoZSBgeyBhY3Rpdml0eSwgYWdlbnRJZCB9YCByZXF1ZXN0IHNoYXBlIHRoZVxuICAgICAgLy8gYC9hY3Rpdml0eWAgcm91dGUgdGFrZXMsIHNvIGEgbG9jYWwgY2xpZW50IGNhbiBzdGlsbCBjaG9vc2UgYW4gYWdlbnQuXG4gICAgICBjb25zdCBib2R5ID1cbiAgICAgICAgb2JqZWN0LmlzUmVjb3JkKHJlcS5ib2R5KSAmJiBvYmplY3QuaXNSZWNvcmQocmVxLmJvZHkuYWN0aXZpdHkpXG4gICAgICAgICAgPyByZXEuYm9keVxuICAgICAgICAgIDogeyBhY3Rpdml0eTogcmVxLmJvZHkgfTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZXhlY3V0ZVR1cm4oYm9keSk7XG4gICAgICBpZiAoIXJlc3VsdC5vaykge1xuICAgICAgICByZXMuc3RhdHVzKHJlc3VsdC5zdGF0dXMpLmpzb24oeyBlcnJvcjogcmVzdWx0Lm1lc3NhZ2UgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHJlcy5qc29uKHJlc3VsdC5kYXRhKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoIWNvbmZpZy5hcHBJZCB8fCAhY29uZmlnLmFwcFBhc3N3b3JkKSB7XG4gICAgICByZXMuc3RhdHVzKDUwMykuanNvbih7XG4gICAgICAgIGVycm9yOlxuICAgICAgICAgIFwidGVhbXM6IG1lc3NhZ2luZyBlbmRwb2ludCBpcyBub3QgY29uZmlndXJlZCAtIHNldCBhcHBJZC9hcHBQYXNzd29yZCBcIiArXG4gICAgICAgICAgXCIoVEVBTVNfQVBQX0lEIC8gVEVBTVNfQVBQX1BBU1NXT1JEKSBmcm9tIHRoZSBBenVyZSBCb3QgcmVnaXN0cmF0aW9uXCIsXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBhdXRob3JpemF0aW9uID0gcmVhZEhlYWRlcihyZXEuaGVhZGVycywgXCJhdXRob3JpemF0aW9uXCIpO1xuICAgIGxldCB2ZXJpZmllZDtcbiAgICB0cnkge1xuICAgICAgdmVyaWZpZWQgPSBhd2FpdCB2ZXJpZnlCb3RUb2tlbihhdXRob3JpemF0aW9uLCB7XG4gICAgICAgIGFwcElkOiBjb25maWcuYXBwSWQsXG4gICAgICAgIC4uLihjb25maWcuYXBwVGVuYW50SWQgPyB7IGFwcFRlbmFudElkOiBjb25maWcuYXBwVGVuYW50SWQgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gRGVsaWJlcmF0ZWx5IHRlcnNlOiBhIGNhbGxlciBmYWlsaW5nIGF1dGhlbnRpY2F0aW9uIGxlYXJucyBvbmx5IHRoYXQgaXRcbiAgICAgIC8vIGZhaWxlZCwgd2hpbGUgdGhlIHJlYXNvbiBnb2VzIHRvIHRoZSBsb2dzLlxuICAgICAgbG9nZ2VyLndhcm4oXCJyZWplY3RlZCBhbiB1bmF1dGhlbnRpY2F0ZWQgcmVxdWVzdFwiLCB7IGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSB9KTtcbiAgICAgIHJlcy5zdGF0dXMoNDAxKS5qc29uKHsgZXJyb3I6IFwidW5hdXRob3JpemVkXCIgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyc2VkID0gYWN0aXZpdHlDb250cmFjdC5hY3Rpdml0eVNjaGVtYS5zYWZlUGFyc2UocmVxLmJvZHkpO1xuICAgIGlmICghcGFyc2VkLnN1Y2Nlc3MpIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAwKS5qc29uKHsgZXJyb3I6IHBhcnNlZC5lcnJvci5tZXNzYWdlIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBpbmJvdW5kID0gcGFyc2VkLmRhdGE7XG5cbiAgICBjb25zdCBzZXJ2aWNlVXJsID0gcmVzb2x2ZVNlcnZpY2VVcmwoaW5ib3VuZCwgdmVyaWZpZWQuc2VydmljZVVybCk7XG4gICAgaWYgKCFzZXJ2aWNlVXJsKSB7XG4gICAgICBsb2dnZXIud2FybihcInJlamVjdGVkIGFuIGFjdGl2aXR5IHdpdGggbm8gdXNhYmxlIHNlcnZpY2VVcmxcIiwge1xuICAgICAgICB0eXBlOiBpbmJvdW5kLnR5cGUsXG4gICAgICB9KTtcbiAgICAgIHJlcy5zdGF0dXMoNDAwKS5qc29uKHsgZXJyb3I6IFwiYWN0aXZpdHkgY2FycmllZCBubyBhY2NlcHRhYmxlIHNlcnZpY2VVcmxcIiB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBhZ2VudCA9IHJlc29sdmVDYXJkQWdlbnQodGhpcy5jb250ZXh0Py5nZXRQbHVnaW5zKCksIGNvbmZpZy5hZ2VudFBsdWdpbik7XG4gICAgaWYgKCFhZ2VudCkge1xuICAgICAgbG9nZ2VyLmVycm9yKFwibm8gYWdlbnQgYXZhaWxhYmxlIHRvIGFuc3dlciBhIFRlYW1zIHR1cm5cIiwge1xuICAgICAgICBhZ2VudFBsdWdpbjogY29uZmlnLmFnZW50UGx1Z2luLFxuICAgICAgfSk7XG4gICAgICByZXMuc3RhdHVzKDUwMykuanNvbih7IGVycm9yOiBcIm5vIGFnZW50IGF2YWlsYWJsZVwiIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEFja25vd2xlZGdlIEZJUlNULiBFdmVyeXRoaW5nIGFmdGVyIHRoaXMgcG9pbnQgaXMgb3V0LW9mLWJhbmQgd29yayB3aG9zZVxuICAgIC8vIHJlc3VsdCByZWFjaGVzIHRoZSB1c2VyIHRocm91Z2ggdGhlIENvbm5lY3RvciBBUEksIG5vdCB0aGlzIHJlc3BvbnNlLlxuICAgIHJlcy5zdGF0dXMoMjAwKS5qc29uKHt9KTtcblxuICAgIGlmICghcHJvbXB0T2YoaW5ib3VuZCkpIHJldHVybjtcblxuICAgIGNvbnN0IGNyZWF0ZVJlcXVlc3RDb250ZXh0ID0gcmVzb2x2ZUNhcmRDb250ZXh0RmFjdG9yeShcbiAgICAgIHRoaXMuY29udGV4dD8uZ2V0UGx1Z2lucygpLFxuICAgICAgY29uZmlnLmFnZW50UGx1Z2luLFxuICAgICk7XG5cbiAgICB2b2lkIGRlbGl2ZXJUdXJuKHtcbiAgICAgIGFnZW50LFxuICAgICAgYWN0aXZpdHk6IGluYm91bmQsXG4gICAgICBzZXJ2aWNlVXJsLFxuICAgICAgLi4uKGNyZWF0ZVJlcXVlc3RDb250ZXh0ID8geyBjcmVhdGVSZXF1ZXN0Q29udGV4dCB9IDoge30pLFxuICAgICAgY3JlZGVudGlhbHM6IHtcbiAgICAgICAgYXBwSWQ6IGNvbmZpZy5hcHBJZCxcbiAgICAgICAgYXBwUGFzc3dvcmQ6IGNvbmZpZy5hcHBQYXNzd29yZCxcbiAgICAgICAgLi4uKGNvbmZpZy5hcHBUZW5hbnRJZCA/IHsgYXBwVGVuYW50SWQ6IGNvbmZpZy5hcHBUZW5hbnRJZCB9IDoge30pLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBDb21waWxlIGEgY2FyZCwgdmFsaWRhdGluZyB0aGUgcmVxdWVzdCBib2R5IGFnYWluc3QgdGhlIHNwZWMgc2NoZW1hLiAqL1xuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVCdWlsZChib2R5OiB1bmtub3duKTogUHJvbWlzZTxFeGVjdXRpb25SZXN1bHQ8Y2FyZC5DYXJkUmVzdWx0Pj4ge1xuICAgIGNvbnN0IHBhcnNlZCA9IGNhcmQuY2FyZFNwZWNTY2hlbWEuc2FmZVBhcnNlKGJvZHkpO1xuICAgIGlmICghcGFyc2VkLnN1Y2Nlc3MpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgc3RhdHVzOiA0MDAsIG1lc3NhZ2U6IHBhcnNlZC5lcnJvci5tZXNzYWdlIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmV4ZWN1dGUoYXN5bmMgKHNpZ25hbCkgPT4gYnVpbGRDYXJkKHBhcnNlZC5kYXRhLCBzaWduYWwpLCBURUFNU19CVUlMRF9TRVRUSU5HUyk7XG4gIH1cblxuICAvKipcbiAgICogUnVuIG9uZSBjb252ZXJzYXRpb24gdHVybjogdmFsaWRhdGUgdGhlIGluYm91bmQgYWN0aXZpdHksIHJlc29sdmUgdGhlIGFnZW50XG4gICAqIGZyb20gdGhlIHNpYmxpbmcgYWdlbnQgcGx1Z2luLCBhbmQgYW5zd2VyIHdpdGggY2FyZC1jYXJyeWluZyBhY3Rpdml0aWVzLlxuICAgKlxuICAgKiBSZXNvbHV0aW9uIGZhaWx1cmVzIGFyZSByZXBvcnRlZCBkaXN0aW5jdGx5IGJlY2F1c2UgdGhleSBoYXZlIGRpZmZlcmVudFxuICAgKiBmaXhlczogNTAzIHdoZW4gbm8gYWdlbnQgcGx1Z2luIGlzIG1vdW50ZWQgYXQgYWxsIChhIHdpcmluZyBwcm9ibGVtKSwgNDA0XG4gICAqIHdoZW4gdGhlIGNhbGxlciBuYW1lZCBhbiBgYWdlbnRJZGAgdGhhdCBpcyBub3QgcmVnaXN0ZXJlZCAoYSByZXF1ZXN0XG4gICAqIHByb2JsZW0pLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBleGVjdXRlVHVybihcbiAgICBib2R5OiB1bmtub3duLFxuICApOiBQcm9taXNlPEV4ZWN1dGlvblJlc3VsdDxhY3Rpdml0eUNvbnRyYWN0LkFjdGl2aXR5UmVzcG9uc2U+PiB7XG4gICAgY29uc3QgcGFyc2VkID0gYWN0aXZpdHlDb250cmFjdC5hY3Rpdml0eVJlcXVlc3RTY2hlbWEuc2FmZVBhcnNlKGJvZHkpO1xuICAgIGlmICghcGFyc2VkLnN1Y2Nlc3MpIHtcbiAgICAgIHJldHVybiB7IG9rOiBmYWxzZSwgc3RhdHVzOiA0MDAsIG1lc3NhZ2U6IHBhcnNlZC5lcnJvci5tZXNzYWdlIH07XG4gICAgfVxuICAgIGNvbnN0IHsgYWN0aXZpdHksIGFnZW50SWQgfSA9IHBhcnNlZC5kYXRhO1xuICAgIGNvbnN0IHsgY29uZmlnIH0gPSBnZXRUZWFtc1J1bnRpbWUodGhpcy5jb25maWcpO1xuICAgIGNvbnN0IGFnZW50ID0gcmVzb2x2ZUNhcmRBZ2VudCh0aGlzLmNvbnRleHQ/LmdldFBsdWdpbnMoKSwgY29uZmlnLmFnZW50UGx1Z2luLCBhZ2VudElkKTtcbiAgICBpZiAoIWFnZW50KSB7XG4gICAgICByZXR1cm4gYWdlbnRJZFxuICAgICAgICA/IHsgb2s6IGZhbHNlLCBzdGF0dXM6IDQwNCwgbWVzc2FnZTogYHRlYW1zOiB1bmtub3duIGFnZW50ICcke2FnZW50SWR9J2AgfVxuICAgICAgICA6IHtcbiAgICAgICAgICAgIG9rOiBmYWxzZSxcbiAgICAgICAgICAgIHN0YXR1czogNTAzLFxuICAgICAgICAgICAgbWVzc2FnZTogYHRlYW1zOiBubyBhZ2VudCBhdmFpbGFibGUgLSBpcyB0aGUgJyR7Y29uZmlnLmFnZW50UGx1Z2lufScgcGx1Z2luIHJlZ2lzdGVyZWQ/YCxcbiAgICAgICAgICB9O1xuICAgIH1cbiAgICBjb25zdCBjcmVhdGVSZXF1ZXN0Q29udGV4dCA9IHJlc29sdmVDYXJkQ29udGV4dEZhY3RvcnkoXG4gICAgICB0aGlzLmNvbnRleHQ/LmdldFBsdWdpbnMoKSxcbiAgICAgIGNvbmZpZy5hZ2VudFBsdWdpbixcbiAgICApO1xuICAgIHJldHVybiB0aGlzLmV4ZWN1dGUoYXN5bmMgKHNpZ25hbCkgPT4ge1xuICAgICAgY29uc3QgYWN0aXZpdGllcyA9IGF3YWl0IHJ1bkNhcmRUdXJuKGFnZW50LCBhY3Rpdml0eSwge1xuICAgICAgICAuLi4oY3JlYXRlUmVxdWVzdENvbnRleHQgPyB7IGNyZWF0ZVJlcXVlc3RDb250ZXh0IH0gOiB7fSksXG4gICAgICAgIC4uLihzaWduYWwgPyB7IHNpZ25hbCB9IDoge30pLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4geyBhY3Rpdml0aWVzIH07XG4gICAgfSwgVEVBTVNfVFVSTl9TRVRUSU5HUyk7XG4gIH1cblxuICAvKipcbiAgICogQ29tcGlsZSB0aGVuIHBvc3QgYSBjYXJkLCB2YWxpZGF0aW5nIHRoZSByZXF1ZXN0IGJvZHkgYWdhaW5zdCB0aGUgc3BlY1xuICAgKiBzY2hlbWEuIFRoZSBjb21waWxlIGlzIGZvbGRlZCBJTlRPIHRoZSBleGVjdXRlZCBjYWxsYmFjayBzbyBhIHRocm93IGZyb21cbiAgICogZWl0aGVyIGhhbGYgKGEgYnVpbGQgZmFpbHVyZSwgb3IgYHBvc3RDYXJkYCByZWZ1c2luZyBiZWNhdXNlIG5vIHdlYmhvb2sgaXNcbiAgICogY29uZmlndXJlZCkgY29tZXMgYmFjayBhcyBhIGZhaWxlZCB7QGxpbmsgRXhlY3V0aW9uUmVzdWx0fSB0aGUgcm91dGUgY2FuXG4gICAqIGFuc3dlciB3aXRoLCByYXRoZXIgdGhhbiBlc2NhcGluZyB0aGUgaGFuZGxlciBhcyBhbiB1bmhhbmRsZWQgcmVqZWN0aW9uLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBleGVjdXRlUG9zdChib2R5OiB1bmtub3duKTogUHJvbWlzZTxFeGVjdXRpb25SZXN1bHQ8dm9pZD4+IHtcbiAgICBjb25zdCBwYXJzZWQgPSBjYXJkLmNhcmRTcGVjU2NoZW1hLnNhZmVQYXJzZShib2R5KTtcbiAgICBpZiAoIXBhcnNlZC5zdWNjZXNzKSB7XG4gICAgICByZXR1cm4geyBvazogZmFsc2UsIHN0YXR1czogNDAwLCBtZXNzYWdlOiBwYXJzZWQuZXJyb3IubWVzc2FnZSB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5leGVjdXRlKGFzeW5jIChzaWduYWwpID0+IHtcbiAgICAgIGNvbnN0IGJ1aWx0ID0gYXdhaXQgYnVpbGRDYXJkKHBhcnNlZC5kYXRhLCBzaWduYWwpO1xuICAgICAgYXdhaXQgcG9zdENhcmQoYnVpbHQuY2FyZCwgc2lnbmFsKTtcbiAgICB9LCBURUFNU19QT1NUX1NFVFRJTkdTKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlZ2lzdGVyIHRoZSBUZWFtcyBwbHVnaW4uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjcmVhdGVBcHAsIHNlcnZlciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbiAqIGltcG9ydCB7IHBsdWdpbiBhcyB0ZWFtc1BsdWdpbiB9IGZyb20gXCJAZGJ4LXRvb2xzL3RlYW1zXCI7XG4gKlxuICogYXdhaXQgY3JlYXRlQXBwKHtcbiAqICAgcGx1Z2luczogW3NlcnZlcigpLCB0ZWFtc1BsdWdpbi50ZWFtcygpXSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCB0ZWFtcyA9IHRvUGx1Z2luKFRlYW1zUGx1Z2luKTtcblxuLyoqXG4gKiBSZWFkIG9uZSBoZWFkZXIgdmFsdWUsIG5vcm1hbGl6aW5nIE5vZGUncyBgc3RyaW5nIHwgc3RyaW5nW11gIHNoYXBlLlxuICpcbiAqIEV4cHJlc3MgbG93ZXItY2FzZXMgaW5jb21pbmcgaGVhZGVyIG5hbWVzLCBidXQgdGhpcyBpcyB3cml0dGVuIGFnYWluc3QgYVxuICogc3RydWN0dXJhbCBgaGVhZGVyc2AgcmVjb3JkIChzbyB0aGUgaGFuZGxlciBzdGF5cyB0ZXN0YWJsZSB3aXRob3V0IGFuIEV4cHJlc3NcbiAqIHJlcXVlc3QpLCBoZW5jZSB0aGUgZXhwbGljaXQgY2FzZS1pbnNlbnNpdGl2ZSBsb29rdXAuXG4gKi9cbmZ1bmN0aW9uIHJlYWRIZWFkZXIoaGVhZGVyczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIG5hbWU6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGRpcmVjdCA9IGhlYWRlcnNbbmFtZV0gPz8gaGVhZGVyc1tuYW1lLnRvTG93ZXJDYXNlKCldO1xuICBjb25zdCB2YWx1ZSA9IEFycmF5LmlzQXJyYXkoZGlyZWN0KSA/IGRpcmVjdFswXSA6IGRpcmVjdDtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiA/IChzdHJpbmcudHJpbVRvTnVsbCh2YWx1ZSkgPz8gdW5kZWZpbmVkKSA6IHVuZGVmaW5lZDtcbn1cbiJdfQ==
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The Teams runtime: a lazily-resolved, process-wide config shared by the
3
+ * plugin and the `create_teams_card` tool, so both read one resolved card
4
+ * version / webhook set. The first caller (normally the plugin at setup)
5
+ * primes it from the plugin's config; later callers (the tool's `execute`)
6
+ * reuse it.
7
+ *
8
+ * The runtime also carries the {@link TeamsExecutor} every operation runs
9
+ * through. The plugin installs its own `execute()` there at setup, which is how
10
+ * the tool - a plain function with no plugin instance in scope - still gets
11
+ * AppKit's cache / retry / timeout / telemetry chain. Without a registered
12
+ * plugin (a direct call from a script or a test) the operations still run, just
13
+ * without interceptors.
14
+ *
15
+ * Like the web-search runtime and unlike the email one, there is no connection
16
+ * pool to hold - card building is in-process and a webhook post is a stateless
17
+ * HTTP call - so the runtime holds only the resolved config and that executor.
18
+ *
19
+ * @module
20
+ */
21
+ import { type ExecutionResult } from "@databricks/appkit";
22
+ import { card } from "@dbx-tools/shared-teams";
23
+ import { type ResolvedTeamsConfig, type TeamsPluginConfig } from "./config.js";
24
+ import { type TeamsExecutionSettings } from "./defaults.js";
25
+ /**
26
+ * Runs one operation through AppKit's interceptor chain. Matches
27
+ * `Plugin.execute()`, which never throws: a failure comes back as
28
+ * `{ ok: false }`.
29
+ */
30
+ export type TeamsExecutor = <T>(fn: (signal?: AbortSignal) => Promise<T>, settings: TeamsExecutionSettings) => Promise<ExecutionResult<T>>;
31
+ /** The shared resolved config plus the executor operations run through. */
32
+ export interface TeamsRuntime {
33
+ config: ResolvedTeamsConfig;
34
+ execute: TeamsExecutor;
35
+ }
36
+ /**
37
+ * Return the shared runtime, building it on first use from the supplied config
38
+ * layered over environment defaults. Overrides are only read when the runtime
39
+ * is first created, so prime it from the plugin's config at setup; subsequent
40
+ * calls (the tool's `execute`) pass nothing and get the same instance.
41
+ */
42
+ export declare function getTeamsRuntime(overrides?: TeamsPluginConfig): TeamsRuntime;
43
+ /**
44
+ * Install the executor operations run through. The plugin calls this at setup
45
+ * with its own `execute()`; a second call replaces the previous one, so a
46
+ * re-registered plugin does not leave the tool bound to a dead instance.
47
+ */
48
+ export declare function setTeamsExecutor(execute: TeamsExecutor): void;
49
+ /** Drop the memoized runtime so the next {@link getTeamsRuntime} rebuilds it. */
50
+ export declare function resetTeamsRuntime(): void;
51
+ /**
52
+ * Compile a card spec into an Adaptive Card document, stamped with the runtime's
53
+ * resolved card version. Runs through the shared executor so a build picks up
54
+ * the app's telemetry / timeout chain.
55
+ */
56
+ export declare function buildCard(spec: card.CardSpec, signal?: AbortSignal): Promise<card.CardResult>;
57
+ /**
58
+ * POST a compiled Adaptive Card to the configured Teams incoming webhook,
59
+ * wrapped in the `MessageCard` attachment envelope Teams expects. Throws when
60
+ * no webhook is configured, so a caller that reaches here without one gets a
61
+ * clear error rather than a silent no-op.
62
+ */
63
+ export declare function postCard(cardDocument: card.AdaptiveCard, signal?: AbortSignal): Promise<void>;