UNPKG

53.4 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.Rule = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const aws_iam_1 = require("@aws-cdk/aws-iam");
8const core_1 = require("@aws-cdk/core");
9const constructs_1 = require("constructs");
10const events_generated_1 = require("./events.generated");
11const schedule_1 = require("./schedule");
12const util_1 = require("./util");
13/**
14 * Defines an EventBridge Rule in this stack.
15 *
16 * @resource AWS::Events::Rule
17 */
18class 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}
365exports.Rule = Rule;
366_a = JSII_RTTI_SYMBOL_1;
367Rule[_a] = { fqn: "@aws-cdk/aws-events.Rule", version: "1.204.0" };
368/**
369 * A rule that mirrors another rule
370 */
371class 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