cdk-common 2.0.30 → 2.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +4 -4
- package/lib/main.js +1 -1
- package/node_modules/@aws-cdk/assert/LICENSE +1 -1
- package/node_modules/@aws-cdk/assert/NOTICE +1 -1
- package/node_modules/@aws-cdk/assert/package.json +9 -9
- package/node_modules/@aws-cdk/cfnspec/CHANGELOG.md +16 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/build.js +7 -53
- package/node_modules/@aws-cdk/cfnspec/build-tools/massage-spec.d.ts +0 -4
- package/node_modules/@aws-cdk/cfnspec/build-tools/massage-spec.js +2 -61
- package/node_modules/@aws-cdk/cfnspec/build-tools/patch-set.d.ts +25 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/patch-set.js +239 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/report-issues.d.ts +4 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/report-issues.js +44 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/split-spec-by-service.d.ts +1 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/split-spec-by-service.js +86 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/template/LICENSE +1 -1
- package/node_modules/@aws-cdk/cfnspec/build-tools/template/NOTICE +1 -1
- package/node_modules/@aws-cdk/cfnspec/build-tools/update-metrics.sh +2 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/update.sh +34 -18
- package/node_modules/@aws-cdk/cfnspec/build-tools/validate-cfn.d.ts +67 -0
- package/node_modules/@aws-cdk/cfnspec/build-tools/validate-cfn.js +285 -0
- package/node_modules/@aws-cdk/cfnspec/coverage/build-tools/index.html +49 -20
- package/node_modules/@aws-cdk/cfnspec/coverage/build-tools/massage-spec.ts.html +12 -166
- package/node_modules/@aws-cdk/cfnspec/coverage/build-tools/patch-set.ts.html +907 -0
- package/node_modules/@aws-cdk/cfnspec/coverage/build-tools/scrutiny.ts.html +1 -2
- package/node_modules/@aws-cdk/cfnspec/coverage/build-tools/validate-cfn.ts.html +1093 -0
- package/node_modules/@aws-cdk/cfnspec/coverage/index.html +34 -35
- package/node_modules/@aws-cdk/cfnspec/coverage/junit.xml +6217 -6177
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/build-tools/index.html +49 -20
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/build-tools/massage-spec.ts.html +12 -166
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/build-tools/patch-set.ts.html +907 -0
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/build-tools/scrutiny.ts.html +1 -2
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/build-tools/validate-cfn.ts.html +1093 -0
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/index.html +34 -35
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/canned-metrics/canned-metrics-schema.ts.html +2 -3
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/canned-metrics/index.html +1 -2
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/canned-metrics.ts.html +22 -23
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/index.html +19 -20
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/index.ts.html +96 -25
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/augmentation.ts.html +5 -6
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/base-types.ts.html +12 -13
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/index.html +7 -8
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/index.ts.html +11 -12
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/property.ts.html +39 -40
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/resource-type.ts.html +20 -21
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov-report/lib/schema/specification.ts.html +2 -3
- package/node_modules/@aws-cdk/cfnspec/coverage/lcov.info +744 -346
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/canned-metrics/canned-metrics-schema.ts.html +2 -3
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/canned-metrics/index.html +1 -2
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/canned-metrics.ts.html +22 -23
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/index.html +19 -20
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/index.ts.html +96 -25
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/augmentation.ts.html +5 -6
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/base-types.ts.html +12 -13
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/index.html +7 -8
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/index.ts.html +11 -12
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/property.ts.html +39 -40
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/resource-type.ts.html +20 -21
- package/node_modules/@aws-cdk/cfnspec/coverage/lib/schema/specification.ts.html +2 -3
- package/node_modules/@aws-cdk/cfnspec/lib/canned-metrics/README.md +6 -1
- package/node_modules/@aws-cdk/cfnspec/lib/canned-metrics/services.json +19997 -10215
- package/node_modules/@aws-cdk/cfnspec/lib/index.d.ts +8 -0
- package/node_modules/@aws-cdk/cfnspec/lib/index.js +25 -2
- package/node_modules/@aws-cdk/cfnspec/lib/schema/docs.d.ts +20 -0
- package/node_modules/@aws-cdk/cfnspec/lib/schema/docs.js +3 -0
- package/node_modules/@aws-cdk/cfnspec/lib/schema/index.d.ts +1 -0
- package/node_modules/@aws-cdk/cfnspec/lib/schema/index.js +2 -1
- package/node_modules/@aws-cdk/cfnspec/package.json +5 -5
- package/node_modules/@aws-cdk/cfnspec/spec/cfn-docs.json +38910 -0
- package/node_modules/@aws-cdk/cfnspec/spec/cfn-lint.json +3 -3
- package/node_modules/@aws-cdk/cfnspec/spec/specification.json +319 -311
- package/node_modules/@aws-cdk/cfnspec/tsconfig.tsbuildinfo +285 -179
- package/node_modules/@aws-cdk/cloudformation-diff/LICENSE +1 -1
- package/node_modules/@aws-cdk/cloudformation-diff/NOTICE +1 -1
- package/node_modules/@aws-cdk/cloudformation-diff/package.json +7 -7
- package/package.json +5 -5
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatErrorInContext = exports.CfnSpecValidator = void 0;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
/**
|
|
6
|
+
* CloudFormation spec validator
|
|
7
|
+
*
|
|
8
|
+
* "Why not JSON Schema?", you might ask, and it's a fair question. The answer is:
|
|
9
|
+
* because the error reporting from JSON schema is pretty bad, and I want the validation
|
|
10
|
+
* errors reported from this check to be blindingly obvious, as non-spec-experts
|
|
11
|
+
* are going to have to consume and understand them.
|
|
12
|
+
*
|
|
13
|
+
* I tried JSON Schema validation and its errors look like:
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* - instance.PropertyTypes["..."].Properties.Xyz does not match allOf schema <#/definitions/Typed> with 7 error[s]:
|
|
17
|
+
* - instance.PropertyTypes["..."].Properties.Xyz requires property "PrimitiveType"
|
|
18
|
+
* - instance.PropertyTypes["..."].Properties.Xyz requires property "Type"
|
|
19
|
+
* - instance.PropertyTypes["..."].Properties.Xyz requires property "Type"
|
|
20
|
+
* - instance.PropertyTypes["..."].Properties.Xyz requires property "ItemType"
|
|
21
|
+
* - instance.PropertyTypes["..."].Properties.Xyz requires property "Type"
|
|
22
|
+
* - instance.PropertyTypes["..."].Properties.Xyz requires property "PrimitiveItemType"
|
|
23
|
+
* - instance.PropertyTypes["..."].Properties.Xyz is not exactly one from "Primitive","Complex Type","Collection of Primitives","Collection of Complex Types"
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* No bueno. In contrast, this script prints:
|
|
27
|
+
*
|
|
28
|
+
* ```
|
|
29
|
+
* {
|
|
30
|
+
* "ResourceTypes": {
|
|
31
|
+
* "AWS::SageMaker::Device": {
|
|
32
|
+
* "Properties": {
|
|
33
|
+
* "Device": {
|
|
34
|
+
*
|
|
35
|
+
* !!! must have exactly one of 'Type', 'PrimitiveType', found: {"Type":"Device","PrimitiveType":"Json"} !!!
|
|
36
|
+
*
|
|
37
|
+
* "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-device.html#cfn-sagemaker-device-device",
|
|
38
|
+
* "UpdateType": "Mutable",
|
|
39
|
+
* "Required": false,
|
|
40
|
+
* "PrimitiveType": "Json",
|
|
41
|
+
* "Type": "Device"
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
const fs = require("fs-extra");
|
|
50
|
+
class CfnSpecValidator {
|
|
51
|
+
constructor(spec) {
|
|
52
|
+
this.errors = new Array();
|
|
53
|
+
this.root = JsonValue.of(spec);
|
|
54
|
+
}
|
|
55
|
+
static validate(spec) {
|
|
56
|
+
const ret = new CfnSpecValidator(spec);
|
|
57
|
+
ret.validateSpec();
|
|
58
|
+
return ret.errors;
|
|
59
|
+
}
|
|
60
|
+
validateSpec() {
|
|
61
|
+
this.assert(this.root.get('PropertyTypes'), isObject, (propTypes) => {
|
|
62
|
+
this.validateMap(propTypes, (propType) => this.validatePropertyType(propType));
|
|
63
|
+
});
|
|
64
|
+
this.assert(this.root.get('ResourceTypes'), isObject, (resTypes) => {
|
|
65
|
+
this.validateMap(resTypes, (propType) => this.validateResourceType(propType));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Property types are extremely weird
|
|
70
|
+
*
|
|
71
|
+
* Nominally, they define "records" that have a `Properties` field with the defined
|
|
72
|
+
* properties.
|
|
73
|
+
*
|
|
74
|
+
* However, they are also commonly used as aliases for other types, meaning they have
|
|
75
|
+
* the same type-indicating fields as individual property *fields* would have.
|
|
76
|
+
*
|
|
77
|
+
* Also also, it seems to be quite common to have them empty--have no fields at all.
|
|
78
|
+
* This seems to be taken as an alias for an unstructured `Json` type. It's probably
|
|
79
|
+
* just a mistake, but unfortunately a mistake that S3 is participating in, so if we
|
|
80
|
+
* fail on that we won't be able to consume updates to S3's schema. Our codegen is
|
|
81
|
+
* ready to deal with this and just renders it to an empty struct.
|
|
82
|
+
*/
|
|
83
|
+
validatePropertyType(propType) {
|
|
84
|
+
// If the only set of properties is "Documentation", we take this to be an alias
|
|
85
|
+
// for an empty struct and allow it. I feel icky allowing this, but it seems to
|
|
86
|
+
// be pragmatic for now.
|
|
87
|
+
if (Object.keys(propType.value).join(',') === 'Documentation') {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const properties = propType.get('Properties');
|
|
91
|
+
if (properties.hasValue) {
|
|
92
|
+
this.assert(properties, isObject, (props) => {
|
|
93
|
+
this.validateProperties(props);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.validateType(propType, 'if a property type doesn\'t have "Properties", it ');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
validateResourceType(resType) {
|
|
101
|
+
this.assertOptional(resType.get('Properties'), isObject, (props) => {
|
|
102
|
+
this.validateProperties(props);
|
|
103
|
+
});
|
|
104
|
+
this.assertOptional(resType.get('Attributes'), isObject, (attrs) => {
|
|
105
|
+
this.validateMap(attrs, attr => {
|
|
106
|
+
this.validateType(attr);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
validateProperties(properties) {
|
|
111
|
+
this.validateMap(properties, prop => {
|
|
112
|
+
this.validateType(prop);
|
|
113
|
+
this.assertOptional(prop.get('UpdateType'), (x) => {
|
|
114
|
+
if (!['Mutable', 'Immutable', 'Conditional'].includes(x)) {
|
|
115
|
+
throw new Error(`invalid value for enum: '${x}'`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Validate the type
|
|
122
|
+
*
|
|
123
|
+
* There must be:
|
|
124
|
+
* - Either Type or PrimitiveType
|
|
125
|
+
* - Only if Type is List or Map, there will be either an ItemType or a PrimitiveItemType
|
|
126
|
+
* - Non-primitive Types must correspond to a property type
|
|
127
|
+
*/
|
|
128
|
+
validateType(typedObject, errorPrefix = '') {
|
|
129
|
+
const type = typedObject.get('Type');
|
|
130
|
+
const primitiveType = typedObject.get('PrimitiveType');
|
|
131
|
+
if (type.hasValue === primitiveType.hasValue) {
|
|
132
|
+
this.report(typedObject, `${errorPrefix}must have exactly one of 'Type', 'PrimitiveType', found: ${JSON.stringify({
|
|
133
|
+
Type: type.valueOrUndefined,
|
|
134
|
+
PrimitiveType: primitiveType.valueOrUndefined,
|
|
135
|
+
})}`);
|
|
136
|
+
}
|
|
137
|
+
this.assertOptional(primitiveType, isValidPrimitive);
|
|
138
|
+
let isCollectionType = false;
|
|
139
|
+
const itemType = typedObject.get('ItemType');
|
|
140
|
+
const primitiveItemType = typedObject.get('PrimitiveItemType');
|
|
141
|
+
if (type.hasValue) {
|
|
142
|
+
isCollectionType = COLLECTION_TYPES.includes(type.value);
|
|
143
|
+
if (isCollectionType) {
|
|
144
|
+
if (itemType.hasValue === primitiveItemType.hasValue) {
|
|
145
|
+
this.report(typedObject, `must have exactly one of 'ItemType', 'PrimitiveItemType', found: ${JSON.stringify({
|
|
146
|
+
ItemType: itemType.valueOrUndefined,
|
|
147
|
+
PrimitiveItemType: primitiveItemType.valueOrUndefined,
|
|
148
|
+
})}`);
|
|
149
|
+
}
|
|
150
|
+
this.assertOptional(primitiveItemType, isValidPrimitive);
|
|
151
|
+
if (itemType.hasValue) {
|
|
152
|
+
this.assertValidPropertyTypeReference(itemType);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
this.assertValidPropertyTypeReference(type);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!isCollectionType) {
|
|
160
|
+
if (itemType.hasValue || primitiveItemType.hasValue) {
|
|
161
|
+
this.report(typedObject, 'only \'List\' or \'Map\' types can have \'ItemType\', \'PrimitiveItemType\'');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const dupes = typedObject.get('DuplicatesAllowed');
|
|
165
|
+
if (dupes.hasValue && !isCollectionType) {
|
|
166
|
+
this.report(dupes, 'occurs on non-collection type');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
assertValidPropertyTypeReference(typeName) {
|
|
170
|
+
if (BUILTIN_COMPLEX_TYPES.includes(typeName.value)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const cfnName = typeName.path[1]; // AWS::Xyz::Resource[.Property]
|
|
174
|
+
const namespace = cfnName.split('.')[0];
|
|
175
|
+
const propTypeName = `${namespace}.${typeName.value}`;
|
|
176
|
+
if (!this.root.get('PropertyTypes').get(propTypeName).hasValue) {
|
|
177
|
+
this.report(typeName, `unknown property type name '${typeName.value}' (missing definition for '${propTypeName}')`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
assertOptional(x, pred, block) {
|
|
181
|
+
return x.hasValue ? this.assert(x, pred, block) : true;
|
|
182
|
+
}
|
|
183
|
+
assert(x, pred, block) {
|
|
184
|
+
try {
|
|
185
|
+
pred(x.value);
|
|
186
|
+
if (block) {
|
|
187
|
+
block(new JsonValue(x.value, x.path));
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
this.report(x, e.message);
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
validateMap(x, block) {
|
|
197
|
+
for (const key in x.value) {
|
|
198
|
+
block(x.get(key));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
report(value, message) {
|
|
202
|
+
this.errors.push({ value, message });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.CfnSpecValidator = CfnSpecValidator;
|
|
206
|
+
function isObject(x) {
|
|
207
|
+
if (x == null || typeof x !== 'object' || Array.isArray(x)) {
|
|
208
|
+
throw new Error(`expected object, found '${x}'`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const COLLECTION_TYPES = ['List', 'Map'];
|
|
212
|
+
const BUILTIN_COMPLEX_TYPES = ['Tag'];
|
|
213
|
+
function isValidPrimitive(x) {
|
|
214
|
+
const primitives = ['String', 'Long', 'Integer', 'Double', 'Boolean', 'Timestamp', 'Json'];
|
|
215
|
+
if (!primitives.includes(x)) {
|
|
216
|
+
throw new Error(`must be one of ${primitives.join(', ')}, got: ${x}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
class JsonValue {
|
|
220
|
+
constructor(value, path) {
|
|
221
|
+
this.value = value;
|
|
222
|
+
this.path = path;
|
|
223
|
+
this.hasValue = true;
|
|
224
|
+
this.valueOrUndefined = this.value;
|
|
225
|
+
this.pathValue = this.value;
|
|
226
|
+
}
|
|
227
|
+
static of(x) {
|
|
228
|
+
return new JsonValue(x, []);
|
|
229
|
+
}
|
|
230
|
+
get(k) {
|
|
231
|
+
if (!this.value || typeof this.value !== 'object' || Array.isArray(this.value)) {
|
|
232
|
+
return new ErrorValue(`expected object, found ${this.value}`, this.path, this.value);
|
|
233
|
+
}
|
|
234
|
+
const ret = this.value[k];
|
|
235
|
+
if (ret === undefined) {
|
|
236
|
+
return new ErrorValue(`missing required key '${k}'`, this.path, this.value);
|
|
237
|
+
}
|
|
238
|
+
return new JsonValue(ret, [...this.path, `${k}`]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
class ErrorValue {
|
|
242
|
+
constructor(error, path, pathValue) {
|
|
243
|
+
this.error = error;
|
|
244
|
+
this.path = path;
|
|
245
|
+
this.pathValue = pathValue;
|
|
246
|
+
this.hasValue = false;
|
|
247
|
+
this.valueOrUndefined = undefined;
|
|
248
|
+
}
|
|
249
|
+
get(_k) {
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
get value() {
|
|
253
|
+
throw new Error(this.error);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function formatErrorInContext(error) {
|
|
257
|
+
let reportValue = error.value.pathValue;
|
|
258
|
+
for (let i = error.value.path.length; i > 0; i--) {
|
|
259
|
+
reportValue = { [error.value.path[i - 1]]: reportValue };
|
|
260
|
+
}
|
|
261
|
+
const formattedLines = JSON.stringify(reportValue, undefined, 2).split('\n');
|
|
262
|
+
const indent = 2 * (error.value.path.length + 1);
|
|
263
|
+
// Insert the error message at line N with an appropriate indent
|
|
264
|
+
formattedLines.splice(error.value.path.length + 1, 0, `\n!!!${' '.repeat(indent - 3)}${error.message} !!!\n`);
|
|
265
|
+
return formattedLines.join('\n');
|
|
266
|
+
}
|
|
267
|
+
exports.formatErrorInContext = formatErrorInContext;
|
|
268
|
+
async function main(args) {
|
|
269
|
+
const spec = await fs.readJson(args[0]);
|
|
270
|
+
const errors = CfnSpecValidator.validate(spec);
|
|
271
|
+
if (errors.length !== 0) {
|
|
272
|
+
for (const error of errors) {
|
|
273
|
+
console.error(formatErrorInContext(error));
|
|
274
|
+
}
|
|
275
|
+
process.exitCode = 1;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (require.main === module) {
|
|
279
|
+
main(process.argv.slice(2)).catch(e => {
|
|
280
|
+
process.exitCode = 1;
|
|
281
|
+
// eslint-disable-next-line no-console
|
|
282
|
+
console.error(e.message);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUtY2ZuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidmFsaWRhdGUtY2ZuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLCtCQUErQjtBQUMvQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJDRztBQUNILCtCQUErQjtBQWEvQixNQUFhLGdCQUFnQjtJQVUzQixZQUFZLElBQWE7UUFIVCxXQUFNLEdBQUcsSUFBSSxLQUFLLEVBQW1CLENBQUM7UUFJcEQsSUFBSSxDQUFDLElBQUksR0FBRyxTQUFTLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFYTSxNQUFNLENBQUMsUUFBUSxDQUFDLElBQWE7UUFDbEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDbkIsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDO0lBQ3BCLENBQUM7SUFTTSxZQUFZO1FBQ2pCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLEVBQUUsUUFBUSxFQUFFLENBQUMsU0FBUyxFQUFFLEVBQUU7WUFDbEUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1FBQ2pGLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUNqRSxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLG9CQUFvQixD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LWNvbnNvbGUgKi9cbi8qKlxuICogQ2xvdWRGb3JtYXRpb24gc3BlYyB2YWxpZGF0b3JcbiAqXG4gKiBcIldoeSBub3QgSlNPTiBTY2hlbWE/XCIsIHlvdSBtaWdodCBhc2ssIGFuZCBpdCdzIGEgZmFpciBxdWVzdGlvbi4gVGhlIGFuc3dlciBpczpcbiAqIGJlY2F1c2UgdGhlIGVycm9yIHJlcG9ydGluZyBmcm9tIEpTT04gc2NoZW1hIGlzIHByZXR0eSBiYWQsIGFuZCBJIHdhbnQgdGhlIHZhbGlkYXRpb25cbiAqIGVycm9ycyByZXBvcnRlZCBmcm9tIHRoaXMgY2hlY2sgdG8gYmUgYmxpbmRpbmdseSBvYnZpb3VzLCBhcyBub24tc3BlYy1leHBlcnRzXG4gKiBhcmUgZ29pbmcgdG8gaGF2ZSB0byBjb25zdW1lIGFuZCB1bmRlcnN0YW5kIHRoZW0uXG4gKlxuICogSSB0cmllZCBKU09OIFNjaGVtYSB2YWxpZGF0aW9uIGFuZCBpdHMgZXJyb3JzIGxvb2sgbGlrZTpcbiAqXG4gKiBgYGBcbiAqIC0gaW5zdGFuY2UuUHJvcGVydHlUeXBlc1tcIi4uLlwiXS5Qcm9wZXJ0aWVzLlh5eiBkb2VzIG5vdCBtYXRjaCBhbGxPZiBzY2hlbWEgPCMvZGVmaW5pdGlvbnMvVHlwZWQ+IHdpdGggNyBlcnJvcltzXTpcbiAqIC0gaW5zdGFuY2UuUHJvcGVydHlUeXBlc1tcIi4uLlwiXS5Qcm9wZXJ0aWVzLlh5eiByZXF1aXJlcyBwcm9wZXJ0eSBcIlByaW1pdGl2ZVR5cGVcIlxuICogLSBpbnN0YW5jZS5Qcm9wZXJ0eVR5cGVzW1wiLi4uXCJdLlByb3BlcnRpZXMuWHl6IHJlcXVpcmVzIHByb3BlcnR5IFwiVHlwZVwiXG4gKiAtIGluc3RhbmNlLlByb3BlcnR5VHlwZXNbXCIuLi5cIl0uUHJvcGVydGllcy5YeXogcmVxdWlyZXMgcHJvcGVydHkgXCJUeXBlXCJcbiAqIC0gaW5zdGFuY2UuUHJvcGVydHlUeXBlc1tcIi4uLlwiXS5Qcm9wZXJ0aWVzLlh5eiByZXF1aXJlcyBwcm9wZXJ0eSBcIkl0ZW1UeXBlXCJcbiAqIC0gaW5zdGFuY2UuUHJvcGVydHlUeXBlc1tcIi4uLlwiXS5Qcm9wZXJ0aWVzLlh5eiByZXF1aXJlcyBwcm9wZXJ0eSBcIlR5cGVcIlxuICogLSBpbnN0YW5jZS5Qcm9wZXJ0eVR5cGVzW1wiLi4uXCJdLlByb3BlcnRpZXMuWHl6IHJlcXVpcmVzIHByb3BlcnR5IFwiUHJpbWl0aXZlSXRlbVR5cGVcIlxuICogLSBpbnN0YW5jZS5Qcm9wZXJ0eVR5cGVzW1wiLi4uXCJdLlByb3BlcnRpZXMuWHl6IGlzIG5vdCBleGFjdGx5IG9uZSBmcm9tIFwiUHJpbWl0aXZlXCIsXCJDb21wbGV4IFR5cGVcIixcIkNvbGxlY3Rpb24gb2YgUHJpbWl0aXZlc1wiLFwiQ29sbGVjdGlvbiBvZiBDb21wbGV4IFR5cGVzXCJcbiAqIGBgYFxuICpcbiAqIE5vIGJ1ZW5vLiBJbiBjb250cmFzdCwgdGhpcyBzY3JpcHQgcHJpbnRzOlxuICpcbiAqIGBgYFxuICoge1xuICogICBcIlJlc291cmNlVHlwZXNcIjoge1xuICogICAgIFwiQVdTOjpTYWdlTWFrZXI6OkRldmljZVwiOiB7XG4gKiAgICAgICBcIlByb3BlcnRpZXNcIjoge1xuICogICAgICAgICBcIkRldmljZVwiOiB7XG4gKlxuICogISEhICAgICAgIG11c3QgaGF2ZSBleGFjdGx5IG9uZSBvZiAnVHlwZScsICdQcmltaXRpdmVUeXBlJywgZm91bmQ6IHtcIlR5cGVcIjpcIkRldmljZVwiLFwiUHJpbWl0aXZlVHlwZVwiOlwiSnNvblwifSAhISFcbiAqXG4gKiAgICAgICAgICAgXCJEb2N1bWVudGF0aW9uXCI6IFwiaHR0cDovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTQ2xvdWRGb3JtYXRpb24vbGF0ZXN0L1VzZXJHdWlkZS9hd3MtcmVzb3VyY2Utc2FnZW1ha2VyLWRldmljZS5odG1sI2Nmbi1zYWdlbWFrZXItZGV2aWNlLWRldmljZVwiLFxuICogICAgICAgICAgIFwiVXBkYXRlVHlwZVwiOiBcIk11dGFibGVcIixcbiAqICAgICAgICAgICBcIlJlcXVpcmVkXCI6IGZhbHNlLFxuICogICAgICAgICAgIFwiUHJpbWl0aXZlVHlwZVwiOiBcIkpzb25cIixcbiAqICAgICAgICAgICBcIlR5cGVcIjogXCJEZXZpY2VcIlxuICogICAgICAgICB9XG4gKiAgICAgICB9XG4gKiAgICAgfVxuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMtZXh0cmEnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENmblNwZWMge1xuICBQcm9wZXJ0eVR5cGVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICBSZXNvdXJjZVR5cGVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICBSZXNvdXJjZVNwZWNpZmljYXRpb25WZXJzaW9uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmFsaWRhdGlvbkVycm9yIHtcbiAgcmVhZG9ubHkgdmFsdWU6IEpzb25WYWx1ZTxhbnk+O1xuICByZWFkb25seSBtZXNzYWdlOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBDZm5TcGVjVmFsaWRhdG9yIHtcbiAgcHVibGljIHN0YXRpYyB2YWxpZGF0ZShzcGVjOiBDZm5TcGVjKSB7XG4gICAgY29uc3QgcmV0ID0gbmV3IENmblNwZWNWYWxpZGF0b3Ioc3BlYyk7XG4gICAgcmV0LnZhbGlkYXRlU3BlYygpO1xuICAgIHJldHVybiByZXQuZXJyb3JzO1xuICB9XG5cbiAgcHVibGljIHJlYWRvbmx5IGVycm9ycyA9IG5ldyBBcnJheTxWYWxpZGF0aW9uRXJyb3I+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcm9vdDogSnNvblZhbHVlPENmblNwZWM+O1xuXG4gIGNvbnN0cnVjdG9yKHNwZWM6IENmblNwZWMpIHtcbiAgICB0aGlzLnJvb3QgPSBKc29uVmFsdWUub2Yoc3BlYyk7XG4gIH1cblxuICBwdWJsaWMgdmFsaWRhdGVTcGVjKCkge1xuICAgIHRoaXMuYXNzZXJ0KHRoaXMucm9vdC5nZXQoJ1Byb3BlcnR5VHlwZXMnKSwgaXNPYmplY3QsIChwcm9wVHlwZXMpID0+IHtcbiAgICAgIHRoaXMudmFsaWRhdGVNYXAocHJvcFR5cGVzLCAocHJvcFR5cGUpID0+IHRoaXMudmFsaWRhdGVQcm9wZXJ0eVR5cGUocHJvcFR5cGUpKTtcbiAgICB9KTtcblxuICAgIHRoaXMuYXNzZXJ0KHRoaXMucm9vdC5nZXQoJ1Jlc291cmNlVHlwZXMnKSwgaXNPYmplY3QsIChyZXNUeXBlcykgPT4ge1xuICAgICAgdGhpcy52YWxpZGF0ZU1hcChyZXNUeXBlcywgKHByb3BUeXBlKSA9PiB0aGlzLnZhbGlkYXRlUmVzb3VyY2VUeXBlKHByb3BUeXBlKSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUHJvcGVydHkgdHlwZXMgYXJlIGV4dHJlbWVseSB3ZWlyZFxuICAgKlxuICAgKiBOb21pbmFsbHksIHRoZXkgZGVmaW5lIFwicmVjb3Jkc1wiIHRoYXQgaGF2ZSBhIGBQcm9wZXJ0aWVzYCBmaWVsZCB3aXRoIHRoZSBkZWZpbmVkXG4gICAqIHByb3BlcnRpZXMuXG4gICAqXG4gICAqIEhvd2V2ZXIsIHRoZXkgYXJlIGFsc28gY29tbW9ubHkgdXNlZCBhcyBhbGlhc2VzIGZvciBvdGhlciB0eXBlcywgbWVhbmluZyB0aGV5IGhhdmVcbiAgICogdGhlIHNhbWUgdHlwZS1pbmRpY2F0aW5nIGZpZWxkcyBhcyBpbmRpdmlkdWFsIHByb3BlcnR5ICpmaWVsZHMqIHdvdWxkIGhhdmUuXG4gICAqXG4gICAqIEFsc28gYWxzbywgaXQgc2VlbXMgdG8gYmUgcXVpdGUgY29tbW9uIHRvIGhhdmUgdGhlbSBlbXB0eS0taGF2ZSBubyBmaWVsZHMgYXQgYWxsLlxuICAgKiBUaGlzIHNlZW1zIHRvIGJlIHRha2VuIGFzIGFuIGFsaWFzIGZvciBhbiB1bnN0cnVjdHVyZWQgYEpzb25gIHR5cGUuIEl0J3MgcHJvYmFibHlcbiAgICoganVzdCBhIG1pc3Rha2UsIGJ1dCB1bmZvcnR1bmF0ZWx5IGEgbWlzdGFrZSB0aGF0IFMzIGlzIHBhcnRpY2lwYXRpbmcgaW4sIHNvIGlmIHdlXG4gICAqIGZhaWwgb24gdGhhdCB3ZSB3b24ndCBiZSBhYmxlIHRvIGNvbnN1bWUgdXBkYXRlcyB0byBTMydzIHNjaGVtYS4gT3VyIGNvZGVnZW4gaXNcbiAgICogcmVhZHkgdG8gZGVhbCB3aXRoIHRoaXMgYW5kIGp1c3QgcmVuZGVycyBpdCB0byBhbiBlbXB0eSBzdHJ1Y3QuXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlUHJvcGVydHlUeXBlKHByb3BUeXBlOiBKc29uVmFsdWU8UmVjb3JkPHN0cmluZywgYW55Pj4pIHtcbiAgICAvLyBJZiB0aGUgb25seSBzZXQgb2YgcHJvcGVydGllcyBpcyBcIkRvY3VtZW50YXRpb25cIiwgd2UgdGFrZSB0aGlzIHRvIGJlIGFuIGFsaWFzXG4gICAgLy8gZm9yIGFuIGVtcHR5IHN0cnVjdCBhbmQgYWxsb3cgaXQuIEkgZmVlbCBpY2t5IGFsbG93aW5nIHRoaXMsIGJ1dCBpdCBzZWVtcyB0b1xuICAgIC8vIGJlIHByYWdtYXRpYyBmb3Igbm93LlxuICAgIGlmIChPYmplY3Qua2V5cyhwcm9wVHlwZS52YWx1ZSkuam9pbignLCcpID09PSAnRG9jdW1lbnRhdGlvbicpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwcm9wZXJ0aWVzID0gcHJvcFR5cGUuZ2V0KCdQcm9wZXJ0aWVzJyk7XG4gICAgaWYgKHByb3BlcnRpZXMuaGFzVmFsdWUpIHtcbiAgICAgIHRoaXMuYXNzZXJ0KHByb3BlcnRpZXMsIGlzT2JqZWN0LCAocHJvcHMpID0+IHtcbiAgICAgICAgdGhpcy52YWxpZGF0ZVByb3BlcnRpZXMocHJvcHMpO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudmFsaWRhdGVUeXBlKHByb3BUeXBlLCAnaWYgYSBwcm9wZXJ0eSB0eXBlIGRvZXNuXFwndCBoYXZlIFwiUHJvcGVydGllc1wiLCBpdCAnKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlUmVzb3VyY2VUeXBlKHJlc1R5cGU6IEpzb25WYWx1ZTxhbnk+KSB7XG4gICAgdGhpcy5hc3NlcnRPcHRpb25hbChyZXNUeXBlLmdldCgnUHJvcGVydGllcycpLCBpc09iamVjdCwgKHByb3BzKSA9PiB7XG4gICAgICB0aGlzLnZhbGlkYXRlUHJvcGVydGllcyhwcm9wcyk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmFzc2VydE9wdGlvbmFsKHJlc1R5cGUuZ2V0KCdBdHRyaWJ1dGVzJyksIGlzT2JqZWN0LCAoYXR0cnMpID0+IHtcbiAgICAgIHRoaXMudmFsaWRhdGVNYXAoYXR0cnMsIGF0dHIgPT4ge1xuICAgICAgICB0aGlzLnZhbGlkYXRlVHlwZShhdHRyKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZVByb3BlcnRpZXMocHJvcGVydGllczogSnNvblZhbHVlPFJlY29yZDxzdHJpbmcsIGFueT4+KSB7XG4gICAgdGhpcy52YWxpZGF0ZU1hcChwcm9wZXJ0aWVzLCBwcm9wID0+IHtcbiAgICAgIHRoaXMudmFsaWRhdGVUeXBlKHByb3ApO1xuXG4gICAgICB0aGlzLmFzc2VydE9wdGlvbmFsKHByb3AuZ2V0KCdVcGRhdGVUeXBlJyksICh4OiBhbnkpID0+IHtcbiAgICAgICAgaWYgKCFbJ011dGFibGUnLCAnSW1tdXRhYmxlJywgJ0NvbmRpdGlvbmFsJ10uaW5jbHVkZXMoeCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgdmFsdWUgZm9yIGVudW06ICcke3h9J2ApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgdHlwZVxuICAgKlxuICAgKiBUaGVyZSBtdXN0IGJlOlxuICAgKiAtIEVpdGhlciBUeXBlIG9yIFByaW1pdGl2ZVR5cGVcbiAgICogLSBPbmx5IGlmIFR5cGUgaXMgTGlzdCBvciBNYXAsIHRoZXJlIHdpbGwgYmUgZWl0aGVyIGFuIEl0ZW1UeXBlIG9yIGEgUHJpbWl0aXZlSXRlbVR5cGVcbiAgICogLSBOb24tcHJpbWl0aXZlIFR5cGVzIG11c3QgY29ycmVzcG9uZCB0byBhIHByb3BlcnR5IHR5cGVcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVUeXBlKHR5cGVkT2JqZWN0OiBKc29uVmFsdWU8UmVjb3JkPHN0cmluZywgYW55Pj4sIGVycm9yUHJlZml4ID0gJycpIHtcbiAgICBjb25zdCB0eXBlID0gdHlwZWRPYmplY3QuZ2V0KCdUeXBlJyk7XG4gICAgY29uc3QgcHJpbWl0aXZlVHlwZSA9IHR5cGVkT2JqZWN0LmdldCgnUHJpbWl0aXZlVHlwZScpO1xuXG4gICAgaWYgKHR5cGUuaGFzVmFsdWUgPT09IHByaW1pdGl2ZVR5cGUuaGFzVmFsdWUpIHtcbiAgICAgIHRoaXMucmVwb3J0KHR5cGVkT2JqZWN0LCBgJHtlcnJvclByZWZpeH1tdXN0IGhhdmUgZXhhY3RseSBvbmUgb2YgJ1R5cGUnLCAnUHJpbWl0aXZlVHlwZScsIGZvdW5kOiAke0pTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgVHlwZTogdHlwZS52YWx1ZU9yVW5kZWZpbmVkLFxuICAgICAgICBQcmltaXRpdmVUeXBlOiBwcmltaXRpdmVUeXBlLnZhbHVlT3JVbmRlZmluZWQsXG4gICAgICB9KX1gKTtcbiAgICB9XG5cbiAgICB0aGlzLmFzc2VydE9wdGlvbmFsKHByaW1pdGl2ZVR5cGUsIGlzVmFsaWRQcmltaXRpdmUpO1xuXG4gICAgbGV0IGlzQ29sbGVjdGlvblR5cGUgPSBmYWxzZTtcbiAgICBjb25zdCBpdGVtVHlwZSA9IHR5cGVkT2JqZWN0LmdldCgnSXRlbVR5cGUnKTtcbiAgICBjb25zdCBwcmltaXRpdmVJdGVtVHlwZSA9IHR5cGVkT2JqZWN0LmdldCgnUHJpbWl0aXZlSXRlbVR5cGUnKTtcblxuICAgIGlmICh0eXBlLmhhc1ZhbHVlKSB7XG4gICAgICBpc0NvbGxlY3Rpb25UeXBlID0gQ09MTEVDVElPTl9UWVBFUy5pbmNsdWRlcyh0eXBlLnZhbHVlKTtcbiAgICAgIGlmIChpc0NvbGxlY3Rpb25UeXBlKSB7XG4gICAgICAgIGlmIChpdGVtVHlwZS5oYXNWYWx1ZSA9PT0gcHJpbWl0aXZlSXRlbVR5cGUuaGFzVmFsdWUpIHtcbiAgICAgICAgICB0aGlzLnJlcG9ydCh0eXBlZE9iamVjdCwgYG11c3QgaGF2ZSBleGFjdGx5IG9uZSBvZiAnSXRlbVR5cGUnLCAnUHJpbWl0aXZlSXRlbVR5cGUnLCBmb3VuZDogJHtKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBJdGVtVHlwZTogaXRlbVR5cGUudmFsdWVPclVuZGVmaW5lZCxcbiAgICAgICAgICAgIFByaW1pdGl2ZUl0ZW1UeXBlOiBwcmltaXRpdmVJdGVtVHlwZS52YWx1ZU9yVW5kZWZpbmVkLFxuICAgICAgICAgIH0pfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5hc3NlcnRPcHRpb25hbChwcmltaXRpdmVJdGVtVHlwZSwgaXNWYWxpZFByaW1pdGl2ZSk7XG4gICAgICAgIGlmIChpdGVtVHlwZS5oYXNWYWx1ZSkge1xuICAgICAgICAgIHRoaXMuYXNzZXJ0VmFsaWRQcm9wZXJ0eVR5cGVSZWZlcmVuY2UoaXRlbVR5cGUpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmFzc2VydFZhbGlkUHJvcGVydHlUeXBlUmVmZXJlbmNlKHR5cGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICghaXNDb2xsZWN0aW9uVHlwZSkge1xuICAgICAgaWYgKGl0ZW1UeXBlLmhhc1ZhbHVlIHx8IHByaW1pdGl2ZUl0ZW1UeXBlLmhhc1ZhbHVlKSB7XG4gICAgICAgIHRoaXMucmVwb3J0KHR5cGVkT2JqZWN0LCAnb25seSBcXCdMaXN0XFwnIG9yIFxcJ01hcFxcJyB0eXBlcyBjYW4gaGF2ZSBcXCdJdGVtVHlwZVxcJywgXFwnUHJpbWl0aXZlSXRlbVR5cGVcXCcnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBkdXBlcyA9IHR5cGVkT2JqZWN0LmdldCgnRHVwbGljYXRlc0FsbG93ZWQnKTtcbiAgICBpZiAoZHVwZXMuaGFzVmFsdWUgJiYgIWlzQ29sbGVjdGlvblR5cGUpIHtcbiAgICAgIHRoaXMucmVwb3J0KGR1cGVzLCAnb2NjdXJzIG9uIG5vbi1jb2xsZWN0aW9uIHR5cGUnKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzc2VydFZhbGlkUHJvcGVydHlUeXBlUmVmZXJlbmNlKHR5cGVOYW1lOiBKc29uVmFsdWU8c3RyaW5nPikge1xuICAgIGlmIChCVUlMVElOX0NPTVBMRVhfVFlQRVMuaW5jbHVkZXModHlwZU5hbWUudmFsdWUpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY2ZuTmFtZSA9IHR5cGVOYW1lLnBhdGhbMV07IC8vIEFXUzo6WHl6OjpSZXNvdXJjZVsuUHJvcGVydHldXG4gICAgY29uc3QgbmFtZXNwYWNlID0gY2ZuTmFtZS5zcGxpdCgnLicpWzBdO1xuXG4gICAgY29uc3QgcHJvcFR5cGVOYW1lID0gYCR7bmFtZXNwYWNlfS4ke3R5cGVOYW1lLnZhbHVlfWA7XG4gICAgaWYgKCF0aGlzLnJvb3QuZ2V0KCdQcm9wZXJ0eVR5cGVzJykuZ2V0KHByb3BUeXBlTmFtZSkuaGFzVmFsdWUpIHtcbiAgICAgIHRoaXMucmVwb3J0KHR5cGVOYW1lLCBgdW5rbm93biBwcm9wZXJ0eSB0eXBlIG5hbWUgJyR7dHlwZU5hbWUudmFsdWV9JyAobWlzc2luZyBkZWZpbml0aW9uIGZvciAnJHtwcm9wVHlwZU5hbWV9JylgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzc2VydE9wdGlvbmFsPEEsIEIgZXh0ZW5kcyBBPih4OiBKc29uVmFsdWU8QT4sIHByZWQ6ICh4OiBBKSA9PiBhc3NlcnRzIHggaXMgQiwgYmxvY2s/OiAoeDogSnNvblZhbHVlPEI+KSA9PiB2b2lkKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHguaGFzVmFsdWUgPyB0aGlzLmFzc2VydCh4LCBwcmVkLCBibG9jaykgOiB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3NlcnQ8QSwgQiBleHRlbmRzIEE+KHg6IEpzb25WYWx1ZTxBPiwgcHJlZDogKHg6IEEpID0+IGFzc2VydHMgeCBpcyBCLCBibG9jaz86ICh4OiBKc29uVmFsdWU8Qj4pID0+IHZvaWQpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgcHJlZCh4LnZhbHVlKTtcbiAgICAgIGlmIChibG9jaykge1xuICAgICAgICBibG9jayhuZXcgSnNvblZhbHVlKHgudmFsdWUsIHgucGF0aCkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5yZXBvcnQoeCwgZS5tZXNzYWdlKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlTWFwPEE+KHg6IEpzb25WYWx1ZTxSZWNvcmQ8c3RyaW5nLCBBPj4sIGJsb2NrOiAoeDogSnNvblZhbHVlPEE+KSA9PiB2b2lkKSB7XG4gICAgZm9yIChjb25zdCBrZXkgaW4geC52YWx1ZSkge1xuICAgICAgYmxvY2soeC5nZXQoa2V5KSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZXBvcnQodmFsdWU6IEpzb25WYWx1ZTxhbnk+LCBtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICB0aGlzLmVycm9ycy5wdXNoKHsgdmFsdWUsIG1lc3NhZ2UgfSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gaXNPYmplY3QoeDogYW55KTogYXNzZXJ0cyB4IGlzIFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICBpZiAoeCA9PSBudWxsIHx8IHR5cGVvZiB4ICE9PSAnb2JqZWN0JyB8fCBBcnJheS5pc0FycmF5KHgpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBleHBlY3RlZCBvYmplY3QsIGZvdW5kICcke3h9J2ApO1xuICB9XG59XG5cbmNvbnN0IENPTExFQ1RJT05fVFlQRVMgPSBbJ0xpc3QnLCAnTWFwJ107XG5jb25zdCBCVUlMVElOX0NPTVBMRVhfVFlQRVMgPSBbJ1RhZyddO1xuXG5mdW5jdGlvbiBpc1ZhbGlkUHJpbWl0aXZlKHg6IGFueSk6IGFzc2VydHMgeCBpcyBzdHJpbmcge1xuICBjb25zdCBwcmltaXRpdmVzID0gWydTdHJpbmcnLCAnTG9uZycsICdJbnRlZ2VyJywgJ0RvdWJsZScsICdCb29sZWFuJywgJ1RpbWVzdGFtcCcsICdKc29uJ107XG5cbiAgaWYgKCFwcmltaXRpdmVzLmluY2x1ZGVzKHgpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBtdXN0IGJlIG9uZSBvZiAke3ByaW1pdGl2ZXMuam9pbignLCAnKX0sIGdvdDogJHt4fWApO1xuICB9XG59XG5cbmludGVyZmFjZSBKc29uVmFsdWU8QT4ge1xuICByZWFkb25seSBwYXRoOiBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgcGF0aFZhbHVlOiBhbnk7XG4gIHJlYWRvbmx5IGhhc1ZhbHVlOiBib29sZWFuO1xuICByZWFkb25seSB2YWx1ZTogQTtcbiAgcmVhZG9ubHkgdmFsdWVPclVuZGVmaW5lZDogQSB8IHVuZGVmaW5lZDtcbiAgZ2V0PEsgZXh0ZW5kcyBrZXlvZiBBPihrOiBLKTogSnNvblZhbHVlPEFbS10+O1xufVxuXG5jbGFzcyBKc29uVmFsdWU8QT4gaW1wbGVtZW50cyBKc29uVmFsdWU8QT4ge1xuICBwdWJsaWMgc3RhdGljIG9mPEI+KHg6IEIpOiBKc29uVmFsdWU8Qj4ge1xuICAgIHJldHVybiBuZXcgSnNvblZhbHVlKHgsIFtdKTtcbiAgfVxuXG4gIHB1YmxpYyByZWFkb25seSBoYXNWYWx1ZTogYm9vbGVhbiA9IHRydWU7XG4gIHB1YmxpYyByZWFkb25seSB2YWx1ZU9yVW5kZWZpbmVkOiBBIHwgdW5kZWZpbmVkID0gdGhpcy52YWx1ZTtcbiAgcHVibGljIHJlYWRvbmx5IHBhdGhWYWx1ZTogYW55ID0gdGhpcy52YWx1ZTtcblxuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgdmFsdWU6IEEsIHB1YmxpYyByZWFkb25seSBwYXRoOiBzdHJpbmdbXSkge1xuICB9XG5cbiAgcHVibGljIGdldDxLIGV4dGVuZHMga2V5b2YgQT4oazogSyk6IEpzb25WYWx1ZTxBW0tdPiB7XG4gICAgaWYgKCF0aGlzLnZhbHVlIHx8IHR5cGVvZiB0aGlzLnZhbHVlICE9PSAnb2JqZWN0JyB8fCBBcnJheS5pc0FycmF5KHRoaXMudmFsdWUpKSB7XG4gICAgICByZXR1cm4gbmV3IEVycm9yVmFsdWUoYGV4cGVjdGVkIG9iamVjdCwgZm91bmQgJHt0aGlzLnZhbHVlfWAsIHRoaXMucGF0aCwgdGhpcy52YWx1ZSk7XG4gICAgfVxuICAgIGNvbnN0IHJldCA9IHRoaXMudmFsdWVba107XG4gICAgaWYgKHJldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gbmV3IEVycm9yVmFsdWUoYG1pc3NpbmcgcmVxdWlyZWQga2V5ICcke2t9J2AsIHRoaXMucGF0aCwgdGhpcy52YWx1ZSk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgSnNvblZhbHVlKHJldCwgWy4uLnRoaXMucGF0aCwgYCR7a31gXSk7XG4gIH1cbn1cblxuY2xhc3MgRXJyb3JWYWx1ZTxBPiBpbXBsZW1lbnRzIEpzb25WYWx1ZTxBPiB7XG4gIHB1YmxpYyByZWFkb25seSBoYXNWYWx1ZSA9IGZhbHNlO1xuICBwdWJsaWMgcmVhZG9ubHkgdmFsdWVPclVuZGVmaW5lZDogQSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGVycm9yOiBzdHJpbmcsIHB1YmxpYyByZWFkb25seSBwYXRoOiBzdHJpbmdbXSwgcHVibGljIHJlYWRvbmx5IHBhdGhWYWx1ZTogYW55KSB7XG4gIH1cblxuICBwdWJsaWMgZ2V0PEsgZXh0ZW5kcyBrZXlvZiBBPihfazogSyk6IEpzb25WYWx1ZTxBW0tdPiB7XG4gICAgcmV0dXJuIHRoaXMgYXMgYW55O1xuICB9XG5cbiAgcHVibGljIGdldCB2YWx1ZSgpOiBBIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy5lcnJvcik7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdEVycm9ySW5Db250ZXh0KGVycm9yOiBWYWxpZGF0aW9uRXJyb3IpIHtcbiAgbGV0IHJlcG9ydFZhbHVlID0gZXJyb3IudmFsdWUucGF0aFZhbHVlO1xuICBmb3IgKGxldCBpID0gZXJyb3IudmFsdWUucGF0aC5sZW5ndGg7IGkgPiAwOyBpLS0pIHtcbiAgICByZXBvcnRWYWx1ZSA9IHsgW2Vycm9yLnZhbHVlLnBhdGhbaSAtIDFdXTogcmVwb3J0VmFsdWUgfTtcbiAgfVxuXG4gIGNvbnN0IGZvcm1hdHRlZExpbmVzID0gSlNPTi5zdHJpbmdpZnkocmVwb3J0VmFsdWUsIHVuZGVmaW5lZCwgMikuc3BsaXQoJ1xcbicpO1xuXG4gIGNvbnN0IGluZGVudCA9IDIgKiAoZXJyb3IudmFsdWUucGF0aC5sZW5ndGggKyAxKTtcblxuICAvLyBJbnNlcnQgdGhlIGVycm9yIG1lc3NhZ2UgYXQgbGluZSBOIHdpdGggYW4gYXBwcm9wcmlhdGUgaW5kZW50XG4gIGZvcm1hdHRlZExpbmVzLnNwbGljZShlcnJvci52YWx1ZS5wYXRoLmxlbmd0aCArIDEsIDAsIGBcXG4hISEkeycgJy5yZXBlYXQoaW5kZW50IC0gMyl9JHtlcnJvci5tZXNzYWdlfSAhISFcXG5gKTtcblxuICByZXR1cm4gZm9ybWF0dGVkTGluZXMuam9pbignXFxuJyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1haW4oYXJnczogc3RyaW5nW10pIHtcbiAgY29uc3Qgc3BlYyA9IGF3YWl0IGZzLnJlYWRKc29uKGFyZ3NbMF0pO1xuICBjb25zdCBlcnJvcnMgPSBDZm5TcGVjVmFsaWRhdG9yLnZhbGlkYXRlKHNwZWMpO1xuICBpZiAoZXJyb3JzLmxlbmd0aCAhPT0gMCkge1xuICAgIGZvciAoY29uc3QgZXJyb3Igb2YgZXJyb3JzKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9ySW5Db250ZXh0KGVycm9yKSk7XG4gICAgfVxuICAgIHByb2Nlc3MuZXhpdENvZGUgPSAxO1xuICB9XG59XG5cbmlmIChyZXF1aXJlLm1haW4gPT09IG1vZHVsZSkge1xuICBtYWluKHByb2Nlc3MuYXJndi5zbGljZSgyKSkuY2F0Y2goZSA9PiB7XG4gICAgcHJvY2Vzcy5leGl0Q29kZSA9IDE7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICBjb25zb2xlLmVycm9yKGUubWVzc2FnZSk7XG4gIH0pO1xufSJdfQ==
|
|
@@ -23,30 +23,30 @@
|
|
|
23
23
|
<div class='clearfix'>
|
|
24
24
|
|
|
25
25
|
<div class='fl pad1y space-right2'>
|
|
26
|
-
<span class="strong">
|
|
26
|
+
<span class="strong">62.24% </span>
|
|
27
27
|
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>
|
|
28
|
+
<span class='fraction'>183/294</span>
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
<div class='fl pad1y space-right2'>
|
|
33
|
-
<span class="strong">
|
|
33
|
+
<span class="strong">45.83% </span>
|
|
34
34
|
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>
|
|
35
|
+
<span class='fraction'>55/120</span>
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
<div class='fl pad1y space-right2'>
|
|
40
|
-
<span class="strong">
|
|
40
|
+
<span class="strong">67.16% </span>
|
|
41
41
|
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>
|
|
42
|
+
<span class='fraction'>45/67</span>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
<div class='fl pad1y space-right2'>
|
|
47
|
-
<span class="strong">
|
|
47
|
+
<span class="strong">63.53% </span>
|
|
48
48
|
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>
|
|
49
|
+
<span class='fraction'>176/277</span>
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
52
|
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
</div>
|
|
62
62
|
</template>
|
|
63
63
|
</div>
|
|
64
|
-
<div class='status-line
|
|
64
|
+
<div class='status-line medium'></div>
|
|
65
65
|
<div class="pad1">
|
|
66
66
|
<table class="coverage-summary">
|
|
67
67
|
<thead>
|
|
@@ -79,18 +79,33 @@
|
|
|
79
79
|
</tr>
|
|
80
80
|
</thead>
|
|
81
81
|
<tbody><tr>
|
|
82
|
-
<td class="file
|
|
83
|
-
<td data-value="
|
|
84
|
-
<div class="chart"><div class="cover-fill" style="width:
|
|
82
|
+
<td class="file medium" data-value="massage-spec.ts"><a href="massage-spec.ts.html">massage-spec.ts</a></td>
|
|
83
|
+
<td data-value="61.53" class="pic medium">
|
|
84
|
+
<div class="chart"><div class="cover-fill" style="width: 61%"></div><div class="cover-empty" style="width: 39%"></div></div>
|
|
85
85
|
</td>
|
|
86
|
-
<td data-value="
|
|
87
|
-
<td data-value="
|
|
88
|
-
<td data-value="22.72" class="pct low">22.72%</td>
|
|
89
|
-
<td data-value="22" class="abs low">5/22</td>
|
|
86
|
+
<td data-value="61.53" class="pct medium">61.53%</td>
|
|
87
|
+
<td data-value="26" class="abs medium">16/26</td>
|
|
90
88
|
<td data-value="45.45" class="pct low">45.45%</td>
|
|
91
89
|
<td data-value="11" class="abs low">5/11</td>
|
|
92
|
-
<td data-value="
|
|
93
|
-
<td data-value="
|
|
90
|
+
<td data-value="71.42" class="pct medium">71.42%</td>
|
|
91
|
+
<td data-value="7" class="abs medium">5/7</td>
|
|
92
|
+
<td data-value="61.53" class="pct medium">61.53%</td>
|
|
93
|
+
<td data-value="26" class="abs medium">16/26</td>
|
|
94
|
+
</tr>
|
|
95
|
+
|
|
96
|
+
<tr>
|
|
97
|
+
<td class="file medium" data-value="patch-set.ts"><a href="patch-set.ts.html">patch-set.ts</a></td>
|
|
98
|
+
<td data-value="54.23" class="pic medium">
|
|
99
|
+
<div class="chart"><div class="cover-fill" style="width: 54%"></div><div class="cover-empty" style="width: 46%"></div></div>
|
|
100
|
+
</td>
|
|
101
|
+
<td data-value="54.23" class="pct medium">54.23%</td>
|
|
102
|
+
<td data-value="118" class="abs medium">64/118</td>
|
|
103
|
+
<td data-value="37.25" class="pct low">37.25%</td>
|
|
104
|
+
<td data-value="51" class="abs low">19/51</td>
|
|
105
|
+
<td data-value="55" class="pct medium">55%</td>
|
|
106
|
+
<td data-value="20" class="abs medium">11/20</td>
|
|
107
|
+
<td data-value="55.85" class="pct medium">55.85%</td>
|
|
108
|
+
<td data-value="111" class="abs medium">62/111</td>
|
|
94
109
|
</tr>
|
|
95
110
|
|
|
96
111
|
<tr>
|
|
@@ -108,6 +123,21 @@
|
|
|
108
123
|
<td data-value="30" class="abs medium">19/30</td>
|
|
109
124
|
</tr>
|
|
110
125
|
|
|
126
|
+
<tr>
|
|
127
|
+
<td class="file high" data-value="validate-cfn.ts"><a href="validate-cfn.ts.html">validate-cfn.ts</a></td>
|
|
128
|
+
<td data-value="72.41" class="pic high">
|
|
129
|
+
<div class="chart"><div class="cover-fill" style="width: 72%"></div><div class="cover-empty" style="width: 28%"></div></div>
|
|
130
|
+
</td>
|
|
131
|
+
<td data-value="72.41" class="pct high">72.41%</td>
|
|
132
|
+
<td data-value="116" class="abs high">84/116</td>
|
|
133
|
+
<td data-value="68.57" class="pct high">68.57%</td>
|
|
134
|
+
<td data-value="35" class="abs high">24/35</td>
|
|
135
|
+
<td data-value="75.75" class="pct medium">75.75%</td>
|
|
136
|
+
<td data-value="33" class="abs medium">25/33</td>
|
|
137
|
+
<td data-value="71.81" class="pct medium">71.81%</td>
|
|
138
|
+
<td data-value="110" class="abs medium">79/110</td>
|
|
139
|
+
</tr>
|
|
140
|
+
|
|
111
141
|
</tbody>
|
|
112
142
|
</table>
|
|
113
143
|
</div>
|
|
@@ -116,9 +146,8 @@
|
|
|
116
146
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
117
147
|
Code coverage generated by
|
|
118
148
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener">istanbul</a>
|
|
119
|
-
at
|
|
149
|
+
at Sun Jan 09 2022 18:58:21 GMT+0000 (Coordinated Universal Time)
|
|
120
150
|
</div>
|
|
121
|
-
</div>
|
|
122
151
|
<script src="../prettify.js"></script>
|
|
123
152
|
<script>
|
|
124
153
|
window.onload = function () {
|