every-plugin 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/rspack/index.cjs +300 -0
- package/dist/build/rspack/index.d.cts +20 -0
- package/dist/build/rspack/index.d.mts +20 -0
- package/dist/build/rspack/index.mjs +298 -0
- package/dist/chunk-QQAxy9l9.mjs +31 -0
- package/dist/chunk-zltIcp7o.cjs +46 -0
- package/dist/effect.cjs +9 -0
- package/dist/effect.d.cts +1 -0
- package/dist/effect.d.mts +1 -0
- package/dist/effect.mjs +3 -0
- package/dist/errors-CVnoPl9v.cjs +68 -0
- package/dist/errors-Car4tFVP.d.mts +75 -0
- package/dist/errors-D7keKf7a.mjs +63 -0
- package/dist/errors-DKPPPYYT.d.cts +75 -0
- package/dist/errors.cjs +4 -0
- package/dist/errors.d.cts +3 -0
- package/dist/errors.d.mts +3 -0
- package/dist/errors.mjs +4 -0
- package/dist/fetch-Cc95-7kM.cjs +336 -0
- package/dist/fetch-KLktuWuM.mjs +335 -0
- package/dist/index-bwAhA9ca.d.mts +383 -0
- package/dist/index-matrPV4m.d.cts +382 -0
- package/dist/index.cjs +57 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +52 -0
- package/dist/{runtime/services/normalize.d.ts → normalize-BLTyqFww.d.mts} +5 -2
- package/dist/{runtime/services/normalize.js → normalize-BW7kk8Lk.d.cts} +5 -1
- package/dist/normalize-D4Qh0wVk.cjs +28 -0
- package/dist/normalize-D7nae0Hn.mjs +22 -0
- package/dist/openapi.DrTcell5-C6kyDyUK.mjs +669 -0
- package/dist/openapi.DrTcell5-DDf4D5V3.cjs +687 -0
- package/dist/orpc.cjs +46 -0
- package/dist/orpc.d.cts +7 -0
- package/dist/orpc.d.mts +7 -0
- package/dist/orpc.mjs +11 -0
- package/dist/package-CmegWGdE.cjs +154 -0
- package/dist/package-Dn-xZ55N.mjs +149 -0
- package/dist/plugins-C-7lh5gK.cjs +128 -0
- package/dist/plugins-Ps5Xxpk2.mjs +128 -0
- package/dist/runtime/index.cjs +6 -0
- package/dist/runtime/index.d.cts +5 -0
- package/dist/runtime/index.d.mts +5 -0
- package/dist/runtime/index.mjs +5 -0
- package/dist/runtime/services/normalize.cjs +3 -0
- package/dist/runtime/services/normalize.d.cts +2 -0
- package/dist/runtime/services/normalize.d.mts +2 -0
- package/dist/runtime/services/normalize.mjs +3 -0
- package/dist/runtime-CgRUExK3.cjs +523 -0
- package/dist/runtime-Da2NjzYy.mjs +458 -0
- package/dist/standard-DaxKTFui.mjs +595 -0
- package/dist/standard-eUgUkWaf.cjs +702 -0
- package/dist/testing/index.cjs +78 -0
- package/dist/testing/index.d.cts +60 -0
- package/dist/testing/index.d.mts +60 -0
- package/dist/testing/index.mjs +75 -0
- package/dist/zod-A7Pti5IV.d.cts +4 -0
- package/dist/zod-BVo51kgJ.mjs +10 -0
- package/dist/zod-D4CFw8d9.d.mts +4 -0
- package/dist/zod-DYghWCz1.cjs +14 -0
- package/dist/zod.cjs +10 -0
- package/dist/zod.d.cts +2 -0
- package/dist/zod.d.mts +2 -0
- package/dist/zod.mjs +5 -0
- package/dist/zod4-BXTBR1od.cjs +318 -0
- package/dist/zod4-VpXuwRO7.mjs +317 -0
- package/package.json +64 -23
- package/dist/effect.d.ts +0 -2
- package/dist/effect.d.ts.map +0 -1
- package/dist/effect.js +0 -1
- package/dist/errors.d.ts +0 -70
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -61
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -5
- package/dist/orpc.d.ts +0 -10
- package/dist/orpc.d.ts.map +0 -1
- package/dist/orpc.js +0 -6
- package/dist/plugin.d.ts +0 -57
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -43
- package/dist/runtime/errors.d.ts +0 -36
- package/dist/runtime/errors.d.ts.map +0 -1
- package/dist/runtime/errors.js +0 -47
- package/dist/runtime/index.d.ts +0 -20
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js +0 -131
- package/dist/runtime/services/module-federation.service.d.ts +0 -13
- package/dist/runtime/services/module-federation.service.d.ts.map +0 -1
- package/dist/runtime/services/module-federation.service.js +0 -155
- package/dist/runtime/services/normalize.d.ts.map +0 -1
- package/dist/runtime/services/plugin-lifecycle.service.d.ts +0 -14
- package/dist/runtime/services/plugin-lifecycle.service.d.ts.map +0 -1
- package/dist/runtime/services/plugin-lifecycle.service.js +0 -34
- package/dist/runtime/services/plugin-loader.service.d.ts +0 -45
- package/dist/runtime/services/plugin-loader.service.d.ts.map +0 -1
- package/dist/runtime/services/plugin-loader.service.js +0 -93
- package/dist/runtime/services/plugin.service.d.ts +0 -36
- package/dist/runtime/services/plugin.service.d.ts.map +0 -1
- package/dist/runtime/services/plugin.service.js +0 -31
- package/dist/runtime/services/secrets.service.d.ts +0 -15
- package/dist/runtime/services/secrets.service.d.ts.map +0 -1
- package/dist/runtime/services/secrets.service.js +0 -35
- package/dist/runtime/services.d.ts +0 -6
- package/dist/runtime/services.d.ts.map +0 -1
- package/dist/runtime/services.js +0 -5
- package/dist/runtime/validation.d.ts +0 -5
- package/dist/runtime/validation.d.ts.map +0 -1
- package/dist/runtime/validation.js +0 -13
- package/dist/testing/index.d.ts +0 -59
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js +0 -45
- package/dist/testing/mocks/module-federation.service.d.ts +0 -6
- package/dist/testing/mocks/module-federation.service.d.ts.map +0 -1
- package/dist/testing/mocks/module-federation.service.js +0 -29
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types.d.ts +0 -187
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
- package/dist/zod.d.ts +0 -2
- package/dist/zod.d.ts.map +0 -1
- package/dist/zod.js +0 -1
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-zltIcp7o.cjs');
|
|
2
|
+
const require_normalize = require('./normalize-D4Qh0wVk.cjs');
|
|
3
|
+
const require_package$1 = require('./package-CmegWGdE.cjs');
|
|
4
|
+
let effect = require("effect");
|
|
5
|
+
let zod = require("zod");
|
|
6
|
+
let __orpc_server = require("@orpc/server");
|
|
7
|
+
let __orpc_contract = require("@orpc/contract");
|
|
8
|
+
let __better_fetch_fetch = require("@better-fetch/fetch");
|
|
9
|
+
let __module_federation_enhanced_runtime = require("@module-federation/enhanced/runtime");
|
|
10
|
+
let __module_federation_runtime_core = require("@module-federation/runtime-core");
|
|
11
|
+
|
|
12
|
+
//#region src/runtime/errors.ts
|
|
13
|
+
var PluginRuntimeError = class extends effect.Data.TaggedError("PluginRuntimeError") {};
|
|
14
|
+
var ModuleFederationError = class extends effect.Data.TaggedError("ModuleFederationError") {};
|
|
15
|
+
var ValidationError = class extends effect.Data.TaggedError("ValidationError") {};
|
|
16
|
+
const isRetryableORPCCode = (code) => {
|
|
17
|
+
switch (code) {
|
|
18
|
+
case "TOO_MANY_REQUESTS":
|
|
19
|
+
case "SERVICE_UNAVAILABLE":
|
|
20
|
+
case "BAD_GATEWAY":
|
|
21
|
+
case "GATEWAY_TIMEOUT":
|
|
22
|
+
case "TIMEOUT": return true;
|
|
23
|
+
default: return false;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const wrapORPCError = (orpcError, pluginId, procedureName, operation) => {
|
|
27
|
+
return new PluginRuntimeError({
|
|
28
|
+
pluginId,
|
|
29
|
+
operation,
|
|
30
|
+
procedureName,
|
|
31
|
+
retryable: isRetryableORPCCode(orpcError.code),
|
|
32
|
+
cause: orpcError
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const toPluginRuntimeError = (error, pluginId, procedureName, operation, defaultRetryable = false) => {
|
|
36
|
+
if (error instanceof __orpc_contract.ORPCError) return wrapORPCError(error, pluginId, procedureName, operation);
|
|
37
|
+
if (error instanceof PluginRuntimeError) return error;
|
|
38
|
+
return new PluginRuntimeError({
|
|
39
|
+
pluginId,
|
|
40
|
+
operation,
|
|
41
|
+
procedureName,
|
|
42
|
+
retryable: defaultRetryable,
|
|
43
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/runtime/services/module-federation.service.ts
|
|
49
|
+
var import_package = /* @__PURE__ */ require_chunk.__toESM(require_package$1.require_package(), 1);
|
|
50
|
+
const createModuleFederationInstance = effect.Effect.cached(effect.Effect.sync(() => {
|
|
51
|
+
try {
|
|
52
|
+
let instance = (0, __module_federation_enhanced_runtime.getInstance)();
|
|
53
|
+
if (!instance) {
|
|
54
|
+
instance = (0, __module_federation_enhanced_runtime.createInstance)({
|
|
55
|
+
name: "host",
|
|
56
|
+
remotes: [],
|
|
57
|
+
shared: {
|
|
58
|
+
"every-plugin": {
|
|
59
|
+
version: import_package.default.version,
|
|
60
|
+
shareConfig: {
|
|
61
|
+
singleton: true,
|
|
62
|
+
requiredVersion: `^${import_package.default.version}`,
|
|
63
|
+
eager: true,
|
|
64
|
+
strictVersion: false
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
effect: {
|
|
68
|
+
version: import_package.default.dependencies.effect,
|
|
69
|
+
shareConfig: {
|
|
70
|
+
singleton: true,
|
|
71
|
+
requiredVersion: "^3.18.0",
|
|
72
|
+
eager: true,
|
|
73
|
+
strictVersion: false
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
zod: {
|
|
77
|
+
version: import_package.default.dependencies.zod,
|
|
78
|
+
shareConfig: {
|
|
79
|
+
singleton: true,
|
|
80
|
+
requiredVersion: "^4.1.0",
|
|
81
|
+
eager: true,
|
|
82
|
+
strictVersion: false
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"@orpc/contract": {
|
|
86
|
+
version: import_package.default.dependencies["@orpc/contract"],
|
|
87
|
+
shareConfig: {
|
|
88
|
+
singleton: true,
|
|
89
|
+
requiredVersion: "^1.8.0",
|
|
90
|
+
eager: true,
|
|
91
|
+
strictVersion: false
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"@orpc/server": {
|
|
95
|
+
version: import_package.default.dependencies["@orpc/server"],
|
|
96
|
+
shareConfig: {
|
|
97
|
+
singleton: true,
|
|
98
|
+
requiredVersion: "^1.8.0",
|
|
99
|
+
eager: true,
|
|
100
|
+
strictVersion: false
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
(0, __module_federation_runtime_core.setGlobalFederationInstance)(instance);
|
|
106
|
+
}
|
|
107
|
+
return instance;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw new Error(`Failed to initialize Module Federation: ${error}`);
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
var ModuleFederationService = class extends effect.Effect.Service()("ModuleFederationService", { effect: effect.Effect.gen(function* () {
|
|
113
|
+
const mf = yield* effect.Effect.flatten(createModuleFederationInstance);
|
|
114
|
+
return {
|
|
115
|
+
registerRemote: (pluginId, url) => effect.Effect.gen(function* () {
|
|
116
|
+
console.log(`[MF] Registering ${pluginId}`);
|
|
117
|
+
const { error } = yield* effect.Effect.tryPromise({
|
|
118
|
+
try: () => (0, __better_fetch_fetch.betterFetch)(url, { method: "HEAD" }),
|
|
119
|
+
catch: (error$1) => new ModuleFederationError({
|
|
120
|
+
pluginId,
|
|
121
|
+
remoteUrl: url,
|
|
122
|
+
cause: error$1 instanceof Error ? error$1 : new Error(String(error$1))
|
|
123
|
+
})
|
|
124
|
+
});
|
|
125
|
+
if (error) {
|
|
126
|
+
console.log(`[MF] ❌ Remote not available for ${pluginId}`);
|
|
127
|
+
return yield* effect.Effect.fail(new ModuleFederationError({
|
|
128
|
+
pluginId,
|
|
129
|
+
remoteUrl: url,
|
|
130
|
+
cause: /* @__PURE__ */ new Error(`Remote not available (${url}): ${JSON.stringify(error)}`)
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
const remoteName = require_normalize.getNormalizedRemoteName(pluginId);
|
|
134
|
+
yield* effect.Effect.try({
|
|
135
|
+
try: () => mf.registerRemotes([{
|
|
136
|
+
name: remoteName,
|
|
137
|
+
entry: url
|
|
138
|
+
}]),
|
|
139
|
+
catch: (error$1) => new ModuleFederationError({
|
|
140
|
+
pluginId,
|
|
141
|
+
remoteUrl: url,
|
|
142
|
+
cause: error$1 instanceof Error ? error$1 : new Error(String(error$1))
|
|
143
|
+
})
|
|
144
|
+
});
|
|
145
|
+
console.log(`[MF] ✅ Registered ${pluginId}`);
|
|
146
|
+
}),
|
|
147
|
+
loadRemoteConstructor: (pluginId, url) => effect.Effect.gen(function* () {
|
|
148
|
+
const remoteName = require_normalize.getNormalizedRemoteName(pluginId);
|
|
149
|
+
console.log(`[MF] Loading remote ${remoteName}`);
|
|
150
|
+
const modulePath = `${remoteName}/plugin`;
|
|
151
|
+
return yield* effect.Effect.tryPromise({
|
|
152
|
+
try: async () => {
|
|
153
|
+
const container = await mf.loadRemote(modulePath);
|
|
154
|
+
if (!container) throw new Error(`No container returned for ${modulePath}`);
|
|
155
|
+
const Constructor = typeof container === "function" ? container : container.default ? container.default : Object.values(container).find((exp) => typeof exp === "function" && exp.prototype?.constructor === exp);
|
|
156
|
+
if (!Constructor || typeof Constructor !== "function") {
|
|
157
|
+
const containerInfo = typeof container === "object" ? `Available exports: ${Object.keys(container).join(", ")}` : `Container type: ${typeof container}`;
|
|
158
|
+
throw new Error(`No valid plugin constructor found for '${pluginId}'.\nSupported patterns:\n - export const YourPlugin = createPlugin({...})\n - export default createPlugin({...})\n${containerInfo}`);
|
|
159
|
+
}
|
|
160
|
+
if (!Constructor.binding) {
|
|
161
|
+
const containerInfo = typeof container === "object" ? `Found exports: ${Object.keys(container).join(", ")}` : `Container type: ${typeof container}`;
|
|
162
|
+
throw new Error(`Invalid plugin constructor for '${pluginId}'. The exported value must be created with createPlugin(). Found a function but it's missing the required 'binding' property.\n${containerInfo}`);
|
|
163
|
+
}
|
|
164
|
+
console.log(`[MF] ✅ Loaded constructor for ${pluginId}`);
|
|
165
|
+
return Constructor;
|
|
166
|
+
},
|
|
167
|
+
catch: (error) => new ModuleFederationError({
|
|
168
|
+
pluginId,
|
|
169
|
+
remoteUrl: url,
|
|
170
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
171
|
+
})
|
|
172
|
+
});
|
|
173
|
+
})
|
|
174
|
+
};
|
|
175
|
+
}) }) {};
|
|
176
|
+
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/runtime/services/plugin-lifecycle.service.ts
|
|
179
|
+
var PluginLifecycleService = class extends effect.Effect.Service()("PluginLifecycleService", { effect: effect.Effect.gen(function* () {
|
|
180
|
+
const activePlugins = yield* effect.Ref.make(/* @__PURE__ */ new Set());
|
|
181
|
+
return {
|
|
182
|
+
register: (plugin) => effect.Ref.update(activePlugins, (plugins) => new Set(plugins).add(plugin)),
|
|
183
|
+
unregister: (plugin) => effect.Ref.update(activePlugins, (plugins) => {
|
|
184
|
+
const newSet = new Set(plugins);
|
|
185
|
+
newSet.delete(plugin);
|
|
186
|
+
return newSet;
|
|
187
|
+
}),
|
|
188
|
+
shutdown: (plugin) => effect.Effect.gen(function* () {
|
|
189
|
+
yield* effect.Ref.update(activePlugins, (plugins) => {
|
|
190
|
+
const newSet = new Set(plugins);
|
|
191
|
+
newSet.delete(plugin);
|
|
192
|
+
return newSet;
|
|
193
|
+
});
|
|
194
|
+
yield* plugin.plugin.shutdown().pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, plugin.plugin.id, void 0, "shutdown-plugin", false)));
|
|
195
|
+
}),
|
|
196
|
+
cleanup: () => effect.Effect.gen(function* () {
|
|
197
|
+
const plugins = yield* effect.Ref.get(activePlugins);
|
|
198
|
+
yield* effect.Effect.forEach(plugins, (plugin) => plugin.plugin.shutdown().pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, plugin.plugin.id, void 0, "cleanup-shutdown", false)), effect.Effect.catchAll((error) => effect.Effect.logError(`Failed to shutdown plugin ${plugin.plugin.id} during cleanup`, error, { pluginId: plugin.plugin.id }))), { concurrency: "unbounded" });
|
|
199
|
+
yield* effect.Ref.set(activePlugins, /* @__PURE__ */ new Set());
|
|
200
|
+
}).pipe(effect.Effect.catchAll(() => effect.Effect.void))
|
|
201
|
+
};
|
|
202
|
+
}) }) {};
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/runtime/validation.ts
|
|
206
|
+
const validate = (schema, data, pluginId, stage) => effect.Effect.gen(function* () {
|
|
207
|
+
const result = schema.safeParse(data);
|
|
208
|
+
if (result.success) return result.data;
|
|
209
|
+
return yield* effect.Effect.fail(new ValidationError({
|
|
210
|
+
pluginId,
|
|
211
|
+
stage,
|
|
212
|
+
zodError: result.error
|
|
213
|
+
}));
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/runtime/services/secrets.service.ts
|
|
218
|
+
const configSchema = zod.z.object({ secrets: zod.z.record(zod.z.string(), zod.z.unknown()) }).loose();
|
|
219
|
+
var SecretsConfigTag = class extends effect.Context.Tag("SecretsConfig")() {};
|
|
220
|
+
var SecretsService = class extends effect.Effect.Service()("SecretsService", { effect: effect.Effect.gen(function* () {
|
|
221
|
+
const secrets = yield* SecretsConfigTag;
|
|
222
|
+
return { hydrateSecrets: (config) => effect.Effect.gen(function* () {
|
|
223
|
+
const parseResult = configSchema.parse(config);
|
|
224
|
+
try {
|
|
225
|
+
let hydratedString = JSON.stringify(parseResult);
|
|
226
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
227
|
+
const pattern = new RegExp(`{{${key}}}`, "g");
|
|
228
|
+
hydratedString = hydratedString.replace(pattern, String(value));
|
|
229
|
+
}
|
|
230
|
+
return JSON.parse(hydratedString);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
return yield* effect.Effect.fail(new PluginRuntimeError({
|
|
233
|
+
operation: "hydrate-secrets",
|
|
234
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
235
|
+
retryable: false
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
}) };
|
|
239
|
+
}) }) {};
|
|
240
|
+
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/runtime/services/plugin-loader.service.ts
|
|
243
|
+
var PluginRegistryTag = class extends effect.Context.Tag("PluginRegistry")() {};
|
|
244
|
+
var RegistryService = class extends effect.Effect.Service()("RegistryService", { effect: effect.Effect.gen(function* () {
|
|
245
|
+
const registry = yield* PluginRegistryTag;
|
|
246
|
+
return { get: (pluginId) => effect.Effect.fromNullable(registry[pluginId]).pipe(effect.Effect.mapError(() => new PluginRuntimeError({
|
|
247
|
+
pluginId,
|
|
248
|
+
operation: "validate-plugin-id",
|
|
249
|
+
cause: /* @__PURE__ */ new Error(`Plugin ${pluginId} not found in registry`),
|
|
250
|
+
retryable: false
|
|
251
|
+
}))) };
|
|
252
|
+
}) }) {};
|
|
253
|
+
var PluginLoaderService = class extends effect.Effect.Service()("PluginLoaderService", { effect: effect.Effect.gen(function* () {
|
|
254
|
+
const moduleFederationService = yield* ModuleFederationService;
|
|
255
|
+
const secretsService = yield* SecretsService;
|
|
256
|
+
const registryService = yield* RegistryService;
|
|
257
|
+
const resolveUrl = (baseUrl, version) => version && version !== "latest" ? baseUrl.replace("@latest", `@${version}`) : baseUrl;
|
|
258
|
+
const getMetadata = (pluginId) => registryService.get(pluginId);
|
|
259
|
+
return {
|
|
260
|
+
loadPlugin: (pluginId) => effect.Effect.gen(function* () {
|
|
261
|
+
const metadata = yield* getMetadata(pluginId);
|
|
262
|
+
const url = resolveUrl(metadata.remoteUrl);
|
|
263
|
+
yield* moduleFederationService.registerRemote(pluginId, url).pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error.cause, pluginId, void 0, "register-remote", true)));
|
|
264
|
+
yield* effect.Effect.logDebug("Loading plugin", {
|
|
265
|
+
pluginId,
|
|
266
|
+
url
|
|
267
|
+
});
|
|
268
|
+
return {
|
|
269
|
+
ctor: yield* moduleFederationService.loadRemoteConstructor(pluginId, url).pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error.cause, pluginId, void 0, "load-remote", false))),
|
|
270
|
+
metadata
|
|
271
|
+
};
|
|
272
|
+
}),
|
|
273
|
+
instantiatePlugin: (pluginId, loadedPlugin) => effect.Effect.gen(function* () {
|
|
274
|
+
const instance = yield* effect.Effect.try(() => new loadedPlugin.ctor()).pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, pluginId, void 0, "instantiate-plugin", false)));
|
|
275
|
+
instance.id = pluginId;
|
|
276
|
+
return {
|
|
277
|
+
plugin: instance,
|
|
278
|
+
metadata: loadedPlugin.metadata
|
|
279
|
+
};
|
|
280
|
+
}),
|
|
281
|
+
initializePlugin: (pluginInstance, config) => effect.Effect.gen(function* () {
|
|
282
|
+
const { plugin } = pluginInstance;
|
|
283
|
+
const validatedVariables = yield* validate(plugin.configSchema.variables, config.variables, plugin.id, "config").pipe(effect.Effect.mapError((validationError) => new PluginRuntimeError({
|
|
284
|
+
pluginId: plugin.id,
|
|
285
|
+
operation: "validate-config",
|
|
286
|
+
cause: validationError.zodError,
|
|
287
|
+
retryable: false
|
|
288
|
+
})));
|
|
289
|
+
const validatedSecrets = yield* validate(plugin.configSchema.secrets, config.secrets, plugin.id, "config").pipe(effect.Effect.mapError((validationError) => new PluginRuntimeError({
|
|
290
|
+
pluginId: plugin.id,
|
|
291
|
+
operation: "validate-secrets",
|
|
292
|
+
cause: validationError.zodError,
|
|
293
|
+
retryable: false
|
|
294
|
+
})));
|
|
295
|
+
const hydratedConfig = yield* secretsService.hydrateSecrets({
|
|
296
|
+
variables: validatedVariables,
|
|
297
|
+
secrets: validatedSecrets
|
|
298
|
+
});
|
|
299
|
+
const _variables = yield* validate(plugin.configSchema.variables, hydratedConfig.variables, plugin.id, "config").pipe(effect.Effect.mapError((validationError) => new PluginRuntimeError({
|
|
300
|
+
pluginId: plugin.id,
|
|
301
|
+
operation: "validate-hydrated-config",
|
|
302
|
+
cause: validationError.zodError,
|
|
303
|
+
retryable: false
|
|
304
|
+
})));
|
|
305
|
+
const scope = yield* effect.Scope.make();
|
|
306
|
+
const context = yield* plugin.initialize({
|
|
307
|
+
variables: _variables,
|
|
308
|
+
secrets: hydratedConfig.secrets
|
|
309
|
+
}).pipe(effect.Effect.provideService(effect.Scope.Scope, scope), effect.Effect.mapError((error) => toPluginRuntimeError(error, plugin.id, void 0, "initialize-plugin", false)));
|
|
310
|
+
return {
|
|
311
|
+
plugin,
|
|
312
|
+
metadata: pluginInstance.metadata,
|
|
313
|
+
config: {
|
|
314
|
+
variables: _variables,
|
|
315
|
+
secrets: hydratedConfig.secrets
|
|
316
|
+
},
|
|
317
|
+
context,
|
|
318
|
+
scope
|
|
319
|
+
};
|
|
320
|
+
})
|
|
321
|
+
};
|
|
322
|
+
}) }) {};
|
|
323
|
+
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/runtime/services/plugin.service.ts
|
|
326
|
+
var PluginService = class PluginService extends effect.Effect.Service()("PluginService", { scoped: effect.Effect.gen(function* () {
|
|
327
|
+
const loader = yield* PluginLoaderService;
|
|
328
|
+
const lifecycle = yield* PluginLifecycleService;
|
|
329
|
+
return {
|
|
330
|
+
loadPlugin: loader.loadPlugin,
|
|
331
|
+
instantiatePlugin: loader.instantiatePlugin,
|
|
332
|
+
initializePlugin: loader.initializePlugin,
|
|
333
|
+
shutdownPlugin: (plugin) => effect.Effect.gen(function* () {
|
|
334
|
+
yield* plugin.plugin.shutdown().pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
335
|
+
yield* effect.Scope.close(plugin.scope, effect.Exit.succeed(void 0));
|
|
336
|
+
yield* lifecycle.unregister(plugin);
|
|
337
|
+
}),
|
|
338
|
+
cleanup: lifecycle.cleanup
|
|
339
|
+
};
|
|
340
|
+
}) }) {
|
|
341
|
+
static Live = (registry, secrets) => {
|
|
342
|
+
const contextLayer = effect.Layer.mergeAll(effect.Layer.succeed(PluginRegistryTag, registry), effect.Layer.succeed(SecretsConfigTag, secrets));
|
|
343
|
+
const servicesLayer = effect.Layer.mergeAll(ModuleFederationService.Default, SecretsService.Default, RegistryService.Default, PluginLifecycleService.Default).pipe(effect.Layer.provide(contextLayer));
|
|
344
|
+
return PluginService.Default.pipe(effect.Layer.provide(PluginLoaderService.Default), effect.Layer.provide(servicesLayer));
|
|
345
|
+
};
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/runtime/index.ts
|
|
350
|
+
var PluginRuntime = class {
|
|
351
|
+
pluginCache = /* @__PURE__ */ new Map();
|
|
352
|
+
constructor(runtime, registry) {
|
|
353
|
+
this.runtime = runtime;
|
|
354
|
+
this.registry = registry;
|
|
355
|
+
}
|
|
356
|
+
generateCacheKey(pluginId, config) {
|
|
357
|
+
return `${pluginId}:${effect.Hash.structure(config).toString()}`;
|
|
358
|
+
}
|
|
359
|
+
validatePluginId(pluginId) {
|
|
360
|
+
if (!(pluginId in this.registry)) return effect.Effect.fail(new PluginRuntimeError({
|
|
361
|
+
pluginId: String(pluginId),
|
|
362
|
+
operation: "validate-plugin-id",
|
|
363
|
+
cause: /* @__PURE__ */ new Error(`Plugin ID '${String(pluginId)}' not found in registry.`),
|
|
364
|
+
retryable: false
|
|
365
|
+
}));
|
|
366
|
+
return effect.Effect.succeed(String(pluginId));
|
|
367
|
+
}
|
|
368
|
+
async runPromise(effect$1) {
|
|
369
|
+
const exit = await this.runtime.runPromiseExit(effect$1);
|
|
370
|
+
if (effect.Exit.isFailure(exit)) {
|
|
371
|
+
const error = effect.Cause.failureOption(exit.cause);
|
|
372
|
+
if (effect.Option.isSome(error)) throw error.value;
|
|
373
|
+
throw effect.Cause.squash(exit.cause);
|
|
374
|
+
}
|
|
375
|
+
return exit.value;
|
|
376
|
+
}
|
|
377
|
+
async usePlugin(pluginId, config) {
|
|
378
|
+
const cacheKey = this.generateCacheKey(pluginId, config);
|
|
379
|
+
let cachedPlugin = this.pluginCache.get(cacheKey);
|
|
380
|
+
if (!cachedPlugin) {
|
|
381
|
+
const operation = effect.Effect.gen(this, function* () {
|
|
382
|
+
const pluginService = yield* PluginService;
|
|
383
|
+
const validatedId = yield* this.validatePluginId(pluginId);
|
|
384
|
+
const ctor = yield* pluginService.loadPlugin(validatedId);
|
|
385
|
+
const instance = yield* pluginService.instantiatePlugin(pluginId, ctor);
|
|
386
|
+
return yield* pluginService.initializePlugin(instance, config);
|
|
387
|
+
}).pipe(effect.Effect.provide(this.runtime));
|
|
388
|
+
cachedPlugin = effect.Effect.cached(operation).pipe(effect.Effect.flatten);
|
|
389
|
+
this.pluginCache.set(cacheKey, cachedPlugin);
|
|
390
|
+
}
|
|
391
|
+
const initialized = await this.runPromise(cachedPlugin);
|
|
392
|
+
const router = initialized.plugin.createRouter(initialized.context);
|
|
393
|
+
return {
|
|
394
|
+
router,
|
|
395
|
+
client: (0, __orpc_server.createRouterClient)(router),
|
|
396
|
+
metadata: initialized.metadata,
|
|
397
|
+
initialized
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
async loadPlugin(pluginId) {
|
|
401
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
402
|
+
return yield* (yield* PluginService).loadPlugin(pluginId);
|
|
403
|
+
});
|
|
404
|
+
return this.runPromise(effect$1);
|
|
405
|
+
}
|
|
406
|
+
async instantiatePlugin(pluginId, loadedPlugin) {
|
|
407
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
408
|
+
return yield* (yield* PluginService).instantiatePlugin(pluginId, loadedPlugin);
|
|
409
|
+
});
|
|
410
|
+
return this.runPromise(effect$1);
|
|
411
|
+
}
|
|
412
|
+
async initializePlugin(instance, config) {
|
|
413
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
414
|
+
return yield* (yield* PluginService).initializePlugin(instance, config);
|
|
415
|
+
});
|
|
416
|
+
return this.runPromise(effect$1);
|
|
417
|
+
}
|
|
418
|
+
async shutdown() {
|
|
419
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
420
|
+
yield* (yield* PluginService).cleanup();
|
|
421
|
+
});
|
|
422
|
+
return this.runPromise(effect$1);
|
|
423
|
+
}
|
|
424
|
+
async evictPlugin(pluginId, config) {
|
|
425
|
+
const cacheKey = this.generateCacheKey(pluginId, config);
|
|
426
|
+
const effect$1 = effect.Effect.gen(this, function* () {
|
|
427
|
+
const pluginService = yield* PluginService;
|
|
428
|
+
const cachedPlugin = this.pluginCache.get(cacheKey);
|
|
429
|
+
if (cachedPlugin) {
|
|
430
|
+
this.pluginCache.delete(cacheKey);
|
|
431
|
+
const pluginResult = yield* cachedPlugin.pipe(effect.Effect.catchAll(() => effect.Effect.succeed(null)));
|
|
432
|
+
if (pluginResult) yield* pluginService.shutdownPlugin(pluginResult).pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
433
|
+
}
|
|
434
|
+
}).pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
435
|
+
return this.runPromise(effect$1);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
/**
|
|
439
|
+
* Normalizes a remote URL to ensure it points to remoteEntry.js
|
|
440
|
+
* If the URL doesn't end with a file extension, appends /remoteEntry.js
|
|
441
|
+
*/
|
|
442
|
+
function normalizeRemoteUrl(url) {
|
|
443
|
+
if (url.endsWith(".js")) return url;
|
|
444
|
+
return `${url.endsWith("/") ? url.slice(0, -1) : url}/remoteEntry.js`;
|
|
445
|
+
}
|
|
446
|
+
function createPluginRuntime(config) {
|
|
447
|
+
const secrets = config.secrets || {};
|
|
448
|
+
const normalizedRegistry = Object.fromEntries(Object.entries(config.registry).map(([pluginId, entry]) => [pluginId, {
|
|
449
|
+
...entry,
|
|
450
|
+
remoteUrl: normalizeRemoteUrl(entry.remoteUrl)
|
|
451
|
+
}]));
|
|
452
|
+
const layer = PluginService.Live(normalizedRegistry, secrets);
|
|
453
|
+
return new PluginRuntime(effect.ManagedRuntime.make(layer), normalizedRegistry);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
//#endregion
|
|
457
|
+
Object.defineProperty(exports, 'ModuleFederationError', {
|
|
458
|
+
enumerable: true,
|
|
459
|
+
get: function () {
|
|
460
|
+
return ModuleFederationError;
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
Object.defineProperty(exports, 'ModuleFederationService', {
|
|
464
|
+
enumerable: true,
|
|
465
|
+
get: function () {
|
|
466
|
+
return ModuleFederationService;
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
Object.defineProperty(exports, 'PluginLifecycleService', {
|
|
470
|
+
enumerable: true,
|
|
471
|
+
get: function () {
|
|
472
|
+
return PluginLifecycleService;
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
Object.defineProperty(exports, 'PluginLoaderService', {
|
|
476
|
+
enumerable: true,
|
|
477
|
+
get: function () {
|
|
478
|
+
return PluginLoaderService;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
Object.defineProperty(exports, 'PluginRegistryTag', {
|
|
482
|
+
enumerable: true,
|
|
483
|
+
get: function () {
|
|
484
|
+
return PluginRegistryTag;
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
Object.defineProperty(exports, 'PluginRuntime', {
|
|
488
|
+
enumerable: true,
|
|
489
|
+
get: function () {
|
|
490
|
+
return PluginRuntime;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
Object.defineProperty(exports, 'PluginService', {
|
|
494
|
+
enumerable: true,
|
|
495
|
+
get: function () {
|
|
496
|
+
return PluginService;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
Object.defineProperty(exports, 'RegistryService', {
|
|
500
|
+
enumerable: true,
|
|
501
|
+
get: function () {
|
|
502
|
+
return RegistryService;
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
Object.defineProperty(exports, 'SecretsConfigTag', {
|
|
506
|
+
enumerable: true,
|
|
507
|
+
get: function () {
|
|
508
|
+
return SecretsConfigTag;
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
Object.defineProperty(exports, 'SecretsService', {
|
|
512
|
+
enumerable: true,
|
|
513
|
+
get: function () {
|
|
514
|
+
return SecretsService;
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
Object.defineProperty(exports, 'createPluginRuntime', {
|
|
518
|
+
enumerable: true,
|
|
519
|
+
get: function () {
|
|
520
|
+
return createPluginRuntime;
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS1DZ1JVRXhLMy5janMiLCJuYW1lcyI6WyJEYXRhIiwiT1JQQ0Vycm9yIiwiRWZmZWN0IiwicGtnIiwiZXJyb3IiLCJnZXROb3JtYWxpemVkUmVtb3RlTmFtZSIsIkVmZmVjdCIsIlJlZiIsIkVmZmVjdCIsInoiLCJDb250ZXh0IiwiRWZmZWN0IiwiQ29udGV4dCIsIkVmZmVjdCIsIlNjb3BlIiwiRWZmZWN0IiwiU2NvcGUiLCJFeGl0IiwiTGF5ZXIiLCJydW50aW1lOiBNYW5hZ2VkUnVudGltZS5NYW5hZ2VkUnVudGltZTxQbHVnaW5TZXJ2aWNlLCBuZXZlcj4iLCJyZWdpc3RyeTogUGx1Z2luUmVnaXN0cnkiLCJIYXNoIiwiRWZmZWN0IiwiZWZmZWN0IiwiRXhpdCIsIkNhdXNlIiwiT3B0aW9uIiwiTWFuYWdlZFJ1bnRpbWUiXSwic291cmNlcyI6WyIuLi9zcmMvcnVudGltZS9lcnJvcnMudHMiLCIuLi9zcmMvcnVudGltZS9zZXJ2aWNlcy9tb2R1bGUtZmVkZXJhdGlvbi5zZXJ2aWNlLnRzIiwiLi4vc3JjL3J1bnRpbWUvc2VydmljZXMvcGx1Z2luLWxpZmVjeWNsZS5zZXJ2aWNlLnRzIiwiLi4vc3JjL3J1bnRpbWUvdmFsaWRhdGlvbi50cyIsIi4uL3NyYy9ydW50aW1lL3NlcnZpY2VzL3NlY3JldHMuc2VydmljZS50cyIsIi4uL3NyYy9ydW50aW1lL3NlcnZpY2VzL3BsdWdpbi1sb2FkZXIuc2VydmljZS50cyIsIi4uL3NyYy9ydW50aW1lL3NlcnZpY2VzL3BsdWdpbi5zZXJ2aWNlLnRzIiwiLi4vc3JjL3J1bnRpbWUvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgT1JQQ0Vycm9yIH0gZnJvbSBcIkBvcnBjL2NvbnRyYWN0XCI7XG5pbXBvcnQgeyBEYXRhIH0gZnJvbSBcImVmZmVjdFwiO1xuaW1wb3J0IHR5cGUgeyB6IH0gZnJvbSBcInpvZFwiO1xuXG5leHBvcnQgY2xhc3MgUGx1Z2luUnVudGltZUVycm9yIGV4dGVuZHMgRGF0YS5UYWdnZWRFcnJvcihcIlBsdWdpblJ1bnRpbWVFcnJvclwiKTx7XG5cdHJlYWRvbmx5IHBsdWdpbklkPzogc3RyaW5nO1xuXHRyZWFkb25seSBvcGVyYXRpb24/OiBzdHJpbmc7XG5cdHJlYWRvbmx5IHByb2NlZHVyZU5hbWU/OiBzdHJpbmc7XG5cdHJlYWRvbmx5IGNhdXNlPzogRXJyb3I7XG5cdHJlYWRvbmx5IHJldHJ5YWJsZTogYm9vbGVhbjtcbn0+IHsgfVxuXG5leHBvcnQgY2xhc3MgTW9kdWxlRmVkZXJhdGlvbkVycm9yIGV4dGVuZHMgRGF0YS5UYWdnZWRFcnJvcihcblx0XCJNb2R1bGVGZWRlcmF0aW9uRXJyb3JcIixcbik8e1xuXHRyZWFkb25seSBwbHVnaW5JZDogc3RyaW5nO1xuXHRyZWFkb25seSByZW1vdGVVcmw6IHN0cmluZztcblx0cmVhZG9ubHkgY2F1c2U/OiBFcnJvcjtcbn0+IHsgfVxuXG5leHBvcnQgY2xhc3MgVmFsaWRhdGlvbkVycm9yIGV4dGVuZHMgRGF0YS5UYWdnZWRFcnJvcihcIlZhbGlkYXRpb25FcnJvclwiKTx7XG5cdHJlYWRvbmx5IHBsdWdpbklkOiBzdHJpbmc7XG5cdHJlYWRvbmx5IHN0YWdlOiBcImNvbmZpZ1wiIHwgXCJpbnB1dFwiIHwgXCJvdXRwdXRcIiB8IFwic3RhdGVcIjtcblx0cmVhZG9ubHkgem9kRXJyb3I6IHouWm9kRXJyb3I7XG59PiB7IH1cblxuLy8gSGVscGVyIHRvIGRldGVybWluZSBpZiBhbiBvUlBDIGVycm9yIGNvZGUgaXMgcmV0cnlhYmxlXG5leHBvcnQgY29uc3QgaXNSZXRyeWFibGVPUlBDQ29kZSA9IChjb2RlOiBzdHJpbmcpOiBib29sZWFuID0+IHtcblx0c3dpdGNoIChjb2RlKSB7XG5cdFx0Y2FzZSAnVE9PX01BTllfUkVRVUVTVFMnOlxuXHRcdGNhc2UgJ1NFUlZJQ0VfVU5BVkFJTEFCTEUnOlxuXHRcdGNhc2UgJ0JBRF9HQVRFV0FZJzpcblx0XHRjYXNlICdHQVRFV0FZX1RJTUVPVVQnOlxuXHRcdGNhc2UgJ1RJTUVPVVQnOlxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHJldHVybiBmYWxzZTtcblx0fVxufTtcblxuLy8gQ29udmVydCBPUlBDIGVycm9ycyBmcm9tIHBsdWdpbiBwcm9jZWR1cmVzIHRvIFBsdWdpblJ1bnRpbWVFcnJvclxuZXhwb3J0IGNvbnN0IHdyYXBPUlBDRXJyb3IgPSAoXG5cdG9ycGNFcnJvcjogT1JQQ0Vycm9yPHN0cmluZywgdW5rbm93bj4sXG5cdHBsdWdpbklkPzogc3RyaW5nLFxuXHRwcm9jZWR1cmVOYW1lPzogc3RyaW5nLFxuXHRvcGVyYXRpb24/OiBzdHJpbmdcbik6IFBsdWdpblJ1bnRpbWVFcnJvciA9PiB7XG5cdHJldHVybiBuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRwbHVnaW5JZCxcblx0XHRvcGVyYXRpb24sXG5cdFx0cHJvY2VkdXJlTmFtZSxcblx0XHRyZXRyeWFibGU6IGlzUmV0cnlhYmxlT1JQQ0NvZGUob3JwY0Vycm9yLmNvZGUpLFxuXHRcdGNhdXNlOiBvcnBjRXJyb3IgYXMgRXJyb3Jcblx0fSk7XG59O1xuXG4vLyBVbml2ZXJzYWwgZXJyb3IgY29udmVydGVyIGZvciB0aGUgcnVudGltZVxuZXhwb3J0IGNvbnN0IHRvUGx1Z2luUnVudGltZUVycm9yID0gKFxuXHRlcnJvcjogdW5rbm93bixcblx0cGx1Z2luSWQ/OiBzdHJpbmcsXG5cdHByb2NlZHVyZU5hbWU/OiBzdHJpbmcsXG5cdG9wZXJhdGlvbj86IHN0cmluZyxcblx0ZGVmYXVsdFJldHJ5YWJsZSA9IGZhbHNlXG4pOiBQbHVnaW5SdW50aW1lRXJyb3IgPT4ge1xuXHRpZiAoZXJyb3IgaW5zdGFuY2VvZiBPUlBDRXJyb3IpIHtcblx0XHRyZXR1cm4gd3JhcE9SUENFcnJvcihlcnJvciwgcGx1Z2luSWQsIHByb2NlZHVyZU5hbWUsIG9wZXJhdGlvbik7XG5cdH1cblxuXHRpZiAoZXJyb3IgaW5zdGFuY2VvZiBQbHVnaW5SdW50aW1lRXJyb3IpIHtcblx0XHRyZXR1cm4gZXJyb3I7IC8vIEFscmVhZHkgY29udmVydGVkXG5cdH1cblxuXHRyZXR1cm4gbmV3IFBsdWdpblJ1bnRpbWVFcnJvcih7XG5cdFx0cGx1Z2luSWQsXG5cdFx0b3BlcmF0aW9uLFxuXHRcdHByb2NlZHVyZU5hbWUsXG5cdFx0cmV0cnlhYmxlOiBkZWZhdWx0UmV0cnlhYmxlLFxuXHRcdGNhdXNlOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSlcblx0fSk7XG59O1xuIiwiaW1wb3J0IHsgYmV0dGVyRmV0Y2ggfSBmcm9tIFwiQGJldHRlci1mZXRjaC9mZXRjaFwiO1xuaW1wb3J0IHtcblx0Y3JlYXRlSW5zdGFuY2UsXG5cdGdldEluc3RhbmNlLFxufSBmcm9tIFwiQG1vZHVsZS1mZWRlcmF0aW9uL2VuaGFuY2VkL3J1bnRpbWVcIjtcbmltcG9ydCB7IHNldEdsb2JhbEZlZGVyYXRpb25JbnN0YW5jZSB9IGZyb20gXCJAbW9kdWxlLWZlZGVyYXRpb24vcnVudGltZS1jb3JlXCI7XG5pbXBvcnQgeyBFZmZlY3QgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7IEFueVBsdWdpbiB9IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuaW1wb3J0IHsgTW9kdWxlRmVkZXJhdGlvbkVycm9yIH0gZnJvbSBcIi4uL2Vycm9yc1wiO1xuaW1wb3J0IHsgZ2V0Tm9ybWFsaXplZFJlbW90ZU5hbWUgfSBmcm9tIFwiLi9ub3JtYWxpemVcIjtcblxudHlwZSBSZW1vdGVNb2R1bGUgPSBcbiAgfCAobmV3ICgpID0+IEFueVBsdWdpbilcbiAgfCB7IGRlZmF1bHQ6IG5ldyAoKSA9PiBBbnlQbHVnaW4gfTtcblxuaW1wb3J0IHBrZyBmcm9tIFwiLi4vLi4vLi4vcGFja2FnZS5qc29uXCI7XG5cbmNvbnN0IGNyZWF0ZU1vZHVsZUZlZGVyYXRpb25JbnN0YW5jZSA9IEVmZmVjdC5jYWNoZWQoXG5cdEVmZmVjdC5zeW5jKCgpID0+IHtcblx0XHR0cnkge1xuXHRcdFx0bGV0IGluc3RhbmNlID0gZ2V0SW5zdGFuY2UoKTtcblxuXHRcdFx0aWYgKCFpbnN0YW5jZSkge1xuXHRcdFx0XHRpbnN0YW5jZSA9IGNyZWF0ZUluc3RhbmNlKHtcblx0XHRcdFx0XHRuYW1lOiBcImhvc3RcIixcblx0XHRcdFx0XHRyZW1vdGVzOiBbXSxcblx0XHRcdFx0XHRzaGFyZWQ6IHtcblx0XHRcdFx0XHRcdFwiZXZlcnktcGx1Z2luXCI6IHtcblx0XHRcdFx0XHRcdFx0dmVyc2lvbjogcGtnLnZlcnNpb24sXG5cdFx0XHRcdFx0XHRcdHNoYXJlQ29uZmlnOiB7XG5cdFx0XHRcdFx0XHRcdFx0c2luZ2xldG9uOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHJlcXVpcmVkVmVyc2lvbjogYF4ke3BrZy52ZXJzaW9ufWAsXG5cdFx0XHRcdFx0XHRcdFx0ZWFnZXI6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0c3RyaWN0VmVyc2lvbjogZmFsc2UsIC8vIEFsbG93IGJpZGlyZWN0aW9uYWwgdmVyc2lvbiBjb21wYXRpYmlsaXR5XG5cdFx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0ZWZmZWN0OiB7XG5cdFx0XHRcdFx0XHRcdHZlcnNpb246IHBrZy5kZXBlbmRlbmNpZXMuZWZmZWN0LFxuXHRcdFx0XHRcdFx0XHRzaGFyZUNvbmZpZzoge1xuXHRcdFx0XHRcdFx0XHRcdHNpbmdsZXRvbjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRyZXF1aXJlZFZlcnNpb246IFwiXjMuMTguMFwiLCAvLyBBbGxvdyBhbnkgMy4xOC54IHBhdGNoIHZlcnNpb25cblx0XHRcdFx0XHRcdFx0XHRlYWdlcjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRzdHJpY3RWZXJzaW9uOiBmYWxzZSwgLy8gQWxsb3cgdmVyc2lvbiBmbGV4aWJpbGl0eSBmb3IgY29tcGF0aWJpbGl0eVxuXHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdHpvZDoge1xuXHRcdFx0XHRcdFx0XHR2ZXJzaW9uOiBwa2cuZGVwZW5kZW5jaWVzLnpvZCxcblx0XHRcdFx0XHRcdFx0c2hhcmVDb25maWc6IHtcblx0XHRcdFx0XHRcdFx0XHRzaW5nbGV0b246IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0cmVxdWlyZWRWZXJzaW9uOiBcIl40LjEuMFwiLCAvLyBBbGxvdyBhbnkgNC4xLnggcGF0Y2ggdmVyc2lvblxuXHRcdFx0XHRcdFx0XHRcdGVhZ2VyOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHN0cmljdFZlcnNpb246IGZhbHNlLCAvLyBBbGxvdyB2ZXJzaW9uIGZsZXhpYmlsaXR5IGZvciBjb21wYXRpYmlsaXR5XG5cdFx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XCJAb3JwYy9jb250cmFjdFwiOiB7XG5cdFx0XHRcdFx0XHRcdHZlcnNpb246IHBrZy5kZXBlbmRlbmNpZXNbXCJAb3JwYy9jb250cmFjdFwiXSxcblx0XHRcdFx0XHRcdFx0c2hhcmVDb25maWc6IHtcblx0XHRcdFx0XHRcdFx0XHRzaW5nbGV0b246IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0cmVxdWlyZWRWZXJzaW9uOiBcIl4xLjguMFwiLCAvLyBBbGxvdyBhbnkgMS44LnggcGF0Y2ggdmVyc2lvblxuXHRcdFx0XHRcdFx0XHRcdGVhZ2VyOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHN0cmljdFZlcnNpb246IGZhbHNlLCAvLyBBbGxvdyB2ZXJzaW9uIGZsZXhpYmlsaXR5IGZvciBjb21wYXRpYmlsaXR5XG5cdFx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XCJAb3JwYy9zZXJ2ZXJcIjoge1xuXHRcdFx0XHRcdFx0XHR2ZXJzaW9uOiBwa2cuZGVwZW5kZW5jaWVzW1wiQG9ycGMvc2VydmVyXCJdLFxuXHRcdFx0XHRcdFx0XHRzaGFyZUNvbmZpZzoge1xuXHRcdFx0XHRcdFx0XHRcdHNpbmdsZXRvbjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRyZXF1aXJlZFZlcnNpb246IFwiXjEuOC4wXCIsIC8vIEFsbG93IGFueSAxLjgueCBwYXRjaCB2ZXJzaW9uXG5cdFx0XHRcdFx0XHRcdFx0ZWFnZXI6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0c3RyaWN0VmVyc2lvbjogZmFsc2UsIC8vIEFsbG93IHZlcnNpb24gZmxleGliaWxpdHkgZm9yIGNvbXBhdGliaWxpdHlcblx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9LFxuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHRzZXRHbG9iYWxGZWRlcmF0aW9uSW5zdGFuY2UoaW5zdGFuY2UpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gaW5zdGFuY2U7XG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGluaXRpYWxpemUgTW9kdWxlIEZlZGVyYXRpb246ICR7ZXJyb3J9YCk7XG5cdFx0fVxuXHR9KSxcbik7XG5cbmV4cG9ydCBjbGFzcyBNb2R1bGVGZWRlcmF0aW9uU2VydmljZSBleHRlbmRzIEVmZmVjdC5TZXJ2aWNlPE1vZHVsZUZlZGVyYXRpb25TZXJ2aWNlPigpKFwiTW9kdWxlRmVkZXJhdGlvblNlcnZpY2VcIiwge1xuXHRlZmZlY3Q6IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRjb25zdCBtZiA9IHlpZWxkKiBFZmZlY3QuZmxhdHRlbihjcmVhdGVNb2R1bGVGZWRlcmF0aW9uSW5zdGFuY2UpO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHJlZ2lzdGVyUmVtb3RlOiAocGx1Z2luSWQ6IHN0cmluZywgdXJsOiBzdHJpbmcpID0+XG5cdFx0XHRcdEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRcdFx0XHRjb25zb2xlLmxvZyhgW01GXSBSZWdpc3RlcmluZyAke3BsdWdpbklkfWApO1xuXG5cdFx0XHRcdFx0Ly8gQ2hlY2sgaWYgcmVtb3RlIGlzIGF2YWlsYWJsZVxuXHRcdFx0XHRcdGNvbnN0IHsgZXJyb3IgfSA9IHlpZWxkKiBFZmZlY3QudHJ5UHJvbWlzZSh7XG5cdFx0XHRcdFx0XHR0cnk6ICgpID0+IGJldHRlckZldGNoKHVybCwgeyBtZXRob2Q6IFwiSEVBRFwiIH0pLFxuXHRcdFx0XHRcdFx0Y2F0Y2g6IChlcnJvcik6IE1vZHVsZUZlZGVyYXRpb25FcnJvciA9PlxuXHRcdFx0XHRcdFx0XHRuZXcgTW9kdWxlRmVkZXJhdGlvbkVycm9yKHtcblx0XHRcdFx0XHRcdFx0XHRwbHVnaW5JZCxcblx0XHRcdFx0XHRcdFx0XHRyZW1vdGVVcmw6IHVybCxcblx0XHRcdFx0XHRcdFx0XHRjYXVzZTpcblx0XHRcdFx0XHRcdFx0XHRcdGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRpZiAoZXJyb3IpIHtcblx0XHRcdFx0XHRcdGNvbnNvbGUubG9nKGBbTUZdIOKdjCBSZW1vdGUgbm90IGF2YWlsYWJsZSBmb3IgJHtwbHVnaW5JZH1gKTtcblx0XHRcdFx0XHRcdHJldHVybiB5aWVsZCogRWZmZWN0LmZhaWwoXG5cdFx0XHRcdFx0XHRcdG5ldyBNb2R1bGVGZWRlcmF0aW9uRXJyb3Ioe1xuXHRcdFx0XHRcdFx0XHRcdHBsdWdpbklkLFxuXHRcdFx0XHRcdFx0XHRcdHJlbW90ZVVybDogdXJsLFxuXHRcdFx0XHRcdFx0XHRcdGNhdXNlOiBuZXcgRXJyb3IoYFJlbW90ZSBub3QgYXZhaWxhYmxlICgke3VybH0pOiAke0pTT04uc3RyaW5naWZ5KGVycm9yKX1gKSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGNvbnN0IHJlbW90ZU5hbWUgPSBnZXROb3JtYWxpemVkUmVtb3RlTmFtZShwbHVnaW5JZCk7XG5cblx0XHRcdFx0XHR5aWVsZCogRWZmZWN0LnRyeSh7XG5cdFx0XHRcdFx0XHR0cnk6ICgpID0+IG1mLnJlZ2lzdGVyUmVtb3RlcyhbeyBuYW1lOiByZW1vdGVOYW1lLCBlbnRyeTogdXJsIH1dKSxcblx0XHRcdFx0XHRcdGNhdGNoOiAoZXJyb3IpOiBNb2R1bGVGZWRlcmF0aW9uRXJyb3IgPT5cblx0XHRcdFx0XHRcdFx0bmV3IE1vZHVsZUZlZGVyYXRpb25FcnJvcih7XG5cdFx0XHRcdFx0XHRcdFx0cGx1Z2luSWQsXG5cdFx0XHRcdFx0XHRcdFx0cmVtb3RlVXJsOiB1cmwsXG5cdFx0XHRcdFx0XHRcdFx0Y2F1c2U6XG5cdFx0XHRcdFx0XHRcdFx0XHRlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSksXG5cdFx0XHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdH0pO1xuXG5cdFx0XHRcdFx0Y29uc29sZS5sb2coYFtNRl0g4pyFIFJlZ2lzdGVyZWQgJHtwbHVnaW5JZH1gKTtcblx0XHRcdFx0fSksXG5cblx0XHRcdGxvYWRSZW1vdGVDb25zdHJ1Y3RvcjogKHBsdWdpbklkOiBzdHJpbmcsIHVybDogc3RyaW5nKSA9PlxuXHRcdFx0XHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdFx0Y29uc3QgcmVtb3RlTmFtZSA9IGdldE5vcm1hbGl6ZWRSZW1vdGVOYW1lKHBsdWdpbklkKTtcblx0XHRcdFx0XHRjb25zb2xlLmxvZyhgW01GXSBMb2FkaW5nIHJlbW90ZSAke3JlbW90ZU5hbWV9YCk7XG5cdFx0XHRcdFx0Y29uc3QgbW9kdWxlUGF0aCA9IGAke3JlbW90ZU5hbWV9L3BsdWdpbmA7XG5cblx0XHRcdFx0XHRyZXR1cm4geWllbGQqIEVmZmVjdC50cnlQcm9taXNlKHtcblx0XHRcdFx0XHRcdHRyeTogYXN5bmMgKCkgPT4ge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGNvbnRhaW5lciA9IGF3YWl0IG1mLmxvYWRSZW1vdGU8UmVtb3RlTW9kdWxlPihtb2R1bGVQYXRoKTtcblx0XHRcdFx0XHRcdFx0aWYgKCFjb250YWluZXIpIHtcblx0XHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoYE5vIGNvbnRhaW5lciByZXR1cm5lZCBmb3IgJHttb2R1bGVQYXRofWApO1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydCBtdWx0aXBsZSBleHBvcnQgcGF0dGVybnM6IGRpcmVjdCBmdW5jdGlvbiwgZGVmYXVsdCBleHBvcnQsIG5hbWVkIGV4cG9ydHNcblx0XHRcdFx0XHRcdFx0Y29uc3QgQ29uc3RydWN0b3IgPVxuXHRcdFx0XHRcdFx0XHRcdHR5cGVvZiBjb250YWluZXIgPT09IFwiZnVuY3Rpb25cIlxuXHRcdFx0XHRcdFx0XHRcdFx0PyBjb250YWluZXIgIC8vIERpcmVjdCBmdW5jdGlvbiBleHBvcnRcblx0XHRcdFx0XHRcdFx0XHRcdDogY29udGFpbmVyLmRlZmF1bHRcblx0XHRcdFx0XHRcdFx0XHRcdD8gY29udGFpbmVyLmRlZmF1bHQgIC8vIERlZmF1bHQgZXhwb3J0XG5cdFx0XHRcdFx0XHRcdFx0XHQ6IE9iamVjdC52YWx1ZXMoY29udGFpbmVyKS5maW5kKCAgLy8gTmFtZWQgZXhwb3J0IGZhbGxiYWNrXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0KGV4cCkgPT4gdHlwZW9mIGV4cCA9PT0gXCJmdW5jdGlvblwiICYmIGV4cC5wcm90b3R5cGU/LmNvbnN0cnVjdG9yID09PSBleHBcblx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIUNvbnN0cnVjdG9yIHx8IHR5cGVvZiBDb25zdHJ1Y3RvciAhPT0gXCJmdW5jdGlvblwiKSB7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgY29udGFpbmVySW5mbyA9IHR5cGVvZiBjb250YWluZXIgPT09IFwib2JqZWN0XCJcblx0XHRcdFx0XHRcdFx0XHRcdD8gYEF2YWlsYWJsZSBleHBvcnRzOiAke09iamVjdC5rZXlzKGNvbnRhaW5lcikuam9pbignLCAnKX1gXG5cdFx0XHRcdFx0XHRcdFx0XHQ6IGBDb250YWluZXIgdHlwZTogJHt0eXBlb2YgY29udGFpbmVyfWA7XG5cblx0XHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXG5cdFx0XHRcdFx0XHRcdFx0XHRgTm8gdmFsaWQgcGx1Z2luIGNvbnN0cnVjdG9yIGZvdW5kIGZvciAnJHtwbHVnaW5JZH0nLlxcbmAgK1xuXHRcdFx0XHRcdFx0XHRcdFx0YFN1cHBvcnRlZCBwYXR0ZXJuczpcXG5gICtcblx0XHRcdFx0XHRcdFx0XHRcdGAgIC0gZXhwb3J0IGNvbnN0IFlvdXJQbHVnaW4gPSBjcmVhdGVQbHVnaW4oey4uLn0pXFxuYCArXG5cdFx0XHRcdFx0XHRcdFx0XHRgICAtIGV4cG9ydCBkZWZhdWx0IGNyZWF0ZVBsdWdpbih7Li4ufSlcXG5gICtcblx0XHRcdFx0XHRcdFx0XHRcdGAke2NvbnRhaW5lckluZm99YCxcblx0XHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0Ly8gVmFsaWRhdGUgaXQgbG9va3MgbGlrZSBhIHBsdWdpbiBjb25zdHJ1Y3RvciAoaGFzIGJpbmRpbmcgcHJvcGVydHkpXG5cdFx0XHRcdFx0XHRcdGlmICghKENvbnN0cnVjdG9yIGFzIGFueSkuYmluZGluZykge1xuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IGNvbnRhaW5lckluZm8gPSB0eXBlb2YgY29udGFpbmVyID09PSBcIm9iamVjdFwiXG5cdFx0XHRcdFx0XHRcdFx0XHQ/IGBGb3VuZCBleHBvcnRzOiAke09iamVjdC5rZXlzKGNvbnRhaW5lcikuam9pbignLCAnKX1gXG5cdFx0XHRcdFx0XHRcdFx0XHQ6IGBDb250YWluZXIgdHlwZTogJHt0eXBlb2YgY29udGFpbmVyfWA7XG5cblx0XHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXG5cdFx0XHRcdFx0XHRcdFx0XHRgSW52YWxpZCBwbHVnaW4gY29uc3RydWN0b3IgZm9yICcke3BsdWdpbklkfScuIGAgK1xuXHRcdFx0XHRcdFx0XHRcdFx0YFRoZSBleHBvcnRlZCB2YWx1ZSBtdXN0IGJlIGNyZWF0ZWQgd2l0aCBjcmVhdGVQbHVnaW4oKS4gYCArXG5cdFx0XHRcdFx0XHRcdFx0XHRgRm91bmQgYSBmdW5jdGlvbiBidXQgaXQncyBtaXNzaW5nIHRoZSByZXF1aXJlZCAnYmluZGluZycgcHJvcGVydHkuXFxuYCArXG5cdFx0XHRcdFx0XHRcdFx0XHRgJHtjb250YWluZXJJbmZvfWAsXG5cdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUubG9nKGBbTUZdIOKchSBMb2FkZWQgY29uc3RydWN0b3IgZm9yICR7cGx1Z2luSWR9YCk7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBDb25zdHJ1Y3Rvcjtcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRjYXRjaDogKGVycm9yKTogTW9kdWxlRmVkZXJhdGlvbkVycm9yID0+XG5cdFx0XHRcdFx0XHRcdG5ldyBNb2R1bGVGZWRlcmF0aW9uRXJyb3Ioe1xuXHRcdFx0XHRcdFx0XHRcdHBsdWdpbklkLFxuXHRcdFx0XHRcdFx0XHRcdHJlbW90ZVVybDogdXJsLFxuXHRcdFx0XHRcdFx0XHRcdGNhdXNlOlxuXHRcdFx0XHRcdFx0XHRcdFx0ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpLFxuXHRcdFx0XHRcdFx0XHR9KSxcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fSksXG5cdFx0fTtcblx0fSksXG59KSB7fVxuIiwiaW1wb3J0IHsgRWZmZWN0LCBSZWYgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7IEFueVBsdWdpbiwgSW5pdGlhbGl6ZWRQbHVnaW4gfSBmcm9tIFwiLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IHRvUGx1Z2luUnVudGltZUVycm9yIH0gZnJvbSBcIi4uL2Vycm9yc1wiO1xuXG5leHBvcnQgY2xhc3MgUGx1Z2luTGlmZWN5Y2xlU2VydmljZSBleHRlbmRzIEVmZmVjdC5TZXJ2aWNlPFBsdWdpbkxpZmVjeWNsZVNlcnZpY2U+KCkoXCJQbHVnaW5MaWZlY3ljbGVTZXJ2aWNlXCIsIHtcbiAgZWZmZWN0OiBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgY29uc3QgYWN0aXZlUGx1Z2lucyA9IHlpZWxkKiBSZWYubWFrZShuZXcgU2V0PEluaXRpYWxpemVkUGx1Z2luPEFueVBsdWdpbj4+KCkpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlZ2lzdGVyOiA8VCBleHRlbmRzIEFueVBsdWdpbj4ocGx1Z2luOiBJbml0aWFsaXplZFBsdWdpbjxUPikgPT5cbiAgICAgICAgUmVmLnVwZGF0ZShhY3RpdmVQbHVnaW5zLCBwbHVnaW5zID0+XG4gICAgICAgICAgbmV3IFNldChwbHVnaW5zKS5hZGQocGx1Z2luIGFzIEluaXRpYWxpemVkUGx1Z2luPEFueVBsdWdpbj4pXG4gICAgICAgICksXG5cbiAgICAgIHVucmVnaXN0ZXI6IChwbHVnaW46IEluaXRpYWxpemVkUGx1Z2luPEFueVBsdWdpbj4pID0+XG4gICAgICAgIFJlZi51cGRhdGUoYWN0aXZlUGx1Z2lucywgcGx1Z2lucyA9PiB7XG4gICAgICAgICAgY29uc3QgbmV3U2V0ID0gbmV3IFNldChwbHVnaW5zKTtcbiAgICAgICAgICBuZXdTZXQuZGVsZXRlKHBsdWdpbik7XG4gICAgICAgICAgcmV0dXJuIG5ld1NldDtcbiAgICAgICAgfSksXG5cbiAgICAgIHNodXRkb3duOiAocGx1Z2luOiBJbml0aWFsaXplZFBsdWdpbjxBbnlQbHVnaW4+KSA9PlxuICAgICAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgICAgLy8gUmVtb3ZlIGZyb20gYWN0aXZlIHBsdWdpbnNcbiAgICAgICAgICB5aWVsZCogUmVmLnVwZGF0ZShhY3RpdmVQbHVnaW5zLCBwbHVnaW5zID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5ld1NldCA9IG5ldyBTZXQocGx1Z2lucyk7XG4gICAgICAgICAgICBuZXdTZXQuZGVsZXRlKHBsdWdpbik7XG4gICAgICAgICAgICByZXR1cm4gbmV3U2V0O1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gU2h1dGRvd24gdGhlIHBsdWdpblxuICAgICAgICAgIHlpZWxkKiBwbHVnaW4ucGx1Z2luLnNodXRkb3duKCkucGlwZShcbiAgICAgICAgICAgIEVmZmVjdC5tYXBFcnJvcihlcnJvciA9PlxuICAgICAgICAgICAgICB0b1BsdWdpblJ1bnRpbWVFcnJvcihlcnJvciwgcGx1Z2luLnBsdWdpbi5pZCwgdW5kZWZpbmVkLCBcInNodXRkb3duLXBsdWdpblwiLCBmYWxzZSlcbiAgICAgICAgICAgIClcbiAgICAgICAgICApO1xuICAgICAgICB9KSxcblxuICAgICAgY2xlYW51cDogKCkgPT5cbiAgICAgICAgRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuICAgICAgICAgIGNvbnN0IHBsdWdpbnMgPSB5aWVsZCogUmVmLmdldChhY3RpdmVQbHVnaW5zKTtcblxuICAgICAgICAgIC8vIFNodXRkb3duIGFsbCBhY3RpdmUgcGx1Z2lucyBjb25jdXJyZW50bHlcbiAgICAgICAgICB5aWVsZCogRWZmZWN0LmZvckVhY2goXG4gICAgICAgICAgICBwbHVnaW5zLFxuICAgICAgICAgICAgcGx1Z2luID0+XG4gICAgICAgICAgICAgIHBsdWdpbi5wbHVnaW4uc2h1dGRvd24oKS5waXBlKFxuICAgICAgICAgICAgICAgIEVmZmVjdC5tYXBFcnJvcihlcnJvciA9PlxuICAgICAgICAgICAgICAgICAgdG9QbHVnaW5SdW50aW1lRXJyb3IoZXJyb3IsIHBsdWdpbi5wbHVnaW4uaWQsIHVuZGVmaW5lZCwgXCJjbGVhbnVwLXNodXRkb3duXCIsIGZhbHNlKVxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgRWZmZWN0LmNhdGNoQWxsKGVycm9yID0+XG4gICAgICAgICAgICAgICAgICBFZmZlY3QubG9nRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIGBGYWlsZWQgdG8gc2h1dGRvd24gcGx1Z2luICR7cGx1Z2luLnBsdWdpbi5pZH0gZHVyaW5nIGNsZWFudXBgLFxuICAgICAgICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgICAgICAgeyBwbHVnaW5JZDogcGx1Z2luLnBsdWdpbi5pZCB9XG4gICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgeyBjb25jdXJyZW5jeTogXCJ1bmJvdW5kZWRcIiB9XG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIENsZWFyIHRoZSBhY3RpdmUgcGx1Z2lucyBzZXRcbiAgICAgICAgICB5aWVsZCogUmVmLnNldChhY3RpdmVQbHVnaW5zLCBuZXcgU2V0KCkpO1xuICAgICAgICB9KS5waXBlKFxuICAgICAgICAgIEVmZmVjdC5jYXRjaEFsbCgoKSA9PiBFZmZlY3Qudm9pZCkgLy8gQ29udmVydCBlcnJvcnMgdG8gdm9pZCBmb3IgY2xlYW51cFxuICAgICAgICApLFxuICAgIH07XG4gIH0pLFxufSkgeyB9XG4iLCJpbXBvcnQgeyBFZmZlY3QgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiLi9lcnJvcnNcIjtcblxuZXhwb3J0IGNvbnN0IHZhbGlkYXRlID0gPFQ+KFxuXHRzY2hlbWE6IHouWm9kU2NoZW1hPFQ+LFxuXHRkYXRhOiB1bmtub3duLFxuXHRwbHVnaW5JZDogc3RyaW5nLFxuXHRzdGFnZTogXCJjb25maWdcIiB8IFwiaW5wdXRcIiB8IFwib3V0cHV0XCIgfCBcInN0YXRlXCIsXG4pOiBFZmZlY3QuRWZmZWN0PFQsIFZhbGlkYXRpb25FcnJvcj4gPT5cblx0RWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdGNvbnN0IHJlc3VsdCA9IHNjaGVtYS5zYWZlUGFyc2UoZGF0YSk7XG5cdFx0aWYgKHJlc3VsdC5zdWNjZXNzKSB7XG5cdFx0XHRyZXR1cm4gcmVzdWx0LmRhdGE7XG5cdFx0fVxuXHRcdHJldHVybiB5aWVsZCogRWZmZWN0LmZhaWwoXG5cdFx0XHRuZXcgVmFsaWRhdGlvbkVycm9yKHtcblx0XHRcdFx0cGx1Z2luSWQsXG5cdFx0XHRcdHN0YWdlLFxuXHRcdFx0XHR6b2RFcnJvcjogcmVzdWx0LmVycm9yLFxuXHRcdFx0fSksXG5cdFx0KTtcblx0fSk7XG4iLCJpbXBvcnQgeyBDb250ZXh0LCBFZmZlY3QgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuaW1wb3J0IHR5cGUgeyBTZWNyZXRzQ29uZmlnIH0gZnJvbSBcIi4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBQbHVnaW5SdW50aW1lRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzXCI7XG5cbmNvbnN0IGNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcblx0c2VjcmV0czogei5yZWNvcmQoei5zdHJpbmcoKSwgei51bmtub3duKCkpXG59KS5sb29zZSgpO1xuXG5leHBvcnQgY2xhc3MgU2VjcmV0c0NvbmZpZ1RhZyBleHRlbmRzIENvbnRleHQuVGFnKFwiU2VjcmV0c0NvbmZpZ1wiKTxcblx0U2VjcmV0c0NvbmZpZ1RhZyxcblx0U2VjcmV0c0NvbmZpZ1xuPigpIHsgfVxuXG5leHBvcnQgY2xhc3MgU2VjcmV0c1NlcnZpY2UgZXh0ZW5kcyBFZmZlY3QuU2VydmljZTxTZWNyZXRzU2VydmljZT4oKShcIlNlY3JldHNTZXJ2aWNlXCIsIHtcblx0ZWZmZWN0OiBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0Y29uc3Qgc2VjcmV0cyA9IHlpZWxkKiBTZWNyZXRzQ29uZmlnVGFnO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGh5ZHJhdGVTZWNyZXRzOiA8VD4oY29uZmlnOiBUKSA9PlxuXHRcdFx0XHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdFx0Y29uc3QgcGFyc2VSZXN1bHQgPSBjb25maWdTY2hlbWEucGFyc2UoY29uZmlnKTtcblx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0Y29uc3QgY29uZmlnU3RyaW5nID0gSlNPTi5zdHJpbmdpZnkocGFyc2VSZXN1bHQpO1xuXHRcdFx0XHRcdFx0bGV0IGh5ZHJhdGVkU3RyaW5nID0gY29uZmlnU3RyaW5nO1xuXG5cdFx0XHRcdFx0XHRmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzZWNyZXRzKSkge1xuXHRcdFx0XHRcdFx0XHRjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cChge3ske2tleX19fWAsIFwiZ1wiKTtcblx0XHRcdFx0XHRcdFx0aHlkcmF0ZWRTdHJpbmcgPSBoeWRyYXRlZFN0cmluZy5yZXBsYWNlKHBhdHRlcm4sIFN0cmluZyh2YWx1ZSkpO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gSlNPTi5wYXJzZShoeWRyYXRlZFN0cmluZykgYXMgVDtcblx0XHRcdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHlpZWxkKiBFZmZlY3QuZmFpbChcblx0XHRcdFx0XHRcdFx0bmV3IFBsdWdpblJ1bnRpbWVFcnJvcih7XG5cdFx0XHRcdFx0XHRcdFx0b3BlcmF0aW9uOiBcImh5ZHJhdGUtc2VjcmV0c1wiLFxuXHRcdFx0XHRcdFx0XHRcdGNhdXNlOlxuXHRcdFx0XHRcdFx0XHRcdFx0ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpLFxuXHRcdFx0XHRcdFx0XHRcdHJldHJ5YWJsZTogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pLFxuXHRcdH07XG5cdH0pLFxufSkgeyB9XG4iLCJpbXBvcnQgdHlwZSB7IEluZmVyU2NoZW1hSW5wdXQsIEluZmVyU2NoZW1hT3V0cHV0IH0gZnJvbSBcIkBvcnBjL2NvbnRyYWN0XCI7XG5pbXBvcnQgeyBDb250ZXh0LCBFZmZlY3QsIFNjb3BlIH0gZnJvbSBcImVmZmVjdFwiO1xuaW1wb3J0IHR5cGUgeyB6IH0gZnJvbSBcInpvZFwiO1xuaW1wb3J0IHR5cGUge1xuXHRBbnlQbHVnaW4sXG5cdEluaXRpYWxpemVkUGx1Z2luLFxuXHRMb2FkZWRQbHVnaW4sXG5cdFBsdWdpbkluc3RhbmNlLFxuXHRQbHVnaW5SZWdpc3RyeVxufSBmcm9tIFwiLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IFBsdWdpblJ1bnRpbWVFcnJvciwgdG9QbHVnaW5SdW50aW1lRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzXCI7XG5pbXBvcnQgeyB2YWxpZGF0ZSB9IGZyb20gXCIuLi92YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBNb2R1bGVGZWRlcmF0aW9uU2VydmljZSB9IGZyb20gXCIuL21vZHVsZS1mZWRlcmF0aW9uLnNlcnZpY2VcIjtcbmltcG9ydCB7IFNlY3JldHNTZXJ2aWNlIH0gZnJvbSBcIi4vc2VjcmV0cy5zZXJ2aWNlXCI7XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5SZWdpc3RyeVRhZyBleHRlbmRzIENvbnRleHQuVGFnKFwiUGx1Z2luUmVnaXN0cnlcIik8XG5cdFBsdWdpblJlZ2lzdHJ5VGFnLFxuXHRQbHVnaW5SZWdpc3RyeVxuPigpIHsgfVxuXG5leHBvcnQgY2xhc3MgUmVnaXN0cnlTZXJ2aWNlIGV4dGVuZHMgRWZmZWN0LlNlcnZpY2U8UmVnaXN0cnlTZXJ2aWNlPigpKFwiUmVnaXN0cnlTZXJ2aWNlXCIsIHtcblx0ZWZmZWN0OiBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0Y29uc3QgcmVnaXN0cnkgPSB5aWVsZCogUGx1Z2luUmVnaXN0cnlUYWc7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0Z2V0OiAocGx1Z2luSWQ6IHN0cmluZykgPT5cblx0XHRcdFx0RWZmZWN0LmZyb21OdWxsYWJsZShyZWdpc3RyeVtwbHVnaW5JZF0pLnBpcGUoXG5cdFx0XHRcdFx0RWZmZWN0Lm1hcEVycm9yKCgpID0+XG5cdFx0XHRcdFx0XHRuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRcdFx0XHRcdFx0cGx1Z2luSWQsXG5cdFx0XHRcdFx0XHRcdG9wZXJhdGlvbjogXCJ2YWxpZGF0ZS1wbHVnaW4taWRcIixcblx0XHRcdFx0XHRcdFx0Y2F1c2U6IG5ldyBFcnJvcihgUGx1Z2luICR7cGx1Z2luSWR9IG5vdCBmb3VuZCBpbiByZWdpc3RyeWApLFxuXHRcdFx0XHRcdFx0XHRyZXRyeWFibGU6IGZhbHNlLFxuXHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0KSxcblx0XHRcdFx0KSxcblx0XHR9O1xuXHR9KSxcbn0pIHsgfVxuXG5leHBvcnQgY2xhc3MgUGx1Z2luTG9hZGVyU2VydmljZSBleHRlbmRzIEVmZmVjdC5TZXJ2aWNlPFBsdWdpbkxvYWRlclNlcnZpY2U+KCkoXCJQbHVnaW5Mb2FkZXJTZXJ2aWNlXCIsIHtcblx0ZWZmZWN0OiBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0Y29uc3QgbW9kdWxlRmVkZXJhdGlvblNlcnZpY2UgPSB5aWVsZCogTW9kdWxlRmVkZXJhdGlvblNlcnZpY2U7XG5cdFx0Y29uc3Qgc2VjcmV0c1NlcnZpY2UgPSB5aWVsZCogU2VjcmV0c1NlcnZpY2U7XG5cdFx0Y29uc3QgcmVnaXN0cnlTZXJ2aWNlID0geWllbGQqIFJlZ2lzdHJ5U2VydmljZTtcblxuXHRcdGNvbnN0IHJlc29sdmVVcmwgPSAoYmFzZVVybDogc3RyaW5nLCB2ZXJzaW9uPzogc3RyaW5nKTogc3RyaW5nID0+XG5cdFx0XHR2ZXJzaW9uICYmIHZlcnNpb24gIT09IFwibGF0ZXN0XCJcblx0XHRcdFx0PyBiYXNlVXJsLnJlcGxhY2UoXCJAbGF0ZXN0XCIsIGBAJHt2ZXJzaW9ufWApXG5cdFx0XHRcdDogYmFzZVVybDtcblxuXHRcdGNvbnN0IGdldE1ldGFkYXRhID0gKHBsdWdpbklkOiBzdHJpbmcpID0+IHJlZ2lzdHJ5U2VydmljZS5nZXQocGx1Z2luSWQpO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGxvYWRQbHVnaW46IChwbHVnaW5JZDogc3RyaW5nKSA9PlxuXHRcdFx0XHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdFx0Y29uc3QgbWV0YWRhdGEgPSB5aWVsZCogZ2V0TWV0YWRhdGEocGx1Z2luSWQpO1xuXHRcdFx0XHRcdGNvbnN0IHVybCA9IHJlc29sdmVVcmwobWV0YWRhdGEucmVtb3RlVXJsKTtcblxuXHRcdFx0XHRcdHlpZWxkKiBtb2R1bGVGZWRlcmF0aW9uU2VydmljZS5yZWdpc3RlclJlbW90ZShwbHVnaW5JZCwgdXJsKS5waXBlKFxuXHRcdFx0XHRcdFx0RWZmZWN0Lm1hcEVycm9yKChlcnJvcikgPT5cblx0XHRcdFx0XHRcdFx0dG9QbHVnaW5SdW50aW1lRXJyb3IoZXJyb3IuY2F1c2UsIHBsdWdpbklkLCB1bmRlZmluZWQsIFwicmVnaXN0ZXItcmVtb3RlXCIsIHRydWUpLFxuXHRcdFx0XHRcdFx0KSxcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0eWllbGQqIEVmZmVjdC5sb2dEZWJ1ZyhcIkxvYWRpbmcgcGx1Z2luXCIsIHsgcGx1Z2luSWQsIHVybCB9KTtcblxuXHRcdFx0XHRcdGNvbnN0IGN0b3IgPSB5aWVsZCogbW9kdWxlRmVkZXJhdGlvblNlcnZpY2UubG9hZFJlbW90ZUNvbnN0cnVjdG9yKHBsdWdpbklkLCB1cmwpLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QubWFwRXJyb3IoKGVycm9yKSA9PlxuXHRcdFx0XHRcdFx0XHR0b1BsdWdpblJ1bnRpbWVFcnJvcihlcnJvci5jYXVzZSwgcGx1Z2luSWQsIHVuZGVmaW5lZCwgXCJsb2FkLXJlbW90ZVwiLCBmYWxzZSksXG5cdFx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0Y3Rvcixcblx0XHRcdFx0XHRcdG1ldGFkYXRhOiBtZXRhZGF0YSxcblx0XHRcdFx0XHR9IHNhdGlzZmllcyBMb2FkZWRQbHVnaW47XG5cdFx0XHRcdH0pLFxuXG5cdFx0XHRpbnN0YW50aWF0ZVBsdWdpbjogPFQgZXh0ZW5kcyBBbnlQbHVnaW4+KFxuXHRcdFx0XHRwbHVnaW5JZDogc3RyaW5nLFxuXHRcdFx0XHRsb2FkZWRQbHVnaW46IExvYWRlZFBsdWdpbjxUPixcblx0XHRcdCkgPT5cblx0XHRcdFx0RWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0XHRcdGNvbnN0IGluc3RhbmNlID0geWllbGQqIEVmZmVjdC50cnkoKCkgPT4gbmV3IGxvYWRlZFBsdWdpbi5jdG9yKCkpLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QubWFwRXJyb3IoKGVycm9yKSA9PlxuXHRcdFx0XHRcdFx0XHR0b1BsdWdpblJ1bnRpbWVFcnJvcihcblx0XHRcdFx0XHRcdFx0XHRlcnJvcixcblx0XHRcdFx0XHRcdFx0XHRwbHVnaW5JZCxcblx0XHRcdFx0XHRcdFx0XHR1bmRlZmluZWQsXG5cdFx0XHRcdFx0XHRcdFx0XCJpbnN0YW50aWF0ZS1wbHVnaW5cIixcblx0XHRcdFx0XHRcdFx0XHRmYWxzZSxcblx0XHRcdFx0XHRcdFx0KSxcblx0XHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdChpbnN0YW5jZS5pZCBhcyBzdHJpbmcpID0gcGx1Z2luSWQ7XG5cblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0cGx1Z2luOiBpbnN0YW5jZSxcblx0XHRcdFx0XHRcdG1ldGFkYXRhOiBsb2FkZWRQbHVnaW4ubWV0YWRhdGEsXG5cdFx0XHRcdFx0fSBzYXRpc2ZpZXMgUGx1Z2luSW5zdGFuY2U8VD47XG5cdFx0XHRcdH0pLFxuXG5cdFx0XHRpbml0aWFsaXplUGx1Z2luOiA8VCBleHRlbmRzIEFueVBsdWdpbj4oXG5cdFx0XHRcdHBsdWdpbkluc3RhbmNlOiBQbHVnaW5JbnN0YW5jZTxUPixcblx0XHRcdFx0Y29uZmlnOiB7IHZhcmlhYmxlczogSW5mZXJTY2hlbWFJbnB1dDxUW1wiY29uZmlnU2NoZW1hXCJdW1widmFyaWFibGVzXCJdPjsgc2VjcmV0czogSW5mZXJTY2hlbWFJbnB1dDxUW1wiY29uZmlnU2NoZW1hXCJdW1wic2VjcmV0c1wiXT4gfSxcblx0XHRcdCkgPT5cblx0XHRcdFx0RWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0XHRcdGNvbnN0IHsgcGx1Z2luIH0gPSBwbHVnaW5JbnN0YW5jZTtcblxuXHRcdFx0XHRcdC8vIFZhbGlkYXRlIGFuZCBoeWRyYXRlIGNvbmZpZ1xuXHRcdFx0XHRcdGNvbnN0IHZhbGlkYXRlZFZhcmlhYmxlcyA9IHlpZWxkKiB2YWxpZGF0ZShcblx0XHRcdFx0XHRcdHBsdWdpbi5jb25maWdTY2hlbWEudmFyaWFibGVzIGFzIHouWm9kU2NoZW1hPEluZmVyU2NoZW1hT3V0cHV0PFRbXCJjb25maWdTY2hlbWFcIl1bXCJ2YXJpYWJsZXNcIl0+Pixcblx0XHRcdFx0XHRcdGNvbmZpZy52YXJpYWJsZXMsXG5cdFx0XHRcdFx0XHRwbHVnaW4uaWQsXG5cdFx0XHRcdFx0XHRcImNvbmZpZ1wiLFxuXHRcdFx0XHRcdCkucGlwZShcblx0XHRcdFx0XHRcdEVmZmVjdC5tYXBFcnJvcigodmFsaWRhdGlvbkVycm9yKSA9PlxuXHRcdFx0XHRcdFx0XHRuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRcdFx0XHRcdFx0XHRwbHVnaW5JZDogcGx1Z2luLmlkLFxuXHRcdFx0XHRcdFx0XHRcdG9wZXJhdGlvbjogXCJ2YWxpZGF0ZS1jb25maWdcIixcblx0XHRcdFx0XHRcdFx0XHRjYXVzZTogdmFsaWRhdGlvbkVycm9yLnpvZEVycm9yLFxuXHRcdFx0XHRcdFx0XHRcdHJldHJ5YWJsZTogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdFx0KSxcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0Ly8gVmFsaWRhdGUgc2VjcmV0c1xuXHRcdFx0XHRcdGNvbnN0IHZhbGlkYXRlZFNlY3JldHMgPSB5aWVsZCogdmFsaWRhdGUoXG5cdFx0XHRcdFx0XHRwbHVnaW4uY29uZmlnU2NoZW1hLnNlY3JldHMgYXMgei5ab2RTY2hlbWE8SW5mZXJTY2hlbWFPdXRwdXQ8VFtcImNvbmZpZ1NjaGVtYVwiXVtcInNlY3JldHNcIl0+Pixcblx0XHRcdFx0XHRcdGNvbmZpZy5zZWNyZXRzLFxuXHRcdFx0XHRcdFx0cGx1Z2luLmlkLFxuXHRcdFx0XHRcdFx0XCJjb25maWdcIixcblx0XHRcdFx0XHQpLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QubWFwRXJyb3IoKHZhbGlkYXRpb25FcnJvcikgPT5cblx0XHRcdFx0XHRcdFx0bmV3IFBsdWdpblJ1bnRpbWVFcnJvcih7XG5cdFx0XHRcdFx0XHRcdFx0cGx1Z2luSWQ6IHBsdWdpbi5pZCxcblx0XHRcdFx0XHRcdFx0XHRvcGVyYXRpb246IFwidmFsaWRhdGUtc2VjcmV0c1wiLFxuXHRcdFx0XHRcdFx0XHRcdGNhdXNlOiB2YWxpZGF0aW9uRXJyb3Iuem9kRXJyb3IsXG5cdFx0XHRcdFx0XHRcdFx0cmV0cnlhYmxlOiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHQvLyBIeWRyYXRlIHNlY3JldHMgaW4gdmFyaWFibGVzXG5cdFx0XHRcdFx0Y29uc3QgaHlkcmF0ZWRDb25maWcgPSB5aWVsZCogc2VjcmV0c1NlcnZpY2UuaHlkcmF0ZVNlY3JldHMoe1xuXHRcdFx0XHRcdFx0dmFyaWFibGVzOiB2YWxpZGF0ZWRWYXJpYWJsZXMsXG5cdFx0XHRcdFx0XHRzZWNyZXRzOiB2YWxpZGF0ZWRTZWNyZXRzLFxuXHRcdFx0XHRcdH0pO1xuXG5cdFx0XHRcdFx0Y29uc3QgX3ZhcmlhYmxlcyA9IHlpZWxkKiB2YWxpZGF0ZShcblx0XHRcdFx0XHRcdHBsdWdpbi5jb25maWdTY2hlbWEudmFyaWFibGVzIGFzIHouWm9kU2NoZW1hPEluZmVyU2NoZW1hT3V0cHV0PFRbXCJjb25maWdTY2hlbWFcIl1bXCJ2YXJpYWJsZXNcIl0+Pixcblx0XHRcdFx0XHRcdGh5ZHJhdGVkQ29uZmlnLnZhcmlhYmxlcyxcblx0XHRcdFx0XHRcdHBsdWdpbi5pZCxcblx0XHRcdFx0XHRcdFwiY29uZmlnXCIsXG5cdFx0XHRcdFx0KS5waXBlKFxuXHRcdFx0XHRcdFx0RWZmZWN0Lm1hcEVycm9yKCh2YWxpZGF0aW9uRXJyb3IpID0+XG5cdFx0XHRcdFx0XHRcdG5ldyBQbHVnaW5SdW50aW1lRXJyb3Ioe1xuXHRcdFx0XHRcdFx0XHRcdHBsdWdpbklkOiBwbHVnaW4uaWQsXG5cdFx0XHRcdFx0XHRcdFx0b3BlcmF0aW9uOiBcInZhbGlkYXRlLWh5ZHJhdGVkLWNvbmZpZ1wiLFxuXHRcdFx0XHRcdFx0XHRcdGNhdXNlOiB2YWxpZGF0aW9uRXJyb3Iuem9kRXJyb3IsXG5cdFx0XHRcdFx0XHRcdFx0cmV0cnlhYmxlOiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHQvLyBDcmVhdGUgYSBsb25nLWxpdmVkIHNjb3BlIGZvciB0aGlzIHBsdWdpbiBpbnN0YW5jZVxuXHRcdFx0XHRcdGNvbnN0IHNjb3BlID0geWllbGQqIFNjb3BlLm1ha2UoKTtcblxuXHRcdFx0XHRcdC8vIEluaXRpYWxpemUgcGx1Z2luIHdpdGhpbiB0aGUgc2NvcGVcblx0XHRcdFx0XHRjb25zdCBjb250ZXh0ID0geWllbGQqIHBsdWdpbi5pbml0aWFsaXplKHsgdmFyaWFibGVzOiBfdmFyaWFibGVzLCBzZWNyZXRzOiBoeWRyYXRlZENvbmZpZy5zZWNyZXRzIH0pLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QucHJvdmlkZVNlcnZpY2UoU2NvcGUuU2NvcGUsIHNjb3BlKSxcblx0XHRcdFx0XHRcdEVmZmVjdC5tYXBFcnJvcigoZXJyb3IpID0+XG5cdFx0XHRcdFx0XHRcdHRvUGx1Z2luUnVudGltZUVycm9yKGVycm9yLCBwbHVnaW4uaWQsIHVuZGVmaW5lZCwgXCJpbml0aWFsaXplLXBsdWdpblwiLCBmYWxzZSksXG5cdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XHRwbHVnaW4sXG5cdFx0XHRcdFx0XHRtZXRhZGF0YTogcGx1Z2luSW5zdGFuY2UubWV0YWRhdGEsXG5cdFx0XHRcdFx0XHRjb25maWc6IHsgdmFyaWFibGVzOiBfdmFyaWFibGVzLCBzZWNyZXRzOiBoeWRyYXRlZENvbmZpZy5zZWNyZXRzIH0sXG5cdFx0XHRcdFx0XHRjb250ZXh0LFxuXHRcdFx0XHRcdFx0c2NvcGUsXG5cdFx0XHRcdFx0fSBzYXRpc2ZpZXMgSW5pdGlhbGl6ZWRQbHVnaW48VD47XG5cdFx0XHRcdH0pLFxuXHRcdH07XG5cdH0pLFxufSkge1xufVxuIiwiaW1wb3J0IHsgRWZmZWN0LCBFeGl0LCBMYXllciwgU2NvcGUgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7XG5cdEFueVBsdWdpbixcblx0SW5pdGlhbGl6ZWRQbHVnaW4sXG5cdFBsdWdpblJlZ2lzdHJ5LFxuXHRTZWNyZXRzQ29uZmlnXG59IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuaW1wb3J0IHsgTW9kdWxlRmVkZXJhdGlvblNlcnZpY2UgfSBmcm9tIFwiLi9tb2R1bGUtZmVkZXJhdGlvbi5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBQbHVnaW5MaWZlY3ljbGVTZXJ2aWNlIH0gZnJvbSBcIi4vcGx1Z2luLWxpZmVjeWNsZS5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBQbHVnaW5Mb2FkZXJTZXJ2aWNlLCBQbHVnaW5SZWdpc3RyeVRhZywgUmVnaXN0cnlTZXJ2aWNlIH0gZnJvbSBcIi4vcGx1Z2luLWxvYWRlci5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBTZWNyZXRzQ29uZmlnVGFnLCBTZWNyZXRzU2VydmljZSB9IGZyb20gXCIuL3NlY3JldHMuc2VydmljZVwiO1xuXG5leHBvcnQgY2xhc3MgUGx1Z2luU2VydmljZSBleHRlbmRzIEVmZmVjdC5TZXJ2aWNlPFBsdWdpblNlcnZpY2U+KCkoXCJQbHVnaW5TZXJ2aWNlXCIsIHtcblx0c2NvcGVkOiBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0Y29uc3QgbG9hZGVyID0geWllbGQqIFBsdWdpbkxvYWRlclNlcnZpY2U7XG5cdFx0Y29uc3QgbGlmZWN5Y2xlID0geWllbGQqIFBsdWdpbkxpZmVjeWNsZVNlcnZpY2U7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0bG9hZFBsdWdpbjogbG9hZGVyLmxvYWRQbHVnaW4sXG5cdFx0XHRpbnN0YW50aWF0ZVBsdWdpbjogbG9hZGVyLmluc3RhbnRpYXRlUGx1Z2luLFxuXHRcdFx0aW5pdGlhbGl6ZVBsdWdpbjogbG9hZGVyLmluaXRpYWxpemVQbHVnaW4sXG5cdFx0XHRzaHV0ZG93blBsdWdpbjogKHBsdWdpbjogSW5pdGlhbGl6ZWRQbHVnaW48QW55UGx1Z2luPikgPT5cblx0XHRcdFx0RWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0XHRcdC8vIFNodXRkb3duIHRoZSBwbHVnaW4gZmlyc3QgKGdyYWNlZnVsIGNsZWFudXApXG5cdFx0XHRcdFx0eWllbGQqIHBsdWdpbi5wbHVnaW4uc2h1dGRvd24oKS5waXBlKFxuXHRcdFx0XHRcdFx0RWZmZWN0LmNhdGNoQWxsKCgpID0+IEVmZmVjdC52b2lkKVxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHQvLyBDbG9zZSB0aGUgcGx1Z2luIHNjb3BlIHRvIGludGVycnVwdCBmaWJlcnMgYW5kIHJlbGVhc2UgcmVzb3VyY2VzXG5cdFx0XHRcdFx0eWllbGQqIFNjb3BlLmNsb3NlKHBsdWdpbi5zY29wZSwgRXhpdC5zdWNjZWVkKHVuZGVmaW5lZCkpO1xuXG5cdFx0XHRcdFx0Ly8gVW5yZWdpc3RlciBmcm9tIGxpZmVjeWNsZSB0cmFja2luZ1xuXHRcdFx0XHRcdHlpZWxkKiBsaWZlY3ljbGUudW5yZWdpc3RlcihwbHVnaW4pO1xuXHRcdFx0XHR9KSxcblx0XHRcdGNsZWFudXA6IGxpZmVjeWNsZS5jbGVhbnVwLFxuXHRcdH07XG5cdH0pLFxufSkge1xuXHRzdGF0aWMgTGl2ZSA9IChyZWdpc3RyeTogUGx1Z2luUmVnaXN0cnksIHNlY3JldHM6IFNlY3JldHNDb25maWcpID0+IHtcblx0XHRjb25zdCBjb250ZXh0TGF5ZXIgPSBMYXllci5tZXJnZUFsbChcblx0XHRcdExheWVyLnN1Y2NlZWQoUGx1Z2luUmVnaXN0cnlUYWcsIHJlZ2lzdHJ5KSxcblx0XHRcdExheWVyLnN1Y2NlZWQoU2VjcmV0c0NvbmZpZ1RhZywgc2VjcmV0cyksXG5cdFx0KTtcblxuXHRcdGNvbnN0IHNlcnZpY2VzTGF5ZXIgPSBMYXllci5tZXJnZUFsbChcblx0XHRcdE1vZHVsZUZlZGVyYXRpb25TZXJ2aWNlLkRlZmF1bHQsXG5cdFx0XHRTZWNyZXRzU2VydmljZS5EZWZhdWx0LFxuXHRcdFx0UmVnaXN0cnlTZXJ2aWNlLkRlZmF1bHQsXG5cdFx0XHRQbHVnaW5MaWZlY3ljbGVTZXJ2aWNlLkRlZmF1bHQsXG5cdFx0KS5waXBlKFxuXHRcdFx0TGF5ZXIucHJvdmlkZShjb250ZXh0TGF5ZXIpXG5cdFx0KTtcblxuXHRcdHJldHVybiBQbHVnaW5TZXJ2aWNlLkRlZmF1bHQucGlwZShcblx0XHRcdExheWVyLnByb3ZpZGUoUGx1Z2luTG9hZGVyU2VydmljZS5EZWZhdWx0KSxcblx0XHRcdExheWVyLnByb3ZpZGUoc2VydmljZXNMYXllcilcblx0XHQpO1xuXHR9XG59XG4iLCJpbXBvcnQgeyBjcmVhdGVSb3V0ZXJDbGllbnQgfSBmcm9tIFwiQG9ycGMvc2VydmVyXCI7XG5pbXBvcnQgeyBDYXVzZSwgRWZmZWN0LCBFeGl0LCBIYXNoLCBNYW5hZ2VkUnVudGltZSwgT3B0aW9uIH0gZnJvbSBcImVmZmVjdFwiO1xuaW1wb3J0IHR5cGUge1xuXHRBbnlQbHVnaW4sXG5cdEluaXRpYWxpemVkUGx1Z2luLFxuXHRMb2FkZWRQbHVnaW4sXG5cdFBsdWdpbkNsaWVudFR5cGUsXG5cdFBsdWdpbkNvbmZpZ0lucHV0LFxuXHRQbHVnaW5JbnN0YW5jZSxcblx0UGx1Z2luUmVnaXN0cnksXG5cdFBsdWdpblJvdXRlclR5cGUsXG5cdFBsdWdpblJ1bnRpbWVDb25maWcsXG5cdFJlZ2lzdGVyZWRQbHVnaW4sXG5cdFJlZ2lzdGVyZWRQbHVnaW5zLFxuXHRVc2VQbHVnaW5SZXN1bHRcbn0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBQbHVnaW5SdW50aW1lRXJyb3IgfSBmcm9tIFwiLi9lcnJvcnNcIjtcbmltcG9ydCB7IFBsdWdpblNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9wbHVnaW4uc2VydmljZVwiO1xuXG5leHBvcnQgY2xhc3MgUGx1Z2luUnVudGltZTxSIGV4dGVuZHMgUmVnaXN0ZXJlZFBsdWdpbnMgPSBSZWdpc3RlcmVkUGx1Z2lucz4ge1xuXHRwcml2YXRlIHBsdWdpbkNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIEVmZmVjdC5FZmZlY3Q8SW5pdGlhbGl6ZWRQbHVnaW48QW55UGx1Z2luPiwgUGx1Z2luUnVudGltZUVycm9yPj4oKTtcblxuXHRjb25zdHJ1Y3Rvcihcblx0XHRwcml2YXRlIHJ1bnRpbWU6IE1hbmFnZWRSdW50aW1lLk1hbmFnZWRSdW50aW1lPFBsdWdpblNlcnZpY2UsIG5ldmVyPixcblx0XHRwcml2YXRlIHJlZ2lzdHJ5OiBQbHVnaW5SZWdpc3RyeVxuXHQpIHsgfVxuXG5cdHByaXZhdGUgZ2VuZXJhdGVDYWNoZUtleShwbHVnaW5JZDogc3RyaW5nLCBjb25maWc6IHVua25vd24pOiBzdHJpbmcge1xuXHRcdGNvbnN0IGNvbmZpZ0hhc2ggPSBIYXNoLnN0cnVjdHVyZShjb25maWcgYXMgb2JqZWN0KS50b1N0cmluZygpO1xuXHRcdHJldHVybiBgJHtwbHVnaW5JZH06JHtjb25maWdIYXNofWA7XG5cdH1cblxuXHRwcml2YXRlIHZhbGlkYXRlUGx1Z2luSWQoXG5cdFx0cGx1Z2luSWQ6IHN0cmluZ1xuXHQpOiBFZmZlY3QuRWZmZWN0PHN0cmluZywgUGx1Z2luUnVudGltZUVycm9yPiB7XG5cdFx0aWYgKCEocGx1Z2luSWQgaW4gdGhpcy5yZWdpc3RyeSkpIHtcblx0XHRcdHJldHVybiBFZmZlY3QuZmFpbChuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRcdFx0cGx1Z2luSWQ6IFN0cmluZyhwbHVnaW5JZCksXG5cdFx0XHRcdG9wZXJhdGlvbjogXCJ2YWxpZGF0ZS1wbHVnaW4taWRcIixcblx0XHRcdFx0Y2F1c2U6IG5ldyBFcnJvcihgUGx1Z2luIElEICcke1N0cmluZyhwbHVnaW5JZCl9JyBub3QgZm91bmQgaW4gcmVnaXN0cnkuYCksXG5cdFx0XHRcdHJldHJ5YWJsZTogZmFsc2UsXG5cdFx0XHR9KSk7XG5cdFx0fVxuXHRcdHJldHVybiBFZmZlY3Quc3VjY2VlZChTdHJpbmcocGx1Z2luSWQpKTtcblx0fVxuXG5cdHByaXZhdGUgYXN5bmMgcnVuUHJvbWlzZTxBLCBFPihcblx0XHRlZmZlY3Q6IEVmZmVjdC5FZmZlY3Q8QSwgRSwgUGx1Z2luU2VydmljZT5cblx0KTogUHJvbWlzZTxBPiB7XG5cdFx0Y29uc3QgZXhpdCA9IGF3YWl0IHRoaXMucnVudGltZS5ydW5Qcm9taXNlRXhpdChlZmZlY3QpO1xuXG5cdFx0aWYgKEV4aXQuaXNGYWlsdXJlKGV4aXQpKSB7XG5cdFx0XHRjb25zdCBlcnJvciA9IENhdXNlLmZhaWx1cmVPcHRpb24oZXhpdC5jYXVzZSk7XG5cdFx0XHRpZiAoT3B0aW9uLmlzU29tZShlcnJvcikpIHtcblx0XHRcdFx0dGhyb3cgZXJyb3IudmFsdWU7XG5cdFx0XHR9XG5cdFx0XHR0aHJvdyBDYXVzZS5zcXVhc2goZXhpdC5jYXVzZSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV4aXQudmFsdWU7XG5cdH1cblxuXHRhc3luYyB1c2VQbHVnaW48SyBleHRlbmRzIGtleW9mIFJlZ2lzdGVyZWRQbHVnaW5zICYgc3RyaW5nPihcblx0XHRwbHVnaW5JZDogSyxcblx0XHRjb25maWc6IFBsdWdpbkNvbmZpZ0lucHV0PFJbS10+XG5cdCk6IFByb21pc2U8VXNlUGx1Z2luUmVzdWx0PEs+PiB7XG5cdFx0Y29uc3QgY2FjaGVLZXkgPSB0aGlzLmdlbmVyYXRlQ2FjaGVLZXkocGx1Z2luSWQsIGNvbmZpZyk7XG5cblx0XHRsZXQgY2FjaGVkUGx1Z2luID0gdGhpcy5wbHVnaW5DYWNoZS5nZXQoY2FjaGVLZXkpO1xuXHRcdGlmICghY2FjaGVkUGx1Z2luKSB7XG5cdFx0XHRjb25zdCBvcGVyYXRpb24gPSBFZmZlY3QuZ2VuKHRoaXMsIGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdGNvbnN0IHBsdWdpblNlcnZpY2UgPSB5aWVsZCogUGx1Z2luU2VydmljZTtcblx0XHRcdFx0Y29uc3QgdmFsaWRhdGVkSWQgPSB5aWVsZCogdGhpcy52YWxpZGF0ZVBsdWdpbklkKHBsdWdpbklkKTtcblxuXHRcdFx0XHQvLyBMb2FkIOKGkiBJbnN0YW50aWF0ZSDihpIgSW5pdGlhbGl6ZVxuXHRcdFx0XHRjb25zdCBjdG9yID0geWllbGQqIHBsdWdpblNlcnZpY2UubG9hZFBsdWdpbih2YWxpZGF0ZWRJZCk7XG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlID0geWllbGQqIHBsdWdpblNlcnZpY2UuaW5zdGFudGlhdGVQbHVnaW4ocGx1Z2luSWQsIGN0b3IpO1xuXHRcdFx0XHRjb25zdCBpbml0aWFsaXplZCA9IHlpZWxkKiBwbHVnaW5TZXJ2aWNlLmluaXRpYWxpemVQbHVnaW4oaW5zdGFuY2UsIGNvbmZpZyk7XG5cblx0XHRcdFx0cmV0dXJuIGluaXRpYWxpemVkO1xuXHRcdFx0fSkucGlwZShFZmZlY3QucHJvdmlkZSh0aGlzLnJ1bnRpbWUpKTtcblxuXHRcdFx0Y2FjaGVkUGx1Z2luID0gRWZmZWN0LmNhY2hlZChvcGVyYXRpb24pLnBpcGUoRWZmZWN0LmZsYXR0ZW4pO1xuXHRcdFx0dGhpcy5wbHVnaW5DYWNoZS5zZXQoY2FjaGVLZXksIGNhY2hlZFBsdWdpbik7XG5cdFx0fVxuXG5cdFx0Y29uc3QgaW5pdGlhbGl6ZWQgPSBhd2FpdCB0aGlzLnJ1blByb21pc2UoY2FjaGVkUGx1Z2luKTtcblx0XHRjb25zdCByb3V0ZXIgPSBpbml0aWFsaXplZC5wbHVnaW4uY3JlYXRlUm91dGVyKGluaXRpYWxpemVkLmNvbnRleHQpO1xuXHRcdGNvbnN0IGNsaWVudCA9IGNyZWF0ZVJvdXRlckNsaWVudChyb3V0ZXIpO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHJvdXRlcjogcm91dGVyIGFzIFBsdWdpblJvdXRlclR5cGU8UltLXT4sXG5cdFx0XHRjbGllbnQ6IGNsaWVudCBhcyBQbHVnaW5DbGllbnRUeXBlPFJbS10+LFxuXHRcdFx0bWV0YWRhdGE6IGluaXRpYWxpemVkLm1ldGFkYXRhLFxuXHRcdFx0aW5pdGlhbGl6ZWQ6IGluaXRpYWxpemVkIGFzIEluaXRpYWxpemVkUGx1Z2luPFJlZ2lzdGVyZWRQbHVnaW48Sz4+XG5cdFx0fSBhcyBVc2VQbHVnaW5SZXN1bHQ8Sz47XG5cdH1cblxuXHRhc3luYyBsb2FkUGx1Z2luPEsgZXh0ZW5kcyBrZXlvZiBSZWdpc3RlcmVkUGx1Z2lucyAmIHN0cmluZz4oXG5cdFx0cGx1Z2luSWQ6IEtcblx0KTogUHJvbWlzZTxMb2FkZWRQbHVnaW48UmVnaXN0ZXJlZFBsdWdpbjxLPj4+IHtcblx0XHRjb25zdCBlZmZlY3QgPSBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRjb25zdCBwbHVnaW5TZXJ2aWNlID0geWllbGQqIFBsdWdpblNlcnZpY2U7XG5cdFx0XHRyZXR1cm4geWllbGQqIHBsdWdpblNlcnZpY2UubG9hZFBsdWdpbihwbHVnaW5JZCk7XG5cdFx0fSk7XG5cdFx0cmV0dXJuIHRoaXMucnVuUHJvbWlzZShlZmZlY3QpIGFzIFByb21pc2U8TG9hZGVkUGx1Z2luPFJlZ2lzdGVyZWRQbHVnaW48Sz4+Pjtcblx0fVxuXG5cdGFzeW5jIGluc3RhbnRpYXRlUGx1Z2luPEsgZXh0ZW5kcyBrZXlvZiBSZWdpc3RlcmVkUGx1Z2lucyAmIHN0cmluZz4oXG5cdFx0cGx1Z2luSWQ6IEssXG5cdFx0bG9hZGVkUGx1Z2luOiBMb2FkZWRQbHVnaW48UmVnaXN0ZXJlZFBsdWdpbjxLPj5cblx0KTogUHJvbWlzZTxQbHVnaW5JbnN0YW5jZTxSZWdpc3RlcmVkUGx1Z2luPEs+Pj4ge1xuXHRcdGNvbnN0IGVmZmVjdCA9IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRcdGNvbnN0IHBsdWdpblNlcnZpY2UgPSB5aWVsZCogUGx1Z2luU2VydmljZTtcblx0XHRcdHJldHVybiB5aWVsZCogcGx1Z2luU2VydmljZS5pbnN0YW50aWF0ZVBsdWdpbihwbHVnaW5JZCwgbG9hZGVkUGx1Z2luKTtcblx0XHR9KTtcblx0XHRyZXR1cm4gdGhpcy5ydW5Qcm9taXNlKGVmZmVjdCkgYXMgUHJvbWlzZTxQbHVnaW5JbnN0YW5jZTxSZWdpc3RlcmVkUGx1Z2luPEs+Pj47XG5cdH1cblxuXHRhc3luYyBpbml0aWFsaXplUGx1Z2luPFQgZXh0ZW5kcyBBbnlQbHVnaW4+KFxuXHRcdGluc3RhbmNlOiBQbHVnaW5JbnN0YW5jZTxUPixcblx0XHRjb25maWc6IGFueVxuXHQpOiBQcm9taXNlPEluaXRpYWxpemVkUGx1Z2luPFQ+PiB7XG5cdFx0Y29uc3QgZWZmZWN0ID0gRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0Y29uc3QgcGx1Z2luU2VydmljZSA9IHlpZWxkKiBQbHVnaW5TZXJ2aWNlO1xuXHRcdFx0cmV0dXJuIHlpZWxkKiBwbHVnaW5TZXJ2aWNlLmluaXRpYWxpemVQbHVnaW4oaW5zdGFuY2UsIGNvbmZpZyk7XG5cdFx0fSk7XG5cdFx0cmV0dXJuIHRoaXMucnVuUHJvbWlzZShlZmZlY3QpO1xuXHR9XG5cblx0YXN5bmMgc2h1dGRvd24oKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0Y29uc3QgZWZmZWN0ID0gRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0Y29uc3QgcGx1Z2luU2VydmljZSA9IHlpZWxkKiBQbHVnaW5TZXJ2aWNlO1xuXHRcdFx0eWllbGQqIHBsdWdpblNlcnZpY2UuY2xlYW51cCgpO1xuXHRcdH0pO1xuXHRcdHJldHVybiB0aGlzLnJ1blByb21pc2UoZWZmZWN0KTtcblx0fVxuXG5cdGFzeW5jIGV2aWN0UGx1Z2luPEsgZXh0ZW5kcyBrZXlvZiBSZWdpc3RlcmVkUGx1Z2lucyAmIHN0cmluZz4oXG5cdFx0cGx1Z2luSWQ6IEssXG5cdFx0Y29uZmlnOiBQbHVnaW5Db25maWdJbnB1dDxSZWdpc3RlcmVkUGx1Z2luc1tLXT5cblx0KTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0Y29uc3QgY2FjaGVLZXkgPSB0aGlzLmdlbmVyYXRlQ2FjaGVLZXkocGx1Z2luSWQsIGNvbmZpZyk7XG5cblx0XHRjb25zdCBlZmZlY3QgPSBFZmZlY3QuZ2VuKHRoaXMsIGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRjb25zdCBwbHVnaW5TZXJ2aWNlID0geWllbGQqIFBsdWdpblNlcnZpY2U7XG5cdFx0XHRjb25zdCBjYWNoZWRQbHVnaW4gPSB0aGlzLnBsdWdpbkNhY2hlLmdldChjYWNoZUtleSk7XG5cblx0XHRcdGlmIChjYWNoZWRQbHVnaW4pIHtcblx0XHRcdFx0dGhpcy5wbHVnaW5DYWNoZS5kZWxldGUoY2FjaGVLZXkpO1xuXG5cdFx0XHRcdGNvbnN0IHBsdWdpblJlc3VsdCA9IHlpZWxkKiBjYWNoZWRQbHVnaW4ucGlwZShcblx0XHRcdFx0XHRFZmZlY3QuY2F0Y2hBbGwoKCkgPT4gRWZmZWN0LnN1Y2NlZWQobnVsbCkpXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0aWYgKHBsdWdpblJlc3VsdCkge1xuXHRcdFx0XHRcdHlpZWxkKiBwbHVnaW5TZXJ2aWNlLnNodXRkb3duUGx1Z2luKHBsdWdpblJlc3VsdCkucGlwZShcblx0XHRcdFx0XHRcdEVmZmVjdC5jYXRjaEFsbCgoKSA9PiBFZmZlY3Qudm9pZClcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSkucGlwZShFZmZlY3QuY2F0Y2hBbGwoKCkgPT4gRWZmZWN0LnZvaWQpKTtcblxuXHRcdHJldHVybiB0aGlzLnJ1blByb21pc2UoZWZmZWN0KTtcblx0fVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgYSByZW1vdGUgVVJMIHRvIGVuc3VyZSBpdCBwb2ludHMgdG8gcmVtb3RlRW50cnkuanNcbiAqIElmIHRoZSBVUkwgZG9lc24ndCBlbmQgd2l0aCBhIGZpbGUgZXh0ZW5zaW9uLCBhcHBlbmRzIC9yZW1vdGVFbnRyeS5qc1xuICovXG5mdW5jdGlvbiBub3JtYWxpemVSZW1vdGVVcmwodXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRpZiAodXJsLmVuZHNXaXRoKCcuanMnKSkgcmV0dXJuIHVybDsgLy8gQWxyZWFkeSBhIGZpbGVcblx0cmV0dXJuIGAke3VybC5lbmRzV2l0aCgnLycpID8gdXJsLnNsaWNlKDAsIC0xKSA6IHVybH0vcmVtb3RlRW50cnkuanNgO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUGx1Z2luUnVudGltZShcblx0Y29uZmlnOiBQbHVnaW5SdW50aW1lQ29uZmlnXG4pOiBQbHVnaW5SdW50aW1lIHtcblx0Y29uc3Qgc2VjcmV0cyA9IGNvbmZpZy5zZWNyZXRzIHx8IHt9O1xuXG5cdC8vIE5vcm1hbGl6ZSBhbGwgcmVtb3RlIFVSTHMgaW4gdGhlIHJlZ2lzdHJ5XG5cdGNvbnN0IG5vcm1hbGl6ZWRSZWdpc3RyeSA9IE9iamVjdC5mcm9tRW50cmllcyhcblx0XHRPYmplY3QuZW50cmllcyhjb25maWcucmVnaXN0cnkpLm1hcCgoW3BsdWdpbklkLCBlbnRyeV0pID0+IFtcblx0XHRcdHBsdWdpbklkLFxuXHRcdFx0e1xuXHRcdFx0XHQuLi5lbnRyeSxcblx0XHRcdFx0cmVtb3RlVXJsOiBub3JtYWxpemVSZW1vdGVVcmwoZW50cnkucmVtb3RlVXJsKVxuXHRcdFx0fVxuXHRcdF0pXG5cdCkgYXMgUGx1Z2luUmVnaXN0cnk7XG5cblx0Y29uc3QgbGF5ZXIgPSBQbHVnaW5TZXJ2aWNlLkxpdmUobm9ybWFsaXplZFJlZ2lzdHJ5LCBzZWNyZXRzKTtcblx0Y29uc3QgcnVudGltZSA9IE1hbmFnZWRSdW50aW1lLm1ha2UobGF5ZXIpO1xuXG5cdHJldHVybiBuZXcgUGx1Z2luUnVudGltZShydW50aW1lLCBub3JtYWxpemVkUmVnaXN0cnkpO1xufSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBSUEsSUFBYSxxQkFBYixjQUF3Q0EsWUFBSyxZQUFZLHFCQUFxQixDQU0zRTtBQUVILElBQWEsd0JBQWIsY0FB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
|