@ng-formworks/core 16.3.0 → 17.3.0
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/esm2022/lib/framework-library/framework-library.service.mjs +174 -174
- package/esm2022/lib/framework-library/framework.mjs +14 -14
- package/esm2022/lib/framework-library/no-framework.component.mjs +17 -17
- package/esm2022/lib/framework-library/no-framework.module.mjs +26 -26
- package/esm2022/lib/framework-library/no.framework.mjs +18 -18
- package/esm2022/lib/json-schema-form.component.mjs +765 -765
- package/esm2022/lib/json-schema-form.module.mjs +25 -25
- package/esm2022/lib/json-schema-form.service.mjs +675 -675
- package/esm2022/lib/locale/de-validation-messages.mjs +59 -59
- package/esm2022/lib/locale/en-validation-messages.mjs +59 -59
- package/esm2022/lib/locale/es-validation-messages.mjs +56 -56
- package/esm2022/lib/locale/fr-validation-messages.mjs +59 -59
- package/esm2022/lib/locale/index.mjs +7 -7
- package/esm2022/lib/locale/it-validation-messages.mjs +59 -59
- package/esm2022/lib/locale/pt-validation-messages.mjs +59 -59
- package/esm2022/lib/locale/zh-validation-messages.mjs +59 -59
- package/esm2022/lib/shared/convert-schema-to-draft6.function.mjs +299 -299
- package/esm2022/lib/shared/form-group.functions.mjs +441 -441
- package/esm2022/lib/shared/format-regex.constants.mjs +53 -53
- package/esm2022/lib/shared/index.mjs +11 -11
- package/esm2022/lib/shared/json-schema.functions.mjs +783 -783
- package/esm2022/lib/shared/json.validators.mjs +883 -883
- package/esm2022/lib/shared/jsonpointer.functions.mjs +1025 -1025
- package/esm2022/lib/shared/layout.functions.mjs +1153 -1153
- package/esm2022/lib/shared/merge-schemas.function.mjs +344 -344
- package/esm2022/lib/shared/utility.functions.mjs +379 -379
- package/esm2022/lib/shared/validator.functions.mjs +583 -583
- package/esm2022/lib/widget-library/add-reference.component.mjs +48 -48
- package/esm2022/lib/widget-library/button.component.mjs +41 -41
- package/esm2022/lib/widget-library/checkbox.component.mjs +46 -46
- package/esm2022/lib/widget-library/checkboxes.component.mjs +52 -52
- package/esm2022/lib/widget-library/file.component.mjs +35 -35
- package/esm2022/lib/widget-library/hidden.component.mjs +33 -33
- package/esm2022/lib/widget-library/index.mjs +54 -54
- package/esm2022/lib/widget-library/input.component.mjs +38 -38
- package/esm2022/lib/widget-library/message.component.mjs +33 -33
- package/esm2022/lib/widget-library/none.component.mjs +20 -20
- package/esm2022/lib/widget-library/number.component.mjs +44 -44
- package/esm2022/lib/widget-library/one-of.component.mjs +35 -35
- package/esm2022/lib/widget-library/orderable.directive.mjs +123 -123
- package/esm2022/lib/widget-library/radios.component.mjs +44 -44
- package/esm2022/lib/widget-library/root.component.mjs +44 -44
- package/esm2022/lib/widget-library/section.component.mjs +78 -78
- package/esm2022/lib/widget-library/select-framework.component.mjs +51 -51
- package/esm2022/lib/widget-library/select-widget.component.mjs +46 -46
- package/esm2022/lib/widget-library/select.component.mjs +41 -41
- package/esm2022/lib/widget-library/submit.component.mjs +55 -55
- package/esm2022/lib/widget-library/tab.component.mjs +30 -30
- package/esm2022/lib/widget-library/tabs.component.mjs +53 -53
- package/esm2022/lib/widget-library/template.component.mjs +46 -46
- package/esm2022/lib/widget-library/textarea.component.mjs +37 -37
- package/esm2022/lib/widget-library/widget-library.module.mjs +41 -41
- package/esm2022/lib/widget-library/widget-library.service.mjs +225 -225
- package/esm2022/ng-formworks-core.mjs +4 -4
- package/esm2022/public_api.mjs +12 -12
- package/fesm2022/ng-formworks-core.mjs +9103 -9103
- package/fesm2022/ng-formworks-core.mjs.map +1 -1
- package/index.d.ts +5 -5
- package/lib/framework-library/framework-library.service.d.ts +55 -55
- package/lib/framework-library/framework.d.ts +13 -13
- package/lib/framework-library/no-framework.component.d.ts +8 -8
- package/lib/framework-library/no-framework.module.d.ts +9 -9
- package/lib/framework-library/no.framework.d.ts +10 -10
- package/lib/json-schema-form.component.d.ts +218 -218
- package/lib/json-schema-form.module.d.ts +11 -11
- package/lib/json-schema-form.service.d.ts +115 -115
- package/lib/locale/de-validation-messages.d.ts +1 -1
- package/lib/locale/en-validation-messages.d.ts +1 -1
- package/lib/locale/es-validation-messages.d.ts +1 -1
- package/lib/locale/fr-validation-messages.d.ts +1 -1
- package/lib/locale/index.d.ts +7 -7
- package/lib/locale/it-validation-messages.d.ts +1 -1
- package/lib/locale/pt-validation-messages.d.ts +1 -1
- package/lib/locale/zh-validation-messages.d.ts +1 -1
- package/lib/shared/convert-schema-to-draft6.function.d.ts +21 -21
- package/lib/shared/form-group.functions.d.ts +100 -100
- package/lib/shared/format-regex.constants.d.ts +19 -19
- package/lib/shared/index.d.ts +9 -9
- package/lib/shared/json-schema.functions.d.ts +193 -193
- package/lib/shared/json.validators.d.ts +441 -441
- package/lib/shared/jsonpointer.functions.d.ts +416 -416
- package/lib/shared/layout.functions.d.ts +83 -83
- package/lib/shared/merge-schemas.function.d.ts +19 -19
- package/lib/shared/utility.functions.d.ts +165 -165
- package/lib/shared/validator.functions.d.ts +364 -364
- package/lib/widget-library/add-reference.component.d.ts +20 -20
- package/lib/widget-library/button.component.d.ts +21 -21
- package/lib/widget-library/checkbox.component.d.ts +24 -24
- package/lib/widget-library/checkboxes.component.d.ts +24 -24
- package/lib/widget-library/file.component.d.ts +21 -21
- package/lib/widget-library/hidden.component.d.ts +19 -19
- package/lib/widget-library/index.d.ts +47 -47
- package/lib/widget-library/input.component.d.ts +22 -22
- package/lib/widget-library/message.component.d.ts +15 -15
- package/lib/widget-library/none.component.d.ts +8 -8
- package/lib/widget-library/number.component.d.ts +25 -25
- package/lib/widget-library/one-of.component.d.ts +21 -21
- package/lib/widget-library/orderable.directive.d.ts +41 -41
- package/lib/widget-library/radios.component.d.ts +23 -23
- package/lib/widget-library/root.component.d.ts +17 -17
- package/lib/widget-library/section.component.d.ts +19 -19
- package/lib/widget-library/select-framework.component.d.ts +18 -18
- package/lib/widget-library/select-widget.component.d.ts +18 -18
- package/lib/widget-library/select.component.d.ts +24 -24
- package/lib/widget-library/submit.component.d.ts +24 -24
- package/lib/widget-library/tab.component.d.ts +14 -14
- package/lib/widget-library/tabs.component.d.ts +20 -20
- package/lib/widget-library/template.component.d.ts +18 -18
- package/lib/widget-library/textarea.component.d.ts +21 -21
- package/lib/widget-library/widget-library.module.d.ts +31 -31
- package/lib/widget-library/widget-library.service.d.ts +22 -22
- package/package.json +5 -5
- package/public_api.d.ts +9 -9
|
@@ -1,1026 +1,1026 @@
|
|
|
1
|
-
import { cleanValueOfQuotes, copy, getExpressionType, getKeyAndValueByExpressionType, hasOwn, isEqual, isNotEqual, isNotExpression } from './utility.functions';
|
|
2
|
-
import { Injectable } from '@angular/core';
|
|
3
|
-
import { isArray, isDefined, isEmpty, isMap, isNumber, isObject, isString } from './validator.functions';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
export class JsonPointer {
|
|
6
|
-
/**
|
|
7
|
-
* 'get' function
|
|
8
|
-
*
|
|
9
|
-
* Uses a JSON Pointer to retrieve a value from an object.
|
|
10
|
-
*
|
|
11
|
-
* // { object } object - Object to get value from
|
|
12
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
13
|
-
* // { number = 0 } startSlice - Zero-based index of first Pointer key to use
|
|
14
|
-
* // { number } endSlice - Zero-based index of last Pointer key to use
|
|
15
|
-
* // { boolean = false } getBoolean - Return only true or false?
|
|
16
|
-
* // { boolean = false } errors - Show error if not found?
|
|
17
|
-
* // { object } - Located value (or true or false if getBoolean = true)
|
|
18
|
-
*/
|
|
19
|
-
static get(object, pointer, startSlice = 0, endSlice = null, getBoolean = false, errors = false) {
|
|
20
|
-
if (object === null) {
|
|
21
|
-
return getBoolean ? false : undefined;
|
|
22
|
-
}
|
|
23
|
-
let keyArray = this.parse(pointer, errors);
|
|
24
|
-
if (typeof object === 'object' && keyArray !== null) {
|
|
25
|
-
let subObject = object;
|
|
26
|
-
if (startSlice >= keyArray.length || endSlice <= -keyArray.length) {
|
|
27
|
-
return object;
|
|
28
|
-
}
|
|
29
|
-
if (startSlice <= -keyArray.length) {
|
|
30
|
-
startSlice = 0;
|
|
31
|
-
}
|
|
32
|
-
if (!isDefined(endSlice) || endSlice >= keyArray.length) {
|
|
33
|
-
endSlice = keyArray.length;
|
|
34
|
-
}
|
|
35
|
-
keyArray = keyArray.slice(startSlice, endSlice);
|
|
36
|
-
for (let key of keyArray) {
|
|
37
|
-
if (key === '-' && isArray(subObject) && subObject.length) {
|
|
38
|
-
key = subObject.length - 1;
|
|
39
|
-
}
|
|
40
|
-
if (isMap(subObject) && subObject.has(key)) {
|
|
41
|
-
subObject = subObject.get(key);
|
|
42
|
-
}
|
|
43
|
-
else if (typeof subObject === 'object' && subObject !== null &&
|
|
44
|
-
hasOwn(subObject, key)) {
|
|
45
|
-
subObject = subObject[key];
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
const evaluatedExpression = JsonPointer.evaluateExpression(subObject, key);
|
|
49
|
-
if (evaluatedExpression.passed) {
|
|
50
|
-
subObject = evaluatedExpression.key ? subObject[evaluatedExpression.key] : subObject;
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
this.logErrors(errors, key, pointer, object);
|
|
54
|
-
return getBoolean ? false : undefined;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return getBoolean ? true : subObject;
|
|
59
|
-
}
|
|
60
|
-
if (errors && keyArray === null) {
|
|
61
|
-
console.error(`get error: Invalid JSON Pointer: ${pointer}`);
|
|
62
|
-
}
|
|
63
|
-
if (errors && typeof object !== 'object') {
|
|
64
|
-
console.error('get error: Invalid object:');
|
|
65
|
-
console.error(object);
|
|
66
|
-
}
|
|
67
|
-
return getBoolean ? false : undefined;
|
|
68
|
-
}
|
|
69
|
-
static logErrors(errors, key, pointer, object) {
|
|
70
|
-
if (errors) {
|
|
71
|
-
console.error(`get error: "${key}" key not found in object.`);
|
|
72
|
-
console.error(pointer);
|
|
73
|
-
console.error(object);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Evaluates conditional expression in form of `model.<property>==<value>` or
|
|
78
|
-
* `model.<property>!=<value>` where the first one means that the value must match to be
|
|
79
|
-
* shown in a form, while the former shows the property only when the property value is not
|
|
80
|
-
* set, or does not equal the given value.
|
|
81
|
-
*
|
|
82
|
-
* // { subObject } subObject - an object containing the data values of properties
|
|
83
|
-
* // { key } key - the key from the for loop in a form of `<property>==<value>`
|
|
84
|
-
*
|
|
85
|
-
* Returns the object with two properties. The property passed informs whether
|
|
86
|
-
* the expression evaluated successfully and the property key returns either the same
|
|
87
|
-
* key if it is not contained inside the subObject or the key of the property if it is contained.
|
|
88
|
-
*/
|
|
89
|
-
static evaluateExpression(subObject, key) {
|
|
90
|
-
const defaultResult = { passed: false, key: key };
|
|
91
|
-
const keysAndExpression = this.parseKeysAndExpression(key, subObject);
|
|
92
|
-
if (!keysAndExpression) {
|
|
93
|
-
return defaultResult;
|
|
94
|
-
}
|
|
95
|
-
const ownCheckResult = this.doOwnCheckResult(subObject, keysAndExpression);
|
|
96
|
-
if (ownCheckResult) {
|
|
97
|
-
return ownCheckResult;
|
|
98
|
-
}
|
|
99
|
-
const cleanedValue = cleanValueOfQuotes(keysAndExpression.keyAndValue[1]);
|
|
100
|
-
const evaluatedResult = this.performExpressionOnValue(keysAndExpression, cleanedValue, subObject);
|
|
101
|
-
if (evaluatedResult) {
|
|
102
|
-
return evaluatedResult;
|
|
103
|
-
}
|
|
104
|
-
return defaultResult;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Performs the actual evaluation on the given expression with given values and keys.
|
|
108
|
-
* // { cleanedValue } cleanedValue - the given valued cleaned of quotes if it had any
|
|
109
|
-
* // { subObject } subObject - the object with properties values
|
|
110
|
-
* // { keysAndExpression } keysAndExpression - an object holding the expressions with
|
|
111
|
-
*/
|
|
112
|
-
static performExpressionOnValue(keysAndExpression, cleanedValue, subObject) {
|
|
113
|
-
const propertyByKey = subObject[keysAndExpression.keyAndValue[0]];
|
|
114
|
-
if (this.doComparisonByExpressionType(keysAndExpression.expressionType, propertyByKey, cleanedValue)) {
|
|
115
|
-
return { passed: true, key: keysAndExpression.keyAndValue[0] };
|
|
116
|
-
}
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
static doComparisonByExpressionType(expressionType, propertyByKey, cleanedValue) {
|
|
120
|
-
if (isEqual(expressionType)) {
|
|
121
|
-
return propertyByKey === cleanedValue;
|
|
122
|
-
}
|
|
123
|
-
if (isNotEqual(expressionType)) {
|
|
124
|
-
return propertyByKey !== cleanedValue;
|
|
125
|
-
}
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Does the checks when the parsed key is actually no a property inside subObject.
|
|
130
|
-
* That would mean that the equal comparison makes no sense and thus the negative result
|
|
131
|
-
* is returned, and the not equal comparison is not necessary because it doesn't equal
|
|
132
|
-
* obviously. Returns null when the given key is a real property inside the subObject.
|
|
133
|
-
* // { subObject } subObject - the object with properties values
|
|
134
|
-
* // { keysAndExpression } keysAndExpression - an object holding the expressions with
|
|
135
|
-
* the associated keys.
|
|
136
|
-
*/
|
|
137
|
-
static doOwnCheckResult(subObject, keysAndExpression) {
|
|
138
|
-
let ownCheckResult = null;
|
|
139
|
-
if (!hasOwn(subObject, keysAndExpression.keyAndValue[0])) {
|
|
140
|
-
if (isEqual(keysAndExpression.expressionType)) {
|
|
141
|
-
ownCheckResult = { passed: false, key: null };
|
|
142
|
-
}
|
|
143
|
-
if (isNotEqual(keysAndExpression.expressionType)) {
|
|
144
|
-
ownCheckResult = { passed: true, key: null };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return ownCheckResult;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Does the basic checks and tries to parse an expression and a pair
|
|
151
|
-
* of key and value.
|
|
152
|
-
* // { key } key - the original for loop created value containing key and value in one string
|
|
153
|
-
* // { subObject } subObject - the object with properties values
|
|
154
|
-
*/
|
|
155
|
-
static parseKeysAndExpression(key, subObject) {
|
|
156
|
-
if (this.keyOrSubObjEmpty(key, subObject)) {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
const expressionType = getExpressionType(key.toString());
|
|
160
|
-
if (isNotExpression(expressionType)) {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
const keyAndValue = getKeyAndValueByExpressionType(expressionType, key);
|
|
164
|
-
if (!keyAndValue || !keyAndValue[0] || !keyAndValue[1]) {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
return { expressionType: expressionType, keyAndValue: keyAndValue };
|
|
168
|
-
}
|
|
169
|
-
static keyOrSubObjEmpty(key, subObject) {
|
|
170
|
-
return !key || !subObject;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* 'getCopy' function
|
|
174
|
-
*
|
|
175
|
-
* Uses a JSON Pointer to deeply clone a value from an object.
|
|
176
|
-
*
|
|
177
|
-
* // { object } object - Object to get value from
|
|
178
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
179
|
-
* // { number = 0 } startSlice - Zero-based index of first Pointer key to use
|
|
180
|
-
* // { number } endSlice - Zero-based index of last Pointer key to use
|
|
181
|
-
* // { boolean = false } getBoolean - Return only true or false?
|
|
182
|
-
* // { boolean = false } errors - Show error if not found?
|
|
183
|
-
* // { object } - Located value (or true or false if getBoolean = true)
|
|
184
|
-
*/
|
|
185
|
-
static getCopy(object, pointer, startSlice = 0, endSlice = null, getBoolean = false, errors = false) {
|
|
186
|
-
const objectToCopy = this.get(object, pointer, startSlice, endSlice, getBoolean, errors);
|
|
187
|
-
return this.forEachDeepCopy(objectToCopy);
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* 'getFirst' function
|
|
191
|
-
*
|
|
192
|
-
* Takes an array of JSON Pointers and objects,
|
|
193
|
-
* checks each object for a value specified by the pointer,
|
|
194
|
-
* and returns the first value found.
|
|
195
|
-
*
|
|
196
|
-
* // { [object, pointer][] } items - Array of objects and pointers to check
|
|
197
|
-
* // { any = null } defaultValue - Value to return if nothing found
|
|
198
|
-
* // { boolean = false } getCopy - Return a copy instead?
|
|
199
|
-
* // - First value found
|
|
200
|
-
*/
|
|
201
|
-
static getFirst(items, defaultValue = null, getCopy = false) {
|
|
202
|
-
if (isEmpty(items)) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
if (isArray(items)) {
|
|
206
|
-
for (const item of items) {
|
|
207
|
-
if (isEmpty(item)) {
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
if (isArray(item) && item.length >= 2) {
|
|
211
|
-
if (isEmpty(item[0]) || isEmpty(item[1])) {
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
const value = getCopy ?
|
|
215
|
-
this.getCopy(item[0], item[1]) :
|
|
216
|
-
this.get(item[0], item[1]);
|
|
217
|
-
if (value) {
|
|
218
|
-
return value;
|
|
219
|
-
}
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
console.error('getFirst error: Input not in correct format.\n' +
|
|
223
|
-
'Should be: [ [ object1, pointer1 ], [ object 2, pointer2 ], etc... ]');
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
return defaultValue;
|
|
227
|
-
}
|
|
228
|
-
if (isMap(items)) {
|
|
229
|
-
for (const [object, pointer] of items) {
|
|
230
|
-
if (object === null || !this.isJsonPointer(pointer)) {
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
const value = getCopy ?
|
|
234
|
-
this.getCopy(object, pointer) :
|
|
235
|
-
this.get(object, pointer);
|
|
236
|
-
if (value) {
|
|
237
|
-
return value;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return defaultValue;
|
|
241
|
-
}
|
|
242
|
-
console.error('getFirst error: Input not in correct format.\n' +
|
|
243
|
-
'Should be: [ [ object1, pointer1 ], [ object 2, pointer2 ], etc... ]');
|
|
244
|
-
return defaultValue;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* 'getFirstCopy' function
|
|
248
|
-
*
|
|
249
|
-
* Similar to getFirst, but always returns a copy.
|
|
250
|
-
*
|
|
251
|
-
* // { [object, pointer][] } items - Array of objects and pointers to check
|
|
252
|
-
* // { any = null } defaultValue - Value to return if nothing found
|
|
253
|
-
* // - Copy of first value found
|
|
254
|
-
*/
|
|
255
|
-
static getFirstCopy(items, defaultValue = null) {
|
|
256
|
-
const firstCopy = this.getFirst(items, defaultValue, true);
|
|
257
|
-
return firstCopy;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* 'set' function
|
|
261
|
-
*
|
|
262
|
-
* Uses a JSON Pointer to set a value on an object.
|
|
263
|
-
* Also creates any missing sub objects or arrays to contain that value.
|
|
264
|
-
*
|
|
265
|
-
* If the optional fourth parameter is TRUE and the inner-most container
|
|
266
|
-
* is an array, the function will insert the value as a new item at the
|
|
267
|
-
* specified location in the array, rather than overwriting the existing
|
|
268
|
-
* value (if any) at that location.
|
|
269
|
-
*
|
|
270
|
-
* So set([1, 2, 3], '/1', 4) => [1, 4, 3]
|
|
271
|
-
* and
|
|
272
|
-
* So set([1, 2, 3], '/1', 4, true) => [1, 4, 2, 3]
|
|
273
|
-
*
|
|
274
|
-
* // { object } object - The object to set value in
|
|
275
|
-
* // { Pointer } pointer - The JSON Pointer (string or array)
|
|
276
|
-
* // value - The new value to set
|
|
277
|
-
* // { boolean } insert - insert value?
|
|
278
|
-
* // { object } - The original object, modified with the set value
|
|
279
|
-
*/
|
|
280
|
-
static set(object, pointer, value, insert = false) {
|
|
281
|
-
const keyArray = this.parse(pointer);
|
|
282
|
-
if (keyArray !== null && keyArray.length) {
|
|
283
|
-
let subObject = object;
|
|
284
|
-
for (let i = 0; i < keyArray.length - 1; ++i) {
|
|
285
|
-
let key = keyArray[i];
|
|
286
|
-
if (key === '-' && isArray(subObject)) {
|
|
287
|
-
key = subObject.length;
|
|
288
|
-
}
|
|
289
|
-
if (isMap(subObject) && subObject.has(key)) {
|
|
290
|
-
subObject = subObject.get(key);
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
if (!hasOwn(subObject, key)) {
|
|
294
|
-
subObject[key] = (keyArray[i + 1].match(/^(\d+|-)$/)) ? [] : {};
|
|
295
|
-
}
|
|
296
|
-
subObject = subObject[key];
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const lastKey = keyArray[keyArray.length - 1];
|
|
300
|
-
if (isArray(subObject) && lastKey === '-') {
|
|
301
|
-
subObject.push(value);
|
|
302
|
-
}
|
|
303
|
-
else if (insert && isArray(subObject) && !isNaN(+lastKey)) {
|
|
304
|
-
subObject.splice(lastKey, 0, value);
|
|
305
|
-
}
|
|
306
|
-
else if (isMap(subObject)) {
|
|
307
|
-
subObject.set(lastKey, value);
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
subObject[lastKey] = value;
|
|
311
|
-
}
|
|
312
|
-
return object;
|
|
313
|
-
}
|
|
314
|
-
console.error(`set error: Invalid JSON Pointer: ${pointer}`);
|
|
315
|
-
return object;
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* 'setCopy' function
|
|
319
|
-
*
|
|
320
|
-
* Copies an object and uses a JSON Pointer to set a value on the copy.
|
|
321
|
-
* Also creates any missing sub objects or arrays to contain that value.
|
|
322
|
-
*
|
|
323
|
-
* If the optional fourth parameter is TRUE and the inner-most container
|
|
324
|
-
* is an array, the function will insert the value as a new item at the
|
|
325
|
-
* specified location in the array, rather than overwriting the existing value.
|
|
326
|
-
*
|
|
327
|
-
* // { object } object - The object to copy and set value in
|
|
328
|
-
* // { Pointer } pointer - The JSON Pointer (string or array)
|
|
329
|
-
* // value - The value to set
|
|
330
|
-
* // { boolean } insert - insert value?
|
|
331
|
-
* // { object } - The new object with the set value
|
|
332
|
-
*/
|
|
333
|
-
static setCopy(object, pointer, value, insert = false) {
|
|
334
|
-
const keyArray = this.parse(pointer);
|
|
335
|
-
if (keyArray !== null) {
|
|
336
|
-
const newObject = copy(object);
|
|
337
|
-
let subObject = newObject;
|
|
338
|
-
for (let i = 0; i < keyArray.length - 1; ++i) {
|
|
339
|
-
let key = keyArray[i];
|
|
340
|
-
if (key === '-' && isArray(subObject)) {
|
|
341
|
-
key = subObject.length;
|
|
342
|
-
}
|
|
343
|
-
if (isMap(subObject) && subObject.has(key)) {
|
|
344
|
-
subObject.set(key, copy(subObject.get(key)));
|
|
345
|
-
subObject = subObject.get(key);
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
if (!hasOwn(subObject, key)) {
|
|
349
|
-
subObject[key] = (keyArray[i + 1].match(/^(\d+|-)$/)) ? [] : {};
|
|
350
|
-
}
|
|
351
|
-
subObject[key] = copy(subObject[key]);
|
|
352
|
-
subObject = subObject[key];
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
const lastKey = keyArray[keyArray.length - 1];
|
|
356
|
-
if (isArray(subObject) && lastKey === '-') {
|
|
357
|
-
subObject.push(value);
|
|
358
|
-
}
|
|
359
|
-
else if (insert && isArray(subObject) && !isNaN(+lastKey)) {
|
|
360
|
-
subObject.splice(lastKey, 0, value);
|
|
361
|
-
}
|
|
362
|
-
else if (isMap(subObject)) {
|
|
363
|
-
subObject.set(lastKey, value);
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
subObject[lastKey] = value;
|
|
367
|
-
}
|
|
368
|
-
return newObject;
|
|
369
|
-
}
|
|
370
|
-
console.error(`setCopy error: Invalid JSON Pointer: ${pointer}`);
|
|
371
|
-
return object;
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* 'insert' function
|
|
375
|
-
*
|
|
376
|
-
* Calls 'set' with insert = TRUE
|
|
377
|
-
*
|
|
378
|
-
* // { object } object - object to insert value in
|
|
379
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
380
|
-
* // value - value to insert
|
|
381
|
-
* // { object }
|
|
382
|
-
*/
|
|
383
|
-
static insert(object, pointer, value) {
|
|
384
|
-
const updatedObject = this.set(object, pointer, value, true);
|
|
385
|
-
return updatedObject;
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* 'insertCopy' function
|
|
389
|
-
*
|
|
390
|
-
* Calls 'setCopy' with insert = TRUE
|
|
391
|
-
*
|
|
392
|
-
* // { object } object - object to insert value in
|
|
393
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
394
|
-
* // value - value to insert
|
|
395
|
-
* // { object }
|
|
396
|
-
*/
|
|
397
|
-
static insertCopy(object, pointer, value) {
|
|
398
|
-
const updatedObject = this.setCopy(object, pointer, value, true);
|
|
399
|
-
return updatedObject;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* 'remove' function
|
|
403
|
-
*
|
|
404
|
-
* Uses a JSON Pointer to remove a key and its attribute from an object
|
|
405
|
-
*
|
|
406
|
-
* // { object } object - object to delete attribute from
|
|
407
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
408
|
-
* // { object }
|
|
409
|
-
*/
|
|
410
|
-
static remove(object, pointer) {
|
|
411
|
-
const keyArray = this.parse(pointer);
|
|
412
|
-
if (keyArray !== null && keyArray.length) {
|
|
413
|
-
let lastKey = keyArray.pop();
|
|
414
|
-
const parentObject = this.get(object, keyArray);
|
|
415
|
-
if (isArray(parentObject)) {
|
|
416
|
-
if (lastKey === '-') {
|
|
417
|
-
lastKey = parentObject.length - 1;
|
|
418
|
-
}
|
|
419
|
-
parentObject.splice(lastKey, 1);
|
|
420
|
-
}
|
|
421
|
-
else if (isObject(parentObject)) {
|
|
422
|
-
delete parentObject[lastKey];
|
|
423
|
-
}
|
|
424
|
-
return object;
|
|
425
|
-
}
|
|
426
|
-
console.error(`remove error: Invalid JSON Pointer: ${pointer}`);
|
|
427
|
-
return object;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* 'has' function
|
|
431
|
-
*
|
|
432
|
-
* Tests if an object has a value at the location specified by a JSON Pointer
|
|
433
|
-
*
|
|
434
|
-
* // { object } object - object to chek for value
|
|
435
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
436
|
-
* // { boolean }
|
|
437
|
-
*/
|
|
438
|
-
static has(object, pointer) {
|
|
439
|
-
const hasValue = this.get(object, pointer, 0, null, true);
|
|
440
|
-
return hasValue;
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* 'dict' function
|
|
444
|
-
*
|
|
445
|
-
* Returns a (pointer -> value) dictionary for an object
|
|
446
|
-
*
|
|
447
|
-
* // { object } object - The object to create a dictionary from
|
|
448
|
-
* // { object } - The resulting dictionary object
|
|
449
|
-
*/
|
|
450
|
-
static dict(object) {
|
|
451
|
-
const results = {};
|
|
452
|
-
this.forEachDeep(object, (value, pointer) => {
|
|
453
|
-
if (typeof value !== 'object') {
|
|
454
|
-
results[pointer] = value;
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
return results;
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* 'forEachDeep' function
|
|
461
|
-
*
|
|
462
|
-
* Iterates over own enumerable properties of an object or items in an array
|
|
463
|
-
* and invokes an iteratee function for each key/value or index/value pair.
|
|
464
|
-
* By default, iterates over items within objects and arrays after calling
|
|
465
|
-
* the iteratee function on the containing object or array itself.
|
|
466
|
-
*
|
|
467
|
-
* The iteratee is invoked with three arguments: (value, pointer, rootObject),
|
|
468
|
-
* where pointer is a JSON pointer indicating the location of the current
|
|
469
|
-
* value within the root object, and rootObject is the root object initially
|
|
470
|
-
* submitted to th function.
|
|
471
|
-
*
|
|
472
|
-
* If a third optional parameter 'bottomUp' is set to TRUE, the iterator
|
|
473
|
-
* function will be called on sub-objects and arrays after being
|
|
474
|
-
* called on their contents, rather than before, which is the default.
|
|
475
|
-
*
|
|
476
|
-
* This function can also optionally be called directly on a sub-object by
|
|
477
|
-
* including optional 4th and 5th parameterss to specify the initial
|
|
478
|
-
* root object and pointer.
|
|
479
|
-
*
|
|
480
|
-
* // { object } object - the initial object or array
|
|
481
|
-
* // { (v: any, p?: string, o?: any) => any } function - iteratee function
|
|
482
|
-
* // { boolean = false } bottomUp - optional, set to TRUE to reverse direction
|
|
483
|
-
* // { object = object } rootObject - optional, root object or array
|
|
484
|
-
* // { string = '' } pointer - optional, JSON Pointer to object within rootObject
|
|
485
|
-
* // { object } - The modified object
|
|
486
|
-
*/
|
|
487
|
-
static forEachDeep(object, fn = (v) => v, bottomUp = false, pointer = '', rootObject = object) {
|
|
488
|
-
if (typeof fn !== 'function') {
|
|
489
|
-
console.error(`forEachDeep error: Iterator is not a function:`, fn);
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
if (!bottomUp) {
|
|
493
|
-
fn(object, pointer, rootObject);
|
|
494
|
-
}
|
|
495
|
-
if (isObject(object) || isArray(object)) {
|
|
496
|
-
for (const key of Object.keys(object)) {
|
|
497
|
-
const newPointer = pointer + '/' + this.escape(key);
|
|
498
|
-
this.forEachDeep(object[key], fn, bottomUp, newPointer, rootObject);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
if (bottomUp) {
|
|
502
|
-
fn(object, pointer, rootObject);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* 'forEachDeepCopy' function
|
|
507
|
-
*
|
|
508
|
-
* Similar to forEachDeep, but returns a copy of the original object, with
|
|
509
|
-
* the same keys and indexes, but with values replaced with the result of
|
|
510
|
-
* the iteratee function.
|
|
511
|
-
*
|
|
512
|
-
* // { object } object - the initial object or array
|
|
513
|
-
* // { (v: any, k?: string, o?: any, p?: any) => any } function - iteratee function
|
|
514
|
-
* // { boolean = false } bottomUp - optional, set to TRUE to reverse direction
|
|
515
|
-
* // { object = object } rootObject - optional, root object or array
|
|
516
|
-
* // { string = '' } pointer - optional, JSON Pointer to object within rootObject
|
|
517
|
-
* // { object } - The copied object
|
|
518
|
-
*/
|
|
519
|
-
static forEachDeepCopy(object, fn = (v) => v, bottomUp = false, pointer = '', rootObject = object) {
|
|
520
|
-
if (typeof fn !== 'function') {
|
|
521
|
-
console.error(`forEachDeepCopy error: Iterator is not a function:`, fn);
|
|
522
|
-
return null;
|
|
523
|
-
}
|
|
524
|
-
if (isObject(object) || isArray(object)) {
|
|
525
|
-
let newObject = isArray(object) ? [...object] : { ...object };
|
|
526
|
-
if (!bottomUp) {
|
|
527
|
-
newObject = fn(newObject, pointer, rootObject);
|
|
528
|
-
}
|
|
529
|
-
for (const key of Object.keys(newObject)) {
|
|
530
|
-
const newPointer = pointer + '/' + this.escape(key);
|
|
531
|
-
newObject[key] = this.forEachDeepCopy(newObject[key], fn, bottomUp, newPointer, rootObject);
|
|
532
|
-
}
|
|
533
|
-
if (bottomUp) {
|
|
534
|
-
newObject = fn(newObject, pointer, rootObject);
|
|
535
|
-
}
|
|
536
|
-
return newObject;
|
|
537
|
-
}
|
|
538
|
-
else {
|
|
539
|
-
return fn(object, pointer, rootObject);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* 'escape' function
|
|
544
|
-
*
|
|
545
|
-
* Escapes a string reference key
|
|
546
|
-
*
|
|
547
|
-
* // { string } key - string key to escape
|
|
548
|
-
* // { string } - escaped key
|
|
549
|
-
*/
|
|
550
|
-
static escape(key) {
|
|
551
|
-
const escaped = key.toString().replace(/~/g, '~0').replace(/\//g, '~1');
|
|
552
|
-
return escaped;
|
|
553
|
-
}
|
|
554
|
-
/**
|
|
555
|
-
* 'unescape' function
|
|
556
|
-
*
|
|
557
|
-
* Unescapes a string reference key
|
|
558
|
-
*
|
|
559
|
-
* // { string } key - string key to unescape
|
|
560
|
-
* // { string } - unescaped key
|
|
561
|
-
*/
|
|
562
|
-
static unescape(key) {
|
|
563
|
-
const unescaped = key.toString().replace(/~1/g, '/').replace(/~0/g, '~');
|
|
564
|
-
return unescaped;
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* 'parse' function
|
|
568
|
-
*
|
|
569
|
-
* Converts a string JSON Pointer into a array of keys
|
|
570
|
-
* (if input is already an an array of keys, it is returned unchanged)
|
|
571
|
-
*
|
|
572
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
573
|
-
* // { boolean = false } errors - Show error if invalid pointer?
|
|
574
|
-
* // { string[] } - JSON Pointer array of keys
|
|
575
|
-
*/
|
|
576
|
-
static parse(pointer, errors = false) {
|
|
577
|
-
if (!this.isJsonPointer(pointer)) {
|
|
578
|
-
if (errors) {
|
|
579
|
-
console.error(`parse error: Invalid JSON Pointer: ${pointer}`);
|
|
580
|
-
}
|
|
581
|
-
return null;
|
|
582
|
-
}
|
|
583
|
-
if (isArray(pointer)) {
|
|
584
|
-
return pointer;
|
|
585
|
-
}
|
|
586
|
-
if (typeof pointer === 'string') {
|
|
587
|
-
if (pointer[0] === '#') {
|
|
588
|
-
pointer = pointer.slice(1);
|
|
589
|
-
}
|
|
590
|
-
if (pointer === '' || pointer === '/') {
|
|
591
|
-
return [];
|
|
592
|
-
}
|
|
593
|
-
return pointer.slice(1).split('/').map(this.unescape);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* 'compile' function
|
|
598
|
-
*
|
|
599
|
-
* Converts an array of keys into a JSON Pointer string
|
|
600
|
-
* (if input is already a string, it is normalized and returned)
|
|
601
|
-
*
|
|
602
|
-
* The optional second parameter is a default which will replace any empty keys.
|
|
603
|
-
*
|
|
604
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
605
|
-
* // { string | number = '' } defaultValue - Default value
|
|
606
|
-
* // { boolean = false } errors - Show error if invalid pointer?
|
|
607
|
-
* // { string } - JSON Pointer string
|
|
608
|
-
*/
|
|
609
|
-
static compile(pointer, defaultValue = '', errors = false) {
|
|
610
|
-
if (pointer === '#') {
|
|
611
|
-
return '';
|
|
612
|
-
}
|
|
613
|
-
if (!this.isJsonPointer(pointer)) {
|
|
614
|
-
if (errors) {
|
|
615
|
-
console.error(`compile error: Invalid JSON Pointer: ${pointer}`);
|
|
616
|
-
}
|
|
617
|
-
return null;
|
|
618
|
-
}
|
|
619
|
-
if (isArray(pointer)) {
|
|
620
|
-
if (pointer.length === 0) {
|
|
621
|
-
return '';
|
|
622
|
-
}
|
|
623
|
-
return '/' + pointer.map(key => key === '' ? defaultValue : this.escape(key)).join('/');
|
|
624
|
-
}
|
|
625
|
-
if (typeof pointer === 'string') {
|
|
626
|
-
if (pointer[0] === '#') {
|
|
627
|
-
pointer = pointer.slice(1);
|
|
628
|
-
}
|
|
629
|
-
return pointer;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
/**
|
|
633
|
-
* 'toKey' function
|
|
634
|
-
*
|
|
635
|
-
* Extracts name of the final key from a JSON Pointer.
|
|
636
|
-
*
|
|
637
|
-
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
638
|
-
* // { boolean = false } errors - Show error if invalid pointer?
|
|
639
|
-
* // { string } - the extracted key
|
|
640
|
-
*/
|
|
641
|
-
static toKey(pointer, errors = false) {
|
|
642
|
-
const keyArray = this.parse(pointer, errors);
|
|
643
|
-
if (keyArray === null) {
|
|
644
|
-
return null;
|
|
645
|
-
}
|
|
646
|
-
if (!keyArray.length) {
|
|
647
|
-
return '';
|
|
648
|
-
}
|
|
649
|
-
return keyArray[keyArray.length - 1];
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* 'isJsonPointer' function
|
|
653
|
-
*
|
|
654
|
-
* Checks a string or array value to determine if it is a valid JSON Pointer.
|
|
655
|
-
* Returns true if a string is empty, or starts with '/' or '#/'.
|
|
656
|
-
* Returns true if an array contains only string values.
|
|
657
|
-
*
|
|
658
|
-
* // value - value to check
|
|
659
|
-
* // { boolean } - true if value is a valid JSON Pointer, otherwise false
|
|
660
|
-
*/
|
|
661
|
-
static isJsonPointer(value) {
|
|
662
|
-
if (isArray(value)) {
|
|
663
|
-
return value.every(key => typeof key === 'string');
|
|
664
|
-
}
|
|
665
|
-
else if (isString(value)) {
|
|
666
|
-
if (value === '' || value === '#') {
|
|
667
|
-
return true;
|
|
668
|
-
}
|
|
669
|
-
if (value[0] === '/' || value.slice(0, 2) === '#/') {
|
|
670
|
-
return !/(~[^01]|~$)/g.test(value);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
return false;
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* 'isSubPointer' function
|
|
677
|
-
*
|
|
678
|
-
* Checks whether one JSON Pointer is a subset of another.
|
|
679
|
-
*
|
|
680
|
-
* // { Pointer } shortPointer - potential subset JSON Pointer
|
|
681
|
-
* // { Pointer } longPointer - potential superset JSON Pointer
|
|
682
|
-
* // { boolean = false } trueIfMatching - return true if pointers match?
|
|
683
|
-
* // { boolean = false } errors - Show error if invalid pointer?
|
|
684
|
-
* // { boolean } - true if shortPointer is a subset of longPointer, false if not
|
|
685
|
-
*/
|
|
686
|
-
static isSubPointer(shortPointer, longPointer, trueIfMatching = false, errors = false) {
|
|
687
|
-
if (!this.isJsonPointer(shortPointer) || !this.isJsonPointer(longPointer)) {
|
|
688
|
-
if (errors) {
|
|
689
|
-
let invalid = '';
|
|
690
|
-
if (!this.isJsonPointer(shortPointer)) {
|
|
691
|
-
invalid += ` 1: ${shortPointer}`;
|
|
692
|
-
}
|
|
693
|
-
if (!this.isJsonPointer(longPointer)) {
|
|
694
|
-
invalid += ` 2: ${longPointer}`;
|
|
695
|
-
}
|
|
696
|
-
console.error(`isSubPointer error: Invalid JSON Pointer ${invalid}`);
|
|
697
|
-
}
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
shortPointer = this.compile(shortPointer, '', errors);
|
|
701
|
-
longPointer = this.compile(longPointer, '', errors);
|
|
702
|
-
return shortPointer === longPointer ? trueIfMatching :
|
|
703
|
-
`${shortPointer}/` === longPointer.slice(0, shortPointer.length + 1);
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* 'toIndexedPointer' function
|
|
707
|
-
*
|
|
708
|
-
* Merges an array of numeric indexes and a generic pointer to create an
|
|
709
|
-
* indexed pointer for a specific item.
|
|
710
|
-
*
|
|
711
|
-
* For example, merging the generic pointer '/foo/-/bar/-/baz' and
|
|
712
|
-
* the array [4, 2] would result in the indexed pointer '/foo/4/bar/2/baz'
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
* // { Pointer } genericPointer - The generic pointer
|
|
716
|
-
* // { number[] } indexArray - The array of numeric indexes
|
|
717
|
-
* // { Map<string, number> } arrayMap - An optional array map
|
|
718
|
-
* // { string } - The merged pointer with indexes
|
|
719
|
-
*/
|
|
720
|
-
static toIndexedPointer(genericPointer, indexArray, arrayMap = null) {
|
|
721
|
-
if (this.isJsonPointer(genericPointer) && isArray(indexArray)) {
|
|
722
|
-
let indexedPointer = this.compile(genericPointer);
|
|
723
|
-
if (isMap(arrayMap)) {
|
|
724
|
-
let arrayIndex = 0;
|
|
725
|
-
return indexedPointer.replace(/\/\-(?=\/|$)/g, (key, stringIndex) => arrayMap.has(indexedPointer.slice(0, stringIndex)) ?
|
|
726
|
-
'/' + indexArray[arrayIndex++] : key);
|
|
727
|
-
}
|
|
728
|
-
else {
|
|
729
|
-
for (const pointerIndex of indexArray) {
|
|
730
|
-
indexedPointer = indexedPointer.replace('/-', '/' + pointerIndex);
|
|
731
|
-
}
|
|
732
|
-
return indexedPointer;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
if (!this.isJsonPointer(genericPointer)) {
|
|
736
|
-
console.error(`toIndexedPointer error: Invalid JSON Pointer: ${genericPointer}`);
|
|
737
|
-
}
|
|
738
|
-
if (!isArray(indexArray)) {
|
|
739
|
-
console.error(`toIndexedPointer error: Invalid indexArray: ${indexArray}`);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
/**
|
|
743
|
-
* 'toGenericPointer' function
|
|
744
|
-
*
|
|
745
|
-
* Compares an indexed pointer to an array map and removes list array
|
|
746
|
-
* indexes (but leaves tuple arrray indexes and all object keys, including
|
|
747
|
-
* numeric keys) to create a generic pointer.
|
|
748
|
-
*
|
|
749
|
-
* For example, using the indexed pointer '/foo/1/bar/2/baz/3' and
|
|
750
|
-
* the arrayMap [['/foo', 0], ['/foo/-/bar', 3], ['/foo/-/bar/-/baz', 0]]
|
|
751
|
-
* would result in the generic pointer '/foo/-/bar/2/baz/-'
|
|
752
|
-
* Using the indexed pointer '/foo/1/bar/4/baz/3' and the same arrayMap
|
|
753
|
-
* would result in the generic pointer '/foo/-/bar/-/baz/-'
|
|
754
|
-
* (the bar array has 3 tuple items, so index 2 is retained, but 4 is removed)
|
|
755
|
-
*
|
|
756
|
-
* The structure of the arrayMap is: [['path to array', number of tuple items]...]
|
|
757
|
-
*
|
|
758
|
-
*
|
|
759
|
-
* // { Pointer } indexedPointer - The indexed pointer (array or string)
|
|
760
|
-
* // { Map<string, number> } arrayMap - The optional array map (for preserving tuple indexes)
|
|
761
|
-
* // { string } - The generic pointer with indexes removed
|
|
762
|
-
*/
|
|
763
|
-
static toGenericPointer(indexedPointer, arrayMap = new Map()) {
|
|
764
|
-
if (this.isJsonPointer(indexedPointer) && isMap(arrayMap)) {
|
|
765
|
-
const pointerArray = this.parse(indexedPointer);
|
|
766
|
-
for (let i = 1; i < pointerArray.length; i++) {
|
|
767
|
-
const subPointer = this.compile(pointerArray.slice(0, i));
|
|
768
|
-
if (arrayMap.has(subPointer) &&
|
|
769
|
-
arrayMap.get(subPointer) <= +pointerArray[i]) {
|
|
770
|
-
pointerArray[i] = '-';
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
return this.compile(pointerArray);
|
|
774
|
-
}
|
|
775
|
-
if (!this.isJsonPointer(indexedPointer)) {
|
|
776
|
-
console.error(`toGenericPointer error: invalid JSON Pointer: ${indexedPointer}`);
|
|
777
|
-
}
|
|
778
|
-
if (!isMap(arrayMap)) {
|
|
779
|
-
console.error(`toGenericPointer error: invalid arrayMap: ${arrayMap}`);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
/**
|
|
783
|
-
* 'toControlPointer' function
|
|
784
|
-
*
|
|
785
|
-
* Accepts a JSON Pointer for a data object and returns a JSON Pointer for the
|
|
786
|
-
* matching control in an Angular FormGroup.
|
|
787
|
-
*
|
|
788
|
-
* // { Pointer } dataPointer - JSON Pointer (string or array) to a data object
|
|
789
|
-
* // { FormGroup } formGroup - Angular FormGroup to get value from
|
|
790
|
-
* // { boolean = false } controlMustExist - Only return if control exists?
|
|
791
|
-
* // { Pointer } - JSON Pointer (string) to the formGroup object
|
|
792
|
-
*/
|
|
793
|
-
static toControlPointer(dataPointer, formGroup, controlMustExist = false) {
|
|
794
|
-
const dataPointerArray = this.parse(dataPointer);
|
|
795
|
-
const controlPointerArray = [];
|
|
796
|
-
let subGroup = formGroup;
|
|
797
|
-
if (dataPointerArray !== null) {
|
|
798
|
-
for (const key of dataPointerArray) {
|
|
799
|
-
if (hasOwn(subGroup, 'controls')) {
|
|
800
|
-
controlPointerArray.push('controls');
|
|
801
|
-
subGroup = subGroup.controls;
|
|
802
|
-
}
|
|
803
|
-
if (isArray(subGroup) && (key === '-')) {
|
|
804
|
-
controlPointerArray.push((subGroup.length - 1).toString());
|
|
805
|
-
subGroup = subGroup[subGroup.length - 1];
|
|
806
|
-
}
|
|
807
|
-
else if (hasOwn(subGroup, key)) {
|
|
808
|
-
controlPointerArray.push(key);
|
|
809
|
-
subGroup = subGroup[key];
|
|
810
|
-
}
|
|
811
|
-
else if (controlMustExist) {
|
|
812
|
-
console.error(`toControlPointer error: Unable to find "${key}" item in FormGroup.`);
|
|
813
|
-
console.error(dataPointer);
|
|
814
|
-
console.error(formGroup);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
else {
|
|
818
|
-
controlPointerArray.push(key);
|
|
819
|
-
subGroup = { controls: {} };
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
return this.compile(controlPointerArray);
|
|
823
|
-
}
|
|
824
|
-
console.error(`toControlPointer error: Invalid JSON Pointer: ${dataPointer}`);
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* 'toSchemaPointer' function
|
|
828
|
-
*
|
|
829
|
-
* Accepts a JSON Pointer to a value inside a data object and a JSON schema
|
|
830
|
-
* for that object.
|
|
831
|
-
*
|
|
832
|
-
* Returns a Pointer to the sub-schema for the value inside the object's schema.
|
|
833
|
-
*
|
|
834
|
-
* // { Pointer } dataPointer - JSON Pointer (string or array) to an object
|
|
835
|
-
* // schema - JSON schema for the object
|
|
836
|
-
* // { Pointer } - JSON Pointer (string) to the object's schema
|
|
837
|
-
*/
|
|
838
|
-
static toSchemaPointer(dataPointer, schema) {
|
|
839
|
-
if (this.isJsonPointer(dataPointer) && typeof schema === 'object') {
|
|
840
|
-
const pointerArray = this.parse(dataPointer);
|
|
841
|
-
if (!pointerArray.length) {
|
|
842
|
-
return '';
|
|
843
|
-
}
|
|
844
|
-
const firstKey = pointerArray.shift();
|
|
845
|
-
if (schema.type === 'object' || schema.properties || schema.additionalProperties) {
|
|
846
|
-
if ((schema.properties || {})[firstKey]) {
|
|
847
|
-
return `/properties/${this.escape(firstKey)}` +
|
|
848
|
-
this.toSchemaPointer(pointerArray, schema.properties[firstKey]);
|
|
849
|
-
}
|
|
850
|
-
else if (schema.additionalProperties) {
|
|
851
|
-
return '/additionalProperties' +
|
|
852
|
-
this.toSchemaPointer(pointerArray, schema.additionalProperties);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
if ((schema.type === 'array' || schema.items) &&
|
|
856
|
-
(isNumber(firstKey) || firstKey === '-' || firstKey === '')) {
|
|
857
|
-
const arrayItem = firstKey === '-' || firstKey === '' ? 0 : +firstKey;
|
|
858
|
-
if (isArray(schema.items)) {
|
|
859
|
-
if (arrayItem < schema.items.length) {
|
|
860
|
-
return '/items/' + arrayItem +
|
|
861
|
-
this.toSchemaPointer(pointerArray, schema.items[arrayItem]);
|
|
862
|
-
}
|
|
863
|
-
else if (schema.additionalItems) {
|
|
864
|
-
return '/additionalItems' +
|
|
865
|
-
this.toSchemaPointer(pointerArray, schema.additionalItems);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
else if (isObject(schema.items)) {
|
|
869
|
-
return '/items' + this.toSchemaPointer(pointerArray, schema.items);
|
|
870
|
-
}
|
|
871
|
-
else if (isObject(schema.additionalItems)) {
|
|
872
|
-
return '/additionalItems' +
|
|
873
|
-
this.toSchemaPointer(pointerArray, schema.additionalItems);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
console.error(`toSchemaPointer error: Data pointer ${dataPointer} ` +
|
|
877
|
-
`not compatible with schema ${schema}`);
|
|
878
|
-
return null;
|
|
879
|
-
}
|
|
880
|
-
if (!this.isJsonPointer(dataPointer)) {
|
|
881
|
-
console.error(`toSchemaPointer error: Invalid JSON Pointer: ${dataPointer}`);
|
|
882
|
-
}
|
|
883
|
-
if (typeof schema !== 'object') {
|
|
884
|
-
console.error(`toSchemaPointer error: Invalid JSON Schema: ${schema}`);
|
|
885
|
-
}
|
|
886
|
-
return null;
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* 'toDataPointer' function
|
|
890
|
-
*
|
|
891
|
-
* Accepts a JSON Pointer to a sub-schema inside a JSON schema and the schema.
|
|
892
|
-
*
|
|
893
|
-
* If possible, returns a generic Pointer to the corresponding value inside
|
|
894
|
-
* the data object described by the JSON schema.
|
|
895
|
-
*
|
|
896
|
-
* Returns null if the sub-schema is in an ambiguous location (such as
|
|
897
|
-
* definitions or additionalProperties) where the corresponding value
|
|
898
|
-
* location cannot be determined.
|
|
899
|
-
*
|
|
900
|
-
* // { Pointer } schemaPointer - JSON Pointer (string or array) to a JSON schema
|
|
901
|
-
* // schema - the JSON schema
|
|
902
|
-
* // { boolean = false } errors - Show errors?
|
|
903
|
-
* // { Pointer } - JSON Pointer (string) to the value in the data object
|
|
904
|
-
*/
|
|
905
|
-
static toDataPointer(schemaPointer, schema, errors = false) {
|
|
906
|
-
if (this.isJsonPointer(schemaPointer) && typeof schema === 'object' &&
|
|
907
|
-
this.has(schema, schemaPointer)) {
|
|
908
|
-
const pointerArray = this.parse(schemaPointer);
|
|
909
|
-
if (!pointerArray.length) {
|
|
910
|
-
return '';
|
|
911
|
-
}
|
|
912
|
-
const firstKey = pointerArray.shift();
|
|
913
|
-
if (firstKey === 'properties' ||
|
|
914
|
-
(firstKey === 'items' && isArray(schema.items))) {
|
|
915
|
-
const secondKey = pointerArray.shift();
|
|
916
|
-
const pointerSuffix = this.toDataPointer(pointerArray, schema[firstKey][secondKey]);
|
|
917
|
-
return pointerSuffix === null ? null : '/' + secondKey + pointerSuffix;
|
|
918
|
-
}
|
|
919
|
-
else if (firstKey === 'additionalItems' ||
|
|
920
|
-
(firstKey === 'items' && isObject(schema.items))) {
|
|
921
|
-
const pointerSuffix = this.toDataPointer(pointerArray, schema[firstKey]);
|
|
922
|
-
return pointerSuffix === null ? null : '/-' + pointerSuffix;
|
|
923
|
-
}
|
|
924
|
-
else if (['allOf', 'anyOf', 'oneOf'].includes(firstKey)) {
|
|
925
|
-
const secondKey = pointerArray.shift();
|
|
926
|
-
return this.toDataPointer(pointerArray, schema[firstKey][secondKey]);
|
|
927
|
-
}
|
|
928
|
-
else if (firstKey === 'not') {
|
|
929
|
-
return this.toDataPointer(pointerArray, schema[firstKey]);
|
|
930
|
-
}
|
|
931
|
-
else if (['contains', 'definitions', 'dependencies', 'additionalItems',
|
|
932
|
-
'additionalProperties', 'patternProperties', 'propertyNames'].includes(firstKey)) {
|
|
933
|
-
if (errors) {
|
|
934
|
-
console.error(`toDataPointer error: Ambiguous location`);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
return '';
|
|
938
|
-
}
|
|
939
|
-
if (errors) {
|
|
940
|
-
if (!this.isJsonPointer(schemaPointer)) {
|
|
941
|
-
console.error(`toDataPointer error: Invalid JSON Pointer: ${schemaPointer}`);
|
|
942
|
-
}
|
|
943
|
-
if (typeof schema !== 'object') {
|
|
944
|
-
console.error(`toDataPointer error: Invalid JSON Schema: ${schema}`);
|
|
945
|
-
}
|
|
946
|
-
if (typeof schema !== 'object') {
|
|
947
|
-
console.error(`toDataPointer error: Pointer ${schemaPointer} invalid for Schema: ${schema}`);
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
return null;
|
|
951
|
-
}
|
|
952
|
-
/**
|
|
953
|
-
* 'parseObjectPath' function
|
|
954
|
-
*
|
|
955
|
-
* Parses a JavaScript object path into an array of keys, which
|
|
956
|
-
* can then be passed to compile() to convert into a string JSON Pointer.
|
|
957
|
-
*
|
|
958
|
-
* Based on mike-marcacci's excellent objectpath parse function:
|
|
959
|
-
* https://github.com/mike-marcacci/objectpath
|
|
960
|
-
*
|
|
961
|
-
* // { Pointer } path - The object path to parse
|
|
962
|
-
* // { string[] } - The resulting array of keys
|
|
963
|
-
*/
|
|
964
|
-
static parseObjectPath(path) {
|
|
965
|
-
if (isArray(path)) {
|
|
966
|
-
return path;
|
|
967
|
-
}
|
|
968
|
-
if (this.isJsonPointer(path)) {
|
|
969
|
-
return this.parse(path);
|
|
970
|
-
}
|
|
971
|
-
if (typeof path === 'string') {
|
|
972
|
-
let index = 0;
|
|
973
|
-
const parts = [];
|
|
974
|
-
while (index < path.length) {
|
|
975
|
-
const nextDot = path.indexOf('.', index);
|
|
976
|
-
const nextOB = path.indexOf('[', index); // next open bracket
|
|
977
|
-
if (nextDot === -1 && nextOB === -1) { // last item
|
|
978
|
-
parts.push(path.slice(index));
|
|
979
|
-
index = path.length;
|
|
980
|
-
}
|
|
981
|
-
else if (nextDot !== -1 && (nextDot < nextOB || nextOB === -1)) { // dot notation
|
|
982
|
-
parts.push(path.slice(index, nextDot));
|
|
983
|
-
index = nextDot + 1;
|
|
984
|
-
}
|
|
985
|
-
else { // bracket notation
|
|
986
|
-
if (nextOB > index) {
|
|
987
|
-
parts.push(path.slice(index, nextOB));
|
|
988
|
-
index = nextOB;
|
|
989
|
-
}
|
|
990
|
-
const quote = path.charAt(nextOB + 1);
|
|
991
|
-
if (quote === '"' || quote === '\'') { // enclosing quotes
|
|
992
|
-
let nextCB = path.indexOf(quote + ']', nextOB); // next close bracket
|
|
993
|
-
while (nextCB !== -1 && path.charAt(nextCB - 1) === '\\') {
|
|
994
|
-
nextCB = path.indexOf(quote + ']', nextCB + 2);
|
|
995
|
-
}
|
|
996
|
-
if (nextCB === -1) {
|
|
997
|
-
nextCB = path.length;
|
|
998
|
-
}
|
|
999
|
-
parts.push(path.slice(index + 2, nextCB)
|
|
1000
|
-
.replace(new RegExp('\\' + quote, 'g'), quote));
|
|
1001
|
-
index = nextCB + 2;
|
|
1002
|
-
}
|
|
1003
|
-
else { // no enclosing quotes
|
|
1004
|
-
let nextCB = path.indexOf(']', nextOB); // next close bracket
|
|
1005
|
-
if (nextCB === -1) {
|
|
1006
|
-
nextCB = path.length;
|
|
1007
|
-
}
|
|
1008
|
-
parts.push(path.slice(index + 1, nextCB));
|
|
1009
|
-
index = nextCB + 1;
|
|
1010
|
-
}
|
|
1011
|
-
if (path.charAt(index) === '.') {
|
|
1012
|
-
index++;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
return parts;
|
|
1017
|
-
}
|
|
1018
|
-
console.error('parseObjectPath error: Input object path must be a string.');
|
|
1019
|
-
}
|
|
1020
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1021
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1022
|
-
}
|
|
1023
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1024
|
-
type: Injectable
|
|
1025
|
-
}] });
|
|
1
|
+
import { cleanValueOfQuotes, copy, getExpressionType, getKeyAndValueByExpressionType, hasOwn, isEqual, isNotEqual, isNotExpression } from './utility.functions';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import { isArray, isDefined, isEmpty, isMap, isNumber, isObject, isString } from './validator.functions';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export class JsonPointer {
|
|
6
|
+
/**
|
|
7
|
+
* 'get' function
|
|
8
|
+
*
|
|
9
|
+
* Uses a JSON Pointer to retrieve a value from an object.
|
|
10
|
+
*
|
|
11
|
+
* // { object } object - Object to get value from
|
|
12
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
13
|
+
* // { number = 0 } startSlice - Zero-based index of first Pointer key to use
|
|
14
|
+
* // { number } endSlice - Zero-based index of last Pointer key to use
|
|
15
|
+
* // { boolean = false } getBoolean - Return only true or false?
|
|
16
|
+
* // { boolean = false } errors - Show error if not found?
|
|
17
|
+
* // { object } - Located value (or true or false if getBoolean = true)
|
|
18
|
+
*/
|
|
19
|
+
static get(object, pointer, startSlice = 0, endSlice = null, getBoolean = false, errors = false) {
|
|
20
|
+
if (object === null) {
|
|
21
|
+
return getBoolean ? false : undefined;
|
|
22
|
+
}
|
|
23
|
+
let keyArray = this.parse(pointer, errors);
|
|
24
|
+
if (typeof object === 'object' && keyArray !== null) {
|
|
25
|
+
let subObject = object;
|
|
26
|
+
if (startSlice >= keyArray.length || endSlice <= -keyArray.length) {
|
|
27
|
+
return object;
|
|
28
|
+
}
|
|
29
|
+
if (startSlice <= -keyArray.length) {
|
|
30
|
+
startSlice = 0;
|
|
31
|
+
}
|
|
32
|
+
if (!isDefined(endSlice) || endSlice >= keyArray.length) {
|
|
33
|
+
endSlice = keyArray.length;
|
|
34
|
+
}
|
|
35
|
+
keyArray = keyArray.slice(startSlice, endSlice);
|
|
36
|
+
for (let key of keyArray) {
|
|
37
|
+
if (key === '-' && isArray(subObject) && subObject.length) {
|
|
38
|
+
key = subObject.length - 1;
|
|
39
|
+
}
|
|
40
|
+
if (isMap(subObject) && subObject.has(key)) {
|
|
41
|
+
subObject = subObject.get(key);
|
|
42
|
+
}
|
|
43
|
+
else if (typeof subObject === 'object' && subObject !== null &&
|
|
44
|
+
hasOwn(subObject, key)) {
|
|
45
|
+
subObject = subObject[key];
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const evaluatedExpression = JsonPointer.evaluateExpression(subObject, key);
|
|
49
|
+
if (evaluatedExpression.passed) {
|
|
50
|
+
subObject = evaluatedExpression.key ? subObject[evaluatedExpression.key] : subObject;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.logErrors(errors, key, pointer, object);
|
|
54
|
+
return getBoolean ? false : undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return getBoolean ? true : subObject;
|
|
59
|
+
}
|
|
60
|
+
if (errors && keyArray === null) {
|
|
61
|
+
console.error(`get error: Invalid JSON Pointer: ${pointer}`);
|
|
62
|
+
}
|
|
63
|
+
if (errors && typeof object !== 'object') {
|
|
64
|
+
console.error('get error: Invalid object:');
|
|
65
|
+
console.error(object);
|
|
66
|
+
}
|
|
67
|
+
return getBoolean ? false : undefined;
|
|
68
|
+
}
|
|
69
|
+
static logErrors(errors, key, pointer, object) {
|
|
70
|
+
if (errors) {
|
|
71
|
+
console.error(`get error: "${key}" key not found in object.`);
|
|
72
|
+
console.error(pointer);
|
|
73
|
+
console.error(object);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Evaluates conditional expression in form of `model.<property>==<value>` or
|
|
78
|
+
* `model.<property>!=<value>` where the first one means that the value must match to be
|
|
79
|
+
* shown in a form, while the former shows the property only when the property value is not
|
|
80
|
+
* set, or does not equal the given value.
|
|
81
|
+
*
|
|
82
|
+
* // { subObject } subObject - an object containing the data values of properties
|
|
83
|
+
* // { key } key - the key from the for loop in a form of `<property>==<value>`
|
|
84
|
+
*
|
|
85
|
+
* Returns the object with two properties. The property passed informs whether
|
|
86
|
+
* the expression evaluated successfully and the property key returns either the same
|
|
87
|
+
* key if it is not contained inside the subObject or the key of the property if it is contained.
|
|
88
|
+
*/
|
|
89
|
+
static evaluateExpression(subObject, key) {
|
|
90
|
+
const defaultResult = { passed: false, key: key };
|
|
91
|
+
const keysAndExpression = this.parseKeysAndExpression(key, subObject);
|
|
92
|
+
if (!keysAndExpression) {
|
|
93
|
+
return defaultResult;
|
|
94
|
+
}
|
|
95
|
+
const ownCheckResult = this.doOwnCheckResult(subObject, keysAndExpression);
|
|
96
|
+
if (ownCheckResult) {
|
|
97
|
+
return ownCheckResult;
|
|
98
|
+
}
|
|
99
|
+
const cleanedValue = cleanValueOfQuotes(keysAndExpression.keyAndValue[1]);
|
|
100
|
+
const evaluatedResult = this.performExpressionOnValue(keysAndExpression, cleanedValue, subObject);
|
|
101
|
+
if (evaluatedResult) {
|
|
102
|
+
return evaluatedResult;
|
|
103
|
+
}
|
|
104
|
+
return defaultResult;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Performs the actual evaluation on the given expression with given values and keys.
|
|
108
|
+
* // { cleanedValue } cleanedValue - the given valued cleaned of quotes if it had any
|
|
109
|
+
* // { subObject } subObject - the object with properties values
|
|
110
|
+
* // { keysAndExpression } keysAndExpression - an object holding the expressions with
|
|
111
|
+
*/
|
|
112
|
+
static performExpressionOnValue(keysAndExpression, cleanedValue, subObject) {
|
|
113
|
+
const propertyByKey = subObject[keysAndExpression.keyAndValue[0]];
|
|
114
|
+
if (this.doComparisonByExpressionType(keysAndExpression.expressionType, propertyByKey, cleanedValue)) {
|
|
115
|
+
return { passed: true, key: keysAndExpression.keyAndValue[0] };
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
static doComparisonByExpressionType(expressionType, propertyByKey, cleanedValue) {
|
|
120
|
+
if (isEqual(expressionType)) {
|
|
121
|
+
return propertyByKey === cleanedValue;
|
|
122
|
+
}
|
|
123
|
+
if (isNotEqual(expressionType)) {
|
|
124
|
+
return propertyByKey !== cleanedValue;
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Does the checks when the parsed key is actually no a property inside subObject.
|
|
130
|
+
* That would mean that the equal comparison makes no sense and thus the negative result
|
|
131
|
+
* is returned, and the not equal comparison is not necessary because it doesn't equal
|
|
132
|
+
* obviously. Returns null when the given key is a real property inside the subObject.
|
|
133
|
+
* // { subObject } subObject - the object with properties values
|
|
134
|
+
* // { keysAndExpression } keysAndExpression - an object holding the expressions with
|
|
135
|
+
* the associated keys.
|
|
136
|
+
*/
|
|
137
|
+
static doOwnCheckResult(subObject, keysAndExpression) {
|
|
138
|
+
let ownCheckResult = null;
|
|
139
|
+
if (!hasOwn(subObject, keysAndExpression.keyAndValue[0])) {
|
|
140
|
+
if (isEqual(keysAndExpression.expressionType)) {
|
|
141
|
+
ownCheckResult = { passed: false, key: null };
|
|
142
|
+
}
|
|
143
|
+
if (isNotEqual(keysAndExpression.expressionType)) {
|
|
144
|
+
ownCheckResult = { passed: true, key: null };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return ownCheckResult;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Does the basic checks and tries to parse an expression and a pair
|
|
151
|
+
* of key and value.
|
|
152
|
+
* // { key } key - the original for loop created value containing key and value in one string
|
|
153
|
+
* // { subObject } subObject - the object with properties values
|
|
154
|
+
*/
|
|
155
|
+
static parseKeysAndExpression(key, subObject) {
|
|
156
|
+
if (this.keyOrSubObjEmpty(key, subObject)) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const expressionType = getExpressionType(key.toString());
|
|
160
|
+
if (isNotExpression(expressionType)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const keyAndValue = getKeyAndValueByExpressionType(expressionType, key);
|
|
164
|
+
if (!keyAndValue || !keyAndValue[0] || !keyAndValue[1]) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return { expressionType: expressionType, keyAndValue: keyAndValue };
|
|
168
|
+
}
|
|
169
|
+
static keyOrSubObjEmpty(key, subObject) {
|
|
170
|
+
return !key || !subObject;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 'getCopy' function
|
|
174
|
+
*
|
|
175
|
+
* Uses a JSON Pointer to deeply clone a value from an object.
|
|
176
|
+
*
|
|
177
|
+
* // { object } object - Object to get value from
|
|
178
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
179
|
+
* // { number = 0 } startSlice - Zero-based index of first Pointer key to use
|
|
180
|
+
* // { number } endSlice - Zero-based index of last Pointer key to use
|
|
181
|
+
* // { boolean = false } getBoolean - Return only true or false?
|
|
182
|
+
* // { boolean = false } errors - Show error if not found?
|
|
183
|
+
* // { object } - Located value (or true or false if getBoolean = true)
|
|
184
|
+
*/
|
|
185
|
+
static getCopy(object, pointer, startSlice = 0, endSlice = null, getBoolean = false, errors = false) {
|
|
186
|
+
const objectToCopy = this.get(object, pointer, startSlice, endSlice, getBoolean, errors);
|
|
187
|
+
return this.forEachDeepCopy(objectToCopy);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 'getFirst' function
|
|
191
|
+
*
|
|
192
|
+
* Takes an array of JSON Pointers and objects,
|
|
193
|
+
* checks each object for a value specified by the pointer,
|
|
194
|
+
* and returns the first value found.
|
|
195
|
+
*
|
|
196
|
+
* // { [object, pointer][] } items - Array of objects and pointers to check
|
|
197
|
+
* // { any = null } defaultValue - Value to return if nothing found
|
|
198
|
+
* // { boolean = false } getCopy - Return a copy instead?
|
|
199
|
+
* // - First value found
|
|
200
|
+
*/
|
|
201
|
+
static getFirst(items, defaultValue = null, getCopy = false) {
|
|
202
|
+
if (isEmpty(items)) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (isArray(items)) {
|
|
206
|
+
for (const item of items) {
|
|
207
|
+
if (isEmpty(item)) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (isArray(item) && item.length >= 2) {
|
|
211
|
+
if (isEmpty(item[0]) || isEmpty(item[1])) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const value = getCopy ?
|
|
215
|
+
this.getCopy(item[0], item[1]) :
|
|
216
|
+
this.get(item[0], item[1]);
|
|
217
|
+
if (value) {
|
|
218
|
+
return value;
|
|
219
|
+
}
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
console.error('getFirst error: Input not in correct format.\n' +
|
|
223
|
+
'Should be: [ [ object1, pointer1 ], [ object 2, pointer2 ], etc... ]');
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
return defaultValue;
|
|
227
|
+
}
|
|
228
|
+
if (isMap(items)) {
|
|
229
|
+
for (const [object, pointer] of items) {
|
|
230
|
+
if (object === null || !this.isJsonPointer(pointer)) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const value = getCopy ?
|
|
234
|
+
this.getCopy(object, pointer) :
|
|
235
|
+
this.get(object, pointer);
|
|
236
|
+
if (value) {
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return defaultValue;
|
|
241
|
+
}
|
|
242
|
+
console.error('getFirst error: Input not in correct format.\n' +
|
|
243
|
+
'Should be: [ [ object1, pointer1 ], [ object 2, pointer2 ], etc... ]');
|
|
244
|
+
return defaultValue;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 'getFirstCopy' function
|
|
248
|
+
*
|
|
249
|
+
* Similar to getFirst, but always returns a copy.
|
|
250
|
+
*
|
|
251
|
+
* // { [object, pointer][] } items - Array of objects and pointers to check
|
|
252
|
+
* // { any = null } defaultValue - Value to return if nothing found
|
|
253
|
+
* // - Copy of first value found
|
|
254
|
+
*/
|
|
255
|
+
static getFirstCopy(items, defaultValue = null) {
|
|
256
|
+
const firstCopy = this.getFirst(items, defaultValue, true);
|
|
257
|
+
return firstCopy;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* 'set' function
|
|
261
|
+
*
|
|
262
|
+
* Uses a JSON Pointer to set a value on an object.
|
|
263
|
+
* Also creates any missing sub objects or arrays to contain that value.
|
|
264
|
+
*
|
|
265
|
+
* If the optional fourth parameter is TRUE and the inner-most container
|
|
266
|
+
* is an array, the function will insert the value as a new item at the
|
|
267
|
+
* specified location in the array, rather than overwriting the existing
|
|
268
|
+
* value (if any) at that location.
|
|
269
|
+
*
|
|
270
|
+
* So set([1, 2, 3], '/1', 4) => [1, 4, 3]
|
|
271
|
+
* and
|
|
272
|
+
* So set([1, 2, 3], '/1', 4, true) => [1, 4, 2, 3]
|
|
273
|
+
*
|
|
274
|
+
* // { object } object - The object to set value in
|
|
275
|
+
* // { Pointer } pointer - The JSON Pointer (string or array)
|
|
276
|
+
* // value - The new value to set
|
|
277
|
+
* // { boolean } insert - insert value?
|
|
278
|
+
* // { object } - The original object, modified with the set value
|
|
279
|
+
*/
|
|
280
|
+
static set(object, pointer, value, insert = false) {
|
|
281
|
+
const keyArray = this.parse(pointer);
|
|
282
|
+
if (keyArray !== null && keyArray.length) {
|
|
283
|
+
let subObject = object;
|
|
284
|
+
for (let i = 0; i < keyArray.length - 1; ++i) {
|
|
285
|
+
let key = keyArray[i];
|
|
286
|
+
if (key === '-' && isArray(subObject)) {
|
|
287
|
+
key = subObject.length;
|
|
288
|
+
}
|
|
289
|
+
if (isMap(subObject) && subObject.has(key)) {
|
|
290
|
+
subObject = subObject.get(key);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
if (!hasOwn(subObject, key)) {
|
|
294
|
+
subObject[key] = (keyArray[i + 1].match(/^(\d+|-)$/)) ? [] : {};
|
|
295
|
+
}
|
|
296
|
+
subObject = subObject[key];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const lastKey = keyArray[keyArray.length - 1];
|
|
300
|
+
if (isArray(subObject) && lastKey === '-') {
|
|
301
|
+
subObject.push(value);
|
|
302
|
+
}
|
|
303
|
+
else if (insert && isArray(subObject) && !isNaN(+lastKey)) {
|
|
304
|
+
subObject.splice(lastKey, 0, value);
|
|
305
|
+
}
|
|
306
|
+
else if (isMap(subObject)) {
|
|
307
|
+
subObject.set(lastKey, value);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
subObject[lastKey] = value;
|
|
311
|
+
}
|
|
312
|
+
return object;
|
|
313
|
+
}
|
|
314
|
+
console.error(`set error: Invalid JSON Pointer: ${pointer}`);
|
|
315
|
+
return object;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* 'setCopy' function
|
|
319
|
+
*
|
|
320
|
+
* Copies an object and uses a JSON Pointer to set a value on the copy.
|
|
321
|
+
* Also creates any missing sub objects or arrays to contain that value.
|
|
322
|
+
*
|
|
323
|
+
* If the optional fourth parameter is TRUE and the inner-most container
|
|
324
|
+
* is an array, the function will insert the value as a new item at the
|
|
325
|
+
* specified location in the array, rather than overwriting the existing value.
|
|
326
|
+
*
|
|
327
|
+
* // { object } object - The object to copy and set value in
|
|
328
|
+
* // { Pointer } pointer - The JSON Pointer (string or array)
|
|
329
|
+
* // value - The value to set
|
|
330
|
+
* // { boolean } insert - insert value?
|
|
331
|
+
* // { object } - The new object with the set value
|
|
332
|
+
*/
|
|
333
|
+
static setCopy(object, pointer, value, insert = false) {
|
|
334
|
+
const keyArray = this.parse(pointer);
|
|
335
|
+
if (keyArray !== null) {
|
|
336
|
+
const newObject = copy(object);
|
|
337
|
+
let subObject = newObject;
|
|
338
|
+
for (let i = 0; i < keyArray.length - 1; ++i) {
|
|
339
|
+
let key = keyArray[i];
|
|
340
|
+
if (key === '-' && isArray(subObject)) {
|
|
341
|
+
key = subObject.length;
|
|
342
|
+
}
|
|
343
|
+
if (isMap(subObject) && subObject.has(key)) {
|
|
344
|
+
subObject.set(key, copy(subObject.get(key)));
|
|
345
|
+
subObject = subObject.get(key);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
if (!hasOwn(subObject, key)) {
|
|
349
|
+
subObject[key] = (keyArray[i + 1].match(/^(\d+|-)$/)) ? [] : {};
|
|
350
|
+
}
|
|
351
|
+
subObject[key] = copy(subObject[key]);
|
|
352
|
+
subObject = subObject[key];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const lastKey = keyArray[keyArray.length - 1];
|
|
356
|
+
if (isArray(subObject) && lastKey === '-') {
|
|
357
|
+
subObject.push(value);
|
|
358
|
+
}
|
|
359
|
+
else if (insert && isArray(subObject) && !isNaN(+lastKey)) {
|
|
360
|
+
subObject.splice(lastKey, 0, value);
|
|
361
|
+
}
|
|
362
|
+
else if (isMap(subObject)) {
|
|
363
|
+
subObject.set(lastKey, value);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
subObject[lastKey] = value;
|
|
367
|
+
}
|
|
368
|
+
return newObject;
|
|
369
|
+
}
|
|
370
|
+
console.error(`setCopy error: Invalid JSON Pointer: ${pointer}`);
|
|
371
|
+
return object;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 'insert' function
|
|
375
|
+
*
|
|
376
|
+
* Calls 'set' with insert = TRUE
|
|
377
|
+
*
|
|
378
|
+
* // { object } object - object to insert value in
|
|
379
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
380
|
+
* // value - value to insert
|
|
381
|
+
* // { object }
|
|
382
|
+
*/
|
|
383
|
+
static insert(object, pointer, value) {
|
|
384
|
+
const updatedObject = this.set(object, pointer, value, true);
|
|
385
|
+
return updatedObject;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* 'insertCopy' function
|
|
389
|
+
*
|
|
390
|
+
* Calls 'setCopy' with insert = TRUE
|
|
391
|
+
*
|
|
392
|
+
* // { object } object - object to insert value in
|
|
393
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
394
|
+
* // value - value to insert
|
|
395
|
+
* // { object }
|
|
396
|
+
*/
|
|
397
|
+
static insertCopy(object, pointer, value) {
|
|
398
|
+
const updatedObject = this.setCopy(object, pointer, value, true);
|
|
399
|
+
return updatedObject;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* 'remove' function
|
|
403
|
+
*
|
|
404
|
+
* Uses a JSON Pointer to remove a key and its attribute from an object
|
|
405
|
+
*
|
|
406
|
+
* // { object } object - object to delete attribute from
|
|
407
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
408
|
+
* // { object }
|
|
409
|
+
*/
|
|
410
|
+
static remove(object, pointer) {
|
|
411
|
+
const keyArray = this.parse(pointer);
|
|
412
|
+
if (keyArray !== null && keyArray.length) {
|
|
413
|
+
let lastKey = keyArray.pop();
|
|
414
|
+
const parentObject = this.get(object, keyArray);
|
|
415
|
+
if (isArray(parentObject)) {
|
|
416
|
+
if (lastKey === '-') {
|
|
417
|
+
lastKey = parentObject.length - 1;
|
|
418
|
+
}
|
|
419
|
+
parentObject.splice(lastKey, 1);
|
|
420
|
+
}
|
|
421
|
+
else if (isObject(parentObject)) {
|
|
422
|
+
delete parentObject[lastKey];
|
|
423
|
+
}
|
|
424
|
+
return object;
|
|
425
|
+
}
|
|
426
|
+
console.error(`remove error: Invalid JSON Pointer: ${pointer}`);
|
|
427
|
+
return object;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* 'has' function
|
|
431
|
+
*
|
|
432
|
+
* Tests if an object has a value at the location specified by a JSON Pointer
|
|
433
|
+
*
|
|
434
|
+
* // { object } object - object to chek for value
|
|
435
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
436
|
+
* // { boolean }
|
|
437
|
+
*/
|
|
438
|
+
static has(object, pointer) {
|
|
439
|
+
const hasValue = this.get(object, pointer, 0, null, true);
|
|
440
|
+
return hasValue;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* 'dict' function
|
|
444
|
+
*
|
|
445
|
+
* Returns a (pointer -> value) dictionary for an object
|
|
446
|
+
*
|
|
447
|
+
* // { object } object - The object to create a dictionary from
|
|
448
|
+
* // { object } - The resulting dictionary object
|
|
449
|
+
*/
|
|
450
|
+
static dict(object) {
|
|
451
|
+
const results = {};
|
|
452
|
+
this.forEachDeep(object, (value, pointer) => {
|
|
453
|
+
if (typeof value !== 'object') {
|
|
454
|
+
results[pointer] = value;
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
return results;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* 'forEachDeep' function
|
|
461
|
+
*
|
|
462
|
+
* Iterates over own enumerable properties of an object or items in an array
|
|
463
|
+
* and invokes an iteratee function for each key/value or index/value pair.
|
|
464
|
+
* By default, iterates over items within objects and arrays after calling
|
|
465
|
+
* the iteratee function on the containing object or array itself.
|
|
466
|
+
*
|
|
467
|
+
* The iteratee is invoked with three arguments: (value, pointer, rootObject),
|
|
468
|
+
* where pointer is a JSON pointer indicating the location of the current
|
|
469
|
+
* value within the root object, and rootObject is the root object initially
|
|
470
|
+
* submitted to th function.
|
|
471
|
+
*
|
|
472
|
+
* If a third optional parameter 'bottomUp' is set to TRUE, the iterator
|
|
473
|
+
* function will be called on sub-objects and arrays after being
|
|
474
|
+
* called on their contents, rather than before, which is the default.
|
|
475
|
+
*
|
|
476
|
+
* This function can also optionally be called directly on a sub-object by
|
|
477
|
+
* including optional 4th and 5th parameterss to specify the initial
|
|
478
|
+
* root object and pointer.
|
|
479
|
+
*
|
|
480
|
+
* // { object } object - the initial object or array
|
|
481
|
+
* // { (v: any, p?: string, o?: any) => any } function - iteratee function
|
|
482
|
+
* // { boolean = false } bottomUp - optional, set to TRUE to reverse direction
|
|
483
|
+
* // { object = object } rootObject - optional, root object or array
|
|
484
|
+
* // { string = '' } pointer - optional, JSON Pointer to object within rootObject
|
|
485
|
+
* // { object } - The modified object
|
|
486
|
+
*/
|
|
487
|
+
static forEachDeep(object, fn = (v) => v, bottomUp = false, pointer = '', rootObject = object) {
|
|
488
|
+
if (typeof fn !== 'function') {
|
|
489
|
+
console.error(`forEachDeep error: Iterator is not a function:`, fn);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (!bottomUp) {
|
|
493
|
+
fn(object, pointer, rootObject);
|
|
494
|
+
}
|
|
495
|
+
if (isObject(object) || isArray(object)) {
|
|
496
|
+
for (const key of Object.keys(object)) {
|
|
497
|
+
const newPointer = pointer + '/' + this.escape(key);
|
|
498
|
+
this.forEachDeep(object[key], fn, bottomUp, newPointer, rootObject);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (bottomUp) {
|
|
502
|
+
fn(object, pointer, rootObject);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* 'forEachDeepCopy' function
|
|
507
|
+
*
|
|
508
|
+
* Similar to forEachDeep, but returns a copy of the original object, with
|
|
509
|
+
* the same keys and indexes, but with values replaced with the result of
|
|
510
|
+
* the iteratee function.
|
|
511
|
+
*
|
|
512
|
+
* // { object } object - the initial object or array
|
|
513
|
+
* // { (v: any, k?: string, o?: any, p?: any) => any } function - iteratee function
|
|
514
|
+
* // { boolean = false } bottomUp - optional, set to TRUE to reverse direction
|
|
515
|
+
* // { object = object } rootObject - optional, root object or array
|
|
516
|
+
* // { string = '' } pointer - optional, JSON Pointer to object within rootObject
|
|
517
|
+
* // { object } - The copied object
|
|
518
|
+
*/
|
|
519
|
+
static forEachDeepCopy(object, fn = (v) => v, bottomUp = false, pointer = '', rootObject = object) {
|
|
520
|
+
if (typeof fn !== 'function') {
|
|
521
|
+
console.error(`forEachDeepCopy error: Iterator is not a function:`, fn);
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
if (isObject(object) || isArray(object)) {
|
|
525
|
+
let newObject = isArray(object) ? [...object] : { ...object };
|
|
526
|
+
if (!bottomUp) {
|
|
527
|
+
newObject = fn(newObject, pointer, rootObject);
|
|
528
|
+
}
|
|
529
|
+
for (const key of Object.keys(newObject)) {
|
|
530
|
+
const newPointer = pointer + '/' + this.escape(key);
|
|
531
|
+
newObject[key] = this.forEachDeepCopy(newObject[key], fn, bottomUp, newPointer, rootObject);
|
|
532
|
+
}
|
|
533
|
+
if (bottomUp) {
|
|
534
|
+
newObject = fn(newObject, pointer, rootObject);
|
|
535
|
+
}
|
|
536
|
+
return newObject;
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
return fn(object, pointer, rootObject);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* 'escape' function
|
|
544
|
+
*
|
|
545
|
+
* Escapes a string reference key
|
|
546
|
+
*
|
|
547
|
+
* // { string } key - string key to escape
|
|
548
|
+
* // { string } - escaped key
|
|
549
|
+
*/
|
|
550
|
+
static escape(key) {
|
|
551
|
+
const escaped = key.toString().replace(/~/g, '~0').replace(/\//g, '~1');
|
|
552
|
+
return escaped;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* 'unescape' function
|
|
556
|
+
*
|
|
557
|
+
* Unescapes a string reference key
|
|
558
|
+
*
|
|
559
|
+
* // { string } key - string key to unescape
|
|
560
|
+
* // { string } - unescaped key
|
|
561
|
+
*/
|
|
562
|
+
static unescape(key) {
|
|
563
|
+
const unescaped = key.toString().replace(/~1/g, '/').replace(/~0/g, '~');
|
|
564
|
+
return unescaped;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* 'parse' function
|
|
568
|
+
*
|
|
569
|
+
* Converts a string JSON Pointer into a array of keys
|
|
570
|
+
* (if input is already an an array of keys, it is returned unchanged)
|
|
571
|
+
*
|
|
572
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
573
|
+
* // { boolean = false } errors - Show error if invalid pointer?
|
|
574
|
+
* // { string[] } - JSON Pointer array of keys
|
|
575
|
+
*/
|
|
576
|
+
static parse(pointer, errors = false) {
|
|
577
|
+
if (!this.isJsonPointer(pointer)) {
|
|
578
|
+
if (errors) {
|
|
579
|
+
console.error(`parse error: Invalid JSON Pointer: ${pointer}`);
|
|
580
|
+
}
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
if (isArray(pointer)) {
|
|
584
|
+
return pointer;
|
|
585
|
+
}
|
|
586
|
+
if (typeof pointer === 'string') {
|
|
587
|
+
if (pointer[0] === '#') {
|
|
588
|
+
pointer = pointer.slice(1);
|
|
589
|
+
}
|
|
590
|
+
if (pointer === '' || pointer === '/') {
|
|
591
|
+
return [];
|
|
592
|
+
}
|
|
593
|
+
return pointer.slice(1).split('/').map(this.unescape);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* 'compile' function
|
|
598
|
+
*
|
|
599
|
+
* Converts an array of keys into a JSON Pointer string
|
|
600
|
+
* (if input is already a string, it is normalized and returned)
|
|
601
|
+
*
|
|
602
|
+
* The optional second parameter is a default which will replace any empty keys.
|
|
603
|
+
*
|
|
604
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
605
|
+
* // { string | number = '' } defaultValue - Default value
|
|
606
|
+
* // { boolean = false } errors - Show error if invalid pointer?
|
|
607
|
+
* // { string } - JSON Pointer string
|
|
608
|
+
*/
|
|
609
|
+
static compile(pointer, defaultValue = '', errors = false) {
|
|
610
|
+
if (pointer === '#') {
|
|
611
|
+
return '';
|
|
612
|
+
}
|
|
613
|
+
if (!this.isJsonPointer(pointer)) {
|
|
614
|
+
if (errors) {
|
|
615
|
+
console.error(`compile error: Invalid JSON Pointer: ${pointer}`);
|
|
616
|
+
}
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
if (isArray(pointer)) {
|
|
620
|
+
if (pointer.length === 0) {
|
|
621
|
+
return '';
|
|
622
|
+
}
|
|
623
|
+
return '/' + pointer.map(key => key === '' ? defaultValue : this.escape(key)).join('/');
|
|
624
|
+
}
|
|
625
|
+
if (typeof pointer === 'string') {
|
|
626
|
+
if (pointer[0] === '#') {
|
|
627
|
+
pointer = pointer.slice(1);
|
|
628
|
+
}
|
|
629
|
+
return pointer;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 'toKey' function
|
|
634
|
+
*
|
|
635
|
+
* Extracts name of the final key from a JSON Pointer.
|
|
636
|
+
*
|
|
637
|
+
* // { Pointer } pointer - JSON Pointer (string or array)
|
|
638
|
+
* // { boolean = false } errors - Show error if invalid pointer?
|
|
639
|
+
* // { string } - the extracted key
|
|
640
|
+
*/
|
|
641
|
+
static toKey(pointer, errors = false) {
|
|
642
|
+
const keyArray = this.parse(pointer, errors);
|
|
643
|
+
if (keyArray === null) {
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
if (!keyArray.length) {
|
|
647
|
+
return '';
|
|
648
|
+
}
|
|
649
|
+
return keyArray[keyArray.length - 1];
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* 'isJsonPointer' function
|
|
653
|
+
*
|
|
654
|
+
* Checks a string or array value to determine if it is a valid JSON Pointer.
|
|
655
|
+
* Returns true if a string is empty, or starts with '/' or '#/'.
|
|
656
|
+
* Returns true if an array contains only string values.
|
|
657
|
+
*
|
|
658
|
+
* // value - value to check
|
|
659
|
+
* // { boolean } - true if value is a valid JSON Pointer, otherwise false
|
|
660
|
+
*/
|
|
661
|
+
static isJsonPointer(value) {
|
|
662
|
+
if (isArray(value)) {
|
|
663
|
+
return value.every(key => typeof key === 'string');
|
|
664
|
+
}
|
|
665
|
+
else if (isString(value)) {
|
|
666
|
+
if (value === '' || value === '#') {
|
|
667
|
+
return true;
|
|
668
|
+
}
|
|
669
|
+
if (value[0] === '/' || value.slice(0, 2) === '#/') {
|
|
670
|
+
return !/(~[^01]|~$)/g.test(value);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* 'isSubPointer' function
|
|
677
|
+
*
|
|
678
|
+
* Checks whether one JSON Pointer is a subset of another.
|
|
679
|
+
*
|
|
680
|
+
* // { Pointer } shortPointer - potential subset JSON Pointer
|
|
681
|
+
* // { Pointer } longPointer - potential superset JSON Pointer
|
|
682
|
+
* // { boolean = false } trueIfMatching - return true if pointers match?
|
|
683
|
+
* // { boolean = false } errors - Show error if invalid pointer?
|
|
684
|
+
* // { boolean } - true if shortPointer is a subset of longPointer, false if not
|
|
685
|
+
*/
|
|
686
|
+
static isSubPointer(shortPointer, longPointer, trueIfMatching = false, errors = false) {
|
|
687
|
+
if (!this.isJsonPointer(shortPointer) || !this.isJsonPointer(longPointer)) {
|
|
688
|
+
if (errors) {
|
|
689
|
+
let invalid = '';
|
|
690
|
+
if (!this.isJsonPointer(shortPointer)) {
|
|
691
|
+
invalid += ` 1: ${shortPointer}`;
|
|
692
|
+
}
|
|
693
|
+
if (!this.isJsonPointer(longPointer)) {
|
|
694
|
+
invalid += ` 2: ${longPointer}`;
|
|
695
|
+
}
|
|
696
|
+
console.error(`isSubPointer error: Invalid JSON Pointer ${invalid}`);
|
|
697
|
+
}
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
shortPointer = this.compile(shortPointer, '', errors);
|
|
701
|
+
longPointer = this.compile(longPointer, '', errors);
|
|
702
|
+
return shortPointer === longPointer ? trueIfMatching :
|
|
703
|
+
`${shortPointer}/` === longPointer.slice(0, shortPointer.length + 1);
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* 'toIndexedPointer' function
|
|
707
|
+
*
|
|
708
|
+
* Merges an array of numeric indexes and a generic pointer to create an
|
|
709
|
+
* indexed pointer for a specific item.
|
|
710
|
+
*
|
|
711
|
+
* For example, merging the generic pointer '/foo/-/bar/-/baz' and
|
|
712
|
+
* the array [4, 2] would result in the indexed pointer '/foo/4/bar/2/baz'
|
|
713
|
+
*
|
|
714
|
+
*
|
|
715
|
+
* // { Pointer } genericPointer - The generic pointer
|
|
716
|
+
* // { number[] } indexArray - The array of numeric indexes
|
|
717
|
+
* // { Map<string, number> } arrayMap - An optional array map
|
|
718
|
+
* // { string } - The merged pointer with indexes
|
|
719
|
+
*/
|
|
720
|
+
static toIndexedPointer(genericPointer, indexArray, arrayMap = null) {
|
|
721
|
+
if (this.isJsonPointer(genericPointer) && isArray(indexArray)) {
|
|
722
|
+
let indexedPointer = this.compile(genericPointer);
|
|
723
|
+
if (isMap(arrayMap)) {
|
|
724
|
+
let arrayIndex = 0;
|
|
725
|
+
return indexedPointer.replace(/\/\-(?=\/|$)/g, (key, stringIndex) => arrayMap.has(indexedPointer.slice(0, stringIndex)) ?
|
|
726
|
+
'/' + indexArray[arrayIndex++] : key);
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
for (const pointerIndex of indexArray) {
|
|
730
|
+
indexedPointer = indexedPointer.replace('/-', '/' + pointerIndex);
|
|
731
|
+
}
|
|
732
|
+
return indexedPointer;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (!this.isJsonPointer(genericPointer)) {
|
|
736
|
+
console.error(`toIndexedPointer error: Invalid JSON Pointer: ${genericPointer}`);
|
|
737
|
+
}
|
|
738
|
+
if (!isArray(indexArray)) {
|
|
739
|
+
console.error(`toIndexedPointer error: Invalid indexArray: ${indexArray}`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* 'toGenericPointer' function
|
|
744
|
+
*
|
|
745
|
+
* Compares an indexed pointer to an array map and removes list array
|
|
746
|
+
* indexes (but leaves tuple arrray indexes and all object keys, including
|
|
747
|
+
* numeric keys) to create a generic pointer.
|
|
748
|
+
*
|
|
749
|
+
* For example, using the indexed pointer '/foo/1/bar/2/baz/3' and
|
|
750
|
+
* the arrayMap [['/foo', 0], ['/foo/-/bar', 3], ['/foo/-/bar/-/baz', 0]]
|
|
751
|
+
* would result in the generic pointer '/foo/-/bar/2/baz/-'
|
|
752
|
+
* Using the indexed pointer '/foo/1/bar/4/baz/3' and the same arrayMap
|
|
753
|
+
* would result in the generic pointer '/foo/-/bar/-/baz/-'
|
|
754
|
+
* (the bar array has 3 tuple items, so index 2 is retained, but 4 is removed)
|
|
755
|
+
*
|
|
756
|
+
* The structure of the arrayMap is: [['path to array', number of tuple items]...]
|
|
757
|
+
*
|
|
758
|
+
*
|
|
759
|
+
* // { Pointer } indexedPointer - The indexed pointer (array or string)
|
|
760
|
+
* // { Map<string, number> } arrayMap - The optional array map (for preserving tuple indexes)
|
|
761
|
+
* // { string } - The generic pointer with indexes removed
|
|
762
|
+
*/
|
|
763
|
+
static toGenericPointer(indexedPointer, arrayMap = new Map()) {
|
|
764
|
+
if (this.isJsonPointer(indexedPointer) && isMap(arrayMap)) {
|
|
765
|
+
const pointerArray = this.parse(indexedPointer);
|
|
766
|
+
for (let i = 1; i < pointerArray.length; i++) {
|
|
767
|
+
const subPointer = this.compile(pointerArray.slice(0, i));
|
|
768
|
+
if (arrayMap.has(subPointer) &&
|
|
769
|
+
arrayMap.get(subPointer) <= +pointerArray[i]) {
|
|
770
|
+
pointerArray[i] = '-';
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return this.compile(pointerArray);
|
|
774
|
+
}
|
|
775
|
+
if (!this.isJsonPointer(indexedPointer)) {
|
|
776
|
+
console.error(`toGenericPointer error: invalid JSON Pointer: ${indexedPointer}`);
|
|
777
|
+
}
|
|
778
|
+
if (!isMap(arrayMap)) {
|
|
779
|
+
console.error(`toGenericPointer error: invalid arrayMap: ${arrayMap}`);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* 'toControlPointer' function
|
|
784
|
+
*
|
|
785
|
+
* Accepts a JSON Pointer for a data object and returns a JSON Pointer for the
|
|
786
|
+
* matching control in an Angular FormGroup.
|
|
787
|
+
*
|
|
788
|
+
* // { Pointer } dataPointer - JSON Pointer (string or array) to a data object
|
|
789
|
+
* // { FormGroup } formGroup - Angular FormGroup to get value from
|
|
790
|
+
* // { boolean = false } controlMustExist - Only return if control exists?
|
|
791
|
+
* // { Pointer } - JSON Pointer (string) to the formGroup object
|
|
792
|
+
*/
|
|
793
|
+
static toControlPointer(dataPointer, formGroup, controlMustExist = false) {
|
|
794
|
+
const dataPointerArray = this.parse(dataPointer);
|
|
795
|
+
const controlPointerArray = [];
|
|
796
|
+
let subGroup = formGroup;
|
|
797
|
+
if (dataPointerArray !== null) {
|
|
798
|
+
for (const key of dataPointerArray) {
|
|
799
|
+
if (hasOwn(subGroup, 'controls')) {
|
|
800
|
+
controlPointerArray.push('controls');
|
|
801
|
+
subGroup = subGroup.controls;
|
|
802
|
+
}
|
|
803
|
+
if (isArray(subGroup) && (key === '-')) {
|
|
804
|
+
controlPointerArray.push((subGroup.length - 1).toString());
|
|
805
|
+
subGroup = subGroup[subGroup.length - 1];
|
|
806
|
+
}
|
|
807
|
+
else if (hasOwn(subGroup, key)) {
|
|
808
|
+
controlPointerArray.push(key);
|
|
809
|
+
subGroup = subGroup[key];
|
|
810
|
+
}
|
|
811
|
+
else if (controlMustExist) {
|
|
812
|
+
console.error(`toControlPointer error: Unable to find "${key}" item in FormGroup.`);
|
|
813
|
+
console.error(dataPointer);
|
|
814
|
+
console.error(formGroup);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
controlPointerArray.push(key);
|
|
819
|
+
subGroup = { controls: {} };
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return this.compile(controlPointerArray);
|
|
823
|
+
}
|
|
824
|
+
console.error(`toControlPointer error: Invalid JSON Pointer: ${dataPointer}`);
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* 'toSchemaPointer' function
|
|
828
|
+
*
|
|
829
|
+
* Accepts a JSON Pointer to a value inside a data object and a JSON schema
|
|
830
|
+
* for that object.
|
|
831
|
+
*
|
|
832
|
+
* Returns a Pointer to the sub-schema for the value inside the object's schema.
|
|
833
|
+
*
|
|
834
|
+
* // { Pointer } dataPointer - JSON Pointer (string or array) to an object
|
|
835
|
+
* // schema - JSON schema for the object
|
|
836
|
+
* // { Pointer } - JSON Pointer (string) to the object's schema
|
|
837
|
+
*/
|
|
838
|
+
static toSchemaPointer(dataPointer, schema) {
|
|
839
|
+
if (this.isJsonPointer(dataPointer) && typeof schema === 'object') {
|
|
840
|
+
const pointerArray = this.parse(dataPointer);
|
|
841
|
+
if (!pointerArray.length) {
|
|
842
|
+
return '';
|
|
843
|
+
}
|
|
844
|
+
const firstKey = pointerArray.shift();
|
|
845
|
+
if (schema.type === 'object' || schema.properties || schema.additionalProperties) {
|
|
846
|
+
if ((schema.properties || {})[firstKey]) {
|
|
847
|
+
return `/properties/${this.escape(firstKey)}` +
|
|
848
|
+
this.toSchemaPointer(pointerArray, schema.properties[firstKey]);
|
|
849
|
+
}
|
|
850
|
+
else if (schema.additionalProperties) {
|
|
851
|
+
return '/additionalProperties' +
|
|
852
|
+
this.toSchemaPointer(pointerArray, schema.additionalProperties);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
if ((schema.type === 'array' || schema.items) &&
|
|
856
|
+
(isNumber(firstKey) || firstKey === '-' || firstKey === '')) {
|
|
857
|
+
const arrayItem = firstKey === '-' || firstKey === '' ? 0 : +firstKey;
|
|
858
|
+
if (isArray(schema.items)) {
|
|
859
|
+
if (arrayItem < schema.items.length) {
|
|
860
|
+
return '/items/' + arrayItem +
|
|
861
|
+
this.toSchemaPointer(pointerArray, schema.items[arrayItem]);
|
|
862
|
+
}
|
|
863
|
+
else if (schema.additionalItems) {
|
|
864
|
+
return '/additionalItems' +
|
|
865
|
+
this.toSchemaPointer(pointerArray, schema.additionalItems);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
else if (isObject(schema.items)) {
|
|
869
|
+
return '/items' + this.toSchemaPointer(pointerArray, schema.items);
|
|
870
|
+
}
|
|
871
|
+
else if (isObject(schema.additionalItems)) {
|
|
872
|
+
return '/additionalItems' +
|
|
873
|
+
this.toSchemaPointer(pointerArray, schema.additionalItems);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
console.error(`toSchemaPointer error: Data pointer ${dataPointer} ` +
|
|
877
|
+
`not compatible with schema ${schema}`);
|
|
878
|
+
return null;
|
|
879
|
+
}
|
|
880
|
+
if (!this.isJsonPointer(dataPointer)) {
|
|
881
|
+
console.error(`toSchemaPointer error: Invalid JSON Pointer: ${dataPointer}`);
|
|
882
|
+
}
|
|
883
|
+
if (typeof schema !== 'object') {
|
|
884
|
+
console.error(`toSchemaPointer error: Invalid JSON Schema: ${schema}`);
|
|
885
|
+
}
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* 'toDataPointer' function
|
|
890
|
+
*
|
|
891
|
+
* Accepts a JSON Pointer to a sub-schema inside a JSON schema and the schema.
|
|
892
|
+
*
|
|
893
|
+
* If possible, returns a generic Pointer to the corresponding value inside
|
|
894
|
+
* the data object described by the JSON schema.
|
|
895
|
+
*
|
|
896
|
+
* Returns null if the sub-schema is in an ambiguous location (such as
|
|
897
|
+
* definitions or additionalProperties) where the corresponding value
|
|
898
|
+
* location cannot be determined.
|
|
899
|
+
*
|
|
900
|
+
* // { Pointer } schemaPointer - JSON Pointer (string or array) to a JSON schema
|
|
901
|
+
* // schema - the JSON schema
|
|
902
|
+
* // { boolean = false } errors - Show errors?
|
|
903
|
+
* // { Pointer } - JSON Pointer (string) to the value in the data object
|
|
904
|
+
*/
|
|
905
|
+
static toDataPointer(schemaPointer, schema, errors = false) {
|
|
906
|
+
if (this.isJsonPointer(schemaPointer) && typeof schema === 'object' &&
|
|
907
|
+
this.has(schema, schemaPointer)) {
|
|
908
|
+
const pointerArray = this.parse(schemaPointer);
|
|
909
|
+
if (!pointerArray.length) {
|
|
910
|
+
return '';
|
|
911
|
+
}
|
|
912
|
+
const firstKey = pointerArray.shift();
|
|
913
|
+
if (firstKey === 'properties' ||
|
|
914
|
+
(firstKey === 'items' && isArray(schema.items))) {
|
|
915
|
+
const secondKey = pointerArray.shift();
|
|
916
|
+
const pointerSuffix = this.toDataPointer(pointerArray, schema[firstKey][secondKey]);
|
|
917
|
+
return pointerSuffix === null ? null : '/' + secondKey + pointerSuffix;
|
|
918
|
+
}
|
|
919
|
+
else if (firstKey === 'additionalItems' ||
|
|
920
|
+
(firstKey === 'items' && isObject(schema.items))) {
|
|
921
|
+
const pointerSuffix = this.toDataPointer(pointerArray, schema[firstKey]);
|
|
922
|
+
return pointerSuffix === null ? null : '/-' + pointerSuffix;
|
|
923
|
+
}
|
|
924
|
+
else if (['allOf', 'anyOf', 'oneOf'].includes(firstKey)) {
|
|
925
|
+
const secondKey = pointerArray.shift();
|
|
926
|
+
return this.toDataPointer(pointerArray, schema[firstKey][secondKey]);
|
|
927
|
+
}
|
|
928
|
+
else if (firstKey === 'not') {
|
|
929
|
+
return this.toDataPointer(pointerArray, schema[firstKey]);
|
|
930
|
+
}
|
|
931
|
+
else if (['contains', 'definitions', 'dependencies', 'additionalItems',
|
|
932
|
+
'additionalProperties', 'patternProperties', 'propertyNames'].includes(firstKey)) {
|
|
933
|
+
if (errors) {
|
|
934
|
+
console.error(`toDataPointer error: Ambiguous location`);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return '';
|
|
938
|
+
}
|
|
939
|
+
if (errors) {
|
|
940
|
+
if (!this.isJsonPointer(schemaPointer)) {
|
|
941
|
+
console.error(`toDataPointer error: Invalid JSON Pointer: ${schemaPointer}`);
|
|
942
|
+
}
|
|
943
|
+
if (typeof schema !== 'object') {
|
|
944
|
+
console.error(`toDataPointer error: Invalid JSON Schema: ${schema}`);
|
|
945
|
+
}
|
|
946
|
+
if (typeof schema !== 'object') {
|
|
947
|
+
console.error(`toDataPointer error: Pointer ${schemaPointer} invalid for Schema: ${schema}`);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* 'parseObjectPath' function
|
|
954
|
+
*
|
|
955
|
+
* Parses a JavaScript object path into an array of keys, which
|
|
956
|
+
* can then be passed to compile() to convert into a string JSON Pointer.
|
|
957
|
+
*
|
|
958
|
+
* Based on mike-marcacci's excellent objectpath parse function:
|
|
959
|
+
* https://github.com/mike-marcacci/objectpath
|
|
960
|
+
*
|
|
961
|
+
* // { Pointer } path - The object path to parse
|
|
962
|
+
* // { string[] } - The resulting array of keys
|
|
963
|
+
*/
|
|
964
|
+
static parseObjectPath(path) {
|
|
965
|
+
if (isArray(path)) {
|
|
966
|
+
return path;
|
|
967
|
+
}
|
|
968
|
+
if (this.isJsonPointer(path)) {
|
|
969
|
+
return this.parse(path);
|
|
970
|
+
}
|
|
971
|
+
if (typeof path === 'string') {
|
|
972
|
+
let index = 0;
|
|
973
|
+
const parts = [];
|
|
974
|
+
while (index < path.length) {
|
|
975
|
+
const nextDot = path.indexOf('.', index);
|
|
976
|
+
const nextOB = path.indexOf('[', index); // next open bracket
|
|
977
|
+
if (nextDot === -1 && nextOB === -1) { // last item
|
|
978
|
+
parts.push(path.slice(index));
|
|
979
|
+
index = path.length;
|
|
980
|
+
}
|
|
981
|
+
else if (nextDot !== -1 && (nextDot < nextOB || nextOB === -1)) { // dot notation
|
|
982
|
+
parts.push(path.slice(index, nextDot));
|
|
983
|
+
index = nextDot + 1;
|
|
984
|
+
}
|
|
985
|
+
else { // bracket notation
|
|
986
|
+
if (nextOB > index) {
|
|
987
|
+
parts.push(path.slice(index, nextOB));
|
|
988
|
+
index = nextOB;
|
|
989
|
+
}
|
|
990
|
+
const quote = path.charAt(nextOB + 1);
|
|
991
|
+
if (quote === '"' || quote === '\'') { // enclosing quotes
|
|
992
|
+
let nextCB = path.indexOf(quote + ']', nextOB); // next close bracket
|
|
993
|
+
while (nextCB !== -1 && path.charAt(nextCB - 1) === '\\') {
|
|
994
|
+
nextCB = path.indexOf(quote + ']', nextCB + 2);
|
|
995
|
+
}
|
|
996
|
+
if (nextCB === -1) {
|
|
997
|
+
nextCB = path.length;
|
|
998
|
+
}
|
|
999
|
+
parts.push(path.slice(index + 2, nextCB)
|
|
1000
|
+
.replace(new RegExp('\\' + quote, 'g'), quote));
|
|
1001
|
+
index = nextCB + 2;
|
|
1002
|
+
}
|
|
1003
|
+
else { // no enclosing quotes
|
|
1004
|
+
let nextCB = path.indexOf(']', nextOB); // next close bracket
|
|
1005
|
+
if (nextCB === -1) {
|
|
1006
|
+
nextCB = path.length;
|
|
1007
|
+
}
|
|
1008
|
+
parts.push(path.slice(index + 1, nextCB));
|
|
1009
|
+
index = nextCB + 1;
|
|
1010
|
+
}
|
|
1011
|
+
if (path.charAt(index) === '.') {
|
|
1012
|
+
index++;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return parts;
|
|
1017
|
+
}
|
|
1018
|
+
console.error('parseObjectPath error: Input object path must be a string.');
|
|
1019
|
+
}
|
|
1020
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JsonPointer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1021
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JsonPointer }); }
|
|
1022
|
+
}
|
|
1023
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JsonPointer, decorators: [{
|
|
1024
|
+
type: Injectable
|
|
1025
|
+
}] });
|
|
1026
1026
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbnBvaW50ZXIuZnVuY3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctZm9ybXdvcmtzLWNvcmUvc3JjL2xpYi9zaGFyZWQvanNvbnBvaW50ZXIuZnVuY3Rpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsSUFBSSxFQUVKLGlCQUFpQixFQUNqQiw4QkFBOEIsRUFDOUIsTUFBTSxFQUNOLE9BQU8sRUFDUCxVQUFVLEVBQ1YsZUFBZSxFQUNoQixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBQyxNQUFNLHVCQUF1QixDQUFDOztBQW1CdkcsTUFBTSxPQUFPLFdBQVc7SUFFdEI7Ozs7Ozs7Ozs7OztPQVlHO0lBQ0gsTUFBTSxDQUFDLEdBQUcsQ0FDUixNQUFNLEVBQUUsT0FBTyxFQUFFLFVBQVUsR0FBRyxDQUFDLEVBQUUsV0FBbUIsSUFBSSxFQUN4RCxVQUFVLEdBQUcsS0FBSyxFQUFFLE1BQU0sR0FBRyxLQUFLO1FBRWxDLElBQUksTUFBTSxLQUFLLElBQUksRUFBRTtZQUFFLE9BQU8sVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztTQUFFO1FBQy9ELElBQUksUUFBUSxHQUFVLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ2xELElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxJQUFJLFFBQVEsS0FBSyxJQUFJLEVBQUU7WUFDbkQsSUFBSSxTQUFTLEdBQUcsTUFBTSxDQUFDO1lBQ3ZCLElBQUksVUFBVSxJQUFJLFFBQVEsQ0FBQyxNQUFNLElB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Q0FBQzsrR0FuOUJVLFdBQVc7bUhBQVgsV0FBVzs7NEZBQVgsV0FBVztrQkFEdkIsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgY2xlYW5WYWx1ZU9mUXVvdGVzLFxyXG4gIGNvcHksXHJcbiAgRXhwcmVzc2lvblR5cGUsXHJcbiAgZ2V0RXhwcmVzc2lvblR5cGUsXHJcbiAgZ2V0S2V5QW5kVmFsdWVCeUV4cHJlc3Npb25UeXBlLFxyXG4gIGhhc093bixcclxuICBpc0VxdWFsLFxyXG4gIGlzTm90RXF1YWwsXHJcbiAgaXNOb3RFeHByZXNzaW9uXHJcbn0gZnJvbSAnLi91dGlsaXR5LmZ1bmN0aW9ucyc7XHJcbmltcG9ydCB7SW5qZWN0YWJsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7aXNBcnJheSwgaXNEZWZpbmVkLCBpc0VtcHR5LCBpc01hcCwgaXNOdW1iZXIsIGlzT2JqZWN0LCBpc1N0cmluZ30gZnJvbSAnLi92YWxpZGF0b3IuZnVuY3Rpb25zJztcclxuXHJcbi8qKlxyXG4gKiAnSnNvblBvaW50ZXInIGNsYXNzXHJcbiAqXHJcbiAqIFNvbWUgdXRpbGl0aWVzIGZvciB1c2luZyBKU09OIFBvaW50ZXJzIHdpdGggSlNPTiBvYmplY3RzXHJcbiAqIGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM2OTAxXHJcbiAqXHJcbiAqIGdldCwgZ2V0Q29weSwgZ2V0Rmlyc3QsIHNldCwgc2V0Q29weSwgaW5zZXJ0LCBpbnNlcnRDb3B5LCByZW1vdmUsIGhhcywgZGljdCxcclxuICogZm9yRWFjaERlZXAsIGZvckVhY2hEZWVwQ29weSwgZXNjYXBlLCB1bmVzY2FwZSwgcGFyc2UsIGNvbXBpbGUsIHRvS2V5LFxyXG4gKiBpc0pzb25Qb2ludGVyLCBpc1N1YlBvaW50ZXIsIHRvSW5kZXhlZFBvaW50ZXIsIHRvR2VuZXJpY1BvaW50ZXIsXHJcbiAqIHRvQ29udHJvbFBvaW50ZXIsIHRvU2NoZW1hUG9pbnRlciwgdG9EYXRhUG9pbnRlciwgcGFyc2VPYmplY3RQYXRoXHJcbiAqXHJcbiAqIFNvbWUgZnVuY3Rpb25zIGJhc2VkIG9uIG1hbnVlbHN0b2ZlcidzIGpzb24tcG9pbnRlciB1dGlsaXRpZXNcclxuICogaHR0cHM6Ly9naXRodWIuY29tL21hbnVlbHN0b2Zlci9qc29uLXBvaW50ZXJcclxuICovXHJcbmV4cG9ydCB0eXBlIFBvaW50ZXIgPSBzdHJpbmcgfCBzdHJpbmdbXTtcclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIEpzb25Qb2ludGVyIHtcclxuXHJcbiAgLyoqXHJcbiAgICogJ2dldCcgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIFVzZXMgYSBKU09OIFBvaW50ZXIgdG8gcmV0cmlldmUgYSB2YWx1ZSBmcm9tIGFuIG9iamVjdC5cclxuICAgKlxyXG4gICAqIC8vICB7IG9iamVjdCB9IG9iamVjdCAtIE9iamVjdCB0byBnZXQgdmFsdWUgZnJvbVxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBwb2ludGVyIC0gSlNPTiBQb2ludGVyIChzdHJpbmcgb3IgYXJyYXkpXHJcbiAgICogLy8gIHsgbnVtYmVyID0gMCB9IHN0YXJ0U2xpY2UgLSBaZXJvLWJhc2VkIGluZGV4IG9mIGZpcnN0IFBvaW50ZXIga2V5IHRvIHVzZVxyXG4gICAqIC8vICB7IG51bWJlciB9IGVuZFNsaWNlIC0gWmVyby1iYXNlZCBpbmRleCBvZiBsYXN0IFBvaW50ZXIga2V5IHRvIHVzZVxyXG4gICAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IGdldEJvb2xlYW4gLSBSZXR1cm4gb25seSB0cnVlIG9yIGZhbHNlP1xyXG4gICAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IGVycm9ycyAtIFNob3cgZXJyb3IgaWYgbm90IGZvdW5kP1xyXG4gICAqIC8vIHsgb2JqZWN0IH0gLSBMb2NhdGVkIHZhbHVlIChvciB0cnVlIG9yIGZhbHNlIGlmIGdldEJvb2xlYW4gPSB0cnVlKVxyXG4gICAqL1xyXG4gIHN0YXRpYyBnZXQoXHJcbiAgICBvYmplY3QsIHBvaW50ZXIsIHN0YXJ0U2xpY2UgPSAwLCBlbmRTbGljZTogbnVtYmVyID0gbnVsbCxcclxuICAgIGdldEJvb2xlYW4gPSBmYWxzZSwgZXJyb3JzID0gZmFsc2VcclxuICApIHtcclxuICAgIGlmIChvYmplY3QgPT09IG51bGwpIHsgcmV0dXJuIGdldEJvb2xlYW4gPyBmYWxzZSA6IHVuZGVmaW5lZDsgfVxyXG4gICAgbGV0IGtleUFycmF5OiBhbnlbXSA9IHRoaXMucGFyc2UocG9pbnRlciwgZXJyb3JzKTtcclxuICAgIGlmICh0eXBlb2Ygb2JqZWN0ID09PSAnb2JqZWN0JyAmJiBrZXlBcnJheSAhPT0gbnVsbCkge1xyXG4gICAgICBsZXQgc3ViT2JqZWN0ID0gb2JqZWN0O1xyXG4gICAgICBpZiAoc3RhcnRTbGljZSA+PSBrZXlBcnJheS5sZW5ndGggfHwgZW5kU2xpY2UgPD0gLWtleUFycmF5Lmxlbmd0aCkgeyByZXR1cm4gb2JqZWN0OyB9XHJcbiAgICAgIGlmIChzdGFydFNsaWNlIDw9IC1rZXlBcnJheS5sZW5ndGgpIHsgc3RhcnRTbGljZSA9IDA7IH1cclxuICAgICAgaWYgKCFpc0RlZmluZWQoZW5kU2xpY2UpIHx8IGVuZFNsaWNlID49IGtleUFycmF5Lmxlbmd0aCkgeyBlbmRTbGljZSA9IGtleUFycmF5Lmxlbmd0aDsgfVxyXG4gICAgICBrZXlBcnJheSA9IGtleUFycmF5LnNsaWNlKHN0YXJ0U2xpY2UsIGVuZFNsaWNlKTtcclxuICAgICAgZm9yIChsZXQga2V5IG9mIGtleUFycmF5KSB7XHJcbiAgICAgICAgaWYgKGtleSA9PT0gJy0nICYmIGlzQXJyYXkoc3ViT2JqZWN0KSAmJiBzdWJPYmplY3QubGVuZ3RoKSB7XHJcbiAgICAgICAgICBrZXkgPSBzdWJPYmplY3QubGVuZ3RoIC0gMTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGlzTWFwKHN1Yk9iamVjdCkgJiYgc3ViT2JqZWN0LmhhcyhrZXkpKSB7XHJcbiAgICAgICAgICBzdWJPYmplY3QgPSBzdWJPYmplY3QuZ2V0KGtleSk7XHJcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygc3ViT2JqZWN0ID09PSAnb2JqZWN0JyAmJiBzdWJPYmplY3QgIT09IG51bGwgJiZcclxuICAgICAgICAgIGhhc093bihzdWJPYmplY3QsIGtleSlcclxuICAgICAgICApIHtcclxuICAgICAgICAgIHN1Yk9iamVjdCA9IHN1Yk9iamVjdFtrZXldO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25zdCBldmFsdWF0ZWRFeHByZXNzaW9uID0gSnNvblBvaW50ZXIuZXZhbHVhdGVFeHByZXNzaW9uKHN1Yk9iamVjdCwga2V5KTtcclxuICAgICAgICAgIGlmIChldmFsdWF0ZWRFeHByZXNzaW9uLnBhc3NlZCkge1xyXG4gICAgICAgICAgICBzdWJPYmplY3QgPSBldmFsdWF0ZWRFeHByZXNzaW9uLmtleSA/IHN1Yk9iamVjdFtldmFsdWF0ZWRFeHByZXNzaW9uLmtleV0gOiBzdWJPYmplY3Q7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLmxvZ0Vycm9ycyhlcnJvcnMsIGtleSwgcG9pbnRlciwgb2JqZWN0KTtcclxuICAgICAgICAgICAgcmV0dXJuIGdldEJvb2xlYW4gPyBmYWxzZSA6IHVuZGVmaW5lZDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGdldEJvb2xlYW4gPyB0cnVlIDogc3ViT2JqZWN0O1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9ycyAmJiBrZXlBcnJheSA9PT0gbnVsbCkge1xyXG4gICAgICBjb25zb2xlLmVycm9yKGBnZXQgZXJyb3I6IEludmFsaWQgSlNPTiBQb2ludGVyOiAke3BvaW50ZXJ9YCk7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3JzICYmIHR5cGVvZiBvYmplY3QgIT09ICdvYmplY3QnKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ2dldCBlcnJvcjogSW52YWxpZCBvYmplY3Q6Jyk7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3Iob2JqZWN0KTtcclxuICAgIH1cclxuICAgIHJldHVybiBnZXRCb29sZWFuID8gZmFsc2UgOiB1bmRlZmluZWQ7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHN0YXRpYyBsb2dFcnJvcnMoZXJyb3JzLCBrZXksIHBvaW50ZXIsIG9iamVjdCkge1xyXG4gICAgaWYgKGVycm9ycykge1xyXG4gICAgICBjb25zb2xlLmVycm9yKGBnZXQgZXJyb3I6IFwiJHtrZXl9XCIga2V5IG5vdCBmb3VuZCBpbiBvYmplY3QuYCk7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IocG9pbnRlcik7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3Iob2JqZWN0KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEV2YWx1YXRlcyBjb25kaXRpb25hbCBleHByZXNzaW9uIGluIGZvcm0gb2YgYG1vZGVsLjxwcm9wZXJ0eT49PTx2YWx1ZT5gIG9yXHJcbiAgICogYG1vZGVsLjxwcm9wZXJ0eT4hPTx2YWx1ZT5gIHdoZXJlIHRoZSBmaXJzdCBvbmUgbWVhbnMgdGhhdCB0aGUgdmFsdWUgbXVzdCBtYXRjaCB0byBiZVxyXG4gICAqIHNob3duIGluIGEgZm9ybSwgd2hpbGUgdGhlIGZvcm1lciBzaG93cyB0aGUgcHJvcGVydHkgb25seSB3aGVuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBpcyBub3RcclxuICAgKiBzZXQsIG9yIGRvZXMgbm90IGVxdWFsIHRoZSBnaXZlbiB2YWx1ZS5cclxuICAgKlxyXG4gICAqIC8vIHsgc3ViT2JqZWN0IH0gc3ViT2JqZWN0IC0gIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBkYXRhIHZhbHVlcyBvZiBwcm9wZXJ0aWVzXHJcbiAgICogLy8geyBrZXkgfSBrZXkgLSB0aGUga2V5IGZyb20gdGhlIGZvciBsb29wIGluIGEgZm9ybSBvZiBgPHByb3BlcnR5Pj09PHZhbHVlPmBcclxuICAgKlxyXG4gICAqIFJldHVybnMgdGhlIG9iamVjdCB3aXRoIHR3byBwcm9wZXJ0aWVzLiBUaGUgcHJvcGVydHkgcGFzc2VkIGluZm9ybXMgd2hldGhlclxyXG4gICAqIHRoZSBleHByZXNzaW9uIGV2YWx1YXRlZCBzdWNjZXNzZnVsbHkgYW5kIHRoZSBwcm9wZXJ0eSBrZXkgcmV0dXJucyBlaXRoZXIgdGhlIHNhbWVcclxuICAgKiBrZXkgaWYgaXQgaXMgbm90IGNvbnRhaW5lZCBpbnNpZGUgdGhlIHN1Yk9iamVjdCBvciB0aGUga2V5IG9mIHRoZSBwcm9wZXJ0eSBpZiBpdCBpcyBjb250YWluZWQuXHJcbiAgICovXHJcbiAgc3RhdGljIGV2YWx1YXRlRXhwcmVzc2lvbihzdWJPYmplY3Q6IE9iamVjdCwga2V5OiBhbnkpIHtcclxuICAgIGNvbnN0IGRlZmF1bHRSZXN1bHQgPSB7cGFzc2VkOiBmYWxzZSwga2V5OiBrZXl9O1xyXG4gICAgY29uc3Qga2V5c0FuZEV4cHJlc3Npb24gPSB0aGlzLnBhcnNlS2V5c0FuZEV4cHJlc3Npb24oa2V5LCBzdWJPYmplY3QpO1xyXG4gICAgaWYgKCFrZXlzQW5kRXhwcmVzc2lvbikge1xyXG4gICAgICByZXR1cm4gZGVmYXVsdFJlc3VsdDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBvd25DaGVja1Jlc3VsdCA9IHRoaXMuZG9Pd25DaGVja1Jlc3VsdChzdWJPYmplY3QsIGtleXNBbmRFeHByZXNzaW9uKTtcclxuICAgIGlmIChvd25DaGVja1Jlc3VsdCkge1xyXG4gICAgICByZXR1cm4gb3duQ2hlY2tSZXN1bHQ7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgY2xlYW5lZFZhbHVlID0gY2xlYW5WYWx1ZU9mUXVvdGVzKGtleXNBbmRFeHByZXNzaW9uLmtleUFuZFZhbHVlWzFdKTtcclxuXHJcbiAgICBjb25zdCBldmFsdWF0ZWRSZXN1bHQgPSB0aGlzLnBlcmZvcm1FeHByZXNzaW9uT25WYWx1ZShrZXlzQW5kRXhwcmVzc2lvbiwgY2xlYW5lZFZhbHVlLCBzdWJPYmplY3QpO1xyXG4gICAgaWYgKGV2YWx1YXRlZFJlc3VsdCkge1xyXG4gICAgICByZXR1cm4gZXZhbHVhdGVkUmVzdWx0O1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBkZWZhdWx0UmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUGVyZm9ybXMgdGhlIGFjdHVhbCBldmFsdWF0aW9uIG9uIHRoZSBnaXZlbiBleHByZXNzaW9uIHdpdGggZ2l2ZW4gdmFsdWVzIGFuZCBrZXlzLlxyXG4gICAqIC8vIHsgY2xlYW5lZFZhbHVlIH0gY2xlYW5lZFZhbHVlIC0gdGhlIGdpdmVuIHZhbHVlZCBjbGVhbmVkIG9mIHF1b3RlcyBpZiBpdCBoYWQgYW55XHJcbiAgICogLy8geyBzdWJPYmplY3QgfSBzdWJPYmplY3QgLSB0aGUgb2JqZWN0IHdpdGggcHJvcGVydGllcyB2YWx1ZXNcclxuICAgKiAvLyB7IGtleXNBbmRFeHByZXNzaW9uIH0ga2V5c0FuZEV4cHJlc3Npb24gLSBhbiBvYmplY3QgaG9sZGluZyB0aGUgZXhwcmVzc2lvbnMgd2l0aFxyXG4gICAqL1xyXG4gIHByaXZhdGUgc3RhdGljIHBlcmZvcm1FeHByZXNzaW9uT25WYWx1ZShrZXlzQW5kRXhwcmVzc2lvbjogYW55LCBjbGVhbmVkVmFsdWU6IFN0cmluZywgc3ViT2JqZWN0OiBPYmplY3QpIHtcclxuICAgIGNvbnN0IHByb3BlcnR5QnlLZXkgPSBzdWJPYmplY3Rba2V5c0FuZEV4cHJlc3Npb24ua2V5QW5kVmFsdWVbMF1dO1xyXG4gICAgaWYgKHRoaXMuZG9Db21wYXJpc29uQnlFeHByZXNzaW9uVHlwZShrZXlzQW5kRXhwcmVzc2lvbi5leHByZXNzaW9uVHlwZSwgcHJvcGVydHlCeUtleSwgY2xlYW5lZFZhbHVlKSkge1xyXG4gICAgICByZXR1cm4ge3Bhc3NlZDogdHJ1ZSwga2V5OiBrZXlzQW5kRXhwcmVzc2lvbi5rZXlBbmRWYWx1ZVswXX07XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHN0YXRpYyBkb0NvbXBhcmlzb25CeUV4cHJlc3Npb25UeXBlKGV4cHJlc3Npb25UeXBlOiBFeHByZXNzaW9uVHlwZSwgcHJvcGVydHlCeUtleSwgY2xlYW5lZFZhbHVlOiBTdHJpbmcpOiBCb29sZWFuIHtcclxuICAgIGlmIChpc0VxdWFsKGV4cHJlc3Npb25UeXBlKSkge1xyXG4gICAgICByZXR1cm4gcHJvcGVydHlCeUtleSA9PT0gY2xlYW5lZFZhbHVlO1xyXG4gICAgfVxyXG4gICAgaWYgKGlzTm90RXF1YWwoZXhwcmVzc2lvblR5cGUpKSB7XHJcbiAgICAgIHJldHVybiBwcm9wZXJ0eUJ5S2V5ICE9PSBjbGVhbmVkVmFsdWU7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEb2VzIHRoZSBjaGVja3Mgd2hlbiB0aGUgcGFyc2VkIGtleSBpcyBhY3R1YWxseSBubyBhIHByb3BlcnR5IGluc2lkZSBzdWJPYmplY3QuXHJcbiAgICogVGhhdCB3b3VsZCBtZWFuIHRoYXQgdGhlIGVxdWFsIGNvbXBhcmlzb24gbWFrZXMgbm8gc2Vuc2UgYW5kIHRodXMgdGhlIG5lZ2F0aXZlIHJlc3VsdFxyXG4gICAqIGlzIHJldHVybmVkLCBhbmQgdGhlIG5vdCBlcXVhbCBjb21wYXJpc29uIGlzIG5vdCBuZWNlc3NhcnkgYmVjYXVzZSBpdCBkb2Vzbid0IGVxdWFsXHJcbiAgICogb2J2aW91c2x5LiBSZXR1cm5zIG51bGwgd2hlbiB0aGUgZ2l2ZW4ga2V5IGlzIGEgcmVhbCBwcm9wZXJ0eSBpbnNpZGUgdGhlIHN1Yk9iamVjdC5cclxuICAgKiAvLyB7IHN1Yk9iamVjdCB9IHN1Yk9iamVjdCAtIHRoZSBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzIHZhbHVlc1xyXG4gICAqIC8vIHsga2V5c0FuZEV4cHJlc3Npb24gfSBrZXlzQW5kRXhwcmVzc2lvbiAtIGFuIG9iamVjdCBob2xkaW5nIHRoZSBleHByZXNzaW9ucyB3aXRoXHJcbiAgICogdGhlIGFzc29jaWF0ZWQga2V5cy5cclxuICAgKi9cclxuICBwcml2YXRlIHN0YXRpYyBkb093bkNoZWNrUmVzdWx0KHN1Yk9iamVjdDogT2JqZWN0LCBrZXlzQW5kRXhwcmVzc2lvbikge1xyXG4gICAgbGV0IG93bkNoZWNrUmVzdWx0ID0gbnVsbDtcclxuICAgIGlmICghaGFzT3duKHN1Yk9iamVjdCwga2V5c0FuZEV4cHJlc3Npb24ua2V5QW5kVmFsdWVbMF0pKSB7XHJcbiAgICAgIGlmIChpc0VxdWFsKGtleXNBbmRFeHByZXNzaW9uLmV4cHJlc3Npb25UeXBlKSkge1xyXG4gICAgICAgIG93bkNoZWNrUmVzdWx0ID0ge3Bhc3NlZDogZmFsc2UsIGtleTogbnVsbH07XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGlzTm90RXF1YWwoa2V5c0FuZEV4cHJlc3Npb24uZXhwcmVzc2lvblR5cGUpKSB7XHJcbiAgICAgICAgb3duQ2hlY2tSZXN1bHQgPSB7cGFzc2VkOiB0cnVlLCBrZXk6IG51bGx9O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gb3duQ2hlY2tSZXN1bHQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEb2VzIHRoZSBiYXNpYyBjaGVja3MgYW5kIHRyaWVzIHRvIHBhcnNlIGFuIGV4cHJlc3Npb24gYW5kIGEgcGFpclxyXG4gICAqIG9mIGtleSBhbmQgdmFsdWUuXHJcbiAgICogLy8geyBrZXkgfSBrZXkgLSB0aGUgb3JpZ2luYWwgZm9yIGxvb3AgY3JlYXRlZCB2YWx1ZSBjb250YWluaW5nIGtleSBhbmQgdmFsdWUgaW4gb25lIHN0cmluZ1xyXG4gICAqIC8vIHsgc3ViT2JqZWN0IH0gc3ViT2JqZWN0IC0gdGhlIG9iamVjdCB3aXRoIHByb3BlcnRpZXMgdmFsdWVzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzdGF0aWMgcGFyc2VLZXlzQW5kRXhwcmVzc2lvbihrZXk6IHN0cmluZywgc3ViT2JqZWN0KSB7XHJcbiAgICBpZiAodGhpcy5rZXlPclN1Yk9iakVtcHR5KGtleSwgc3ViT2JqZWN0KSkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICAgIGNvbnN0IGV4cHJlc3Npb25UeXBlID0gZ2V0RXhwcmVzc2lvblR5cGUoa2V5LnRvU3RyaW5nKCkpO1xyXG4gICAgaWYgKGlzTm90RXhwcmVzc2lvbihleHByZXNzaW9uVHlwZSkpIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgICBjb25zdCBrZXlBbmRWYWx1ZSA9IGdldEtleUFuZFZhbHVlQnlFeHByZXNzaW9uVHlwZShleHByZXNzaW9uVHlwZSwga2V5KTtcclxuICAgIGlmICgha2V5QW5kVmFsdWUgfHwgIWtleUFuZFZhbHVlWzBdIHx8ICFrZXlBbmRWYWx1ZVsxXSkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICAgIHJldHVybiB7ZXhwcmVzc2lvblR5cGU6IGV4cHJlc3Npb25UeXBlLCBrZXlBbmRWYWx1ZToga2V5QW5kVmFsdWV9O1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzdGF0aWMga2V5T3JTdWJPYmpFbXB0eShrZXk6IGFueSwgc3ViT2JqZWN0OiBPYmplY3QpIHtcclxuICAgIHJldHVybiAha2V5IHx8ICFzdWJPYmplY3Q7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnZ2V0Q29weScgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIFVzZXMgYSBKU09OIFBvaW50ZXIgdG8gZGVlcGx5IGNsb25lIGEgdmFsdWUgZnJvbSBhbiBvYmplY3QuXHJcbiAgICpcclxuICAgKiAvLyAgeyBvYmplY3QgfSBvYmplY3QgLSBPYmplY3QgdG8gZ2V0IHZhbHVlIGZyb21cclxuICAgKiAvLyAgeyBQb2ludGVyIH0gcG9pbnRlciAtIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KVxyXG4gICAqIC8vICB7IG51bWJlciA9IDAgfSBzdGFydFNsaWNlIC0gWmVyby1iYXNlZCBpbmRleCBvZiBmaXJzdCBQb2ludGVyIGtleSB0byB1c2VcclxuICAgKiAvLyAgeyBudW1iZXIgfSBlbmRTbGljZSAtIFplcm8tYmFzZWQgaW5kZXggb2YgbGFzdCBQb2ludGVyIGtleSB0byB1c2VcclxuICAgKiAvLyAgeyBib29sZWFuID0gZmFsc2UgfSBnZXRCb29sZWFuIC0gUmV0dXJuIG9ubHkgdHJ1ZSBvciBmYWxzZT9cclxuICAgKiAvLyAgeyBib29sZWFuID0gZmFsc2UgfSBlcnJvcnMgLSBTaG93IGVycm9yIGlmIG5vdCBmb3VuZD9cclxuICAgKiAvLyB7IG9iamVjdCB9IC0gTG9jYXRlZCB2YWx1ZSAob3IgdHJ1ZSBvciBmYWxzZSBpZiBnZXRCb29sZWFuID0gdHJ1ZSlcclxuICAgKi9cclxuICBzdGF0aWMgZ2V0Q29weShcclxuICAgIG9iamVjdCwgcG9pbnRlciwgc3RhcnRTbGljZSA9IDAsIGVuZFNsaWNlOiBudW1iZXIgPSBudWxsLFxyXG4gICAgZ2V0Qm9vbGVhbiA9IGZhbHNlLCBlcnJvcnMgPSBmYWxzZVxyXG4gICkge1xyXG4gICAgY29uc3Qgb2JqZWN0VG9Db3B5ID1cclxuICAgICAgdGhpcy5nZXQob2JqZWN0LCBwb2ludGVyLCBzdGFydFNsaWNlLCBlbmRTbGljZSwgZ2V0Qm9vbGVhbiwgZXJyb3JzKTtcclxuICAgIHJldHVybiB0aGlzLmZvckVhY2hEZWVwQ29weShvYmplY3RUb0NvcHkpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ2dldEZpcnN0JyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogVGFrZXMgYW4gYXJyYXkgb2YgSlNPTiBQb2ludGVycyBhbmQgb2JqZWN0cyxcclxuICAgKiBjaGVja3MgZWFjaCBvYmplY3QgZm9yIGEgdmFsdWUgc3BlY2lmaWVkIGJ5IHRoZSBwb2ludGVyLFxyXG4gICAqIGFuZCByZXR1cm5zIHRoZSBmaXJzdCB2YWx1ZSBmb3VuZC5cclxuICAgKlxyXG4gICAqIC8vICB7IFtvYmplY3QsIHBvaW50ZXJdW10gfSBpdGVtcyAtIEFycmF5IG9mIG9iamVjdHMgYW5kIHBvaW50ZXJzIHRvIGNoZWNrXHJcbiAgICogLy8gIHsgYW55ID0gbnVsbCB9IGRlZmF1bHRWYWx1ZSAtIFZhbHVlIHRvIHJldHVybiBpZiBub3RoaW5nIGZvdW5kXHJcbiAgICogLy8gIHsgYm9vbGVhbiA9IGZhbHNlIH0gZ2V0Q29weSAtIFJldHVybiBhIGNvcHkgaW5zdGVhZD9cclxuICAgKiAvLyAgLSBGaXJzdCB2YWx1ZSBmb3VuZFxyXG4gICAqL1xyXG4gIHN0YXRpYyBnZXRGaXJzdChpdGVtcywgZGVmYXVsdFZhbHVlOiBhbnkgPSBudWxsLCBnZXRDb3B5ID0gZmFsc2UpIHtcclxuICAgIGlmIChpc0VtcHR5KGl0ZW1zKSkgeyByZXR1cm47IH1cclxuICAgIGlmIChpc0FycmF5KGl0ZW1zKSkge1xyXG4gICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgaXRlbXMpIHtcclxuICAgICAgICBpZiAoaXNFbXB0eShpdGVtKSkgeyBjb250aW51ZTsgfVxyXG4gICAgICAgIGlmIChpc0FycmF5KGl0ZW0pICYmIGl0ZW0ubGVuZ3RoID49IDIpIHtcclxuICAgICAgICAgIGlmIChpc0VtcHR5KGl0ZW1bMF0pIHx8IGlzRW1wdHkoaXRlbVsxXSkpIHsgY29udGludWU7IH1cclxuICAgICAgICAgIGNvbnN0IHZhbHVlID0gZ2V0Q29weSA/XHJcbiAgICAgICAgICAgIHRoaXMuZ2V0Q29weShpdGVtWzBdLCBpdGVtWzFdKSA6XHJcbiAgICAgICAgICAgIHRoaXMuZ2V0KGl0ZW1bMF0sIGl0ZW1bMV0pO1xyXG4gICAgICAgICAgaWYgKHZhbHVlKSB7IHJldHVybiB2YWx1ZTsgfVxyXG4gICAgICAgICAgY29udGludWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ2dldEZpcnN0IGVycm9yOiBJbnB1dCBub3QgaW4gY29ycmVjdCBmb3JtYXQuXFxuJyArXHJcbiAgICAgICAgICAnU2hvdWxkIGJlOiBbIFsgb2JqZWN0MSwgcG9pbnRlcjEgXSwgWyBvYmplY3QgMiwgcG9pbnRlcjIgXSwgZXRjLi4uIF0nKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTtcclxuICAgIH1cclxuICAgIGlmIChpc01hcChpdGVtcykpIHtcclxuICAgICAgZm9yIChjb25zdCBbb2JqZWN0LCBwb2ludGVyXSBvZiBpdGVtcykge1xyXG4gICAgICAgIGlmIChvYmplY3QgPT09IG51bGwgfHwgIXRoaXMuaXNKc29uUG9pbnRlcihwb2ludGVyKSkgeyBjb250aW51ZTsgfVxyXG4gICAgICAgIGNvbnN0IHZhbHVlID0gZ2V0Q29weSA/XHJcbiAgICAgICAgICB0aGlzLmdldENvcHkob2JqZWN0LCBwb2ludGVyKSA6XHJcbiAgICAgICAgICB0aGlzLmdldChvYmplY3QsIHBvaW50ZXIpO1xyXG4gICAgICAgIGlmICh2YWx1ZSkgeyByZXR1cm4gdmFsdWU7IH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZGVmYXVsdFZhbHVlO1xyXG4gICAgfVxyXG4gICAgY29uc29sZS5lcnJvcignZ2V0Rmlyc3QgZXJyb3I6IElucHV0IG5vdCBpbiBjb3JyZWN0IGZvcm1hdC5cXG4nICtcclxuICAgICAgJ1Nob3VsZCBiZTogWyBbIG9iamVjdDEsIHBvaW50ZXIxIF0sIFsgb2JqZWN0IDIsIHBvaW50ZXIyIF0sIGV0Yy4uLiBdJyk7XHJcbiAgICByZXR1cm4gZGVmYXVsdFZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ2dldEZpcnN0Q29weScgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIFNpbWlsYXIgdG8gZ2V0Rmlyc3QsIGJ1dCBhbHdheXMgcmV0dXJucyBhIGNvcHkuXHJcbiAgICpcclxuICAgKiAvLyAgeyBbb2JqZWN0LCBwb2ludGVyXVtdIH0gaXRlbXMgLSBBcnJheSBvZiBvYmplY3RzIGFuZCBwb2ludGVycyB0byBjaGVja1xyXG4gICAqIC8vICB7IGFueSA9IG51bGwgfSBkZWZhdWx0VmFsdWUgLSBWYWx1ZSB0byByZXR1cm4gaWYgbm90aGluZyBmb3VuZFxyXG4gICAqIC8vICAtIENvcHkgb2YgZmlyc3QgdmFsdWUgZm91bmRcclxuICAgKi9cclxuICBzdGF0aWMgZ2V0Rmlyc3RDb3B5KGl0ZW1zLCBkZWZhdWx0VmFsdWU6IGFueSA9IG51bGwpIHtcclxuICAgIGNvbnN0IGZpcnN0Q29weSA9IHRoaXMuZ2V0Rmlyc3QoaXRlbXMsIGRlZmF1bHRWYWx1ZSwgdHJ1ZSk7XHJcbiAgICByZXR1cm4gZmlyc3RDb3B5O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ3NldCcgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIFVzZXMgYSBKU09OIFBvaW50ZXIgdG8gc2V0IGEgdmFsdWUgb24gYW4gb2JqZWN0LlxyXG4gICAqIEFsc28gY3JlYXRlcyBhbnkgbWlzc2luZyBzdWIgb2JqZWN0cyBvciBhcnJheXMgdG8gY29udGFpbiB0aGF0IHZhbHVlLlxyXG4gICAqXHJcbiAgICogSWYgdGhlIG9wdGlvbmFsIGZvdXJ0aCBwYXJhbWV0ZXIgaXMgVFJVRSBhbmQgdGhlIGlubmVyLW1vc3QgY29udGFpbmVyXHJcbiAgICogaXMgYW4gYXJyYXksIHRoZSBmdW5jdGlvbiB3aWxsIGluc2VydCB0aGUgdmFsdWUgYXMgYSBuZXcgaXRlbSBhdCB0aGVcclxuICAgKiBzcGVjaWZpZWQgbG9jYXRpb24gaW4gdGhlIGFycmF5LCByYXRoZXIgdGhhbiBvdmVyd3JpdGluZyB0aGUgZXhpc3RpbmdcclxuICAgKiB2YWx1ZSAoaWYgYW55KSBhdCB0aGF0IGxvY2F0aW9uLlxyXG4gICAqXHJcbiAgICogU28gc2V0KFsxLCAyLCAzXSwgJy8xJywgNCkgPT4gWzEsIDQsIDNdXHJcbiAgICogYW5kXHJcbiAgICogU28gc2V0KFsxLCAyLCAzXSwgJy8xJywgNCwgdHJ1ZSkgPT4gWzEsIDQsIDIsIDNdXHJcbiAgICpcclxuICAgKiAvLyAgeyBvYmplY3QgfSBvYmplY3QgLSBUaGUgb2JqZWN0IHRvIHNldCB2YWx1ZSBpblxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBwb2ludGVyIC0gVGhlIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KVxyXG4gICAqIC8vICAgdmFsdWUgLSBUaGUgbmV3IHZhbHVlIHRvIHNldFxyXG4gICAqIC8vICB7IGJvb2xlYW4gfSBpbnNlcnQgLSBpbnNlcnQgdmFsdWU/XHJcbiAgICogLy8geyBvYmplY3QgfSAtIFRoZSBvcmlnaW5hbCBvYmplY3QsIG1vZGlmaWVkIHdpdGggdGhlIHNldCB2YWx1ZVxyXG4gICAqL1xyXG4gIHN0YXRpYyBzZXQob2JqZWN0LCBwb2ludGVyLCB2YWx1ZSwgaW5zZXJ0ID0gZmFsc2UpIHtcclxuICAgIGNvbnN0IGtleUFycmF5ID0gdGhpcy5wYXJzZShwb2ludGVyKTtcclxuICAgIGlmIChrZXlBcnJheSAhPT0gbnVsbCAmJiBrZXlBcnJheS5sZW5ndGgpIHtcclxuICAgICAgbGV0IHN1Yk9iamVjdCA9IG9iamVjdDtcclxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlBcnJheS5sZW5ndGggLSAxOyArK2kpIHtcclxuICAgICAgICBsZXQga2V5ID0ga2V5QXJyYXlbaV07XHJcbiAgICAgICAgaWYgKGtleSA9PT0gJy0nICYmIGlzQXJyYXkoc3ViT2JqZWN0KSkge1xyXG4gICAgICAgICAga2V5ID0gc3ViT2JqZWN0Lmxlbmd0aDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGlzTWFwKHN1Yk9iamVjdCkgJiYgc3ViT2JqZWN0LmhhcyhrZXkpKSB7XHJcbiAgICAgICAgICBzdWJPYmplY3QgPSBzdWJPYmplY3QuZ2V0KGtleSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGlmICghaGFzT3duKHN1Yk9iamVjdCwga2V5KSkge1xyXG4gICAgICAgICAgICBzdWJPYmplY3Rba2V5XSA9IChrZXlBcnJheVtpICsgMV0ubWF0Y2goL14oXFxkK3wtKSQvKSkgPyBbXSA6IHt9O1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgc3ViT2JqZWN0ID0gc3ViT2JqZWN0W2tleV07XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGNvbnN0IGxhc3RLZXkgPSBrZXlBcnJheVtrZXlBcnJheS5sZW5ndGggLSAxXTtcclxuICAgICAgaWYgKGlzQXJyYXkoc3ViT2JqZWN0KSAmJiBsYXN0S2V5ID09PSAnLScpIHtcclxuICAgICAgICBzdWJPYmplY3QucHVzaCh2YWx1ZSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoaW5zZXJ0ICYmIGlzQXJyYXkoc3ViT2JqZWN0KSAmJiAhaXNOYU4oK2xhc3RLZXkpKSB7XHJcbiAgICAgICAgc3ViT2JqZWN0LnNwbGljZShsYXN0S2V5LCAwLCB2YWx1ZSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoaXNNYXAoc3ViT2JqZWN0KSkge1xyXG4gICAgICAgIHN1Yk9iamVjdC5zZXQobGFzdEtleSwgdmFsdWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHN1Yk9iamVjdFtsYXN0S2V5XSA9IHZhbHVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmplY3Q7XHJcbiAgICB9XHJcbiAgICBjb25zb2xlLmVycm9yKGBzZXQgZXJyb3I6IEludmFsaWQgSlNPTiBQb2ludGVyOiAke3BvaW50ZXJ9YCk7XHJcbiAgICByZXR1cm4gb2JqZWN0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ3NldENvcHknIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBDb3BpZXMgYW4gb2JqZWN0IGFuZCB1c2VzIGEgSlNPTiBQb2ludGVyIHRvIHNldCBhIHZhbHVlIG9uIHRoZSBjb3B5LlxyXG4gICAqIEFsc28gY3JlYXRlcyBhbnkgbWlzc2luZyBzdWIgb2JqZWN0cyBvciBhcnJheXMgdG8gY29udGFpbiB0aGF0IHZhbHVlLlxyXG4gICAqXHJcbiAgICogSWYgdGhlIG9wdGlvbmFsIGZvdXJ0aCBwYXJhbWV0ZXIgaXMgVFJVRSBhbmQgdGhlIGlubmVyLW1vc3QgY29udGFpbmVyXHJcbiAgICogaXMgYW4gYXJyYXksIHRoZSBmdW5jdGlvbiB3aWxsIGluc2VydCB0aGUgdmFsdWUgYXMgYSBuZXcgaXRlbSBhdCB0aGVcclxuICAgKiBzcGVjaWZpZWQgbG9jYXRpb24gaW4gdGhlIGFycmF5LCByYXRoZXIgdGhhbiBvdmVyd3JpdGluZyB0aGUgZXhpc3RpbmcgdmFsdWUuXHJcbiAgICpcclxuICAgKiAvLyAgeyBvYmplY3QgfSBvYmplY3QgLSBUaGUgb2JqZWN0IHRvIGNvcHkgYW5kIHNldCB2YWx1ZSBpblxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBwb2ludGVyIC0gVGhlIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KVxyXG4gICAqIC8vICAgdmFsdWUgLSBUaGUgdmFsdWUgdG8gc2V0XHJcbiAgICogLy8gIHsgYm9vbGVhbiB9IGluc2VydCAtIGluc2VydCB2YWx1ZT9cclxuICAgKiAvLyB7IG9iamVjdCB9IC0gVGhlIG5ldyBvYmplY3Qgd2l0aCB0aGUgc2V0IHZhbHVlXHJcbiAgICovXHJcbiAgc3RhdGljIHNldENvcHkob2JqZWN0LCBwb2ludGVyLCB2YWx1ZSwgaW5zZXJ0ID0gZmFsc2UpIHtcclxuICAgIGNvbnN0IGtleUFycmF5ID0gdGhpcy5wYXJzZShwb2ludGVyKTtcclxuICAgIGlmIChrZXlBcnJheSAhPT0gbnVsbCkge1xyXG4gICAgICBjb25zdCBuZXdPYmplY3QgPSBjb3B5KG9iamVjdCk7XHJcbiAgICAgIGxldCBzdWJPYmplY3QgPSBuZXdPYmplY3Q7XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5QXJyYXkubGVuZ3RoIC0gMTsgKytpKSB7XHJcbiAgICAgICAgbGV0IGtleSA9IGtleUFycmF5W2ldO1xyXG4gICAgICAgIGlmIChrZXkgPT09ICctJyAmJiBpc0FycmF5KHN1Yk9iamVjdCkpIHtcclxuICAgICAgICAgIGtleSA9IHN1Yk9iamVjdC5sZW5ndGg7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChpc01hcChzdWJPYmplY3QpICYmIHN1Yk9iamVjdC5oYXMoa2V5KSkge1xyXG4gICAgICAgICAgc3ViT2JqZWN0LnNldChrZXksIGNvcHkoc3ViT2JqZWN0LmdldChrZXkpKSk7XHJcbiAgICAgICAgICBzdWJPYmplY3QgPSBzdWJPYmplY3QuZ2V0KGtleSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGlmICghaGFzT3duKHN1Yk9iamVjdCwga2V5KSkge1xyXG4gICAgICAgICAgICBzdWJPYmplY3Rba2V5XSA9IChrZXlBcnJheVtpICsgMV0ubWF0Y2goL14oXFxkK3wtKSQvKSkgPyBbXSA6IHt9O1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgc3ViT2JqZWN0W2tleV0gPSBjb3B5KHN1Yk9iamVjdFtrZXldKTtcclxuICAgICAgICAgIHN1Yk9iamVjdCA9IHN1Yk9iamVjdFtrZXldO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBjb25zdCBsYXN0S2V5ID0ga2V5QXJyYXlba2V5QXJyYXkubGVuZ3RoIC0gMV07XHJcbiAgICAgIGlmIChpc0FycmF5KHN1Yk9iamVjdCkgJiYgbGFzdEtleSA9PT0gJy0nKSB7XHJcbiAgICAgICAgc3ViT2JqZWN0LnB1c2godmFsdWUpO1xyXG4gICAgICB9IGVsc2UgaWYgKGluc2VydCAmJiBpc0FycmF5KHN1Yk9iamVjdCkgJiYgIWlzTmFOKCtsYXN0S2V5KSkge1xyXG4gICAgICAgIHN1Yk9iamVjdC5zcGxpY2UobGFzdEtleSwgMCwgdmFsdWUpO1xyXG4gICAgICB9IGVsc2UgaWYgKGlzTWFwKHN1Yk9iamVjdCkpIHtcclxuICAgICAgICBzdWJPYmplY3Quc2V0KGxhc3RLZXksIHZhbHVlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzdWJPYmplY3RbbGFzdEtleV0gPSB2YWx1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gbmV3T2JqZWN0O1xyXG4gICAgfVxyXG4gICAgY29uc29sZS5lcnJvcihgc2V0Q29weSBlcnJvcjogSW52YWxpZCBKU09OIFBvaW50ZXI6ICR7cG9pbnRlcn1gKTtcclxuICAgIHJldHVybiBvYmplY3Q7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnaW5zZXJ0JyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogQ2FsbHMgJ3NldCcgd2l0aCBpbnNlcnQgPSBUUlVFXHJcbiAgICpcclxuICAgKiAvLyAgeyBvYmplY3QgfSBvYmplY3QgLSBvYmplY3QgdG8gaW5zZXJ0IHZhbHVlIGluXHJcbiAgICogLy8gIHsgUG9pbnRlciB9IHBvaW50ZXIgLSBKU09OIFBvaW50ZXIgKHN0cmluZyBvciBhcnJheSlcclxuICAgKiAvLyAgIHZhbHVlIC0gdmFsdWUgdG8gaW5zZXJ0XHJcbiAgICogLy8geyBvYmplY3QgfVxyXG4gICAqL1xyXG4gIHN0YXRpYyBpbnNlcnQob2JqZWN0LCBwb2ludGVyLCB2YWx1ZSkge1xyXG4gICAgY29uc3QgdXBkYXRlZE9iamVjdCA9IHRoaXMuc2V0KG9iamVjdCwgcG9pbnRlciwgdmFsdWUsIHRydWUpO1xyXG4gICAgcmV0dXJuIHVwZGF0ZWRPYmplY3Q7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnaW5zZXJ0Q29weScgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIENhbGxzICdzZXRDb3B5JyB3aXRoIGluc2VydCA9IFRSVUVcclxuICAgKlxyXG4gICAqIC8vICB7IG9iamVjdCB9IG9iamVjdCAtIG9iamVjdCB0byBpbnNlcnQgdmFsdWUgaW5cclxuICAgKiAvLyAgeyBQb2ludGVyIH0gcG9pbnRlciAtIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KVxyXG4gICAqIC8vICAgdmFsdWUgLSB2YWx1ZSB0byBpbnNlcnRcclxuICAgKiAvLyB7IG9iamVjdCB9XHJcbiAgICovXHJcbiAgc3RhdGljIGluc2VydENvcHkob2JqZWN0LCBwb2ludGVyLCB2YWx1ZSkge1xyXG4gICAgY29uc3QgdXBkYXRlZE9iamVjdCA9IHRoaXMuc2V0Q29weShvYmplY3QsIHBvaW50ZXIsIHZhbHVlLCB0cnVlKTtcclxuICAgIHJldHVybiB1cGRhdGVkT2JqZWN0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ3JlbW92ZScgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIFVzZXMgYSBKU09OIFBvaW50ZXIgdG8gcmVtb3ZlIGEga2V5IGFuZCBpdHMgYXR0cmlidXRlIGZyb20gYW4gb2JqZWN0XHJcbiAgICpcclxuICAgKiAvLyAgeyBvYmplY3QgfSBvYmplY3QgLSBvYmplY3QgdG8gZGVsZXRlIGF0dHJpYnV0ZSBmcm9tXHJcbiAgICogLy8gIHsgUG9pbnRlciB9IHBvaW50ZXIgLSBKU09OIFBvaW50ZXIgKHN0cmluZyBvciBhcnJheSlcclxuICAgKiAvLyB7IG9iamVjdCB9XHJcbiAgICovXHJcbiAgc3RhdGljIHJlbW92ZShvYmplY3QsIHBvaW50ZXIpIHtcclxuICAgIGNvbnN0IGtleUFycmF5ID0gdGhpcy5wYXJzZShwb2ludGVyKTtcclxuICAgIGlmIChrZXlBcnJheSAhPT0gbnVsbCAmJiBrZXlBcnJheS5sZW5ndGgpIHtcclxuICAgICAgbGV0IGxhc3RLZXkgPSBrZXlBcnJheS5wb3AoKTtcclxuICAgICAgY29uc3QgcGFyZW50T2JqZWN0ID0gdGhpcy5nZXQob2JqZWN0LCBrZXlBcnJheSk7XHJcbiAgICAgIGlmIChpc0FycmF5KHBhcmVudE9iamVjdCkpIHtcclxuICAgICAgICBpZiAobGFzdEtleSA9PT0gJy0nKSB7IGxhc3RLZXkgPSBwYXJlbnRPYmplY3QubGVuZ3RoIC0gMTsgfVxyXG4gICAgICAgIHBhcmVudE9iamVjdC5zcGxpY2UobGFzdEtleSwgMSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoaXNPYmplY3QocGFyZW50T2JqZWN0KSkge1xyXG4gICAgICAgIGRlbGV0ZSBwYXJlbnRPYmplY3RbbGFzdEtleV07XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9iamVjdDtcclxuICAgIH1cclxuICAgIGNvbnNvbGUuZXJyb3IoYHJlbW92ZSBlcnJvcjogSW52YWxpZCBKU09OIFBvaW50ZXI6ICR7cG9pbnRlcn1gKTtcclxuICAgIHJldHVybiBvYmplY3Q7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnaGFzJyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogVGVzdHMgaWYgYW4gb2JqZWN0IGhhcyBhIHZhbHVlIGF0IHRoZSBsb2NhdGlvbiBzcGVjaWZpZWQgYnkgYSBKU09OIFBvaW50ZXJcclxuICAgKlxyXG4gICAqIC8vICB7IG9iamVjdCB9IG9iamVjdCAtIG9iamVjdCB0byBjaGVrIGZvciB2YWx1ZVxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBwb2ludGVyIC0gSlNPTiBQb2ludGVyIChzdHJpbmcgb3IgYXJyYXkpXHJcbiAgICogLy8geyBib29sZWFuIH1cclxuICAgKi9cclxuICBzdGF0aWMgaGFzKG9iamVjdCwgcG9pbnRlcikge1xyXG4gICAgY29uc3QgaGFzVmFsdWUgPSB0aGlzLmdldChvYmplY3QsIHBvaW50ZXIsIDAsIG51bGwsIHRydWUpO1xyXG4gICAgcmV0dXJuIGhhc1ZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ2RpY3QnIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBSZXR1cm5zIGEgKHBvaW50ZXIgLT4gdmFsdWUpIGRpY3Rpb25hcnkgZm9yIGFuIG9iamVjdFxyXG4gICAqXHJcbiAgICogLy8gIHsgb2JqZWN0IH0gb2JqZWN0IC0gVGhlIG9iamVjdCB0byBjcmVhdGUgYSBkaWN0aW9uYXJ5IGZyb21cclxuICAgKiAvLyB7IG9iamVjdCB9IC0gVGhlIHJlc3VsdGluZyBkaWN0aW9uYXJ5IG9iamVjdFxyXG4gICAqL1xyXG4gIHN0YXRpYyBkaWN0KG9iamVjdCkge1xyXG4gICAgY29uc3QgcmVzdWx0czogYW55ID0ge307XHJcbiAgICB0aGlzLmZvckVhY2hEZWVwKG9iamVjdCwgKHZhbHVlLCBwb2ludGVyKSA9PiB7XHJcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnKSB7IHJlc3VsdHNbcG9pbnRlcl0gPSB2YWx1ZTsgfVxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gcmVzdWx0cztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqICdmb3JFYWNoRGVlcCcgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIEl0ZXJhdGVzIG92ZXIgb3duIGVudW1lcmFibGUgcHJvcGVydGllcyBvZiBhbiBvYmplY3Qgb3IgaXRlbXMgaW4gYW4gYXJyYXlcclxuICAgKiBhbmQgaW52b2tlcyBhbiBpdGVyYXRlZSBmdW5jdGlvbiBmb3IgZWFjaCBrZXkvdmFsdWUgb3IgaW5kZXgvdmFsdWUgcGFpci5cclxuICAgKiBCeSBkZWZhdWx0LCBpdGVyYXRlcyBvdmVyIGl0ZW1zIHdpdGhpbiBvYmplY3RzIGFuZCBhcnJheXMgYWZ0ZXIgY2FsbGluZ1xyXG4gICAqIHRoZSBpdGVyYXRlZSBmdW5jdGlvbiBvbiB0aGUgY29udGFpbmluZyBvYmplY3Qgb3IgYXJyYXkgaXRzZWxmLlxyXG4gICAqXHJcbiAgICogVGhlIGl0ZXJhdGVlIGlzIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM6ICh2YWx1ZSwgcG9pbnRlciwgcm9vdE9iamVjdCksXHJcbiAgICogd2hlcmUgcG9pbnRlciBpcyBhIEpTT04gcG9pbnRlciBpbmRpY2F0aW5nIHRoZSBsb2NhdGlvbiBvZiB0aGUgY3VycmVudFxyXG4gICAqIHZhbHVlIHdpdGhpbiB0aGUgcm9vdCBvYmplY3QsIGFuZCByb290T2JqZWN0IGlzIHRoZSByb290IG9iamVjdCBpbml0aWFsbHlcclxuICAgKiBzdWJtaXR0ZWQgdG8gdGggZnVuY3Rpb24uXHJcbiAgICpcclxuICAgKiBJZiBhIHRoaXJkIG9wdGlvbmFsIHBhcmFtZXRlciAnYm90dG9tVXAnIGlzIHNldCB0byBUUlVFLCB0aGUgaXRlcmF0b3JcclxuICAgKiBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCBvbiBzdWItb2JqZWN0cyBhbmQgYXJyYXlzIGFmdGVyIGJlaW5nXHJcbiAgICogY2FsbGVkIG9uIHRoZWlyIGNvbnRlbnRzLCByYXRoZXIgdGhhbiBiZWZvcmUsIHdoaWNoIGlzIHRoZSBkZWZhdWx0LlxyXG4gICAqXHJcbiAgICogVGhpcyBmdW5jdGlvbiBjYW4gYWxzbyBvcHRpb25hbGx5IGJlIGNhbGxlZCBkaXJlY3RseSBvbiBhIHN1Yi1vYmplY3QgYnlcclxuICAgKiBpbmNsdWRpbmcgb3B0aW9uYWwgNHRoIGFuZCA1dGggcGFyYW1ldGVyc3MgdG8gc3BlY2lmeSB0aGUgaW5pdGlhbFxyXG4gICAqIHJvb3Qgb2JqZWN0IGFuZCBwb2ludGVyLlxyXG4gICAqXHJcbiAgICogLy8gIHsgb2JqZWN0IH0gb2JqZWN0IC0gdGhlIGluaXRpYWwgb2JqZWN0IG9yIGFycmF5XHJcbiAgICogLy8gIHsgKHY6IGFueSwgcD86IHN0cmluZywgbz86IGFueSkgPT4gYW55IH0gZnVuY3Rpb24gLSBpdGVyYXRlZSBmdW5jdGlvblxyXG4gICAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IGJvdHRvbVVwIC0gb3B0aW9uYWwsIHNldCB0byBUUlVFIHRvIHJldmVyc2UgZGlyZWN0aW9uXHJcbiAgICogLy8gIHsgb2JqZWN0ID0gb2JqZWN0IH0gcm9vdE9iamVjdCAtIG9wdGlvbmFsLCByb290IG9iamVjdCBvciBhcnJheVxyXG4gICAqIC8vICB7IHN0cmluZyA9ICcnIH0gcG9pbnRlciAtIG9wdGlvbmFsLCBKU09OIFBvaW50ZXIgdG8gb2JqZWN0IHdpdGhpbiByb290T2JqZWN0XHJcbiAgICogLy8geyBvYmplY3QgfSAtIFRoZSBtb2RpZmllZCBvYmplY3RcclxuICAgKi9cclxuICBzdGF0aWMgZm9yRWFjaERlZXAoXHJcbiAgICBvYmplY3QsIGZuOiAodjogYW55LCBwPzogc3RyaW5nLCBvPzogYW55KSA9PiBhbnkgPSAodikgPT4gdixcclxuICAgIGJvdHRvbVVwID0gZmFsc2UsIHBvaW50ZXIgPSAnJywgcm9vdE9iamVjdCA9IG9iamVjdFxyXG4gICkge1xyXG4gICAgaWYgKHR5cGVvZiBmbiAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBjb25zb2xlLmVycm9yKGBmb3JFYWNoRGVlcCBlcnJvcjogSXRlcmF0b3IgaXMgbm90IGEgZnVuY3Rpb246YCwgZm4pO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBpZiAoIWJvdHRvbVVwKSB7IGZuKG9iamVjdCwgcG9pbnRlciwgcm9vdE9iamVjdCk7IH1cclxuICAgIGlmIChpc09iamVjdChvYmplY3QpIHx8IGlzQXJyYXkob2JqZWN0KSkge1xyXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhvYmplY3QpKSB7XHJcbiAgICAgICAgY29uc3QgbmV3UG9pbnRlciA9IHBvaW50ZXIgKyAnLycgKyB0aGlzLmVzY2FwZShrZXkpO1xyXG4gICAgICAgIHRoaXMuZm9yRWFjaERlZXAob2JqZWN0W2tleV0sIGZuLCBib3R0b21VcCwgbmV3UG9pbnRlciwgcm9vdE9iamVjdCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmIChib3R0b21VcCkgeyBmbihvYmplY3QsIHBvaW50ZXIsIHJvb3RPYmplY3QpOyB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnZm9yRWFjaERlZXBDb3B5JyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogU2ltaWxhciB0byBmb3JFYWNoRGVlcCwgYnV0IHJldHVybnMgYSBjb3B5IG9mIHRoZSBvcmlnaW5hbCBvYmplY3QsIHdpdGhcclxuICAgKiB0aGUgc2FtZSBrZXlzIGFuZCBpbmRleGVzLCBidXQgd2l0aCB2YWx1ZXMgcmVwbGFjZWQgd2l0aCB0aGUgcmVzdWx0IG9mXHJcbiAgICogdGhlIGl0ZXJhdGVlIGZ1bmN0aW9uLlxyXG4gICAqXHJcbiAgICogLy8gIHsgb2JqZWN0IH0gb2JqZWN0IC0gdGhlIGluaXRpYWwgb2JqZWN0IG9yIGFycmF5XHJcbiAgICogLy8gIHsgKHY6IGFueSwgaz86IHN0cmluZywgbz86IGFueSwgcD86IGFueSkgPT4gYW55IH0gZnVuY3Rpb24gLSBpdGVyYXRlZSBmdW5jdGlvblxyXG4gICAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IGJvdHRvbVVwIC0gb3B0aW9uYWwsIHNldCB0byBUUlVFIHRvIHJldmVyc2UgZGlyZWN0aW9uXHJcbiAgICogLy8gIHsgb2JqZWN0ID0gb2JqZWN0IH0gcm9vdE9iamVjdCAtIG9wdGlvbmFsLCByb290IG9iamVjdCBvciBhcnJheVxyXG4gICAqIC8vICB7IHN0cmluZyA9ICcnIH0gcG9pbnRlciAtIG9wdGlvbmFsLCBKU09OIFBvaW50ZXIgdG8gb2JqZWN0IHdpdGhpbiByb290T2JqZWN0XHJcbiAgICogLy8geyBvYmplY3QgfSAtIFRoZSBjb3BpZWQgb2JqZWN0XHJcbiAgICovXHJcbiAgc3RhdGljIGZvckVhY2hEZWVwQ29weShcclxuICAgIG9iamVjdCwgZm46ICh2OiBhbnksIHA/OiBzdHJpbmcsIG8/OiBhbnkpID0+IGFueSA9ICh2KSA9PiB2LFxyXG4gICAgYm90dG9tVXAgPSBmYWxzZSwgcG9pbnRlciA9ICcnLCByb290T2JqZWN0ID0gb2JqZWN0XHJcbiAgKSB7XHJcbiAgICBpZiAodHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoYGZvckVhY2hEZWVwQ29weSBlcnJvcjogSXRlcmF0b3IgaXMgbm90IGEgZnVuY3Rpb246YCwgZm4pO1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICAgIGlmIChpc09iamVjdChvYmplY3QpIHx8IGlzQXJyYXkob2JqZWN0KSkge1xyXG4gICAgICBsZXQgbmV3T2JqZWN0ID0gaXNBcnJheShvYmplY3QpID8gWyAuLi5vYmplY3QgXSA6IHsgLi4ub2JqZWN0IH07XHJcbiAgICAgIGlmICghYm90dG9tVXApIHsgbmV3T2JqZWN0ID0gZm4obmV3T2JqZWN0LCBwb2ludGVyLCByb290T2JqZWN0KTsgfVxyXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhuZXdPYmplY3QpKSB7XHJcbiAgICAgICAgY29uc3QgbmV3UG9pbnRlciA9IHBvaW50ZXIgKyAnLycgKyB0aGlzLmVzY2FwZShrZXkpO1xyXG4gICAgICAgIG5ld09iamVjdFtrZXldID0gdGhpcy5mb3JFYWNoRGVlcENvcHkoXHJcbiAgICAgICAgICBuZXdPYmplY3Rba2V5XSwgZm4sIGJvdHRvbVVwLCBuZXdQb2ludGVyLCByb290T2JqZWN0XHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoYm90dG9tVXApIHsgbmV3T2JqZWN0ID0gZm4obmV3T2JqZWN0LCBwb2ludGVyLCByb290T2JqZWN0KTsgfVxyXG4gICAgICByZXR1cm4gbmV3T2JqZWN0O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIGZuKG9iamVjdCwgcG9pbnRlciwgcm9vdE9iamVjdCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnZXNjYXBlJyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogRXNjYXBlcyBhIHN0cmluZyByZWZlcmVuY2Uga2V5XHJcbiAgICpcclxuICAgKiAvLyAgeyBzdHJpbmcgfSBrZXkgLSBzdHJpbmcga2V5IHRvIGVzY2FwZVxyXG4gICAqIC8vIHsgc3RyaW5nIH0gLSBlc2NhcGVkIGtleVxyXG4gICAqL1xyXG4gIHN0YXRpYyBlc2NhcGUoa2V5KSB7XHJcbiAgICBjb25zdCBlc2NhcGVkID0ga2V5LnRvU3RyaW5nKCkucmVwbGFjZSgvfi9nLCAnfjAnKS5yZXBsYWNlKC9cXC8vZywgJ34xJyk7XHJcbiAgICByZXR1cm4gZXNjYXBlZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqICd1bmVzY2FwZScgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIFVuZXNjYXBlcyBhIHN0cmluZyByZWZlcmVuY2Uga2V5XHJcbiAgICpcclxuICAgKiAvLyAgeyBzdHJpbmcgfSBrZXkgLSBzdHJpbmcga2V5IHRvIHVuZXNjYXBlXHJcbiAgICogLy8geyBzdHJpbmcgfSAtIHVuZXNjYXBlZCBrZXlcclxuICAgKi9cclxuICBzdGF0aWMgdW5lc2NhcGUoa2V5KSB7XHJcbiAgICBjb25zdCB1bmVzY2FwZWQgPSBrZXkudG9TdHJpbmcoKS5yZXBsYWNlKC9+MS9nLCAnLycpLnJlcGxhY2UoL34wL2csICd+Jyk7XHJcbiAgICByZXR1cm4gdW5lc2NhcGVkO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ3BhcnNlJyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogQ29udmVydHMgYSBzdHJpbmcgSlNPTiBQb2ludGVyIGludG8gYSBhcnJheSBvZiBrZXlzXHJcbiAgICogKGlmIGlucHV0IGlzIGFscmVhZHkgYW4gYW4gYXJyYXkgb2Yga2V5cywgaXQgaXMgcmV0dXJuZWQgdW5jaGFuZ2VkKVxyXG4gICAqXHJcbiAgICogLy8gIHsgUG9pbnRlciB9IHBvaW50ZXIgLSBKU09OIFBvaW50ZXIgKHN0cmluZyBvciBhcnJheSlcclxuICAgKiAvLyAgeyBib29sZWFuID0gZmFsc2UgfSBlcnJvcnMgLSBTaG93IGVycm9yIGlmIGludmFsaWQgcG9pbnRlcj9cclxuICAgKiAvLyB7IHN0cmluZ1tdIH0gLSBKU09OIFBvaW50ZXIgYXJyYXkgb2Yga2V5c1xyXG4gICAqL1xyXG4gIHN0YXRpYyBwYXJzZShwb2ludGVyLCBlcnJvcnMgPSBmYWxzZSkge1xyXG4gICAgaWYgKCF0aGlzLmlzSnNvblBvaW50ZXIocG9pbnRlcikpIHtcclxuICAgICAgaWYgKGVycm9ycykgeyBjb25zb2xlLmVycm9yKGBwYXJzZSBlcnJvcjogSW52YWxpZCBKU09OIFBvaW50ZXI6ICR7cG9pbnRlcn1gKTsgfVxyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICAgIGlmIChpc0FycmF5KHBvaW50ZXIpKSB7IHJldHVybiA8c3RyaW5nW10+cG9pbnRlcjsgfVxyXG4gICAgaWYgKHR5cGVvZiBwb2ludGVyID09PSAnc3RyaW5nJykge1xyXG4gICAgICBpZiAoKDxzdHJpbmc+cG9pbnRlcilbMF0gPT09ICcjJykgeyBwb2ludGVyID0gcG9pbnRlci5zbGljZSgxKTsgfVxyXG4gICAgICBpZiAoPHN0cmluZz5wb2ludGVyID09PSAnJyB8fCA8c3RyaW5nPnBvaW50ZXIgPT09ICcvJykgeyByZXR1cm4gW107IH1cclxuICAgICAgcmV0dXJuICg8c3RyaW5nPnBvaW50ZXIpLnNsaWNlKDEpLnNwbGl0KCcvJykubWFwKHRoaXMudW5lc2NhcGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ2NvbXBpbGUnIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBDb252ZXJ0cyBhbiBhcnJheSBvZiBrZXlzIGludG8gYSBKU09OIFBvaW50ZXIgc3RyaW5nXHJcbiAgICogKGlmIGlucHV0IGlzIGFscmVhZHkgYSBzdHJpbmcsIGl0IGlzIG5vcm1hbGl6ZWQgYW5kIHJldHVybmVkKVxyXG4gICAqXHJcbiAgICogVGhlIG9wdGlvbmFsIHNlY29uZCBwYXJhbWV0ZXIgaXMgYSBkZWZhdWx0IHdoaWNoIHdpbGwgcmVwbGFjZSBhbnkgZW1wdHkga2V5cy5cclxuICAgKlxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBwb2ludGVyIC0gSlNPTiBQb2ludGVyIChzdHJpbmcgb3IgYXJyYXkpXHJcbiAgICogLy8gIHsgc3RyaW5nIHwgbnVtYmVyID0gJycgfSBkZWZhdWx0VmFsdWUgLSBEZWZhdWx0IHZhbHVlXHJcbiAgICogLy8gIHsgYm9vbGVhbiA9IGZhbHNlIH0gZXJyb3JzIC0gU2hvdyBlcnJvciBpZiBpbnZhbGlkIHBvaW50ZXI/XHJcbiAgICogLy8geyBzdHJpbmcgfSAtIEpTT04gUG9pbnRlciBzdHJpbmdcclxuICAgKi9cclxuICBzdGF0aWMgY29tcGlsZShwb2ludGVyLCBkZWZhdWx0VmFsdWUgPSAnJywgZXJyb3JzID0gZmFsc2UpIHtcclxuICAgIGlmIChwb2ludGVyID09PSAnIycpIHsgcmV0dXJuICcnOyB9XHJcbiAgICBpZiAoIXRoaXMuaXNKc29uUG9pbnRlcihwb2ludGVyKSkge1xyXG4gICAgICBpZiAoZXJyb3JzKSB7IGNvbnNvbGUuZXJyb3IoYGNvbXBpbGUgZXJyb3I6IEludmFsaWQgSlNPTiBQb2ludGVyOiAke3BvaW50ZXJ9YCk7IH1cclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgICBpZiAoaXNBcnJheShwb2ludGVyKSkge1xyXG4gICAgICBpZiAoKDxzdHJpbmdbXT5wb2ludGVyKS5sZW5ndGggPT09IDApIHsgcmV0dXJuICcnOyB9XHJcbiAgICAgIHJldHVybiAnLycgKyAoPHN0cmluZ1tdPnBvaW50ZXIpLm1hcChcclxuICAgICAgICBrZXkgPT4ga2V5ID09PSAnJyA/IGRlZmF1bHRWYWx1ZSA6IHRoaXMuZXNjYXBlKGtleSlcclxuICAgICAgKS5qb2luKCcvJyk7XHJcbiAgICB9XHJcbiAgICBpZiAodHlwZW9mIHBvaW50ZXIgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIGlmIChwb2ludGVyWzBdID09PSAnIycpIHsgcG9pbnRlciA9IHBvaW50ZXIuc2xpY2UoMSk7IH1cclxuICAgICAgcmV0dXJuIHBvaW50ZXI7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAndG9LZXknIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBFeHRyYWN0cyBuYW1lIG9mIHRoZSBmaW5hbCBrZXkgZnJvbSBhIEpTT04gUG9pbnRlci5cclxuICAgKlxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBwb2ludGVyIC0gSlNPTiBQb2ludGVyIChzdHJpbmcgb3IgYXJyYXkpXHJcbiAgICogLy8gIHsgYm9vbGVhbiA9IGZhbHNlIH0gZXJyb3JzIC0gU2hvdyBlcnJvciBpZiBpbnZhbGlkIHBvaW50ZXI/XHJcbiAgICogLy8geyBzdHJpbmcgfSAtIHRoZSBleHRyYWN0ZWQga2V5XHJcbiAgICovXHJcbiAgc3RhdGljIHRvS2V5KHBvaW50ZXIsIGVycm9ycyA9IGZhbHNlKSB7XHJcbiAgICBjb25zdCBrZXlBcnJheSA9IHRoaXMucGFyc2UocG9pbnRlciwgZXJyb3JzKTtcclxuICAgIGlmIChrZXlBcnJheSA9PT0gbnVsbCkgeyByZXR1cm4gbnVsbDsgfVxyXG4gICAgaWYgKCFrZXlBcnJheS5sZW5ndGgpIHsgcmV0dXJuICcnOyB9XHJcbiAgICByZXR1cm4ga2V5QXJyYXlba2V5QXJyYXkubGVuZ3RoIC0gMV07XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAnaXNKc29uUG9pbnRlcicgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIENoZWNrcyBhIHN0cmluZyBvciBhcnJheSB2YWx1ZSB0byBkZXRlcm1pbmUgaWYgaXQgaXMgYSB2YWxpZCBKU09OIFBvaW50ZXIuXHJcbiAgICogUmV0dXJucyB0cnVlIGlmIGEgc3RyaW5nIGlzIGVtcHR5LCBvciBzdGFydHMgd2l0aCAnLycgb3IgJyMvJy5cclxuICAgKiBSZXR1cm5zIHRydWUgaWYgYW4gYXJyYXkgY29udGFpbnMgb25seSBzdHJpbmcgdmFsdWVzLlxyXG4gICAqXHJcbiAgICogLy8gICB2YWx1ZSAtIHZhbHVlIHRvIGNoZWNrXHJcbiAgICogLy8geyBib29sZWFuIH0gLSB0cnVlIGlmIHZhbHVlIGlzIGEgdmFsaWQgSlNPTiBQb2ludGVyLCBvdGhlcndpc2UgZmFsc2VcclxuICAgKi9cclxuICBzdGF0aWMgaXNKc29uUG9pbnRlcih2YWx1ZSkge1xyXG4gICAgaWYgKGlzQXJyYXkodmFsdWUpKSB7XHJcbiAgICAgIHJldHVybiB2YWx1ZS5ldmVyeShrZXkgPT4gdHlwZW9mIGtleSA9PT0gJ3N0cmluZycpO1xyXG4gICAgfSBlbHNlIGlmIChpc1N0cmluZyh2YWx1ZSkpIHtcclxuICAgICAgaWYgKHZhbHVlID09PSAnJyB8fCB2YWx1ZSA9PT0gJyMnKSB7IHJldHVybiB0cnVlOyB9XHJcbiAgICAgIGlmICh2YWx1ZVswXSA9PT0gJy8nIHx8IHZhbHVlLnNsaWNlKDAsIDIpID09PSAnIy8nKSB7XHJcbiAgICAgICAgcmV0dXJuICEvKH5bXjAxXXx+JCkvZy50ZXN0KHZhbHVlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ2lzU3ViUG9pbnRlcicgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIENoZWNrcyB3aGV0aGVyIG9uZSBKU09OIFBvaW50ZXIgaXMgYSBzdWJzZXQgb2YgYW5vdGhlci5cclxuICAgKlxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBzaG9ydFBvaW50ZXIgLSBwb3RlbnRpYWwgc3Vic2V0IEpTT04gUG9pbnRlclxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBsb25nUG9pbnRlciAtIHBvdGVudGlhbCBzdXBlcnNldCBKU09OIFBvaW50ZXJcclxuICAgKiAvLyAgeyBib29sZWFuID0gZmFsc2UgfSB0cnVlSWZNYXRjaGluZyAtIHJldHVybiB0cnVlIGlmIHBvaW50ZXJzIG1hdGNoP1xyXG4gICAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IGVycm9ycyAtIFNob3cgZXJyb3IgaWYgaW52YWxpZCBwb2ludGVyP1xyXG4gICAqIC8vIHsgYm9vbGVhbiB9IC0gdHJ1ZSBpZiBzaG9ydFBvaW50ZXIgaXMgYSBzdWJzZXQgb2YgbG9uZ1BvaW50ZXIsIGZhbHNlIGlmIG5vdFxyXG4gICAqL1xyXG4gIHN0YXRpYyBpc1N1YlBvaW50ZXIoXHJcbiAgICBzaG9ydFBvaW50ZXIsIGxvbmdQb2ludGVyLCB0cnVlSWZNYXRjaGluZyA9IGZhbHNlLCBlcnJvcnMgPSBmYWxzZVxyXG4gICkge1xyXG4gICAgaWYgKCF0aGlzLmlzSnNvblBvaW50ZXIoc2hvcnRQb2ludGVyKSB8fCAhdGhpcy5pc0pzb25Qb2ludGVyKGxvbmdQb2ludGVyKSkge1xyXG4gICAgICBpZiAoZXJyb3JzKSB7XHJcbiAgICAgICAgbGV0IGludmFsaWQgPSAnJztcclxuICAgICAgICBpZiAoIXRoaXMuaXNKc29uUG9pbnRlcihzaG9ydFBvaW50ZXIpKSB7IGludmFsaWQgKz0gYCAxOiAke3Nob3J0UG9pbnRlcn1gOyB9XHJcbiAgICAgICAgaWYgKCF0aGlzLmlzSnNvblBvaW50ZXIobG9uZ1BvaW50ZXIpKSB7IGludmFsaWQgKz0gYCAyOiAke2xvbmdQb2ludGVyfWA7IH1cclxuICAgICAgICBjb25zb2xlLmVycm9yKGBpc1N1YlBvaW50ZXIgZXJyb3I6IEludmFsaWQgSlNPTiBQb2ludGVyICR7aW52YWxpZH1gKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBzaG9ydFBvaW50ZXIgPSB0aGlzLmNvbXBpbGUoc2hvcnRQb2ludGVyLCAnJywgZXJyb3JzKTtcclxuICAgIGxvbmdQb2ludGVyID0gdGhpcy5jb21waWxlKGxvbmdQb2ludGVyLCAnJywgZXJyb3JzKTtcclxuICAgIHJldHVybiBzaG9ydFBvaW50ZXIgPT09IGxvbmdQb2ludGVyID8gdHJ1ZUlmTWF0Y2hpbmcgOlxyXG4gICAgICBgJHtzaG9ydFBvaW50ZXJ9L2AgPT09IGxvbmdQb2ludGVyLnNsaWNlKDAsIHNob3J0UG9pbnRlci5sZW5ndGggKyAxKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqICd0b0luZGV4ZWRQb2ludGVyJyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogTWVyZ2VzIGFuIGFycmF5IG9mIG51bWVyaWMgaW5kZXhlcyBhbmQgYSBnZW5lcmljIHBvaW50ZXIgdG8gY3JlYXRlIGFuXHJcbiAgICogaW5kZXhlZCBwb2ludGVyIGZvciBhIHNwZWNpZmljIGl0ZW0uXHJcbiAgICpcclxuICAgKiBGb3IgZXhhbXBsZSwgbWVyZ2luZyB0aGUgZ2VuZXJpYyBwb2ludGVyICcvZm9vLy0vYmFyLy0vYmF6JyBhbmRcclxuICAgKiB0aGUgYXJyYXkgWzQsIDJdIHdvdWxkIHJlc3VsdCBpbiB0aGUgaW5kZXhlZCBwb2ludGVyICcvZm9vLzQvYmFyLzIvYmF6J1xyXG4gICAqXHJcbiAgICpcclxuICAgKiAvLyAgeyBQb2ludGVyIH0gZ2VuZXJpY1BvaW50ZXIgLSBUaGUgZ2VuZXJpYyBwb2ludGVyXHJcbiAgICogLy8gIHsgbnVtYmVyW10gfSBpbmRleEFycmF5IC0gVGhlIGFycmF5IG9mIG51bWVyaWMgaW5kZXhlc1xyXG4gICAqIC8vICB7IE1hcDxzdHJpbmcsIG51bWJlcj4gfSBhcnJheU1hcCAtIEFuIG9wdGlvbmFsIGFycmF5IG1hcFxyXG4gICAqIC8vIHsgc3RyaW5nIH0gLSBUaGUgbWVyZ2VkIHBvaW50ZXIgd2l0aCBpbmRleGVzXHJcbiAgICovXHJcbiAgc3RhdGljIHRvSW5kZXhlZFBvaW50ZXIoXHJcbiAgICBnZW5lcmljUG9pbnRlciwgaW5kZXhBcnJheSwgYXJyYXlNYXA6IE1hcDxzdHJpbmcsIG51bWJlcj4gPSBudWxsXHJcbiAgKSB7XHJcbiAgICBpZiAodGhpcy5pc0pzb25Qb2ludGVyKGdlbmVyaWNQb2ludGVyKSAmJiBpc0FycmF5KGluZGV4QXJyYXkpKSB7XHJcbiAgICAgIGxldCBpbmRleGVkUG9pbnRlciA9IHRoaXMuY29tcGlsZShnZW5lcmljUG9pbnRlcik7XHJcbiAgICAgIGlmIChpc01hcChhcnJheU1hcCkpIHtcclxuICAgICAgICBsZXQgYXJyYXlJbmRleCA9IDA7XHJcbiAgICAgICAgcmV0dXJuIGluZGV4ZWRQb2ludGVyLnJlcGxhY2UoL1xcL1xcLSg/PVxcL3wkKS9nLCAoa2V5LCBzdHJpbmdJbmRleCkgPT5cclxuICAgICAgICAgIGFycmF5TWFwLmhhcygoPHN0cmluZz5pbmRleGVkUG9pbnRlcikuc2xpY2UoMCwgc3RyaW5nSW5kZXgpKSA/XHJcbiAgICAgICAgICAgICcvJyArIGluZGV4QXJyYXlbYXJyYXlJbmRleCsrXSA6IGtleVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZm9yIChjb25zdCBwb2ludGVySW5kZXggb2YgaW5kZXhBcnJheSkge1xyXG4gICAgICAgICAgaW5kZXhlZFBvaW50ZXIgPSBpbmRleGVkUG9pbnRlci5yZXBsYWNlKCcvLScsICcvJyArIHBvaW50ZXJJbmRleCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBpbmRleGVkUG9pbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYgKCF0aGlzLmlzSnNvblBvaW50ZXIoZ2VuZXJpY1BvaW50ZXIpKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoYHRvSW5kZXhlZFBvaW50ZXIgZXJyb3I6IEludmFsaWQgSlNPTiBQb2ludGVyOiAke2dlbmVyaWNQb2ludGVyfWApO1xyXG4gICAgfVxyXG4gICAgaWYgKCFpc0FycmF5KGluZGV4QXJyYXkpKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoYHRvSW5kZXhlZFBvaW50ZXIgZXJyb3I6IEludmFsaWQgaW5kZXhBcnJheTogJHtpbmRleEFycmF5fWApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogJ3RvR2VuZXJpY1BvaW50ZXInIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBDb21wYXJlcyBhbiBpbmRleGVkIHBvaW50ZXIgdG8gYW4gYXJyYXkgbWFwIGFuZCByZW1vdmVzIGxpc3QgYXJyYXlcclxuICAgKiBpbmRleGVzIChidXQgbGVhdmVzIHR1cGxlIGFycnJheSBpbmRleGVzIGFuZCBhbGwgb2JqZWN0IGtleXMsIGluY2x1ZGluZ1xyXG4gICAqIG51bWVyaWMga2V5cykgdG8gY3JlYXRlIGEgZ2VuZXJpYyBwb2ludGVyLlxyXG4gICAqXHJcbiAgICogRm9yIGV4YW1wbGUsIHVzaW5nIHRoZSBpbmRleGVkIHBvaW50ZXIgJy9mb28vMS9iYXIvMi9iYXovMycgYW5kXHJcbiAgICogdGhlIGFycmF5TWFwIFtbJy9mb28nLCAwXSwgWycvZm9vLy0vYmFyJywgM10sIFsnL2Zvby8tL2Jhci8tL2JheicsIDBdXVxyXG4gICAqIHdvdWxkIHJlc3VsdCBpbiB0aGUgZ2VuZXJpYyBwb2ludGVyICcvZm9vLy0vYmFyLzIvYmF6Ly0nXHJcbiAgICogVXNpbmcgdGhlIGluZGV4ZWQgcG9pbnRlciAnL2Zvby8xL2Jhci80L2Jhei8zJyBhbmQgdGhlIHNhbWUgYXJyYXlNYXBcclxuICAgKiB3b3VsZCByZXN1bHQgaW4gdGhlIGdlbmVyaWMgcG9pbnRlciAnL2Zvby8tL2Jhci8tL2Jhei8tJ1xyXG4gICAqICh0aGUgYmFyIGFycmF5IGhhcyAzIHR1cGxlIGl0ZW1zLCBzbyBpbmRleCAyIGlzIHJldGFpbmVkLCBidXQgNCBpcyByZW1vdmVkKVxyXG4gICAqXHJcbiAgICogVGhlIHN0cnVjdHVyZSBvZiB0aGUgYXJyYXlNYXAgaXM6IFtbJ3BhdGggdG8gYXJyYXknLCBudW1iZXIgb2YgdHVwbGUgaXRlbXNdLi4uXVxyXG4gICAqXHJcbiAgICpcclxuICAgKiAvLyAgeyBQb2ludGVyIH0gaW5kZXhlZFBvaW50ZXIgLSBUaGUgaW5kZXhlZCBwb2ludGVyIChhcnJheSBvciBzdHJpbmcpXHJcbiAgICogLy8gIHsgTWFwPHN0cmluZywgbnVtYmVyPiB9IGFycmF5TWFwIC0gVGhlIG9wdGlvbmFsIGFycmF5IG1hcCAoZm9yIHByZXNlcnZpbmcgdHVwbGUgaW5kZXhlcylcclxuICAgKiAvLyB7IHN0cmluZyB9IC0gVGhlIGdlbmVyaWMgcG9pbnRlciB3aXRoIGluZGV4ZXMgcmVtb3ZlZFxyXG4gICAqL1xyXG4gIHN0YXRpYyB0b0dlbmVyaWNQb2ludGVyKGluZGV4ZWRQb2ludGVyLCBhcnJheU1hcCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCkpIHtcclxuICAgIGlmICh0aGlzLmlzSnNvblBvaW50ZXIoaW5kZXhlZFBvaW50ZXIpICYmIGlzTWFwKGFycmF5TWFwKSkge1xyXG4gICAgICBjb25zdCBwb2ludGVyQXJyYXkgPSB0aGlzLnBhcnNlKGluZGV4ZWRQb2ludGVyKTtcclxuICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCBwb2ludGVyQXJyYXkubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBjb25zdCBzdWJQb2ludGVyID0gdGhpcy5jb21waWxlKHBvaW50ZXJBcnJheS5zbGljZSgwLCBpKSk7XHJcbiAgICAgICAgaWYgKGFycmF5TWFwLmhhcyhzdWJQb2ludGVyKSAmJlxyXG4gICAgICAgICAgYXJyYXlNYXAuZ2V0KHN1YlBvaW50ZXIpIDw9ICtwb2ludGVyQXJyYXlbaV1cclxuICAgICAgICApIHtcclxuICAgICAgICAgIHBvaW50ZXJBcnJheVtpXSA9ICctJztcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRoaXMuY29tcGlsZShwb2ludGVyQXJyYXkpO1xyXG4gICAgfVxyXG4gICAgaWYgKCF0aGlzLmlzSnNvblBvaW50ZXIoaW5kZXhlZFBvaW50ZXIpKSB7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoYHRvR2VuZXJpY1BvaW50ZXIgZXJyb3I6IGludmFsaWQgSlNPTiBQb2ludGVyOiAke2luZGV4ZWRQb2ludGVyfWApO1xyXG4gICAgfVxyXG4gICAgaWYgKCFpc01hcChhcnJheU1hcCkpIHtcclxuICAgICAgY29uc29sZS5lcnJvcihgdG9HZW5lcmljUG9pbnRlciBlcnJvcjogaW52YWxpZCBhcnJheU1hcDogJHthcnJheU1hcH1gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqICd0b0NvbnRyb2xQb2ludGVyJyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogQWNjZXB0cyBhIEpTT04gUG9pbnRlciBmb3IgYSBkYXRhIG9iamVjdCBhbmQgcmV0dXJucyBhIEpTT04gUG9pbnRlciBmb3IgdGhlXHJcbiAgICogbWF0Y2hpbmcgY29udHJvbCBpbiBhbiBBbmd1bGFyIEZvcm1Hcm91cC5cclxuICAgKlxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBkYXRhUG9pbnRlciAtIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KSB0byBhIGRhdGEgb2JqZWN0XHJcbiAgICogLy8gIHsgRm9ybUdyb3VwIH0gZm9ybUdyb3VwIC0gQW5ndWxhciBGb3JtR3JvdXAgdG8gZ2V0IHZhbHVlIGZyb21cclxuICAgKiAvLyAgeyBib29sZWFuID0gZmFsc2UgfSBjb250cm9sTXVzdEV4aXN0IC0gT25seSByZXR1cm4gaWYgY29udHJvbCBleGlzdHM/XHJcbiAgICogLy8geyBQb2ludGVyIH0gLSBKU09OIFBvaW50ZXIgKHN0cmluZykgdG8gdGhlIGZvcm1Hcm91cCBvYmplY3RcclxuICAgKi9cclxuICBzdGF0aWMgdG9Db250cm9sUG9pbnRlcihkYXRhUG9pbnRlciwgZm9ybUdyb3VwLCBjb250cm9sTXVzdEV4aXN0ID0gZmFsc2UpIHtcclxuICAgIGNvbnN0IGRhdGFQb2ludGVyQXJyYXkgPSB0aGlzLnBhcnNlKGRhdGFQb2ludGVyKTtcclxuICAgIGNvbnN0IGNvbnRyb2xQb2ludGVyQXJyYXk6IHN0cmluZ1tdID0gW107XHJcbiAgICBsZXQgc3ViR3JvdXAgPSBmb3JtR3JvdXA7XHJcbiAgICBpZiAoZGF0YVBvaW50ZXJBcnJheSAhPT0gbnVsbCkge1xyXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBkYXRhUG9pbnRlckFycmF5KSB7XHJcbiAgICAgICAgaWYgKGhhc093bihzdWJHcm91cCwgJ2NvbnRyb2xzJykpIHtcclxuICAgICAgICAgIGNvbnRyb2xQb2ludGVyQXJyYXkucHVzaCgnY29udHJvbHMnKTtcclxuICAgICAgICAgIHN1Ykdyb3VwID0gc3ViR3JvdXAuY29udHJvbHM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChpc0FycmF5KHN1Ykdyb3VwKSAmJiAoa2V5ID09PSAnLScpKSB7XHJcbiAgICAgICAgICBjb250cm9sUG9pbnRlckFycmF5LnB1c2goKHN1Ykdyb3VwLmxlbmd0aCAtIDEpLnRvU3RyaW5nKCkpO1xyXG4gICAgICAgICAgc3ViR3JvdXAgPSBzdWJHcm91cFtzdWJHcm91cC5sZW5ndGggLSAxXTtcclxuICAgICAgICB9IGVsc2UgaWYgKGhhc093bihzdWJHcm91cCwga2V5KSkge1xyXG4gICAgICAgICAgY29udHJvbFBvaW50ZXJBcnJheS5wdXNoKGtleSk7XHJcbiAgICAgICAgICBzdWJHcm91cCA9IHN1Ykdyb3VwW2tleV07XHJcbiAgICAgICAgfSBlbHNlIGlmIChjb250cm9sTXVzdEV4aXN0KSB7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGB0b0NvbnRyb2xQb2ludGVyIGVycm9yOiBVbmFibGUgdG8gZmluZCBcIiR7a2V5fVwiIGl0ZW0gaW4gRm9ybUdyb3VwLmApO1xyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihkYXRhUG9pbnRlcik7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1Hcm91cCk7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnRyb2xQb2ludGVyQXJyYXkucHVzaChrZXkpO1xyXG4gICAgICAgICAgc3ViR3JvdXAgPSB7IGNvbnRyb2xzOiB7fSB9O1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdGhpcy5jb21waWxlKGNvbnRyb2xQb2ludGVyQXJyYXkpO1xyXG4gICAgfVxyXG4gICAgY29uc29sZS5lcnJvcihgdG9Db250cm9sUG9pbnRlciBlcnJvcjogSW52YWxpZCBKU09OIFBvaW50ZXI6ICR7ZGF0YVBvaW50ZXJ9YCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAndG9TY2hlbWFQb2ludGVyJyBmdW5jdGlvblxyXG4gICAqXHJcbiAgICogQWNjZXB0cyBhIEpTT04gUG9pbnRlciB0byBhIHZhbHVlIGluc2lkZSBhIGRhdGEgb2JqZWN0IGFuZCBhIEpTT04gc2NoZW1hXHJcbiAgICogZm9yIHRoYXQgb2JqZWN0LlxyXG4gICAqXHJcbiAgICogUmV0dXJucyBhIFBvaW50ZXIgdG8gdGhlIHN1Yi1zY2hlbWEgZm9yIHRoZSB2YWx1ZSBpbnNpZGUgdGhlIG9iamVjdCdzIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIC8vICB7IFBvaW50ZXIgfSBkYXRhUG9pbnRlciAtIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KSB0byBhbiBvYmplY3RcclxuICAgKiAvLyAgIHNjaGVtYSAtIEpTT04gc2NoZW1hIGZvciB0aGUgb2JqZWN0XHJcbiAgICogLy8geyBQb2ludGVyIH0gLSBKU09OIFBvaW50ZXIgKHN0cmluZykgdG8gdGhlIG9iamVjdCdzIHNjaGVtYVxyXG4gICAqL1xyXG4gIHN0YXRpYyB0b1NjaGVtYVBvaW50ZXIoZGF0YVBvaW50ZXIsIHNjaGVtYSkge1xyXG4gICAgaWYgKHRoaXMuaXNKc29uUG9pbnRlcihkYXRhUG9pbnRlcikgJiYgdHlwZW9mIHNjaGVtYSA9PT0gJ29iamVjdCcpIHtcclxuICAgICAgY29uc3QgcG9pbnRlckFycmF5ID0gdGhpcy5wYXJzZShkYXRhUG9pbnRlcik7XHJcbiAgICAgIGlmICghcG9pbnRlckFycmF5Lmxlbmd0aCkgeyByZXR1cm4gJyc7IH1cclxuICAgICAgY29uc3QgZmlyc3RLZXkgPSBwb2ludGVyQXJyYXkuc2hpZnQoKTtcclxuICAgICAgaWYgKHNjaGVtYS50eXBlID09PSAnb2JqZWN0JyB8fCBzY2hlbWEucHJvcGVydGllcyB8fCBzY2hlbWEuYWRkaXRpb25hbFByb3BlcnRpZXMpIHtcclxuICAgICAgICBpZiAoKHNjaGVtYS5wcm9wZXJ0aWVzIHx8IHt9KVtmaXJzdEtleV0pIHtcclxuICAgICAgICAgIHJldHVybiBgL3Byb3BlcnRpZXMvJHt0aGlzLmVzY2FwZShmaXJzdEtleSl9YCArXHJcbiAgICAgICAgICAgIHRoaXMudG9TY2hlbWFQb2ludGVyKHBvaW50ZXJBcnJheSwgc2NoZW1hLnByb3BlcnRpZXNbZmlyc3RLZXldKTtcclxuICAgICAgICB9IGVsc2UgIGlmIChzY2hlbWEuYWRkaXRpb25hbFByb3BlcnRpZXMpIHtcclxuICAgICAgICAgIHJldHVybiAnL2FkZGl0aW9uYWxQcm9wZXJ0aWVzJyArXHJcbiAgICAgICAgICAgIHRoaXMudG9TY2hlbWFQb2ludGVyKHBvaW50ZXJBcnJheSwgc2NoZW1hLmFkZGl0aW9uYWxQcm9wZXJ0aWVzKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaWYgKChzY2hlbWEudHlwZSA9PT0gJ2FycmF5JyB8fCBzY2hlbWEuaXRlbXMpICYmXHJcbiAgICAgICAgKGlzTnVtYmVyKGZpcnN0S2V5KSB8fCBmaXJzdEtleSA9PT0gJy0nIHx8IGZpcnN0S2V5ID09PSAnJylcclxuICAgICAgKSB7XHJcbiAgICAgICAgY29uc3QgYXJyYXlJdGVtID0gZmlyc3RLZXkgPT09ICctJyB8fCBmaXJzdEtleSA9PT0gJycgPyAwIDogK2ZpcnN0S2V5O1xyXG4gICAgICAgIGlmIChpc0FycmF5KHNjaGVtYS5pdGVtcykpIHtcclxuICAgICAgICAgIGlmIChhcnJheUl0ZW0gPCBzY2hlbWEuaXRlbXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAnL2l0ZW1zLycgKyBhcnJheUl0ZW0gK1xyXG4gICAgICAgICAgICAgIHRoaXMudG9TY2hlbWFQb2ludGVyKHBvaW50ZXJBcnJheSwgc2NoZW1hLml0ZW1zW2FycmF5SXRlbV0pO1xyXG4gICAgICAgICAgfSBlbHNlIGlmIChzY2hlbWEuYWRkaXRpb25hbEl0ZW1zKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAnL2FkZGl0aW9uYWxJdGVtcycgK1xyXG4gICAgICAgICAgICAgIHRoaXMudG9TY2hlbWFQb2ludGVyKHBvaW50ZXJBcnJheSwgc2NoZW1hLmFkZGl0aW9uYWxJdGVtcyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIGlmIChpc09iamVjdChzY2hlbWEuaXRlbXMpKSB7XHJcbiAgICAgICAgICByZXR1cm4gJy9pdGVtcycgKyB0aGlzLnRvU2NoZW1hUG9pbnRlcihwb2ludGVyQXJyYXksIHNjaGVtYS5pdGVtcyk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChpc09iamVjdChzY2hlbWEuYWRkaXRpb25hbEl0ZW1zKSkge1xyXG4gICAgICAgICAgcmV0dXJuICcvYWRkaXRpb25hbEl0ZW1zJyArXHJcbiAgICAgICAgICAgIHRoaXMudG9TY2hlbWFQb2ludGVyKHBvaW50ZXJBcnJheSwgc2NoZW1hLmFkZGl0aW9uYWxJdGVtcyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoYHRvU2NoZW1hUG9pbnRlciBlcnJvcjogRGF0YSBwb2ludGVyICR7ZGF0YVBvaW50ZXJ9IGAgK1xyXG4gICAgICAgIGBub3QgY29tcGF0aWJsZSB3aXRoIHNjaGVtYSAke3NjaGVtYX1gKTtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgICBpZiAoIXRoaXMuaXNKc29uUG9pbnRlcihkYXRhUG9pbnRlcikpIHtcclxuICAgICAgY29uc29sZS5lcnJvcihgdG9TY2hlbWFQb2ludGVyIGVycm9yOiBJbnZhbGlkIEpTT04gUG9pbnRlcjogJHtkYXRhUG9pbnRlcn1gKTtcclxuICAgIH1cclxuICAgIGlmICh0eXBlb2Ygc2NoZW1hICE9PSAnb2JqZWN0Jykge1xyXG4gICAgICBjb25zb2xlLmVycm9yKGB0b1NjaGVtYVBvaW50ZXIgZXJyb3I6IEludmFsaWQgSlNPTiBTY2hlbWE6ICR7c2NoZW1hfWApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiAndG9EYXRhUG9pbnRlcicgZnVuY3Rpb25cclxuICAgKlxyXG4gICAqIEFjY2VwdHMgYSBKU09OIFBvaW50ZXIgdG8gYSBzdWItc2NoZW1hIGluc2lkZSBhIEpTT04gc2NoZW1hIGFuZCB0aGUgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogSWYgcG9zc2libGUsIHJldHVybnMgYSBnZW5lcmljIFBvaW50ZXIgdG8gdGhlIGNvcnJlc3BvbmRpbmcgdmFsdWUgaW5zaWRlXHJcbiAgICogdGhlIGRhdGEgb2JqZWN0IGRlc2NyaWJlZCBieSB0aGUgSlNPTiBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBSZXR1cm5zIG51bGwgaWYgdGhlIHN1Yi1zY2hlbWEgaXMgaW4gYW4gYW1iaWd1b3VzIGxvY2F0aW9uIChzdWNoIGFzXHJcbiAgICogZGVmaW5pdGlvbnMgb3IgYWRkaXRpb25hbFByb3BlcnRpZXMpIHdoZXJlIHRoZSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICogbG9jYXRpb24gY2Fubm90IGJlIGRldGVybWluZWQuXHJcbiAgICpcclxuICAgKiAvLyAgeyBQb2ludGVyIH0gc2NoZW1hUG9pbnRlciAtIEpTT04gUG9pbnRlciAoc3RyaW5nIG9yIGFycmF5KSB0byBhIEpTT04gc2NoZW1hXHJcbiAgICogLy8gICBzY2hlbWEgLSB0aGUgSlNPTiBzY2hlbWFcclxuICAgKiAvLyAgeyBib29sZWFuID0gZmFsc2UgfSBlcnJvcnMgLSBTaG93IGVycm9ycz9cclxuICAgKiAvLyB7IFBvaW50ZXIgfSAtIEpTT04gUG9pbnRlciAoc3RyaW5nKSB0byB0aGUgdmFsdWUgaW4gdGhlIGRhdGEgb2JqZWN0XHJcbiAgICovXHJcbiAgc3RhdGljIHRvRGF0YVBvaW50ZXIoc2NoZW1hUG9pbnRlciwgc2NoZW1hLCBlcnJvcnMgPSBmYWxzZSkge1xyXG4gICAgaWYgKHRoaXMuaXNKc29uUG9pbnRlcihzY2hlbWFQb2ludGVyKSAmJiB0eXBlb2Ygc2NoZW1hID09PSAnb2JqZWN0JyAmJlxyXG4gICAgICB0aGlzLmhhcyhzY2hlbWEsIHNjaGVtYVBvaW50ZXIpXHJcbiAgICApIHtcclxuICAgICAgY29uc3QgcG9pbnRlckFycmF5ID0gdGhpcy5wYXJzZShzY2hlbWFQb2ludGVyKTtcclxuICAgICAgaWYgKCFwb2ludGVyQXJyYXkubGVuZ3RoKSB7IHJldHVybiAnJzsgfVxyXG4gICAgICBjb25zdCBmaXJzdEtleSA9IHBvaW50ZXJBcnJheS5zaGlmdCgpO1xyXG4gICAgICBpZiAoZmlyc3RLZXkgPT09ICdwcm9wZXJ0aWVzJyB8fFxyXG4gICAgICAgIChmaXJzdEtleSA9PT0gJ2l0ZW1zJyAmJiBpc0FycmF5KHNjaGVtYS5pdGVtcykpXHJcbiAgICAgICkge1xyXG4gICAgICAgIGNvbnN0IHNlY29uZEtleSA9IHBvaW50ZXJBcnJheS5zaGlmdCgpO1xyXG4gICAgICAgIGNvbnN0IHBvaW50ZXJTdWZmaXggPSB0aGlzLnRvRGF0YVBvaW50ZXIocG9pbnRlckFycmF5LCBzY2hlbWFbZmlyc3RLZXldW3NlY29uZEtleV0pO1xyXG4gICAgICAgIHJldHVybiBwb2ludGVyU3VmZml4ID09PSBudWxsID8gbnVsbCA6ICcvJyArIHNlY29uZEtleSArIHBvaW50ZXJTdWZmaXg7XHJcbiAgICAgIH0gZWxzZSBpZiAoZmlyc3RLZXkgPT09ICdhZGRpdGlvbmFsSXRlbXMnIHx8XHJcbiAgICAgICAgKGZpcnN0S2V5ID09PSAnaXRlbXMnICYmIGlzT2JqZWN0KHNjaGVtYS5pdGVtcykpXHJcbiAgICAgICkge1xyXG4gICAgICAgIGNvbnN0IHBvaW50ZXJTdWZmaXggPSB0aGlzLnRvRGF0YVBvaW50ZXIocG9pbnRlckFycmF5LCBzY2hlbWFbZmlyc3RLZXldKTtcclxuICAgICAgICByZXR1cm4gcG9pbnRlclN1ZmZpeCA9PT0gbnVsbCA/IG51bGwgOiAnLy0nICsgcG9pbnRlclN1ZmZpeDtcclxuICAgICAgfSBlbHNlIGlmIChbJ2FsbE9mJywgJ2FueU9mJywgJ29uZU9mJ10uaW5jbHVkZXMoZmlyc3RLZXkpKSB7XHJcbiAgICAgICAgY29uc3Qgc2Vjb25kS2V5ID0gcG9pbnRlckFycmF5LnNoaWZ0KCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudG9EYXRhUG9pbnRlcihwb2ludGVyQXJyYXksIHNjaGVtYVtmaXJzdEtleV1bc2Vjb25kS2V5XSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZmlyc3RLZXkgPT09ICdub3QnKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudG9EYXRhUG9pbnRlcihwb2ludGVyQXJyYXksIHNjaGVtYVtmaXJzdEtleV0pO1xyXG4gICAgICB9IGVsc2UgaWYgKFsnY29udGFpbnMnLCAnZGVmaW5pdGlvbnMnLCAnZGVwZW5kZW5jaWVzJywgJ2FkZGl0aW9uYWxJdGVtcycsXHJcbiAgICAgICAgJ2FkZGl0aW9uYWxQcm9wZXJ0aWVzJywgJ3BhdHRlcm5Qcm9wZXJ0aWVzJywgJ3Byb3BlcnR5TmFtZXMnXS5pbmNsdWRlcyhmaXJzdEtleSlcclxuICAgICAgKSB7XHJcbiAgICAgICAgaWYgKGVycm9ycykgeyBjb25zb2xlLmVycm9yKGB0b0RhdGFQb2ludGVyIGVycm9yOiBBbWJpZ3VvdXMgbG9jYXRpb25gKTsgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAnJztcclxuICAgIH1cclxuICAgIGlmIChlcnJvcnMpIHtcclxuICAgICAgaWYgKCF0aGlzLmlzSnNvblBvaW50ZXIoc2NoZW1hUG9pbnRlcikpIHtcclxuICAgICAgICBjb25zb2xlLmVycm9yKGB0b0RhdGFQb2ludGVyIGVycm9yOiBJbnZhbGlkIEpTT04gUG9pbnRlcjogJHtzY2hlbWFQb2ludGVyfWApO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICh0eXBlb2Ygc2NoZW1hICE9PSAnb2JqZWN0Jykge1xyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYHRvRGF0YVBvaW50ZXIgZXJyb3I6IEludmFsaWQgSlNPTiBTY2hlbWE6ICR7c2NoZW1hfWApO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICh0eXBlb2Ygc2NoZW1hICE9PSAnb2JqZWN0Jykge1xyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYHRvRGF0YVBvaW50ZXIgZXJyb3I6IFBvaW50ZXIgJHtzY2hlbWFQb2ludGVyfSBpbnZhbGlkIGZvciBTY2hlbWE6ICR7c2NoZW1hfWApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqICdwYXJzZU9iamVjdFBhdGgnIGZ1bmN0aW9uXHJcbiAgICpcclxuICAgKiBQYXJzZXMgYSBKYXZhU2NyaXB0IG9iamVjdCBwYXRoIGludG8gYW4gYXJyYXkgb2Yga2V5cywgd2hpY2hcclxuICAgKiBjYW4gdGhlbiBiZSBwYXNzZWQgdG8gY29tcGlsZSgpIHRvIGNvbnZlcnQgaW50byBhIHN0cmluZyBKU09OIFBvaW50ZXIuXHJcbiAgICpcclxuICAgKiBCYXNlZCBvbiBtaWtlLW1hcmNhY2NpJ3MgZXhjZWxsZW50IG9iamVjdHBhdGggcGFyc2UgZnVuY3Rpb246XHJcbiAgICogaHR0cHM6Ly9naXRodWIuY29tL21pa2UtbWFyY2FjY2kvb2JqZWN0cGF0aFxyXG4gICAqXHJcbiAgICogLy8gIHsgUG9pbnRlciB9IHBhdGggLSBUaGUgb2JqZWN0IHBhdGggdG8gcGFyc2VcclxuICAgKiAvLyB7IHN0cmluZ1tdIH0gLSBUaGUgcmVzdWx0aW5nIGFycmF5IG9mIGtleXNcclxuICAgKi9cclxuICBzdGF0aWMgcGFyc2VPYmplY3RQYXRoKHBhdGgpIHtcclxuICAgIGlmIChpc0FycmF5KHBhdGgpKSB7IHJldHVybiA8c3RyaW5nW10+cGF0aDsgfVxyXG4gICAgaWYgKHRoaXMuaXNKc29uUG9pbnRlcihwYXRoKSkgeyByZXR1cm4gdGhpcy5wYXJzZShwYXRoKTsgfVxyXG4gICAgaWYgKHR5cGVvZiBwYXRoID09PSAnc3RyaW5nJykge1xyXG4gICAgICBsZXQgaW5kZXggPSAwO1xyXG4gICAgICBjb25zdCBwYXJ0czogc3RyaW5nW10gPSBbXTtcclxuICAgICAgd2hpbGUgKGluZGV4IDwgcGF0aC5sZW5ndGgpIHtcclxuICAgICAgICBjb25zdCBuZXh0RG90ID0gcGF0aC5pbmRleE9mKCcuJywgaW5kZXgpO1xyXG4gICAgICAgIGNvbnN0IG5leHRPQiA9IHBhdGguaW5kZXhPZignWycsIGluZGV4KTsgLy8gbmV4dCBvcGVuIGJyYWNrZXRcclxuICAgICAgICBpZiAobmV4dERvdCA9PT0gLTEgJiYgbmV4dE9CID09PSAtMSkgeyAvLyBsYXN0IGl0ZW1cclxuICAgICAgICAgIHBhcnRzLnB1c2gocGF0aC5zbGljZShpbmRleCkpO1xyXG4gICAgICAgICAgaW5kZXggPSBwYXRoLmxlbmd0aDtcclxuICAgICAgICB9IGVsc2UgaWYgKG5leHREb3QgIT09IC0xICYmIChuZXh0RG90IDwgbmV4dE9CIHx8IG5leHRPQiA9PT0gLTEpKSB7IC8vIGRvdCBub3RhdGlvblxyXG4gICAgICAgICAgcGFydHMucHVzaChwYXRoLnNsaWNlKGluZGV4LCBuZXh0RG90KSk7XHJcbiAgICAgICAgICBpbmRleCA9IG5leHREb3QgKyAxO1xyXG4gICAgICAgIH0gZWxzZSB7IC8vIGJyYWNrZXQgbm90YXRpb25cclxuICAgICAgICAgIGlmIChuZXh0T0IgPiBpbmRleCkge1xyXG4gICAgICAgICAgICBwYXJ0cy5wdXNoKHBhdGguc2xpY2UoaW5kZXgsIG5leHRPQikpO1xyXG4gICAgICAgICAgICBpbmRleCA9IG5leHRPQjtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGNvbnN0IHF1b3RlID0gcGF0aC5jaGFyQXQobmV4dE9CICsgMSk7XHJcbiAgICAgICAgICBpZiAocXVvdGUgPT09ICdcIicgfHwgcXVvdGUgPT09ICdcXCcnKSB7IC8vIGVuY2xvc2luZyBxdW90ZXNcclxuICAgICAgICAgICAgbGV0IG5leHRDQiA9IHBhdGguaW5kZXhPZihxdW90ZSArICddJywgbmV4dE9CKTsgLy8gbmV4dCBjbG9zZSBicmFja2V0XHJcbiAgICAgICAgICAgIHdoaWxlIChuZXh0Q0IgIT09IC0xICYmIHBhdGguY2hhckF0KG5leHRDQiAtIDEpID09PSAnXFxcXCcpIHtcclxuICAgICAgICAgICAgICBuZXh0Q0IgPSBwYXRoLmluZGV4T2YocXVvdGUgKyAnXScsIG5leHRDQiArIDIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGlmIChuZXh0Q0IgPT09IC0xKSB7IG5leHRDQiA9IHBhdGgubGVuZ3RoOyB9XHJcbiAgICAgICAgICAgIHBhcnRzLnB1c2gocGF0aC5zbGljZShpbmRleCArIDIsIG5leHRDQilcclxuICAgICAgICAgICAgICAucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcJyArIHF1b3RlLCAnZycpLCBxdW90ZSkpO1xyXG4gICAgICAgICAgICBpbmRleCA9IG5leHRDQiArIDI7XHJcbiAgICAgICAgICB9IGVsc2UgeyAvLyBubyBlbmNsb3NpbmcgcXVvdGVzXHJcbiAgICAgICAgICAgIGxldCBuZXh0Q0IgPSBwYXRoLmluZGV4T2YoJ10nLCBuZXh0T0IpOyAvLyBuZXh0IGNsb3NlIGJyYWNrZXRcclxuICAgICAgICAgICAgaWYgKG5leHRDQiA9PT0gLTEpIHsgbmV4dENCID0gcGF0aC5sZW5ndGg7IH1cclxuICAgICAgICAgICAgcGFydHMucHVzaChwYXRoLnNsaWNlKGluZGV4ICsgMSwgbmV4dENCKSk7XHJcbiAgICAgICAgICAgIGluZGV4ID0gbmV4dENCICsgMTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGlmIChwYXRoLmNoYXJBdChpbmRleCkgPT09ICcuJykgeyBpbmRleCsrOyB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBwYXJ0cztcclxuICAgIH1cclxuICAgIGNvbnNvbGUuZXJyb3IoJ3BhcnNlT2JqZWN0UGF0aCBlcnJvcjogSW5wdXQgb2JqZWN0IHBhdGggbXVzdCBiZSBhIHN0cmluZy4nKTtcclxuICB9XHJcbn1cclxuIl19
|