every-plugin 0.4.12 → 0.4.14
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 +80 -79
- package/dist/build/rspack/index.d.cts +1 -1
- package/dist/build/rspack/index.d.mts +1 -1
- package/dist/build/rspack/index.mjs +80 -79
- package/dist/{index-matrPV4m.d.cts → index-DM9S53Bx.d.cts} +2 -2
- package/dist/{index-qxKsRmCb.d.mts → index-DrOou1Hc.d.mts} +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{package-OrUVCH-p.mjs → package-BoyftHDo.mjs} +2 -2
- package/dist/{package-DawQ8na8.cjs → package-CgNIVjVe.cjs} +2 -2
- package/dist/runtime/index.cjs +2 -2
- package/dist/runtime/index.d.cts +1 -1
- package/dist/runtime/index.d.mts +1 -1
- package/dist/runtime/index.mjs +2 -2
- package/dist/runtime-BYrdNAff.cjs +524 -0
- package/dist/runtime-BzkHRj0E.mjs +459 -0
- package/dist/testing/index.cjs +2 -2
- package/dist/testing/index.d.cts +1 -1
- package/dist/testing/index.d.mts +1 -1
- package/dist/testing/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/runtime-Br0wOcuk.mjs +0 -458
- package/dist/runtime-Ckpw0yAc.cjs +0 -523
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-zltIcp7o.cjs');
|
|
2
|
+
const require_normalize = require('./normalize-D4Qh0wVk.cjs');
|
|
3
|
+
const require_package$1 = require('./package-CgNIVjVe.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 manifestUrl = url.endsWith("/") ? `${url}mf-manifest.json` : `${url}/mf-manifest.json`;
|
|
118
|
+
const { error: manifestError } = yield* effect.Effect.tryPromise({
|
|
119
|
+
try: () => (0, __better_fetch_fetch.betterFetch)(manifestUrl, { method: "HEAD" }),
|
|
120
|
+
catch: (error) => error
|
|
121
|
+
});
|
|
122
|
+
let entryUrl;
|
|
123
|
+
let isManifestMode = false;
|
|
124
|
+
if (!manifestError) {
|
|
125
|
+
entryUrl = manifestUrl;
|
|
126
|
+
isManifestMode = true;
|
|
127
|
+
console.log(`[MF] Using MF 2.0 manifest mode for ${pluginId}`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`[MF] ⚠️ Manifest not found, falling back to MF 1.5 mode for ${pluginId}`);
|
|
130
|
+
entryUrl = url;
|
|
131
|
+
isManifestMode = false;
|
|
132
|
+
}
|
|
133
|
+
const remoteName = isManifestMode ? pluginId : require_normalize.getNormalizedRemoteName(pluginId);
|
|
134
|
+
yield* effect.Effect.try({
|
|
135
|
+
try: () => mf.registerRemotes([{
|
|
136
|
+
name: remoteName,
|
|
137
|
+
entry: entryUrl,
|
|
138
|
+
...isManifestMode && { alias: pluginId }
|
|
139
|
+
}]),
|
|
140
|
+
catch: (error) => new ModuleFederationError({
|
|
141
|
+
pluginId,
|
|
142
|
+
remoteUrl: url,
|
|
143
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
console.log(`[MF] ✅ Registered ${pluginId} (${isManifestMode ? "MF 2.0" : "MF 1.5"})`);
|
|
147
|
+
}),
|
|
148
|
+
loadRemoteConstructor: (pluginId, url) => effect.Effect.gen(function* () {
|
|
149
|
+
const remoteName = require_normalize.getNormalizedRemoteName(pluginId);
|
|
150
|
+
console.log(`[MF] Loading remote ${remoteName}`);
|
|
151
|
+
const modulePath = `${remoteName}/plugin`;
|
|
152
|
+
return yield* effect.Effect.tryPromise({
|
|
153
|
+
try: async () => {
|
|
154
|
+
const container = await mf.loadRemote(modulePath);
|
|
155
|
+
if (!container) throw new Error(`No container returned for ${modulePath}`);
|
|
156
|
+
const Constructor = typeof container === "function" ? container : container.default ? container.default : Object.values(container).find((exp) => typeof exp === "function" && exp.prototype?.constructor === exp);
|
|
157
|
+
if (!Constructor || typeof Constructor !== "function") {
|
|
158
|
+
const containerInfo = typeof container === "object" ? `Available exports: ${Object.keys(container).join(", ")}` : `Container type: ${typeof container}`;
|
|
159
|
+
throw new Error(`No valid plugin constructor found for '${pluginId}'.\nSupported patterns:\n - export const YourPlugin = createPlugin({...})\n - export default createPlugin({...})\n${containerInfo}`);
|
|
160
|
+
}
|
|
161
|
+
if (!Constructor.binding) {
|
|
162
|
+
const containerInfo = typeof container === "object" ? `Found exports: ${Object.keys(container).join(", ")}` : `Container type: ${typeof container}`;
|
|
163
|
+
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}`);
|
|
164
|
+
}
|
|
165
|
+
console.log(`[MF] ✅ Loaded constructor for ${pluginId}`);
|
|
166
|
+
return Constructor;
|
|
167
|
+
},
|
|
168
|
+
catch: (error) => new ModuleFederationError({
|
|
169
|
+
pluginId,
|
|
170
|
+
remoteUrl: url,
|
|
171
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
172
|
+
})
|
|
173
|
+
});
|
|
174
|
+
})
|
|
175
|
+
};
|
|
176
|
+
}) }) {};
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/runtime/services/plugin-lifecycle.service.ts
|
|
180
|
+
var PluginLifecycleService = class extends effect.Effect.Service()("PluginLifecycleService", { effect: effect.Effect.gen(function* () {
|
|
181
|
+
const activePlugins = yield* effect.Ref.make(/* @__PURE__ */ new Set());
|
|
182
|
+
return {
|
|
183
|
+
register: (plugin) => effect.Ref.update(activePlugins, (plugins) => new Set(plugins).add(plugin)),
|
|
184
|
+
unregister: (plugin) => effect.Ref.update(activePlugins, (plugins) => {
|
|
185
|
+
const newSet = new Set(plugins);
|
|
186
|
+
newSet.delete(plugin);
|
|
187
|
+
return newSet;
|
|
188
|
+
}),
|
|
189
|
+
shutdown: (plugin) => effect.Effect.gen(function* () {
|
|
190
|
+
yield* effect.Ref.update(activePlugins, (plugins) => {
|
|
191
|
+
const newSet = new Set(plugins);
|
|
192
|
+
newSet.delete(plugin);
|
|
193
|
+
return newSet;
|
|
194
|
+
});
|
|
195
|
+
yield* plugin.plugin.shutdown().pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, plugin.plugin.id, void 0, "shutdown-plugin", false)));
|
|
196
|
+
}),
|
|
197
|
+
cleanup: () => effect.Effect.gen(function* () {
|
|
198
|
+
const plugins = yield* effect.Ref.get(activePlugins);
|
|
199
|
+
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" });
|
|
200
|
+
yield* effect.Ref.set(activePlugins, /* @__PURE__ */ new Set());
|
|
201
|
+
}).pipe(effect.Effect.catchAll(() => effect.Effect.void))
|
|
202
|
+
};
|
|
203
|
+
}) }) {};
|
|
204
|
+
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/runtime/validation.ts
|
|
207
|
+
const validate = (schema, data, pluginId, stage) => effect.Effect.gen(function* () {
|
|
208
|
+
const result = schema.safeParse(data);
|
|
209
|
+
if (result.success) return result.data;
|
|
210
|
+
return yield* effect.Effect.fail(new ValidationError({
|
|
211
|
+
pluginId,
|
|
212
|
+
stage,
|
|
213
|
+
zodError: result.error
|
|
214
|
+
}));
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/runtime/services/secrets.service.ts
|
|
219
|
+
const configSchema = zod.z.object({ secrets: zod.z.record(zod.z.string(), zod.z.unknown()) }).loose();
|
|
220
|
+
var SecretsConfigTag = class extends effect.Context.Tag("SecretsConfig")() {};
|
|
221
|
+
var SecretsService = class extends effect.Effect.Service()("SecretsService", { effect: effect.Effect.gen(function* () {
|
|
222
|
+
const secrets = yield* SecretsConfigTag;
|
|
223
|
+
return { hydrateSecrets: (config) => effect.Effect.gen(function* () {
|
|
224
|
+
const parseResult = configSchema.parse(config);
|
|
225
|
+
try {
|
|
226
|
+
let hydratedString = JSON.stringify(parseResult);
|
|
227
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
228
|
+
const pattern = new RegExp(`{{${key}}}`, "g");
|
|
229
|
+
hydratedString = hydratedString.replace(pattern, String(value));
|
|
230
|
+
}
|
|
231
|
+
return JSON.parse(hydratedString);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
return yield* effect.Effect.fail(new PluginRuntimeError({
|
|
234
|
+
operation: "hydrate-secrets",
|
|
235
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
236
|
+
retryable: false
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
}) };
|
|
240
|
+
}) }) {};
|
|
241
|
+
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/runtime/services/plugin-loader.service.ts
|
|
244
|
+
var PluginRegistryTag = class extends effect.Context.Tag("PluginRegistry")() {};
|
|
245
|
+
var RegistryService = class extends effect.Effect.Service()("RegistryService", { effect: effect.Effect.gen(function* () {
|
|
246
|
+
const registry = yield* PluginRegistryTag;
|
|
247
|
+
return { get: (pluginId) => effect.Effect.fromNullable(registry[pluginId]).pipe(effect.Effect.mapError(() => new PluginRuntimeError({
|
|
248
|
+
pluginId,
|
|
249
|
+
operation: "validate-plugin-id",
|
|
250
|
+
cause: /* @__PURE__ */ new Error(`Plugin ${pluginId} not found in registry`),
|
|
251
|
+
retryable: false
|
|
252
|
+
}))) };
|
|
253
|
+
}) }) {};
|
|
254
|
+
var PluginLoaderService = class extends effect.Effect.Service()("PluginLoaderService", { effect: effect.Effect.gen(function* () {
|
|
255
|
+
const moduleFederationService = yield* ModuleFederationService;
|
|
256
|
+
const secretsService = yield* SecretsService;
|
|
257
|
+
const registryService = yield* RegistryService;
|
|
258
|
+
const resolveUrl = (baseUrl, version) => version && version !== "latest" ? baseUrl.replace("@latest", `@${version}`) : baseUrl;
|
|
259
|
+
const getMetadata = (pluginId) => registryService.get(pluginId);
|
|
260
|
+
return {
|
|
261
|
+
loadPlugin: (pluginId) => effect.Effect.gen(function* () {
|
|
262
|
+
const metadata = yield* getMetadata(pluginId);
|
|
263
|
+
const url = resolveUrl(metadata.remoteUrl);
|
|
264
|
+
yield* moduleFederationService.registerRemote(pluginId, url).pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, pluginId, void 0, "register-remote", true)));
|
|
265
|
+
yield* effect.Effect.logDebug("Loading plugin", {
|
|
266
|
+
pluginId,
|
|
267
|
+
url
|
|
268
|
+
});
|
|
269
|
+
return {
|
|
270
|
+
ctor: yield* moduleFederationService.loadRemoteConstructor(pluginId, url).pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, pluginId, void 0, "load-remote", false))),
|
|
271
|
+
metadata
|
|
272
|
+
};
|
|
273
|
+
}),
|
|
274
|
+
instantiatePlugin: (pluginId, loadedPlugin) => effect.Effect.gen(function* () {
|
|
275
|
+
const instance = yield* effect.Effect.try(() => new loadedPlugin.ctor()).pipe(effect.Effect.mapError((error) => toPluginRuntimeError(error, pluginId, void 0, "instantiate-plugin", false)));
|
|
276
|
+
instance.id = pluginId;
|
|
277
|
+
return {
|
|
278
|
+
plugin: instance,
|
|
279
|
+
metadata: loadedPlugin.metadata
|
|
280
|
+
};
|
|
281
|
+
}),
|
|
282
|
+
initializePlugin: (pluginInstance, config) => effect.Effect.gen(function* () {
|
|
283
|
+
const { plugin } = pluginInstance;
|
|
284
|
+
const validatedVariables = yield* validate(plugin.configSchema.variables, config.variables, plugin.id, "config").pipe(effect.Effect.mapError((validationError) => new PluginRuntimeError({
|
|
285
|
+
pluginId: plugin.id,
|
|
286
|
+
operation: "validate-config",
|
|
287
|
+
cause: validationError.zodError,
|
|
288
|
+
retryable: false
|
|
289
|
+
})));
|
|
290
|
+
const validatedSecrets = yield* validate(plugin.configSchema.secrets, config.secrets, plugin.id, "config").pipe(effect.Effect.mapError((validationError) => new PluginRuntimeError({
|
|
291
|
+
pluginId: plugin.id,
|
|
292
|
+
operation: "validate-secrets",
|
|
293
|
+
cause: validationError.zodError,
|
|
294
|
+
retryable: false
|
|
295
|
+
})));
|
|
296
|
+
const hydratedConfig = yield* secretsService.hydrateSecrets({
|
|
297
|
+
variables: validatedVariables,
|
|
298
|
+
secrets: validatedSecrets
|
|
299
|
+
});
|
|
300
|
+
const _variables = yield* validate(plugin.configSchema.variables, hydratedConfig.variables, plugin.id, "config").pipe(effect.Effect.mapError((validationError) => new PluginRuntimeError({
|
|
301
|
+
pluginId: plugin.id,
|
|
302
|
+
operation: "validate-hydrated-config",
|
|
303
|
+
cause: validationError.zodError,
|
|
304
|
+
retryable: false
|
|
305
|
+
})));
|
|
306
|
+
const scope = yield* effect.Scope.make();
|
|
307
|
+
const context = yield* plugin.initialize({
|
|
308
|
+
variables: _variables,
|
|
309
|
+
secrets: hydratedConfig.secrets
|
|
310
|
+
}).pipe(effect.Effect.provideService(effect.Scope.Scope, scope), effect.Effect.mapError((error) => toPluginRuntimeError(error, plugin.id, void 0, "initialize-plugin", false)));
|
|
311
|
+
return {
|
|
312
|
+
plugin,
|
|
313
|
+
metadata: pluginInstance.metadata,
|
|
314
|
+
config: {
|
|
315
|
+
variables: _variables,
|
|
316
|
+
secrets: hydratedConfig.secrets
|
|
317
|
+
},
|
|
318
|
+
context,
|
|
319
|
+
scope
|
|
320
|
+
};
|
|
321
|
+
})
|
|
322
|
+
};
|
|
323
|
+
}) }) {};
|
|
324
|
+
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/runtime/services/plugin.service.ts
|
|
327
|
+
var PluginService = class PluginService extends effect.Effect.Service()("PluginService", { scoped: effect.Effect.gen(function* () {
|
|
328
|
+
const loader = yield* PluginLoaderService;
|
|
329
|
+
const lifecycle = yield* PluginLifecycleService;
|
|
330
|
+
return {
|
|
331
|
+
loadPlugin: loader.loadPlugin,
|
|
332
|
+
instantiatePlugin: loader.instantiatePlugin,
|
|
333
|
+
initializePlugin: loader.initializePlugin,
|
|
334
|
+
shutdownPlugin: (plugin) => effect.Effect.gen(function* () {
|
|
335
|
+
yield* plugin.plugin.shutdown().pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
336
|
+
yield* effect.Scope.close(plugin.scope, effect.Exit.succeed(void 0));
|
|
337
|
+
yield* lifecycle.unregister(plugin);
|
|
338
|
+
}),
|
|
339
|
+
cleanup: lifecycle.cleanup
|
|
340
|
+
};
|
|
341
|
+
}) }) {
|
|
342
|
+
static Live = (registry, secrets) => {
|
|
343
|
+
const contextLayer = effect.Layer.mergeAll(effect.Layer.succeed(PluginRegistryTag, registry), effect.Layer.succeed(SecretsConfigTag, secrets));
|
|
344
|
+
const servicesLayer = effect.Layer.mergeAll(ModuleFederationService.Default, SecretsService.Default, RegistryService.Default, PluginLifecycleService.Default).pipe(effect.Layer.provide(contextLayer));
|
|
345
|
+
return PluginService.Default.pipe(effect.Layer.provide(PluginLoaderService.Default), effect.Layer.provide(servicesLayer));
|
|
346
|
+
};
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/runtime/index.ts
|
|
351
|
+
var PluginRuntime = class {
|
|
352
|
+
pluginCache = /* @__PURE__ */ new Map();
|
|
353
|
+
constructor(runtime, registry) {
|
|
354
|
+
this.runtime = runtime;
|
|
355
|
+
this.registry = registry;
|
|
356
|
+
}
|
|
357
|
+
generateCacheKey(pluginId, config) {
|
|
358
|
+
return `${pluginId}:${effect.Hash.structure(config).toString()}`;
|
|
359
|
+
}
|
|
360
|
+
validatePluginId(pluginId) {
|
|
361
|
+
if (!(pluginId in this.registry)) return effect.Effect.fail(new PluginRuntimeError({
|
|
362
|
+
pluginId: String(pluginId),
|
|
363
|
+
operation: "validate-plugin-id",
|
|
364
|
+
cause: /* @__PURE__ */ new Error(`Plugin ID '${String(pluginId)}' not found in registry.`),
|
|
365
|
+
retryable: false
|
|
366
|
+
}));
|
|
367
|
+
return effect.Effect.succeed(String(pluginId));
|
|
368
|
+
}
|
|
369
|
+
async runPromise(effect$1) {
|
|
370
|
+
const exit = await this.runtime.runPromiseExit(effect$1);
|
|
371
|
+
if (effect.Exit.isFailure(exit)) {
|
|
372
|
+
const error = effect.Cause.failureOption(exit.cause);
|
|
373
|
+
if (effect.Option.isSome(error)) throw error.value;
|
|
374
|
+
throw effect.Cause.squash(exit.cause);
|
|
375
|
+
}
|
|
376
|
+
return exit.value;
|
|
377
|
+
}
|
|
378
|
+
async usePlugin(pluginId, config) {
|
|
379
|
+
const cacheKey = this.generateCacheKey(pluginId, config);
|
|
380
|
+
let cachedPlugin = this.pluginCache.get(cacheKey);
|
|
381
|
+
if (!cachedPlugin) {
|
|
382
|
+
const operation = effect.Effect.gen(this, function* () {
|
|
383
|
+
const pluginService = yield* PluginService;
|
|
384
|
+
const validatedId = yield* this.validatePluginId(pluginId);
|
|
385
|
+
const ctor = yield* pluginService.loadPlugin(validatedId);
|
|
386
|
+
const instance = yield* pluginService.instantiatePlugin(pluginId, ctor);
|
|
387
|
+
return yield* pluginService.initializePlugin(instance, config);
|
|
388
|
+
}).pipe(effect.Effect.provide(this.runtime));
|
|
389
|
+
cachedPlugin = effect.Effect.cached(operation).pipe(effect.Effect.flatten);
|
|
390
|
+
this.pluginCache.set(cacheKey, cachedPlugin);
|
|
391
|
+
}
|
|
392
|
+
const initialized = await this.runPromise(cachedPlugin);
|
|
393
|
+
const router = initialized.plugin.createRouter(initialized.context);
|
|
394
|
+
return {
|
|
395
|
+
router,
|
|
396
|
+
client: (0, __orpc_server.createRouterClient)(router),
|
|
397
|
+
metadata: initialized.metadata,
|
|
398
|
+
initialized
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async loadPlugin(pluginId) {
|
|
402
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
403
|
+
return yield* (yield* PluginService).loadPlugin(pluginId);
|
|
404
|
+
});
|
|
405
|
+
return this.runPromise(effect$1);
|
|
406
|
+
}
|
|
407
|
+
async instantiatePlugin(pluginId, loadedPlugin) {
|
|
408
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
409
|
+
return yield* (yield* PluginService).instantiatePlugin(pluginId, loadedPlugin);
|
|
410
|
+
});
|
|
411
|
+
return this.runPromise(effect$1);
|
|
412
|
+
}
|
|
413
|
+
async initializePlugin(instance, config) {
|
|
414
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
415
|
+
return yield* (yield* PluginService).initializePlugin(instance, config);
|
|
416
|
+
});
|
|
417
|
+
return this.runPromise(effect$1);
|
|
418
|
+
}
|
|
419
|
+
async shutdown() {
|
|
420
|
+
const effect$1 = effect.Effect.gen(function* () {
|
|
421
|
+
yield* (yield* PluginService).cleanup();
|
|
422
|
+
});
|
|
423
|
+
return this.runPromise(effect$1);
|
|
424
|
+
}
|
|
425
|
+
async evictPlugin(pluginId, config) {
|
|
426
|
+
const cacheKey = this.generateCacheKey(pluginId, config);
|
|
427
|
+
const effect$1 = effect.Effect.gen(this, function* () {
|
|
428
|
+
const pluginService = yield* PluginService;
|
|
429
|
+
const cachedPlugin = this.pluginCache.get(cacheKey);
|
|
430
|
+
if (cachedPlugin) {
|
|
431
|
+
this.pluginCache.delete(cacheKey);
|
|
432
|
+
const pluginResult = yield* cachedPlugin.pipe(effect.Effect.catchAll(() => effect.Effect.succeed(null)));
|
|
433
|
+
if (pluginResult) yield* pluginService.shutdownPlugin(pluginResult).pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
434
|
+
}
|
|
435
|
+
}).pipe(effect.Effect.catchAll(() => effect.Effect.void));
|
|
436
|
+
return this.runPromise(effect$1);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Normalizes a remote URL to ensure it points to remoteEntry.js
|
|
441
|
+
* If the URL doesn't end with a file extension, appends /remoteEntry.js
|
|
442
|
+
*/
|
|
443
|
+
function normalizeRemoteUrl(url) {
|
|
444
|
+
if (url.endsWith(".js")) return url;
|
|
445
|
+
return `${url.endsWith("/") ? url.slice(0, -1) : url}/remoteEntry.js`;
|
|
446
|
+
}
|
|
447
|
+
function createPluginRuntime(config) {
|
|
448
|
+
const secrets = config.secrets || {};
|
|
449
|
+
const normalizedRegistry = Object.fromEntries(Object.entries(config.registry).map(([pluginId, entry]) => [pluginId, {
|
|
450
|
+
...entry,
|
|
451
|
+
remoteUrl: normalizeRemoteUrl(entry.remoteUrl)
|
|
452
|
+
}]));
|
|
453
|
+
const layer = PluginService.Live(normalizedRegistry, secrets);
|
|
454
|
+
return new PluginRuntime(effect.ManagedRuntime.make(layer), normalizedRegistry);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
//#endregion
|
|
458
|
+
Object.defineProperty(exports, 'ModuleFederationError', {
|
|
459
|
+
enumerable: true,
|
|
460
|
+
get: function () {
|
|
461
|
+
return ModuleFederationError;
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
Object.defineProperty(exports, 'ModuleFederationService', {
|
|
465
|
+
enumerable: true,
|
|
466
|
+
get: function () {
|
|
467
|
+
return ModuleFederationService;
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
Object.defineProperty(exports, 'PluginLifecycleService', {
|
|
471
|
+
enumerable: true,
|
|
472
|
+
get: function () {
|
|
473
|
+
return PluginLifecycleService;
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
Object.defineProperty(exports, 'PluginLoaderService', {
|
|
477
|
+
enumerable: true,
|
|
478
|
+
get: function () {
|
|
479
|
+
return PluginLoaderService;
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
Object.defineProperty(exports, 'PluginRegistryTag', {
|
|
483
|
+
enumerable: true,
|
|
484
|
+
get: function () {
|
|
485
|
+
return PluginRegistryTag;
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
Object.defineProperty(exports, 'PluginRuntime', {
|
|
489
|
+
enumerable: true,
|
|
490
|
+
get: function () {
|
|
491
|
+
return PluginRuntime;
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
Object.defineProperty(exports, 'PluginService', {
|
|
495
|
+
enumerable: true,
|
|
496
|
+
get: function () {
|
|
497
|
+
return PluginService;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
Object.defineProperty(exports, 'RegistryService', {
|
|
501
|
+
enumerable: true,
|
|
502
|
+
get: function () {
|
|
503
|
+
return RegistryService;
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
Object.defineProperty(exports, 'SecretsConfigTag', {
|
|
507
|
+
enumerable: true,
|
|
508
|
+
get: function () {
|
|
509
|
+
return SecretsConfigTag;
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
Object.defineProperty(exports, 'SecretsService', {
|
|
513
|
+
enumerable: true,
|
|
514
|
+
get: function () {
|
|
515
|
+
return SecretsService;
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
Object.defineProperty(exports, 'createPluginRuntime', {
|
|
519
|
+
enumerable: true,
|
|
520
|
+
get: function () {
|
|
521
|
+
return createPluginRuntime;
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS1CWXJkTkFmZi5janMiLCJuYW1lcyI6WyJEYXRhIiwiT1JQQ0Vycm9yIiwiRWZmZWN0IiwicGtnIiwiZW50cnlVcmw6IHN0cmluZyIsImdldE5vcm1hbGl6ZWRSZW1vdGVOYW1lIiwiRWZmZWN0IiwiUmVmIiwiRWZmZWN0IiwieiIsIkNvbnRleHQiLCJFZmZlY3QiLCJDb250ZXh0IiwiRWZmZWN0IiwiU2NvcGUiLCJFZmZlY3QiLCJTY29wZSIsIkV4aXQiLCJMYXllciIsInJ1bnRpbWU6IE1hbmFnZWRSdW50aW1lLk1hbmFnZWRSdW50aW1lPFBsdWdpblNlcnZpY2UsIG5ldmVyPiIsInJlZ2lzdHJ5OiBQbHVnaW5SZWdpc3RyeSIsIkhhc2giLCJFZmZlY3QiLCJlZmZlY3QiLCJFeGl0IiwiQ2F1c2UiLCJPcHRpb24iLCJNYW5hZ2VkUnVudGltZSJdLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lL2Vycm9ycy50cyIsIi4uL3NyYy9ydW50aW1lL3NlcnZpY2VzL21vZHVsZS1mZWRlcmF0aW9uLnNlcnZpY2UudHMiLCIuLi9zcmMvcnVudGltZS9zZXJ2aWNlcy9wbHVnaW4tbGlmZWN5Y2xlLnNlcnZpY2UudHMiLCIuLi9zcmMvcnVudGltZS92YWxpZGF0aW9uLnRzIiwiLi4vc3JjL3J1bnRpbWUvc2VydmljZXMvc2VjcmV0cy5zZXJ2aWNlLnRzIiwiLi4vc3JjL3J1bnRpbWUvc2VydmljZXMvcGx1Z2luLWxvYWRlci5zZXJ2aWNlLnRzIiwiLi4vc3JjL3J1bnRpbWUvc2VydmljZXMvcGx1Z2luLnNlcnZpY2UudHMiLCIuLi9zcmMvcnVudGltZS9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBPUlBDRXJyb3IgfSBmcm9tIFwiQG9ycGMvY29udHJhY3RcIjtcbmltcG9ydCB7IERhdGEgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5SdW50aW1lRXJyb3IgZXh0ZW5kcyBEYXRhLlRhZ2dlZEVycm9yKFwiUGx1Z2luUnVudGltZUVycm9yXCIpPHtcblx0cmVhZG9ubHkgcGx1Z2luSWQ/OiBzdHJpbmc7XG5cdHJlYWRvbmx5IG9wZXJhdGlvbj86IHN0cmluZztcblx0cmVhZG9ubHkgcHJvY2VkdXJlTmFtZT86IHN0cmluZztcblx0cmVhZG9ubHkgY2F1c2U/OiBFcnJvcjtcblx0cmVhZG9ubHkgcmV0cnlhYmxlOiBib29sZWFuO1xufT4geyB9XG5cbmV4cG9ydCBjbGFzcyBNb2R1bGVGZWRlcmF0aW9uRXJyb3IgZXh0ZW5kcyBEYXRhLlRhZ2dlZEVycm9yKFxuXHRcIk1vZHVsZUZlZGVyYXRpb25FcnJvclwiLFxuKTx7XG5cdHJlYWRvbmx5IHBsdWdpbklkOiBzdHJpbmc7XG5cdHJlYWRvbmx5IHJlbW90ZVVybDogc3RyaW5nO1xuXHRyZWFkb25seSBjYXVzZT86IEVycm9yO1xufT4geyB9XG5cbmV4cG9ydCBjbGFzcyBWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBEYXRhLlRhZ2dlZEVycm9yKFwiVmFsaWRhdGlvbkVycm9yXCIpPHtcblx0cmVhZG9ubHkgcGx1Z2luSWQ6IHN0cmluZztcblx0cmVhZG9ubHkgc3RhZ2U6IFwiY29uZmlnXCIgfCBcImlucHV0XCIgfCBcIm91dHB1dFwiIHwgXCJzdGF0ZVwiO1xuXHRyZWFkb25seSB6b2RFcnJvcjogei5ab2RFcnJvcjtcbn0+IHsgfVxuXG4vLyBIZWxwZXIgdG8gZGV0ZXJtaW5lIGlmIGFuIG9SUEMgZXJyb3IgY29kZSBpcyByZXRyeWFibGVcbmV4cG9ydCBjb25zdCBpc1JldHJ5YWJsZU9SUENDb2RlID0gKGNvZGU6IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuXHRzd2l0Y2ggKGNvZGUpIHtcblx0XHRjYXNlICdUT09fTUFOWV9SRVFVRVNUUyc6XG5cdFx0Y2FzZSAnU0VSVklDRV9VTkFWQUlMQUJMRSc6XG5cdFx0Y2FzZSAnQkFEX0dBVEVXQVknOlxuXHRcdGNhc2UgJ0dBVEVXQVlfVElNRU9VVCc6XG5cdFx0Y2FzZSAnVElNRU9VVCc6XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRkZWZhdWx0OlxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG59O1xuXG4vLyBDb252ZXJ0IE9SUEMgZXJyb3JzIGZyb20gcGx1Z2luIHByb2NlZHVyZXMgdG8gUGx1Z2luUnVudGltZUVycm9yXG5leHBvcnQgY29uc3Qgd3JhcE9SUENFcnJvciA9IChcblx0b3JwY0Vycm9yOiBPUlBDRXJyb3I8c3RyaW5nLCB1bmtub3duPixcblx0cGx1Z2luSWQ/OiBzdHJpbmcsXG5cdHByb2NlZHVyZU5hbWU/OiBzdHJpbmcsXG5cdG9wZXJhdGlvbj86IHN0cmluZ1xuKTogUGx1Z2luUnVudGltZUVycm9yID0+IHtcblx0cmV0dXJuIG5ldyBQbHVnaW5SdW50aW1lRXJyb3Ioe1xuXHRcdHBsdWdpbklkLFxuXHRcdG9wZXJhdGlvbixcblx0XHRwcm9jZWR1cmVOYW1lLFxuXHRcdHJldHJ5YWJsZTogaXNSZXRyeWFibGVPUlBDQ29kZShvcnBjRXJyb3IuY29kZSksXG5cdFx0Y2F1c2U6IG9ycGNFcnJvciBhcyBFcnJvclxuXHR9KTtcbn07XG5cbi8vIFVuaXZlcnNhbCBlcnJvciBjb252ZXJ0ZXIgZm9yIHRoZSBydW50aW1lXG5leHBvcnQgY29uc3QgdG9QbHVnaW5SdW50aW1lRXJyb3IgPSAoXG5cdGVycm9yOiB1bmtub3duLFxuXHRwbHVnaW5JZD86IHN0cmluZyxcblx0cHJvY2VkdXJlTmFtZT86IHN0cmluZyxcblx0b3BlcmF0aW9uPzogc3RyaW5nLFxuXHRkZWZhdWx0UmV0cnlhYmxlID0gZmFsc2Vcbik6IFBsdWdpblJ1bnRpbWVFcnJvciA9PiB7XG5cdGlmIChlcnJvciBpbnN0YW5jZW9mIE9SUENFcnJvcikge1xuXHRcdHJldHVybiB3cmFwT1JQQ0Vycm9yKGVycm9yLCBwbHVnaW5JZCwgcHJvY2VkdXJlTmFtZSwgb3BlcmF0aW9uKTtcblx0fVxuXG5cdGlmIChlcnJvciBpbnN0YW5jZW9mIFBsdWdpblJ1bnRpbWVFcnJvcikge1xuXHRcdHJldHVybiBlcnJvcjsgLy8gQWxyZWFkeSBjb252ZXJ0ZWRcblx0fVxuXG5cdHJldHVybiBuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRwbHVnaW5JZCxcblx0XHRvcGVyYXRpb24sXG5cdFx0cHJvY2VkdXJlTmFtZSxcblx0XHRyZXRyeWFibGU6IGRlZmF1bHRSZXRyeWFibGUsXG5cdFx0Y2F1c2U6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKVxuXHR9KTtcbn07XG4iLCJpbXBvcnQgeyBiZXR0ZXJGZXRjaCB9IGZyb20gXCJAYmV0dGVyLWZldGNoL2ZldGNoXCI7XG5pbXBvcnQge1xuXHRjcmVhdGVJbnN0YW5jZSxcblx0Z2V0SW5zdGFuY2UsXG59IGZyb20gXCJAbW9kdWxlLWZlZGVyYXRpb24vZW5oYW5jZWQvcnVudGltZVwiO1xuaW1wb3J0IHsgc2V0R2xvYmFsRmVkZXJhdGlvbkluc3RhbmNlIH0gZnJvbSBcIkBtb2R1bGUtZmVkZXJhdGlvbi9ydW50aW1lLWNvcmVcIjtcbmltcG9ydCB7IEVmZmVjdCB9IGZyb20gXCJlZmZlY3RcIjtcbmltcG9ydCB0eXBlIHsgQW55UGx1Z2luIH0gZnJvbSBcIi4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBNb2R1bGVGZWRlcmF0aW9uRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBnZXROb3JtYWxpemVkUmVtb3RlTmFtZSB9IGZyb20gXCIuL25vcm1hbGl6ZVwiO1xuXG50eXBlIFJlbW90ZU1vZHVsZSA9IFxuICB8IChuZXcgKCkgPT4gQW55UGx1Z2luKVxuICB8IHsgZGVmYXVsdDogbmV3ICgpID0+IEFueVBsdWdpbiB9O1xuXG5pbXBvcnQgcGtnIGZyb20gXCIuLi8uLi8uLi9wYWNrYWdlLmpzb25cIjtcblxuY29uc3QgY3JlYXRlTW9kdWxlRmVkZXJhdGlvbkluc3RhbmNlID0gRWZmZWN0LmNhY2hlZChcblx0RWZmZWN0LnN5bmMoKCkgPT4ge1xuXHRcdHRyeSB7XG5cdFx0XHRsZXQgaW5zdGFuY2UgPSBnZXRJbnN0YW5jZSgpO1xuXG5cdFx0XHRpZiAoIWluc3RhbmNlKSB7XG5cdFx0XHRcdGluc3RhbmNlID0gY3JlYXRlSW5zdGFuY2Uoe1xuXHRcdFx0XHRcdG5hbWU6IFwiaG9zdFwiLFxuXHRcdFx0XHRcdHJlbW90ZXM6IFtdLFxuXHRcdFx0XHRcdHNoYXJlZDoge1xuXHRcdFx0XHRcdFx0XCJldmVyeS1wbHVnaW5cIjoge1xuXHRcdFx0XHRcdFx0XHR2ZXJzaW9uOiBwa2cudmVyc2lvbixcblx0XHRcdFx0XHRcdFx0c2hhcmVDb25maWc6IHtcblx0XHRcdFx0XHRcdFx0XHRzaW5nbGV0b246IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0cmVxdWlyZWRWZXJzaW9uOiBgXiR7cGtnLnZlcnNpb259YCxcblx0XHRcdFx0XHRcdFx0XHRlYWdlcjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRzdHJpY3RWZXJzaW9uOiBmYWxzZSwgLy8gQWxsb3cgYmlkaXJlY3Rpb25hbCB2ZXJzaW9uIGNvbXBhdGliaWxpdHlcblx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRlZmZlY3Q6IHtcblx0XHRcdFx0XHRcdFx0dmVyc2lvbjogcGtnLmRlcGVuZGVuY2llcy5lZmZlY3QsXG5cdFx0XHRcdFx0XHRcdHNoYXJlQ29uZmlnOiB7XG5cdFx0XHRcdFx0XHRcdFx0c2luZ2xldG9uOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHJlcXVpcmVkVmVyc2lvbjogXCJeMy4xOC4wXCIsIC8vIEFsbG93IGFueSAzLjE4LnggcGF0Y2ggdmVyc2lvblxuXHRcdFx0XHRcdFx0XHRcdGVhZ2VyOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHN0cmljdFZlcnNpb246IGZhbHNlLCAvLyBBbGxvdyB2ZXJzaW9uIGZsZXhpYmlsaXR5IGZvciBjb21wYXRpYmlsaXR5XG5cdFx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0em9kOiB7XG5cdFx0XHRcdFx0XHRcdHZlcnNpb246IHBrZy5kZXBlbmRlbmNpZXMuem9kLFxuXHRcdFx0XHRcdFx0XHRzaGFyZUNvbmZpZzoge1xuXHRcdFx0XHRcdFx0XHRcdHNpbmdsZXRvbjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRyZXF1aXJlZFZlcnNpb246IFwiXjQuMS4wXCIsIC8vIEFsbG93IGFueSA0LjEueCBwYXRjaCB2ZXJzaW9uXG5cdFx0XHRcdFx0XHRcdFx0ZWFnZXI6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0c3RyaWN0VmVyc2lvbjogZmFsc2UsIC8vIEFsbG93IHZlcnNpb24gZmxleGliaWxpdHkgZm9yIGNvbXBhdGliaWxpdHlcblx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRcIkBvcnBjL2NvbnRyYWN0XCI6IHtcblx0XHRcdFx0XHRcdFx0dmVyc2lvbjogcGtnLmRlcGVuZGVuY2llc1tcIkBvcnBjL2NvbnRyYWN0XCJdLFxuXHRcdFx0XHRcdFx0XHRzaGFyZUNvbmZpZzoge1xuXHRcdFx0XHRcdFx0XHRcdHNpbmdsZXRvbjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRyZXF1aXJlZFZlcnNpb246IFwiXjEuOC4wXCIsIC8vIEFsbG93IGFueSAxLjgueCBwYXRjaCB2ZXJzaW9uXG5cdFx0XHRcdFx0XHRcdFx0ZWFnZXI6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0c3RyaWN0VmVyc2lvbjogZmFsc2UsIC8vIEFsbG93IHZlcnNpb24gZmxleGliaWxpdHkgZm9yIGNvbXBhdGliaWxpdHlcblx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRcIkBvcnBjL3NlcnZlclwiOiB7XG5cdFx0XHRcdFx0XHRcdHZlcnNpb246IHBrZy5kZXBlbmRlbmNpZXNbXCJAb3JwYy9zZXJ2ZXJcIl0sXG5cdFx0XHRcdFx0XHRcdHNoYXJlQ29uZmlnOiB7XG5cdFx0XHRcdFx0XHRcdFx0c2luZ2xldG9uOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHJlcXVpcmVkVmVyc2lvbjogXCJeMS44LjBcIiwgLy8gQWxsb3cgYW55IDEuOC54IHBhdGNoIHZlcnNpb25cblx0XHRcdFx0XHRcdFx0XHRlYWdlcjogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRzdHJpY3RWZXJzaW9uOiBmYWxzZSwgLy8gQWxsb3cgdmVyc2lvbiBmbGV4aWJpbGl0eSBmb3IgY29tcGF0aWJpbGl0eVxuXHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdH0pO1xuXG5cdFx0XHRcdHNldEdsb2JhbEZlZGVyYXRpb25JbnN0YW5jZShpbnN0YW5jZSk7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBpbnN0YW5jZTtcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gaW5pdGlhbGl6ZSBNb2R1bGUgRmVkZXJhdGlvbjogJHtlcnJvcn1gKTtcblx0XHR9XG5cdH0pLFxuKTtcblxuZXhwb3J0IGNsYXNzIE1vZHVsZUZlZGVyYXRpb25TZXJ2aWNlIGV4dGVuZHMgRWZmZWN0LlNlcnZpY2U8TW9kdWxlRmVkZXJhdGlvblNlcnZpY2U+KCkoXCJNb2R1bGVGZWRlcmF0aW9uU2VydmljZVwiLCB7XG5cdGVmZmVjdDogRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdGNvbnN0IG1mID0geWllbGQqIEVmZmVjdC5mbGF0dGVuKGNyZWF0ZU1vZHVsZUZlZGVyYXRpb25JbnN0YW5jZSk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0cmVnaXN0ZXJSZW1vdGU6IChwbHVnaW5JZDogc3RyaW5nLCB1cmw6IHN0cmluZykgPT5cblx0XHRcdFx0RWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0XHRcdGNvbnNvbGUubG9nKGBbTUZdIFJlZ2lzdGVyaW5nICR7cGx1Z2luSWR9YCk7XG5cblx0XHRcdFx0XHRjb25zdCBtYW5pZmVzdFVybCA9IHVybC5lbmRzV2l0aCgnLycpXG5cdFx0XHRcdFx0XHQ/IGAke3VybH1tZi1tYW5pZmVzdC5qc29uYFxuXHRcdFx0XHRcdFx0OiBgJHt1cmx9L21mLW1hbmlmZXN0Lmpzb25gO1xuXG5cdFx0XHRcdFx0Ly8gQ2hlY2sgaWYgbWFuaWZlc3QgaXMgYXZhaWxhYmxlIChNRiAyLjAgd2l0aCBtYW5pZmVzdHMpXG5cdFx0XHRcdFx0Y29uc3QgeyBlcnJvcjogbWFuaWZlc3RFcnJvciB9ID0geWllbGQqIEVmZmVjdC50cnlQcm9taXNlKHtcblx0XHRcdFx0XHRcdHRyeTogKCkgPT4gYmV0dGVyRmV0Y2gobWFuaWZlc3RVcmwsIHsgbWV0aG9kOiBcIkhFQURcIiB9KSxcblx0XHRcdFx0XHRcdGNhdGNoOiAoZXJyb3IpID0+IGVycm9yLCAvLyBEb24ndCBmYWlsIHlldCwgdHJ5IGZhbGxiYWNrXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRsZXQgZW50cnlVcmw6IHN0cmluZztcblx0XHRcdFx0XHRsZXQgaXNNYW5pZmVzdE1vZGUgPSBmYWxzZTtcblxuXHRcdFx0XHRcdGlmICghbWFuaWZlc3RFcnJvcikge1xuXHRcdFx0XHRcdFx0Ly8gTUYgMi4wIG1hbmlmZXN0IG1vZGUgLSB1c2UgbWFuaWZlc3QgVVJMXG5cdFx0XHRcdFx0XHRlbnRyeVVybCA9IG1hbmlmZXN0VXJsO1xuXHRcdFx0XHRcdFx0aXNNYW5pZmVzdE1vZGUgPSB0cnVlO1xuXHRcdFx0XHRcdFx0Y29uc29sZS5sb2coYFtNRl0gVXNpbmcgTUYgMi4wIG1hbmlmZXN0IG1vZGUgZm9yICR7cGx1Z2luSWR9YCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdC8vIEZhbGxiYWNrIHRvIE1GIDEuNSBkaXJlY3QgbW9kZSAtIGFzc3VtZSBVUkwgcG9pbnRzIHRvIHJlbW90ZUVudHJ5LmpzXG5cdFx0XHRcdFx0XHRjb25zb2xlLmxvZyhgW01GXSDimqDvuI8gTWFuaWZlc3Qgbm90IGZvdW5kLCBmYWxsaW5nIGJhY2sgdG8gTUYgMS41IG1vZGUgZm9yICR7cGx1Z2luSWR9YCk7XG5cdFx0XHRcdFx0XHRlbnRyeVVybCA9IHVybDtcblx0XHRcdFx0XHRcdGlzTWFuaWZlc3RNb2RlID0gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gRm9yIE1GIDIuMCwgdGhlIG5hbWUgY2FuIGJlIHRoZSBwbHVnaW5JZCAoYWxpYXMpXG5cdFx0XHRcdFx0Ly8gVGhlIG1hbmlmZXN0IHdpbGwgY29udGFpbiB0aGUgYWN0dWFsIGNvbnRhaW5lciBuYW1lXG5cdFx0XHRcdFx0Y29uc3QgcmVtb3RlTmFtZSA9IGlzTWFuaWZlc3RNb2RlID8gcGx1Z2luSWQgOiBnZXROb3JtYWxpemVkUmVtb3RlTmFtZShwbHVnaW5JZCk7XG5cblx0XHRcdFx0XHR5aWVsZCogRWZmZWN0LnRyeSh7XG5cdFx0XHRcdFx0XHR0cnk6ICgpID0+IG1mLnJlZ2lzdGVyUmVtb3Rlcyhbe1xuXHRcdFx0XHRcdFx0XHRuYW1lOiByZW1vdGVOYW1lLFxuXHRcdFx0XHRcdFx0XHRlbnRyeTogZW50cnlVcmwsXG5cdFx0XHRcdFx0XHRcdC4uLihpc01hbmlmZXN0TW9kZSAmJiB7IGFsaWFzOiBwbHVnaW5JZCB9KSAvLyBFeHBsaWNpdCBhbGlhcyBmb3IgY2xhcml0eVxuXHRcdFx0XHRcdFx0fV0pLFxuXHRcdFx0XHRcdFx0Y2F0Y2g6IChlcnJvcik6IE1vZHVsZUZlZGVyYXRpb25FcnJvciA9PlxuXHRcdFx0XHRcdFx0XHRuZXcgTW9kdWxlRmVkZXJhdGlvbkVycm9yKHtcblx0XHRcdFx0XHRcdFx0XHRwbHVnaW5JZCxcblx0XHRcdFx0XHRcdFx0XHRyZW1vdGVVcmw6IHVybCxcblx0XHRcdFx0XHRcdFx0XHRjYXVzZTpcblx0XHRcdFx0XHRcdFx0XHRcdGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRjb25zb2xlLmxvZyhgW01GXSDinIUgUmVnaXN0ZXJlZCAke3BsdWdpbklkfSAoJHtpc01hbmlmZXN0TW9kZSA/ICdNRiAyLjAnIDogJ01GIDEuNSd9KWApO1xuXHRcdFx0XHR9KSxcblxuXHRcdFx0bG9hZFJlbW90ZUNvbnN0cnVjdG9yOiAocGx1Z2luSWQ6IHN0cmluZywgdXJsOiBzdHJpbmcpID0+XG5cdFx0XHRcdEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRcdFx0XHRjb25zdCByZW1vdGVOYW1lID0gZ2V0Tm9ybWFsaXplZFJlbW90ZU5hbWUocGx1Z2luSWQpO1xuXHRcdFx0XHRcdGNvbnNvbGUubG9nKGBbTUZdIExvYWRpbmcgcmVtb3RlICR7cmVtb3RlTmFtZX1gKTtcblx0XHRcdFx0XHRjb25zdCBtb2R1bGVQYXRoID0gYCR7cmVtb3RlTmFtZX0vcGx1Z2luYDtcblxuXHRcdFx0XHRcdHJldHVybiB5aWVsZCogRWZmZWN0LnRyeVByb21pc2Uoe1xuXHRcdFx0XHRcdFx0dHJ5OiBhc3luYyAoKSA9PiB7XG5cblx0XHRcdFx0XHRcdFx0Y29uc3QgY29udGFpbmVyID0gYXdhaXQgbWYubG9hZFJlbW90ZTxSZW1vdGVNb2R1bGU+KG1vZHVsZVBhdGgpO1xuXHRcdFx0XHRcdFx0XHRpZiAoIWNvbnRhaW5lcikge1xuXHRcdFx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvcihgTm8gY29udGFpbmVyIHJldHVybmVkIGZvciAke21vZHVsZVBhdGh9YCk7XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0IG11bHRpcGxlIGV4cG9ydCBwYXR0ZXJuczogZGlyZWN0IGZ1bmN0aW9uLCBkZWZhdWx0IGV4cG9ydCwgbmFtZWQgZXhwb3J0c1xuXHRcdFx0XHRcdFx0XHRjb25zdCBDb25zdHJ1Y3RvciA9XG5cdFx0XHRcdFx0XHRcdFx0dHlwZW9mIGNvbnRhaW5lciA9PT0gXCJmdW5jdGlvblwiXG5cdFx0XHRcdFx0XHRcdFx0XHQ/IGNvbnRhaW5lciAgLy8gRGlyZWN0IGZ1bmN0aW9uIGV4cG9ydFxuXHRcdFx0XHRcdFx0XHRcdFx0OiBjb250YWluZXIuZGVmYXVsdFxuXHRcdFx0XHRcdFx0XHRcdFx0PyBjb250YWluZXIuZGVmYXVsdCAgLy8gRGVmYXVsdCBleHBvcnRcblx0XHRcdFx0XHRcdFx0XHRcdDogT2JqZWN0LnZhbHVlcyhjb250YWluZXIpLmZpbmQoICAvLyBOYW1lZCBleHBvcnQgZmFsbGJhY2tcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQoZXhwKSA9PiB0eXBlb2YgZXhwID09PSBcImZ1bmN0aW9uXCIgJiYgZXhwLnByb3RvdHlwZT8uY29uc3RydWN0b3IgPT09IGV4cFxuXHRcdFx0XHRcdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHRcdGlmICghQ29uc3RydWN0b3IgfHwgdHlwZW9mIENvbnN0cnVjdG9yICE9PSBcImZ1bmN0aW9uXCIpIHtcblx0XHRcdFx0XHRcdFx0XHRjb25zdCBjb250YWluZXJJbmZvID0gdHlwZW9mIGNvbnRhaW5lciA9PT0gXCJvYmplY3RcIlxuXHRcdFx0XHRcdFx0XHRcdFx0PyBgQXZhaWxhYmxlIGV4cG9ydHM6ICR7T2JqZWN0LmtleXMoY29udGFpbmVyKS5qb2luKCcsICcpfWBcblx0XHRcdFx0XHRcdFx0XHRcdDogYENvbnRhaW5lciB0eXBlOiAke3R5cGVvZiBjb250YWluZXJ9YDtcblxuXHRcdFx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvcihcblx0XHRcdFx0XHRcdFx0XHRcdGBObyB2YWxpZCBwbHVnaW4gY29uc3RydWN0b3IgZm91bmQgZm9yICcke3BsdWdpbklkfScuXFxuYCArXG5cdFx0XHRcdFx0XHRcdFx0XHRgU3VwcG9ydGVkIHBhdHRlcm5zOlxcbmAgK1xuXHRcdFx0XHRcdFx0XHRcdFx0YCAgLSBleHBvcnQgY29uc3QgWW91clBsdWdpbiA9IGNyZWF0ZVBsdWdpbih7Li4ufSlcXG5gICtcblx0XHRcdFx0XHRcdFx0XHRcdGAgIC0gZXhwb3J0IGRlZmF1bHQgY3JlYXRlUGx1Z2luKHsuLi59KVxcbmAgK1xuXHRcdFx0XHRcdFx0XHRcdFx0YCR7Y29udGFpbmVySW5mb31gLFxuXHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHQvLyBWYWxpZGF0ZSBpdCBsb29rcyBsaWtlIGEgcGx1Z2luIGNvbnN0cnVjdG9yIChoYXMgYmluZGluZyBwcm9wZXJ0eSlcblx0XHRcdFx0XHRcdFx0aWYgKCEoQ29uc3RydWN0b3IgYXMgYW55KS5iaW5kaW5nKSB7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgY29udGFpbmVySW5mbyA9IHR5cGVvZiBjb250YWluZXIgPT09IFwib2JqZWN0XCJcblx0XHRcdFx0XHRcdFx0XHRcdD8gYEZvdW5kIGV4cG9ydHM6ICR7T2JqZWN0LmtleXMoY29udGFpbmVyKS5qb2luKCcsICcpfWBcblx0XHRcdFx0XHRcdFx0XHRcdDogYENvbnRhaW5lciB0eXBlOiAke3R5cGVvZiBjb250YWluZXJ9YDtcblxuXHRcdFx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvcihcblx0XHRcdFx0XHRcdFx0XHRcdGBJbnZhbGlkIHBsdWdpbiBjb25zdHJ1Y3RvciBmb3IgJyR7cGx1Z2luSWR9Jy4gYCArXG5cdFx0XHRcdFx0XHRcdFx0XHRgVGhlIGV4cG9ydGVkIHZhbHVlIG11c3QgYmUgY3JlYXRlZCB3aXRoIGNyZWF0ZVBsdWdpbigpLiBgICtcblx0XHRcdFx0XHRcdFx0XHRcdGBGb3VuZCBhIGZ1bmN0aW9uIGJ1dCBpdCdzIG1pc3NpbmcgdGhlIHJlcXVpcmVkICdiaW5kaW5nJyBwcm9wZXJ0eS5cXG5gICtcblx0XHRcdFx0XHRcdFx0XHRcdGAke2NvbnRhaW5lckluZm99YCxcblx0XHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0Y29uc29sZS5sb2coYFtNRl0g4pyFIExvYWRlZCBjb25zdHJ1Y3RvciBmb3IgJHtwbHVnaW5JZH1gKTtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIENvbnN0cnVjdG9yO1xuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdGNhdGNoOiAoZXJyb3IpOiBNb2R1bGVGZWRlcmF0aW9uRXJyb3IgPT5cblx0XHRcdFx0XHRcdFx0bmV3IE1vZHVsZUZlZGVyYXRpb25FcnJvcih7XG5cdFx0XHRcdFx0XHRcdFx0cGx1Z2luSWQsXG5cdFx0XHRcdFx0XHRcdFx0cmVtb3RlVXJsOiB1cmwsXG5cdFx0XHRcdFx0XHRcdFx0Y2F1c2U6XG5cdFx0XHRcdFx0XHRcdFx0XHRlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSksXG5cdFx0XHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9KSxcblx0XHR9O1xuXHR9KSxcbn0pIHt9XG4iLCJpbXBvcnQgeyBFZmZlY3QsIFJlZiB9IGZyb20gXCJlZmZlY3RcIjtcbmltcG9ydCB0eXBlIHsgQW55UGx1Z2luLCBJbml0aWFsaXplZFBsdWdpbiB9IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuaW1wb3J0IHsgdG9QbHVnaW5SdW50aW1lRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzXCI7XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5MaWZlY3ljbGVTZXJ2aWNlIGV4dGVuZHMgRWZmZWN0LlNlcnZpY2U8UGx1Z2luTGlmZWN5Y2xlU2VydmljZT4oKShcIlBsdWdpbkxpZmVjeWNsZVNlcnZpY2VcIiwge1xuICBlZmZlY3Q6IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICBjb25zdCBhY3RpdmVQbHVnaW5zID0geWllbGQqIFJlZi5tYWtlKG5ldyBTZXQ8SW5pdGlhbGl6ZWRQbHVnaW48QW55UGx1Z2luPj4oKSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgcmVnaXN0ZXI6IDxUIGV4dGVuZHMgQW55UGx1Z2luPihwbHVnaW46IEluaXRpYWxpemVkUGx1Z2luPFQ+KSA9PlxuICAgICAgICBSZWYudXBkYXRlKGFjdGl2ZVBsdWdpbnMsIHBsdWdpbnMgPT5cbiAgICAgICAgICBuZXcgU2V0KHBsdWdpbnMpLmFkZChwbHVnaW4gYXMgSW5pdGlhbGl6ZWRQbHVnaW48QW55UGx1Z2luPilcbiAgICAgICAgKSxcblxuICAgICAgdW5yZWdpc3RlcjogKHBsdWdpbjogSW5pdGlhbGl6ZWRQbHVnaW48QW55UGx1Z2luPikgPT5cbiAgICAgICAgUmVmLnVwZGF0ZShhY3RpdmVQbHVnaW5zLCBwbHVnaW5zID0+IHtcbiAgICAgICAgICBjb25zdCBuZXdTZXQgPSBuZXcgU2V0KHBsdWdpbnMpO1xuICAgICAgICAgIG5ld1NldC5kZWxldGUocGx1Z2luKTtcbiAgICAgICAgICByZXR1cm4gbmV3U2V0O1xuICAgICAgICB9KSxcblxuICAgICAgc2h1dGRvd246IChwbHVnaW46IEluaXRpYWxpemVkUGx1Z2luPEFueVBsdWdpbj4pID0+XG4gICAgICAgIEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcbiAgICAgICAgICAvLyBSZW1vdmUgZnJvbSBhY3RpdmUgcGx1Z2luc1xuICAgICAgICAgIHlpZWxkKiBSZWYudXBkYXRlKGFjdGl2ZVBsdWdpbnMsIHBsdWdpbnMgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV3U2V0ID0gbmV3IFNldChwbHVnaW5zKTtcbiAgICAgICAgICAgIG5ld1NldC5kZWxldGUocGx1Z2luKTtcbiAgICAgICAgICAgIHJldHVybiBuZXdTZXQ7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyBTaHV0ZG93biB0aGUgcGx1Z2luXG4gICAgICAgICAgeWllbGQqIHBsdWdpbi5wbHVnaW4uc2h1dGRvd24oKS5waXBlKFxuICAgICAgICAgICAgRWZmZWN0Lm1hcEVycm9yKGVycm9yID0+XG4gICAgICAgICAgICAgIHRvUGx1Z2luUnVudGltZUVycm9yKGVycm9yLCBwbHVnaW4ucGx1Z2luLmlkLCB1bmRlZmluZWQsIFwic2h1dGRvd24tcGx1Z2luXCIsIGZhbHNlKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICk7XG4gICAgICAgIH0pLFxuXG4gICAgICBjbGVhbnVwOiAoKSA9PlxuICAgICAgICBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgICAgY29uc3QgcGx1Z2lucyA9IHlpZWxkKiBSZWYuZ2V0KGFjdGl2ZVBsdWdpbnMpO1xuXG4gICAgICAgICAgLy8gU2h1dGRvd24gYWxsIGFjdGl2ZSBwbHVnaW5zIGNvbmN1cnJlbnRseVxuICAgICAgICAgIHlpZWxkKiBFZmZlY3QuZm9yRWFjaChcbiAgICAgICAgICAgIHBsdWdpbnMsXG4gICAgICAgICAgICBwbHVnaW4gPT5cbiAgICAgICAgICAgICAgcGx1Z2luLnBsdWdpbi5zaHV0ZG93bigpLnBpcGUoXG4gICAgICAgICAgICAgICAgRWZmZWN0Lm1hcEVycm9yKGVycm9yID0+XG4gICAgICAgICAgICAgICAgICB0b1BsdWdpblJ1bnRpbWVFcnJvcihlcnJvciwgcGx1Z2luLnBsdWdpbi5pZCwgdW5kZWZpbmVkLCBcImNsZWFudXAtc2h1dGRvd25cIiwgZmFsc2UpXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBFZmZlY3QuY2F0Y2hBbGwoZXJyb3IgPT5cbiAgICAgICAgICAgICAgICAgIEVmZmVjdC5sb2dFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgYEZhaWxlZCB0byBzaHV0ZG93biBwbHVnaW4gJHtwbHVnaW4ucGx1Z2luLmlkfSBkdXJpbmcgY2xlYW51cGAsXG4gICAgICAgICAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgICAgICAgICB7IHBsdWdpbklkOiBwbHVnaW4ucGx1Z2luLmlkIH1cbiAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICB7IGNvbmN1cnJlbmN5OiBcInVuYm91bmRlZFwiIH1cbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gQ2xlYXIgdGhlIGFjdGl2ZSBwbHVnaW5zIHNldFxuICAgICAgICAgIHlpZWxkKiBSZWYuc2V0KGFjdGl2ZVBsdWdpbnMsIG5ldyBTZXQoKSk7XG4gICAgICAgIH0pLnBpcGUoXG4gICAgICAgICAgRWZmZWN0LmNhdGNoQWxsKCgpID0+IEVmZmVjdC52b2lkKSAvLyBDb252ZXJ0IGVycm9ycyB0byB2b2lkIGZvciBjbGVhbnVwXG4gICAgICAgICksXG4gICAgfTtcbiAgfSksXG59KSB7IH1cbiIsImltcG9ydCB7IEVmZmVjdCB9IGZyb20gXCJlZmZlY3RcIjtcbmltcG9ydCB0eXBlIHsgeiB9IGZyb20gXCJ6b2RcIjtcbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCIuL2Vycm9yc1wiO1xuXG5leHBvcnQgY29uc3QgdmFsaWRhdGUgPSA8VD4oXG5cdHNjaGVtYTogei5ab2RTY2hlbWE8VD4sXG5cdGRhdGE6IHVua25vd24sXG5cdHBsdWdpbklkOiBzdHJpbmcsXG5cdHN0YWdlOiBcImNvbmZpZ1wiIHwgXCJpbnB1dFwiIHwgXCJvdXRwdXRcIiB8IFwic3RhdGVcIixcbik6IEVmZmVjdC5FZmZlY3Q8VCwgVmFsaWRhdGlvbkVycm9yPiA9PlxuXHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0Y29uc3QgcmVzdWx0ID0gc2NoZW1hLnNhZmVQYXJzZShkYXRhKTtcblx0XHRpZiAocmVzdWx0LnN1Y2Nlc3MpIHtcblx0XHRcdHJldHVybiByZXN1bHQuZGF0YTtcblx0XHR9XG5cdFx0cmV0dXJuIHlpZWxkKiBFZmZlY3QuZmFpbChcblx0XHRcdG5ldyBWYWxpZGF0aW9uRXJyb3Ioe1xuXHRcdFx0XHRwbHVnaW5JZCxcblx0XHRcdFx0c3RhZ2UsXG5cdFx0XHRcdHpvZEVycm9yOiByZXN1bHQuZXJyb3IsXG5cdFx0XHR9KSxcblx0XHQpO1xuXHR9KTtcbiIsImltcG9ydCB7IENvbnRleHQsIEVmZmVjdCB9IGZyb20gXCJlZmZlY3RcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgdHlwZSB7IFNlY3JldHNDb25maWcgfSBmcm9tIFwiLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IFBsdWdpblJ1bnRpbWVFcnJvciB9IGZyb20gXCIuLi9lcnJvcnNcIjtcblxuY29uc3QgY29uZmlnU2NoZW1hID0gei5vYmplY3Qoe1xuXHRzZWNyZXRzOiB6LnJlY29yZCh6LnN0cmluZygpLCB6LnVua25vd24oKSlcbn0pLmxvb3NlKCk7XG5cbmV4cG9ydCBjbGFzcyBTZWNyZXRzQ29uZmlnVGFnIGV4dGVuZHMgQ29udGV4dC5UYWcoXCJTZWNyZXRzQ29uZmlnXCIpPFxuXHRTZWNyZXRzQ29uZmlnVGFnLFxuXHRTZWNyZXRzQ29uZmlnXG4+KCkgeyB9XG5cbmV4cG9ydCBjbGFzcyBTZWNyZXRzU2VydmljZSBleHRlbmRzIEVmZmVjdC5TZXJ2aWNlPFNlY3JldHNTZXJ2aWNlPigpKFwiU2VjcmV0c1NlcnZpY2VcIiwge1xuXHRlZmZlY3Q6IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRjb25zdCBzZWNyZXRzID0geWllbGQqIFNlY3JldHNDb25maWdUYWc7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0aHlkcmF0ZVNlY3JldHM6IDxUPihjb25maWc6IFQpID0+XG5cdFx0XHRcdEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRcdFx0XHRjb25zdCBwYXJzZVJlc3VsdCA9IGNvbmZpZ1NjaGVtYS5wYXJzZShjb25maWcpO1xuXHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRjb25zdCBjb25maWdTdHJpbmcgPSBKU09OLnN0cmluZ2lmeShwYXJzZVJlc3VsdCk7XG5cdFx0XHRcdFx0XHRsZXQgaHlkcmF0ZWRTdHJpbmcgPSBjb25maWdTdHJpbmc7XG5cblx0XHRcdFx0XHRcdGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNlY3JldHMpKSB7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IHBhdHRlcm4gPSBuZXcgUmVnRXhwKGB7eyR7a2V5fX19YCwgXCJnXCIpO1xuXHRcdFx0XHRcdFx0XHRoeWRyYXRlZFN0cmluZyA9IGh5ZHJhdGVkU3RyaW5nLnJlcGxhY2UocGF0dGVybiwgU3RyaW5nKHZhbHVlKSk7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdHJldHVybiBKU09OLnBhcnNlKGh5ZHJhdGVkU3RyaW5nKSBhcyBUO1xuXHRcdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4geWllbGQqIEVmZmVjdC5mYWlsKFxuXHRcdFx0XHRcdFx0XHRuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRcdFx0XHRcdFx0XHRvcGVyYXRpb246IFwiaHlkcmF0ZS1zZWNyZXRzXCIsXG5cdFx0XHRcdFx0XHRcdFx0Y2F1c2U6XG5cdFx0XHRcdFx0XHRcdFx0XHRlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSksXG5cdFx0XHRcdFx0XHRcdFx0cmV0cnlhYmxlOiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSksXG5cdFx0fTtcblx0fSksXG59KSB7IH1cbiIsImltcG9ydCB0eXBlIHsgSW5mZXJTY2hlbWFJbnB1dCwgSW5mZXJTY2hlbWFPdXRwdXQgfSBmcm9tIFwiQG9ycGMvY29udHJhY3RcIjtcbmltcG9ydCB7IENvbnRleHQsIEVmZmVjdCwgU2NvcGUgfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgdHlwZSB7XG5cdEFueVBsdWdpbixcblx0SW5pdGlhbGl6ZWRQbHVnaW4sXG5cdExvYWRlZFBsdWdpbixcblx0UGx1Z2luSW5zdGFuY2UsXG5cdFBsdWdpblJlZ2lzdHJ5XG59IGZyb20gXCIuLi8uLi90eXBlc1wiO1xuaW1wb3J0IHsgUGx1Z2luUnVudGltZUVycm9yLCB0b1BsdWdpblJ1bnRpbWVFcnJvciB9IGZyb20gXCIuLi9lcnJvcnNcIjtcbmltcG9ydCB7IHZhbGlkYXRlIH0gZnJvbSBcIi4uL3ZhbGlkYXRpb25cIjtcbmltcG9ydCB7IE1vZHVsZUZlZGVyYXRpb25TZXJ2aWNlIH0gZnJvbSBcIi4vbW9kdWxlLWZlZGVyYXRpb24uc2VydmljZVwiO1xuaW1wb3J0IHsgU2VjcmV0c1NlcnZpY2UgfSBmcm9tIFwiLi9zZWNyZXRzLnNlcnZpY2VcIjtcblxuZXhwb3J0IGNsYXNzIFBsdWdpblJlZ2lzdHJ5VGFnIGV4dGVuZHMgQ29udGV4dC5UYWcoXCJQbHVnaW5SZWdpc3RyeVwiKTxcblx0UGx1Z2luUmVnaXN0cnlUYWcsXG5cdFBsdWdpblJlZ2lzdHJ5XG4+KCkgeyB9XG5cbmV4cG9ydCBjbGFzcyBSZWdpc3RyeVNlcnZpY2UgZXh0ZW5kcyBFZmZlY3QuU2VydmljZTxSZWdpc3RyeVNlcnZpY2U+KCkoXCJSZWdpc3RyeVNlcnZpY2VcIiwge1xuXHRlZmZlY3Q6IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRjb25zdCByZWdpc3RyeSA9IHlpZWxkKiBQbHVnaW5SZWdpc3RyeVRhZztcblxuXHRcdHJldHVybiB7XG5cdFx0XHRnZXQ6IChwbHVnaW5JZDogc3RyaW5nKSA9PlxuXHRcdFx0XHRFZmZlY3QuZnJvbU51bGxhYmxlKHJlZ2lzdHJ5W3BsdWdpbklkXSkucGlwZShcblx0XHRcdFx0XHRFZmZlY3QubWFwRXJyb3IoKCkgPT5cblx0XHRcdFx0XHRcdG5ldyBQbHVnaW5SdW50aW1lRXJyb3Ioe1xuXHRcdFx0XHRcdFx0XHRwbHVnaW5JZCxcblx0XHRcdFx0XHRcdFx0b3BlcmF0aW9uOiBcInZhbGlkYXRlLXBsdWdpbi1pZFwiLFxuXHRcdFx0XHRcdFx0XHRjYXVzZTogbmV3IEVycm9yKGBQbHVnaW4gJHtwbHVnaW5JZH0gbm90IGZvdW5kIGluIHJlZ2lzdHJ5YCksXG5cdFx0XHRcdFx0XHRcdHJldHJ5YWJsZTogZmFsc2UsXG5cdFx0XHRcdFx0XHR9KSxcblx0XHRcdFx0XHQpLFxuXHRcdFx0XHQpLFxuXHRcdH07XG5cdH0pLFxufSkgeyB9XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5Mb2FkZXJTZXJ2aWNlIGV4dGVuZHMgRWZmZWN0LlNlcnZpY2U8UGx1Z2luTG9hZGVyU2VydmljZT4oKShcIlBsdWdpbkxvYWRlclNlcnZpY2VcIiwge1xuXHRlZmZlY3Q6IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRjb25zdCBtb2R1bGVGZWRlcmF0aW9uU2VydmljZSA9IHlpZWxkKiBNb2R1bGVGZWRlcmF0aW9uU2VydmljZTtcblx0XHRjb25zdCBzZWNyZXRzU2VydmljZSA9IHlpZWxkKiBTZWNyZXRzU2VydmljZTtcblx0XHRjb25zdCByZWdpc3RyeVNlcnZpY2UgPSB5aWVsZCogUmVnaXN0cnlTZXJ2aWNlO1xuXG5cdFx0Y29uc3QgcmVzb2x2ZVVybCA9IChiYXNlVXJsOiBzdHJpbmcsIHZlcnNpb24/OiBzdHJpbmcpOiBzdHJpbmcgPT5cblx0XHRcdHZlcnNpb24gJiYgdmVyc2lvbiAhPT0gXCJsYXRlc3RcIlxuXHRcdFx0XHQ/IGJhc2VVcmwucmVwbGFjZShcIkBsYXRlc3RcIiwgYEAke3ZlcnNpb259YClcblx0XHRcdFx0OiBiYXNlVXJsO1xuXG5cdFx0Y29uc3QgZ2V0TWV0YWRhdGEgPSAocGx1Z2luSWQ6IHN0cmluZykgPT4gcmVnaXN0cnlTZXJ2aWNlLmdldChwbHVnaW5JZCk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0bG9hZFBsdWdpbjogKHBsdWdpbklkOiBzdHJpbmcpID0+XG5cdFx0XHRcdEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRcdFx0XHRjb25zdCBtZXRhZGF0YSA9IHlpZWxkKiBnZXRNZXRhZGF0YShwbHVnaW5JZCk7XG5cdFx0XHRcdFx0Y29uc3QgdXJsID0gcmVzb2x2ZVVybChtZXRhZGF0YS5yZW1vdGVVcmwpO1xuXG5cdFx0XHRcdFx0eWllbGQqIG1vZHVsZUZlZGVyYXRpb25TZXJ2aWNlLnJlZ2lzdGVyUmVtb3RlKHBsdWdpbklkLCB1cmwpLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QubWFwRXJyb3IoKGVycm9yKSA9PlxuXHRcdFx0XHRcdFx0XHR0b1BsdWdpblJ1bnRpbWVFcnJvcihlcnJvciwgcGx1Z2luSWQsIHVuZGVmaW5lZCwgXCJyZWdpc3Rlci1yZW1vdGVcIiwgdHJ1ZSksXG5cdFx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHR5aWVsZCogRWZmZWN0LmxvZ0RlYnVnKFwiTG9hZGluZyBwbHVnaW5cIiwgeyBwbHVnaW5JZCwgdXJsIH0pO1xuXG5cdFx0XHRcdFx0Y29uc3QgY3RvciA9IHlpZWxkKiBtb2R1bGVGZWRlcmF0aW9uU2VydmljZS5sb2FkUmVtb3RlQ29uc3RydWN0b3IocGx1Z2luSWQsIHVybCkucGlwZShcblx0XHRcdFx0XHRcdEVmZmVjdC5tYXBFcnJvcigoZXJyb3IpID0+XG5cdFx0XHRcdFx0XHRcdHRvUGx1Z2luUnVudGltZUVycm9yKGVycm9yLCBwbHVnaW5JZCwgdW5kZWZpbmVkLCBcImxvYWQtcmVtb3RlXCIsIGZhbHNlKSxcblx0XHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XHRjdG9yLFxuXHRcdFx0XHRcdFx0bWV0YWRhdGE6IG1ldGFkYXRhLFxuXHRcdFx0XHRcdH0gc2F0aXNmaWVzIExvYWRlZFBsdWdpbjtcblx0XHRcdFx0fSksXG5cblx0XHRcdGluc3RhbnRpYXRlUGx1Z2luOiA8VCBleHRlbmRzIEFueVBsdWdpbj4oXG5cdFx0XHRcdHBsdWdpbklkOiBzdHJpbmcsXG5cdFx0XHRcdGxvYWRlZFBsdWdpbjogTG9hZGVkUGx1Z2luPFQ+LFxuXHRcdFx0KSA9PlxuXHRcdFx0XHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdFx0Y29uc3QgaW5zdGFuY2UgPSB5aWVsZCogRWZmZWN0LnRyeSgoKSA9PiBuZXcgbG9hZGVkUGx1Z2luLmN0b3IoKSkucGlwZShcblx0XHRcdFx0XHRcdEVmZmVjdC5tYXBFcnJvcigoZXJyb3IpID0+XG5cdFx0XHRcdFx0XHRcdHRvUGx1Z2luUnVudGltZUVycm9yKFxuXHRcdFx0XHRcdFx0XHRcdGVycm9yLFxuXHRcdFx0XHRcdFx0XHRcdHBsdWdpbklkLFxuXHRcdFx0XHRcdFx0XHRcdHVuZGVmaW5lZCxcblx0XHRcdFx0XHRcdFx0XHRcImluc3RhbnRpYXRlLXBsdWdpblwiLFxuXHRcdFx0XHRcdFx0XHRcdGZhbHNlLFxuXHRcdFx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdFx0KSxcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0KGluc3RhbmNlLmlkIGFzIHN0cmluZykgPSBwbHVnaW5JZDtcblxuXHRcdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XHRwbHVnaW46IGluc3RhbmNlLFxuXHRcdFx0XHRcdFx0bWV0YWRhdGE6IGxvYWRlZFBsdWdpbi5tZXRhZGF0YSxcblx0XHRcdFx0XHR9IHNhdGlzZmllcyBQbHVnaW5JbnN0YW5jZTxUPjtcblx0XHRcdFx0fSksXG5cblx0XHRcdGluaXRpYWxpemVQbHVnaW46IDxUIGV4dGVuZHMgQW55UGx1Z2luPihcblx0XHRcdFx0cGx1Z2luSW5zdGFuY2U6IFBsdWdpbkluc3RhbmNlPFQ+LFxuXHRcdFx0XHRjb25maWc6IHsgdmFyaWFibGVzOiBJbmZlclNjaGVtYUlucHV0PFRbXCJjb25maWdTY2hlbWFcIl1bXCJ2YXJpYWJsZXNcIl0+OyBzZWNyZXRzOiBJbmZlclNjaGVtYUlucHV0PFRbXCJjb25maWdTY2hlbWFcIl1bXCJzZWNyZXRzXCJdPiB9LFxuXHRcdFx0KSA9PlxuXHRcdFx0XHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdFx0Y29uc3QgeyBwbHVnaW4gfSA9IHBsdWdpbkluc3RhbmNlO1xuXG5cdFx0XHRcdFx0Ly8gVmFsaWRhdGUgYW5kIGh5ZHJhdGUgY29uZmlnXG5cdFx0XHRcdFx0Y29uc3QgdmFsaWRhdGVkVmFyaWFibGVzID0geWllbGQqIHZhbGlkYXRlKFxuXHRcdFx0XHRcdFx0cGx1Z2luLmNvbmZpZ1NjaGVtYS52YXJpYWJsZXMgYXMgei5ab2RTY2hlbWE8SW5mZXJTY2hlbWFPdXRwdXQ8VFtcImNvbmZpZ1NjaGVtYVwiXVtcInZhcmlhYmxlc1wiXT4+LFxuXHRcdFx0XHRcdFx0Y29uZmlnLnZhcmlhYmxlcyxcblx0XHRcdFx0XHRcdHBsdWdpbi5pZCxcblx0XHRcdFx0XHRcdFwiY29uZmlnXCIsXG5cdFx0XHRcdFx0KS5waXBlKFxuXHRcdFx0XHRcdFx0RWZmZWN0Lm1hcEVycm9yKCh2YWxpZGF0aW9uRXJyb3IpID0+XG5cdFx0XHRcdFx0XHRcdG5ldyBQbHVnaW5SdW50aW1lRXJyb3Ioe1xuXHRcdFx0XHRcdFx0XHRcdHBsdWdpbklkOiBwbHVnaW4uaWQsXG5cdFx0XHRcdFx0XHRcdFx0b3BlcmF0aW9uOiBcInZhbGlkYXRlLWNvbmZpZ1wiLFxuXHRcdFx0XHRcdFx0XHRcdGNhdXNlOiB2YWxpZGF0aW9uRXJyb3Iuem9kRXJyb3IsXG5cdFx0XHRcdFx0XHRcdFx0cmV0cnlhYmxlOiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0fSksXG5cdFx0XHRcdFx0XHQpLFxuXHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHQvLyBWYWxpZGF0ZSBzZWNyZXRzXG5cdFx0XHRcdFx0Y29uc3QgdmFsaWRhdGVkU2VjcmV0cyA9IHlpZWxkKiB2YWxpZGF0ZShcblx0XHRcdFx0XHRcdHBsdWdpbi5jb25maWdTY2hlbWEuc2VjcmV0cyBhcyB6LlpvZFNjaGVtYTxJbmZlclNjaGVtYU91dHB1dDxUW1wiY29uZmlnU2NoZW1hXCJdW1wic2VjcmV0c1wiXT4+LFxuXHRcdFx0XHRcdFx0Y29uZmlnLnNlY3JldHMsXG5cdFx0XHRcdFx0XHRwbHVnaW4uaWQsXG5cdFx0XHRcdFx0XHRcImNvbmZpZ1wiLFxuXHRcdFx0XHRcdCkucGlwZShcblx0XHRcdFx0XHRcdEVmZmVjdC5tYXBFcnJvcigodmFsaWRhdGlvbkVycm9yKSA9PlxuXHRcdFx0XHRcdFx0XHRuZXcgUGx1Z2luUnVudGltZUVycm9yKHtcblx0XHRcdFx0XHRcdFx0XHRwbHVnaW5JZDogcGx1Z2luLmlkLFxuXHRcdFx0XHRcdFx0XHRcdG9wZXJhdGlvbjogXCJ2YWxpZGF0ZS1zZWNyZXRzXCIsXG5cdFx0XHRcdFx0XHRcdFx0Y2F1c2U6IHZhbGlkYXRpb25FcnJvci56b2RFcnJvcixcblx0XHRcdFx0XHRcdFx0XHRyZXRyeWFibGU6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHR9KSxcblx0XHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdC8vIEh5ZHJhdGUgc2VjcmV0cyBpbiB2YXJpYWJsZXNcblx0XHRcdFx0XHRjb25zdCBoeWRyYXRlZENvbmZpZyA9IHlpZWxkKiBzZWNyZXRzU2VydmljZS5oeWRyYXRlU2VjcmV0cyh7XG5cdFx0XHRcdFx0XHR2YXJpYWJsZXM6IHZhbGlkYXRlZFZhcmlhYmxlcyxcblx0XHRcdFx0XHRcdHNlY3JldHM6IHZhbGlkYXRlZFNlY3JldHMsXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRjb25zdCBfdmFyaWFibGVzID0geWllbGQqIHZhbGlkYXRlKFxuXHRcdFx0XHRcdFx0cGx1Z2luLmNvbmZpZ1NjaGVtYS52YXJpYWJsZXMgYXMgei5ab2RTY2hlbWE8SW5mZXJTY2hlbWFPdXRwdXQ8VFtcImNvbmZpZ1NjaGVtYVwiXVtcInZhcmlhYmxlc1wiXT4+LFxuXHRcdFx0XHRcdFx0aHlkcmF0ZWRDb25maWcudmFyaWFibGVzLFxuXHRcdFx0XHRcdFx0cGx1Z2luLmlkLFxuXHRcdFx0XHRcdFx0XCJjb25maWdcIixcblx0XHRcdFx0XHQpLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QubWFwRXJyb3IoKHZhbGlkYXRpb25FcnJvcikgPT5cblx0XHRcdFx0XHRcdFx0bmV3IFBsdWdpblJ1bnRpbWVFcnJvcih7XG5cdFx0XHRcdFx0XHRcdFx0cGx1Z2luSWQ6IHBsdWdpbi5pZCxcblx0XHRcdFx0XHRcdFx0XHRvcGVyYXRpb246IFwidmFsaWRhdGUtaHlkcmF0ZWQtY29uZmlnXCIsXG5cdFx0XHRcdFx0XHRcdFx0Y2F1c2U6IHZhbGlkYXRpb25FcnJvci56b2RFcnJvcixcblx0XHRcdFx0XHRcdFx0XHRyZXRyeWFibGU6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHR9KSxcblx0XHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdC8vIENyZWF0ZSBhIGxvbmctbGl2ZWQgc2NvcGUgZm9yIHRoaXMgcGx1Z2luIGluc3RhbmNlXG5cdFx0XHRcdFx0Y29uc3Qgc2NvcGUgPSB5aWVsZCogU2NvcGUubWFrZSgpO1xuXG5cdFx0XHRcdFx0Ly8gSW5pdGlhbGl6ZSBwbHVnaW4gd2l0aGluIHRoZSBzY29wZVxuXHRcdFx0XHRcdGNvbnN0IGNvbnRleHQgPSB5aWVsZCogcGx1Z2luLmluaXRpYWxpemUoeyB2YXJpYWJsZXM6IF92YXJpYWJsZXMsIHNlY3JldHM6IGh5ZHJhdGVkQ29uZmlnLnNlY3JldHMgfSkucGlwZShcblx0XHRcdFx0XHRcdEVmZmVjdC5wcm92aWRlU2VydmljZShTY29wZS5TY29wZSwgc2NvcGUpLFxuXHRcdFx0XHRcdFx0RWZmZWN0Lm1hcEVycm9yKChlcnJvcikgPT5cblx0XHRcdFx0XHRcdFx0dG9QbHVnaW5SdW50aW1lRXJyb3IoZXJyb3IsIHBsdWdpbi5pZCwgdW5kZWZpbmVkLCBcImluaXRpYWxpemUtcGx1Z2luXCIsIGZhbHNlKSxcblx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdHBsdWdpbixcblx0XHRcdFx0XHRcdG1ldGFkYXRhOiBwbHVnaW5JbnN0YW5jZS5tZXRhZGF0YSxcblx0XHRcdFx0XHRcdGNvbmZpZzogeyB2YXJpYWJsZXM6IF92YXJpYWJsZXMsIHNlY3JldHM6IGh5ZHJhdGVkQ29uZmlnLnNlY3JldHMgfSxcblx0XHRcdFx0XHRcdGNvbnRleHQsXG5cdFx0XHRcdFx0XHRzY29wZSxcblx0XHRcdFx0XHR9IHNhdGlzZmllcyBJbml0aWFsaXplZFBsdWdpbjxUPjtcblx0XHRcdFx0fSksXG5cdFx0fTtcblx0fSksXG59KSB7XG59XG4iLCJpbXBvcnQgeyBFZmZlY3QsIEV4aXQsIExheWVyLCBTY29wZSB9IGZyb20gXCJlZmZlY3RcIjtcbmltcG9ydCB0eXBlIHtcblx0QW55UGx1Z2luLFxuXHRJbml0aWFsaXplZFBsdWdpbixcblx0UGx1Z2luUmVnaXN0cnksXG5cdFNlY3JldHNDb25maWdcbn0gZnJvbSBcIi4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBNb2R1bGVGZWRlcmF0aW9uU2VydmljZSB9IGZyb20gXCIuL21vZHVsZS1mZWRlcmF0aW9uLnNlcnZpY2VcIjtcbmltcG9ydCB7IFBsdWdpbkxpZmVjeWNsZVNlcnZpY2UgfSBmcm9tIFwiLi9wbHVnaW4tbGlmZWN5Y2xlLnNlcnZpY2VcIjtcbmltcG9ydCB7IFBsdWdpbkxvYWRlclNlcnZpY2UsIFBsdWdpblJlZ2lzdHJ5VGFnLCBSZWdpc3RyeVNlcnZpY2UgfSBmcm9tIFwiLi9wbHVnaW4tbG9hZGVyLnNlcnZpY2VcIjtcbmltcG9ydCB7IFNlY3JldHNDb25maWdUYWcsIFNlY3JldHNTZXJ2aWNlIH0gZnJvbSBcIi4vc2VjcmV0cy5zZXJ2aWNlXCI7XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5TZXJ2aWNlIGV4dGVuZHMgRWZmZWN0LlNlcnZpY2U8UGx1Z2luU2VydmljZT4oKShcIlBsdWdpblNlcnZpY2VcIiwge1xuXHRzY29wZWQ6IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRjb25zdCBsb2FkZXIgPSB5aWVsZCogUGx1Z2luTG9hZGVyU2VydmljZTtcblx0XHRjb25zdCBsaWZlY3ljbGUgPSB5aWVsZCogUGx1Z2luTGlmZWN5Y2xlU2VydmljZTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHRsb2FkUGx1Z2luOiBsb2FkZXIubG9hZFBsdWdpbixcblx0XHRcdGluc3RhbnRpYXRlUGx1Z2luOiBsb2FkZXIuaW5zdGFudGlhdGVQbHVnaW4sXG5cdFx0XHRpbml0aWFsaXplUGx1Z2luOiBsb2FkZXIuaW5pdGlhbGl6ZVBsdWdpbixcblx0XHRcdHNodXRkb3duUGx1Z2luOiAocGx1Z2luOiBJbml0aWFsaXplZFBsdWdpbjxBbnlQbHVnaW4+KSA9PlxuXHRcdFx0XHRFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRcdFx0Ly8gU2h1dGRvd24gdGhlIHBsdWdpbiBmaXJzdCAoZ3JhY2VmdWwgY2xlYW51cClcblx0XHRcdFx0XHR5aWVsZCogcGx1Z2luLnBsdWdpbi5zaHV0ZG93bigpLnBpcGUoXG5cdFx0XHRcdFx0XHRFZmZlY3QuY2F0Y2hBbGwoKCkgPT4gRWZmZWN0LnZvaWQpXG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdC8vIENsb3NlIHRoZSBwbHVnaW4gc2NvcGUgdG8gaW50ZXJydXB0IGZpYmVycyBhbmQgcmVsZWFzZSByZXNvdXJjZXNcblx0XHRcdFx0XHR5aWVsZCogU2NvcGUuY2xvc2UocGx1Z2luLnNjb3BlLCBFeGl0LnN1Y2NlZWQodW5kZWZpbmVkKSk7XG5cblx0XHRcdFx0XHQvLyBVbnJlZ2lzdGVyIGZyb20gbGlmZWN5Y2xlIHRyYWNraW5nXG5cdFx0XHRcdFx0eWllbGQqIGxpZmVjeWNsZS51bnJlZ2lzdGVyKHBsdWdpbik7XG5cdFx0XHRcdH0pLFxuXHRcdFx0Y2xlYW51cDogbGlmZWN5Y2xlLmNsZWFudXAsXG5cdFx0fTtcblx0fSksXG59KSB7XG5cdHN0YXRpYyBMaXZlID0gKHJlZ2lzdHJ5OiBQbHVnaW5SZWdpc3RyeSwgc2VjcmV0czogU2VjcmV0c0NvbmZpZykgPT4ge1xuXHRcdGNvbnN0IGNvbnRleHRMYXllciA9IExheWVyLm1lcmdlQWxsKFxuXHRcdFx0TGF5ZXIuc3VjY2VlZChQbHVnaW5SZWdpc3RyeVRhZywgcmVnaXN0cnkpLFxuXHRcdFx0TGF5ZXIuc3VjY2VlZChTZWNyZXRzQ29uZmlnVGFnLCBzZWNyZXRzKSxcblx0XHQpO1xuXG5cdFx0Y29uc3Qgc2VydmljZXNMYXllciA9IExheWVyLm1lcmdlQWxsKFxuXHRcdFx0TW9kdWxlRmVkZXJhdGlvblNlcnZpY2UuRGVmYXVsdCxcblx0XHRcdFNlY3JldHNTZXJ2aWNlLkRlZmF1bHQsXG5cdFx0XHRSZWdpc3RyeVNlcnZpY2UuRGVmYXVsdCxcblx0XHRcdFBsdWdpbkxpZmVjeWNsZVNlcnZpY2UuRGVmYXVsdCxcblx0XHQpLnBpcGUoXG5cdFx0XHRMYXllci5wcm92aWRlKGNvbnRleHRMYXllcilcblx0XHQpO1xuXG5cdFx0cmV0dXJuIFBsdWdpblNlcnZpY2UuRGVmYXVsdC5waXBlKFxuXHRcdFx0TGF5ZXIucHJvdmlkZShQbHVnaW5Mb2FkZXJTZXJ2aWNlLkRlZmF1bHQpLFxuXHRcdFx0TGF5ZXIucHJvdmlkZShzZXJ2aWNlc0xheWVyKVxuXHRcdCk7XG5cdH1cbn1cbiIsImltcG9ydCB7IGNyZWF0ZVJvdXRlckNsaWVudCB9IGZyb20gXCJAb3JwYy9zZXJ2ZXJcIjtcbmltcG9ydCB7IENhdXNlLCBFZmZlY3QsIEV4aXQsIEhhc2gsIE1hbmFnZWRSdW50aW1lLCBPcHRpb24gfSBmcm9tIFwiZWZmZWN0XCI7XG5pbXBvcnQgdHlwZSB7XG5cdEFueVBsdWdpbixcblx0SW5pdGlhbGl6ZWRQbHVnaW4sXG5cdExvYWRlZFBsdWdpbixcblx0UGx1Z2luQ2xpZW50VHlwZSxcblx0UGx1Z2luQ29uZmlnSW5wdXQsXG5cdFBsdWdpbkluc3RhbmNlLFxuXHRQbHVnaW5SZWdpc3RyeSxcblx0UGx1Z2luUm91dGVyVHlwZSxcblx0UGx1Z2luUnVudGltZUNvbmZpZyxcblx0UmVnaXN0ZXJlZFBsdWdpbixcblx0UmVnaXN0ZXJlZFBsdWdpbnMsXG5cdFVzZVBsdWdpblJlc3VsdFxufSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IFBsdWdpblJ1bnRpbWVFcnJvciB9IGZyb20gXCIuL2Vycm9yc1wiO1xuaW1wb3J0IHsgUGx1Z2luU2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL3BsdWdpbi5zZXJ2aWNlXCI7XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5SdW50aW1lPFIgZXh0ZW5kcyBSZWdpc3RlcmVkUGx1Z2lucyA9IFJlZ2lzdGVyZWRQbHVnaW5zPiB7XG5cdHByaXZhdGUgcGx1Z2luQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgRWZmZWN0LkVmZmVjdDxJbml0aWFsaXplZFBsdWdpbjxBbnlQbHVnaW4+LCBQbHVnaW5SdW50aW1lRXJyb3I+PigpO1xuXG5cdGNvbnN0cnVjdG9yKFxuXHRcdHByaXZhdGUgcnVudGltZTogTWFuYWdlZFJ1bnRpbWUuTWFuYWdlZFJ1bnRpbWU8UGx1Z2luU2VydmljZSwgbmV2ZXI+LFxuXHRcdHByaXZhdGUgcmVnaXN0cnk6IFBsdWdpblJlZ2lzdHJ5XG5cdCkgeyB9XG5cblx0cHJpdmF0ZSBnZW5lcmF0ZUNhY2hlS2V5KHBsdWdpbklkOiBzdHJpbmcsIGNvbmZpZzogdW5rbm93bik6IHN0cmluZyB7XG5cdFx0Y29uc3QgY29uZmlnSGFzaCA9IEhhc2guc3RydWN0dXJlKGNvbmZpZyBhcyBvYmplY3QpLnRvU3RyaW5nKCk7XG5cdFx0cmV0dXJuIGAke3BsdWdpbklkfToke2NvbmZpZ0hhc2h9YDtcblx0fVxuXG5cdHByaXZhdGUgdmFsaWRhdGVQbHVnaW5JZChcblx0XHRwbHVnaW5JZDogc3RyaW5nXG5cdCk6IEVmZmVjdC5FZmZlY3Q8c3RyaW5nLCBQbHVnaW5SdW50aW1lRXJyb3I+IHtcblx0XHRpZiAoIShwbHVnaW5JZCBpbiB0aGlzLnJlZ2lzdHJ5KSkge1xuXHRcdFx0cmV0dXJuIEVmZmVjdC5mYWlsKG5ldyBQbHVnaW5SdW50aW1lRXJyb3Ioe1xuXHRcdFx0XHRwbHVnaW5JZDogU3RyaW5nKHBsdWdpbklkKSxcblx0XHRcdFx0b3BlcmF0aW9uOiBcInZhbGlkYXRlLXBsdWdpbi1pZFwiLFxuXHRcdFx0XHRjYXVzZTogbmV3IEVycm9yKGBQbHVnaW4gSUQgJyR7U3RyaW5nKHBsdWdpbklkKX0nIG5vdCBmb3VuZCBpbiByZWdpc3RyeS5gKSxcblx0XHRcdFx0cmV0cnlhYmxlOiBmYWxzZSxcblx0XHRcdH0pKTtcblx0XHR9XG5cdFx0cmV0dXJuIEVmZmVjdC5zdWNjZWVkKFN0cmluZyhwbHVnaW5JZCkpO1xuXHR9XG5cblx0cHJpdmF0ZSBhc3luYyBydW5Qcm9taXNlPEEsIEU+KFxuXHRcdGVmZmVjdDogRWZmZWN0LkVmZmVjdDxBLCBFLCBQbHVnaW5TZXJ2aWNlPlxuXHQpOiBQcm9taXNlPEE+IHtcblx0XHRjb25zdCBleGl0ID0gYXdhaXQgdGhpcy5ydW50aW1lLnJ1blByb21pc2VFeGl0KGVmZmVjdCk7XG5cblx0XHRpZiAoRXhpdC5pc0ZhaWx1cmUoZXhpdCkpIHtcblx0XHRcdGNvbnN0IGVycm9yID0gQ2F1c2UuZmFpbHVyZU9wdGlvbihleGl0LmNhdXNlKTtcblx0XHRcdGlmIChPcHRpb24uaXNTb21lKGVycm9yKSkge1xuXHRcdFx0XHR0aHJvdyBlcnJvci52YWx1ZTtcblx0XHRcdH1cblx0XHRcdHRocm93IENhdXNlLnNxdWFzaChleGl0LmNhdXNlKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZXhpdC52YWx1ZTtcblx0fVxuXG5cdGFzeW5jIHVzZVBsdWdpbjxLIGV4dGVuZHMga2V5b2YgUmVnaXN0ZXJlZFBsdWdpbnMgJiBzdHJpbmc+KFxuXHRcdHBsdWdpbklkOiBLLFxuXHRcdGNvbmZpZzogUGx1Z2luQ29uZmlnSW5wdXQ8UltLXT5cblx0KTogUHJvbWlzZTxVc2VQbHVnaW5SZXN1bHQ8Sz4+IHtcblx0XHRjb25zdCBjYWNoZUtleSA9IHRoaXMuZ2VuZXJhdGVDYWNoZUtleShwbHVnaW5JZCwgY29uZmlnKTtcblxuXHRcdGxldCBjYWNoZWRQbHVnaW4gPSB0aGlzLnBsdWdpbkNhY2hlLmdldChjYWNoZUtleSk7XG5cdFx0aWYgKCFjYWNoZWRQbHVnaW4pIHtcblx0XHRcdGNvbnN0IG9wZXJhdGlvbiA9IEVmZmVjdC5nZW4odGhpcywgZnVuY3Rpb24qICgpIHtcblx0XHRcdFx0Y29uc3QgcGx1Z2luU2VydmljZSA9IHlpZWxkKiBQbHVnaW5TZXJ2aWNlO1xuXHRcdFx0XHRjb25zdCB2YWxpZGF0ZWRJZCA9IHlpZWxkKiB0aGlzLnZhbGlkYXRlUGx1Z2luSWQocGx1Z2luSWQpO1xuXG5cdFx0XHRcdC8vIExvYWQg4oaSIEluc3RhbnRpYXRlIOKGkiBJbml0aWFsaXplXG5cdFx0XHRcdGNvbnN0IGN0b3IgPSB5aWVsZCogcGx1Z2luU2VydmljZS5sb2FkUGx1Z2luKHZhbGlkYXRlZElkKTtcblx0XHRcdFx0Y29uc3QgaW5zdGFuY2UgPSB5aWVsZCogcGx1Z2luU2VydmljZS5pbnN0YW50aWF0ZVBsdWdpbihwbHVnaW5JZCwgY3Rvcik7XG5cdFx0XHRcdGNvbnN0IGluaXRpYWxpemVkID0geWllbGQqIHBsdWdpblNlcnZpY2UuaW5pdGlhbGl6ZVBsdWdpbihpbnN0YW5jZSwgY29uZmlnKTtcblxuXHRcdFx0XHRyZXR1cm4gaW5pdGlhbGl6ZWQ7XG5cdFx0XHR9KS5waXBlKEVmZmVjdC5wcm92aWRlKHRoaXMucnVudGltZSkpO1xuXG5cdFx0XHRjYWNoZWRQbHVnaW4gPSBFZmZlY3QuY2FjaGVkKG9wZXJhdGlvbikucGlwZShFZmZlY3QuZmxhdHRlbik7XG5cdFx0XHR0aGlzLnBsdWdpbkNhY2hlLnNldChjYWNoZUtleSwgY2FjaGVkUGx1Z2luKTtcblx0XHR9XG5cblx0XHRjb25zdCBpbml0aWFsaXplZCA9IGF3YWl0IHRoaXMucnVuUHJvbWlzZShjYWNoZWRQbHVnaW4pO1xuXHRcdGNvbnN0IHJvdXRlciA9IGluaXRpYWxpemVkLnBsdWdpbi5jcmVhdGVSb3V0ZXIoaW5pdGlhbGl6ZWQuY29udGV4dCk7XG5cdFx0Y29uc3QgY2xpZW50ID0gY3JlYXRlUm91dGVyQ2xpZW50KHJvdXRlcik7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0cm91dGVyOiByb3V0ZXIgYXMgUGx1Z2luUm91dGVyVHlwZTxSW0tdPixcblx0XHRcdGNsaWVudDogY2xpZW50IGFzIFBsdWdpbkNsaWVudFR5cGU8UltLXT4sXG5cdFx0XHRtZXRhZGF0YTogaW5pdGlhbGl6ZWQubWV0YWRhdGEsXG5cdFx0XHRpbml0aWFsaXplZDogaW5pdGlhbGl6ZWQgYXMgSW5pdGlhbGl6ZWRQbHVnaW48UmVnaXN0ZXJlZFBsdWdpbjxLPj5cblx0XHR9IGFzIFVzZVBsdWdpblJlc3VsdDxLPjtcblx0fVxuXG5cdGFzeW5jIGxvYWRQbHVnaW48SyBleHRlbmRzIGtleW9mIFJlZ2lzdGVyZWRQbHVnaW5zICYgc3RyaW5nPihcblx0XHRwbHVnaW5JZDogS1xuXHQpOiBQcm9taXNlPExvYWRlZFBsdWdpbjxSZWdpc3RlcmVkUGx1Z2luPEs+Pj4ge1xuXHRcdGNvbnN0IGVmZmVjdCA9IEVmZmVjdC5nZW4oZnVuY3Rpb24qICgpIHtcblx0XHRcdGNvbnN0IHBsdWdpblNlcnZpY2UgPSB5aWVsZCogUGx1Z2luU2VydmljZTtcblx0XHRcdHJldHVybiB5aWVsZCogcGx1Z2luU2VydmljZS5sb2FkUGx1Z2luKHBsdWdpbklkKTtcblx0XHR9KTtcblx0XHRyZXR1cm4gdGhpcy5ydW5Qcm9taXNlKGVmZmVjdCkgYXMgUHJvbWlzZTxMb2FkZWRQbHVnaW48UmVnaXN0ZXJlZFBsdWdpbjxLPj4+O1xuXHR9XG5cblx0YXN5bmMgaW5zdGFudGlhdGVQbHVnaW48SyBleHRlbmRzIGtleW9mIFJlZ2lzdGVyZWRQbHVnaW5zICYgc3RyaW5nPihcblx0XHRwbHVnaW5JZDogSyxcblx0XHRsb2FkZWRQbHVnaW46IExvYWRlZFBsdWdpbjxSZWdpc3RlcmVkUGx1Z2luPEs+PlxuXHQpOiBQcm9taXNlPFBsdWdpbkluc3RhbmNlPFJlZ2lzdGVyZWRQbHVnaW48Sz4+PiB7XG5cdFx0Y29uc3QgZWZmZWN0ID0gRWZmZWN0LmdlbihmdW5jdGlvbiogKCkge1xuXHRcdFx0Y29uc3QgcGx1Z2luU2VydmljZSA9IHlpZWxkKiBQbHVnaW5TZXJ2aWNlO1xuXHRcdFx0cmV0dXJuIHlpZWxkKiBwbHVnaW5TZXJ2aWNlLmluc3RhbnRpYXRlUGx1Z2luKHBsdWdpbklkLCBsb2FkZWRQbHVnaW4pO1xuXHRcdH0pO1xuXHRcdHJldHVybiB0aGlzLnJ1blByb21pc2UoZWZmZWN0KSBhcyBQcm9taXNlPFBsdWdpbkluc3RhbmNlPFJlZ2lzdGVyZWRQbHVnaW48Sz4+Pjtcblx0fVxuXG5cdGFzeW5jIGluaXRpYWxpemVQbHVnaW48VCBleHRlbmRzIEFueVBsdWdpbj4oXG5cdFx0aW5zdGFuY2U6IFBsdWdpbkluc3RhbmNlPFQ+LFxuXHRcdGNvbmZpZzogYW55XG5cdCk6IFByb21pc2U8SW5pdGlhbGl6ZWRQbHVnaW48VD4+IHtcblx0XHRjb25zdCBlZmZlY3QgPSBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRjb25zdCBwbHVnaW5TZXJ2aWNlID0geWllbGQqIFBsdWdpblNlcnZpY2U7XG5cdFx0XHRyZXR1cm4geWllbGQqIHBsdWdpblNlcnZpY2UuaW5pdGlhbGl6ZVBsdWdpbihpbnN0YW5jZSwgY29uZmlnKTtcblx0XHR9KTtcblx0XHRyZXR1cm4gdGhpcy5ydW5Qcm9taXNlKGVmZmVjdCk7XG5cdH1cblxuXHRhc3luYyBzaHV0ZG93bigpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRjb25zdCBlZmZlY3QgPSBFZmZlY3QuZ2VuKGZ1bmN0aW9uKiAoKSB7XG5cdFx0XHRjb25zdCBwbHVnaW5TZXJ2aWNlID0geWllbGQqIFBsdWdpblNlcnZpY2U7XG5cdFx0XHR5aWVsZCogcGx1Z2luU2VydmljZS5jbGVhbnVwKCk7XG5cdFx0fSk7XG5cdFx0cmV0dXJuIHRoaXMucnVuUHJvbWlzZShlZmZlY3QpO1xuXHR9XG5cblx0YXN5bmMgZXZpY3RQbHVnaW48SyBleHRlbmRzIGtleW9mIFJlZ2lzdGVyZWRQbHVnaW5zICYgc3RyaW5nPihcblx0XHRwbHVnaW5JZDogSyxcblx0XHRjb25maWc6IFBsdWdpbkNvbmZpZ0lucHV0PFJlZ2lzdGVyZWRQbHVnaW5zW0tdPlxuXHQpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRjb25zdCBjYWNoZUtleSA9IHRoaXMuZ2VuZXJhdGVDYWNoZUtleShwbHVnaW5JZCwgY29uZmlnKTtcblxuXHRcdGNvbnN0IGVmZmVjdCA9IEVmZmVjdC5nZW4odGhpcywgZnVuY3Rpb24qICgpIHtcblx0XHRcdGNvbnN0IHBsdWdpblNlcnZpY2UgPSB5aWVsZCogUGx1Z2luU2VydmljZTtcblx0XHRcdGNvbnN0IGNhY2hlZFBsdWdpbiA9IHRoaXMucGx1Z2luQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcblxuXHRcdFx0aWYgKGNhY2hlZFBsdWdpbikge1xuXHRcdFx0XHR0aGlzLnBsdWdpbkNhY2hlLmRlbGV0ZShjYWNoZUtleSk7XG5cblx0XHRcdFx0Y29uc3QgcGx1Z2luUmVzdWx0ID0geWllbGQqIGNhY2hlZFBsdWdpbi5waXBlKFxuXHRcdFx0XHRcdEVmZmVjdC5jYXRjaEFsbCgoKSA9PiBFZmZlY3Quc3VjY2VlZChudWxsKSlcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRpZiAocGx1Z2luUmVzdWx0KSB7XG5cdFx0XHRcdFx0eWllbGQqIHBsdWdpblNlcnZpY2Uuc2h1dGRvd25QbHVnaW4ocGx1Z2luUmVzdWx0KS5waXBlKFxuXHRcdFx0XHRcdFx0RWZmZWN0LmNhdGNoQWxsKCgpID0+IEVmZmVjdC52b2lkKVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9KS5waXBlKEVmZmVjdC5jYXRjaEFsbCgoKSA9PiBFZmZlY3Qudm9pZCkpO1xuXG5cdFx0cmV0dXJuIHRoaXMucnVuUHJvbWlzZShlZmZlY3QpO1xuXHR9XG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHJlbW90ZSBVUkwgdG8gZW5zdXJlIGl0IHBvaW50cyB0byByZW1vdGVFbnRyeS5qc1xuICogSWYgdGhlIFVSTCBkb2Vzbid0IGVuZCB3aXRoIGEgZmlsZSBleHRlbnNpb24sIGFwcGVuZHMgL3JlbW90ZUVudHJ5LmpzXG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZVJlbW90ZVVybCh1cmw6IHN0cmluZyk6IHN0cmluZyB7XG5cdGlmICh1cmwuZW5kc1dpdGgoJy5qcycpKSByZXR1cm4gdXJsOyAvLyBBbHJlYWR5IGEgZmlsZVxuXHRyZXR1cm4gYCR7dXJsLmVuZHNXaXRoKCcvJykgPyB1cmwuc2xpY2UoMCwgLTEpIDogdXJsfS9yZW1vdGVFbnRyeS5qc2A7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQbHVnaW5SdW50aW1lKFxuXHRjb25maWc6IFBsdWdpblJ1bnRpbWVDb25maWdcbik6IFBsdWdpblJ1bnRpbWUge1xuXHRjb25zdCBzZWNyZXRzID0gY29uZmlnLnNlY3JldHMgfHwge307XG5cblx0Ly8gTm9ybWFsaXplIGFsbCByZW1vdGUgVVJMcyBpbiB0aGUgcmVnaXN0cnlcblx0Y29uc3Qgbm9ybWFsaXplZFJlZ2lzdHJ5ID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuXHRcdE9iamVjdC5lbnRyaWVzKGNvbmZpZy5yZWdpc3RyeSkubWFwKChbcGx1Z2luSWQsIGVudHJ5XSkgPT4gW1xuXHRcdFx0cGx1Z2luSWQsXG5cdFx0XHR7XG5cdFx0XHRcdC4uLmVudHJ5LFxuXHRcdFx0XHRyZW1vdGVVcmw6IG5vcm1hbGl6ZVJlbW90ZVVybChlbnRyeS5yZW1vdGVVcmwpXG5cdFx0XHR9XG5cdFx0XSlcblx0KSBhcyBQbHVnaW5SZWdpc3RyeTtcblxuXHRjb25zdCBsYXllciA9IFBsdWdpblNlcnZpY2UuTGl2ZShub3JtYWxpemVkUmVnaXN0cnksIHNlY3JldHMpO1xuXHRjb25zdCBydW50aW1lID0gTWFuYWdlZFJ1bnRpbWUubWFrZShsYXllcik7XG5cblx0cmV0dXJuIG5ldyBQbHVnaW5SdW50aW1lKHJ1bnRpbWUsIG5vcm1hbGl6ZWRSZWdpc3RyeSk7XG59Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFJQSxJQUFhLHFCQUFiLGNBQXdDQSxZQUFLLFlBQVkscUJBQXFCLENBTTNFO0FBRUgsSUFBYSx3QkFBYixjQUEyQ0EsWUFBSyxZQUMvQyx3QkFDQSxDQUlFO0FBRUgsSUFBYSxrQkFBYixjQUFxQ0EsWUFBSyxZQUFZLGtCQUFrQixDQUlyRTtBQUdILE1BQWEsdUJBQXVCLFNBQTBCO0FBQzdELFNBQVEsTUFBUjtFQUNDLEtBQUs7RUFDTCxLQUFLO0VBQ0wsS0FBSztFQUNMLEtBQUs7RUFDTCxLQUFLLFVBQ0osUUFBTztFQUNSLFFBQ0MsUUFBTzs7O0FBS1YsTUFBYSxpQkFDWixXQUNBLFVBQ0EsZUFDQSxjQUN3QjtBQUN4QixRQUFPLElBQUksbUJBQW1CO0VBQzdCO0VBQ0E7RUFDQTtFQUNBLFdBQVcsb0JBQW9CLFVBQVUsS0FBSztFQUM5QyxPQUFPO0VBQ1AsQ0FBQzs7QUFJSCxNQUFhLHdCQUNaLE9BQ0EsVUFDQSxlQUNBLFdBQ0EsbUJBQW1CLFVBQ0s7QUFDeEIsS0FBSSxp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
|