1 | ;
|
2 | var _a;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.LogGroup = exports.RetentionDays = void 0;
|
5 | const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const cloudwatch = require("@aws-cdk/aws-cloudwatch");
|
8 | const iam = require("@aws-cdk/aws-iam");
|
9 | const core_1 = require("@aws-cdk/core");
|
10 | const log_stream_1 = require("./log-stream");
|
11 | const logs_generated_1 = require("./logs.generated");
|
12 | const metric_filter_1 = require("./metric-filter");
|
13 | const pattern_1 = require("./pattern");
|
14 | const policy_1 = require("./policy");
|
15 | const subscription_filter_1 = require("./subscription-filter");
|
16 | /**
|
17 | * An CloudWatch Log Group
|
18 | */
|
19 | class LogGroupBase extends core_1.Resource {
|
20 | /**
|
21 | * Create a new Log Stream for this Log Group
|
22 | *
|
23 | * @param id Unique identifier for the construct in its parent
|
24 | * @param props Properties for creating the LogStream
|
25 | */
|
26 | addStream(id, props = {}) {
|
27 | return new log_stream_1.LogStream(this, id, {
|
28 | logGroup: this,
|
29 | ...props,
|
30 | });
|
31 | }
|
32 | /**
|
33 | * Create a new Subscription Filter on this Log Group
|
34 | *
|
35 | * @param id Unique identifier for the construct in its parent
|
36 | * @param props Properties for creating the SubscriptionFilter
|
37 | */
|
38 | addSubscriptionFilter(id, props) {
|
39 | return new subscription_filter_1.SubscriptionFilter(this, id, {
|
40 | logGroup: this,
|
41 | ...props,
|
42 | });
|
43 | }
|
44 | /**
|
45 | * Create a new Metric Filter on this Log Group
|
46 | *
|
47 | * @param id Unique identifier for the construct in its parent
|
48 | * @param props Properties for creating the MetricFilter
|
49 | */
|
50 | addMetricFilter(id, props) {
|
51 | return new metric_filter_1.MetricFilter(this, id, {
|
52 | logGroup: this,
|
53 | ...props,
|
54 | });
|
55 | }
|
56 | /**
|
57 | * Extract a metric from structured log events in the LogGroup
|
58 | *
|
59 | * Creates a MetricFilter on this LogGroup that will extract the value
|
60 | * of the indicated JSON field in all records where it occurs.
|
61 | *
|
62 | * The metric will be available in CloudWatch Metrics under the
|
63 | * indicated namespace and name.
|
64 | *
|
65 | * @param jsonField JSON field to extract (example: '$.myfield')
|
66 | * @param metricNamespace Namespace to emit the metric under
|
67 | * @param metricName Name to emit the metric under
|
68 | * @returns A Metric object representing the extracted metric
|
69 | */
|
70 | extractMetric(jsonField, metricNamespace, metricName) {
|
71 | new metric_filter_1.MetricFilter(this, `${metricNamespace}_${metricName}`, {
|
72 | logGroup: this,
|
73 | metricNamespace,
|
74 | metricName,
|
75 | filterPattern: pattern_1.FilterPattern.exists(jsonField),
|
76 | metricValue: jsonField,
|
77 | });
|
78 | return new cloudwatch.Metric({ metricName, namespace: metricNamespace }).attachTo(this);
|
79 | }
|
80 | /**
|
81 | * Give permissions to create and write to streams in this log group
|
82 | */
|
83 | grantWrite(grantee) {
|
84 | return this.grant(grantee, 'logs:CreateLogStream', 'logs:PutLogEvents');
|
85 | }
|
86 | /**
|
87 | * Give the indicated permissions on this log group and all streams
|
88 | */
|
89 | grant(grantee, ...actions) {
|
90 | return iam.Grant.addToPrincipalOrResource({
|
91 | grantee,
|
92 | actions,
|
93 | // A LogGroup ARN out of CloudFormation already includes a ':*' at the end to include the log streams under the group.
|
94 | // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html#w2ab1c21c10c63c43c11
|
95 | resourceArns: [this.logGroupArn],
|
96 | resource: this,
|
97 | });
|
98 | }
|
99 | /**
|
100 | * Public method to get the physical name of this log group
|
101 | * @returns Physical name of log group
|
102 | */
|
103 | logGroupPhysicalName() {
|
104 | return this.physicalName;
|
105 | }
|
106 | /**
|
107 | * Adds a statement to the resource policy associated with this log group.
|
108 | * A resource policy will be automatically created upon the first call to `addToResourcePolicy`.
|
109 | *
|
110 | * Any ARN Principals inside of the statement will be converted into AWS Account ID strings
|
111 | * because CloudWatch Logs Resource Policies do not accept ARN principals.
|
112 | *
|
113 | * @param statement The policy statement to add
|
114 | */
|
115 | addToResourcePolicy(statement) {
|
116 | if (!this.policy) {
|
117 | this.policy = new policy_1.ResourcePolicy(this, 'Policy');
|
118 | }
|
119 | this.policy.document.addStatements(statement.copy({
|
120 | principals: statement.principals.map(p => this.convertArnPrincpalToAccountId(p)),
|
121 | }));
|
122 | return { statementAdded: true, policyDependable: this.policy };
|
123 | }
|
124 | convertArnPrincpalToAccountId(principal) {
|
125 | if (principal.principalAccount) {
|
126 | // we use ArnPrincipal here because the constructor inserts the argument
|
127 | // into the template without mutating it, which means that there is no
|
128 | // ARN created by this call.
|
129 | return new iam.ArnPrincipal(principal.principalAccount);
|
130 | }
|
131 | if (principal instanceof iam.ArnPrincipal) {
|
132 | const parsedArn = core_1.Arn.split(principal.arn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
|
133 | if (parsedArn.account) {
|
134 | return new iam.ArnPrincipal(parsedArn.account);
|
135 | }
|
136 | }
|
137 | return principal;
|
138 | }
|
139 | }
|
140 | /**
|
141 | * How long, in days, the log contents will be retained.
|
142 | */
|
143 | var RetentionDays;
|
144 | (function (RetentionDays) {
|
145 | /**
|
146 | * 1 day
|
147 | */
|
148 | RetentionDays[RetentionDays["ONE_DAY"] = 1] = "ONE_DAY";
|
149 | /**
|
150 | * 3 days
|
151 | */
|
152 | RetentionDays[RetentionDays["THREE_DAYS"] = 3] = "THREE_DAYS";
|
153 | /**
|
154 | * 5 days
|
155 | */
|
156 | RetentionDays[RetentionDays["FIVE_DAYS"] = 5] = "FIVE_DAYS";
|
157 | /**
|
158 | * 1 week
|
159 | */
|
160 | RetentionDays[RetentionDays["ONE_WEEK"] = 7] = "ONE_WEEK";
|
161 | /**
|
162 | * 2 weeks
|
163 | */
|
164 | RetentionDays[RetentionDays["TWO_WEEKS"] = 14] = "TWO_WEEKS";
|
165 | /**
|
166 | * 1 month
|
167 | */
|
168 | RetentionDays[RetentionDays["ONE_MONTH"] = 30] = "ONE_MONTH";
|
169 | /**
|
170 | * 2 months
|
171 | */
|
172 | RetentionDays[RetentionDays["TWO_MONTHS"] = 60] = "TWO_MONTHS";
|
173 | /**
|
174 | * 3 months
|
175 | */
|
176 | RetentionDays[RetentionDays["THREE_MONTHS"] = 90] = "THREE_MONTHS";
|
177 | /**
|
178 | * 4 months
|
179 | */
|
180 | RetentionDays[RetentionDays["FOUR_MONTHS"] = 120] = "FOUR_MONTHS";
|
181 | /**
|
182 | * 5 months
|
183 | */
|
184 | RetentionDays[RetentionDays["FIVE_MONTHS"] = 150] = "FIVE_MONTHS";
|
185 | /**
|
186 | * 6 months
|
187 | */
|
188 | RetentionDays[RetentionDays["SIX_MONTHS"] = 180] = "SIX_MONTHS";
|
189 | /**
|
190 | * 1 year
|
191 | */
|
192 | RetentionDays[RetentionDays["ONE_YEAR"] = 365] = "ONE_YEAR";
|
193 | /**
|
194 | * 13 months
|
195 | */
|
196 | RetentionDays[RetentionDays["THIRTEEN_MONTHS"] = 400] = "THIRTEEN_MONTHS";
|
197 | /**
|
198 | * 18 months
|
199 | */
|
200 | RetentionDays[RetentionDays["EIGHTEEN_MONTHS"] = 545] = "EIGHTEEN_MONTHS";
|
201 | /**
|
202 | * 2 years
|
203 | */
|
204 | RetentionDays[RetentionDays["TWO_YEARS"] = 731] = "TWO_YEARS";
|
205 | /**
|
206 | * 5 years
|
207 | */
|
208 | RetentionDays[RetentionDays["FIVE_YEARS"] = 1827] = "FIVE_YEARS";
|
209 | /**
|
210 | * 6 years
|
211 | */
|
212 | RetentionDays[RetentionDays["SIX_YEARS"] = 2192] = "SIX_YEARS";
|
213 | /**
|
214 | * 7 years
|
215 | */
|
216 | RetentionDays[RetentionDays["SEVEN_YEARS"] = 2557] = "SEVEN_YEARS";
|
217 | /**
|
218 | * 8 years
|
219 | */
|
220 | RetentionDays[RetentionDays["EIGHT_YEARS"] = 2922] = "EIGHT_YEARS";
|
221 | /**
|
222 | * 9 years
|
223 | */
|
224 | RetentionDays[RetentionDays["NINE_YEARS"] = 3288] = "NINE_YEARS";
|
225 | /**
|
226 | * 10 years
|
227 | */
|
228 | RetentionDays[RetentionDays["TEN_YEARS"] = 3653] = "TEN_YEARS";
|
229 | /**
|
230 | * Retain logs forever
|
231 | */
|
232 | RetentionDays[RetentionDays["INFINITE"] = 9999] = "INFINITE";
|
233 | })(RetentionDays = exports.RetentionDays || (exports.RetentionDays = {}));
|
234 | /**
|
235 | * Define a CloudWatch Log Group
|
236 | */
|
237 | class LogGroup extends LogGroupBase {
|
238 | constructor(scope, id, props = {}) {
|
239 | super(scope, id, {
|
240 | physicalName: props.logGroupName,
|
241 | });
|
242 | try {
|
243 | jsiiDeprecationWarnings._aws_cdk_aws_logs_LogGroupProps(props);
|
244 | }
|
245 | catch (error) {
|
246 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
247 | Error.captureStackTrace(error, LogGroup);
|
248 | }
|
249 | throw error;
|
250 | }
|
251 | let retentionInDays = props.retention;
|
252 | if (retentionInDays === undefined) {
|
253 | retentionInDays = RetentionDays.TWO_YEARS;
|
254 | }
|
255 | if (retentionInDays === Infinity || retentionInDays === RetentionDays.INFINITE) {
|
256 | retentionInDays = undefined;
|
257 | }
|
258 | if (retentionInDays !== undefined && !core_1.Token.isUnresolved(retentionInDays) && retentionInDays <= 0) {
|
259 | throw new Error(`retentionInDays must be positive, got ${retentionInDays}`);
|
260 | }
|
261 | const resource = new logs_generated_1.CfnLogGroup(this, 'Resource', {
|
262 | kmsKeyId: props.encryptionKey?.keyArn,
|
263 | logGroupName: this.physicalName,
|
264 | retentionInDays,
|
265 | });
|
266 | resource.applyRemovalPolicy(props.removalPolicy);
|
267 | this.logGroupArn = this.getResourceArnAttribute(resource.attrArn, {
|
268 | service: 'logs',
|
269 | resource: 'log-group',
|
270 | resourceName: this.physicalName,
|
271 | arnFormat: core_1.ArnFormat.COLON_RESOURCE_NAME,
|
272 | });
|
273 | this.logGroupName = this.getResourceNameAttribute(resource.ref);
|
274 | }
|
275 | /**
|
276 | * Import an existing LogGroup given its ARN
|
277 | */
|
278 | static fromLogGroupArn(scope, id, logGroupArn) {
|
279 | const baseLogGroupArn = logGroupArn.replace(/:\*$/, '');
|
280 | class Import extends LogGroupBase {
|
281 | constructor() {
|
282 | super(...arguments);
|
283 | this.logGroupArn = `${baseLogGroupArn}:*`;
|
284 | this.logGroupName = core_1.Stack.of(scope).splitArn(baseLogGroupArn, core_1.ArnFormat.COLON_RESOURCE_NAME).resourceName;
|
285 | }
|
286 | }
|
287 | return new Import(scope, id, {
|
288 | environmentFromArn: baseLogGroupArn,
|
289 | });
|
290 | }
|
291 | /**
|
292 | * Import an existing LogGroup given its name
|
293 | */
|
294 | static fromLogGroupName(scope, id, logGroupName) {
|
295 | const baseLogGroupName = logGroupName.replace(/:\*$/, '');
|
296 | class Import extends LogGroupBase {
|
297 | constructor() {
|
298 | super(...arguments);
|
299 | this.logGroupName = baseLogGroupName;
|
300 | this.logGroupArn = core_1.Stack.of(scope).formatArn({
|
301 | service: 'logs',
|
302 | resource: 'log-group',
|
303 | arnFormat: core_1.ArnFormat.COLON_RESOURCE_NAME,
|
304 | resourceName: baseLogGroupName + ':*',
|
305 | });
|
306 | }
|
307 | }
|
308 | return new Import(scope, id);
|
309 | }
|
310 | }
|
311 | exports.LogGroup = LogGroup;
|
312 | _a = JSII_RTTI_SYMBOL_1;
|
313 | LogGroup[_a] = { fqn: "@aws-cdk/aws-logs.LogGroup", version: "1.204.0" };
|
314 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLWdyb3VwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibG9nLWdyb3VwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHNEQUFzRDtBQUN0RCx3Q0FBd0M7QUFFeEMsd0NBQXNGO0FBRXRGLDZDQUF5QztBQUN6QyxxREFBK0M7QUFDL0MsbURBQStDO0FBQy9DLHVDQUEwRDtBQUMxRCxxQ0FBMEM7QUFDMUMsK0RBQXdGO0FBd0V4Rjs7R0FFRztBQUNILE1BQWUsWUFBYSxTQUFRLGVBQVE7SUFjMUM7Ozs7O09BS0c7SUFDSSxTQUFTLENBQUMsRUFBVSxFQUFFLFFBQXVCLEVBQUU7UUFDcEQsT0FBTyxJQUFJLHNCQUFTLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRTtZQUM3QixRQUFRLEVBQUUsSUFBSTtZQUNkLEdBQUcsS0FBSztTQUNULENBQUMsQ0FBQztLQUNKO0lBRUQ7Ozs7O09BS0c7SUFDSSxxQkFBcUIsQ0FBQyxFQUFVLEVBQUUsS0FBZ0M7UUFDdkUsT0FBTyxJQUFJLHdDQUFrQixDQUFDLElBQUksRUFBRSxFQUFFLEVBQUU7WUFDdEMsUUFBUSxFQUFFLElBQUk7WUFDZCxHQUFHLEtBQUs7U0FDVCxDQUFDLENBQUM7S0FDSjtJQUVEOzs7OztPQUtHO0lBQ0ksZUFBZSxDQUFDLEVBQVUsRUFBRSxLQUEwQjtRQUMzRCxPQUFPLElBQUksNEJBQVksQ0FBQyxJQUFJLEVBQUUsRUFBRSxFQUFFO1lBQ2hDLFFBQVEsRUFBRSxJQUFJO1lBQ2QsR0FBRyxLQUFLO1NBQ1QsQ0FBQyxDQUFDO0tBQ0o7SUFFRDs7Ozs7Ozs7Ozs7OztPQWFHO0lBQ0ksYUFBYSxDQUFDLFNBQWlCLEVBQUUsZUFBdUIsRUFBRSxVQUFrQjtRQUNqRixJQUFJLDRCQUFZLENBQUMsSUFBSSxFQUFFLEdBQUcsZUFBZSxJQUFJLFVBQVUsRUFBRSxFQUFFO1lBQ3pELFFBQVEsRUFBRSxJQUFJO1lBQ2QsZUFBZTtZQUNmLFVBQVU7WUFDVixhQUFhLEVBQUUsdUJB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QUFVLEVBQUUsWUFBb0I7UUFDL0UsTUFBTSxnQkFBZ0IsR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztRQUUxRCxNQUFNLE1BQU8sU0FBUSxZQUFZO1lBQWpDOztnQkFDa0IsaUJBQVksR0FBRyxnQkFBZ0IsQ0FBQztnQkFDaEMsZ0JBQVcsR0FBRyxZQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLFNBQVMsQ0FBQztvQkFDdEQsT0FBTyxFQUFFLE1BQU07b0JBQ2YsUUFBUSxFQUFFLFdBQVc7b0JBQ3JCLFNBQVMsRUFBRSxnQkFBUyxDQUFDLG1CQUFtQjtvQkFDeEMsWUFBWSxFQUFFLGdCQUFnQixHQUFHLElBQUk7aUJBQ3RDLENBQUMsQ0FBQztZQUNMLENBQUM7U0FBQTtRQUVELE9BQU8sSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0tBQzlCOztBQWxDSCw0QkEyRUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjbG91ZHdhdGNoIGZyb20gJ0Bhd3MtY2RrL2F3cy1jbG91ZHdhdGNoJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGttcyBmcm9tICdAYXdzLWNkay9hd3Mta21zJztcbmltcG9ydCB7IEFybiwgQXJuRm9ybWF0LCBSZW1vdmFsUG9saWN5LCBSZXNvdXJjZSwgU3RhY2ssIFRva2VuIH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IExvZ1N0cmVhbSB9IGZyb20gJy4vbG9nLXN0cmVhbSc7XG5pbXBvcnQgeyBDZm5Mb2dHcm91cCB9IGZyb20gJy4vbG9ncy5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgTWV0cmljRmlsdGVyIH0gZnJvbSAnLi9tZXRyaWMtZmlsdGVyJztcbmltcG9ydCB7IEZpbHRlclBhdHRlcm4sIElGaWx0ZXJQYXR0ZXJuIH0gZnJvbSAnLi9wYXR0ZXJuJztcbmltcG9ydCB7IFJlc291cmNlUG9saWN5IH0gZnJvbSAnLi9wb2xpY3knO1xuaW1wb3J0IHsgSUxvZ1N1YnNjcmlwdGlvbkRlc3RpbmF0aW9uLCBTdWJzY3JpcHRpb25GaWx0ZXIgfSBmcm9tICcuL3N1YnNjcmlwdGlvbi1maWx0ZXInO1xuXG5leHBvcnQgaW50ZXJmYWNlIElMb2dHcm91cCBleHRlbmRzIGlhbS5JUmVzb3VyY2VXaXRoUG9saWN5IHtcbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhpcyBsb2cgZ3JvdXAsIHdpdGggJzoqJyBhcHBlbmRlZFxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cEFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGlzIGxvZyBncm91cFxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cE5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IExvZyBTdHJlYW0gZm9yIHRoaXMgTG9nIEdyb3VwXG4gICAqXG4gICAqIEBwYXJhbSBpZCBVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIGNvbnN0cnVjdCBpbiBpdHMgcGFyZW50XG4gICAqIEBwYXJhbSBwcm9wcyBQcm9wZXJ0aWVzIGZvciBjcmVhdGluZyB0aGUgTG9nU3RyZWFtXG4gICAqL1xuICBhZGRTdHJlYW0oaWQ6IHN0cmluZywgcHJvcHM/OiBTdHJlYW1PcHRpb25zKTogTG9nU3RyZWFtO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgU3Vic2NyaXB0aW9uIEZpbHRlciBvbiB0aGlzIExvZyBHcm91cFxuICAgKlxuICAgKiBAcGFyYW0gaWQgVW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBjb25zdHJ1Y3QgaW4gaXRzIHBhcmVudFxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgY3JlYXRpbmcgdGhlIFN1YnNjcmlwdGlvbkZpbHRlclxuICAgKi9cbiAgYWRkU3Vic2NyaXB0aW9uRmlsdGVyKGlkOiBzdHJpbmcsIHByb3BzOiBTdWJzY3JpcHRpb25GaWx0ZXJPcHRpb25zKTogU3Vic2NyaXB0aW9uRmlsdGVyO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgTWV0cmljIEZpbHRlciBvbiB0aGlzIExvZyBHcm91cFxuICAgKlxuICAgKiBAcGFyYW0gaWQgVW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBjb25zdHJ1Y3QgaW4gaXRzIHBhcmVudFxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgY3JlYXRpbmcgdGhlIE1ldHJpY0ZpbHRlclxuICAgKi9cbiAgYWRkTWV0cmljRmlsdGVyKGlkOiBzdHJpbmcsIHByb3BzOiBNZXRyaWNGaWx0ZXJPcHRpb25zKTogTWV0cmljRmlsdGVyO1xuXG4gIC8qKlxuICAgKiBFeHRyYWN0IGEgbWV0cmljIGZyb20gc3RydWN0dXJlZCBsb2cgZXZlbnRzIGluIHRoZSBMb2dHcm91cFxuICAgKlxuICAgKiBDcmVhdGVzIGEgTWV0cmljRmlsdGVyIG9uIHRoaXMgTG9nR3JvdXAgdGhhdCB3aWxsIGV4dHJhY3QgdGhlIHZhbHVlXG4gICAqIG9mIHRoZSBpbmRpY2F0ZWQgSlNPTiBmaWVsZCBpbiBhbGwgcmVjb3JkcyB3aGVyZSBpdCBvY2N1cnMuXG4gICAqXG4gICAqIFRoZSBtZXRyaWMgd2lsbCBiZSBhdmFpbGFibGUgaW4gQ2xvdWRXYXRjaCBNZXRyaWNzIHVuZGVyIHRoZVxuICAgKiBpbmRpY2F0ZWQgbmFtZXNwYWNlIGFuZCBuYW1lLlxuICAgKlxuICAgKiBAcGFyYW0ganNvbkZpZWxkIEpTT04gZmllbGQgdG8gZXh0cmFjdCAoZXhhbXBsZTogJyQubXlmaWVsZCcpXG4gICAqIEBwYXJhbSBtZXRyaWNOYW1lc3BhY2UgTmFtZXNwYWNlIHRvIGVtaXQgdGhlIG1ldHJpYyB1bmRlclxuICAgKiBAcGFyYW0gbWV0cmljTmFtZSBOYW1lIHRvIGVtaXQgdGhlIG1ldHJpYyB1bmRlclxuICAgKiBAcmV0dXJucyBBIE1ldHJpYyBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBleHRyYWN0ZWQgbWV0cmljXG4gICAqL1xuICBleHRyYWN0TWV0cmljKGpzb25GaWVsZDogc3RyaW5nLCBtZXRyaWNOYW1lc3BhY2U6IHN0cmluZywgbWV0cmljTmFtZTogc3RyaW5nKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIEdpdmUgcGVybWlzc2lvbnMgdG8gd3JpdGUgdG8gY3JlYXRlIGFuZCB3cml0ZSB0byBzdHJlYW1zIGluIHRoaXMgbG9nIGdyb3VwXG4gICAqL1xuICBncmFudFdyaXRlKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50O1xuXG4gIC8qKlxuICAgKiBHaXZlIHRoZSBpbmRpY2F0ZWQgcGVybWlzc2lvbnMgb24gdGhpcyBsb2cgZ3JvdXAgYW5kIGFsbCBzdHJlYW1zXG4gICAqL1xuICBncmFudChncmFudGVlOiBpYW0uSUdyYW50YWJsZSwgLi4uYWN0aW9uczogc3RyaW5nW10pOiBpYW0uR3JhbnQ7XG5cbiAgLyoqXG4gICAqIFB1YmxpYyBtZXRob2QgdG8gZ2V0IHRoZSBwaHlzaWNhbCBuYW1lIG9mIHRoaXMgbG9nIGdyb3VwXG4gICAqL1xuICBsb2dHcm91cFBoeXNpY2FsTmFtZSgpOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQW4gQ2xvdWRXYXRjaCBMb2cgR3JvdXBcbiAqL1xuYWJzdHJhY3QgY2xhc3MgTG9nR3JvdXBCYXNlIGV4dGVuZHMgUmVzb3VyY2UgaW1wbGVtZW50cyBJTG9nR3JvdXAge1xuICAvKipcbiAgICogVGhlIEFSTiBvZiB0aGlzIGxvZyBncm91cCwgd2l0aCAnOionIGFwcGVuZGVkXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgbG9nR3JvdXBBcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhpcyBsb2cgZ3JvdXBcbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBsb2dHcm91cE5hbWU6IHN0cmluZztcblxuXG4gIHByaXZhdGUgcG9saWN5PzogUmVzb3VyY2VQb2xpY3k7XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBMb2cgU3RyZWFtIGZvciB0aGlzIExvZyBHcm91cFxuICAgKlxuICAgKiBAcGFyYW0gaWQgVW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBjb25zdHJ1Y3QgaW4gaXRzIHBhcmVudFxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgY3JlYXRpbmcgdGhlIExvZ1N0cmVhbVxuICAgKi9cbiAgcHVibGljIGFkZFN0cmVhbShpZDogc3RyaW5nLCBwcm9wczogU3RyZWFtT3B0aW9ucyA9IHt9KTogTG9nU3RyZWFtIHtcbiAgICByZXR1cm4gbmV3IExvZ1N0cmVhbSh0aGlzLCBpZCwge1xuICAgICAgbG9nR3JvdXA6IHRoaXMsXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgU3Vic2NyaXB0aW9uIEZpbHRlciBvbiB0aGlzIExvZyBHcm91cFxuICAgKlxuICAgKiBAcGFyYW0gaWQgVW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBjb25zdHJ1Y3QgaW4gaXRzIHBhcmVudFxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgY3JlYXRpbmcgdGhlIFN1YnNjcmlwdGlvbkZpbHRlclxuICAgKi9cbiAgcHVibGljIGFkZFN1YnNjcmlwdGlvbkZpbHRlcihpZDogc3RyaW5nLCBwcm9wczogU3Vic2NyaXB0aW9uRmlsdGVyT3B0aW9ucyk6IFN1YnNjcmlwdGlvbkZpbHRlciB7XG4gICAgcmV0dXJuIG5ldyBTdWJzY3JpcHRpb25GaWx0ZXIodGhpcywgaWQsIHtcbiAgICAgIGxvZ0dyb3VwOiB0aGlzLFxuICAgICAgLi4ucHJvcHMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IE1ldHJpYyBGaWx0ZXIgb24gdGhpcyBMb2cgR3JvdXBcbiAgICpcbiAgICogQHBhcmFtIGlkIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgY29uc3RydWN0IGluIGl0cyBwYXJlbnRcbiAgICogQHBhcmFtIHByb3BzIFByb3BlcnRpZXMgZm9yIGNyZWF0aW5nIHRoZSBNZXRyaWNGaWx0ZXJcbiAgICovXG4gIHB1YmxpYyBhZGRNZXRyaWNGaWx0ZXIoaWQ6IHN0cmluZywgcHJvcHM6IE1ldHJpY0ZpbHRlck9wdGlvbnMpOiBNZXRyaWNGaWx0ZXIge1xuICAgIHJldHVybiBuZXcgTWV0cmljRmlsdGVyKHRoaXMsIGlkLCB7XG4gICAgICBsb2dHcm91cDogdGhpcyxcbiAgICAgIC4uLnByb3BzLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4dHJhY3QgYSBtZXRyaWMgZnJvbSBzdHJ1Y3R1cmVkIGxvZyBldmVudHMgaW4gdGhlIExvZ0dyb3VwXG4gICAqXG4gICAqIENyZWF0ZXMgYSBNZXRyaWNGaWx0ZXIgb24gdGhpcyBMb2dHcm91cCB0aGF0IHdpbGwgZXh0cmFjdCB0aGUgdmFsdWVcbiAgICogb2YgdGhlIGluZGljYXRlZCBKU09OIGZpZWxkIGluIGFsbCByZWNvcmRzIHdoZXJlIGl0IG9jY3Vycy5cbiAgICpcbiAgICogVGhlIG1ldHJpYyB3aWxsIGJlIGF2YWlsYWJsZSBpbiBDbG91ZFdhdGNoIE1ldHJpY3MgdW5kZXIgdGhlXG4gICAqIGluZGljYXRlZCBuYW1lc3BhY2UgYW5kIG5hbWUuXG4gICAqXG4gICAqIEBwYXJhbSBqc29uRmllbGQgSlNPTiBmaWVsZCB0byBleHRyYWN0IChleGFtcGxlOiAnJC5teWZpZWxkJylcbiAgICogQHBhcmFtIG1ldHJpY05hbWVzcGFjZSBOYW1lc3BhY2UgdG8gZW1pdCB0aGUgbWV0cmljIHVuZGVyXG4gICAqIEBwYXJhbSBtZXRyaWNOYW1lIE5hbWUgdG8gZW1pdCB0aGUgbWV0cmljIHVuZGVyXG4gICAqIEByZXR1cm5zIEEgTWV0cmljIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIGV4dHJhY3RlZCBtZXRyaWNcbiAgICovXG4gIHB1YmxpYyBleHRyYWN0TWV0cmljKGpzb25GaWVsZDogc3RyaW5nLCBtZXRyaWNOYW1lc3BhY2U6IHN0cmluZywgbWV0cmljTmFtZTogc3RyaW5nKSB7XG4gICAgbmV3IE1ldHJpY0ZpbHRlcih0aGlzLCBgJHttZXRyaWNOYW1lc3BhY2V9XyR7bWV0cmljTmFtZX1gLCB7XG4gICAgICBsb2dHcm91cDogdGhpcyxcbiAgICAgIG1ldHJpY05hbWVzcGFjZSxcbiAgICAgIG1ldHJpY05hbWUsXG4gICAgICBmaWx0ZXJQYXR0ZXJuOiBGaWx0ZXJQYXR0ZXJuLmV4aXN0cyhqc29uRmllbGQpLFxuICAgICAgbWV0cmljVmFsdWU6IGpzb25GaWVsZCxcbiAgICB9KTtcblxuICAgIHJldHVybiBuZXcgY2xvdWR3YXRjaC5NZXRyaWMoeyBtZXRyaWNOYW1lLCBuYW1lc3BhY2U6IG1ldHJpY05hbWVzcGFjZSB9KS5hdHRhY2hUbyh0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHaXZlIHBlcm1pc3Npb25zIHRvIGNyZWF0ZSBhbmQgd3JpdGUgdG8gc3RyZWFtcyBpbiB0aGlzIGxvZyBncm91cFxuICAgKi9cbiAgcHVibGljIGdyYW50V3JpdGUoZ3JhbnRlZTogaWFtLklHcmFudGFibGUpIHtcbiAgICByZXR1cm4gdGhpcy5ncmFudChncmFudGVlLCAnbG9nczpDcmVhdGVMb2dTdHJlYW0nLCAnbG9nczpQdXRMb2dFdmVudHMnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHaXZlIHRoZSBpbmRpY2F0ZWQgcGVybWlzc2lvbnMgb24gdGhpcyBsb2cgZ3JvdXAgYW5kIGFsbCBzdHJlYW1zXG4gICAqL1xuICBwdWJsaWMgZ3JhbnQoZ3JhbnRlZTogaWFtLklHcmFudGFibGUsIC4uLmFjdGlvbnM6IHN0cmluZ1tdKSB7XG4gICAgcmV0dXJuIGlhbS5HcmFudC5hZGRUb1ByaW5jaXBhbE9yUmVzb3VyY2Uoe1xuICAgICAgZ3JhbnRlZSxcbiAgICAgIGFjdGlvbnMsXG4gICAgICAvLyBBIExvZ0dyb3VwIEFSTiBvdXQgb2YgQ2xvdWRGb3JtYXRpb24gYWxyZWFkeSBpbmNsdWRlcyBhICc6KicgYXQgdGhlIGVuZCB0byBpbmNsdWRlIHRoZSBsb2cgc3RyZWFtcyB1bmRlciB0aGUgZ3JvdXAuXG4gICAgICAvLyBTZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvYXdzLXJlc291cmNlLWxvZ3MtbG9nZ3JvdXAuaHRtbCN3MmFiMWMyMWMxMGM2M2M0M2MxMVxuICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5sb2dHcm91cEFybl0sXG4gICAgICByZXNvdXJjZTogdGhpcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWMgbWV0aG9kIHRvIGdldCB0aGUgcGh5c2ljYWwgbmFtZSBvZiB0aGlzIGxvZyBncm91cFxuICAgKiBAcmV0dXJucyBQaHlzaWNhbCBuYW1lIG9mIGxvZyBncm91cFxuICAgKi9cbiAgcHVibGljIGxvZ0dyb3VwUGh5c2ljYWxOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucGh5c2ljYWxOYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzdGF0ZW1lbnQgdG8gdGhlIHJlc291cmNlIHBvbGljeSBhc3NvY2lhdGVkIHdpdGggdGhpcyBsb2cgZ3JvdXAuXG4gICAqIEEgcmVzb3VyY2UgcG9saWN5IHdpbGwgYmUgYXV0b21hdGljYWxseSBjcmVhdGVkIHVwb24gdGhlIGZpcnN0IGNhbGwgdG8gYGFkZFRvUmVzb3VyY2VQb2xpY3lgLlxuICAgKlxuICAgKiBBbnkgQVJOIFByaW5jaXBhbHMgaW5zaWRlIG9mIHRoZSBzdGF0ZW1lbnQgd2lsbCBiZSBjb252ZXJ0ZWQgaW50byBBV1MgQWNjb3VudCBJRCBzdHJpbmdzXG4gICAqIGJlY2F1c2UgQ2xvdWRXYXRjaCBMb2dzIFJlc291cmNlIFBvbGljaWVzIGRvIG5vdCBhY2NlcHQgQVJOIHByaW5jaXBhbHMuXG4gICAqXG4gICAqIEBwYXJhbSBzdGF0ZW1lbnQgVGhlIHBvbGljeSBzdGF0ZW1lbnQgdG8gYWRkXG4gICAqL1xuICBwdWJsaWMgYWRkVG9SZXNvdXJjZVBvbGljeShzdGF0ZW1lbnQ6IGlhbS5Qb2xpY3lTdGF0ZW1lbnQpOiBpYW0uQWRkVG9SZXNvdXJjZVBvbGljeVJlc3VsdCB7XG4gICAgaWYgKCF0aGlzLnBvbGljeSkge1xuICAgICAgdGhpcy5wb2xpY3kgPSBuZXcgUmVzb3VyY2VQb2xpY3kodGhpcywgJ1BvbGljeScpO1xuICAgIH1cbiAgICB0aGlzLnBvbGljeS5kb2N1bWVudC5hZGRTdGF0ZW1lbnRzKHN0YXRlbWVudC5jb3B5KHtcbiAgICAgIHByaW5jaXBhbHM6IHN0YXRlbWVudC5wcmluY2lwYWxzLm1hcChwID0+IHRoaXMuY29udmVydEFyblByaW5jcGFsVG9BY2NvdW50SWQocCkpLFxuICAgIH0pKTtcbiAgICByZXR1cm4geyBzdGF0ZW1lbnRBZGRlZDogdHJ1ZSwgcG9saWN5RGVwZW5kYWJsZTogdGhpcy5wb2xpY3kgfTtcbiAgfVxuXG4gIHByaXZhdGUgY29udmVydEFyblByaW5jcGFsVG9BY2NvdW50SWQocHJpbmNpcGFsOiBpYW0uSVByaW5jaXBhbCkge1xuICAgIGlmIChwcmluY2lwYWwucHJpbmNpcGFsQWNjb3VudCkge1xuICAgICAgLy8gd2UgdXNlIEFyblByaW5jaXBhbCBoZXJlIGJlY2F1c2UgdGhlIGNvbnN0cnVjdG9yIGluc2VydHMgdGhlIGFyZ3VtZW50XG4gICAgICAvLyBpbnRvIHRoZSB0ZW1wbGF0ZSB3aXRob3V0IG11dGF0aW5nIGl0LCB3aGljaCBtZWFucyB0aGF0IHRoZXJlIGlzIG5vXG4gICAgICAvLyBBUk4gY3JlYXRlZCBieSB0aGlzIGNhbGwuXG4gICAgICByZXR1cm4gbmV3IGlhbS5Bcm5QcmluY2lwYWwocHJpbmNpcGFsLnByaW5jaXBhbEFjY291bnQpO1xuICAgIH1cblxuICAgIGlmIChwcmluY2lwYWwgaW5zdGFuY2VvZiBpYW0uQXJuUHJpbmNpcGFsKSB7XG4gICAgICBjb25zdCBwYXJzZWRBcm4gPSBBcm4uc3BsaXQocHJpbmNpcGFsLmFybiwgQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUpO1xuICAgICAgaWYgKHBhcnNlZEFybi5hY2NvdW50KSB7XG4gICAgICAgIHJldHVybiBuZXcgaWFtLkFyblByaW5jaXBhbChwYXJzZWRBcm4uYWNjb3VudCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByaW5jaXBhbDtcbiAgfVxufVxuXG4vKipcbiAqIEhvdyBsb25nLCBpbiBkYXlzLCB0aGUgbG9nIGNvbnRlbnRzIHdpbGwgYmUgcmV0YWluZWQuXG4gKi9cbmV4cG9ydCBlbnVtIFJldGVudGlvbkRheXMge1xuICAvKipcbiAgICogMSBkYXlcbiAgICovXG4gIE9ORV9EQVkgPSAxLFxuXG4gIC8qKlxuICAgKiAzIGRheXNcbiAgICovXG4gIFRIUkVFX0RBWVMgPSAzLFxuXG4gIC8qKlxuICAgKiA1IGRheXNcbiAgICovXG4gIEZJVkVfREFZUyA9IDUsXG5cbiAgLyoqXG4gICAqIDEgd2Vla1xuICAgKi9cbiAgT05FX1dFRUsgPSA3LFxuXG4gIC8qKlxuICAgKiAyIHdlZWtzXG4gICAqL1xuICBUV09fV0VFS1MgPSAxNCxcblxuICAvKipcbiAgICogMSBtb250aFxuICAgKi9cbiAgT05FX01PTlRIID0gMzAsXG5cbiAgLyoqXG4gICAqIDIgbW9udGhzXG4gICAqL1xuICBUV09fTU9OVEhTID0gNjAsXG5cbiAgLyoqXG4gICAqIDMgbW9udGhzXG4gICAqL1xuICBUSFJFRV9NT05USFMgPSA5MCxcblxuICAvKipcbiAgICogNCBtb250aHNcbiAgICovXG4gIEZPVVJfTU9OVEhTID0gMTIwLFxuXG4gIC8qKlxuICAgKiA1IG1vbnRoc1xuICAgKi9cbiAgRklWRV9NT05USFMgPSAxNTAsXG5cbiAgLyoqXG4gICAqIDYgbW9udGhzXG4gICAqL1xuICBTSVhfTU9OVEhTID0gMTgwLFxuXG4gIC8qKlxuICAgKiAxIHllYXJcbiAgICovXG4gIE9ORV9ZRUFSID0gMzY1LFxuXG4gIC8qKlxuICAgKiAxMyBtb250aHNcbiAgICovXG4gIFRISVJURUVOX01PTlRIUyA9IDQwMCxcblxuICAvKipcbiAgICogMTggbW9udGhzXG4gICAqL1xuICBFSUdIVEVFTl9NT05USFMgPSA1NDUsXG5cbiAgLyoqXG4gICAqIDIgeWVhcnNcbiAgICovXG4gIFRXT19ZRUFSUyA9IDczMSxcblxuICAvKipcbiAgICogNSB5ZWFyc1xuICAgKi9cbiAgRklWRV9ZRUFSUyA9IDE4MjcsXG5cbiAgLyoqXG4gICAqIDYgeWVhcnNcbiAgICovXG4gIFNJWF9ZRUFSUyA9IDIxOTIsXG5cbiAgLyoqXG4gICAqIDcgeWVhcnNcbiAgICovXG4gIFNFVkVOX1lFQVJTID0gMjU1NyxcblxuICAvKipcbiAgICogOCB5ZWFyc1xuICAgKi9cbiAgRUlHSFRfWUVBUlMgPSAyOTIyLFxuXG4gIC8qKlxuICAgKiA5IHllYXJzXG4gICAqL1xuICBOSU5FX1lFQVJTID0gMzI4OCxcblxuICAvKipcbiAgICogMTAgeWVhcnNcbiAgICovXG4gIFRFTl9ZRUFSUyA9IDM2NTMsXG5cbiAgLyoqXG4gICAqIFJldGFpbiBsb2dzIGZvcmV2ZXJcbiAgICovXG4gIElORklOSVRFID0gOTk5OSxcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBhIExvZ0dyb3VwXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTG9nR3JvdXBQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgS01TIEtleSB0byBlbmNyeXB0IHRoZSBsb2cgZ3JvdXAgd2l0aC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBsb2cgZ3JvdXAgaXMgZW5jcnlwdGVkIHdpdGggdGhlIGRlZmF1bHQgbWFzdGVyIGtleVxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbktleT86IGttcy5JS2V5O1xuXG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSBsb2cgZ3JvdXAuXG4gICAqXG4gICAqIEBkZWZhdWx0IEF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cE5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEhvdyBsb25nLCBpbiBkYXlzLCB0aGUgbG9nIGNvbnRlbnRzIHdpbGwgYmUgcmV0YWluZWQuXG4gICAqXG4gICAqIFRvIHJldGFpbiBhbGwgbG9ncywgc2V0IHRoaXMgdmFsdWUgdG8gUmV0ZW50aW9uRGF5cy5JTkZJTklURS5cbiAgICpcbiAgICogQGRlZmF1bHQgUmV0ZW50aW9uRGF5cy5UV09fWUVBUlNcbiAgICovXG4gIHJlYWRvbmx5IHJldGVudGlvbj86IFJldGVudGlvbkRheXM7XG5cbiAgLyoqXG4gICAqIERldGVybWluZSB0aGUgcmVtb3ZhbCBwb2xpY3kgb2YgdGhpcyBsb2cgZ3JvdXAuXG4gICAqXG4gICAqIE5vcm1hbGx5IHlvdSB3YW50IHRvIHJldGFpbiB0aGUgbG9nIGdyb3VwIHNvIHlvdSBjYW4gZGlhZ25vc2UgaXNzdWVzXG4gICAqIGZyb20gbG9ncyBldmVuIGFmdGVyIGEgZGVwbG95bWVudCB0aGF0IG5vIGxvbmdlciBpbmNsdWRlcyB0aGUgbG9nIGdyb3VwLlxuICAgKiBJbiB0aGF0IGNhc2UsIHVzZSB0aGUgbm9ybWFsIGRhdGUtYmFzZWQgcmV0ZW50aW9uIHBvbGljeSB0byBhZ2Ugb3V0IHlvdXJcbiAgICogbG9ncy5cbiAgICpcbiAgICogQGRlZmF1bHQgUmVtb3ZhbFBvbGljeS5SZXRhaW5cbiAgICovXG4gIHJlYWRvbmx5IHJlbW92YWxQb2xpY3k/OiBSZW1vdmFsUG9saWN5O1xufVxuXG4vKipcbiAqIERlZmluZSBhIENsb3VkV2F0Y2ggTG9nIEdyb3VwXG4gKi9cbmV4cG9ydCBjbGFzcyBMb2dHcm91cCBleHRlbmRzIExvZ0dyb3VwQmFzZSB7XG4gIC8qKlxuICAgKiBJbXBvcnQgYW4gZXhpc3RpbmcgTG9nR3JvdXAgZ2l2ZW4gaXRzIEFSTlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tTG9nR3JvdXBBcm4oc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgbG9nR3JvdXBBcm46IHN0cmluZyk6IElMb2dHcm91cCB7XG4gICAgY29uc3QgYmFzZUxvZ0dyb3VwQXJuID0gbG9nR3JvdXBBcm4ucmVwbGFjZSgvOlxcKiQvLCAnJyk7XG5cbiAgICBjbGFzcyBJbXBvcnQgZXh0ZW5kcyBMb2dHcm91cEJhc2Uge1xuICAgICAgcHVibGljIHJlYWRvbmx5IGxvZ0dyb3VwQXJuID0gYCR7YmFzZUxvZ0dyb3VwQXJufToqYDtcbiAgICAgIHB1YmxpYyByZWFkb25seSBsb2dHcm91cE5hbWUgPSBTdGFjay5vZihzY29wZSkuc3BsaXRBcm4oYmFzZUxvZ0dyb3VwQXJuLCBBcm5Gb3JtYXQuQ09MT05fUkVTT1VSQ0VfTkFNRSkucmVzb3VyY2VOYW1lITtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEltcG9ydChzY29wZSwgaWQsIHtcbiAgICAgIGVudmlyb25tZW50RnJvbUFybjogYmFzZUxvZ0dyb3VwQXJuLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEltcG9ydCBhbiBleGlzdGluZyBMb2dHcm91cCBnaXZlbiBpdHMgbmFtZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tTG9nR3JvdXBOYW1lKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIGxvZ0dyb3VwTmFtZTogc3RyaW5nKTogSUxvZ0dyb3VwIHtcbiAgICBjb25zdCBiYXNlTG9nR3JvdXBOYW1lID0gbG9nR3JvdXBOYW1lLnJlcGxhY2UoLzpcXCokLywgJycpO1xuXG4gICAgY2xhc3MgSW1wb3J0IGV4dGVuZHMgTG9nR3JvdXBCYXNlIHtcbiAgICAgIHB1YmxpYyByZWFkb25seSBsb2dHcm91cE5hbWUgPSBiYXNlTG9nR3JvdXBOYW1lO1xuICAgICAgcHVibGljIHJlYWRvbmx5IGxvZ0dyb3VwQXJuID0gU3RhY2sub2Yoc2NvcGUpLmZvcm1hdEFybih7XG4gICAgICAgIHNlcnZpY2U6ICdsb2dzJyxcbiAgICAgICAgcmVzb3VyY2U6ICdsb2ctZ3JvdXAnLFxuICAgICAgICBhcm5Gb3JtYXQ6IEFybkZvcm1hdC5DT0xPTl9SRVNPVVJDRV9OQU1FLFxuICAgICAgICByZXNvdXJjZU5hbWU6IGJhc2VMb2dHcm91cE5hbWUgKyAnOionLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBJbXBvcnQoc2NvcGUsIGlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoaXMgbG9nIGdyb3VwXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbG9nR3JvdXBBcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhpcyBsb2cgZ3JvdXBcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBsb2dHcm91cE5hbWU6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTG9nR3JvdXBQcm9wcyA9IHt9KSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBwaHlzaWNhbE5hbWU6IHByb3BzLmxvZ0dyb3VwTmFtZSxcbiAgICB9KTtcblxuICAgIGxldCByZXRlbnRpb25JbkRheXMgPSBwcm9wcy5yZXRlbnRpb247XG4gICAgaWYgKHJldGVudGlvbkluRGF5cyA9PT0gdW5kZWZpbmVkKSB7IHJldGVudGlvbkluRGF5cyA9IFJldGVudGlvbkRheXMuVFdPX1lFQVJTOyB9XG4gICAgaWYgKHJldGVudGlvbkluRGF5cyA9PT0gSW5maW5pdHkgfHwgcmV0ZW50aW9uSW5EYXlzID09PSBSZXRlbnRpb25EYXlzLklORklOSVRFKSB7IHJldGVudGlvbkluRGF5cyA9IHVuZGVmaW5lZDsgfVxuXG4gICAgaWYgKHJldGVudGlvbkluRGF5cyAhPT0gdW5kZWZpbmVkICYmICFUb2tlbi5pc1VucmVzb2x2ZWQocmV0ZW50aW9uSW5EYXlzKSAmJiByZXRlbnRpb25JbkRheXMgPD0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGByZXRlbnRpb25JbkRheXMgbXVzdCBiZSBwb3NpdGl2ZSwgZ290ICR7cmV0ZW50aW9uSW5EYXlzfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc291cmNlID0gbmV3IENmbkxvZ0dyb3VwKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIGttc0tleUlkOiBwcm9wcy5lbmNyeXB0aW9uS2V5Py5rZXlBcm4sXG4gICAgICBsb2dHcm91cE5hbWU6IHRoaXMucGh5c2ljYWxOYW1lLFxuICAgICAgcmV0ZW50aW9uSW5EYXlzLFxuICAgIH0pO1xuXG4gICAgcmVzb3VyY2UuYXBwbHlSZW1vdmFsUG9saWN5KHByb3BzLnJlbW92YWxQb2xpY3kpO1xuXG4gICAgdGhpcy5sb2dHcm91cEFybiA9IHRoaXMuZ2V0UmVzb3VyY2VBcm5BdHRyaWJ1dGUocmVzb3VyY2UuYXR0ckFybiwge1xuICAgICAgc2VydmljZTogJ2xvZ3MnLFxuICAgICAgcmVzb3VyY2U6ICdsb2ctZ3JvdXAnLFxuICAgICAgcmVzb3VyY2VOYW1lOiB0aGlzLnBoeXNpY2FsTmFtZSxcbiAgICAgIGFybkZvcm1hdDogQXJuRm9ybWF0LkNPTE9OX1JFU09VUkNFX05BTUUsXG4gICAgfSk7XG4gICAgdGhpcy5sb2dHcm91cE5hbWUgPSB0aGlzLmdldFJlc291cmNlTmFtZUF0dHJpYnV0ZShyZXNvdXJjZS5yZWYpO1xuICB9XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgYSBuZXcgTG9nU3RyZWFtIGNyZWF0ZWQgZnJvbSBhIExvZ0dyb3VwXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RyZWFtT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgbG9nIHN0cmVhbSB0byBjcmVhdGUuXG4gICAqXG4gICAqIFRoZSBuYW1lIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGUgbG9nIGdyb3VwLlxuICAgKlxuICAgKiBAZGVmYXVsdCBBdXRvbWF0aWNhbGx5IGdlbmVyYXRlZFxuICAgKi9cbiAgcmVhZG9ubHkgbG9nU3RyZWFtTmFtZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBhIG5ldyBTdWJzY3JpcHRpb25GaWx0ZXIgY3JlYXRlZCBmcm9tIGEgTG9nR3JvdXBcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdWJzY3JpcHRpb25GaWx0ZXJPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBkZXN0aW5hdGlvbiB0byBzZW5kIHRoZSBmaWx0ZXJlZCBldmVudHMgdG8uXG4gICAqXG4gICAqIEZvciBleGFtcGxlLCBhIEtpbmVzaXMgc3RyZWFtIG9yIGEgTGFtYmRhIGZ1bmN0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgZGVzdGluYXRpb246IElMb2dTdWJzY3JpcHRpb25EZXN0aW5hdGlvbjtcblxuICAvKipcbiAgICogTG9nIGV2ZW50cyBtYXRjaGluZyB0aGlzIHBhdHRlcm4gd2lsbCBiZSBzZW50IHRvIHRoZSBkZXN0aW5hdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGZpbHRlclBhdHRlcm46IElGaWx0ZXJQYXR0ZXJuO1xufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIGEgTWV0cmljRmlsdGVyIGNyZWF0ZWQgZnJvbSBhIExvZ0dyb3VwXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWV0cmljRmlsdGVyT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBQYXR0ZXJuIHRvIHNlYXJjaCBmb3IgbG9nIGV2ZW50cy5cbiAgICovXG4gIHJlYWRvbmx5IGZpbHRlclBhdHRlcm46IElGaWx0ZXJQYXR0ZXJuO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZXNwYWNlIG9mIHRoZSBtZXRyaWMgdG8gZW1pdC5cbiAgICovXG4gIHJlYWRvbmx5IG1ldHJpY05hbWVzcGFjZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgbWV0cmljIHRvIGVtaXQuXG4gICAqL1xuICByZWFkb25seSBtZXRyaWNOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSB0byBlbWl0IGZvciB0aGUgbWV0cmljLlxuICAgKlxuICAgKiBDYW4gZWl0aGVyIGJlIGEgbGl0ZXJhbCBudW1iZXIgKHR5cGljYWxseSBcIjFcIiksIG9yIHRoZSBuYW1lIG9mIGEgZmllbGQgaW4gdGhlIHN0cnVjdHVyZVxuICAgKiB0byB0YWtlIHRoZSB2YWx1ZSBmcm9tIHRoZSBtYXRjaGVkIGV2ZW50LiBJZiB5b3UgYXJlIHVzaW5nIGEgZmllbGQgdmFsdWUsIHRoZSBmaWVsZFxuICAgKiB2YWx1ZSBtdXN0IGhhdmUgYmVlbiBtYXRjaGVkIHVzaW5nIHRoZSBwYXR0ZXJuLlxuICAgKlxuICAgKiBJZiB5b3Ugd2FudCB0byBzcGVjaWZ5IGEgZmllbGQgZnJvbSBhIG1hdGNoZWQgSlNPTiBzdHJ1Y3R1cmUsIHVzZSAnJC5maWVsZE5hbWUnLFxuICAgKiBhbmQgbWFrZSBzdXJlIHRoZSBmaWVsZCBpcyBpbiB0aGUgcGF0dGVybiAoaWYgb25seSBhcyAnJC5maWVsZE5hbWUgPSAqJykuXG4gICAqXG4gICAqIElmIHlvdSB3YW50IHRvIHNwZWNpZnkgYSBmaWVsZCBmcm9tIGEgbWF0Y2hlZCBzcGFjZS1kZWxpbWl0ZWQgc3RydWN0dXJlLFxuICAgKiB1c2UgJyRmaWVsZE5hbWUnLlxuICAgKlxuICAgKiBAZGVmYXVsdCBcIjFcIlxuICAgKi9cbiAgcmVhZG9ubHkgbWV0cmljVmFsdWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSB0byBlbWl0IGlmIHRoZSBwYXR0ZXJuIGRvZXMgbm90IG1hdGNoIGEgcGFydGljdWxhciBldmVudC5cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gbWV0cmljIGVtaXR0ZWQuXG4gICAqL1xuICByZWFkb25seSBkZWZhdWx0VmFsdWU/OiBudW1iZXI7XG59XG4iXX0= |
\ | No newline at end of file |