UNPKG

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