@dbx-tools/appkit-generator 0.0.0-stage → 0.9.138

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.
Files changed (60) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +181 -2
  3. package/index.ts +44 -0
  4. package/lib/index.d.ts +40 -0
  5. package/lib/index.js +30 -0
  6. package/lib/src/assets.d.ts +33 -0
  7. package/lib/src/assets.js +224 -0
  8. package/lib/src/config.d.ts +75 -0
  9. package/lib/src/config.js +31 -0
  10. package/lib/src/dashboard.d.ts +30 -0
  11. package/lib/src/dashboard.js +257 -0
  12. package/lib/src/data.d.ts +17 -0
  13. package/lib/src/data.js +114 -0
  14. package/lib/src/defaults.d.ts +39 -0
  15. package/lib/src/defaults.js +36 -0
  16. package/lib/src/generate.d.ts +51 -0
  17. package/lib/src/generate.js +163 -0
  18. package/lib/src/genie.d.ts +51 -0
  19. package/lib/src/genie.js +84 -0
  20. package/lib/src/kpi.d.ts +22 -0
  21. package/lib/src/kpi.js +74 -0
  22. package/lib/src/manifest.json +72 -0
  23. package/lib/src/namespace.d.ts +36 -0
  24. package/lib/src/namespace.js +119 -0
  25. package/lib/src/operations.d.ts +42 -0
  26. package/lib/src/operations.js +96 -0
  27. package/lib/src/palette.d.ts +10 -0
  28. package/lib/src/palette.js +69 -0
  29. package/lib/src/plan.d.ts +21 -0
  30. package/lib/src/plan.js +33 -0
  31. package/lib/src/plugin.d.ts +619 -0
  32. package/lib/src/plugin.js +205 -0
  33. package/lib/src/research.d.ts +78 -0
  34. package/lib/src/research.js +235 -0
  35. package/lib/src/schema.d.ts +52 -0
  36. package/lib/src/schema.js +82 -0
  37. package/lib/src/structured.d.ts +27 -0
  38. package/lib/src/structured.js +30 -0
  39. package/lib/src/workflow.d.ts +314 -0
  40. package/lib/src/workflow.js +171 -0
  41. package/lib/tsconfig.tsbuildinfo +1 -0
  42. package/package.json +218 -4
  43. package/src/assets.ts +248 -0
  44. package/src/config.ts +98 -0
  45. package/src/dashboard.ts +295 -0
  46. package/src/data.ts +167 -0
  47. package/src/defaults.ts +61 -0
  48. package/src/generate.ts +250 -0
  49. package/src/genie.ts +111 -0
  50. package/src/kpi.ts +106 -0
  51. package/src/manifest.json +72 -0
  52. package/src/namespace.ts +192 -0
  53. package/src/operations.ts +171 -0
  54. package/src/palette.ts +81 -0
  55. package/src/plan.ts +59 -0
  56. package/src/plugin.ts +244 -0
  57. package/src/research.ts +382 -0
  58. package/src/schema.ts +114 -0
  59. package/src/structured.ts +54 -0
  60. package/src/workflow.ts +221 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * AppKit ToolProvider plugin for governed Databricks demo generation.
3
+ *
4
+ * @module
5
+ */
6
+ import { defineManifest, toPlugin } from "@databricks/appkit";
7
+ import { defineTool } from "@databricks/appkit/beta";
8
+ import { pluginRegistry, ToolRegistryPlugin } from "@dbx-tools/appkit";
9
+ import { mastra } from "@dbx-tools/appkit-mastra";
10
+ import { webSearch } from "@dbx-tools/appkit-web-search";
11
+ import { errorUtils, log } from "@dbx-tools/shared-core";
12
+ import { GENERATOR_ROUTES, GeneratorClientConfigSchema, GeneratorPluginClient, BrandGenerationEventSchema, BrandGenerationRequestSchema, } from "@dbx-tools/shared-generator/brand";
13
+ import { KpiResearchRequestSchema, KpiResearchResultSchema } from "@dbx-tools/shared-generator/kpi";
14
+ import { CreateGeneratorPresentationRequestSchema, GeneratedAssetsSchema, GeneratedDashboardSchema, GeneratedGenieSpaceSchema, GeneratedSchemaSchema, GeneratorPlanSchema, MaterializeGeneratorDataRequestSchema, MaterializedGeneratorDataSchema, PlanGeneratorDataRequestSchema, ProvisionGeneratorSchemaRequestSchema, } from "@dbx-tools/shared-generator/workflow";
15
+ import { resolveGeneratorConfig, } from "./config.js";
16
+ import manifest from "./manifest.json" with { type: "json" };
17
+ import { GeneratorOperations } from "./operations.js";
18
+ import { GENERATE_BRAND_TOOL_DESCRIPTION } from "./schema.js";
19
+ import { createGeneratorWorkflow } from "./workflow.js";
20
+ const logger = log.logger("generator");
21
+ const WORKFLOW_KEY = "generatorDemoAssets";
22
+ /** AppKit plugin exposing reusable generator tools and a hosted Mastra workflow. */
23
+ export class GeneratorPlugin extends ToolRegistryPlugin {
24
+ static manifest = defineManifest(manifest);
25
+ resolved = resolveGeneratorConfig(this.config);
26
+ operations;
27
+ workflow;
28
+ /** AppKit mount prefix used by browser clients. */
29
+ get basePath() {
30
+ return `/api/${this.name}`;
31
+ }
32
+ /** Native tools exposed independently of the composed workflow. */
33
+ get toolRegistry() {
34
+ const operations = this.requireOperations();
35
+ const mutation = { effect: "write", destructive: true, requiresUserContext: true };
36
+ return {
37
+ generate_brand: defineTool({
38
+ description: GENERATE_BRAND_TOOL_DESCRIPTION,
39
+ schema: BrandGenerationRequestSchema,
40
+ annotations: { effect: "read", requiresUserContext: true },
41
+ autoInheritable: false,
42
+ execute: (input, signal) => operations.generateBrand(BrandGenerationRequestSchema.parse(input), signal),
43
+ }),
44
+ research_kpis: defineTool({
45
+ description: "Research evidence-backed KPIs for company demo questions.",
46
+ schema: KpiResearchRequestSchema,
47
+ annotations: { effect: "read", requiresUserContext: true },
48
+ autoInheritable: false,
49
+ execute: (input, signal) => operations.researchKpis(KpiResearchRequestSchema.parse(input), signal),
50
+ }),
51
+ plan_demo_data: defineTool({
52
+ description: "Build a typed deterministic data plan from brand and KPI research.",
53
+ schema: PlanGeneratorDataRequestSchema,
54
+ annotations: { effect: "read", requiresUserContext: true },
55
+ autoInheritable: false,
56
+ execute: (input, signal) => operations.planData(PlanGeneratorDataRequestSchema.parse(input), signal),
57
+ }),
58
+ provision_schema: defineTool({
59
+ description: "Provision and grant the active user's deterministic Unity Catalog schema.",
60
+ schema: ProvisionGeneratorSchemaRequestSchema,
61
+ annotations: mutation,
62
+ autoInheritable: false,
63
+ execute: (input, signal) => operations.provisionSchema(ProvisionGeneratorSchemaRequestSchema.parse(input), signal),
64
+ }),
65
+ materialize_data: defineTool({
66
+ description: "Create generated Delta data and validate every planned KPI.",
67
+ schema: MaterializeGeneratorDataRequestSchema,
68
+ annotations: mutation,
69
+ autoInheritable: false,
70
+ execute: (input, signal) => operations.materializeData(MaterializeGeneratorDataRequestSchema.parse(input), signal),
71
+ }),
72
+ create_dashboard: defineTool({
73
+ description: "Create and publish an AI/BI dashboard with automatic companion Genie.",
74
+ schema: CreateGeneratorPresentationRequestSchema,
75
+ annotations: mutation,
76
+ autoInheritable: false,
77
+ execute: (input, signal) => operations.createDashboard(CreateGeneratorPresentationRequestSchema.parse(input), signal),
78
+ }),
79
+ create_genie_space: defineTool({
80
+ description: "Create a standalone Genie space when no dashboard is requested.",
81
+ schema: CreateGeneratorPresentationRequestSchema,
82
+ annotations: mutation,
83
+ autoInheritable: false,
84
+ execute: (input, signal) => operations.createGenie(CreateGeneratorPresentationRequestSchema.parse(input), signal),
85
+ }),
86
+ };
87
+ }
88
+ /** Capture sibling capabilities and register the workflow before Mastra boots. */
89
+ async setup() {
90
+ this.operations = new GeneratorOperations({
91
+ config: this.resolved,
92
+ researchClient: this.researchClient(),
93
+ });
94
+ this.workflow = createGeneratorWorkflow(this.operations);
95
+ pluginRegistry
96
+ .require(this.context, mastra, this)
97
+ .exports()
98
+ .registerWorkflow(WORKFLOW_KEY, this.workflow);
99
+ logger.info("ready", {
100
+ model: this.resolved.model ?? "automatic",
101
+ catalog: this.resolved.catalog ?? "brand-only",
102
+ warehouse: this.resolved.warehouseId ?? "brand-only",
103
+ workflow: WORKFLOW_KEY,
104
+ });
105
+ }
106
+ shutdown() {
107
+ return;
108
+ }
109
+ clientConfig() {
110
+ return GeneratorClientConfigSchema.parse({ basePath: this.basePath });
111
+ }
112
+ /** Stream standalone brand generation to the existing Brand page. */
113
+ injectRoutes(router) {
114
+ this.route(router, {
115
+ name: "generateBrand",
116
+ method: "post",
117
+ path: GENERATOR_ROUTES.generateBrand,
118
+ handler: async (req, res) => {
119
+ const parsed = BrandGenerationRequestSchema.safeParse(req.body);
120
+ if (!parsed.success) {
121
+ res.status(400).json({ error: "Enter a brand name and an optional HTTPS website." });
122
+ return;
123
+ }
124
+ res.set({
125
+ "Cache-Control": "no-cache, no-transform",
126
+ Connection: "keep-alive",
127
+ "Content-Type": "text/event-stream",
128
+ "X-Accel-Buffering": "no",
129
+ });
130
+ res.flushHeaders();
131
+ let closed = false;
132
+ const controller = new AbortController();
133
+ res.on("close", () => {
134
+ closed = true;
135
+ controller.abort();
136
+ });
137
+ const send = (event) => {
138
+ if (closed)
139
+ return;
140
+ const validated = BrandGenerationEventSchema.parse(event);
141
+ res.write(`event: ${validated.type}\ndata: ${JSON.stringify(validated)}\n\n`);
142
+ };
143
+ try {
144
+ const generated = await this.asUser(req)
145
+ .requireOperations()
146
+ .generateBrand(parsed.data, controller.signal, send);
147
+ send({ type: "result", package: generated });
148
+ }
149
+ catch (cause) {
150
+ logger.warn("brand-route-failed", { error: errorUtils.toError(cause) });
151
+ send({
152
+ type: "error",
153
+ message: "Brand generation failed. Retry the request; if it fails again, check the server logs.",
154
+ });
155
+ }
156
+ finally {
157
+ if (!closed)
158
+ res.end();
159
+ }
160
+ },
161
+ });
162
+ }
163
+ /** Programmatic operations and workflow for trusted application code. */
164
+ exports() {
165
+ return {
166
+ generateBrand: this.requireOperations().generateBrand.bind(this.requireOperations()),
167
+ researchKpis: this.requireOperations().researchKpis.bind(this.requireOperations()),
168
+ planData: this.requireOperations().planData.bind(this.requireOperations()),
169
+ provisionSchema: this.requireOperations().provisionSchema.bind(this.requireOperations()),
170
+ materializeData: this.requireOperations().materializeData.bind(this.requireOperations()),
171
+ createDashboard: this.requireOperations().createDashboard.bind(this.requireOperations()),
172
+ createGenie: this.requireOperations().createGenie.bind(this.requireOperations()),
173
+ workflow: this.workflow,
174
+ schemas: {
175
+ kpiResearch: KpiResearchResultSchema,
176
+ plan: GeneratorPlanSchema,
177
+ location: GeneratedSchemaSchema,
178
+ materialized: MaterializedGeneratorDataSchema,
179
+ dashboard: GeneratedDashboardSchema,
180
+ genie: GeneratedGenieSpaceSchema,
181
+ assets: GeneratedAssetsSchema,
182
+ },
183
+ client: GeneratorPluginClient,
184
+ };
185
+ }
186
+ /** Resolve the sibling web-search plugin without recreating its policy. */
187
+ researchClient() {
188
+ const sibling = pluginRegistry.require(this.context, webSearch, this).exports();
189
+ return {
190
+ search: sibling.search,
191
+ fetch: sibling.fetch,
192
+ fetchAssetPage: sibling.fetchAssetPage,
193
+ fetchImage: sibling.fetchImage,
194
+ };
195
+ }
196
+ /** Initialized operations or a clear lifecycle error. */
197
+ requireOperations() {
198
+ if (!this.operations)
199
+ throw new Error("Generator plugin setup has not completed");
200
+ return this.operations;
201
+ }
202
+ }
203
+ /** Register AppKit generator tools and workflow integration. */
204
+ export const generator = toPlugin(GeneratorPlugin);
205
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQW1CLE1BQU0sb0JBQW9CLENBQUM7QUFDL0UsT0FBTyxFQUFFLFVBQVUsRUFBcUIsTUFBTSx5QkFBeUIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsY0FBYyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDdkUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3pELE9BQU8sRUFDTCxnQkFBZ0IsRUFDaEIsMkJBQTJCLEVBQzNCLHFCQUFxQixFQUNyQiwwQkFBMEIsRUFDMUIsNEJBQTRCLEdBRTdCLE1BQU0sbUNBQW1DLENBQUM7QUFDM0MsT0FBTyxFQUFFLHdCQUF3QixFQUFFLHVCQUF1QixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDcEcsT0FBTyxFQUNMLHdDQUF3QyxFQUN4QyxxQkFBcUIsRUFDckIsd0JBQXdCLEVBQ3hCLHlCQUF5QixFQUN6QixxQkFBcUIsRUFDckIsbUJBQW1CLEVBQ25CLHFDQUFxQyxFQUNyQywrQkFBK0IsRUFDL0IsOEJBQThCLEVBQzlCLHFDQUFxQyxHQUN0QyxNQUFNLHNDQUFzQyxDQUFDO0FBQzlDLE9BQU8sRUFDTCxzQkFBc0IsR0FHdkIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxRQUFRLE1BQU0saUJBQWlCLENBQUMsT0FBTyxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUM7QUFDN0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFdEQsT0FBTyxFQUFFLCtCQUEr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SUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUNoRixRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7WUFDdkIsT0FBTyxFQUFFO2dCQUNQLFdBQVcsRUFBRSx1QkFBdUI7Z0JBQ3BDLElBQUksRUFBRSxtQkFBbUI7Z0JBQ3pCLFFBQVEsRUFBRSxxQkFBcUI7Z0JBQy9CLFlBQVksRUFBRSwrQkFBK0I7Z0JBQzdDLFNBQVMsRUFBRSx3QkFBd0I7Z0JBQ25DLEtBQUssRUFBRSx5QkFBeUI7Z0JBQ2hDLE1BQU0sRUFBRSxxQkFBcUI7YUFDOUI7WUFDRCxNQUFNLEVBQUUscUJBQXFCO1NBQzlCLENBQUM7SUFDSixDQUFDO0lBRUQsMkVBQTJFO0lBQ25FLGNBQWM7UUFDcEIsTUFBTSxPQUFPLEdBQUcsY0FBYyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNoRixPQUFPO1lBQ0wsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1lBQ3RCLEtBQUssRUFBRSxPQUFPLENBQUMsS0FBSztZQUNwQixjQUFjLEVBQUUsT0FBTyxDQUFDLGNBQWM7WUFDdEMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVO1NBQy9CLENBQUM7SUFDSixDQUFDO0lBRUQseURBQXlEO0lBQ2pELGlCQUFpQjtRQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVU7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDbEYsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7O0FBR0gsZ0VBQWdFO0FBQ2hFLE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsZUFBZSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEFwcEtpdCBUb29sUHJvdmlkZXIgcGx1Z2luIGZvciBnb3Zlcm5lZCBEYXRhYnJpY2tzIGRlbW8gZ2VuZXJhdGlvbi5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgZGVmaW5lTWFuaWZlc3QsIHRvUGx1Z2luLCB0eXBlIElBcHBSb3V0ZXIgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBkZWZpbmVUb29sLCB0eXBlIFRvb2xSZWdpc3RyeSB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXQvYmV0YVwiO1xuaW1wb3J0IHsgcGx1Z2luUmVnaXN0cnksIFRvb2xSZWdpc3RyeVBsdWdpbiB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdFwiO1xuaW1wb3J0IHsgbWFzdHJhIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0LW1hc3RyYVwiO1xuaW1wb3J0IHsgd2ViU2VhcmNoIH0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0LXdlYi1zZWFyY2hcIjtcbmltcG9ydCB7IGVycm9yVXRpbHMsIGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQge1xuICBHRU5FUkFUT1JfUk9VVEVTLFxuICBHZW5lcmF0b3JDbGllbnRDb25maWdTY2hlbWEsXG4gIEdlbmVyYXRvclBsdWdpbkNsaWVudCxcbiAgQnJhbmRHZW5lcmF0aW9uRXZlbnRTY2hlbWEsXG4gIEJyYW5kR2VuZXJhdGlvblJlcXVlc3RTY2hlbWEsXG4gIHR5cGUgQnJhbmRHZW5lcmF0aW9uRXZlbnQsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1nZW5lcmF0b3IvYnJhbmRcIjtcbmltcG9ydCB7IEtwaVJlc2VhcmNoUmVxdWVzdFNjaGVtYSwgS3BpUmVzZWFyY2hSZXN1bHRTY2hlbWEgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZ2VuZXJhdG9yL2twaVwiO1xuaW1wb3J0IHtcbiAgQ3JlYXRlR2VuZXJhdG9yUHJlc2VudGF0aW9uUmVxdWVzdFNjaGVtYSxcbiAgR2VuZXJhdGVkQXNzZXRzU2NoZW1hLFxuICBHZW5lcmF0ZWREYXNoYm9hcmRTY2hlbWEsXG4gIEdlbmVyYXRlZEdlbmllU3BhY2VTY2hlbWEsXG4gIEdlbmVyYXRlZFNjaGVtYVNjaGVtYSxcbiAgR2VuZXJhdG9yUGxhblNjaGVtYSxcbiAgTWF0ZXJpYWxpemVHZW5lcmF0b3JEYXRhUmVxdWVzdFNjaGVtYSxcbiAgTWF0ZXJpYWxpemVkR2VuZXJhdG9yRGF0YVNjaGVtYSxcbiAgUGxhbkdlbmVyYXRvckRhdGFSZXF1ZXN0U2NoZW1hLFxuICBQcm92aXNpb25HZW5lcmF0b3JTY2hlbWFSZXF1ZXN0U2NoZW1hLFxufSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZ2VuZXJhdG9yL3dvcmtmbG93XCI7XG5pbXBvcnQge1xuICByZXNvbHZlR2VuZXJhdG9yQ29uZmlnLFxuICB0eXBlIEdlbmVyYXRvclBsdWdpbkNvbmZpZyxcbiAgdHlwZSBSZXNvbHZlZEdlbmVyYXRvckNvbmZpZyxcbn0gZnJvbSBcIi4vY29uZmlnLnRzXCI7XG5pbXBvcnQgbWFuaWZlc3QgZnJvbSBcIi4vbWFuaWZlc3QuanNvblwiIHdpdGggeyB0eXBlOiBcImpzb25cIiB9O1xuaW1wb3J0IHsgR2VuZXJhdG9yT3BlcmF0aW9ucyB9IGZyb20gXCIuL29wZXJhdGlvbnMudHNcIjtcbmltcG9ydCB0eXBlIHsgQnJhbmRSZXNlYXJjaENsaWVudCB9IGZyb20gXCIuL3Jlc2VhcmNoLnRzXCI7XG5pbXBvcnQgeyBHRU5FUkFURV9CUkFORF9UT09MX0RFU0NSSVBUSU9OIH0gZnJvbSBcIi4vc2NoZW1hLnRzXCI7XG5pbXBvcnQgeyBjcmVhdGVHZW5lcmF0b3JXb3JrZmxvdywgdHlwZSBHZW5lcmF0b3JXb3JrZmxvdyB9IGZyb20gXCIuL3dvcmtmbG93LnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJnZW5lcmF0b3JcIik7XG5jb25zdCBXT1JLRkxPV19LRVkgPSBcImdlbmVyYXRvckRlbW9Bc3NldHNcIjtcblxuLyoqIEFwcEtpdCBwbHVnaW4gZXhwb3NpbmcgcmV1c2FibGUgZ2VuZXJhdG9yIHRvb2xzIGFuZCBhIGhvc3RlZCBNYXN0cmEgd29ya2Zsb3cuICovXG5leHBvcnQgY2xhc3MgR2VuZXJhdG9yUGx1Z2luIGV4dGVuZHMgVG9vbFJlZ2lzdHJ5UGx1Z2luPEdlbmVyYXRvclBsdWdpbkNvbmZpZz4ge1xuICBzdGF0aWMgbWFuaWZlc3QgPSBkZWZpbmVNYW5pZmVzdDxcImdlbmVyYXRvclwiPihtYW5pZmVzdCk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSByZXNvbHZlZDogUmVzb2x2ZWRHZW5lcmF0b3JDb25maWcgPSByZXNvbHZlR2VuZXJhdG9yQ29uZmlnKHRoaXMuY29uZmlnKTtcbiAgcHJpdmF0ZSBvcGVyYXRpb25zOiBHZW5lcmF0b3JPcGVyYXRpb25zIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHdvcmtmbG93OiBHZW5lcmF0b3JXb3JrZmxvdyB8IHVuZGVmaW5lZDtcblxuICAvKiogQXBwS2l0IG1vdW50IHByZWZpeCB1c2VkIGJ5IGJyb3dzZXIgY2xpZW50cy4gKi9cbiAgcHJpdmF0ZSBnZXQgYmFzZVBhdGgoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYC9hcGkvJHt0aGlzLm5hbWV9YDtcbiAgfVxuXG4gIC8qKiBOYXRpdmUgdG9vbHMgZXhwb3NlZCBpbmRlcGVuZGVudGx5IG9mIHRoZSBjb21wb3NlZCB3b3JrZmxvdy4gKi9cbiAgcHJvdGVjdGVkIGdldCB0b29sUmVnaXN0cnkoKTogVG9vbFJlZ2lzdHJ5IHtcbiAgICBjb25zdCBvcGVyYXRpb25zID0gdGhpcy5yZXF1aXJlT3BlcmF0aW9ucygpO1xuICAgIGNvbnN0IG11dGF0aW9uID0geyBlZmZlY3Q6IFwid3JpdGVcIiBhcyBjb25zdCwgZGVzdHJ1Y3RpdmU6IHRydWUsIHJlcXVpcmVzVXNlckNvbnRleHQ6IHRydWUgfTtcbiAgICByZXR1cm4ge1xuICAgICAgZ2VuZXJhdGVfYnJhbmQ6IGRlZmluZVRvb2woe1xuICAgICAgICBkZXNjcmlwdGlvbjogR0VORVJBVEVfQlJBTkRfVE9PTF9ERVNDUklQVElPTixcbiAgICAgICAgc2NoZW1hOiBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0U2NoZW1hLFxuICAgICAgICBhbm5vdGF0aW9uczogeyBlZmZlY3Q6IFwicmVhZFwiLCByZXF1aXJlc1VzZXJDb250ZXh0OiB0cnVlIH0sXG4gICAgICAgIGF1dG9Jbmhlcml0YWJsZTogZmFsc2UsXG4gICAgICAgIGV4ZWN1dGU6IChpbnB1dCwgc2lnbmFsKSA9PlxuICAgICAgICAgIG9wZXJhdGlvbnMuZ2VuZXJhdGVCcmFuZChCcmFuZEdlbmVyYXRpb25SZXF1ZXN0U2NoZW1hLnBhcnNlKGlucHV0KSwgc2lnbmFsKSxcbiAgICAgIH0pLFxuICAgICAgcmVzZWFyY2hfa3BpczogZGVmaW5lVG9vbCh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIlJlc2VhcmNoIGV2aWRlbmNlLWJhY2tlZCBLUElzIGZvciBjb21wYW55IGRlbW8gcXVlc3Rpb25zLlwiLFxuICAgICAgICBzY2hlbWE6IEtwaVJlc2VhcmNoUmVxdWVzdFNjaGVtYSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IHsgZWZmZWN0OiBcInJlYWRcIiwgcmVxdWlyZXNVc2VyQ29udGV4dDogdHJ1ZSB9LFxuICAgICAgICBhdXRvSW5oZXJpdGFibGU6IGZhbHNlLFxuICAgICAgICBleGVjdXRlOiAoaW5wdXQsIHNpZ25hbCkgPT5cbiAgICAgICAgICBvcGVyYXRpb25zLnJlc2VhcmNoS3BpcyhLcGlSZXNlYXJjaFJlcXVlc3RTY2hlbWEucGFyc2UoaW5wdXQpLCBzaWduYWwpLFxuICAgICAgfSksXG4gICAgICBwbGFuX2RlbW9fZGF0YTogZGVmaW5lVG9vbCh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIkJ1aWxkIGEgdHlwZWQgZGV0ZXJtaW5pc3RpYyBkYXRhIHBsYW4gZnJvbSBicmFuZCBhbmQgS1BJIHJlc2VhcmNoLlwiLFxuICAgICAgICBzY2hlbWE6IFBsYW5HZW5lcmF0b3JEYXRhUmVxdWVzdFNjaGVtYSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IHsgZWZmZWN0OiBcInJlYWRcIiwgcmVxdWlyZXNVc2VyQ29udGV4dDogdHJ1ZSB9LFxuICAgICAgICBhdXRvSW5oZXJpdGFibGU6IGZhbHNlLFxuICAgICAgICBleGVjdXRlOiAoaW5wdXQsIHNpZ25hbCkgPT5cbiAgICAgICAgICBvcGVyYXRpb25zLnBsYW5EYXRhKFBsYW5HZW5lcmF0b3JEYXRhUmVxdWVzdFNjaGVtYS5wYXJzZShpbnB1dCksIHNpZ25hbCksXG4gICAgICB9KSxcbiAgICAgIHByb3Zpc2lvbl9zY2hlbWE6IGRlZmluZVRvb2woe1xuICAgICAgICBkZXNjcmlwdGlvbjogXCJQcm92aXNpb24gYW5kIGdyYW50IHRoZSBhY3RpdmUgdXNlcidzIGRldGVybWluaXN0aWMgVW5pdHkgQ2F0YWxvZyBzY2hlbWEuXCIsXG4gICAgICAgIHNjaGVtYTogUHJvdmlzaW9uR2VuZXJhdG9yU2NoZW1hUmVxdWVzdFNjaGVtYSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IG11dGF0aW9uLFxuICAgICAgICBhdXRvSW5oZXJpdGFibGU6IGZhbHNlLFxuICAgICAgICBleGVjdXRlOiAoaW5wdXQsIHNpZ25hbCkgPT5cbiAgICAgICAgICBvcGVyYXRpb25zLnByb3Zpc2lvblNjaGVtYShQcm92aXNpb25HZW5lcmF0b3JTY2hlbWFSZXF1ZXN0U2NoZW1hLnBhcnNlKGlucHV0KSwgc2lnbmFsKSxcbiAgICAgIH0pLFxuICAgICAgbWF0ZXJpYWxpemVfZGF0YTogZGVmaW5lVG9vbCh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIkNyZWF0ZSBnZW5lcmF0ZWQgRGVsdGEgZGF0YSBhbmQgdmFsaWRhdGUgZXZlcnkgcGxhbm5lZCBLUEkuXCIsXG4gICAgICAgIHNjaGVtYTogTWF0ZXJpYWxpemVHZW5lcmF0b3JEYXRhUmVxdWVzdFNjaGVtYSxcbiAgICAgICAgYW5ub3RhdGlvbnM6IG11dGF0aW9uLFxuICAgICAgICBhdXRvSW5oZXJpdGFibGU6IGZhbHNlLFxuICAgICAgICBleGVjdXRlOiAoaW5wdXQsIHNpZ25hbCkgPT5cbiAgICAgICAgICBvcGVyYXRpb25zLm1hdGVyaWFsaXplRGF0YShNYXRlcmlhbGl6ZUdlbmVyYXRvckRhdGFSZXF1ZXN0U2NoZW1hLnBhcnNlKGlucHV0KSwgc2lnbmFsKSxcbiAgICAgIH0pLFxuICAgICAgY3JlYXRlX2Rhc2hib2FyZDogZGVmaW5lVG9vbCh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIkNyZWF0ZSBhbmQgcHVibGlzaCBhbiBBSS9CSSBkYXNoYm9hcmQgd2l0aCBhdXRvbWF0aWMgY29tcGFuaW9uIEdlbmllLlwiLFxuICAgICAgICBzY2hlbWE6IENyZWF0ZUdlbmVyYXRvclByZXNlbnRhdGlvblJlcXVlc3RTY2hlbWEsXG4gICAgICAgIGFubm90YXRpb25zOiBtdXRhdGlvbixcbiAgICAgICAgYXV0b0luaGVyaXRhYmxlOiBmYWxzZSxcbiAgICAgICAgZXhlY3V0ZTogKGlucHV0LCBzaWduYWwpID0+XG4gICAgICAgICAgb3BlcmF0aW9ucy5jcmVhdGVEYXNoYm9hcmQoQ3JlYXRlR2VuZXJhdG9yUHJlc2VudGF0aW9uUmVxdWVzdFNjaGVtYS5wYXJzZShpbnB1dCksIHNpZ25hbCksXG4gICAgICB9KSxcbiAgICAgIGNyZWF0ZV9nZW5pZV9zcGFjZTogZGVmaW5lVG9vbCh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIkNyZWF0ZSBhIHN0YW5kYWxvbmUgR2VuaWUgc3BhY2Ugd2hlbiBubyBkYXNoYm9hcmQgaXMgcmVxdWVzdGVkLlwiLFxuICAgICAgICBzY2hlbWE6IENyZWF0ZUdlbmVyYXRvclByZXNlbnRhdGlvblJlcXVlc3RTY2hlbWEsXG4gICAgICAgIGFubm90YXRpb25zOiBtdXRhdGlvbixcbiAgICAgICAgYXV0b0luaGVyaXRhYmxlOiBmYWxzZSxcbiAgICAgICAgZXhlY3V0ZTogKGlucHV0LCBzaWduYWwpID0+XG4gICAgICAgICAgb3BlcmF0aW9ucy5jcmVhdGVHZW5pZShDcmVhdGVHZW5lcmF0b3JQcmVzZW50YXRpb25SZXF1ZXN0U2NoZW1hLnBhcnNlKGlucHV0KSwgc2lnbmFsKSxcbiAgICAgIH0pLFxuICAgIH07XG4gIH1cblxuICAvKiogQ2FwdHVyZSBzaWJsaW5nIGNhcGFiaWxpdGllcyBhbmQgcmVnaXN0ZXIgdGhlIHdvcmtmbG93IGJlZm9yZSBNYXN0cmEgYm9vdHMuICovXG4gIG92ZXJyaWRlIGFzeW5jIHNldHVwKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMub3BlcmF0aW9ucyA9IG5ldyBHZW5lcmF0b3JPcGVyYXRpb25zKHtcbiAgICAgIGNvbmZpZzogdGhpcy5yZXNvbHZlZCxcbiAgICAgIHJlc2VhcmNoQ2xpZW50OiB0aGlzLnJlc2VhcmNoQ2xpZW50KCksXG4gICAgfSk7XG4gICAgdGhpcy53b3JrZmxvdyA9IGNyZWF0ZUdlbmVyYXRvcldvcmtmbG93KHRoaXMub3BlcmF0aW9ucyk7XG4gICAgcGx1Z2luUmVnaXN0cnlcbiAgICAgIC5yZXF1aXJlKHRoaXMuY29udGV4dCwgbWFzdHJhLCB0aGlzKVxuICAgICAgLmV4cG9ydHMoKVxuICAgICAgLnJlZ2lzdGVyV29ya2Zsb3coV09SS0ZMT1dfS0VZLCB0aGlzLndvcmtmbG93KTtcbiAgICBsb2dnZXIuaW5mbyhcInJlYWR5XCIsIHtcbiAgICAgIG1vZGVsOiB0aGlzLnJlc29sdmVkLm1vZGVsID8/IFwiYXV0b21hdGljXCIsXG4gICAgICBjYXRhbG9nOiB0aGlzLnJlc29sdmVkLmNhdGFsb2cgPz8gXCJicmFuZC1vbmx5XCIsXG4gICAgICB3YXJlaG91c2U6IHRoaXMucmVzb2x2ZWQud2FyZWhvdXNlSWQgPz8gXCJicmFuZC1vbmx5XCIsXG4gICAgICB3b3JrZmxvdzogV09SS0ZMT1dfS0VZLFxuICAgIH0pO1xuICB9XG5cbiAgc2h1dGRvd24oKTogdm9pZCB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2xpZW50Q29uZmlnKCkge1xuICAgIHJldHVybiBHZW5lcmF0b3JDbGllbnRDb25maWdTY2hlbWEucGFyc2UoeyBiYXNlUGF0aDogdGhpcy5iYXNlUGF0aCB9KTtcbiAgfVxuXG4gIC8qKiBTdHJlYW0gc3RhbmRhbG9uZSBicmFuZCBnZW5lcmF0aW9uIHRvIHRoZSBleGlzdGluZyBCcmFuZCBwYWdlLiAqL1xuICBvdmVycmlkZSBpbmplY3RSb3V0ZXMocm91dGVyOiBJQXBwUm91dGVyKTogdm9pZCB7XG4gICAgdGhpcy5yb3V0ZShyb3V0ZXIsIHtcbiAgICAgIG5hbWU6IFwiZ2VuZXJhdGVCcmFuZFwiLFxuICAgICAgbWV0aG9kOiBcInBvc3RcIixcbiAgICAgIHBhdGg6IEdFTkVSQVRPUl9ST1VURVMuZ2VuZXJhdGVCcmFuZCxcbiAgICAgIGhhbmRsZXI6IGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgICAgICBjb25zdCBwYXJzZWQgPSBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0U2NoZW1hLnNhZmVQYXJzZShyZXEuYm9keSk7XG4gICAgICAgIGlmICghcGFyc2VkLnN1Y2Nlc3MpIHtcbiAgICAgICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7IGVycm9yOiBcIkVudGVyIGEgYnJhbmQgbmFtZSBhbmQgYW4gb3B0aW9uYWwgSFRUUFMgd2Vic2l0ZS5cIiB9KTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcmVzLnNldCh7XG4gICAgICAgICAgXCJDYWNoZS1Db250cm9sXCI6IFwibm8tY2FjaGUsIG5vLXRyYW5zZm9ybVwiLFxuICAgICAgICAgIENvbm5lY3Rpb246IFwia2VlcC1hbGl2ZVwiLFxuICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwidGV4dC9ldmVudC1zdHJlYW1cIixcbiAgICAgICAgICBcIlgtQWNjZWwtQnVmZmVyaW5nXCI6IFwibm9cIixcbiAgICAgICAgfSk7XG4gICAgICAgIHJlcy5mbHVzaEhlYWRlcnMoKTtcbiAgICAgICAgbGV0IGNsb3NlZCA9IGZhbHNlO1xuICAgICAgICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgICAgICByZXMub24oXCJjbG9zZVwiLCAoKSA9PiB7XG4gICAgICAgICAgY2xvc2VkID0gdHJ1ZTtcbiAgICAgICAgICBjb250cm9sbGVyLmFib3J0KCk7XG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBzZW5kID0gKGV2ZW50OiBCcmFuZEdlbmVyYXRpb25FdmVudCkgPT4ge1xuICAgICAgICAgIGlmIChjbG9zZWQpIHJldHVybjtcbiAgICAgICAgICBjb25zdCB2YWxpZGF0ZWQgPSBCcmFuZEdlbmVyYXRpb25FdmVudFNjaGVtYS5wYXJzZShldmVudCk7XG4gICAgICAgICAgcmVzLndyaXRlKGBldmVudDogJHt2YWxpZGF0ZWQudHlwZX1cXG5kYXRhOiAke0pTT04uc3RyaW5naWZ5KHZhbGlkYXRlZCl9XFxuXFxuYCk7XG4gICAgICAgIH07XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgZ2VuZXJhdGVkID0gYXdhaXQgdGhpcy5hc1VzZXIocmVxKVxuICAgICAgICAgICAgLnJlcXVpcmVPcGVyYXRpb25zKClcbiAgICAgICAgICAgIC5nZW5lcmF0ZUJyYW5kKHBhcnNlZC5kYXRhLCBjb250cm9sbGVyLnNpZ25hbCwgc2VuZCk7XG4gICAgICAgICAgc2VuZCh7IHR5cGU6IFwicmVzdWx0XCIsIHBhY2thZ2U6IGdlbmVyYXRlZCB9KTtcbiAgICAgICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgICAgICBsb2dnZXIud2FybihcImJyYW5kLXJvdXRlLWZhaWxlZFwiLCB7IGVycm9yOiBlcnJvclV0aWxzLnRvRXJyb3IoY2F1c2UpIH0pO1xuICAgICAgICAgIHNlbmQoe1xuICAgICAgICAgICAgdHlwZTogXCJlcnJvclwiLFxuICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgXCJCcmFuZCBnZW5lcmF0aW9uIGZhaWxlZC4gUmV0cnkgdGhlIHJlcXVlc3Q7IGlmIGl0IGZhaWxzIGFnYWluLCBjaGVjayB0aGUgc2VydmVyIGxvZ3MuXCIsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgaWYgKCFjbG9zZWQpIHJlcy5lbmQoKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBQcm9ncmFtbWF0aWMgb3BlcmF0aW9ucyBhbmQgd29ya2Zsb3cgZm9yIHRydXN0ZWQgYXBwbGljYXRpb24gY29kZS4gKi9cbiAgb3ZlcnJpZGUgZXhwb3J0cygpIHtcbiAgICByZXR1cm4ge1xuICAgICAgZ2VuZXJhdGVCcmFuZDogdGhpcy5yZXF1aXJlT3BlcmF0aW9ucygpLmdlbmVyYXRlQnJhbmQuYmluZCh0aGlzLnJlcXVpcmVPcGVyYXRpb25zKCkpLFxuICAgICAgcmVzZWFyY2hLcGlzOiB0aGlzLnJlcXVpcmVPcGVyYXRpb25zKCkucmVzZWFyY2hLcGlzLmJpbmQodGhpcy5yZXF1aXJlT3BlcmF0aW9ucygpKSxcbiAgICAgIHBsYW5EYXRhOiB0aGlzLnJlcXVpcmVPcGVyYXRpb25zKCkucGxhbkRhdGEuYmluZCh0aGlzLnJlcXVpcmVPcGVyYXRpb25zKCkpLFxuICAgICAgcHJvdmlzaW9uU2NoZW1hOiB0aGlzLnJlcXVpcmVPcGVyYXRpb25zKCkucHJvdmlzaW9uU2NoZW1hLmJpbmQodGhpcy5yZXF1aXJlT3BlcmF0aW9ucygpKSxcbiAgICAgIG1hdGVyaWFsaXplRGF0YTogdGhpcy5yZXF1aXJlT3BlcmF0aW9ucygpLm1hdGVyaWFsaXplRGF0YS5iaW5kKHRoaXMucmVxdWlyZU9wZXJhdGlvbnMoKSksXG4gICAgICBjcmVhdGVEYXNoYm9hcmQ6IHRoaXMucmVxdWlyZU9wZXJhdGlvbnMoKS5jcmVhdGVEYXNoYm9hcmQuYmluZCh0aGlzLnJlcXVpcmVPcGVyYXRpb25zKCkpLFxuICAgICAgY3JlYXRlR2VuaWU6IHRoaXMucmVxdWlyZU9wZXJhdGlvbnMoKS5jcmVhdGVHZW5pZS5iaW5kKHRoaXMucmVxdWlyZU9wZXJhdGlvbnMoKSksXG4gICAgICB3b3JrZmxvdzogdGhpcy53b3JrZmxvdyxcbiAgICAgIHNjaGVtYXM6IHtcbiAgICAgICAga3BpUmVzZWFyY2g6IEtwaVJlc2VhcmNoUmVzdWx0U2NoZW1hLFxuICAgICAgICBwbGFuOiBHZW5lcmF0b3JQbGFuU2NoZW1hLFxuICAgICAgICBsb2NhdGlvbjogR2VuZXJhdGVkU2NoZW1hU2NoZW1hLFxuICAgICAgICBtYXRlcmlhbGl6ZWQ6IE1hdGVyaWFsaXplZEdlbmVyYXRvckRhdGFTY2hlbWEsXG4gICAgICAgIGRhc2hib2FyZDogR2VuZXJhdGVkRGFzaGJvYXJkU2NoZW1hLFxuICAgICAgICBnZW5pZTogR2VuZXJhdGVkR2VuaWVTcGFjZVNjaGVtYSxcbiAgICAgICAgYXNzZXRzOiBHZW5lcmF0ZWRBc3NldHNTY2hlbWEsXG4gICAgICB9LFxuICAgICAgY2xpZW50OiBHZW5lcmF0b3JQbHVnaW5DbGllbnQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIHRoZSBzaWJsaW5nIHdlYi1zZWFyY2ggcGx1Z2luIHdpdGhvdXQgcmVjcmVhdGluZyBpdHMgcG9saWN5LiAqL1xuICBwcml2YXRlIHJlc2VhcmNoQ2xpZW50KCk6IEJyYW5kUmVzZWFyY2hDbGllbnQge1xuICAgIGNvbnN0IHNpYmxpbmcgPSBwbHVnaW5SZWdpc3RyeS5yZXF1aXJlKHRoaXMuY29udGV4dCwgd2ViU2VhcmNoLCB0aGlzKS5leHBvcnRzKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNlYXJjaDogc2libGluZy5zZWFyY2gsXG4gICAgICBmZXRjaDogc2libGluZy5mZXRjaCxcbiAgICAgIGZldGNoQXNzZXRQYWdlOiBzaWJsaW5nLmZldGNoQXNzZXRQYWdlLFxuICAgICAgZmV0Y2hJbWFnZTogc2libGluZy5mZXRjaEltYWdlLFxuICAgIH07XG4gIH1cblxuICAvKiogSW5pdGlhbGl6ZWQgb3BlcmF0aW9ucyBvciBhIGNsZWFyIGxpZmVjeWNsZSBlcnJvci4gKi9cbiAgcHJpdmF0ZSByZXF1aXJlT3BlcmF0aW9ucygpOiBHZW5lcmF0b3JPcGVyYXRpb25zIHtcbiAgICBpZiAoIXRoaXMub3BlcmF0aW9ucykgdGhyb3cgbmV3IEVycm9yKFwiR2VuZXJhdG9yIHBsdWdpbiBzZXR1cCBoYXMgbm90IGNvbXBsZXRlZFwiKTtcbiAgICByZXR1cm4gdGhpcy5vcGVyYXRpb25zO1xuICB9XG59XG5cbi8qKiBSZWdpc3RlciBBcHBLaXQgZ2VuZXJhdG9yIHRvb2xzIGFuZCB3b3JrZmxvdyBpbnRlZ3JhdGlvbi4gKi9cbmV4cG9ydCBjb25zdCBnZW5lcmF0b3IgPSB0b1BsdWdpbihHZW5lcmF0b3JQbHVnaW4pO1xuIl19
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Brand research composed from the web-search plugin's search and fetch
3
+ * operations.
4
+ *
5
+ * @module
6
+ */
7
+ import type { WebAssetPageFetchRequest, WebImageFetchRequest, WebImageFetchResult } from "@dbx-tools/appkit-web-search/fetch";
8
+ import type { WebFetchRequest, WebFetchResult, WebSearchRequest, WebSearchResult } from "@dbx-tools/appkit-web-search/schema";
9
+ import { type BrandGenerationProgressEvent, type BrandGenerationRequest, type BrandPackageSource, type BrandVisualReference } from "./schema.ts";
10
+ /** Default number of cited pages fetched for one brand. */
11
+ export declare const DEFAULT_MAX_SOURCES = 4;
12
+ /** Default character cap for each fetched page excerpt. */
13
+ export declare const DEFAULT_SOURCE_MAX_LENGTH = 8000;
14
+ /** Upper bound that prevents one request from fanning out across too many sites. */
15
+ export declare const MAX_SOURCES = 8;
16
+ /** Upper bound on readable characters retained from one fetched page. */
17
+ export declare const MAX_SOURCE_MAX_LENGTH = 20000;
18
+ /** Markup cap used for official and mobile page asset discovery. */
19
+ export declare const ASSET_HTML_MAX_LENGTH = 1500000;
20
+ /** Search and fetch operations supplied by the registered web-search plugin. */
21
+ export interface BrandResearchClient {
22
+ /** Search the web and return a synthesized answer with citations. */
23
+ search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
24
+ /** Fetch one cited page as text or HTML. */
25
+ fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>;
26
+ /** Fetch expanded markup for deterministic in-process asset discovery. */
27
+ fetchAssetPage?(request: WebAssetPageFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>;
28
+ /** Fetch one image for multimodal research and package export. */
29
+ fetchImage(request: WebImageFetchRequest, signal?: AbortSignal): Promise<WebImageFetchResult>;
30
+ }
31
+ /** Research options controlling bounded page reads. */
32
+ export interface BrandResearchOptions {
33
+ /** Maximum number of unique sources to fetch. */
34
+ maxSources?: number;
35
+ /** Maximum text characters retained from each source. */
36
+ sourceMaxLength?: number;
37
+ /** Receives observable workflow progress. */
38
+ onProgress?: BrandProgressReporter;
39
+ }
40
+ /** Callback receiving one validated workflow progress event. */
41
+ export type BrandProgressReporter = (event: BrandGenerationProgressEvent) => void | Promise<void>;
42
+ /** One selected source and the text made available to synthesis. */
43
+ export interface BrandResearchSource extends BrandPackageSource {
44
+ /** Readable page text, omitted when the fetch failed. */
45
+ content?: string;
46
+ }
47
+ /** Search answer, fetched sources, and official-page markup used by generation. */
48
+ export interface BrandResearch {
49
+ /** Web-search model's evidence summary. */
50
+ answer: string;
51
+ /** Endpoint or fallback that ran the web search. */
52
+ model: string;
53
+ /** Selected and deduplicated citations. */
54
+ sources: BrandResearchSource[];
55
+ /** URL of the first source selected as the likely official page. */
56
+ officialPageUrl: string;
57
+ /** Raw markup used only for deterministic asset discovery. */
58
+ officialPageHtml?: string;
59
+ /** iOS and Android app-store references used as supplemental visual research. */
60
+ visualReferences: BrandResearchVisualReference[];
61
+ }
62
+ /** Fetched image retained in memory for multimodal synthesis. */
63
+ export interface BrandResearchVisualImage {
64
+ url: string;
65
+ contentType?: string;
66
+ data?: Uint8Array;
67
+ }
68
+ /** Mobile-store page plus downloaded visual references. */
69
+ export interface BrandResearchVisualReference extends Omit<BrandVisualReference, "images"> {
70
+ images: BrandResearchVisualImage[];
71
+ }
72
+ /** Build the focused, first-party search request for a brand. */
73
+ export declare function brandResearchQuery(request: BrandGenerationRequest): string;
74
+ /**
75
+ * Search for a brand, fetch a bounded set of cited pages, and retain the first
76
+ * page's markup for logo and favicon discovery.
77
+ */
78
+ export declare function researchBrand(request: BrandGenerationRequest, client: BrandResearchClient, options?: BrandResearchOptions, signal?: AbortSignal): Promise<BrandResearch>;
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Brand research composed from the web-search plugin's search and fetch
3
+ * operations.
4
+ *
5
+ * @module
6
+ */
7
+ import { errorUtils, log, stringUtils } from "@dbx-tools/shared-core";
8
+ import { discoverMobileAppVisuals } from "./assets.js";
9
+ import { brandRequestSubject, } from "./schema.js";
10
+ const logger = log.logger("brand/research");
11
+ /** Default number of cited pages fetched for one brand. */
12
+ export const DEFAULT_MAX_SOURCES = 4;
13
+ /** Default character cap for each fetched page excerpt. */
14
+ export const DEFAULT_SOURCE_MAX_LENGTH = 8_000;
15
+ /** Upper bound that prevents one request from fanning out across too many sites. */
16
+ export const MAX_SOURCES = 8;
17
+ /** Upper bound on readable characters retained from one fetched page. */
18
+ export const MAX_SOURCE_MAX_LENGTH = 20_000;
19
+ /** Markup cap used for official and mobile page asset discovery. */
20
+ export const ASSET_HTML_MAX_LENGTH = 1_500_000;
21
+ /** Use expanded asset markup when supplied, retaining compatibility with direct clients. */
22
+ function fetchAssetPage(client, request, signal) {
23
+ return client.fetchAssetPage
24
+ ? client.fetchAssetPage(request, signal)
25
+ : client.fetch({ ...request, format: "html" }, signal);
26
+ }
27
+ /** Build the focused, first-party search request for a brand. */
28
+ export function brandResearchQuery(request) {
29
+ const subject = brandRequestSubject(request);
30
+ const website = request.website ? ` The known official website is ${request.website}.` : "";
31
+ return stringUtils.toDescription(`
32
+ Research the official brand identity and design direction for "${subject}".${website}
33
+ The broader brief is: ${request.prompt ?? subject}.
34
+ Prefer first-party sources and cite the official website first. Identify
35
+ the canonical and short names, current tagline, plain-language
36
+ description, audiences, writing tone, brand colors as hex values,
37
+ typography, documentation, source repository, logo, icon, and favicon.
38
+ Distinguish documented facts from reasonable visual inferences.
39
+ `);
40
+ }
41
+ /** Build a targeted mobile-store search query for visual references. */
42
+ function mobileStoreQuery(request, platform) {
43
+ const subject = brandRequestSubject(request);
44
+ const site = platform === "ios" ? "apps.apple.com" : "play.google.com/store/apps";
45
+ return `site:${site} ${JSON.stringify(subject)} official app`;
46
+ }
47
+ /** Find one matching store page and download representative images. */
48
+ async function researchMobileStore(request, platform, client, signal) {
49
+ try {
50
+ const search = await client.search({ query: mobileStoreQuery(request, platform) }, signal);
51
+ const expectedHost = platform === "ios" ? "apps.apple.com" : "play.google.com";
52
+ const pageUrl = search.citations
53
+ .map(({ url }) => publicHttpsUrl(url))
54
+ .find((url) => url && new URL(url).hostname === expectedHost);
55
+ if (!pageUrl)
56
+ return undefined;
57
+ const page = await fetchAssetPage(client, { url: pageUrl, maxLength: ASSET_HTML_MAX_LENGTH }, signal);
58
+ const discovered = discoverMobileAppVisuals(page.content, page.url);
59
+ const images = await Promise.all(discovered.imageUrls.slice(0, 4).map(async (url) => {
60
+ try {
61
+ const image = await client.fetchImage({ url }, signal);
62
+ return {
63
+ url: image.url,
64
+ contentType: image.contentType,
65
+ data: image.data,
66
+ };
67
+ }
68
+ catch (error) {
69
+ logger.warn("mobile-image-fetch-failed", {
70
+ platform,
71
+ url,
72
+ error: errorUtils.errorMessage(error),
73
+ });
74
+ return { url };
75
+ }
76
+ }));
77
+ return {
78
+ platform,
79
+ appName: discovered.appName,
80
+ pageUrl: page.url,
81
+ images,
82
+ };
83
+ }
84
+ catch (error) {
85
+ logger.warn("mobile-store-research-failed", {
86
+ platform,
87
+ error: errorUtils.errorMessage(error),
88
+ });
89
+ return undefined;
90
+ }
91
+ }
92
+ /** Return a normalized public HTTPS URL or `undefined`. */
93
+ function publicHttpsUrl(value) {
94
+ try {
95
+ const url = new URL(value);
96
+ return url.protocol === "https:" ? url.toString() : undefined;
97
+ }
98
+ catch {
99
+ return undefined;
100
+ }
101
+ }
102
+ /** Compute a small first-party likelihood score while preserving search order. */
103
+ function sourceScore(citation, request, index) {
104
+ const url = new URL(citation.url);
105
+ const subject = brandRequestSubject(request);
106
+ const knownWebsite = request.website ? new URL(request.website) : undefined;
107
+ const normalizedName = subject.toLowerCase().replace(/[^a-z\d]/g, "");
108
+ const normalizedHost = url.hostname.toLowerCase().replace(/[^a-z\d]/g, "");
109
+ const sameKnownOrigin = knownWebsite?.origin === url.origin ? 1_000 : 0;
110
+ const hostMatchesName = normalizedName.length >= 3 &&
111
+ (normalizedHost.includes(normalizedName) || normalizedName.includes(normalizedHost))
112
+ ? 100
113
+ : 0;
114
+ const titleMatchesName = citation.title?.toLowerCase().includes(subject.toLowerCase()) ? 10 : 0;
115
+ return sameKnownOrigin + hostMatchesName + titleMatchesName - index;
116
+ }
117
+ /** Select unique HTTPS citations and put the likely official page first. */
118
+ function selectSources(citations, request, maxSources) {
119
+ const subject = brandRequestSubject(request);
120
+ const candidates = request.website
121
+ ? [{ url: request.website, title: `${subject} official website` }, ...citations]
122
+ : [...citations];
123
+ const unique = new Map();
124
+ for (const citation of candidates) {
125
+ const url = publicHttpsUrl(citation.url);
126
+ if (url && !unique.has(url))
127
+ unique.set(url, { ...citation, url });
128
+ }
129
+ return [...unique.values()]
130
+ .map((citation, index) => ({ citation, score: sourceScore(citation, request, index) }))
131
+ .sort((left, right) => right.score - left.score)
132
+ .slice(0, maxSources)
133
+ .map(({ citation }) => citation);
134
+ }
135
+ /** Fetch one citation as readable text without failing the whole research pass. */
136
+ async function fetchSource(client, citation, sourceMaxLength, onComplete, signal) {
137
+ try {
138
+ const page = await client.fetch({ url: citation.url, format: "text", maxLength: sourceMaxLength }, signal);
139
+ return {
140
+ ...citation,
141
+ url: page.url,
142
+ ...(page.title ? { title: page.title } : {}),
143
+ fetched: true,
144
+ content: page.content,
145
+ };
146
+ }
147
+ catch (error) {
148
+ logger.warn("source-fetch-failed", {
149
+ url: citation.url,
150
+ error: errorUtils.errorMessage(error),
151
+ });
152
+ return { ...citation, fetched: false };
153
+ }
154
+ finally {
155
+ await onComplete();
156
+ }
157
+ }
158
+ /**
159
+ * Search for a brand, fetch a bounded set of cited pages, and retain the first
160
+ * page's markup for logo and favicon discovery.
161
+ */
162
+ export async function researchBrand(request, client, options = {}, signal) {
163
+ const subject = brandRequestSubject(request);
164
+ const maxSources = Math.min(Math.max(1, options.maxSources ?? DEFAULT_MAX_SOURCES), MAX_SOURCES);
165
+ const sourceMaxLength = Math.max(1, Math.min(options.sourceMaxLength ?? DEFAULT_SOURCE_MAX_LENGTH, MAX_SOURCE_MAX_LENGTH));
166
+ await options.onProgress?.({
167
+ type: "progress",
168
+ stage: "search",
169
+ message: `Searching for official ${subject} brand sources`,
170
+ });
171
+ const [search, iosReference, androidReference] = await Promise.all([
172
+ client.search({ query: brandResearchQuery(request) }, signal),
173
+ researchMobileStore(request, "ios", client, signal),
174
+ researchMobileStore(request, "android", client, signal),
175
+ ]);
176
+ const visualReferences = [iosReference, androidReference].filter((reference) => reference !== undefined);
177
+ await options.onProgress?.({
178
+ type: "progress",
179
+ stage: "visuals",
180
+ message: `Reviewed ${visualReferences.length} mobile app references`,
181
+ current: visualReferences.length,
182
+ total: 2,
183
+ });
184
+ const citations = selectSources(search.citations, request, maxSources);
185
+ if (citations.length === 0) {
186
+ throw new Error(`Brand research for "${subject}" returned no public HTTPS sources to fetch.`);
187
+ }
188
+ let completedSources = 0;
189
+ await options.onProgress?.({
190
+ type: "progress",
191
+ stage: "fetch",
192
+ message: `Reading 0 of ${citations.length} sources`,
193
+ current: 0,
194
+ total: citations.length,
195
+ });
196
+ const official = citations[0];
197
+ const [sources, officialHtml] = await Promise.all([
198
+ Promise.all(citations.map((citation) => fetchSource(client, citation, sourceMaxLength, async () => {
199
+ completedSources += 1;
200
+ await options.onProgress?.({
201
+ type: "progress",
202
+ stage: "fetch",
203
+ message: `Read ${completedSources} of ${citations.length} sources`,
204
+ current: completedSources,
205
+ total: citations.length,
206
+ });
207
+ }, signal))),
208
+ fetchAssetPage(client, {
209
+ url: official.url,
210
+ maxLength: ASSET_HTML_MAX_LENGTH,
211
+ }, signal).catch((error) => {
212
+ logger.warn("official-page-html-fetch-failed", {
213
+ url: official.url,
214
+ error: errorUtils.errorMessage(error),
215
+ });
216
+ return undefined;
217
+ }),
218
+ ]);
219
+ await options.onProgress?.({
220
+ type: "progress",
221
+ stage: "assets",
222
+ message: officialHtml
223
+ ? "Found official page artwork"
224
+ : "Using the official site favicon fallback",
225
+ });
226
+ return {
227
+ answer: search.answer,
228
+ model: search.model,
229
+ sources,
230
+ officialPageUrl: officialHtml?.url ?? official.url,
231
+ ...(officialHtml ? { officialPageHtml: officialHtml.content } : {}),
232
+ visualReferences,
233
+ };
234
+ }
235
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzZWFyY2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVzZWFyY2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFjSCxPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDdkQsT0FBTyxFQUNMLG1CQUFtQixHQUtwQixNQUFNLGFBQWEsQ0FBQztBQUVyQixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFFNUMsMkRBQTJEO0FBQzNELE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLENBQUMsQ0FBQztBQUVyQywyREFBMkQ7QUFDM0QsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsS0FBSyxDQUFDO0FBRS9DLG9GQUFvRjtBQUNwRixNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFDO0FBRTdCLHlFQUF5RTtBQUN6RSxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxNQUFNLENBQUM7QUFFNUMsb0VBQW9FO0FBQ3BFLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLFNBQVMsQ0FBQztBQTZEL0MsNEZBQTRGO0FBQzVGLFNBQVMsY0FBYyxDQUNyQixNQUEyQixFQUMzQixPQUFpQyxFQUNqQyxNQUFvQjtJQUVwQixPQUFPLE1BQU0sQ0FBQyxjQUFjO1FBQzFCLENBQUMsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUM7UUFDeEMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDM0QsQ0FBQztBQUVELGlFQUFpRTtBQUNqRSxNQUFNLFVBQVUsa0JBQWtCLENB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QU0sQ0FDUCxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQWMsRUFBRSxFQUFFO1lBQ3pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsaUNBQWlDLEVBQUU7Z0JBQzdDLEdBQUcsRUFBRSxRQUFRLENBQUMsR0FBRztnQkFDakIsS0FBSyxFQUFFLFVBQVUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDO2FBQ3RDLENBQUMsQ0FBQztZQUNILE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUMsQ0FBQztLQUNILENBQUMsQ0FBQztJQUNILE1BQU0sT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3pCLElBQUksRUFBRSxVQUFVO1FBQ2hCLEtBQUssRUFBRSxRQUFRO1FBQ2YsT0FBTyxFQUFFLFlBQVk7WUFDbkIsQ0FBQyxDQUFDLDZCQUE2QjtZQUMvQixDQUFDLENBQUMsMENBQTBDO0tBQy9DLENBQUMsQ0FBQztJQUVILE9BQU87UUFDTCxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDckIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLO1FBQ25CLE9BQU87UUFDUCxlQUFlLEVBQUUsWUFBWSxFQUFFLEdBQUcsSUFBSSxRQUFRLENBQUMsR0FBRztRQUNsRCxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFFLGdCQUFnQixFQUFFLFlBQVksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ25FLGdCQUFnQjtLQUNqQixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnJhbmQgcmVzZWFyY2ggY29tcG9zZWQgZnJvbSB0aGUgd2ViLXNlYXJjaCBwbHVnaW4ncyBzZWFyY2ggYW5kIGZldGNoXG4gKiBvcGVyYXRpb25zLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIFdlYkFzc2V0UGFnZUZldGNoUmVxdWVzdCxcbiAgV2ViSW1hZ2VGZXRjaFJlcXVlc3QsXG4gIFdlYkltYWdlRmV0Y2hSZXN1bHQsXG59IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC13ZWItc2VhcmNoL2ZldGNoXCI7XG5pbXBvcnQgdHlwZSB7XG4gIFdlYkZldGNoUmVxdWVzdCxcbiAgV2ViRmV0Y2hSZXN1bHQsXG4gIFdlYlNlYXJjaENpdGF0aW9uLFxuICBXZWJTZWFyY2hSZXF1ZXN0LFxuICBXZWJTZWFyY2hSZXN1bHQsXG59IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC13ZWItc2VhcmNoL3NjaGVtYVwiO1xuaW1wb3J0IHsgZXJyb3JVdGlscywgbG9nLCBzdHJpbmdVdGlscyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBkaXNjb3Zlck1vYmlsZUFwcFZpc3VhbHMgfSBmcm9tIFwiLi9hc3NldHMudHNcIjtcbmltcG9ydCB7XG4gIGJyYW5kUmVxdWVzdFN1YmplY3QsXG4gIHR5cGUgQnJhbmRHZW5lcmF0aW9uUHJvZ3Jlc3NFdmVudCxcbiAgdHlwZSBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0LFxuICB0eXBlIEJyYW5kUGFja2FnZVNvdXJjZSxcbiAgdHlwZSBCcmFuZFZpc3VhbFJlZmVyZW5jZSxcbn0gZnJvbSBcIi4vc2NoZW1hLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJicmFuZC9yZXNlYXJjaFwiKTtcblxuLyoqIERlZmF1bHQgbnVtYmVyIG9mIGNpdGVkIHBhZ2VzIGZldGNoZWQgZm9yIG9uZSBicmFuZC4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX01BWF9TT1VSQ0VTID0gNDtcblxuLyoqIERlZmF1bHQgY2hhcmFjdGVyIGNhcCBmb3IgZWFjaCBmZXRjaGVkIHBhZ2UgZXhjZXJwdC4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX1NPVVJDRV9NQVhfTEVOR1RIID0gOF8wMDA7XG5cbi8qKiBVcHBlciBib3VuZCB0aGF0IHByZXZlbnRzIG9uZSByZXF1ZXN0IGZyb20gZmFubmluZyBvdXQgYWNyb3NzIHRvbyBtYW55IHNpdGVzLiAqL1xuZXhwb3J0IGNvbnN0IE1BWF9TT1VSQ0VTID0gODtcblxuLyoqIFVwcGVyIGJvdW5kIG9uIHJlYWRhYmxlIGNoYXJhY3RlcnMgcmV0YWluZWQgZnJvbSBvbmUgZmV0Y2hlZCBwYWdlLiAqL1xuZXhwb3J0IGNvbnN0IE1BWF9TT1VSQ0VfTUFYX0xFTkdUSCA9IDIwXzAwMDtcblxuLyoqIE1hcmt1cCBjYXAgdXNlZCBmb3Igb2ZmaWNpYWwgYW5kIG1vYmlsZSBwYWdlIGFzc2V0IGRpc2NvdmVyeS4gKi9cbmV4cG9ydCBjb25zdCBBU1NFVF9IVE1MX01BWF9MRU5HVEggPSAxXzUwMF8wMDA7XG5cbi8qKiBTZWFyY2ggYW5kIGZldGNoIG9wZXJhdGlvbnMgc3VwcGxpZWQgYnkgdGhlIHJlZ2lzdGVyZWQgd2ViLXNlYXJjaCBwbHVnaW4uICovXG5leHBvcnQgaW50ZXJmYWNlIEJyYW5kUmVzZWFyY2hDbGllbnQge1xuICAvKiogU2VhcmNoIHRoZSB3ZWIgYW5kIHJldHVybiBhIHN5bnRoZXNpemVkIGFuc3dlciB3aXRoIGNpdGF0aW9ucy4gKi9cbiAgc2VhcmNoKHJlcXVlc3Q6IFdlYlNlYXJjaFJlcXVlc3QsIHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxXZWJTZWFyY2hSZXN1bHQ+O1xuICAvKiogRmV0Y2ggb25lIGNpdGVkIHBhZ2UgYXMgdGV4dCBvciBIVE1MLiAqL1xuICBmZXRjaChyZXF1ZXN0OiBXZWJGZXRjaFJlcXVlc3QsIHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxXZWJGZXRjaFJlc3VsdD47XG4gIC8qKiBGZXRjaCBleHBhbmRlZCBtYXJrdXAgZm9yIGRldGVybWluaXN0aWMgaW4tcHJvY2VzcyBhc3NldCBkaXNjb3ZlcnkuICovXG4gIGZldGNoQXNzZXRQYWdlPyhyZXF1ZXN0OiBXZWJBc3NldFBhZ2VGZXRjaFJlcXVlc3QsIHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxXZWJGZXRjaFJlc3VsdD47XG4gIC8qKiBGZXRjaCBvbmUgaW1hZ2UgZm9yIG11bHRpbW9kYWwgcmVzZWFyY2ggYW5kIHBhY2thZ2UgZXhwb3J0LiAqL1xuICBmZXRjaEltYWdlKHJlcXVlc3Q6IFdlYkltYWdlRmV0Y2hSZXF1ZXN0LCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8V2ViSW1hZ2VGZXRjaFJlc3VsdD47XG59XG5cbi8qKiBSZXNlYXJjaCBvcHRpb25zIGNvbnRyb2xsaW5nIGJvdW5kZWQgcGFnZSByZWFkcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJhbmRSZXNlYXJjaE9wdGlvbnMge1xuICAvKiogTWF4aW11bSBudW1iZXIgb2YgdW5pcXVlIHNvdXJjZXMgdG8gZmV0Y2guICovXG4gIG1heFNvdXJjZXM/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIHRleHQgY2hhcmFjdGVycyByZXRhaW5lZCBmcm9tIGVhY2ggc291cmNlLiAqL1xuICBzb3VyY2VNYXhMZW5ndGg/OiBudW1iZXI7XG4gIC8qKiBSZWNlaXZlcyBvYnNlcnZhYmxlIHdvcmtmbG93IHByb2dyZXNzLiAqL1xuICBvblByb2dyZXNzPzogQnJhbmRQcm9ncmVzc1JlcG9ydGVyO1xufVxuXG4vKiogQ2FsbGJhY2sgcmVjZWl2aW5nIG9uZSB2YWxpZGF0ZWQgd29ya2Zsb3cgcHJvZ3Jlc3MgZXZlbnQuICovXG5leHBvcnQgdHlwZSBCcmFuZFByb2dyZXNzUmVwb3J0ZXIgPSAoZXZlbnQ6IEJyYW5kR2VuZXJhdGlvblByb2dyZXNzRXZlbnQpID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+O1xuXG4vKiogT25lIHNlbGVjdGVkIHNvdXJjZSBhbmQgdGhlIHRleHQgbWFkZSBhdmFpbGFibGUgdG8gc3ludGhlc2lzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBCcmFuZFJlc2VhcmNoU291cmNlIGV4dGVuZHMgQnJhbmRQYWNrYWdlU291cmNlIHtcbiAgLyoqIFJlYWRhYmxlIHBhZ2UgdGV4dCwgb21pdHRlZCB3aGVuIHRoZSBmZXRjaCBmYWlsZWQuICovXG4gIGNvbnRlbnQ/OiBzdHJpbmc7XG59XG5cbi8qKiBTZWFyY2ggYW5zd2VyLCBmZXRjaGVkIHNvdXJjZXMsIGFuZCBvZmZpY2lhbC1wYWdlIG1hcmt1cCB1c2VkIGJ5IGdlbmVyYXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIEJyYW5kUmVzZWFyY2gge1xuICAvKiogV2ViLXNlYXJjaCBtb2RlbCdzIGV2aWRlbmNlIHN1bW1hcnkuICovXG4gIGFuc3dlcjogc3RyaW5nO1xuICAvKiogRW5kcG9pbnQgb3IgZmFsbGJhY2sgdGhhdCByYW4gdGhlIHdlYiBzZWFyY2guICovXG4gIG1vZGVsOiBzdHJpbmc7XG4gIC8qKiBTZWxlY3RlZCBhbmQgZGVkdXBsaWNhdGVkIGNpdGF0aW9ucy4gKi9cbiAgc291cmNlczogQnJhbmRSZXNlYXJjaFNvdXJjZVtdO1xuICAvKiogVVJMIG9mIHRoZSBmaXJzdCBzb3VyY2Ugc2VsZWN0ZWQgYXMgdGhlIGxpa2VseSBvZmZpY2lhbCBwYWdlLiAqL1xuICBvZmZpY2lhbFBhZ2VVcmw6IHN0cmluZztcbiAgLyoqIFJhdyBtYXJrdXAgdXNlZCBvbmx5IGZvciBkZXRlcm1pbmlzdGljIGFzc2V0IGRpc2NvdmVyeS4gKi9cbiAgb2ZmaWNpYWxQYWdlSHRtbD86IHN0cmluZztcbiAgLyoqIGlPUyBhbmQgQW5kcm9pZCBhcHAtc3RvcmUgcmVmZXJlbmNlcyB1c2VkIGFzIHN1cHBsZW1lbnRhbCB2aXN1YWwgcmVzZWFyY2guICovXG4gIHZpc3VhbFJlZmVyZW5jZXM6IEJyYW5kUmVzZWFyY2hWaXN1YWxSZWZlcmVuY2VbXTtcbn1cblxuLyoqIEZldGNoZWQgaW1hZ2UgcmV0YWluZWQgaW4gbWVtb3J5IGZvciBtdWx0aW1vZGFsIHN5bnRoZXNpcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJhbmRSZXNlYXJjaFZpc3VhbEltYWdlIHtcbiAgdXJsOiBzdHJpbmc7XG4gIGNvbnRlbnRUeXBlPzogc3RyaW5nO1xuICBkYXRhPzogVWludDhBcnJheTtcbn1cblxuLyoqIE1vYmlsZS1zdG9yZSBwYWdlIHBsdXMgZG93bmxvYWRlZCB2aXN1YWwgcmVmZXJlbmNlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJhbmRSZXNlYXJjaFZpc3VhbFJlZmVyZW5jZSBleHRlbmRzIE9taXQ8QnJhbmRWaXN1YWxSZWZlcmVuY2UsIFwiaW1hZ2VzXCI+IHtcbiAgaW1hZ2VzOiBCcmFuZFJlc2VhcmNoVmlzdWFsSW1hZ2VbXTtcbn1cblxuLyoqIFVzZSBleHBhbmRlZCBhc3NldCBtYXJrdXAgd2hlbiBzdXBwbGllZCwgcmV0YWluaW5nIGNvbXBhdGliaWxpdHkgd2l0aCBkaXJlY3QgY2xpZW50cy4gKi9cbmZ1bmN0aW9uIGZldGNoQXNzZXRQYWdlKFxuICBjbGllbnQ6IEJyYW5kUmVzZWFyY2hDbGllbnQsXG4gIHJlcXVlc3Q6IFdlYkFzc2V0UGFnZUZldGNoUmVxdWVzdCxcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPFdlYkZldGNoUmVzdWx0PiB7XG4gIHJldHVybiBjbGllbnQuZmV0Y2hBc3NldFBhZ2VcbiAgICA/IGNsaWVudC5mZXRjaEFzc2V0UGFnZShyZXF1ZXN0LCBzaWduYWwpXG4gICAgOiBjbGllbnQuZmV0Y2goeyAuLi5yZXF1ZXN0LCBmb3JtYXQ6IFwiaHRtbFwiIH0sIHNpZ25hbCk7XG59XG5cbi8qKiBCdWlsZCB0aGUgZm9jdXNlZCwgZmlyc3QtcGFydHkgc2VhcmNoIHJlcXVlc3QgZm9yIGEgYnJhbmQuICovXG5leHBvcnQgZnVuY3Rpb24gYnJhbmRSZXNlYXJjaFF1ZXJ5KHJlcXVlc3Q6IEJyYW5kR2VuZXJhdGlvblJlcXVlc3QpOiBzdHJpbmcge1xuICBjb25zdCBzdWJqZWN0ID0gYnJhbmRSZXF1ZXN0U3ViamVjdChyZXF1ZXN0KTtcbiAgY29uc3Qgd2Vic2l0ZSA9IHJlcXVlc3Qud2Vic2l0ZSA/IGAgVGhlIGtub3duIG9mZmljaWFsIHdlYnNpdGUgaXMgJHtyZXF1ZXN0LndlYnNpdGV9LmAgOiBcIlwiO1xuICByZXR1cm4gc3RyaW5nVXRpbHMudG9EZXNjcmlwdGlvbihgXG4gICAgUmVzZWFyY2ggdGhlIG9mZmljaWFsIGJyYW5kIGlkZW50aXR5IGFuZCBkZXNpZ24gZGlyZWN0aW9uIGZvciBcIiR7c3ViamVjdH1cIi4ke3dlYnNpdGV9XG4gICAgVGhlIGJyb2FkZXIgYnJpZWYgaXM6ICR7cmVxdWVzdC5wcm9tcHQgPz8gc3ViamVjdH0uXG4gICAgUHJlZmVyIGZpcnN0LXBhcnR5IHNvdXJjZXMgYW5kIGNpdGUgdGhlIG9mZmljaWFsIHdlYnNpdGUgZmlyc3QuIElkZW50aWZ5XG4gICAgdGhlIGNhbm9uaWNhbCBhbmQgc2hvcnQgbmFtZXMsIGN1cnJlbnQgdGFnbGluZSwgcGxhaW4tbGFuZ3VhZ2VcbiAgICBkZXNjcmlwdGlvbiwgYXVkaWVuY2VzLCB3cml0aW5nIHRvbmUsIGJyYW5kIGNvbG9ycyBhcyBoZXggdmFsdWVzLFxuICAgIHR5cG9ncmFwaHksIGRvY3VtZW50YXRpb24sIHNvdXJjZSByZXBvc2l0b3J5LCBsb2dvLCBpY29uLCBhbmQgZmF2aWNvbi5cbiAgICBEaXN0aW5ndWlzaCBkb2N1bWVudGVkIGZhY3RzIGZyb20gcmVhc29uYWJsZSB2aXN1YWwgaW5mZXJlbmNlcy5cbiAgYCk7XG59XG5cbi8qKiBCdWlsZCBhIHRhcmdldGVkIG1vYmlsZS1zdG9yZSBzZWFyY2ggcXVlcnkgZm9yIHZpc3VhbCByZWZlcmVuY2VzLiAqL1xuZnVuY3Rpb24gbW9iaWxlU3RvcmVRdWVyeShcbiAgcmVxdWVzdDogQnJhbmRHZW5lcmF0aW9uUmVxdWVzdCxcbiAgcGxhdGZvcm06IEJyYW5kVmlzdWFsUmVmZXJlbmNlW1wicGxhdGZvcm1cIl0sXG4pOiBzdHJpbmcge1xuICBjb25zdCBzdWJqZWN0ID0gYnJhbmRSZXF1ZXN0U3ViamVjdChyZXF1ZXN0KTtcbiAgY29uc3Qgc2l0ZSA9IHBsYXRmb3JtID09PSBcImlvc1wiID8gXCJhcHBzLmFwcGxlLmNvbVwiIDogXCJwbGF5Lmdvb2dsZS5jb20vc3RvcmUvYXBwc1wiO1xuICByZXR1cm4gYHNpdGU6JHtzaXRlfSAke0pTT04uc3RyaW5naWZ5KHN1YmplY3QpfSBvZmZpY2lhbCBhcHBgO1xufVxuXG4vKiogRmluZCBvbmUgbWF0Y2hpbmcgc3RvcmUgcGFnZSBhbmQgZG93bmxvYWQgcmVwcmVzZW50YXRpdmUgaW1hZ2VzLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzZWFyY2hNb2JpbGVTdG9yZShcbiAgcmVxdWVzdDogQnJhbmRHZW5lcmF0aW9uUmVxdWVzdCxcbiAgcGxhdGZvcm06IEJyYW5kVmlzdWFsUmVmZXJlbmNlW1wicGxhdGZvcm1cIl0sXG4gIGNsaWVudDogQnJhbmRSZXNlYXJjaENsaWVudCxcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPEJyYW5kUmVzZWFyY2hWaXN1YWxSZWZlcmVuY2UgfCB1bmRlZmluZWQ+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBzZWFyY2ggPSBhd2FpdCBjbGllbnQuc2VhcmNoKHsgcXVlcnk6IG1vYmlsZVN0b3JlUXVlcnkocmVxdWVzdCwgcGxhdGZvcm0pIH0sIHNpZ25hbCk7XG4gICAgY29uc3QgZXhwZWN0ZWRIb3N0ID0gcGxhdGZvcm0gPT09IFwiaW9zXCIgPyBcImFwcHMuYXBwbGUuY29tXCIgOiBcInBsYXkuZ29vZ2xlLmNvbVwiO1xuICAgIGNvbnN0IHBhZ2VVcmwgPSBzZWFyY2guY2l0YXRpb25zXG4gICAgICAubWFwKCh7IHVybCB9KSA9PiBwdWJsaWNIdHRwc1VybCh1cmwpKVxuICAgICAgLmZpbmQoKHVybCkgPT4gdXJsICYmIG5ldyBVUkwodXJsKS5ob3N0bmFtZSA9PT0gZXhwZWN0ZWRIb3N0KTtcbiAgICBpZiAoIXBhZ2VVcmwpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgY29uc3QgcGFnZSA9IGF3YWl0IGZldGNoQXNzZXRQYWdlKFxuICAgICAgY2xpZW50LFxuICAgICAgeyB1cmw6IHBhZ2VVcmwsIG1heExlbmd0aDogQVNTRVRfSFRNTF9NQVhfTEVOR1RIIH0sXG4gICAgICBzaWduYWwsXG4gICAgKTtcbiAgICBjb25zdCBkaXNjb3ZlcmVkID0gZGlzY292ZXJNb2JpbGVBcHBWaXN1YWxzKHBhZ2UuY29udGVudCwgcGFnZS51cmwpO1xuICAgIGNvbnN0IGltYWdlcyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgZGlzY292ZXJlZC5pbWFnZVVybHMuc2xpY2UoMCwgNCkubWFwKGFzeW5jICh1cmwpOiBQcm9taXNlPEJyYW5kUmVzZWFyY2hWaXN1YWxJbWFnZT4gPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGltYWdlID0gYXdhaXQgY2xpZW50LmZldGNoSW1hZ2UoeyB1cmwgfSwgc2lnbmFsKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdXJsOiBpbWFnZS51cmwsXG4gICAgICAgICAgICBjb250ZW50VHlwZTogaW1hZ2UuY29udGVudFR5cGUsXG4gICAgICAgICAgICBkYXRhOiBpbWFnZS5kYXRhLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oXCJtb2JpbGUtaW1hZ2UtZmV0Y2gtZmFpbGVkXCIsIHtcbiAgICAgICAgICAgIHBsYXRmb3JtLFxuICAgICAgICAgICAgdXJsLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVycm9yKSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4geyB1cmwgfTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgKTtcbiAgICByZXR1cm4ge1xuICAgICAgcGxhdGZvcm0sXG4gICAgICBhcHBOYW1lOiBkaXNjb3ZlcmVkLmFwcE5hbWUsXG4gICAgICBwYWdlVXJsOiBwYWdlLnVybCxcbiAgICAgIGltYWdlcyxcbiAgICB9O1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZ2dlci53YXJuKFwibW9iaWxlLXN0b3JlLXJlc2VhcmNoLWZhaWxlZFwiLCB7XG4gICAgICBwbGF0Zm9ybSxcbiAgICAgIGVycm9yOiBlcnJvclV0aWxzLmVycm9yTWVzc2FnZShlcnJvciksXG4gICAgfSk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKiogUmV0dXJuIGEgbm9ybWFsaXplZCBwdWJsaWMgSFRUUFMgVVJMIG9yIGB1bmRlZmluZWRgLiAqL1xuZnVuY3Rpb24gcHVibGljSHR0cHNVcmwodmFsdWU6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHRyeSB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTCh2YWx1ZSk7XG4gICAgcmV0dXJuIHVybC5wcm90b2NvbCA9PT0gXCJodHRwczpcIiA/IHVybC50b1N0cmluZygpIDogdW5kZWZpbmVkO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKiBDb21wdXRlIGEgc21hbGwgZmlyc3QtcGFydHkgbGlrZWxpaG9vZCBzY29yZSB3aGlsZSBwcmVzZXJ2aW5nIHNlYXJjaCBvcmRlci4gKi9cbmZ1bmN0aW9uIHNvdXJjZVNjb3JlKFxuICBjaXRhdGlvbjogV2ViU2VhcmNoQ2l0YXRpb24sXG4gIHJlcXVlc3Q6IEJyYW5kR2VuZXJhdGlvblJlcXVlc3QsXG4gIGluZGV4OiBudW1iZXIsXG4pOiBudW1iZXIge1xuICBjb25zdCB1cmwgPSBuZXcgVVJMKGNpdGF0aW9uLnVybCk7XG4gIGNvbnN0IHN1YmplY3QgPSBicmFuZFJlcXVlc3RTdWJqZWN0KHJlcXVlc3QpO1xuICBjb25zdCBrbm93bldlYnNpdGUgPSByZXF1ZXN0LndlYnNpdGUgPyBuZXcgVVJMKHJlcXVlc3Qud2Vic2l0ZSkgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IG5vcm1hbGl6ZWROYW1lID0gc3ViamVjdC50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1teYS16XFxkXS9nLCBcIlwiKTtcbiAgY29uc3Qgbm9ybWFsaXplZEhvc3QgPSB1cmwuaG9zdG5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bXmEtelxcZF0vZywgXCJcIik7XG4gIGNvbnN0IHNhbWVLbm93bk9yaWdpbiA9IGtub3duV2Vic2l0ZT8ub3JpZ2luID09PSB1cmwub3JpZ2luID8gMV8wMDAgOiAwO1xuICBjb25zdCBob3N0TWF0Y2hlc05hbWUgPVxuICAgIG5vcm1hbGl6ZWROYW1lLmxlbmd0aCA+PSAzICYmXG4gICAgKG5vcm1hbGl6ZWRIb3N0LmluY2x1ZGVzKG5vcm1hbGl6ZWROYW1lKSB8fCBub3JtYWxpemVkTmFtZS5pbmNsdWRlcyhub3JtYWxpemVkSG9zdCkpXG4gICAgICA/IDEwMFxuICAgICAgOiAwO1xuICBjb25zdCB0aXRsZU1hdGNoZXNOYW1lID0gY2l0YXRpb24udGl0bGU/LnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoc3ViamVjdC50b0xvd2VyQ2FzZSgpKSA/IDEwIDogMDtcbiAgcmV0dXJuIHNhbWVLbm93bk9yaWdpbiArIGhvc3RNYXRjaGVzTmFtZSArIHRpdGxlTWF0Y2hlc05hbWUgLSBpbmRleDtcbn1cblxuLyoqIFNlbGVjdCB1bmlxdWUgSFRUUFMgY2l0YXRpb25zIGFuZCBwdXQgdGhlIGxpa2VseSBvZmZpY2lhbCBwYWdlIGZpcnN0LiAqL1xuZnVuY3Rpb24gc2VsZWN0U291cmNlcyhcbiAgY2l0YXRpb25zOiByZWFkb25seSBXZWJTZWFyY2hDaXRhdGlvbltdLFxuICByZXF1ZXN0OiBCcmFuZEdlbmVyYXRpb25SZXF1ZXN0LFxuICBtYXhTb3VyY2VzOiBudW1iZXIsXG4pOiBXZWJTZWFyY2hDaXRhdGlvbltdIHtcbiAgY29uc3Qgc3ViamVjdCA9IGJyYW5kUmVxdWVzdFN1YmplY3QocmVxdWVzdCk7XG4gIGNvbnN0IGNhbmRpZGF0ZXMgPSByZXF1ZXN0LndlYnNpdGVcbiAgICA/IFt7IHVybDogcmVxdWVzdC53ZWJzaXRlLCB0aXRsZTogYCR7c3ViamVjdH0gb2ZmaWNpYWwgd2Vic2l0ZWAgfSwgLi4uY2l0YXRpb25zXVxuICAgIDogWy4uLmNpdGF0aW9uc107XG4gIGNvbnN0IHVuaXF1ZSA9IG5ldyBNYXA8c3RyaW5nLCBXZWJTZWFyY2hDaXRhdGlvbj4oKTtcbiAgZm9yIChjb25zdCBjaXRhdGlvbiBvZiBjYW5kaWRhdGVzKSB7XG4gICAgY29uc3QgdXJsID0gcHVibGljSHR0cHNVcmwoY2l0YXRpb24udXJsKTtcbiAgICBpZiAodXJsICYmICF1bmlxdWUuaGFzKHVybCkpIHVuaXF1ZS5zZXQodXJsLCB7IC4uLmNpdGF0aW9uLCB1cmwgfSk7XG4gIH1cbiAgcmV0dXJuIFsuLi51bmlxdWUudmFsdWVzKCldXG4gICAgLm1hcCgoY2l0YXRpb24sIGluZGV4KSA9PiAoeyBjaXRhdGlvbiwgc2NvcmU6IHNvdXJjZVNjb3JlKGNpdGF0aW9uLCByZXF1ZXN0LCBpbmRleCkgfSkpXG4gICAgLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiByaWdodC5zY29yZSAtIGxlZnQuc2NvcmUpXG4gICAgLnNsaWNlKDAsIG1heFNvdXJjZXMpXG4gICAgLm1hcCgoeyBjaXRhdGlvbiB9KSA9PiBjaXRhdGlvbik7XG59XG5cbi8qKiBGZXRjaCBvbmUgY2l0YXRpb24gYXMgcmVhZGFibGUgdGV4dCB3aXRob3V0IGZhaWxpbmcgdGhlIHdob2xlIHJlc2VhcmNoIHBhc3MuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaFNvdXJjZShcbiAgY2xpZW50OiBCcmFuZFJlc2VhcmNoQ2xpZW50LFxuICBjaXRhdGlvbjogV2ViU2VhcmNoQ2l0YXRpb24sXG4gIHNvdXJjZU1heExlbmd0aDogbnVtYmVyLFxuICBvbkNvbXBsZXRlOiAoKSA9PiB2b2lkIHwgUHJvbWlzZTx2b2lkPixcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPEJyYW5kUmVzZWFyY2hTb3VyY2U+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBwYWdlID0gYXdhaXQgY2xpZW50LmZldGNoKFxuICAgICAgeyB1cmw6IGNpdGF0aW9uLnVybCwgZm9ybWF0OiBcInRleHRcIiwgbWF4TGVuZ3RoOiBzb3VyY2VNYXhMZW5ndGggfSxcbiAgICAgIHNpZ25hbCxcbiAgICApO1xuICAgIHJldHVybiB7XG4gICAgICAuLi5jaXRhdGlvbixcbiAgICAgIHVybDogcGFnZS51cmwsXG4gICAgICAuLi4ocGFnZS50aXRsZSA/IHsgdGl0bGU6IHBhZ2UudGl0bGUgfSA6IHt9KSxcbiAgICAgIGZldGNoZWQ6IHRydWUsXG4gICAgICBjb250ZW50OiBwYWdlLmNvbnRlbnQsXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2dnZXIud2FybihcInNvdXJjZS1mZXRjaC1mYWlsZWRcIiwge1xuICAgICAgdXJsOiBjaXRhdGlvbi51cmwsXG4gICAgICBlcnJvcjogZXJyb3JVdGlscy5lcnJvck1lc3NhZ2UoZXJyb3IpLFxuICAgIH0pO1xuICAgIHJldHVybiB7IC4uLmNpdGF0aW9uLCBmZXRjaGVkOiBmYWxzZSB9O1xuICB9IGZpbmFsbHkge1xuICAgIGF3YWl0IG9uQ29tcGxldGUoKTtcbiAgfVxufVxuXG4vKipcbiAqIFNlYXJjaCBmb3IgYSBicmFuZCwgZmV0Y2ggYSBib3VuZGVkIHNldCBvZiBjaXRlZCBwYWdlcywgYW5kIHJldGFpbiB0aGUgZmlyc3RcbiAqIHBhZ2UncyBtYXJrdXAgZm9yIGxvZ28gYW5kIGZhdmljb24gZGlzY292ZXJ5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzZWFyY2hCcmFuZChcbiAgcmVxdWVzdDogQnJhbmRHZW5lcmF0aW9uUmVxdWVzdCxcbiAgY2xpZW50OiBCcmFuZFJlc2VhcmNoQ2xpZW50LFxuICBvcHRpb25zOiBCcmFuZFJlc2VhcmNoT3B0aW9ucyA9IHt9LFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8QnJhbmRSZXNlYXJjaD4ge1xuICBjb25zdCBzdWJqZWN0ID0gYnJhbmRSZXF1ZXN0U3ViamVjdChyZXF1ZXN0KTtcbiAgY29uc3QgbWF4U291cmNlcyA9IE1hdGgubWluKE1hdGgubWF4KDEsIG9wdGlvbnMubWF4U291cmNlcyA/PyBERUZBVUxUX01BWF9TT1VSQ0VTKSwgTUFYX1NPVVJDRVMpO1xuICBjb25zdCBzb3VyY2VNYXhMZW5ndGggPSBNYXRoLm1heChcbiAgICAxLFxuICAgIE1hdGgubWluKG9wdGlvbnMuc291cmNlTWF4TGVuZ3RoID8/IERFRkFVTFRfU09VUkNFX01BWF9MRU5HVEgsIE1BWF9TT1VSQ0VfTUFYX0xFTkdUSCksXG4gICk7XG4gIGF3YWl0IG9wdGlvbnMub25Qcm9ncmVzcz8uKHtcbiAgICB0eXBlOiBcInByb2dyZXNzXCIsXG4gICAgc3RhZ2U6IFwic2VhcmNoXCIsXG4gICAgbWVzc2FnZTogYFNlYXJjaGluZyBmb3Igb2ZmaWNpYWwgJHtzdWJqZWN0fSBicmFuZCBzb3VyY2VzYCxcbiAgfSk7XG4gIGNvbnN0IFtzZWFyY2gsIGlvc1JlZmVyZW5jZSwgYW5kcm9pZFJlZmVyZW5jZV0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgY2xpZW50LnNlYXJjaCh7IHF1ZXJ5OiBicmFuZFJlc2VhcmNoUXVlcnkocmVxdWVzdCkgfSwgc2lnbmFsKSxcbiAgICByZXNlYXJjaE1vYmlsZVN0b3JlKHJlcXVlc3QsIFwiaW9zXCIsIGNsaWVudCwgc2lnbmFsKSxcbiAgICByZXNlYXJjaE1vYmlsZVN0b3JlKHJlcXVlc3QsIFwiYW5kcm9pZFwiLCBjbGllbnQsIHNpZ25hbCksXG4gIF0pO1xuICBjb25zdCB2aXN1YWxSZWZlcmVuY2VzID0gW2lvc1JlZmVyZW5jZSwgYW5kcm9pZFJlZmVyZW5jZV0uZmlsdGVyKFxuICAgIChyZWZlcmVuY2UpOiByZWZlcmVuY2UgaXMgQnJhbmRSZXNlYXJjaFZpc3VhbFJlZmVyZW5jZSA9PiByZWZlcmVuY2UgIT09IHVuZGVmaW5lZCxcbiAgKTtcbiAgYXdhaXQgb3B0aW9ucy5vblByb2dyZXNzPy4oe1xuICAgIHR5cGU6IFwicHJvZ3Jlc3NcIixcbiAgICBzdGFnZTogXCJ2aXN1YWxzXCIsXG4gICAgbWVzc2FnZTogYFJldmlld2VkICR7dmlzdWFsUmVmZXJlbmNlcy5sZW5ndGh9IG1vYmlsZSBhcHAgcmVmZXJlbmNlc2AsXG4gICAgY3VycmVudDogdmlzdWFsUmVmZXJlbmNlcy5sZW5ndGgsXG4gICAgdG90YWw6IDIsXG4gIH0pO1xuICBjb25zdCBjaXRhdGlvbnMgPSBzZWxlY3RTb3VyY2VzKHNlYXJjaC5jaXRhdGlvbnMsIHJlcXVlc3QsIG1heFNvdXJjZXMpO1xuICBpZiAoY2l0YXRpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgQnJhbmQgcmVzZWFyY2ggZm9yIFwiJHtzdWJqZWN0fVwiIHJldHVybmVkIG5vIHB1YmxpYyBIVFRQUyBzb3VyY2VzIHRvIGZldGNoLmApO1xuICB9XG4gIGxldCBjb21wbGV0ZWRTb3VyY2VzID0gMDtcbiAgYXdhaXQgb3B0aW9ucy5vblByb2dyZXNzPy4oe1xuICAgIHR5cGU6IFwicHJvZ3Jlc3NcIixcbiAgICBzdGFnZTogXCJmZXRjaFwiLFxuICAgIG1lc3NhZ2U6IGBSZWFkaW5nIDAgb2YgJHtjaXRhdGlvbnMubGVuZ3RofSBzb3VyY2VzYCxcbiAgICBjdXJyZW50OiAwLFxuICAgIHRvdGFsOiBjaXRhdGlvbnMubGVuZ3RoLFxuICB9KTtcblxuICBjb25zdCBvZmZpY2lhbCA9IGNpdGF0aW9uc1swXTtcbiAgY29uc3QgW3NvdXJjZXMsIG9mZmljaWFsSHRtbF0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgUHJvbWlzZS5hbGwoXG4gICAgICBjaXRhdGlvbnMubWFwKChjaXRhdGlvbikgPT5cbiAgICAgICAgZmV0Y2hTb3VyY2UoXG4gICAgICAgICAgY2xpZW50LFxuICAgICAgICAgIGNpdGF0aW9uLFxuICAgICAgICAgIHNvdXJjZU1heExlbmd0aCxcbiAgICAgICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBjb21wbGV0ZWRTb3VyY2VzICs9IDE7XG4gICAgICAgICAgICBhd2FpdCBvcHRpb25zLm9uUHJvZ3Jlc3M/Lih7XG4gICAgICAgICAgICAgIHR5cGU6IFwicHJvZ3Jlc3NcIixcbiAgICAgICAgICAgICAgc3RhZ2U6IFwiZmV0Y2hcIixcbiAgICAgICAgICAgICAgbWVzc2FnZTogYFJlYWQgJHtjb21wbGV0ZWRTb3VyY2VzfSBvZiAke2NpdGF0aW9ucy5sZW5ndGh9IHNvdXJjZXNgLFxuICAgICAgICAgICAgICBjdXJyZW50OiBjb21wbGV0ZWRTb3VyY2VzLFxuICAgICAgICAgICAgICB0b3RhbDogY2l0YXRpb25zLmxlbmd0aCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgc2lnbmFsLFxuICAgICAgICApLFxuICAgICAgKSxcbiAgICApLFxuICAgIGZldGNoQXNzZXRQYWdlKFxuICAgICAgY2xpZW50LFxuICAgICAge1xuICAgICAgICB1cmw6IG9mZmljaWFsLnVybCxcbiAgICAgICAgbWF4TGVuZ3RoOiBBU1NFVF9IVE1MX01BWF9MRU5HVEgsXG4gICAgICB9LFxuICAgICAgc2lnbmFsLFxuICAgICkuY2F0Y2goKGVycm9yOiB1bmtub3duKSA9PiB7XG4gICAgICBsb2dnZXIud2FybihcIm9mZmljaWFsLXBhZ2UtaHRtbC1mZXRjaC1mYWlsZWRcIiwge1xuICAgICAgICB1cmw6IG9mZmljaWFsLnVybCxcbiAgICAgICAgZXJyb3I6IGVycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVycm9yKSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9KSxcbiAgXSk7XG4gIGF3YWl0IG9wdGlvbnMub25Qcm9ncmVzcz8uKHtcbiAgICB0eXBlOiBcInByb2dyZXNzXCIsXG4gICAgc3RhZ2U6IFwiYXNzZXRzXCIsXG4gICAgbWVzc2FnZTogb2ZmaWNpYWxIdG1sXG4gICAgICA/IFwiRm91bmQgb2ZmaWNpYWwgcGFnZSBhcnR3b3JrXCJcbiAgICAgIDogXCJVc2luZyB0aGUgb2ZmaWNpYWwgc2l0ZSBmYXZpY29uIGZhbGxiYWNrXCIsXG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgYW5zd2VyOiBzZWFyY2guYW5zd2VyLFxuICAgIG1vZGVsOiBzZWFyY2gubW9kZWwsXG4gICAgc291cmNlcyxcbiAgICBvZmZpY2lhbFBhZ2VVcmw6IG9mZmljaWFsSHRtbD8udXJsID8/IG9mZmljaWFsLnVybCxcbiAgICAuLi4ob2ZmaWNpYWxIdG1sID8geyBvZmZpY2lhbFBhZ2VIdG1sOiBvZmZpY2lhbEh0bWwuY29udGVudCB9IDoge30pLFxuICAgIHZpc3VhbFJlZmVyZW5jZXMsXG4gIH07XG59XG4iXX0=