1 | ;
|
2 | var _a;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.Rule = void 0;
|
5 | const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const aws_iam_1 = require("@aws-cdk/aws-iam");
|
8 | const core_1 = require("@aws-cdk/core");
|
9 | const constructs_1 = require("constructs");
|
10 | const events_generated_1 = require("./events.generated");
|
11 | const schedule_1 = require("./schedule");
|
12 | const util_1 = require("./util");
|
13 | /**
|
14 | * Defines an EventBridge Rule in this stack.
|
15 | *
|
16 | * @resource AWS::Events::Rule
|
17 | */
|
18 | class Rule extends core_1.Resource {
|
19 | constructor(scope, id, props = {}) {
|
20 | super(scope, id, {
|
21 | physicalName: props.ruleName,
|
22 | });
|
23 | this.targets = new Array();
|
24 | this.eventPattern = {};
|
25 | /** Set to keep track of what target accounts and regions we've already created event buses for */
|
26 | this._xEnvTargetsAdded = new Set();
|
27 | try {
|
28 | jsiiDeprecationWarnings._aws_cdk_aws_events_RuleProps(props);
|
29 | }
|
30 | catch (error) {
|
31 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
32 | Error.captureStackTrace(error, Rule);
|
33 | }
|
34 | throw error;
|
35 | }
|
36 | if (props.eventBus && props.schedule) {
|
37 | throw new Error('Cannot associate rule with \'eventBus\' when using \'schedule\'');
|
38 | }
|
39 | this.description = props.description;
|
40 | this.scheduleExpression = props.schedule?.expressionString;
|
41 | // add a warning on synth when minute is not defined in a cron schedule
|
42 | props.schedule?._bind(this);
|
43 | const resource = new events_generated_1.CfnRule(this, 'Resource', {
|
44 | name: this.physicalName,
|
45 | description: this.description,
|
46 | state: props.enabled == null ? 'ENABLED' : (props.enabled ? 'ENABLED' : 'DISABLED'),
|
47 | scheduleExpression: this.scheduleExpression,
|
48 | eventPattern: core_1.Lazy.any({ produce: () => this._renderEventPattern() }),
|
49 | targets: core_1.Lazy.any({ produce: () => this.renderTargets() }),
|
50 | eventBusName: props.eventBus && props.eventBus.eventBusName,
|
51 | });
|
52 | this.ruleArn = this.getResourceArnAttribute(resource.attrArn, {
|
53 | service: 'events',
|
54 | resource: 'rule',
|
55 | resourceName: this.physicalName,
|
56 | });
|
57 | this.ruleName = this.getResourceNameAttribute(resource.ref);
|
58 | this.addEventPattern(props.eventPattern);
|
59 | for (const target of props.targets || []) {
|
60 | this.addTarget(target);
|
61 | }
|
62 | }
|
63 | /**
|
64 | * Import an existing EventBridge Rule provided an ARN
|
65 | *
|
66 | * @param scope The parent creating construct (usually `this`).
|
67 | * @param id The construct's name.
|
68 | * @param eventRuleArn Event Rule ARN (i.e. arn:aws:events:<region>:<account-id>:rule/MyScheduledRule).
|
69 | */
|
70 | static fromEventRuleArn(scope, id, eventRuleArn) {
|
71 | const parts = core_1.Stack.of(scope).splitArn(eventRuleArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
|
72 | class Import extends core_1.Resource {
|
73 | constructor() {
|
74 | super(...arguments);
|
75 | this.ruleArn = eventRuleArn;
|
76 | this.ruleName = parts.resourceName || '';
|
77 | }
|
78 | }
|
79 | return new Import(scope, id);
|
80 | }
|
81 | /**
|
82 | * Adds a target to the rule. The abstract class RuleTarget can be extended to define new
|
83 | * targets.
|
84 | *
|
85 | * No-op if target is undefined.
|
86 | */
|
87 | addTarget(target) {
|
88 | try {
|
89 | jsiiDeprecationWarnings._aws_cdk_aws_events_IRuleTarget(target);
|
90 | }
|
91 | catch (error) {
|
92 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
93 | Error.captureStackTrace(error, this.addTarget);
|
94 | }
|
95 | throw error;
|
96 | }
|
97 | if (!target) {
|
98 | return;
|
99 | }
|
100 | // Simply increment id for each `addTarget` call. This is guaranteed to be unique.
|
101 | const autoGeneratedId = `Target${this.targets.length}`;
|
102 | const targetProps = target.bind(this, autoGeneratedId);
|
103 | const inputProps = targetProps.input && targetProps.input.bind(this);
|
104 | const roleArn = targetProps.role?.roleArn;
|
105 | const id = targetProps.id || autoGeneratedId;
|
106 | if (targetProps.targetResource) {
|
107 | const targetStack = core_1.Stack.of(targetProps.targetResource);
|
108 | const targetAccount = targetProps.targetResource.env?.account || targetStack.account;
|
109 | const targetRegion = targetProps.targetResource.env?.region || targetStack.region;
|
110 | const sourceStack = core_1.Stack.of(this);
|
111 | const sourceAccount = sourceStack.account;
|
112 | const sourceRegion = sourceStack.region;
|
113 | // if the target is in a different account or region and is defined in this CDK App
|
114 | // we can generate all the needed components:
|
115 | // - forwarding rule in the source stack (target: default event bus of the receiver region)
|
116 | // - eventbus permissions policy (creating an extra stack)
|
117 | // - receiver rule in the target stack (target: the actual target)
|
118 | if (!util_1.sameEnvDimension(sourceAccount, targetAccount) || !util_1.sameEnvDimension(sourceRegion, targetRegion)) {
|
119 | // cross-account and/or cross-region event - strap in, this works differently than regular events!
|
120 | // based on:
|
121 | // https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cross-account.html
|
122 | // for cross-account or cross-region events, we require a concrete target account and region
|
123 | if (!targetAccount || core_1.Token.isUnresolved(targetAccount)) {
|
124 | throw new Error('You need to provide a concrete account for the target stack when using cross-account or cross-region events');
|
125 | }
|
126 | if (!targetRegion || core_1.Token.isUnresolved(targetRegion)) {
|
127 | throw new Error('You need to provide a concrete region for the target stack when using cross-account or cross-region events');
|
128 | }
|
129 | if (core_1.Token.isUnresolved(sourceAccount)) {
|
130 | throw new Error('You need to provide a concrete account for the source stack when using cross-account or cross-region events');
|
131 | }
|
132 | // Don't exactly understand why this code was here (seems unlikely this rule would be violated), but
|
133 | // let's leave it in nonetheless.
|
134 | const sourceApp = this.node.root;
|
135 | if (!sourceApp || !core_1.App.isApp(sourceApp)) {
|
136 | throw new Error('Event stack which uses cross-account or cross-region targets must be part of a CDK app');
|
137 | }
|
138 | const targetApp = constructs_1.Node.of(targetProps.targetResource).root;
|
139 | if (!targetApp || !core_1.App.isApp(targetApp)) {
|
140 | throw new Error('Target stack which uses cross-account or cross-region event targets must be part of a CDK app');
|
141 | }
|
142 | if (sourceApp !== targetApp) {
|
143 | throw new Error('Event stack and target stack must belong to the same CDK app');
|
144 | }
|
145 | // The target of this Rule will be the default event bus of the target environment
|
146 | this.ensureXEnvTargetEventBus(targetStack, targetAccount, targetRegion, id);
|
147 | // The actual rule lives in the target stack. Other than the account, it's identical to this one,
|
148 | // but only evaluated at render time (via a special subclass).
|
149 | //
|
150 | // FIXME: the MirrorRule is a bit silly, forwarding the exact same event to another event bus
|
151 | // and trigger on it there (there will be issues with construct references, for example). Especially
|
152 | // in the case of scheduled events, we will just trigger both rules in parallel in both environments.
|
153 | //
|
154 | // A better solution would be to have the source rule add a unique token to the the event,
|
155 | // and have the mirror rule trigger on that token only (thereby properly separating triggering, which
|
156 | // happens in the source env; and activating, which happens in the target env).
|
157 | //
|
158 | // Don't have time to do that right now.
|
159 | const mirrorRuleScope = this.obtainMirrorRuleScope(targetStack, targetAccount, targetRegion);
|
160 | new MirrorRule(mirrorRuleScope, `${core_1.Names.uniqueId(this)}-${id}`, {
|
161 | targets: [target],
|
162 | eventPattern: this.eventPattern,
|
163 | schedule: this.scheduleExpression ? schedule_1.Schedule.expression(this.scheduleExpression) : undefined,
|
164 | description: this.description,
|
165 | }, this);
|
166 | return;
|
167 | }
|
168 | }
|
169 | // Here only if the target does not have a targetResource defined.
|
170 | // In such case we don't have to generate any extra component.
|
171 | // Note that this can also be an imported resource (i.e: EventBus target)
|
172 | this.targets.push({
|
173 | id,
|
174 | arn: targetProps.arn,
|
175 | roleArn,
|
176 | ecsParameters: targetProps.ecsParameters,
|
177 | httpParameters: targetProps.httpParameters,
|
178 | kinesisParameters: targetProps.kinesisParameters,
|
179 | runCommandParameters: targetProps.runCommandParameters,
|
180 | batchParameters: targetProps.batchParameters,
|
181 | deadLetterConfig: targetProps.deadLetterConfig,
|
182 | retryPolicy: targetProps.retryPolicy,
|
183 | sqsParameters: targetProps.sqsParameters,
|
184 | input: inputProps && inputProps.input,
|
185 | inputPath: inputProps && inputProps.inputPath,
|
186 | inputTransformer: inputProps?.inputTemplate !== undefined ? {
|
187 | inputTemplate: inputProps.inputTemplate,
|
188 | inputPathsMap: inputProps.inputPathsMap,
|
189 | } : undefined,
|
190 | });
|
191 | }
|
192 | /**
|
193 | * Adds an event pattern filter to this rule. If a pattern was already specified,
|
194 | * these values are merged into the existing pattern.
|
195 | *
|
196 | * For example, if the rule already contains the pattern:
|
197 | *
|
198 | * {
|
199 | * "resources": [ "r1" ],
|
200 | * "detail": {
|
201 | * "hello": [ 1 ]
|
202 | * }
|
203 | * }
|
204 | *
|
205 | * And `addEventPattern` is called with the pattern:
|
206 | *
|
207 | * {
|
208 | * "resources": [ "r2" ],
|
209 | * "detail": {
|
210 | * "foo": [ "bar" ]
|
211 | * }
|
212 | * }
|
213 | *
|
214 | * The resulting event pattern will be:
|
215 | *
|
216 | * {
|
217 | * "resources": [ "r1", "r2" ],
|
218 | * "detail": {
|
219 | * "hello": [ 1 ],
|
220 | * "foo": [ "bar" ]
|
221 | * }
|
222 | * }
|
223 | *
|
224 | */
|
225 | addEventPattern(eventPattern) {
|
226 | try {
|
227 | jsiiDeprecationWarnings._aws_cdk_aws_events_EventPattern(eventPattern);
|
228 | }
|
229 | catch (error) {
|
230 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
231 | Error.captureStackTrace(error, this.addEventPattern);
|
232 | }
|
233 | throw error;
|
234 | }
|
235 | if (!eventPattern) {
|
236 | return;
|
237 | }
|
238 | util_1.mergeEventPattern(this.eventPattern, eventPattern);
|
239 | }
|
240 | /**
|
241 | * Not private only to be overrideen in CopyRule.
|
242 | *
|
243 | * @internal
|
244 | */
|
245 | _renderEventPattern() {
|
246 | return util_1.renderEventPattern(this.eventPattern);
|
247 | }
|
248 | validate() {
|
249 | if (Object.keys(this.eventPattern).length === 0 && !this.scheduleExpression) {
|
250 | return ['Either \'eventPattern\' or \'schedule\' must be defined'];
|
251 | }
|
252 | return [];
|
253 | }
|
254 | renderTargets() {
|
255 | if (this.targets.length === 0) {
|
256 | return undefined;
|
257 | }
|
258 | return this.targets;
|
259 | }
|
260 | /**
|
261 | * Make sure we add the target environments event bus as a target, and the target has permissions set up to receive our events
|
262 | *
|
263 | * For cross-account rules, uses a support stack to set up a policy on the target event bus.
|
264 | */
|
265 | ensureXEnvTargetEventBus(targetStack, targetAccount, targetRegion, id) {
|
266 | // the _actual_ target is just the event bus of the target's account
|
267 | // make sure we only add it once per account per region
|
268 | const key = `${targetAccount}:${targetRegion}`;
|
269 | if (this._xEnvTargetsAdded.has(key)) {
|
270 | return;
|
271 | }
|
272 | this._xEnvTargetsAdded.add(key);
|
273 | const eventBusArn = targetStack.formatArn({
|
274 | service: 'events',
|
275 | resource: 'event-bus',
|
276 | resourceName: 'default',
|
277 | region: targetRegion,
|
278 | account: targetAccount,
|
279 | });
|
280 | // For some reason, cross-region requires a Role (with `PutEvents` on the
|
281 | // target event bus) while cross-account doesn't
|
282 | const roleArn = !util_1.sameEnvDimension(targetRegion, core_1.Stack.of(this).region)
|
283 | ? this.crossRegionPutEventsRole(eventBusArn).roleArn
|
284 | : undefined;
|
285 | this.targets.push({
|
286 | id,
|
287 | arn: eventBusArn,
|
288 | roleArn,
|
289 | });
|
290 | // Add a policy to the target Event Bus to allow the source account/region to publish into it.
|
291 | //
|
292 | // Since this Event Bus permission needs to be deployed before the stack containing the Rule is deployed
|
293 | // (as EventBridge verifies whether you have permissions to the targets on rule creation), this needs
|
294 | // to be in a support stack.
|
295 | const sourceApp = this.node.root;
|
296 | const sourceAccount = core_1.Stack.of(this).account;
|
297 | // If different accounts, we need to add the permissions to the target eventbus
|
298 | //
|
299 | // For different region, no need for a policy on the target event bus (but a need
|
300 | // for a role).
|
301 | if (!util_1.sameEnvDimension(sourceAccount, targetAccount)) {
|
302 | const stackId = `EventBusPolicy-${sourceAccount}-${targetRegion}-${targetAccount}`;
|
303 | let eventBusPolicyStack = sourceApp.node.tryFindChild(stackId);
|
304 | if (!eventBusPolicyStack) {
|
305 | eventBusPolicyStack = new core_1.Stack(sourceApp, stackId, {
|
306 | env: {
|
307 | account: targetAccount,
|
308 | region: targetRegion,
|
309 | },
|
310 | // The region in the stack name is rather redundant (it will always be the target region)
|
311 | // Leaving it in for backwards compatibility.
|
312 | stackName: `${targetStack.stackName}-EventBusPolicy-support-${targetRegion}-${sourceAccount}`,
|
313 | });
|
314 | new events_generated_1.CfnEventBusPolicy(eventBusPolicyStack, 'GivePermToOtherAccount', {
|
315 | action: 'events:PutEvents',
|
316 | statementId: `Allow-account-${sourceAccount}-${this.node.addr}`,
|
317 | principal: sourceAccount,
|
318 | });
|
319 | }
|
320 | // deploy the event bus permissions before the source stack
|
321 | core_1.Stack.of(this).addDependency(eventBusPolicyStack);
|
322 | }
|
323 | }
|
324 | /**
|
325 | * Return the scope where the mirror rule should be created for x-env event targets
|
326 | *
|
327 | * This is the target resource's containing stack if it shares the same region (owned
|
328 | * resources), or should be a fresh support stack for imported resources.
|
329 | *
|
330 | * We don't implement the second yet, as I have to think long and hard on whether we
|
331 | * can reuse the existing support stack or not, and I don't have time for that right now.
|
332 | */
|
333 | obtainMirrorRuleScope(targetStack, targetAccount, targetRegion) {
|
334 | // for cross-account or cross-region events, we cannot create new components for an imported resource
|
335 | // because we don't have the target stack
|
336 | if (util_1.sameEnvDimension(targetStack.account, targetAccount) && util_1.sameEnvDimension(targetStack.region, targetRegion)) {
|
337 | return targetStack;
|
338 | }
|
339 | // For now, we don't do the work for the support stack yet
|
340 | throw new Error('Cannot create a cross-account or cross-region rule for an imported resource (create a stack with the right environment for the imported resource)');
|
341 | }
|
342 | /**
|
343 | * Obtain the Role for the EventBridge event
|
344 | *
|
345 | * If a role already exists, it will be returned. This ensures that if multiple
|
346 | * events have the same target, they will share a role.
|
347 | * @internal
|
348 | */
|
349 | crossRegionPutEventsRole(eventBusArn) {
|
350 | const id = 'EventsRole';
|
351 | let role = this.node.tryFindChild(id);
|
352 | if (!role) {
|
353 | role = new aws_iam_1.Role(this, id, {
|
354 | roleName: core_1.PhysicalName.GENERATE_IF_NEEDED,
|
355 | assumedBy: new aws_iam_1.ServicePrincipal('events.amazonaws.com'),
|
356 | });
|
357 | }
|
358 | role.addToPrincipalPolicy(new aws_iam_1.PolicyStatement({
|
359 | actions: ['events:PutEvents'],
|
360 | resources: [eventBusArn],
|
361 | }));
|
362 | return role;
|
363 | }
|
364 | }
|
365 | exports.Rule = Rule;
|
366 | _a = JSII_RTTI_SYMBOL_1;
|
367 | Rule[_a] = { fqn: "@aws-cdk/aws-events.Rule", version: "1.204.0" };
|
368 | /**
|
369 | * A rule that mirrors another rule
|
370 | */
|
371 | class MirrorRule extends Rule {
|
372 | constructor(scope, id, props, source) {
|
373 | super(scope, id, props);
|
374 | this.source = source;
|
375 | }
|
376 | _renderEventPattern() {
|
377 | return this.source._renderEventPattern();
|
378 | }
|
379 | /**
|
380 | * Override validate to be a no-op
|
381 | *
|
382 | * The rules are never stored on this object so there's nothing to validate.
|
383 | *
|
384 | * Instead, we mirror the other rule at render time.
|
385 | */
|
386 | validate() {
|
387 | return [];
|
388 | }
|
389 | }
|
390 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJ1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsOENBQWtGO0FBQ2xGLHdDQUE2RztBQUM3RywyQ0FBNkM7QUFHN0MseURBQWdFO0FBRWhFLHlDQUFzQztBQUV0QyxpQ0FBaUY7QUE0RWpGOzs7O0dBSUc7QUFDSCxNQUFhLElBQUssU0FBUSxlQUFRO0lBOEJoQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLFFBQW1CLEVBQUc7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixZQUFZLEVBQUUsS0FBSyxDQUFDLFFBQVE7U0FDN0IsQ0FBQyxDQUFDO1FBWFksWUFBTyxHQUFHLElBQUksS0FBSyxFQUEwQixDQUFDO1FBQzlDLGlCQUFZLEdBQWlCLEVBQUcsQ0FBQztRQUlsRCxrR0FBa0c7UUFDakYsc0JBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQzs7Ozs7OytDQTVCNUMsSUFBSTs7OztRQW1DYixJQUFJLEtBQUssQ0FBQyxRQUFRLElBQUksS0FBSyxDQUFDLFFBQVEsRUFBRTtZQUNwQyxNQUFNLElBQUksS0FBSyxDQUFDLGlFQUFpRSxDQUFDLENBQUM7U0FDcEY7UUFFRCxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7UUFDckMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEtBQUssQ0FBQyxRQUFRLEVBQUUsZ0JBQWdCLENBQUM7UUFFM0QsdUVBQXVFO1FBQ3ZFLEtBQUssQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRTVCLE1BQU0sUUFBUSxHQUFHLElBQUksMEJBQU8sQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFO1lBQzdDLElBQUksRUFBRSxJQUFJLENBQUMsWUFBWTtZQUN2QixXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVc7WUFDN0IsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPLElBQUks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LENBQUMsQ0FBQztRQUVKLE9BQU8sSUFBSSxDQUFDO0tBQ2I7O0FBeldILG9CQTBXQzs7O0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVcsU0FBUSxJQUFJO0lBQzNCLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBZ0IsRUFBbUIsTUFBWTtRQUN2RixLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQURtRCxXQUFNLEdBQU4sTUFBTSxDQUFNO0tBRXhGO0lBRU0sbUJBQW1CO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO0tBQzFDO0lBRUQ7Ozs7OztPQU1HO0lBQ08sUUFBUTtRQUNoQixPQUFPLEVBQUUsQ0FBQztLQUNYO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJUm9sZSwgUG9saWN5U3RhdGVtZW50LCBSb2xlLCBTZXJ2aWNlUHJpbmNpcGFsIH0gZnJvbSAnQGF3cy1jZGsvYXdzLWlhbSc7XG5pbXBvcnQgeyBBcHAsIElSZXNvdXJjZSwgTGF6eSwgTmFtZXMsIFJlc291cmNlLCBTdGFjaywgVG9rZW4sIFBoeXNpY2FsTmFtZSwgQXJuRm9ybWF0IH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgeyBOb2RlLCBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IElFdmVudEJ1cyB9IGZyb20gJy4vZXZlbnQtYnVzJztcbmltcG9ydCB7IEV2ZW50UGF0dGVybiB9IGZyb20gJy4vZXZlbnQtcGF0dGVybic7XG5pbXBvcnQgeyBDZm5FdmVudEJ1c1BvbGljeSwgQ2ZuUnVsZSB9IGZyb20gJy4vZXZlbnRzLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBJUnVsZSB9IGZyb20gJy4vcnVsZS1yZWYnO1xuaW1wb3J0IHsgU2NoZWR1bGUgfSBmcm9tICcuL3NjaGVkdWxlJztcbmltcG9ydCB7IElSdWxlVGFyZ2V0IH0gZnJvbSAnLi90YXJnZXQnO1xuaW1wb3J0IHsgbWVyZ2VFdmVudFBhdHRlcm4sIHJlbmRlckV2ZW50UGF0dGVybiwgc2FtZUVudkRpbWVuc2lvbiB9IGZyb20gJy4vdXRpbCc7XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgZGVmaW5pbmcgYW4gRXZlbnRCcmlkZ2UgUnVsZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJ1bGVQcm9wcyB7XG4gIC8qKlxuICAgKiBBIGRlc2NyaXB0aW9uIG9mIHRoZSBydWxlJ3MgcHVycG9zZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkZXNjcmlwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIG5hbWUgZm9yIHRoZSBydWxlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEFXUyBDbG91ZEZvcm1hdGlvbiBnZW5lcmF0ZXMgYSB1bmlxdWUgcGh5c2ljYWwgSUQgYW5kIHVzZXMgdGhhdCBJRFxuICAgKiBmb3IgdGhlIHJ1bGUgbmFtZS4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZSBOYW1lIFR5cGUuXG4gICAqL1xuICByZWFkb25seSBydWxlTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIHJ1bGUgaXMgZW5hYmxlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgZW5hYmxlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBzY2hlZHVsZSBvciByYXRlIChmcmVxdWVuY3kpIHRoYXQgZGV0ZXJtaW5lcyB3aGVuIEV2ZW50QnJpZGdlXG4gICAqIHJ1bnMgdGhlIHJ1bGUuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgU2NoZWR1bGUgRXhwcmVzc2lvbiBTeW50YXggZm9yXG4gICAqIFJ1bGVzIGluIHRoZSBBbWF6b24gRXZlbnRCcmlkZ2UgVXNlciBHdWlkZS5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZXZlbnRicmlkZ2UvbGF0ZXN0L3VzZXJndWlkZS9zY2hlZHVsZWQtZXZlbnRzLmh0bWxcbiAgICpcbiAgICogWW91IG11c3Qgc3BlY2lmeSB0aGlzIHByb3BlcnR5LCB0aGUgYGV2ZW50UGF0dGVybmAgcHJvcGVydHksIG9yIGJvdGguXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm9uZS5cbiAgICovXG4gIHJlYWRvbmx5IHNjaGVkdWxlPzogU2NoZWR1bGU7XG5cbiAgLyoqXG4gICAqIERlc2NyaWJlcyB3aGljaCBldmVudHMgRXZlbnRCcmlkZ2Ugcm91dGVzIHRvIHRoZSBzcGVjaWZpZWQgdGFyZ2V0LlxuICAgKiBUaGVzZSByb3V0ZWQgZXZlbnRzIGFyZSBtYXRjaGVkIGV2ZW50cy4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZSBFdmVudHNcbiAgICogYW5kIEV2ZW50IFBhdHRlcm5zIGluIHRoZSBBbWF6b24gRXZlbnRCcmlkZ2UgVXNlciBHdWlkZS5cbiAgICpcbiAgICogQHNlZVxuICAgKiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZXZlbnRicmlkZ2UvbGF0ZXN0L3VzZXJndWlkZS9ldmVudGJyaWRnZS1hbmQtZXZlbnQtcGF0dGVybnMuaHRtbFxuICAgKlxuICAgKiBZb3UgbXVzdCBzcGVjaWZ5IHRoaXMgcHJvcGVydHkgKGVpdGhlciB2aWEgcHJvcHMgb3IgdmlhXG4gICAqIGBhZGRFdmVudFBhdHRlcm5gKSwgdGhlIGBzY2hlZHVsZUV4cHJlc3Npb25gIHByb3BlcnR5LCBvciBib3RoLiBUaGVcbiAgICogbWV0aG9kIGBhZGRFdmVudFBhdHRlcm5gIGNhbiBiZSB1c2VkIHRvIGFkZCBmaWx0ZXIgdmFsdWVzIHRvIHRoZSBldmVudFxuICAgKiBwYXR0ZXJuLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vbmUuXG4gICAqL1xuICByZWFkb25seSBldmVudFBhdHRlcm4/OiBFdmVudFBhdHRlcm47XG5cbiAgLyoqXG4gICAqIFRhcmdldHMgdG8gaW52b2tlIHdoZW4gdGhpcyBydWxlIG1hdGNoZXMgYW4gZXZlbnQuXG4gICAqXG4gICAqIElucHV0IHdpbGwgYmUgdGhlIGZ1bGwgbWF0Y2hlZCBldmVudC4gSWYgeW91IHdpc2ggdG8gc3BlY2lmeSBjdXN0b21cbiAgICogdGFyZ2V0IGlucHV0LCB1c2UgYGFkZFRhcmdldCh0YXJnZXRbLCBpbnB1dE9wdGlvbnNdKWAuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gdGFyZ2V0cy5cbiAgICovXG4gIHJlYWRvbmx5IHRhcmdldHM/OiBJUnVsZVRhcmdldFtdO1xuXG4gIC8qKlxuICAgKiBUaGUgZXZlbnQgYnVzIHRvIGFzc29jaWF0ZSB3aXRoIHRoaXMgcnVsZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGUgZGVmYXVsdCBldmVudCBidXMuXG4gICAqL1xuICByZWFkb25seSBldmVudEJ1cz86IElFdmVudEJ1cztcbn1cblxuLyoqXG4gKiBEZWZpbmVzIGFuIEV2ZW50QnJpZGdlIFJ1bGUgaW4gdGhpcyBzdGFjay5cbiAqXG4gKiBAcmVzb3VyY2UgQVdTOjpFdmVudHM6OlJ1bGVcbiAqL1xuZXhwb3J0IGNsYXNzIFJ1bGUgZXh0ZW5kcyBSZXNvdXJjZSBpbXBsZW1lbnRzIElSdWxlIHtcblxuICAvKipcbiAgICogSW1wb3J0IGFuIGV4aXN0aW5nIEV2ZW50QnJpZGdlIFJ1bGUgcHJvdmlkZWQgYW4gQVJOXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSBUaGUgcGFyZW50IGNyZWF0aW5nIGNvbnN0cnVjdCAodXN1YWxseSBgdGhpc2ApLlxuICAgKiBAcGFyYW0gaWQgVGhlIGNvbnN0cnVjdCdzIG5hbWUuXG4gICAqIEBwYXJhbSBldmVudFJ1bGVBcm4gRXZlbnQgUnVsZSBBUk4gKGkuZS4gYXJuOmF3czpldmVudHM6PHJlZ2lvbj46PGFjY291bnQtaWQ+OnJ1bGUvTXlTY2hlZHVsZWRSdWxlKS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbUV2ZW50UnVsZUFybihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBldmVudFJ1bGVBcm46IHN0cmluZyk6IElSdWxlIHtcbiAgICBjb25zdCBwYXJ0cyA9IFN0YWNrLm9mKHNjb3BlKS5zcGxpdEFybihldmVudFJ1bGVBcm4sIEFybkZvcm1hdC5TTEFTSF9SRVNPVVJDRV9OQU1FKTtcblxuICAgIGNsYXNzIEltcG9ydCBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVJ1bGUge1xuICAgICAgcHVibGljIHJ1bGVBcm4gPSBldmVudFJ1bGVBcm47XG4gICAgICBwdWJsaWMgcnVsZU5hbWUgPSBwYXJ0cy5yZXNvdXJjZU5hbWUgfHwgJyc7XG4gICAgfVxuICAgIHJldHVybiBuZXcgSW1wb3J0KHNjb3BlLCBpZCk7XG4gIH1cblxuICBwdWJsaWMgcmVhZG9ubHkgcnVsZUFybjogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgcnVsZU5hbWU6IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IHRhcmdldHMgPSBuZXcgQXJyYXk8Q2ZuUnVsZS5UYXJnZXRQcm9wZXJ0eT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBldmVudFBhdHRlcm46IEV2ZW50UGF0dGVybiA9IHsgfTtcbiAgcHJpdmF0ZSByZWFkb25seSBzY2hlZHVsZUV4cHJlc3Npb24/OiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG5cbiAgLyoqIFNldCB0byBrZWVwIHRyYWNrIG9mIHdoYXQgdGFyZ2V0IGFjY291bnRzIGFuZCByZWdpb25zIHdlJ3ZlIGFscmVhZHkgY3JlYXRlZCBldmVudCBidXNlcyBmb3IgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBfeEVudlRhcmdldHNBZGRlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBSdWxlUHJvcHMgPSB7IH0pIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIHBoeXNpY2FsTmFtZTogcHJvcHMucnVsZU5hbWUsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMuZXZlbnRCdXMgJiYgcHJvcHMuc2NoZWR1bGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGFzc29jaWF0ZSBydWxlIHdpdGggXFwnZXZlbnRCdXNcXCcgd2hlbiB1c2luZyBcXCdzY2hlZHVsZVxcJycpO1xuICAgIH1cblxuICAgIHRoaXMuZGVzY3JpcHRpb24gPSBwcm9wcy5kZXNjcmlwdGlvbjtcbiAgICB0aGlzLnNjaGVkdWxlRXhwcmVzc2lvbiA9IHByb3BzLnNjaGVkdWxlPy5leHByZXNzaW9uU3RyaW5nO1xuXG4gICAgLy8gYWRkIGEgd2FybmluZyBvbiBzeW50aCB3aGVuIG1pbnV0ZSBpcyBub3QgZGVmaW5lZCBpbiBhIGNyb24gc2NoZWR1bGVcbiAgICBwcm9wcy5zY2hlZHVsZT8uX2JpbmQodGhpcyk7XG5cbiAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBDZm5SdWxlKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIG5hbWU6IHRoaXMucGh5c2ljYWxOYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHRoaXMuZGVzY3JpcHRpb24sXG4gICAgICBzdGF0ZTogcHJvcHMuZW5hYmxlZCA9PSBudWxsID8gJ0VOQUJMRUQnIDogKHByb3BzLmVuYWJsZWQgPyAnRU5BQkxFRCcgOiAnRElTQUJMRUQnKSxcbiAgICAgIHNjaGVkdWxlRXhwcmVzc2lvbjogdGhpcy5zY2hlZHVsZUV4cHJlc3Npb24sXG4gICAgICBldmVudFBhdHRlcm46IExhenkuYW55KHsgcHJvZHVjZTogKCkgPT4gdGhpcy5fcmVuZGVyRXZlbnRQYXR0ZXJuKCkgfSksXG4gICAgICB0YXJnZXRzOiBMYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMucmVuZGVyVGFyZ2V0cygpIH0pLFxuICAgICAgZXZlbnRCdXNOYW1lOiBwcm9wcy5ldmVudEJ1cyAmJiBwcm9wcy5ldmVudEJ1cy5ldmVudEJ1c05hbWUsXG4gICAgfSk7XG5cbiAgICB0aGlzLnJ1bGVBcm4gPSB0aGlzLmdldFJlc291cmNlQXJuQXR0cmlidXRlKHJlc291cmNlLmF0dHJBcm4sIHtcbiAgICAgIHNlcnZpY2U6ICdldmVudHMnLFxuICAgICAgcmVzb3VyY2U6ICdydWxlJyxcbiAgICAgIHJlc291cmNlTmFtZTogdGhpcy5waHlzaWNhbE5hbWUsXG4gICAgfSk7XG4gICAgdGhpcy5ydWxlTmFtZSA9IHRoaXMuZ2V0UmVzb3VyY2VOYW1lQXR0cmlidXRlKHJlc291cmNlLnJlZik7XG5cbiAgICB0aGlzLmFkZEV2ZW50UGF0dGVybihwcm9wcy5ldmVudFBhdHRlcm4pO1xuXG4gICAgZm9yIChjb25zdCB0YXJnZXQgb2YgcHJvcHMudGFyZ2V0cyB8fCBbXSkge1xuICAgICAgdGhpcy5hZGRUYXJnZXQodGFyZ2V0KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHRhcmdldCB0byB0aGUgcnVsZS4gVGhlIGFic3RyYWN0IGNsYXNzIFJ1bGVUYXJnZXQgY2FuIGJlIGV4dGVuZGVkIHRvIGRlZmluZSBuZXdcbiAgICogdGFyZ2V0cy5cbiAgICpcbiAgICogTm8tb3AgaWYgdGFyZ2V0IGlzIHVuZGVmaW5lZC5cbiAgICovXG4gIHB1YmxpYyBhZGRUYXJnZXQodGFyZ2V0PzogSVJ1bGVUYXJnZXQpOiB2b2lkIHtcbiAgICBpZiAoIXRhcmdldCkgeyByZXR1cm47IH1cblxuICAgIC8vIFNpbXBseSBpbmNyZW1lbnQgaWQgZm9yIGVhY2ggYGFkZFRhcmdldGAgY2FsbC4gVGhpcyBpcyBndWFyYW50ZWVkIHRvIGJlIHVuaXF1ZS5cbiAgICBjb25zdCBhdXRvR2VuZXJhdGVkSWQgPSBgVGFyZ2V0JHt0aGlzLnRhcmdldHMubGVuZ3RofWA7XG5cbiAgICBjb25zdCB0YXJnZXRQcm9wcyA9IHRhcmdldC5iaW5kKHRoaXMsIGF1dG9HZW5lcmF0ZWRJZCk7XG4gICAgY29uc3QgaW5wdXRQcm9wcyA9IHRhcmdldFByb3BzLmlucHV0ICYmIHRhcmdldFByb3BzLmlucHV0LmJpbmQodGhpcyk7XG5cbiAgICBjb25zdCByb2xlQXJuID0gdGFyZ2V0UHJvcHMucm9sZT8ucm9sZUFybjtcbiAgICBjb25zdCBpZCA9IHRhcmdldFByb3BzLmlkIHx8IGF1dG9HZW5lcmF0ZWRJZDtcblxuICAgIGlmICh0YXJnZXRQcm9wcy50YXJnZXRSZXNvdXJjZSkge1xuICAgICAgY29uc3QgdGFyZ2V0U3RhY2sgPSBTdGFjay5vZih0YXJnZXRQcm9wcy50YXJnZXRSZXNvdXJjZSk7XG5cbiAgICAgIGNvbnN0IHRhcmdldEFjY291bnQgPSAodGFyZ2V0UHJvcHMudGFyZ2V0UmVzb3VyY2UgYXMgSVJlc291cmNlKS5lbnY/LmFjY291bnQgfHwgdGFyZ2V0U3RhY2suYWNjb3VudDtcbiAgICAgIGNvbnN0IHRhcmdldFJlZ2lvbiA9ICh0YXJnZXRQcm9wcy50YXJnZXRSZXNvdXJjZSBhcyBJUmVzb3VyY2UpLmVudj8ucmVnaW9uIHx8IHRhcmdldFN0YWNrLnJlZ2lvbjtcblxuICAgICAgY29uc3Qgc291cmNlU3RhY2sgPSBTdGFjay5vZih0aGlzKTtcbiAgICAgIGNvbnN0IHNvdXJjZUFjY291bnQgPSBzb3VyY2VTdGFjay5hY2NvdW50O1xuICAgICAgY29uc3Qgc291cmNlUmVnaW9uID0gc291cmNlU3RhY2sucmVnaW9uO1xuXG4gICAgICAvLyBpZiB0aGUgdGFyZ2V0IGlzIGluIGEgZGlmZmVyZW50IGFjY291bnQgb3IgcmVnaW9uIGFuZCBpcyBkZWZpbmVkIGluIHRoaXMgQ0RLIEFwcFxuICAgICAgLy8gd2UgY2FuIGdlbmVyYXRlIGFsbCB0aGUgbmVlZGVkIGNvbXBvbmVudHM6XG4gICAgICAvLyAtIGZvcndhcmRpbmcgcnVsZSBpbiB0aGUgc291cmNlIHN0YWNrICh0YXJnZXQ6IGRlZmF1bHQgZXZlbnQgYnVzIG9mIHRoZSByZWNlaXZlciByZWdpb24pXG4gICAgICAvLyAtIGV2ZW50YnVzIHBlcm1pc3Npb25zIHBvbGljeSAoY3JlYXRpbmcgYW4gZXh0cmEgc3RhY2spXG4gICAgICAvLyAtIHJlY2VpdmVyIHJ1bGUgaW4gdGhlIHRhcmdldCBzdGFjayAodGFyZ2V0OiB0aGUgYWN0dWFsIHRhcmdldClcbiAgICAgIGlmICghc2FtZUVudkRpbWVuc2lvbihzb3VyY2VBY2NvdW50LCB0YXJnZXRBY2NvdW50KSB8fCAhc2FtZUVudkRpbWVuc2lvbihzb3VyY2VSZWdpb24sIHRhcmdldFJlZ2lvbikpIHtcbiAgICAgICAgLy8gY3Jvc3MtYWNjb3VudCBhbmQvb3IgY3Jvc3MtcmVnaW9uIGV2ZW50IC0gc3RyYXAgaW4sIHRoaXMgd29ya3MgZGlmZmVyZW50bHkgdGhhbiByZWd1bGFyIGV2ZW50cyFcbiAgICAgICAgLy8gYmFzZWQgb246XG4gICAgICAgIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9ldmVudGJyaWRnZS9sYXRlc3QvdXNlcmd1aWRlL2ViLWNyb3NzLWFjY291bnQuaHRtbFxuXG4gICAgICAgIC8vIGZvciBjcm9zcy1hY2NvdW50IG9yIGNyb3NzLXJlZ2lvbiBldmVudHMsIHdlIHJlcXVpcmUgYSBjb25jcmV0ZSB0YXJnZXQgYWNjb3VudCBhbmQgcmVnaW9uXG4gICAgICAgIGlmICghdGFyZ2V0QWNjb3VudCB8fCBUb2tlbi5pc1VucmVzb2x2ZWQodGFyZ2V0QWNjb3VudCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHByb3ZpZGUgYSBjb25jcmV0ZSBhY2NvdW50IGZvciB0aGUgdGFyZ2V0IHN0YWNrIHdoZW4gdXNpbmcgY3Jvc3MtYWNjb3VudCBvciBjcm9zcy1yZWdpb24gZXZlbnRzJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0YXJnZXRSZWdpb24gfHwgVG9rZW4uaXNVbnJlc29sdmVkKHRhcmdldFJlZ2lvbikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHByb3ZpZGUgYSBjb25jcmV0ZSByZWdpb24gZm9yIHRoZSB0YXJnZXQgc3RhY2sgd2hlbiB1c2luZyBjcm9zcy1hY2NvdW50IG9yIGNyb3NzLXJlZ2lvbiBldmVudHMnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHNvdXJjZUFjY291bnQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwcm92aWRlIGEgY29uY3JldGUgYWNjb3VudCBmb3IgdGhlIHNvdXJjZSBzdGFjayB3aGVuIHVzaW5nIGNyb3NzLWFjY291bnQgb3IgY3Jvc3MtcmVnaW9uIGV2ZW50cycpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRG9uJ3QgZXhhY3RseSB1bmRlcnN0YW5kIHdoeSB0aGlzIGNvZGUgd2FzIGhlcmUgKHNlZW1zIHVubGlrZWx5IHRoaXMgcnVsZSB3b3VsZCBiZSB2aW9sYXRlZCksIGJ1dFxuICAgICAgICAvLyBsZXQncyBsZWF2ZSBpdCBpbiBub25ldGhlbGVzcy5cbiAgICAgICAgY29uc3Qgc291cmNlQXBwID0gdGhpcy5ub2RlLnJvb3Q7XG4gICAgICAgIGlmICghc291cmNlQXBwIHx8ICFBcHAuaXNBcHAoc291cmNlQXBwKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRXZlbnQgc3RhY2sgd2hpY2ggdXNlcyBjcm9zcy1hY2NvdW50IG9yIGNyb3NzLXJlZ2lvbiB0YXJnZXRzIG11c3QgYmUgcGFydCBvZiBhIENESyBhcHAnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0YXJnZXRBcHAgPSBOb2RlLm9mKHRhcmdldFByb3BzLnRhcmdldFJlc291cmNlKS5yb290O1xuICAgICAgICBpZiAoIXRhcmdldEFwcCB8fCAhQXBwLmlzQXBwKHRhcmdldEFwcCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RhcmdldCBzdGFjayB3aGljaCB1c2VzIGNyb3NzLWFjY291bnQgb3IgY3Jvc3MtcmVnaW9uIGV2ZW50IHRhcmdldHMgbXVzdCBiZSBwYXJ0IG9mIGEgQ0RLIGFwcCcpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzb3VyY2VBcHAgIT09IHRhcmdldEFwcCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRXZlbnQgc3RhY2sgYW5kIHRhcmdldCBzdGFjayBtdXN0IGJlbG9uZyB0byB0aGUgc2FtZSBDREsgYXBwJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgdGFyZ2V0IG9mIHRoaXMgUnVsZSB3aWxsIGJlIHRoZSBkZWZhdWx0IGV2ZW50IGJ1cyBvZiB0aGUgdGFyZ2V0IGVudmlyb25tZW50XG4gICAgICAgIHRoaXMuZW5zdXJlWEVudlRhcmdldEV2ZW50QnVzKHRhcmdldFN0YWNrLCB0YXJnZXRBY2NvdW50LCB0YXJnZXRSZWdpb24sIGlkKTtcblxuICAgICAgICAvLyBUaGUgYWN0dWFsIHJ1bGUgbGl2ZXMgaW4gdGhlIHRhcmdldCBzdGFjay4gT3RoZXIgdGhhbiB0aGUgYWNjb3VudCwgaXQncyBpZGVudGljYWwgdG8gdGhpcyBvbmUsXG4gICAgICAgIC8vIGJ1dCBvbmx5IGV2YWx1YXRlZCBhdCByZW5kZXIgdGltZSAodmlhIGEgc3BlY2lhbCBzdWJjbGFzcykuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIEZJWE1FOiB0aGUgTWlycm9yUnVsZSBpcyBhIGJpdCBzaWxseSwgZm9yd2FyZGluZyB0aGUgZXhhY3Qgc2FtZSBldmVudCB0byBhbm90aGVyIGV2ZW50IGJ1c1xuICAgICAgICAvLyBhbmQgdHJpZ2dlciBvbiBpdCB0aGVyZSAodGhlcmUgd2lsbCBiZSBpc3N1ZXMgd2l0aCBjb25zdHJ1Y3QgcmVmZXJlbmNlcywgZm9yIGV4YW1wbGUpLiBFc3BlY2lhbGx5XG4gICAgICAgIC8vIGluIHRoZSBjYXNlIG9mIHNjaGVkdWxlZCBldmVudHMsIHdlIHdpbGwganVzdCB0cmlnZ2VyIGJvdGggcnVsZXMgaW4gcGFyYWxsZWwgaW4gYm90aCBlbnZpcm9ubWVudHMuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIEEgYmV0dGVyIHNvbHV0aW9uIHdvdWxkIGJlIHRvIGhhdmUgdGhlIHNvdXJjZSBydWxlIGFkZCBhIHVuaXF1ZSB0b2tlbiB0byB0aGUgdGhlIGV2ZW50LFxuICAgICAgICAvLyBhbmQgaGF2ZSB0aGUgbWlycm9yIHJ1bGUgdHJpZ2dlciBvbiB0aGF0IHRva2VuIG9ubHkgKHRoZXJlYnkgcHJvcGVybHkgc2VwYXJhdGluZyB0cmlnZ2VyaW5nLCB3aGljaFxuICAgICAgICAvLyBoYXBwZW5zIGluIHRoZSBzb3VyY2UgZW52OyBhbmQgYWN0aXZhdGluZywgd2hpY2ggaGFwcGVucyBpbiB0aGUgdGFyZ2V0IGVudikuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIERvbid0IGhhdmUgdGltZSB0byBkbyB0aGF0IHJpZ2h0IG5vdy5cbiAgICAgICAgY29uc3QgbWlycm9yUnVsZVNjb3BlID0gdGhpcy5vYnRhaW5NaXJyb3JSdWxlU2NvcGUodGFyZ2V0U3RhY2ssIHRhcmdldEFjY291bnQsIHRhcmdldFJlZ2lvbik7XG4gICAgICAgIG5ldyBNaXJyb3JSdWxlKG1pcnJvclJ1bGVTY29wZSwgYCR7TmFtZXMudW5pcXVlSWQodGhpcyl9LSR7aWR9YCwge1xuICAgICAgICAgIHRhcmdldHM6IFt0YXJnZXRdLFxuICAgICAgICAgIGV2ZW50UGF0dGVybjogdGhpcy5ldmVudFBhdHRlcm4sXG4gICAgICAgICAgc2NoZWR1bGU6IHRoaXMuc2NoZWR1bGVFeHByZXNzaW9uID8gU2NoZWR1bGUuZXhwcmVzc2lvbih0aGlzLnNjaGVkdWxlRXhwcmVzc2lvbikgOiB1bmRlZmluZWQsXG4gICAgICAgICAgZGVzY3JpcHRpb246IHRoaXMuZGVzY3JpcHRpb24sXG4gICAgICAgIH0sIHRoaXMpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBIZXJlIG9ubHkgaWYgdGhlIHRhcmdldCBkb2VzIG5vdCBoYXZlIGEgdGFyZ2V0UmVzb3VyY2UgZGVmaW5lZC5cbiAgICAvLyBJbiBzdWNoIGNhc2Ugd2UgZG9uJ3QgaGF2ZSB0byBnZW5lcmF0ZSBhbnkgZXh0cmEgY29tcG9uZW50LlxuICAgIC8vIE5vdGUgdGhhdCB0aGlzIGNhbiBhbHNvIGJlIGFuIGltcG9ydGVkIHJlc291cmNlIChpLmU6IEV2ZW50QnVzIHRhcmdldClcblxuICAgIHRoaXMudGFyZ2V0cy5wdXNoKHtcbiAgICAgIGlkLFxuICAgICAgYXJuOiB0YXJnZXRQcm9wcy5hcm4sXG4gICAgICByb2xlQXJuLFxuICAgICAgZWNzUGFyYW1ldGVyczogdGFyZ2V0UHJvcHMuZWNzUGFyYW1ldGVycyxcbiAgICAgIGh0dHBQYXJhbWV0ZXJzOiB0YXJnZXRQcm9wcy5odHRwUGFyYW1ldGVycyxcbiAgICAgIGtpbmVzaXNQYXJhbWV0ZXJzOiB0YXJnZXRQcm9wcy5raW5lc2lzUGFyYW1ldGVycyxcbiAgICAgIHJ1bkNvbW1hbmRQYXJhbWV0ZXJzOiB0YXJnZXRQcm9wcy5ydW5Db21tYW5kUGFyYW1ldGVycyxcbiAgICAgIGJhdGNoUGFyYW1ldGVyczogdGFyZ2V0UHJvcHMuYmF0Y2hQYXJhbWV0ZXJzLFxuICAgICAgZGVhZExldHRlckNvbmZpZzogdGFyZ2V0UHJvcHMuZGVhZExldHRlckNvbmZpZyxcbiAgICAgIHJldHJ5UG9saWN5OiB0YXJnZXRQcm9wcy5yZXRyeVBvbGljeSxcbiAgICAgIHNxc1BhcmFtZXRlcnM6IHRhcmdldFByb3BzLnNxc1BhcmFtZXRlcnMsXG4gICAgICBpbnB1dDogaW5wdXRQcm9wcyAmJiBpbnB1dFByb3BzLmlucHV0LFxuICAgICAgaW5wdXRQYXRoOiBpbnB1dFByb3BzICYmIGlucHV0UHJvcHMuaW5wdXRQYXRoLFxuICAgICAgaW5wdXRUcmFuc2Zvcm1lcjogaW5wdXRQcm9wcz8uaW5wdXRUZW1wbGF0ZSAhPT0gdW5kZWZpbmVkID8ge1xuICAgICAgICBpbnB1dFRlbXBsYXRlOiBpbnB1dFByb3BzLmlucHV0VGVtcGxhdGUsXG4gICAgICAgIGlucHV0UGF0aHNNYXA6IGlucHV0UHJvcHMuaW5wdXRQYXRoc01hcCxcbiAgICAgIH0gOiB1bmRlZmluZWQsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhbiBldmVudCBwYXR0ZXJuIGZpbHRlciB0byB0aGlzIHJ1bGUuIElmIGEgcGF0dGVybiB3YXMgYWxyZWFkeSBzcGVjaWZpZWQsXG4gICAqIHRoZXNlIHZhbHVlcyBhcmUgbWVyZ2VkIGludG8gdGhlIGV4aXN0aW5nIHBhdHRlcm4uXG4gICAqXG4gICAqIEZvciBleGFtcGxlLCBpZiB0aGUgcnVsZSBhbHJlYWR5IGNvbnRhaW5zIHRoZSBwYXR0ZXJuOlxuICAgKlxuICAgKiAgICB7XG4gICAqICAgICAgXCJyZXNvdXJjZXNcIjogWyBcInIxXCIgXSxcbiAgICogICAgICBcImRldGFpbFwiOiB7XG4gICAqICAgICAgICBcImhlbGxvXCI6IFsgMSBdXG4gICAqICAgICAgfVxuICAgKiAgICB9XG4gICAqXG4gICAqIEFuZCBgYWRkRXZlbnRQYXR0ZXJuYCBpcyBjYWxsZWQgd2l0aCB0aGUgcGF0dGVybjpcbiAgICpcbiAgICogICAge1xuICAgKiAgICAgIFwicmVzb3VyY2VzXCI6IFsgXCJyMlwiIF0sXG4gICAqICAgICAgXCJkZXRhaWxcIjoge1xuICAgKiAgICAgICAgXCJmb29cIjogWyBcImJhclwiIF1cbiAgICogICAgICB9XG4gICAqICAgIH1cbiAgICpcbiAgICogVGhlIHJlc3VsdGluZyBldmVudCBwYXR0ZXJuIHdpbGwgYmU6XG4gICAqXG4gICAqICAgIHtcbiAgICogICAgICBcInJlc291cmNlc1wiOiBbIFwicjFcIiwgXCJyMlwiIF0sXG4gICAqICAgICAgXCJkZXRhaWxcIjoge1xuICAgKiAgICAgICAgXCJoZWxsb1wiOiBbIDEgXSxcbiAgICogICAgICAgIFwiZm9vXCI6IFsgXCJiYXJcIiBdXG4gICAqICAgICAgfVxuICAgKiAgICB9XG4gICAqXG4gICAqL1xuICBwdWJsaWMgYWRkRXZlbnRQYXR0ZXJuKGV2ZW50UGF0dGVybj86IEV2ZW50UGF0dGVybikge1xuICAgIGlmICghZXZlbnRQYXR0ZXJuKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIG1lcmdlRXZlbnRQYXR0ZXJuKHRoaXMuZXZlbnRQYXR0ZXJuLCBldmVudFBhdHRlcm4pO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdCBwcml2YXRlIG9ubHkgdG8gYmUgb3ZlcnJpZGVlbiBpbiBDb3B5UnVsZS5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBwdWJsaWMgX3JlbmRlckV2ZW50UGF0dGVybigpOiBhbnkge1xuICAgIHJldHVybiByZW5kZXJFdmVudFBhdHRlcm4odGhpcy5ldmVudFBhdHRlcm4pO1xuICB9XG5cbiAgcHJvdGVjdGVkIHZhbGlkYXRlKCkge1xuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLmV2ZW50UGF0dGVybikubGVuZ3RoID09PSAwICYmICF0aGlzLnNjaGVkdWxlRXhwcmVzc2lvbikge1xuICAgICAgcmV0dXJuIFsnRWl0aGVyIFxcJ2V2ZW50UGF0dGVyblxcJyBvciBcXCdzY2hlZHVsZVxcJyBtdXN0IGJlIGRlZmluZWQnXTtcbiAgICB9XG5cbiAgICByZXR1cm4gW107XG4gIH1cblxuICBwcml2YXRlIHJlbmRlclRhcmdldHMoKSB7XG4gICAgaWYgKHRoaXMudGFyZ2V0cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudGFyZ2V0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBNYWtlIHN1cmUgd2UgYWRkIHRoZSB0YXJnZXQgZW52aXJvbm1lbnRzIGV2ZW50IGJ1cyBhcyBhIHRhcmdldCwgYW5kIHRoZSB0YXJnZXQgaGFzIHBlcm1pc3Npb25zIHNldCB1cCB0byByZWNlaXZlIG91ciBldmVudHNcbiAgICpcbiAgICogRm9yIGNyb3NzLWFjY291bnQgcnVsZXMsIHVzZXMgYSBzdXBwb3J0IHN0YWNrIHRvIHNldCB1cCBhIHBvbGljeSBvbiB0aGUgdGFyZ2V0IGV2ZW50IGJ1cy5cbiAgICovXG4gIHByaXZhdGUgZW5zdXJlWEVudlRhcmdldEV2ZW50QnVzKHRhcmdldFN0YWNrOiBTdGFjaywgdGFyZ2V0QWNjb3VudDogc3RyaW5nLCB0YXJnZXRSZWdpb246IHN0cmluZywgaWQ6IHN0cmluZykge1xuICAgIC8vIHRoZSBfYWN0dWFsXyB0YXJnZXQgaXMganVzdCB0aGUgZXZlbnQgYnVzIG9mIHRoZSB0YXJnZXQncyBhY2NvdW50XG4gICAgLy8gbWFrZSBzdXJlIHdlIG9ubHkgYWRkIGl0IG9uY2UgcGVyIGFjY291bnQgcGVyIHJlZ2lvblxuICAgIGNvbnN0IGtleSA9IGAke3RhcmdldEFjY291bnR9OiR7dGFyZ2V0UmVnaW9ufWA7XG4gICAgaWYgKHRoaXMuX3hFbnZUYXJnZXRzQWRkZWQuaGFzKGtleSkpIHsgcmV0dXJuOyB9XG4gICAgdGhpcy5feEVudlRhcmdldHNBZGRlZC5hZGQoa2V5KTtcblxuICAgIGNvbnN0IGV2ZW50QnVzQXJuID0gdGFyZ2V0U3RhY2suZm9ybWF0QXJuKHtcbiAgICAgIHNlcnZpY2U6ICdldmVudHMnLFxuICAgICAgcmVzb3VyY2U6ICdldmVudC1idXMnLFxuICAgICAgcmVzb3VyY2VOYW1lOiAnZGVmYXVsdCcsXG4gICAgICByZWdpb246IHRhcmdldFJlZ2lvbixcbiAgICAgIGFjY291bnQ6IHRhcmdldEFjY291bnQsXG4gICAgfSk7XG5cbiAgICAvLyBGb3Igc29tZSByZWFzb24sIGNyb3NzLXJlZ2lvbiByZXF1aXJlcyBhIFJvbGUgKHdpdGggYFB1dEV2ZW50c2Agb24gdGhlXG4gICAgLy8gdGFyZ2V0IGV2ZW50IGJ1cykgd2hpbGUgY3Jvc3MtYWNjb3VudCBkb2Vzbid0XG4gICAgY29uc3Qgcm9sZUFybiA9ICFzYW1lRW52RGltZW5zaW9uKHRhcmdldFJlZ2lvbiwgU3RhY2sub2YodGhpcykucmVnaW9uKVxuICAgICAgPyB0aGlzLmNyb3NzUmVnaW9uUHV0RXZlbnRzUm9sZShldmVudEJ1c0Fybikucm9sZUFyblxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICB0aGlzLnRhcmdldHMucHVzaCh7XG4gICAgICBpZCxcbiAgICAgIGFybjogZXZlbnRCdXNBcm4sXG4gICAgICByb2xlQXJuLFxuICAgIH0pO1xuXG4gICAgLy8gQWRkIGEgcG9saWN5IHRvIHRoZSB0YXJnZXQgRXZlbnQgQnVzIHRvIGFsbG93IHRoZSBzb3VyY2UgYWNjb3VudC9yZWdpb24gdG8gcHVibGlzaCBpbnRvIGl0LlxuICAgIC8vXG4gICAgLy8gU2luY2UgdGhpcyBFdmVudCBCdXMgcGVybWlzc2lvbiBuZWVkcyB0byBiZSBkZXBsb3llZCBiZWZvcmUgdGhlIHN0YWNrIGNvbnRhaW5pbmcgdGhlIFJ1bGUgaXMgZGVwbG95ZWRcbiAgICAvLyAoYXMgRXZlbnRCcmlkZ2UgdmVyaWZpZXMgd2hldGhlciB5b3UgaGF2ZSBwZXJtaXNzaW9ucyB0byB0aGUgdGFyZ2V0cyBvbiBydWxlIGNyZWF0aW9uKSwgdGhpcyBuZWVkc1xuICAgIC8vIHRvIGJlIGluIGEgc3VwcG9ydCBzdGFjay5cblxuICAgIGNvbnN0IHNvdXJjZUFwcCA9IHRoaXMubm9kZS5yb290IGFzIEFwcDtcbiAgICBjb25zdCBzb3VyY2VBY2NvdW50ID0gU3RhY2sub2YodGhpcykuYWNjb3VudDtcblxuICAgIC8vIElmIGRpZmZlcmVudCBhY2NvdW50cywgd2UgbmVlZCB0byBhZGQgdGhlIHBlcm1pc3Npb25zIHRvIHRoZSB0YXJnZXQgZXZlbnRidXNcbiAgICAvL1xuICAgIC8vIEZvciBkaWZmZXJlbnQgcmVnaW9uLCBubyBuZWVkIGZvciBhIHBvbGljeSBvbiB0aGUgdGFyZ2V0IGV2ZW50IGJ1cyAoYnV0IGEgbmVlZFxuICAgIC8vIGZvciBhIHJvbGUpLlxuICAgIGlmICghc2FtZUVudkRpbWVuc2lvbihzb3VyY2VBY2NvdW50LCB0YXJnZXRBY2NvdW50KSkge1xuICAgICAgY29uc3Qgc3RhY2tJZCA9IGBFdmVudEJ1c1BvbGljeS0ke3NvdXJjZUFjY291bnR9LSR7dGFyZ2V0UmVnaW9ufS0ke3RhcmdldEFjY291bnR9YDtcbiAgICAgIGxldCBldmVudEJ1c1BvbGljeVN0YWNrOiBTdGFjayA9IHNvdXJjZUFwcC5ub2RlLnRyeUZpbmRDaGlsZChzdGFja0lkKSBhcyBTdGFjaztcbiAgICAgIGlmICghZXZlbnRCdXNQb2xpY3lTdGFjaykge1xuICAgICAgICBldmVudEJ1c1BvbGljeVN0YWNrID0gbmV3IFN0YWNrKHNvdXJjZUFwcCwgc3RhY2tJZCwge1xuICAgICAgICAgIGVudjoge1xuICAgICAgICAgICAgYWNjb3VudDogdGFyZ2V0QWNjb3VudCxcbiAgICAgICAgICAgIHJlZ2lvbjogdGFyZ2V0UmVnaW9uLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgLy8gVGhlIHJlZ2lvbiBpbiB0aGUgc3RhY2sgbmFtZSBpcyByYXRoZXIgcmVkdW5kYW50IChpdCB3aWxsIGFsd2F5cyBiZSB0aGUgdGFyZ2V0IHJlZ2lvbilcbiAgICAgICAgICAvLyBMZWF2aW5nIGl0IGluIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cbiAgICAgICAgICBzdGFja05hbWU6IGAke3RhcmdldFN0YWNrLnN0YWNrTmFtZX0tRXZlbnRCdXNQb2xpY3ktc3VwcG9ydC0ke3RhcmdldFJlZ2lvbn0tJHtzb3VyY2VBY2NvdW50fWAsXG4gICAgICAgIH0pO1xuICAgICAgICBuZXcgQ2ZuRXZlbnRCdXNQb2xpY3koZXZlbnRCdXNQb2xpY3lTdGFjaywgJ0dpdmVQZXJtVG9PdGhlckFjY291bnQnLCB7XG4gICAgICAgICAgYWN0aW9uOiAnZXZlbnRzOlB1dEV2ZW50cycsXG4gICAgICAgICAgc3RhdGVtZW50SWQ6IGBBbGxvdy1hY2NvdW50LSR7c291cmNlQWNjb3VudH0tJHt0aGlzLm5vZGUuYWRkcn1gLFxuICAgICAgICAgIHByaW5jaXBhbDogc291cmNlQWNjb3VudCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICAvLyBkZXBsb3kgdGhlIGV2ZW50IGJ1cyBwZXJtaXNzaW9ucyBiZWZvcmUgdGhlIHNvdXJjZSBzdGFja1xuICAgICAgU3RhY2sub2YodGhpcykuYWRkRGVwZW5kZW5jeShldmVudEJ1c1BvbGljeVN0YWNrKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBzY29wZSB3aGVyZSB0aGUgbWlycm9yIHJ1bGUgc2hvdWxkIGJlIGNyZWF0ZWQgZm9yIHgtZW52IGV2ZW50IHRhcmdldHNcbiAgICpcbiAgICogVGhpcyBpcyB0aGUgdGFyZ2V0IHJlc291cmNlJ3MgY29udGFpbmluZyBzdGFjayBpZiBpdCBzaGFyZXMgdGhlIHNhbWUgcmVnaW9uIChvd25lZFxuICAgKiByZXNvdXJjZXMpLCBvciBzaG91bGQgYmUgYSBmcmVzaCBzdXBwb3J0IHN0YWNrIGZvciBpbXBvcnRlZCByZXNvdXJjZXMuXG4gICAqXG4gICAqIFdlIGRvbid0IGltcGxlbWVudCB0aGUgc2Vjb25kIHlldCwgYXMgSSBoYXZlIHRvIHRoaW5rIGxvbmcgYW5kIGhhcmQgb24gd2hldGhlciB3ZVxuICAgKiBjYW4gcmV1c2UgdGhlIGV4aXN0aW5nIHN1cHBvcnQgc3RhY2sgb3Igbm90LCBhbmQgSSBkb24ndCBoYXZlIHRpbWUgZm9yIHRoYXQgcmlnaHQgbm93LlxuICAgKi9cbiAgcHJpdmF0ZSBvYnRhaW5NaXJyb3JSdWxlU2NvcGUodGFyZ2V0U3RhY2s6IFN0YWNrLCB0YXJnZXRBY2NvdW50OiBzdHJpbmcsIHRhcmdldFJlZ2lvbjogc3RyaW5nKTogQ29uc3RydWN0IHtcbiAgICAvLyBmb3IgY3Jvc3MtYWNjb3VudCBvciBjcm9zcy1yZWdpb24gZXZlbnRzLCB3ZSBjYW5ub3QgY3JlYXRlIG5ldyBjb21wb25lbnRzIGZvciBhbiBpbXBvcnRlZCByZXNvdXJjZVxuICAgIC8vIGJlY2F1c2Ugd2UgZG9uJ3QgaGF2ZSB0aGUgdGFyZ2V0IHN0YWNrXG4gICAgaWYgKHNhbWVFbnZEaW1lbnNpb24odGFyZ2V0U3RhY2suYWNjb3VudCwgdGFyZ2V0QWNjb3VudCkgJiYgc2FtZUVudkRpbWVuc2lvbih0YXJnZXRTdGFjay5yZWdpb24sIHRhcmdldFJlZ2lvbikpIHtcbiAgICAgIHJldHVybiB0YXJnZXRTdGFjaztcbiAgICB9XG5cbiAgICAvLyBGb3Igbm93LCB3ZSBkb24ndCBkbyB0aGUgd29yayBmb3IgdGhlIHN1cHBvcnQgc3RhY2sgeWV0XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgY3JlYXRlIGEgY3Jvc3MtYWNjb3VudCBvciBjcm9zcy1yZWdpb24gcnVsZSBmb3IgYW4gaW1wb3J0ZWQgcmVzb3VyY2UgKGNyZWF0ZSBhIHN0YWNrIHdpdGggdGhlIHJpZ2h0IGVudmlyb25tZW50IGZvciB0aGUgaW1wb3J0ZWQgcmVzb3VyY2UpJyk7XG4gIH1cblxuICAvKipcbiAgICogT2J0YWluIHRoZSBSb2xlIGZvciB0aGUgRXZlbnRCcmlkZ2UgZXZlbnRcbiAgICpcbiAgICogSWYgYSByb2xlIGFscmVhZHkgZXhpc3RzLCBpdCB3aWxsIGJlIHJldHVybmVkLiBUaGlzIGVuc3VyZXMgdGhhdCBpZiBtdWx0aXBsZVxuICAgKiBldmVudHMgaGF2ZSB0aGUgc2FtZSB0YXJnZXQsIHRoZXkgd2lsbCBzaGFyZSBhIHJvbGUuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHJpdmF0ZSBjcm9zc1JlZ2lvblB1dEV2ZW50c1JvbGUoZXZlbnRCdXNBcm46IHN0cmluZyk6IElSb2xlIHtcbiAgICBjb25zdCBpZCA9ICdFdmVudHNSb2xlJztcbiAgICBsZXQgcm9sZSA9IHRoaXMubm9kZS50cnlGaW5kQ2hpbGQoaWQpIGFzIElSb2xlO1xuICAgIGlmICghcm9sZSkge1xuICAgICAgcm9sZSA9IG5ldyBSb2xlKHRoaXMsIGlkLCB7XG4gICAgICAgIHJvbGVOYW1lOiBQaHlzaWNhbE5hbWUuR0VORVJBVEVfSUZfTkVFREVELFxuICAgICAgICBhc3N1bWVkQnk6IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdldmVudHMuYW1hem9uYXdzLmNvbScpLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcm9sZS5hZGRUb1ByaW5jaXBhbFBvbGljeShuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGFjdGlvbnM6IFsnZXZlbnRzOlB1dEV2ZW50cyddLFxuICAgICAgcmVzb3VyY2VzOiBbZXZlbnRCdXNBcm5dLFxuICAgIH0pKTtcblxuICAgIHJldHVybiByb2xlO1xuICB9XG59XG5cbi8qKlxuICogQSBydWxlIHRoYXQgbWlycm9ycyBhbm90aGVyIHJ1bGVcbiAqL1xuY2xhc3MgTWlycm9yUnVsZSBleHRlbmRzIFJ1bGUge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogUnVsZVByb3BzLCBwcml2YXRlIHJlYWRvbmx5IHNvdXJjZTogUnVsZSkge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpO1xuICB9XG5cbiAgcHVibGljIF9yZW5kZXJFdmVudFBhdHRlcm4oKTogYW55IHtcbiAgICByZXR1cm4gdGhpcy5zb3VyY2UuX3JlbmRlckV2ZW50UGF0dGVybigpO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHZhbGlkYXRlIHRvIGJlIGEgbm8tb3BcbiAgICpcbiAgICogVGhlIHJ1bGVzIGFyZSBuZXZlciBzdG9yZWQgb24gdGhpcyBvYmplY3Qgc28gdGhlcmUncyBub3RoaW5nIHRvIHZhbGlkYXRlLlxuICAgKlxuICAgKiBJbnN0ZWFkLCB3ZSBtaXJyb3IgdGhlIG90aGVyIHJ1bGUgYXQgcmVuZGVyIHRpbWUuXG4gICAqL1xuICBwcm90ZWN0ZWQgdmFsaWRhdGUoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBbXTtcbiAgfVxufVxuIl19 |
\ | No newline at end of file |