@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,584 +1,584 @@
|
|
|
1
|
-
import { from, Observable } from 'rxjs';
|
|
2
|
-
/**
|
|
3
|
-
* '_executeValidators' utility function
|
|
4
|
-
*
|
|
5
|
-
* Validates a control against an array of validators, and returns
|
|
6
|
-
* an array of the same length containing a combination of error messages
|
|
7
|
-
* (from invalid validators) and null values (from valid validators)
|
|
8
|
-
*
|
|
9
|
-
* // { AbstractControl } control - control to validate
|
|
10
|
-
* // { IValidatorFn[] } validators - array of validators
|
|
11
|
-
* // { boolean } invert - invert?
|
|
12
|
-
* // { PlainObject[] } - array of nulls and error message
|
|
13
|
-
*/
|
|
14
|
-
export function _executeValidators(control, validators, invert = false) {
|
|
15
|
-
return validators.map(validator => validator(control, invert));
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* '_executeAsyncValidators' utility function
|
|
19
|
-
*
|
|
20
|
-
* Validates a control against an array of async validators, and returns
|
|
21
|
-
* an array of observabe results of the same length containing a combination of
|
|
22
|
-
* error messages (from invalid validators) and null values (from valid ones)
|
|
23
|
-
*
|
|
24
|
-
* // { AbstractControl } control - control to validate
|
|
25
|
-
* // { AsyncIValidatorFn[] } validators - array of async validators
|
|
26
|
-
* // { boolean } invert - invert?
|
|
27
|
-
* // - array of observable nulls and error message
|
|
28
|
-
*/
|
|
29
|
-
export function _executeAsyncValidators(control, validators, invert = false) {
|
|
30
|
-
return validators.map(validator => validator(control, invert));
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* '_mergeObjects' utility function
|
|
34
|
-
*
|
|
35
|
-
* Recursively Merges one or more objects into a single object with combined keys.
|
|
36
|
-
* Automatically detects and ignores null and undefined inputs.
|
|
37
|
-
* Also detects duplicated boolean 'not' keys and XORs their values.
|
|
38
|
-
*
|
|
39
|
-
* // { PlainObject[] } objects - one or more objects to merge
|
|
40
|
-
* // { PlainObject } - merged object
|
|
41
|
-
*/
|
|
42
|
-
export function _mergeObjects(...objects) {
|
|
43
|
-
const mergedObject = {};
|
|
44
|
-
for (const currentObject of objects) {
|
|
45
|
-
if (isObject(currentObject)) {
|
|
46
|
-
for (const key of Object.keys(currentObject)) {
|
|
47
|
-
const currentValue = currentObject[key];
|
|
48
|
-
const mergedValue = mergedObject[key];
|
|
49
|
-
mergedObject[key] = !isDefined(mergedValue) ? currentValue :
|
|
50
|
-
key === 'not' && isBoolean(mergedValue, 'strict') &&
|
|
51
|
-
isBoolean(currentValue, 'strict') ? xor(mergedValue, currentValue) :
|
|
52
|
-
getType(mergedValue) === 'object' && getType(currentValue) === 'object' ?
|
|
53
|
-
_mergeObjects(mergedValue, currentValue) :
|
|
54
|
-
currentValue;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return mergedObject;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* '_mergeErrors' utility function
|
|
62
|
-
*
|
|
63
|
-
* Merges an array of objects.
|
|
64
|
-
* Used for combining the validator errors returned from 'executeValidators'
|
|
65
|
-
*
|
|
66
|
-
* // { PlainObject[] } arrayOfErrors - array of objects
|
|
67
|
-
* // { PlainObject } - merged object, or null if no usable input objectcs
|
|
68
|
-
*/
|
|
69
|
-
export function _mergeErrors(arrayOfErrors) {
|
|
70
|
-
const mergedErrors = _mergeObjects(...arrayOfErrors);
|
|
71
|
-
return isEmpty(mergedErrors) ? null : mergedErrors;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* 'isDefined' utility function
|
|
75
|
-
*
|
|
76
|
-
* Checks if a variable contains a value of any type.
|
|
77
|
-
* Returns true even for otherwise 'falsey' values of 0, '', and false.
|
|
78
|
-
*
|
|
79
|
-
* // value - the value to check
|
|
80
|
-
* // { boolean } - false if undefined or null, otherwise true
|
|
81
|
-
*/
|
|
82
|
-
export function isDefined(value) {
|
|
83
|
-
return value !== undefined && value !== null;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* 'hasValue' utility function
|
|
87
|
-
*
|
|
88
|
-
* Checks if a variable contains a value.
|
|
89
|
-
* Returs false for null, undefined, or a zero-length strng, '',
|
|
90
|
-
* otherwise returns true.
|
|
91
|
-
* (Stricter than 'isDefined' because it also returns false for '',
|
|
92
|
-
* though it stil returns true for otherwise 'falsey' values 0 and false.)
|
|
93
|
-
*
|
|
94
|
-
* // value - the value to check
|
|
95
|
-
* // { boolean } - false if undefined, null, or '', otherwise true
|
|
96
|
-
*/
|
|
97
|
-
export function hasValue(value) {
|
|
98
|
-
return value !== undefined && value !== null && value !== '';
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* 'isEmpty' utility function
|
|
102
|
-
*
|
|
103
|
-
* Similar to !hasValue, but also returns true for empty arrays and objects.
|
|
104
|
-
*
|
|
105
|
-
* // value - the value to check
|
|
106
|
-
* // { boolean } - false if undefined, null, or '', otherwise true
|
|
107
|
-
*/
|
|
108
|
-
export function isEmpty(value) {
|
|
109
|
-
if (isArray(value)) {
|
|
110
|
-
return !value.length;
|
|
111
|
-
}
|
|
112
|
-
if (isObject(value)) {
|
|
113
|
-
return !Object.keys(value).length;
|
|
114
|
-
}
|
|
115
|
-
return value === undefined || value === null || value === '';
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* 'isString' utility function
|
|
119
|
-
*
|
|
120
|
-
* Checks if a value is a string.
|
|
121
|
-
*
|
|
122
|
-
* // value - the value to check
|
|
123
|
-
* // { boolean } - true if string, false if not
|
|
124
|
-
*/
|
|
125
|
-
export function isString(value) {
|
|
126
|
-
return typeof value === 'string';
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* 'isNumber' utility function
|
|
130
|
-
*
|
|
131
|
-
* Checks if a value is a regular number, numeric string, or JavaScript Date.
|
|
132
|
-
*
|
|
133
|
-
* // value - the value to check
|
|
134
|
-
* // { any = false } strict - if truthy, also checks JavaScript tyoe
|
|
135
|
-
* // { boolean } - true if number, false if not
|
|
136
|
-
*/
|
|
137
|
-
export function isNumber(value, strict = false) {
|
|
138
|
-
if (strict && typeof value !== 'number') {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
return !isNaN(value) && value !== value / 0;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* 'isInteger' utility function
|
|
145
|
-
*
|
|
146
|
-
* Checks if a value is an integer.
|
|
147
|
-
*
|
|
148
|
-
* // value - the value to check
|
|
149
|
-
* // { any = false } strict - if truthy, also checks JavaScript tyoe
|
|
150
|
-
* // {boolean } - true if number, false if not
|
|
151
|
-
*/
|
|
152
|
-
export function isInteger(value, strict = false) {
|
|
153
|
-
if (strict && typeof value !== 'number') {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
return !isNaN(value) && value !== value / 0 && value % 1 === 0;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* 'isBoolean' utility function
|
|
160
|
-
*
|
|
161
|
-
* Checks if a value is a boolean.
|
|
162
|
-
*
|
|
163
|
-
* // value - the value to check
|
|
164
|
-
* // { any = null } option - if 'strict', also checks JavaScript type
|
|
165
|
-
* if TRUE or FALSE, checks only for that value
|
|
166
|
-
* // { boolean } - true if boolean, false if not
|
|
167
|
-
*/
|
|
168
|
-
export function isBoolean(value, option = null) {
|
|
169
|
-
if (option === 'strict') {
|
|
170
|
-
return value === true || value === false;
|
|
171
|
-
}
|
|
172
|
-
if (option === true) {
|
|
173
|
-
return value === true || value === 1 || value === 'true' || value === '1';
|
|
174
|
-
}
|
|
175
|
-
if (option === false) {
|
|
176
|
-
return value === false || value === 0 || value === 'false' || value === '0';
|
|
177
|
-
}
|
|
178
|
-
return value === true || value === 1 || value === 'true' || value === '1' ||
|
|
179
|
-
value === false || value === 0 || value === 'false' || value === '0';
|
|
180
|
-
}
|
|
181
|
-
export function isFunction(item) {
|
|
182
|
-
return typeof item === 'function';
|
|
183
|
-
}
|
|
184
|
-
export function isObject(item) {
|
|
185
|
-
return item !== null && typeof item === 'object';
|
|
186
|
-
}
|
|
187
|
-
export function isArray(item) {
|
|
188
|
-
return Array.isArray(item);
|
|
189
|
-
}
|
|
190
|
-
export function isDate(item) {
|
|
191
|
-
return !!item && Object.prototype.toString.call(item) === '[object Date]';
|
|
192
|
-
}
|
|
193
|
-
export function isMap(item) {
|
|
194
|
-
return !!item && Object.prototype.toString.call(item) === '[object Map]';
|
|
195
|
-
}
|
|
196
|
-
export function isSet(item) {
|
|
197
|
-
return !!item && Object.prototype.toString.call(item) === '[object Set]';
|
|
198
|
-
}
|
|
199
|
-
export function isSymbol(item) {
|
|
200
|
-
return typeof item === 'symbol';
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* 'getType' function
|
|
204
|
-
*
|
|
205
|
-
* Detects the JSON Schema Type of a value.
|
|
206
|
-
* By default, detects numbers and integers even if formatted as strings.
|
|
207
|
-
* (So all integers are also numbers, and any number may also be a string.)
|
|
208
|
-
* However, it only detects true boolean values (to detect boolean values
|
|
209
|
-
* in non-boolean formats, use isBoolean() instead).
|
|
210
|
-
*
|
|
211
|
-
* If passed a second optional parameter of 'strict', it will only detect
|
|
212
|
-
* numbers and integers if they are formatted as JavaScript numbers.
|
|
213
|
-
*
|
|
214
|
-
* Examples:
|
|
215
|
-
* getType('10.5') = 'number'
|
|
216
|
-
* getType(10.5) = 'number'
|
|
217
|
-
* getType('10') = 'integer'
|
|
218
|
-
* getType(10) = 'integer'
|
|
219
|
-
* getType('true') = 'string'
|
|
220
|
-
* getType(true) = 'boolean'
|
|
221
|
-
* getType(null) = 'null'
|
|
222
|
-
* getType({ }) = 'object'
|
|
223
|
-
* getType([]) = 'array'
|
|
224
|
-
*
|
|
225
|
-
* getType('10.5', 'strict') = 'string'
|
|
226
|
-
* getType(10.5, 'strict') = 'number'
|
|
227
|
-
* getType('10', 'strict') = 'string'
|
|
228
|
-
* getType(10, 'strict') = 'integer'
|
|
229
|
-
* getType('true', 'strict') = 'string'
|
|
230
|
-
* getType(true, 'strict') = 'boolean'
|
|
231
|
-
*
|
|
232
|
-
* // value - value to check
|
|
233
|
-
* // { any = false } strict - if truthy, also checks JavaScript tyoe
|
|
234
|
-
* // { SchemaType }
|
|
235
|
-
*/
|
|
236
|
-
export function getType(value, strict = false) {
|
|
237
|
-
if (!isDefined(value)) {
|
|
238
|
-
return 'null';
|
|
239
|
-
}
|
|
240
|
-
if (isArray(value)) {
|
|
241
|
-
return 'array';
|
|
242
|
-
}
|
|
243
|
-
if (isObject(value)) {
|
|
244
|
-
return 'object';
|
|
245
|
-
}
|
|
246
|
-
if (isBoolean(value, 'strict')) {
|
|
247
|
-
return 'boolean';
|
|
248
|
-
}
|
|
249
|
-
if (isInteger(value, strict)) {
|
|
250
|
-
return 'integer';
|
|
251
|
-
}
|
|
252
|
-
if (isNumber(value, strict)) {
|
|
253
|
-
return 'number';
|
|
254
|
-
}
|
|
255
|
-
if (isString(value) || (!strict && isDate(value))) {
|
|
256
|
-
return 'string';
|
|
257
|
-
}
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* 'isType' function
|
|
262
|
-
*
|
|
263
|
-
* Checks wether an input (probably string) value contains data of
|
|
264
|
-
* a specified JSON Schema type
|
|
265
|
-
*
|
|
266
|
-
* // { PrimitiveValue } value - value to check
|
|
267
|
-
* // { SchemaPrimitiveType } type - type to check
|
|
268
|
-
* // { boolean }
|
|
269
|
-
*/
|
|
270
|
-
export function isType(value, type) {
|
|
271
|
-
switch (type) {
|
|
272
|
-
case 'string':
|
|
273
|
-
return isString(value) || isDate(value);
|
|
274
|
-
case 'number':
|
|
275
|
-
return isNumber(value);
|
|
276
|
-
case 'integer':
|
|
277
|
-
return isInteger(value);
|
|
278
|
-
case 'boolean':
|
|
279
|
-
return isBoolean(value);
|
|
280
|
-
case 'null':
|
|
281
|
-
return !hasValue(value);
|
|
282
|
-
default:
|
|
283
|
-
console.error(`isType error: "${type}" is not a recognized type.`);
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* 'isPrimitive' function
|
|
289
|
-
*
|
|
290
|
-
* Checks wether an input value is a JavaScript primitive type:
|
|
291
|
-
* string, number, boolean, or null.
|
|
292
|
-
*
|
|
293
|
-
* // value - value to check
|
|
294
|
-
* // { boolean }
|
|
295
|
-
*/
|
|
296
|
-
export function isPrimitive(value) {
|
|
297
|
-
return (isString(value) || isNumber(value) ||
|
|
298
|
-
isBoolean(value, 'strict') || value === null);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
*
|
|
302
|
-
* @param date
|
|
303
|
-
* @returns {string}
|
|
304
|
-
* exmaple:
|
|
305
|
-
* toDateString('2018-01-01') = '2018-01-01'
|
|
306
|
-
* toDateString('2018-01-30T00:00:00.000Z') = '2018-01-30'
|
|
307
|
-
*/
|
|
308
|
-
export const toIsoString = (date) => {
|
|
309
|
-
const day = date.getDate();
|
|
310
|
-
const month = date.getMonth() + 1;
|
|
311
|
-
const year = date.getFullYear();
|
|
312
|
-
return `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`;
|
|
313
|
-
};
|
|
314
|
-
/**
|
|
315
|
-
* 'toJavaScriptType' function
|
|
316
|
-
*
|
|
317
|
-
* Converts an input (probably string) value to a JavaScript primitive type -
|
|
318
|
-
* 'string', 'number', 'boolean', or 'null' - before storing in a JSON object.
|
|
319
|
-
*
|
|
320
|
-
* Does not coerce values (other than null), and only converts the types
|
|
321
|
-
* of values that would otherwise be valid.
|
|
322
|
-
*
|
|
323
|
-
* If the optional third parameter 'strictIntegers' is TRUE, and the
|
|
324
|
-
* JSON Schema type 'integer' is specified, it also verifies the input value
|
|
325
|
-
* is an integer and, if it is, returns it as a JaveScript number.
|
|
326
|
-
* If 'strictIntegers' is FALSE (or not set) the type 'integer' is treated
|
|
327
|
-
* exactly the same as 'number', and allows decimals.
|
|
328
|
-
*
|
|
329
|
-
* Valid Examples:
|
|
330
|
-
* toJavaScriptType('10', 'number' ) = 10 // '10' is a number
|
|
331
|
-
* toJavaScriptType('10', 'integer') = 10 // '10' is also an integer
|
|
332
|
-
* toJavaScriptType( 10, 'integer') = 10 // 10 is still an integer
|
|
333
|
-
* toJavaScriptType( 10, 'string' ) = '10' // 10 can be made into a string
|
|
334
|
-
* toJavaScriptType('10.5', 'number' ) = 10.5 // '10.5' is a number
|
|
335
|
-
*
|
|
336
|
-
* Invalid Examples:
|
|
337
|
-
* toJavaScriptType('10.5', 'integer') = null // '10.5' is not an integer
|
|
338
|
-
* toJavaScriptType( 10.5, 'integer') = null // 10.5 is still not an integer
|
|
339
|
-
*
|
|
340
|
-
* // { PrimitiveValue } value - value to convert
|
|
341
|
-
* // { SchemaPrimitiveType | SchemaPrimitiveType[] } types - types to convert to
|
|
342
|
-
* // { boolean = false } strictIntegers - if FALSE, treat integers as numbers
|
|
343
|
-
* // { PrimitiveValue }
|
|
344
|
-
*/
|
|
345
|
-
export function toJavaScriptType(value, types, strictIntegers = true) {
|
|
346
|
-
if (!isDefined(value)) {
|
|
347
|
-
return null;
|
|
348
|
-
}
|
|
349
|
-
if (isString(types)) {
|
|
350
|
-
types = [types];
|
|
351
|
-
}
|
|
352
|
-
if (strictIntegers && inArray('integer', types)) {
|
|
353
|
-
if (isInteger(value, 'strict')) {
|
|
354
|
-
return value;
|
|
355
|
-
}
|
|
356
|
-
if (isInteger(value)) {
|
|
357
|
-
return parseInt(value, 10);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
if (inArray('number', types) || (!strictIntegers && inArray('integer', types))) {
|
|
361
|
-
if (isNumber(value, 'strict')) {
|
|
362
|
-
return value;
|
|
363
|
-
}
|
|
364
|
-
if (isNumber(value)) {
|
|
365
|
-
return parseFloat(value);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
if (inArray('string', types)) {
|
|
369
|
-
if (isString(value)) {
|
|
370
|
-
return value;
|
|
371
|
-
}
|
|
372
|
-
// If value is a date, and types includes 'string',
|
|
373
|
-
// convert the date to a string
|
|
374
|
-
if (isDate(value)) {
|
|
375
|
-
return toIsoString(value);
|
|
376
|
-
}
|
|
377
|
-
if (isNumber(value)) {
|
|
378
|
-
return value.toString();
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
// If value is a date, and types includes 'integer' or 'number',
|
|
382
|
-
// but not 'string', convert the date to a number
|
|
383
|
-
if (isDate(value) && (inArray('integer', types) || inArray('number', types))) {
|
|
384
|
-
return value.getTime();
|
|
385
|
-
}
|
|
386
|
-
if (inArray('boolean', types)) {
|
|
387
|
-
if (isBoolean(value, true)) {
|
|
388
|
-
return true;
|
|
389
|
-
}
|
|
390
|
-
if (isBoolean(value, false)) {
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
return null;
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* 'toSchemaType' function
|
|
398
|
-
*
|
|
399
|
-
* Converts an input (probably string) value to the "best" JavaScript
|
|
400
|
-
* equivalent available from an allowed list of JSON Schema types, which may
|
|
401
|
-
* contain 'string', 'number', 'integer', 'boolean', and/or 'null'.
|
|
402
|
-
* If necssary, it does progressively agressive type coersion.
|
|
403
|
-
* It will not return null unless null is in the list of allowed types.
|
|
404
|
-
*
|
|
405
|
-
* Number conversion examples:
|
|
406
|
-
* toSchemaType('10', ['number','integer','string']) = 10 // integer
|
|
407
|
-
* toSchemaType('10', ['number','string']) = 10 // number
|
|
408
|
-
* toSchemaType('10', ['string']) = '10' // string
|
|
409
|
-
* toSchemaType('10.5', ['number','integer','string']) = 10.5 // number
|
|
410
|
-
* toSchemaType('10.5', ['integer','string']) = '10.5' // string
|
|
411
|
-
* toSchemaType('10.5', ['integer']) = 10 // integer
|
|
412
|
-
* toSchemaType(10.5, ['null','boolean','string']) = '10.5' // string
|
|
413
|
-
* toSchemaType(10.5, ['null','boolean']) = true // boolean
|
|
414
|
-
*
|
|
415
|
-
* String conversion examples:
|
|
416
|
-
* toSchemaType('1.5x', ['boolean','number','integer','string']) = '1.5x' // string
|
|
417
|
-
* toSchemaType('1.5x', ['boolean','number','integer']) = '1.5' // number
|
|
418
|
-
* toSchemaType('1.5x', ['boolean','integer']) = '1' // integer
|
|
419
|
-
* toSchemaType('1.5x', ['boolean']) = true // boolean
|
|
420
|
-
* toSchemaType('xyz', ['number','integer','boolean','null']) = true // boolean
|
|
421
|
-
* toSchemaType('xyz', ['number','integer','null']) = null // null
|
|
422
|
-
* toSchemaType('xyz', ['number','integer']) = 0 // number
|
|
423
|
-
*
|
|
424
|
-
* Boolean conversion examples:
|
|
425
|
-
* toSchemaType('1', ['integer','number','string','boolean']) = 1 // integer
|
|
426
|
-
* toSchemaType('1', ['number','string','boolean']) = 1 // number
|
|
427
|
-
* toSchemaType('1', ['string','boolean']) = '1' // string
|
|
428
|
-
* toSchemaType('1', ['boolean']) = true // boolean
|
|
429
|
-
* toSchemaType('true', ['number','string','boolean']) = 'true' // string
|
|
430
|
-
* toSchemaType('true', ['boolean']) = true // boolean
|
|
431
|
-
* toSchemaType('true', ['number']) = 0 // number
|
|
432
|
-
* toSchemaType(true, ['number','string','boolean']) = true // boolean
|
|
433
|
-
* toSchemaType(true, ['number','string']) = 'true' // string
|
|
434
|
-
* toSchemaType(true, ['number']) = 1 // number
|
|
435
|
-
*
|
|
436
|
-
* // { PrimitiveValue } value - value to convert
|
|
437
|
-
* // { SchemaPrimitiveType | SchemaPrimitiveType[] } types - allowed types to convert to
|
|
438
|
-
* // { PrimitiveValue }
|
|
439
|
-
*/
|
|
440
|
-
export function toSchemaType(value, types) {
|
|
441
|
-
if (!isArray(types)) {
|
|
442
|
-
types = [types];
|
|
443
|
-
}
|
|
444
|
-
if (types.includes('null') && !hasValue(value)) {
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
if (types.includes('boolean') && !isBoolean(value, 'strict')) {
|
|
448
|
-
return value;
|
|
449
|
-
}
|
|
450
|
-
if (types.includes('integer')) {
|
|
451
|
-
const testValue = toJavaScriptType(value, 'integer');
|
|
452
|
-
if (testValue !== null) {
|
|
453
|
-
return +testValue;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
if (types.includes('number')) {
|
|
457
|
-
const testValue = toJavaScriptType(value, 'number');
|
|
458
|
-
if (testValue !== null) {
|
|
459
|
-
return +testValue;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
if ((isString(value) || isNumber(value, 'strict')) &&
|
|
463
|
-
types.includes('string')) { // Convert number to string
|
|
464
|
-
return toJavaScriptType(value, 'string');
|
|
465
|
-
}
|
|
466
|
-
if (types.includes('boolean') && isBoolean(value)) {
|
|
467
|
-
return toJavaScriptType(value, 'boolean');
|
|
468
|
-
}
|
|
469
|
-
if (types.includes('string')) { // Convert null & boolean to string
|
|
470
|
-
if (value === null) {
|
|
471
|
-
return '';
|
|
472
|
-
}
|
|
473
|
-
const testValue = toJavaScriptType(value, 'string');
|
|
474
|
-
if (testValue !== null) {
|
|
475
|
-
return testValue;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
if ((types.includes('number') ||
|
|
479
|
-
types.includes('integer'))) {
|
|
480
|
-
if (value === true) {
|
|
481
|
-
return 1;
|
|
482
|
-
} // Convert boolean & null to number
|
|
483
|
-
if (value === false || value === null || value === '') {
|
|
484
|
-
return 0;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (types.includes('number')) { // Convert mixed string to number
|
|
488
|
-
const testValue = parseFloat(value);
|
|
489
|
-
if (!!testValue) {
|
|
490
|
-
return testValue;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
if (types.includes('integer')) { // Convert string or number to integer
|
|
494
|
-
const testValue = parseInt(value, 10);
|
|
495
|
-
if (!!testValue) {
|
|
496
|
-
return testValue;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
if (types.includes('boolean')) { // Convert anything to boolean
|
|
500
|
-
return !!value;
|
|
501
|
-
}
|
|
502
|
-
if ((types.includes('number') ||
|
|
503
|
-
types.includes('integer')) && !types.includes('null')) {
|
|
504
|
-
return 0; // If null not allowed, return 0 for non-convertable values
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* 'isPromise' function
|
|
509
|
-
*
|
|
510
|
-
* // object
|
|
511
|
-
* // { boolean }
|
|
512
|
-
*/
|
|
513
|
-
export function isPromise(object) {
|
|
514
|
-
return !!object && typeof object.then === 'function';
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* 'isObservable' function
|
|
518
|
-
*
|
|
519
|
-
* // object
|
|
520
|
-
* // { boolean }
|
|
521
|
-
*/
|
|
522
|
-
export function isObservable(object) {
|
|
523
|
-
return !!object && typeof object.subscribe === 'function';
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* '_toPromise' function
|
|
527
|
-
*
|
|
528
|
-
* // { object } object
|
|
529
|
-
* // { Promise<any> }
|
|
530
|
-
*/
|
|
531
|
-
export function _toPromise(object) {
|
|
532
|
-
return isPromise(object) ? object : object.toPromise();
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* 'toObservable' function
|
|
536
|
-
*
|
|
537
|
-
* // { object } object
|
|
538
|
-
* // { Observable<any> }
|
|
539
|
-
*/
|
|
540
|
-
export function toObservable(object) {
|
|
541
|
-
const observable = isPromise(object) ? from(object) : object;
|
|
542
|
-
if (isObservable(observable)) {
|
|
543
|
-
return observable;
|
|
544
|
-
}
|
|
545
|
-
console.error('toObservable error: Expected validator to return Promise or Observable.');
|
|
546
|
-
return new Observable();
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* 'inArray' function
|
|
550
|
-
*
|
|
551
|
-
* Searches an array for an item, or one of a list of items, and returns true
|
|
552
|
-
* as soon as a match is found, or false if no match.
|
|
553
|
-
*
|
|
554
|
-
* If the optional third parameter allIn is set to TRUE, and the item to find
|
|
555
|
-
* is an array, then the function returns true only if all elements from item
|
|
556
|
-
* are found in the array list, and false if any element is not found. If the
|
|
557
|
-
* item to find is not an array, setting allIn to TRUE has no effect.
|
|
558
|
-
*
|
|
559
|
-
* // { any|any[] } item - the item to search for
|
|
560
|
-
* // array - the array to search
|
|
561
|
-
* // { boolean = false } allIn - if TRUE, all items must be in array
|
|
562
|
-
* // { boolean } - true if item(s) in array, false otherwise
|
|
563
|
-
*/
|
|
564
|
-
export function inArray(item, array, allIn = false) {
|
|
565
|
-
if (!isDefined(item) || !isArray(array)) {
|
|
566
|
-
return false;
|
|
567
|
-
}
|
|
568
|
-
return isArray(item) ?
|
|
569
|
-
item[allIn ? 'every' : 'some'](subItem => array.includes(subItem)) :
|
|
570
|
-
array.includes(item);
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* 'xor' utility function - exclusive or
|
|
574
|
-
*
|
|
575
|
-
* Returns true if exactly one of two values is truthy.
|
|
576
|
-
*
|
|
577
|
-
* // value1 - first value to check
|
|
578
|
-
* // value2 - second value to check
|
|
579
|
-
* // { boolean } - true if exactly one input value is truthy, false if not
|
|
580
|
-
*/
|
|
581
|
-
export function xor(value1, value2) {
|
|
582
|
-
return (!!value1 && !value2) || (!value1 && !!value2);
|
|
583
|
-
}
|
|
1
|
+
import { from, Observable } from 'rxjs';
|
|
2
|
+
/**
|
|
3
|
+
* '_executeValidators' utility function
|
|
4
|
+
*
|
|
5
|
+
* Validates a control against an array of validators, and returns
|
|
6
|
+
* an array of the same length containing a combination of error messages
|
|
7
|
+
* (from invalid validators) and null values (from valid validators)
|
|
8
|
+
*
|
|
9
|
+
* // { AbstractControl } control - control to validate
|
|
10
|
+
* // { IValidatorFn[] } validators - array of validators
|
|
11
|
+
* // { boolean } invert - invert?
|
|
12
|
+
* // { PlainObject[] } - array of nulls and error message
|
|
13
|
+
*/
|
|
14
|
+
export function _executeValidators(control, validators, invert = false) {
|
|
15
|
+
return validators.map(validator => validator(control, invert));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* '_executeAsyncValidators' utility function
|
|
19
|
+
*
|
|
20
|
+
* Validates a control against an array of async validators, and returns
|
|
21
|
+
* an array of observabe results of the same length containing a combination of
|
|
22
|
+
* error messages (from invalid validators) and null values (from valid ones)
|
|
23
|
+
*
|
|
24
|
+
* // { AbstractControl } control - control to validate
|
|
25
|
+
* // { AsyncIValidatorFn[] } validators - array of async validators
|
|
26
|
+
* // { boolean } invert - invert?
|
|
27
|
+
* // - array of observable nulls and error message
|
|
28
|
+
*/
|
|
29
|
+
export function _executeAsyncValidators(control, validators, invert = false) {
|
|
30
|
+
return validators.map(validator => validator(control, invert));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* '_mergeObjects' utility function
|
|
34
|
+
*
|
|
35
|
+
* Recursively Merges one or more objects into a single object with combined keys.
|
|
36
|
+
* Automatically detects and ignores null and undefined inputs.
|
|
37
|
+
* Also detects duplicated boolean 'not' keys and XORs their values.
|
|
38
|
+
*
|
|
39
|
+
* // { PlainObject[] } objects - one or more objects to merge
|
|
40
|
+
* // { PlainObject } - merged object
|
|
41
|
+
*/
|
|
42
|
+
export function _mergeObjects(...objects) {
|
|
43
|
+
const mergedObject = {};
|
|
44
|
+
for (const currentObject of objects) {
|
|
45
|
+
if (isObject(currentObject)) {
|
|
46
|
+
for (const key of Object.keys(currentObject)) {
|
|
47
|
+
const currentValue = currentObject[key];
|
|
48
|
+
const mergedValue = mergedObject[key];
|
|
49
|
+
mergedObject[key] = !isDefined(mergedValue) ? currentValue :
|
|
50
|
+
key === 'not' && isBoolean(mergedValue, 'strict') &&
|
|
51
|
+
isBoolean(currentValue, 'strict') ? xor(mergedValue, currentValue) :
|
|
52
|
+
getType(mergedValue) === 'object' && getType(currentValue) === 'object' ?
|
|
53
|
+
_mergeObjects(mergedValue, currentValue) :
|
|
54
|
+
currentValue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return mergedObject;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* '_mergeErrors' utility function
|
|
62
|
+
*
|
|
63
|
+
* Merges an array of objects.
|
|
64
|
+
* Used for combining the validator errors returned from 'executeValidators'
|
|
65
|
+
*
|
|
66
|
+
* // { PlainObject[] } arrayOfErrors - array of objects
|
|
67
|
+
* // { PlainObject } - merged object, or null if no usable input objectcs
|
|
68
|
+
*/
|
|
69
|
+
export function _mergeErrors(arrayOfErrors) {
|
|
70
|
+
const mergedErrors = _mergeObjects(...arrayOfErrors);
|
|
71
|
+
return isEmpty(mergedErrors) ? null : mergedErrors;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 'isDefined' utility function
|
|
75
|
+
*
|
|
76
|
+
* Checks if a variable contains a value of any type.
|
|
77
|
+
* Returns true even for otherwise 'falsey' values of 0, '', and false.
|
|
78
|
+
*
|
|
79
|
+
* // value - the value to check
|
|
80
|
+
* // { boolean } - false if undefined or null, otherwise true
|
|
81
|
+
*/
|
|
82
|
+
export function isDefined(value) {
|
|
83
|
+
return value !== undefined && value !== null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 'hasValue' utility function
|
|
87
|
+
*
|
|
88
|
+
* Checks if a variable contains a value.
|
|
89
|
+
* Returs false for null, undefined, or a zero-length strng, '',
|
|
90
|
+
* otherwise returns true.
|
|
91
|
+
* (Stricter than 'isDefined' because it also returns false for '',
|
|
92
|
+
* though it stil returns true for otherwise 'falsey' values 0 and false.)
|
|
93
|
+
*
|
|
94
|
+
* // value - the value to check
|
|
95
|
+
* // { boolean } - false if undefined, null, or '', otherwise true
|
|
96
|
+
*/
|
|
97
|
+
export function hasValue(value) {
|
|
98
|
+
return value !== undefined && value !== null && value !== '';
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 'isEmpty' utility function
|
|
102
|
+
*
|
|
103
|
+
* Similar to !hasValue, but also returns true for empty arrays and objects.
|
|
104
|
+
*
|
|
105
|
+
* // value - the value to check
|
|
106
|
+
* // { boolean } - false if undefined, null, or '', otherwise true
|
|
107
|
+
*/
|
|
108
|
+
export function isEmpty(value) {
|
|
109
|
+
if (isArray(value)) {
|
|
110
|
+
return !value.length;
|
|
111
|
+
}
|
|
112
|
+
if (isObject(value)) {
|
|
113
|
+
return !Object.keys(value).length;
|
|
114
|
+
}
|
|
115
|
+
return value === undefined || value === null || value === '';
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 'isString' utility function
|
|
119
|
+
*
|
|
120
|
+
* Checks if a value is a string.
|
|
121
|
+
*
|
|
122
|
+
* // value - the value to check
|
|
123
|
+
* // { boolean } - true if string, false if not
|
|
124
|
+
*/
|
|
125
|
+
export function isString(value) {
|
|
126
|
+
return typeof value === 'string';
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 'isNumber' utility function
|
|
130
|
+
*
|
|
131
|
+
* Checks if a value is a regular number, numeric string, or JavaScript Date.
|
|
132
|
+
*
|
|
133
|
+
* // value - the value to check
|
|
134
|
+
* // { any = false } strict - if truthy, also checks JavaScript tyoe
|
|
135
|
+
* // { boolean } - true if number, false if not
|
|
136
|
+
*/
|
|
137
|
+
export function isNumber(value, strict = false) {
|
|
138
|
+
if (strict && typeof value !== 'number') {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return !isNaN(value) && value !== value / 0;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 'isInteger' utility function
|
|
145
|
+
*
|
|
146
|
+
* Checks if a value is an integer.
|
|
147
|
+
*
|
|
148
|
+
* // value - the value to check
|
|
149
|
+
* // { any = false } strict - if truthy, also checks JavaScript tyoe
|
|
150
|
+
* // {boolean } - true if number, false if not
|
|
151
|
+
*/
|
|
152
|
+
export function isInteger(value, strict = false) {
|
|
153
|
+
if (strict && typeof value !== 'number') {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
return !isNaN(value) && value !== value / 0 && value % 1 === 0;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 'isBoolean' utility function
|
|
160
|
+
*
|
|
161
|
+
* Checks if a value is a boolean.
|
|
162
|
+
*
|
|
163
|
+
* // value - the value to check
|
|
164
|
+
* // { any = null } option - if 'strict', also checks JavaScript type
|
|
165
|
+
* if TRUE or FALSE, checks only for that value
|
|
166
|
+
* // { boolean } - true if boolean, false if not
|
|
167
|
+
*/
|
|
168
|
+
export function isBoolean(value, option = null) {
|
|
169
|
+
if (option === 'strict') {
|
|
170
|
+
return value === true || value === false;
|
|
171
|
+
}
|
|
172
|
+
if (option === true) {
|
|
173
|
+
return value === true || value === 1 || value === 'true' || value === '1';
|
|
174
|
+
}
|
|
175
|
+
if (option === false) {
|
|
176
|
+
return value === false || value === 0 || value === 'false' || value === '0';
|
|
177
|
+
}
|
|
178
|
+
return value === true || value === 1 || value === 'true' || value === '1' ||
|
|
179
|
+
value === false || value === 0 || value === 'false' || value === '0';
|
|
180
|
+
}
|
|
181
|
+
export function isFunction(item) {
|
|
182
|
+
return typeof item === 'function';
|
|
183
|
+
}
|
|
184
|
+
export function isObject(item) {
|
|
185
|
+
return item !== null && typeof item === 'object';
|
|
186
|
+
}
|
|
187
|
+
export function isArray(item) {
|
|
188
|
+
return Array.isArray(item);
|
|
189
|
+
}
|
|
190
|
+
export function isDate(item) {
|
|
191
|
+
return !!item && Object.prototype.toString.call(item) === '[object Date]';
|
|
192
|
+
}
|
|
193
|
+
export function isMap(item) {
|
|
194
|
+
return !!item && Object.prototype.toString.call(item) === '[object Map]';
|
|
195
|
+
}
|
|
196
|
+
export function isSet(item) {
|
|
197
|
+
return !!item && Object.prototype.toString.call(item) === '[object Set]';
|
|
198
|
+
}
|
|
199
|
+
export function isSymbol(item) {
|
|
200
|
+
return typeof item === 'symbol';
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 'getType' function
|
|
204
|
+
*
|
|
205
|
+
* Detects the JSON Schema Type of a value.
|
|
206
|
+
* By default, detects numbers and integers even if formatted as strings.
|
|
207
|
+
* (So all integers are also numbers, and any number may also be a string.)
|
|
208
|
+
* However, it only detects true boolean values (to detect boolean values
|
|
209
|
+
* in non-boolean formats, use isBoolean() instead).
|
|
210
|
+
*
|
|
211
|
+
* If passed a second optional parameter of 'strict', it will only detect
|
|
212
|
+
* numbers and integers if they are formatted as JavaScript numbers.
|
|
213
|
+
*
|
|
214
|
+
* Examples:
|
|
215
|
+
* getType('10.5') = 'number'
|
|
216
|
+
* getType(10.5) = 'number'
|
|
217
|
+
* getType('10') = 'integer'
|
|
218
|
+
* getType(10) = 'integer'
|
|
219
|
+
* getType('true') = 'string'
|
|
220
|
+
* getType(true) = 'boolean'
|
|
221
|
+
* getType(null) = 'null'
|
|
222
|
+
* getType({ }) = 'object'
|
|
223
|
+
* getType([]) = 'array'
|
|
224
|
+
*
|
|
225
|
+
* getType('10.5', 'strict') = 'string'
|
|
226
|
+
* getType(10.5, 'strict') = 'number'
|
|
227
|
+
* getType('10', 'strict') = 'string'
|
|
228
|
+
* getType(10, 'strict') = 'integer'
|
|
229
|
+
* getType('true', 'strict') = 'string'
|
|
230
|
+
* getType(true, 'strict') = 'boolean'
|
|
231
|
+
*
|
|
232
|
+
* // value - value to check
|
|
233
|
+
* // { any = false } strict - if truthy, also checks JavaScript tyoe
|
|
234
|
+
* // { SchemaType }
|
|
235
|
+
*/
|
|
236
|
+
export function getType(value, strict = false) {
|
|
237
|
+
if (!isDefined(value)) {
|
|
238
|
+
return 'null';
|
|
239
|
+
}
|
|
240
|
+
if (isArray(value)) {
|
|
241
|
+
return 'array';
|
|
242
|
+
}
|
|
243
|
+
if (isObject(value)) {
|
|
244
|
+
return 'object';
|
|
245
|
+
}
|
|
246
|
+
if (isBoolean(value, 'strict')) {
|
|
247
|
+
return 'boolean';
|
|
248
|
+
}
|
|
249
|
+
if (isInteger(value, strict)) {
|
|
250
|
+
return 'integer';
|
|
251
|
+
}
|
|
252
|
+
if (isNumber(value, strict)) {
|
|
253
|
+
return 'number';
|
|
254
|
+
}
|
|
255
|
+
if (isString(value) || (!strict && isDate(value))) {
|
|
256
|
+
return 'string';
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* 'isType' function
|
|
262
|
+
*
|
|
263
|
+
* Checks wether an input (probably string) value contains data of
|
|
264
|
+
* a specified JSON Schema type
|
|
265
|
+
*
|
|
266
|
+
* // { PrimitiveValue } value - value to check
|
|
267
|
+
* // { SchemaPrimitiveType } type - type to check
|
|
268
|
+
* // { boolean }
|
|
269
|
+
*/
|
|
270
|
+
export function isType(value, type) {
|
|
271
|
+
switch (type) {
|
|
272
|
+
case 'string':
|
|
273
|
+
return isString(value) || isDate(value);
|
|
274
|
+
case 'number':
|
|
275
|
+
return isNumber(value);
|
|
276
|
+
case 'integer':
|
|
277
|
+
return isInteger(value);
|
|
278
|
+
case 'boolean':
|
|
279
|
+
return isBoolean(value);
|
|
280
|
+
case 'null':
|
|
281
|
+
return !hasValue(value);
|
|
282
|
+
default:
|
|
283
|
+
console.error(`isType error: "${type}" is not a recognized type.`);
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* 'isPrimitive' function
|
|
289
|
+
*
|
|
290
|
+
* Checks wether an input value is a JavaScript primitive type:
|
|
291
|
+
* string, number, boolean, or null.
|
|
292
|
+
*
|
|
293
|
+
* // value - value to check
|
|
294
|
+
* // { boolean }
|
|
295
|
+
*/
|
|
296
|
+
export function isPrimitive(value) {
|
|
297
|
+
return (isString(value) || isNumber(value) ||
|
|
298
|
+
isBoolean(value, 'strict') || value === null);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
*
|
|
302
|
+
* @param date
|
|
303
|
+
* @returns {string}
|
|
304
|
+
* exmaple:
|
|
305
|
+
* toDateString('2018-01-01') = '2018-01-01'
|
|
306
|
+
* toDateString('2018-01-30T00:00:00.000Z') = '2018-01-30'
|
|
307
|
+
*/
|
|
308
|
+
export const toIsoString = (date) => {
|
|
309
|
+
const day = date.getDate();
|
|
310
|
+
const month = date.getMonth() + 1;
|
|
311
|
+
const year = date.getFullYear();
|
|
312
|
+
return `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`;
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* 'toJavaScriptType' function
|
|
316
|
+
*
|
|
317
|
+
* Converts an input (probably string) value to a JavaScript primitive type -
|
|
318
|
+
* 'string', 'number', 'boolean', or 'null' - before storing in a JSON object.
|
|
319
|
+
*
|
|
320
|
+
* Does not coerce values (other than null), and only converts the types
|
|
321
|
+
* of values that would otherwise be valid.
|
|
322
|
+
*
|
|
323
|
+
* If the optional third parameter 'strictIntegers' is TRUE, and the
|
|
324
|
+
* JSON Schema type 'integer' is specified, it also verifies the input value
|
|
325
|
+
* is an integer and, if it is, returns it as a JaveScript number.
|
|
326
|
+
* If 'strictIntegers' is FALSE (or not set) the type 'integer' is treated
|
|
327
|
+
* exactly the same as 'number', and allows decimals.
|
|
328
|
+
*
|
|
329
|
+
* Valid Examples:
|
|
330
|
+
* toJavaScriptType('10', 'number' ) = 10 // '10' is a number
|
|
331
|
+
* toJavaScriptType('10', 'integer') = 10 // '10' is also an integer
|
|
332
|
+
* toJavaScriptType( 10, 'integer') = 10 // 10 is still an integer
|
|
333
|
+
* toJavaScriptType( 10, 'string' ) = '10' // 10 can be made into a string
|
|
334
|
+
* toJavaScriptType('10.5', 'number' ) = 10.5 // '10.5' is a number
|
|
335
|
+
*
|
|
336
|
+
* Invalid Examples:
|
|
337
|
+
* toJavaScriptType('10.5', 'integer') = null // '10.5' is not an integer
|
|
338
|
+
* toJavaScriptType( 10.5, 'integer') = null // 10.5 is still not an integer
|
|
339
|
+
*
|
|
340
|
+
* // { PrimitiveValue } value - value to convert
|
|
341
|
+
* // { SchemaPrimitiveType | SchemaPrimitiveType[] } types - types to convert to
|
|
342
|
+
* // { boolean = false } strictIntegers - if FALSE, treat integers as numbers
|
|
343
|
+
* // { PrimitiveValue }
|
|
344
|
+
*/
|
|
345
|
+
export function toJavaScriptType(value, types, strictIntegers = true) {
|
|
346
|
+
if (!isDefined(value)) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
if (isString(types)) {
|
|
350
|
+
types = [types];
|
|
351
|
+
}
|
|
352
|
+
if (strictIntegers && inArray('integer', types)) {
|
|
353
|
+
if (isInteger(value, 'strict')) {
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
if (isInteger(value)) {
|
|
357
|
+
return parseInt(value, 10);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (inArray('number', types) || (!strictIntegers && inArray('integer', types))) {
|
|
361
|
+
if (isNumber(value, 'strict')) {
|
|
362
|
+
return value;
|
|
363
|
+
}
|
|
364
|
+
if (isNumber(value)) {
|
|
365
|
+
return parseFloat(value);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (inArray('string', types)) {
|
|
369
|
+
if (isString(value)) {
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
372
|
+
// If value is a date, and types includes 'string',
|
|
373
|
+
// convert the date to a string
|
|
374
|
+
if (isDate(value)) {
|
|
375
|
+
return toIsoString(value);
|
|
376
|
+
}
|
|
377
|
+
if (isNumber(value)) {
|
|
378
|
+
return value.toString();
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
// If value is a date, and types includes 'integer' or 'number',
|
|
382
|
+
// but not 'string', convert the date to a number
|
|
383
|
+
if (isDate(value) && (inArray('integer', types) || inArray('number', types))) {
|
|
384
|
+
return value.getTime();
|
|
385
|
+
}
|
|
386
|
+
if (inArray('boolean', types)) {
|
|
387
|
+
if (isBoolean(value, true)) {
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
if (isBoolean(value, false)) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* 'toSchemaType' function
|
|
398
|
+
*
|
|
399
|
+
* Converts an input (probably string) value to the "best" JavaScript
|
|
400
|
+
* equivalent available from an allowed list of JSON Schema types, which may
|
|
401
|
+
* contain 'string', 'number', 'integer', 'boolean', and/or 'null'.
|
|
402
|
+
* If necssary, it does progressively agressive type coersion.
|
|
403
|
+
* It will not return null unless null is in the list of allowed types.
|
|
404
|
+
*
|
|
405
|
+
* Number conversion examples:
|
|
406
|
+
* toSchemaType('10', ['number','integer','string']) = 10 // integer
|
|
407
|
+
* toSchemaType('10', ['number','string']) = 10 // number
|
|
408
|
+
* toSchemaType('10', ['string']) = '10' // string
|
|
409
|
+
* toSchemaType('10.5', ['number','integer','string']) = 10.5 // number
|
|
410
|
+
* toSchemaType('10.5', ['integer','string']) = '10.5' // string
|
|
411
|
+
* toSchemaType('10.5', ['integer']) = 10 // integer
|
|
412
|
+
* toSchemaType(10.5, ['null','boolean','string']) = '10.5' // string
|
|
413
|
+
* toSchemaType(10.5, ['null','boolean']) = true // boolean
|
|
414
|
+
*
|
|
415
|
+
* String conversion examples:
|
|
416
|
+
* toSchemaType('1.5x', ['boolean','number','integer','string']) = '1.5x' // string
|
|
417
|
+
* toSchemaType('1.5x', ['boolean','number','integer']) = '1.5' // number
|
|
418
|
+
* toSchemaType('1.5x', ['boolean','integer']) = '1' // integer
|
|
419
|
+
* toSchemaType('1.5x', ['boolean']) = true // boolean
|
|
420
|
+
* toSchemaType('xyz', ['number','integer','boolean','null']) = true // boolean
|
|
421
|
+
* toSchemaType('xyz', ['number','integer','null']) = null // null
|
|
422
|
+
* toSchemaType('xyz', ['number','integer']) = 0 // number
|
|
423
|
+
*
|
|
424
|
+
* Boolean conversion examples:
|
|
425
|
+
* toSchemaType('1', ['integer','number','string','boolean']) = 1 // integer
|
|
426
|
+
* toSchemaType('1', ['number','string','boolean']) = 1 // number
|
|
427
|
+
* toSchemaType('1', ['string','boolean']) = '1' // string
|
|
428
|
+
* toSchemaType('1', ['boolean']) = true // boolean
|
|
429
|
+
* toSchemaType('true', ['number','string','boolean']) = 'true' // string
|
|
430
|
+
* toSchemaType('true', ['boolean']) = true // boolean
|
|
431
|
+
* toSchemaType('true', ['number']) = 0 // number
|
|
432
|
+
* toSchemaType(true, ['number','string','boolean']) = true // boolean
|
|
433
|
+
* toSchemaType(true, ['number','string']) = 'true' // string
|
|
434
|
+
* toSchemaType(true, ['number']) = 1 // number
|
|
435
|
+
*
|
|
436
|
+
* // { PrimitiveValue } value - value to convert
|
|
437
|
+
* // { SchemaPrimitiveType | SchemaPrimitiveType[] } types - allowed types to convert to
|
|
438
|
+
* // { PrimitiveValue }
|
|
439
|
+
*/
|
|
440
|
+
export function toSchemaType(value, types) {
|
|
441
|
+
if (!isArray(types)) {
|
|
442
|
+
types = [types];
|
|
443
|
+
}
|
|
444
|
+
if (types.includes('null') && !hasValue(value)) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
if (types.includes('boolean') && !isBoolean(value, 'strict')) {
|
|
448
|
+
return value;
|
|
449
|
+
}
|
|
450
|
+
if (types.includes('integer')) {
|
|
451
|
+
const testValue = toJavaScriptType(value, 'integer');
|
|
452
|
+
if (testValue !== null) {
|
|
453
|
+
return +testValue;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (types.includes('number')) {
|
|
457
|
+
const testValue = toJavaScriptType(value, 'number');
|
|
458
|
+
if (testValue !== null) {
|
|
459
|
+
return +testValue;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if ((isString(value) || isNumber(value, 'strict')) &&
|
|
463
|
+
types.includes('string')) { // Convert number to string
|
|
464
|
+
return toJavaScriptType(value, 'string');
|
|
465
|
+
}
|
|
466
|
+
if (types.includes('boolean') && isBoolean(value)) {
|
|
467
|
+
return toJavaScriptType(value, 'boolean');
|
|
468
|
+
}
|
|
469
|
+
if (types.includes('string')) { // Convert null & boolean to string
|
|
470
|
+
if (value === null) {
|
|
471
|
+
return '';
|
|
472
|
+
}
|
|
473
|
+
const testValue = toJavaScriptType(value, 'string');
|
|
474
|
+
if (testValue !== null) {
|
|
475
|
+
return testValue;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if ((types.includes('number') ||
|
|
479
|
+
types.includes('integer'))) {
|
|
480
|
+
if (value === true) {
|
|
481
|
+
return 1;
|
|
482
|
+
} // Convert boolean & null to number
|
|
483
|
+
if (value === false || value === null || value === '') {
|
|
484
|
+
return 0;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (types.includes('number')) { // Convert mixed string to number
|
|
488
|
+
const testValue = parseFloat(value);
|
|
489
|
+
if (!!testValue) {
|
|
490
|
+
return testValue;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (types.includes('integer')) { // Convert string or number to integer
|
|
494
|
+
const testValue = parseInt(value, 10);
|
|
495
|
+
if (!!testValue) {
|
|
496
|
+
return testValue;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (types.includes('boolean')) { // Convert anything to boolean
|
|
500
|
+
return !!value;
|
|
501
|
+
}
|
|
502
|
+
if ((types.includes('number') ||
|
|
503
|
+
types.includes('integer')) && !types.includes('null')) {
|
|
504
|
+
return 0; // If null not allowed, return 0 for non-convertable values
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* 'isPromise' function
|
|
509
|
+
*
|
|
510
|
+
* // object
|
|
511
|
+
* // { boolean }
|
|
512
|
+
*/
|
|
513
|
+
export function isPromise(object) {
|
|
514
|
+
return !!object && typeof object.then === 'function';
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* 'isObservable' function
|
|
518
|
+
*
|
|
519
|
+
* // object
|
|
520
|
+
* // { boolean }
|
|
521
|
+
*/
|
|
522
|
+
export function isObservable(object) {
|
|
523
|
+
return !!object && typeof object.subscribe === 'function';
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* '_toPromise' function
|
|
527
|
+
*
|
|
528
|
+
* // { object } object
|
|
529
|
+
* // { Promise<any> }
|
|
530
|
+
*/
|
|
531
|
+
export function _toPromise(object) {
|
|
532
|
+
return isPromise(object) ? object : object.toPromise();
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* 'toObservable' function
|
|
536
|
+
*
|
|
537
|
+
* // { object } object
|
|
538
|
+
* // { Observable<any> }
|
|
539
|
+
*/
|
|
540
|
+
export function toObservable(object) {
|
|
541
|
+
const observable = isPromise(object) ? from(object) : object;
|
|
542
|
+
if (isObservable(observable)) {
|
|
543
|
+
return observable;
|
|
544
|
+
}
|
|
545
|
+
console.error('toObservable error: Expected validator to return Promise or Observable.');
|
|
546
|
+
return new Observable();
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* 'inArray' function
|
|
550
|
+
*
|
|
551
|
+
* Searches an array for an item, or one of a list of items, and returns true
|
|
552
|
+
* as soon as a match is found, or false if no match.
|
|
553
|
+
*
|
|
554
|
+
* If the optional third parameter allIn is set to TRUE, and the item to find
|
|
555
|
+
* is an array, then the function returns true only if all elements from item
|
|
556
|
+
* are found in the array list, and false if any element is not found. If the
|
|
557
|
+
* item to find is not an array, setting allIn to TRUE has no effect.
|
|
558
|
+
*
|
|
559
|
+
* // { any|any[] } item - the item to search for
|
|
560
|
+
* // array - the array to search
|
|
561
|
+
* // { boolean = false } allIn - if TRUE, all items must be in array
|
|
562
|
+
* // { boolean } - true if item(s) in array, false otherwise
|
|
563
|
+
*/
|
|
564
|
+
export function inArray(item, array, allIn = false) {
|
|
565
|
+
if (!isDefined(item) || !isArray(array)) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
return isArray(item) ?
|
|
569
|
+
item[allIn ? 'every' : 'some'](subItem => array.includes(subItem)) :
|
|
570
|
+
array.includes(item);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* 'xor' utility function - exclusive or
|
|
574
|
+
*
|
|
575
|
+
* Returns true if exactly one of two values is truthy.
|
|
576
|
+
*
|
|
577
|
+
* // value1 - first value to check
|
|
578
|
+
* // value2 - second value to check
|
|
579
|
+
* // { boolean } - true if exactly one input value is truthy, false if not
|
|
580
|
+
*/
|
|
581
|
+
export function xor(value1, value2) {
|
|
582
|
+
return (!!value1 && !value2) || (!value1 && !!value2);
|
|
583
|
+
}
|
|
584
584
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmZ1bmN0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25nLWZvcm13b3Jrcy1jb3JlL3NyYy9saWIvc2hhcmVkL3ZhbGlkYXRvci5mdW5jdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFnRHhDOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxHQUFHLEtBQUs7SUFDcEUsT0FBTyxVQUFVLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0FBQ2pFLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sVUFBVSx1QkFBdUIsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sR0FBRyxLQUFLO0lBQ3pFLE9BQU8sVUFBVSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUNqRSxDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxHQUFHLE9BQU87SUFDdEMsTUFBTSxZQUFZLEdBQWdCLEVBQUcsQ0FBQztJQUN0QyxLQUFLLE1BQU0sYUFBYSxJQUFJLE9BQU8sRUFBRTtRQUNuQyxJQUFJLFFBQVEsQ0FBQyxhQUFhLENBQUMsRUFBRTtZQUMzQixLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQUU7Z0JBQzVDLE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDeEMsTUFBTSxXQUFXLEdBQUcsWUFBWSxDQUFDLEdB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Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFNLFVBQVUsT0FBTyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsS0FBSyxHQUFHLEtBQUs7SUFDaEQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUFFLE9BQU8sS0FBSyxDQUFDO0tBQUU7SUFDMUQsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNwQixJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDcEUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUN6QixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNO0lBQ2hDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDeEQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFic3RyYWN0Q29udHJvbCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgZnJvbSwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRvciB1dGlsaXR5IGZ1bmN0aW9uIGxpYnJhcnk6XHJcbiAqXHJcbiAqIFZhbGlkYXRvciBhbmQgZXJyb3IgdXRpbGl0aWVzOlxyXG4gKiAgIF9leGVjdXRlVmFsaWRhdG9ycywgX2V4ZWN1dGVBc3luY1ZhbGlkYXRvcnMsIF9tZXJnZU9iamVjdHMsIF9tZXJnZUVycm9yc1xyXG4gKlxyXG4gKiBJbmRpdmlkdWFsIHZhbHVlIGNoZWNraW5nOlxyXG4gKiAgIGlzRGVmaW5lZCwgaGFzVmFsdWUsIGlzRW1wdHlcclxuICpcclxuICogSW5kaXZpZHVhbCB0eXBlIGNoZWNraW5nOlxyXG4gKiAgIGlzU3RyaW5nLCBpc051bWJlciwgaXNJbnRlZ2VyLCBpc0Jvb2xlYW4sIGlzRnVuY3Rpb24sIGlzT2JqZWN0LCBpc0FycmF5LFxyXG4gKiAgIGlzTWFwLCBpc1NldCwgaXNQcm9taXNlLCBpc09ic2VydmFibGVcclxuICpcclxuICogTXVsdGlwbGUgdHlwZSBjaGVja2luZyBhbmQgZml4aW5nOlxyXG4gKiAgIGdldFR5cGUsIGlzVHlwZSwgaXNQcmltaXRpdmUsIHRvSmF2YVNjcmlwdFR5cGUsIHRvU2NoZW1hVHlwZSxcclxuICogICBfdG9Qcm9taXNlLCB0b09ic2VydmFibGVcclxuICpcclxuICogVXRpbGl0eSBmdW5jdGlvbnM6XHJcbiAqICAgaW5BcnJheSwgeG9yXHJcbiAqXHJcbiAqIFR5cGVzY3JpcHQgdHlwZXMgYW5kIGludGVyZmFjZXM6XHJcbiAqICAgU2NoZW1hUHJpbWl0aXZlVHlwZSwgU2NoZW1hVHlwZSwgSmF2YVNjcmlwdFByaW1pdGl2ZVR5cGUsIEphdmFTY3JpcHRUeXBlLFxyXG4gKiAgIFByaW1pdGl2ZVZhbHVlLCBQbGFpbk9iamVjdCwgSVZhbGlkYXRvckZuLCBBc3luY0lWYWxpZGF0b3JGblxyXG4gKlxyXG4gKiBOb3RlOiAnSVZhbGlkYXRvckZuJyBpcyBzaG9ydCBmb3IgJ2ludmVydGFibGUgdmFsaWRhdG9yIGZ1bmN0aW9uJyxcclxuICogICB3aGljaCBpcyBhIHZhbGlkYXRvciBmdW5jdGlvbnMgdGhhdCBhY2NlcHRzIGFuIG9wdGlvbmFsIHNlY29uZFxyXG4gKiAgIGFyZ3VtZW50IHdoaWNoLCBpZiBzZXQgdG8gVFJVRSwgY2F1c2VzIHRoZSB2YWxpZGF0b3IgdG8gcGVyZm9ybVxyXG4gKiAgIHRoZSBvcHBvc2l0ZSBvZiBpdHMgb3JpZ2luYWwgZnVuY3Rpb24uXHJcbiAqL1xyXG5cclxuZXhwb3J0IHR5cGUgU2NoZW1hUHJpbWl0aXZlVHlwZSA9XHJcbiAgJ3N0cmluZycgfCAnbnVtYmVyJyB8ICdpbnRlZ2VyJyB8ICdib29sZWFuJyB8ICdudWxsJztcclxuZXhwb3J0IHR5cGUgU2NoZW1hVHlwZSA9XHJcbiAgJ3N0cmluZycgfCAnbnVtYmVyJyB8ICdpbnRlZ2VyJyB8ICdib29sZWFuJyB8ICdudWxsJyB8ICdvYmplY3QnIHwgJ2FycmF5JztcclxuZXhwb3J0IHR5cGUgSmF2YVNjcmlwdFByaW1pdGl2ZVR5cGUgPVxyXG4gICdzdHJpbmcnIHwgJ251bWJlcicgfCAnYm9vbGVhbicgfCAnbnVsbCcgfCAndW5kZWZpbmVkJztcclxuZXhwb3J0IHR5cGUgSmF2YVNjcmlwdFR5cGUgPVxyXG4gICdzdHJpbmcnIHwgJ251bWJlcicgfCAnYm9vbGVhbicgfCAnbnVsbCcgfCAndW5kZWZpbmVkJyB8ICdvYmplY3QnIHwgJ2FycmF5JyB8XHJcbiAgJ21hcCcgfCAnc2V0JyB8ICdhcmd1bWVudHMnIHwgJ2RhdGUnIHwgJ2Vycm9yJyB8ICdmdW5jdGlvbicgfCAnanNvbicgfFxyXG4gICdtYXRoJyB8ICdyZWdleHAnOyAvLyBOb3RlOiB0aGlzIGxpc3QgaXMgaW5jb21wbGV0ZVxyXG5leHBvcnQgdHlwZSBQcmltaXRpdmVWYWx1ZSA9IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBudWxsIHwgdW5kZWZpbmVkO1xyXG5leHBvcnQgaW50ZXJmYWNlIFBsYWluT2JqZWN0IHsgW2s6IHN0cmluZ106IGFueTsgfVxyXG5cclxuZXhwb3J0IHR5cGUgSVZhbGlkYXRvckZuID0gKGM6IEFic3RyYWN0Q29udHJvbCwgaT86IGJvb2xlYW4pID0+IFBsYWluT2JqZWN0O1xyXG5leHBvcnQgdHlwZSBBc3luY0lWYWxpZGF0b3JGbiA9IChjOiBBYnN0cmFjdENvbnRyb2wsIGk/OiBib29sZWFuKSA9PiBhbnk7XHJcblxyXG4vKipcclxuICogJ19leGVjdXRlVmFsaWRhdG9ycycgdXRpbGl0eSBmdW5jdGlvblxyXG4gKlxyXG4gKiBWYWxpZGF0ZXMgYSBjb250cm9sIGFnYWluc3QgYW4gYXJyYXkgb2YgdmFsaWRhdG9ycywgYW5kIHJldHVybnNcclxuICogYW4gYXJyYXkgb2YgdGhlIHNhbWUgbGVuZ3RoIGNvbnRhaW5pbmcgYSBjb21iaW5hdGlvbiBvZiBlcnJvciBtZXNzYWdlc1xyXG4gKiAoZnJvbSBpbnZhbGlkIHZhbGlkYXRvcnMpIGFuZCBudWxsIHZhbHVlcyAoZnJvbSB2YWxpZCB2YWxpZGF0b3JzKVxyXG4gKlxyXG4gKiAvLyAgeyBBYnN0cmFjdENvbnRyb2wgfSBjb250cm9sIC0gY29udHJvbCB0byB2YWxpZGF0ZVxyXG4gKiAvLyAgeyBJVmFsaWRhdG9yRm5bXSB9IHZhbGlkYXRvcnMgLSBhcnJheSBvZiB2YWxpZGF0b3JzXHJcbiAqIC8vICB7IGJvb2xlYW4gfSBpbnZlcnQgLSBpbnZlcnQ/XHJcbiAqIC8vIHsgUGxhaW5PYmplY3RbXSB9IC0gYXJyYXkgb2YgbnVsbHMgYW5kIGVycm9yIG1lc3NhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfZXhlY3V0ZVZhbGlkYXRvcnMoY29udHJvbCwgdmFsaWRhdG9ycywgaW52ZXJ0ID0gZmFsc2UpIHtcclxuICByZXR1cm4gdmFsaWRhdG9ycy5tYXAodmFsaWRhdG9yID0+IHZhbGlkYXRvcihjb250cm9sLCBpbnZlcnQpKTtcclxufVxyXG5cclxuLyoqXHJcbiAqICdfZXhlY3V0ZUFzeW5jVmFsaWRhdG9ycycgdXRpbGl0eSBmdW5jdGlvblxyXG4gKlxyXG4gKiBWYWxpZGF0ZXMgYSBjb250cm9sIGFnYWluc3QgYW4gYXJyYXkgb2YgYXN5bmMgdmFsaWRhdG9ycywgYW5kIHJldHVybnNcclxuICogYW4gYXJyYXkgb2Ygb2JzZXJ2YWJlIHJlc3VsdHMgb2YgdGhlIHNhbWUgbGVuZ3RoIGNvbnRhaW5pbmcgYSBjb21iaW5hdGlvbiBvZlxyXG4gKiBlcnJvciBtZXNzYWdlcyAoZnJvbSBpbnZhbGlkIHZhbGlkYXRvcnMpIGFuZCBudWxsIHZhbHVlcyAoZnJvbSB2YWxpZCBvbmVzKVxyXG4gKlxyXG4gKiAvLyAgeyBBYnN0cmFjdENvbnRyb2wgfSBjb250cm9sIC0gY29udHJvbCB0byB2YWxpZGF0ZVxyXG4gKiAvLyAgeyBBc3luY0lWYWxpZGF0b3JGbltdIH0gdmFsaWRhdG9ycyAtIGFycmF5IG9mIGFzeW5jIHZhbGlkYXRvcnNcclxuICogLy8gIHsgYm9vbGVhbiB9IGludmVydCAtIGludmVydD9cclxuICogLy8gIC0gYXJyYXkgb2Ygb2JzZXJ2YWJsZSBudWxscyBhbmQgZXJyb3IgbWVzc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9leGVjdXRlQXN5bmNWYWxpZGF0b3JzKGNvbnRyb2wsIHZhbGlkYXRvcnMsIGludmVydCA9IGZhbHNlKSB7XHJcbiAgcmV0dXJuIHZhbGlkYXRvcnMubWFwKHZhbGlkYXRvciA9PiB2YWxpZGF0b3IoY29udHJvbCwgaW52ZXJ0KSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnX21lcmdlT2JqZWN0cycgdXRpbGl0eSBmdW5jdGlvblxyXG4gKlxyXG4gKiBSZWN1cnNpdmVseSBNZXJnZXMgb25lIG9yIG1vcmUgb2JqZWN0cyBpbnRvIGEgc2luZ2xlIG9iamVjdCB3aXRoIGNvbWJpbmVkIGtleXMuXHJcbiAqIEF1dG9tYXRpY2FsbHkgZGV0ZWN0cyBhbmQgaWdub3JlcyBudWxsIGFuZCB1bmRlZmluZWQgaW5wdXRzLlxyXG4gKiBBbHNvIGRldGVjdHMgZHVwbGljYXRlZCBib29sZWFuICdub3QnIGtleXMgYW5kIFhPUnMgdGhlaXIgdmFsdWVzLlxyXG4gKlxyXG4gKiAvLyAgeyBQbGFpbk9iamVjdFtdIH0gb2JqZWN0cyAtIG9uZSBvciBtb3JlIG9iamVjdHMgdG8gbWVyZ2VcclxuICogLy8geyBQbGFpbk9iamVjdCB9IC0gbWVyZ2VkIG9iamVjdFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9tZXJnZU9iamVjdHMoLi4ub2JqZWN0cykge1xyXG4gIGNvbnN0IG1lcmdlZE9iamVjdDogUGxhaW5PYmplY3QgPSB7IH07XHJcbiAgZm9yIChjb25zdCBjdXJyZW50T2JqZWN0IG9mIG9iamVjdHMpIHtcclxuICAgIGlmIChpc09iamVjdChjdXJyZW50T2JqZWN0KSkge1xyXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhjdXJyZW50T2JqZWN0KSkge1xyXG4gICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IGN1cnJlbnRPYmplY3Rba2V5XTtcclxuICAgICAgICBjb25zdCBtZXJnZWRWYWx1ZSA9IG1lcmdlZE9iamVjdFtrZXldO1xyXG4gICAgICAgIG1lcmdlZE9iamVjdFtrZXldID0gIWlzRGVmaW5lZChtZXJnZWRWYWx1ZSkgPyBjdXJyZW50VmFsdWUgOlxyXG4gICAgICAgICAga2V5ID09PSAnbm90JyAmJiBpc0Jvb2xlYW4obWVyZ2VkVmFsdWUsICdzdHJpY3QnKSAmJlxyXG4gICAgICAgICAgICBpc0Jvb2xlYW4oY3VycmVudFZhbHVlLCAnc3RyaWN0JykgPyB4b3IobWVyZ2VkVmFsdWUsIGN1cnJlbnRWYWx1ZSkgOlxyXG4gICAgICAgICAgZ2V0VHlwZShtZXJnZWRWYWx1ZSkgPT09ICdvYmplY3QnICYmIGdldFR5cGUoY3VycmVudFZhbHVlKSA9PT0gJ29iamVjdCcgP1xyXG4gICAgICAgICAgICBfbWVyZ2VPYmplY3RzKG1lcmdlZFZhbHVlLCBjdXJyZW50VmFsdWUpIDpcclxuICAgICAgICAgICAgY3VycmVudFZhbHVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBtZXJnZWRPYmplY3Q7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnX21lcmdlRXJyb3JzJyB1dGlsaXR5IGZ1bmN0aW9uXHJcbiAqXHJcbiAqIE1lcmdlcyBhbiBhcnJheSBvZiBvYmplY3RzLlxyXG4gKiBVc2VkIGZvciBjb21iaW5pbmcgdGhlIHZhbGlkYXRvciBlcnJvcnMgcmV0dXJuZWQgZnJvbSAnZXhlY3V0ZVZhbGlkYXRvcnMnXHJcbiAqXHJcbiAqIC8vICB7IFBsYWluT2JqZWN0W10gfSBhcnJheU9mRXJyb3JzIC0gYXJyYXkgb2Ygb2JqZWN0c1xyXG4gKiAvLyB7IFBsYWluT2JqZWN0IH0gLSBtZXJnZWQgb2JqZWN0LCBvciBudWxsIGlmIG5vIHVzYWJsZSBpbnB1dCBvYmplY3Rjc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIF9tZXJnZUVycm9ycyhhcnJheU9mRXJyb3JzKSB7XHJcbiAgY29uc3QgbWVyZ2VkRXJyb3JzID0gX21lcmdlT2JqZWN0cyguLi5hcnJheU9mRXJyb3JzKTtcclxuICByZXR1cm4gaXNFbXB0eShtZXJnZWRFcnJvcnMpID8gbnVsbCA6IG1lcmdlZEVycm9ycztcclxufVxyXG5cclxuLyoqXHJcbiAqICdpc0RlZmluZWQnIHV0aWxpdHkgZnVuY3Rpb25cclxuICpcclxuICogQ2hlY2tzIGlmIGEgdmFyaWFibGUgY29udGFpbnMgYSB2YWx1ZSBvZiBhbnkgdHlwZS5cclxuICogUmV0dXJucyB0cnVlIGV2ZW4gZm9yIG90aGVyd2lzZSAnZmFsc2V5JyB2YWx1ZXMgb2YgMCwgJycsIGFuZCBmYWxzZS5cclxuICpcclxuICogLy8gICB2YWx1ZSAtIHRoZSB2YWx1ZSB0byBjaGVja1xyXG4gKiAvLyB7IGJvb2xlYW4gfSAtIGZhbHNlIGlmIHVuZGVmaW5lZCBvciBudWxsLCBvdGhlcndpc2UgdHJ1ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzRGVmaW5lZCh2YWx1ZSkge1xyXG4gIHJldHVybiB2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsO1xyXG59XHJcblxyXG4vKipcclxuICogJ2hhc1ZhbHVlJyB1dGlsaXR5IGZ1bmN0aW9uXHJcbiAqXHJcbiAqIENoZWNrcyBpZiBhIHZhcmlhYmxlIGNvbnRhaW5zIGEgdmFsdWUuXHJcbiAqIFJldHVycyBmYWxzZSBmb3IgbnVsbCwgdW5kZWZpbmVkLCBvciBhIHplcm8tbGVuZ3RoIHN0cm5nLCAnJyxcclxuICogb3RoZXJ3aXNlIHJldHVybnMgdHJ1ZS5cclxuICogKFN0cmljdGVyIHRoYW4gJ2lzRGVmaW5lZCcgYmVjYXVzZSBpdCBhbHNvIHJldHVybnMgZmFsc2UgZm9yICcnLFxyXG4gKiB0aG91Z2ggaXQgc3RpbCByZXR1cm5zIHRydWUgZm9yIG90aGVyd2lzZSAnZmFsc2V5JyB2YWx1ZXMgMCBhbmQgZmFsc2UuKVxyXG4gKlxyXG4gKiAvLyAgIHZhbHVlIC0gdGhlIHZhbHVlIHRvIGNoZWNrXHJcbiAqIC8vIHsgYm9vbGVhbiB9IC0gZmFsc2UgaWYgdW5kZWZpbmVkLCBudWxsLCBvciAnJywgb3RoZXJ3aXNlIHRydWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBoYXNWYWx1ZSh2YWx1ZSkge1xyXG4gIHJldHVybiB2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSAnJztcclxufVxyXG5cclxuLyoqXHJcbiAqICdpc0VtcHR5JyB1dGlsaXR5IGZ1bmN0aW9uXHJcbiAqXHJcbiAqIFNpbWlsYXIgdG8gIWhhc1ZhbHVlLCBidXQgYWxzbyByZXR1cm5zIHRydWUgZm9yIGVtcHR5IGFycmF5cyBhbmQgb2JqZWN0cy5cclxuICpcclxuICogLy8gICB2YWx1ZSAtIHRoZSB2YWx1ZSB0byBjaGVja1xyXG4gKiAvLyB7IGJvb2xlYW4gfSAtIGZhbHNlIGlmIHVuZGVmaW5lZCwgbnVsbCwgb3IgJycsIG90aGVyd2lzZSB0cnVlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNFbXB0eSh2YWx1ZSkge1xyXG4gIGlmIChpc0FycmF5KHZhbHVlKSkgeyByZXR1cm4gIXZhbHVlLmxlbmd0aDsgfVxyXG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHsgcmV0dXJuICFPYmplY3Qua2V5cyh2YWx1ZSkubGVuZ3RoOyB9XHJcbiAgcmV0dXJuIHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09ICcnO1xyXG59XHJcblxyXG4vKipcclxuICogJ2lzU3RyaW5nJyB1dGlsaXR5IGZ1bmN0aW9uXHJcbiAqXHJcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGEgc3RyaW5nLlxyXG4gKlxyXG4gKiAvLyAgIHZhbHVlIC0gdGhlIHZhbHVlIHRvIGNoZWNrXHJcbiAqIC8vIHsgYm9vbGVhbiB9IC0gdHJ1ZSBpZiBzdHJpbmcsIGZhbHNlIGlmIG5vdFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzU3RyaW5nKHZhbHVlKSB7XHJcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnaXNOdW1iZXInIHV0aWxpdHkgZnVuY3Rpb25cclxuICpcclxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYSByZWd1bGFyIG51bWJlciwgbnVtZXJpYyBzdHJpbmcsIG9yIEphdmFTY3JpcHQgRGF0ZS5cclxuICpcclxuICogLy8gICB2YWx1ZSAtIHRoZSB2YWx1ZSB0byBjaGVja1xyXG4gKiAvLyAgeyBhbnkgPSBmYWxzZSB9IHN0cmljdCAtIGlmIHRydXRoeSwgYWxzbyBjaGVja3MgSmF2YVNjcmlwdCB0eW9lXHJcbiAqIC8vIHsgYm9vbGVhbiB9IC0gdHJ1ZSBpZiBudW1iZXIsIGZhbHNlIGlmIG5vdFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzTnVtYmVyKHZhbHVlLCBzdHJpY3Q6IGFueSA9IGZhbHNlKSB7XHJcbiAgaWYgKHN0cmljdCAmJiB0eXBlb2YgdmFsdWUgIT09ICdudW1iZXInKSB7IHJldHVybiBmYWxzZTsgfVxyXG4gIHJldHVybiAhaXNOYU4odmFsdWUpICYmIHZhbHVlICE9PSB2YWx1ZSAvIDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnaXNJbnRlZ2VyJyB1dGlsaXR5IGZ1bmN0aW9uXHJcbiAqXHJcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGFuIGludGVnZXIuXHJcbiAqXHJcbiAqIC8vICAgdmFsdWUgLSB0aGUgdmFsdWUgdG8gY2hlY2tcclxuICogLy8gIHsgYW55ID0gZmFsc2UgfSBzdHJpY3QgLSBpZiB0cnV0aHksIGFsc28gY2hlY2tzIEphdmFTY3JpcHQgdHlvZVxyXG4gKiAvLyB7Ym9vbGVhbiB9IC0gdHJ1ZSBpZiBudW1iZXIsIGZhbHNlIGlmIG5vdFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzSW50ZWdlcih2YWx1ZSwgc3RyaWN0OiBhbnkgPSBmYWxzZSkge1xyXG4gIGlmIChzdHJpY3QgJiYgdHlwZW9mIHZhbHVlICE9PSAnbnVtYmVyJykgeyByZXR1cm4gZmFsc2U7IH1cclxuICByZXR1cm4gIWlzTmFOKHZhbHVlKSAmJiAgdmFsdWUgIT09IHZhbHVlIC8gMCAmJiB2YWx1ZSAlIDEgPT09IDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnaXNCb29sZWFuJyB1dGlsaXR5IGZ1bmN0aW9uXHJcbiAqXHJcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGEgYm9vbGVhbi5cclxuICpcclxuICogLy8gICB2YWx1ZSAtIHRoZSB2YWx1ZSB0byBjaGVja1xyXG4gKiAvLyAgeyBhbnkgPSBudWxsIH0gb3B0aW9uIC0gaWYgJ3N0cmljdCcsIGFsc28gY2hlY2tzIEphdmFTY3JpcHQgdHlwZVxyXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIFRSVUUgb3IgRkFMU0UsIGNoZWNrcyBvbmx5IGZvciB0aGF0IHZhbHVlXHJcbiAqIC8vIHsgYm9vbGVhbiB9IC0gdHJ1ZSBpZiBib29sZWFuLCBmYWxzZSBpZiBub3RcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0Jvb2xlYW4odmFsdWUsIG9wdGlvbjogYW55ID0gbnVsbCkge1xyXG4gIGlmIChvcHRpb24gPT09ICdzdHJpY3QnKSB7IHJldHVybiB2YWx1ZSA9PT0gdHJ1ZSB8fCB2YWx1ZSA9PT0gZmFsc2U7IH1cclxuICBpZiAob3B0aW9uID09PSB0cnVlKSB7XHJcbiAgICByZXR1cm4gdmFsdWUgPT09IHRydWUgfHwgdmFsdWUgPT09IDEgfHwgdmFsdWUgPT09ICd0cnVlJyB8fCB2YWx1ZSA9PT0gJzEnO1xyXG4gIH1cclxuICBpZiAob3B0aW9uID09PSBmYWxzZSkge1xyXG4gICAgcmV0dXJuIHZhbHVlID09PSBmYWxzZSB8fCB2YWx1ZSA9PT0gMCB8fCB2YWx1ZSA9PT0gJ2ZhbHNlJyB8fCB2YWx1ZSA9PT0gJzAnO1xyXG4gIH1cclxuICByZXR1cm4gdmFsdWUgPT09IHRydWUgfHwgdmFsdWUgPT09IDEgfHwgdmFsdWUgPT09ICd0cnVlJyB8fCB2YWx1ZSA9PT0gJzEnIHx8XHJcbiAgICB2YWx1ZSA9PT0gZmFsc2UgfHwgdmFsdWUgPT09IDAgfHwgdmFsdWUgPT09ICdmYWxzZScgfHwgdmFsdWUgPT09ICcwJztcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGlzRnVuY3Rpb24oaXRlbTogYW55KTogYm9vbGVhbiB7XHJcbiAgcmV0dXJuIHR5cGVvZiBpdGVtID09PSAnZnVuY3Rpb24nO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbTogYW55KTogYm9vbGVhbiB7XHJcbiAgcmV0dXJuIGl0ZW0gIT09IG51bGwgJiYgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNBcnJheShpdGVtOiBhbnkpOiBib29sZWFuIHtcclxuICByZXR1cm4gQXJyYXkuaXNBcnJheShpdGVtKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGlzRGF0ZShpdGVtOiBhbnkpOiBib29sZWFuIHtcclxuICByZXR1cm4gISFpdGVtICYmIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChpdGVtKSA9PT0gJ1tvYmplY3QgRGF0ZV0nO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNNYXAoaXRlbTogYW55KTogYm9vbGVhbiB7XHJcbiAgcmV0dXJuICEhaXRlbSAmJiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE1hcF0nO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNTZXQoaXRlbTogYW55KTogYm9vbGVhbiB7XHJcbiAgcmV0dXJuICEhaXRlbSAmJiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IFNldF0nO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNTeW1ib2woaXRlbTogYW55KTogYm9vbGVhbiB7XHJcbiAgcmV0dXJuIHR5cGVvZiBpdGVtID09PSAnc3ltYm9sJztcclxufVxyXG5cclxuLyoqXHJcbiAqICdnZXRUeXBlJyBmdW5jdGlvblxyXG4gKlxyXG4gKiBEZXRlY3RzIHRoZSBKU09OIFNjaGVtYSBUeXBlIG9mIGEgdmFsdWUuXHJcbiAqIEJ5IGRlZmF1bHQsIGRldGVjdHMgbnVtYmVycyBhbmQgaW50ZWdlcnMgZXZlbiBpZiBmb3JtYXR0ZWQgYXMgc3RyaW5ncy5cclxuICogKFNvIGFsbCBpbnRlZ2VycyBhcmUgYWxzbyBudW1iZXJzLCBhbmQgYW55IG51bWJlciBtYXkgYWxzbyBiZSBhIHN0cmluZy4pXHJcbiAqIEhvd2V2ZXIsIGl0IG9ubHkgZGV0ZWN0cyB0cnVlIGJvb2xlYW4gdmFsdWVzICh0byBkZXRlY3QgYm9vbGVhbiB2YWx1ZXNcclxuICogaW4gbm9uLWJvb2xlYW4gZm9ybWF0cywgdXNlIGlzQm9vbGVhbigpIGluc3RlYWQpLlxyXG4gKlxyXG4gKiBJZiBwYXNzZWQgYSBzZWNvbmQgb3B0aW9uYWwgcGFyYW1ldGVyIG9mICdzdHJpY3QnLCBpdCB3aWxsIG9ubHkgZGV0ZWN0XHJcbiAqIG51bWJlcnMgYW5kIGludGVnZXJzIGlmIHRoZXkgYXJlIGZvcm1hdHRlZCBhcyBKYXZhU2NyaXB0IG51bWJlcnMuXHJcbiAqXHJcbiAqIEV4YW1wbGVzOlxyXG4gKiBnZXRUeXBlKCcxMC41JykgPSAnbnVtYmVyJ1xyXG4gKiBnZXRUeXBlKDEwLjUpID0gJ251bWJlcidcclxuICogZ2V0VHlwZSgnMTAnKSA9ICdpbnRlZ2VyJ1xyXG4gKiBnZXRUeXBlKDEwKSA9ICdpbnRlZ2VyJ1xyXG4gKiBnZXRUeXBlKCd0cnVlJykgPSAnc3RyaW5nJ1xyXG4gKiBnZXRUeXBlKHRydWUpID0gJ2Jvb2xlYW4nXHJcbiAqIGdldFR5cGUobnVsbCkgPSAnbnVsbCdcclxuICogZ2V0VHlwZSh7IH0pID0gJ29iamVjdCdcclxuICogZ2V0VHlwZShbXSkgPSAnYXJyYXknXHJcbiAqXHJcbiAqIGdldFR5cGUoJzEwLjUnLCAnc3RyaWN0JykgPSAnc3RyaW5nJ1xyXG4gKiBnZXRUeXBlKDEwLjUsICdzdHJpY3QnKSA9ICdudW1iZXInXHJcbiAqIGdldFR5cGUoJzEwJywgJ3N0cmljdCcpID0gJ3N0cmluZydcclxuICogZ2V0VHlwZSgxMCwgJ3N0cmljdCcpID0gJ2ludGVnZXInXHJcbiAqIGdldFR5cGUoJ3RydWUnLCAnc3RyaWN0JykgPSAnc3RyaW5nJ1xyXG4gKiBnZXRUeXBlKHRydWUsICdzdHJpY3QnKSA9ICdib29sZWFuJ1xyXG4gKlxyXG4gKiAvLyAgIHZhbHVlIC0gdmFsdWUgdG8gY2hlY2tcclxuICogLy8gIHsgYW55ID0gZmFsc2UgfSBzdHJpY3QgLSBpZiB0cnV0aHksIGFsc28gY2hlY2tzIEphdmFTY3JpcHQgdHlvZVxyXG4gKiAvLyB7IFNjaGVtYVR5cGUgfVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFR5cGUodmFsdWUsIHN0cmljdDogYW55ID0gZmFsc2UpIHtcclxuICBpZiAoIWlzRGVmaW5lZCh2YWx1ZSkpIHsgcmV0dXJuICdudWxsJzsgfVxyXG4gIGlmIChpc0FycmF5KHZhbHVlKSkgeyByZXR1cm4gJ2FycmF5JzsgfVxyXG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHsgcmV0dXJuICdvYmplY3QnOyB9XHJcbiAgaWYgKGlzQm9vbGVhbih2YWx1ZSwgJ3N0cmljdCcpKSB7IHJldHVybiAnYm9vbGVhbic7IH1cclxuICBpZiAoaXNJbnRlZ2VyKHZhbHVlLCBzdHJpY3QpKSB7IHJldHVybiAnaW50ZWdlcic7IH1cclxuICBpZiAoaXNOdW1iZXIodmFsdWUsIHN0cmljdCkpIHsgcmV0dXJuICdudW1iZXInOyB9XHJcbiAgaWYgKGlzU3RyaW5nKHZhbHVlKSB8fCAoIXN0cmljdCAmJiBpc0RhdGUodmFsdWUpKSkgeyByZXR1cm4gJ3N0cmluZyc7IH1cclxuICByZXR1cm4gbnVsbDtcclxufVxyXG5cclxuLyoqXHJcbiAqICdpc1R5cGUnIGZ1bmN0aW9uXHJcbiAqXHJcbiAqIENoZWNrcyB3ZXRoZXIgYW4gaW5wdXQgKHByb2JhYmx5IHN0cmluZykgdmFsdWUgY29udGFpbnMgZGF0YSBvZlxyXG4gKiBhIHNwZWNpZmllZCBKU09OIFNjaGVtYSB0eXBlXHJcbiAqXHJcbiAqIC8vICB7IFByaW1pdGl2ZVZhbHVlIH0gdmFsdWUgLSB2YWx1ZSB0byBjaGVja1xyXG4gKiAvLyAgeyBTY2hlbWFQcmltaXRpdmVUeXBlIH0gdHlwZSAtIHR5cGUgdG8gY2hlY2tcclxuICogLy8geyBib29sZWFuIH1cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc1R5cGUodmFsdWUsIHR5cGUpIHtcclxuICBzd2l0Y2ggKHR5cGUpIHtcclxuICAgIGNhc2UgJ3N0cmluZyc6XHJcbiAgICAgIHJldHVybiBpc1N0cmluZyh2YWx1ZSkgfHwgaXNEYXRlKHZhbHVlKTtcclxuICAgIGNhc2UgJ251bWJlcic6XHJcbiAgICAgIHJldHVybiBpc051bWJlcih2YWx1ZSk7XHJcbiAgICBjYXNlICdpbnRlZ2VyJzpcclxuICAgICAgcmV0dXJuIGlzSW50ZWdlcih2YWx1ZSk7XHJcbiAgICBjYXNlICdib29sZWFuJzpcclxuICAgICAgcmV0dXJuIGlzQm9vbGVhbih2YWx1ZSk7XHJcbiAgICBjYXNlICdudWxsJzpcclxuICAgICAgcmV0dXJuICFoYXNWYWx1ZSh2YWx1ZSk7XHJcbiAgICBkZWZhdWx0OlxyXG4gICAgICBjb25zb2xlLmVycm9yKGBpc1R5cGUgZXJyb3I6IFwiJHt0eXBlfVwiIGlzIG5vdCBhIHJlY29nbml6ZWQgdHlwZS5gKTtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogJ2lzUHJpbWl0aXZlJyBmdW5jdGlvblxyXG4gKlxyXG4gKiBDaGVja3Mgd2V0aGVyIGFuIGlucHV0IHZhbHVlIGlzIGEgSmF2YVNjcmlwdCBwcmltaXRpdmUgdHlwZTpcclxuICogc3RyaW5nLCBudW1iZXIsIGJvb2xlYW4sIG9yIG51bGwuXHJcbiAqXHJcbiAqIC8vICAgdmFsdWUgLSB2YWx1ZSB0byBjaGVja1xyXG4gKiAvLyB7IGJvb2xlYW4gfVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzUHJpbWl0aXZlKHZhbHVlKSB7XHJcbiAgcmV0dXJuIChpc1N0cmluZyh2YWx1ZSkgfHwgaXNOdW1iZXIodmFsdWUpIHx8XHJcbiAgICBpc0Jvb2xlYW4odmFsdWUsICdzdHJpY3QnKSB8fCB2YWx1ZSA9PT0gbnVsbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBcclxuICogQHBhcmFtIGRhdGUgXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9XHJcbiAqIGV4bWFwbGU6XHJcbiAqIHRvRGF0ZVN0cmluZygnMjAxOC0wMS0wMScpID0gJzIwMTgtMDEtMDEnXHJcbiAqIHRvRGF0ZVN0cmluZygnMjAxOC0wMS0zMFQwMDowMDowMC4wMDBaJykgPSAnMjAxOC0wMS0zMCdcclxuICovXHJcbmV4cG9ydCBjb25zdCB0b0lzb1N0cmluZyA9IChkYXRlOiBEYXRlKSA9PiB7XHJcbiAgY29uc3QgZGF5ID0gZGF0ZS5nZXREYXRlKCk7XHJcbiAgY29uc3QgbW9udGggPSBkYXRlLmdldE1vbnRoKCkgKyAxO1xyXG4gIGNvbnN0IHllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCk7XHJcbiAgcmV0dXJuIGAke3llYXJ9LSR7bW9udGggPCAxMCA/ICcwJyArIG1vbnRoIDogbW9udGh9LSR7ZGF5IDwgMTAgPyAnMCcgKyBkYXkgOiBkYXl9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqICd0b0phdmFTY3JpcHRUeXBlJyBmdW5jdGlvblxyXG4gKlxyXG4gKiBDb252ZXJ0cyBhbiBpbnB1dCAocHJvYmFibHkgc3RyaW5nKSB2YWx1ZSB0byBhIEphdmFTY3JpcHQgcHJpbWl0aXZlIHR5cGUgLVxyXG4gKiAnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJywgb3IgJ251bGwnIC0gYmVmb3JlIHN0b3JpbmcgaW4gYSBKU09OIG9iamVjdC5cclxuICpcclxuICogRG9lcyBub3QgY29lcmNlIHZhbHVlcyAob3RoZXIgdGhhbiBudWxsKSwgYW5kIG9ubHkgY29udmVydHMgdGhlIHR5cGVzXHJcbiAqIG9mIHZhbHVlcyB0aGF0IHdvdWxkIG90aGVyd2lzZSBiZSB2YWxpZC5cclxuICpcclxuICogSWYgdGhlIG9wdGlvbmFsIHRoaXJkIHBhcmFtZXRlciAnc3RyaWN0SW50ZWdlcnMnIGlzIFRSVUUsIGFuZCB0aGVcclxuICogSlNPTiBTY2hlbWEgdHlwZSAnaW50ZWdlcicgaXMgc3BlY2lmaWVkLCBpdCBhbHNvIHZlcmlmaWVzIHRoZSBpbnB1dCB2YWx1ZVxyXG4gKiBpcyBhbiBpbnRlZ2VyIGFuZCwgaWYgaXQgaXMsIHJldHVybnMgaXQgYXMgYSBKYXZlU2NyaXB0IG51bWJlci5cclxuICogSWYgJ3N0cmljdEludGVnZXJzJyBpcyBGQUxTRSAob3Igbm90IHNldCkgdGhlIHR5cGUgJ2ludGVnZXInIGlzIHRyZWF0ZWRcclxuICogZXhhY3RseSB0aGUgc2FtZSBhcyAnbnVtYmVyJywgYW5kIGFsbG93cyBkZWNpbWFscy5cclxuICpcclxuICogVmFsaWQgRXhhbXBsZXM6XHJcbiAqIHRvSmF2YVNjcmlwdFR5cGUoJzEwJywgICAnbnVtYmVyJyApID0gMTAgICAvLyAnMTAnICAgaXMgYSBudW1iZXJcclxuICogdG9KYXZhU2NyaXB0VHlwZSgnMTAnLCAgICdpbnRlZ2VyJykgPSAxMCAgIC8vICcxMCcgICBpcyBhbHNvIGFuIGludGVnZXJcclxuICogdG9KYXZhU2NyaXB0VHlwZSggMTAsICAgICdpbnRlZ2VyJykgPSAxMCAgIC8vICAxMCAgICBpcyBzdGlsbCBhbiBpbnRlZ2VyXHJcbiAqIHRvSmF2YVNjcmlwdFR5cGUoIDEwLCAgICAnc3RyaW5nJyApID0gJzEwJyAvLyAgMTAgICAgY2FuIGJlIG1hZGUgaW50byBhIHN0cmluZ1xyXG4gKiB0b0phdmFTY3JpcHRUeXBlKCcxMC41JywgJ251bWJlcicgKSA9IDEwLjUgLy8gJzEwLjUnIGlzIGEgbnVtYmVyXHJcbiAqXHJcbiAqIEludmFsaWQgRXhhbXBsZXM6XHJcbiAqIHRvSmF2YVNjcmlwdFR5cGUoJzEwLjUnLCAnaW50ZWdlcicpID0gbnVsbCAvLyAnMTAuNScgaXMgbm90IGFuIGludGVnZXJcclxuICogdG9KYXZhU2NyaXB0VHlwZSggMTAuNSwgICdpbnRlZ2VyJykgPSBudWxsIC8vICAxMC41ICBpcyBzdGlsbCBub3QgYW4gaW50ZWdlclxyXG4gKlxyXG4gKiAvLyAgeyBQcmltaXRpdmVWYWx1ZSB9IHZhbHVlIC0gdmFsdWUgdG8gY29udmVydFxyXG4gKiAvLyAgeyBTY2hlbWFQcmltaXRpdmVUeXBlIHwgU2NoZW1hUHJpbWl0aXZlVHlwZVtdIH0gdHlwZXMgLSB0eXBlcyB0byBjb252ZXJ0IHRvXHJcbiAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IHN0cmljdEludGVnZXJzIC0gaWYgRkFMU0UsIHRyZWF0IGludGVnZXJzIGFzIG51bWJlcnNcclxuICogLy8geyBQcmltaXRpdmVWYWx1ZSB9XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdG9KYXZhU2NyaXB0VHlwZSh2YWx1ZSwgdHlwZXMsIHN0cmljdEludGVnZXJzID0gdHJ1ZSkgIHtcclxuICBpZiAoIWlzRGVmaW5lZCh2YWx1ZSkpIHsgcmV0dXJuIG51bGw7IH1cclxuICBpZiAoaXNTdHJpbmcodHlwZXMpKSB7IHR5cGVzID0gW3R5cGVzXTsgfVxyXG4gIGlmIChzdHJpY3RJbnRlZ2VycyAmJiBpbkFycmF5KCdpbnRlZ2VyJywgdHlwZXMpKSB7XHJcbiAgICBpZiAoaXNJbnRlZ2VyKHZhbHVlLCAnc3RyaWN0JykpIHsgcmV0dXJuIHZhbHVlOyB9XHJcbiAgICBpZiAoaXNJbnRlZ2VyKHZhbHVlKSkgeyByZXR1cm4gcGFyc2VJbnQodmFsdWUsIDEwKTsgfVxyXG4gIH1cclxuICBpZiAoaW5BcnJheSgnbnVtYmVyJywgdHlwZXMpIHx8ICghc3RyaWN0SW50ZWdlcnMgJiYgaW5BcnJheSgnaW50ZWdlcicsIHR5cGVzKSkpIHtcclxuICAgIGlmIChpc051bWJlcih2YWx1ZSwgJ3N0cmljdCcpKSB7IHJldHVybiB2YWx1ZTsgfVxyXG4gICAgaWYgKGlzTnVtYmVyKHZhbHVlKSkgeyByZXR1cm4gcGFyc2VGbG9hdCh2YWx1ZSk7IH1cclxuICB9XHJcbiAgaWYgKGluQXJyYXkoJ3N0cmluZycsIHR5cGVzKSkge1xyXG4gICAgaWYgKGlzU3RyaW5nKHZhbHVlKSkgeyByZXR1cm4gdmFsdWU7IH1cclxuICAgIC8vIElmIHZhbHVlIGlzIGEgZGF0ZSwgYW5kIHR5cGVzIGluY2x1ZGVzICdzdHJpbmcnLFxyXG4gICAgLy8gY29udmVydCB0aGUgZGF0ZSB0byBhIHN0cmluZ1xyXG4gICAgaWYgKGlzRGF0ZSh2YWx1ZSkpIHsgcmV0dXJuIHRvSXNvU3RyaW5nKHZhbHVlKTsgfVxyXG4gICAgaWYgKGlzTnVtYmVyKHZhbHVlKSkgeyByZXR1cm4gdmFsdWUudG9TdHJpbmcoKTsgfVxyXG4gIH1cclxuICAvLyBJZiB2YWx1ZSBpcyBhIGRhdGUsIGFuZCB0eXBlcyBpbmNsdWRlcyAnaW50ZWdlcicgb3IgJ251bWJlcicsXHJcbiAgLy8gYnV0IG5vdCAnc3RyaW5nJywgY29udmVydCB0aGUgZGF0ZSB0byBhIG51bWJlclxyXG4gIGlmIChpc0RhdGUodmFsdWUpICYmIChpbkFycmF5KCdpbnRlZ2VyJywgdHlwZXMpIHx8IGluQXJyYXkoJ251bWJlcicsIHR5cGVzKSkpIHtcclxuICAgIHJldHVybiB2YWx1ZS5nZXRUaW1lKCk7XHJcbiAgfVxyXG4gIGlmIChpbkFycmF5KCdib29sZWFuJywgdHlwZXMpKSB7XHJcbiAgICBpZiAoaXNCb29sZWFuKHZhbHVlLCB0cnVlKSkgeyByZXR1cm4gdHJ1ZTsgfVxyXG4gICAgaWYgKGlzQm9vbGVhbih2YWx1ZSwgZmFsc2UpKSB7IHJldHVybiBmYWxzZTsgfVxyXG4gIH1cclxuICByZXR1cm4gbnVsbDtcclxufVxyXG5cclxuLyoqXHJcbiAqICd0b1NjaGVtYVR5cGUnIGZ1bmN0aW9uXHJcbiAqXHJcbiAqIENvbnZlcnRzIGFuIGlucHV0IChwcm9iYWJseSBzdHJpbmcpIHZhbHVlIHRvIHRoZSBcImJlc3RcIiBKYXZhU2NyaXB0XHJcbiAqIGVxdWl2YWxlbnQgYXZhaWxhYmxlIGZyb20gYW4gYWxsb3dlZCBsaXN0IG9mIEpTT04gU2NoZW1hIHR5cGVzLCB3aGljaCBtYXlcclxuICogY29udGFpbiAnc3RyaW5nJywgJ251bWJlcicsICdpbnRlZ2VyJywgJ2Jvb2xlYW4nLCBhbmQvb3IgJ251bGwnLlxyXG4gKiBJZiBuZWNzc2FyeSwgaXQgZG9lcyBwcm9ncmVzc2l2ZWx5IGFncmVzc2l2ZSB0eXBlIGNvZXJzaW9uLlxyXG4gKiBJdCB3aWxsIG5vdCByZXR1cm4gbnVsbCB1bmxlc3MgbnVsbCBpcyBpbiB0aGUgbGlzdCBvZiBhbGxvd2VkIHR5cGVzLlxyXG4gKlxyXG4gKiBOdW1iZXIgY29udmVyc2lvbiBleGFtcGxlczpcclxuICogdG9TY2hlbWFUeXBlKCcxMCcsIFsnbnVtYmVyJywnaW50ZWdlcicsJ3N0cmluZyddKSA9IDEwIC8vIGludGVnZXJcclxuICogdG9TY2hlbWFUeXBlKCcxMCcsIFsnbnVtYmVyJywnc3RyaW5nJ10pID0gMTAgLy8gbnVtYmVyXHJcbiAqIHRvU2NoZW1hVHlwZSgnMTAnLCBbJ3N0cmluZyddKSA9ICcxMCcgLy8gc3RyaW5nXHJcbiAqIHRvU2NoZW1hVHlwZSgnMTAuNScsIFsnbnVtYmVyJywnaW50ZWdlcicsJ3N0cmluZyddKSA9IDEwLjUgLy8gbnVtYmVyXHJcbiAqIHRvU2NoZW1hVHlwZSgnMTAuNScsIFsnaW50ZWdlcicsJ3N0cmluZyddKSA9ICcxMC41JyAvLyBzdHJpbmdcclxuICogdG9TY2hlbWFUeXBlKCcxMC41JywgWydpbnRlZ2VyJ10pID0gMTAgLy8gaW50ZWdlclxyXG4gKiB0b1NjaGVtYVR5cGUoMTAuNSwgWydudWxsJywnYm9vbGVhbicsJ3N0cmluZyddKSA9ICcxMC41JyAvLyBzdHJpbmdcclxuICogdG9TY2hlbWFUeXBlKDEwLjUsIFsnbnVsbCcsJ2Jvb2xlYW4nXSkgPSB0cnVlIC8vIGJvb2xlYW5cclxuICpcclxuICogU3RyaW5nIGNvbnZlcnNpb24gZXhhbXBsZXM6XHJcbiAqIHRvU2NoZW1hVHlwZSgnMS41eCcsIFsnYm9vbGVhbicsJ251bWJlcicsJ2ludGVnZXInLCdzdHJpbmcnXSkgPSAnMS41eCcgLy8gc3RyaW5nXHJcbiAqIHRvU2NoZW1hVHlwZSgnMS41eCcsIFsnYm9vbGVhbicsJ251bWJlcicsJ2ludGVnZXInXSkgPSAnMS41JyAvLyBudW1iZXJcclxuICogdG9TY2hlbWFUeXBlKCcxLjV4JywgWydib29sZWFuJywnaW50ZWdlciddKSA9ICcxJyAvLyBpbnRlZ2VyXHJcbiAqIHRvU2NoZW1hVHlwZSgnMS41eCcsIFsnYm9vbGVhbiddKSA9IHRydWUgLy8gYm9vbGVhblxyXG4gKiB0b1NjaGVtYVR5cGUoJ3h5eicsIFsnbnVtYmVyJywnaW50ZWdlcicsJ2Jvb2xlYW4nLCdudWxsJ10pID0gdHJ1ZSAvLyBib29sZWFuXHJcbiAqIHRvU2NoZW1hVHlwZSgneHl6JywgWydudW1iZXInLCdpbnRlZ2VyJywnbnVsbCddKSA9IG51bGwgLy8gbnVsbFxyXG4gKiB0b1NjaGVtYVR5cGUoJ3h5eicsIFsnbnVtYmVyJywnaW50ZWdlciddKSA9IDAgLy8gbnVtYmVyXHJcbiAqXHJcbiAqIEJvb2xlYW4gY29udmVyc2lvbiBleGFtcGxlczpcclxuICogdG9TY2hlbWFUeXBlKCcxJywgWydpbnRlZ2VyJywnbnVtYmVyJywnc3RyaW5nJywnYm9vbGVhbiddKSA9IDEgLy8gaW50ZWdlclxyXG4gKiB0b1NjaGVtYVR5cGUoJzEnLCBbJ251bWJlcicsJ3N0cmluZycsJ2Jvb2xlYW4nXSkgPSAxIC8vIG51bWJlclxyXG4gKiB0b1NjaGVtYVR5cGUoJzEnLCBbJ3N0cmluZycsJ2Jvb2xlYW4nXSkgPSAnMScgLy8gc3RyaW5nXHJcbiAqIHRvU2NoZW1hVHlwZSgnMScsIFsnYm9vbGVhbiddKSA9IHRydWUgLy8gYm9vbGVhblxyXG4gKiB0b1NjaGVtYVR5cGUoJ3RydWUnLCBbJ251bWJlcicsJ3N0cmluZycsJ2Jvb2xlYW4nXSkgPSAndHJ1ZScgLy8gc3RyaW5nXHJcbiAqIHRvU2NoZW1hVHlwZSgndHJ1ZScsIFsnYm9vbGVhbiddKSA9IHRydWUgLy8gYm9vbGVhblxyXG4gKiB0b1NjaGVtYVR5cGUoJ3RydWUnLCBbJ251bWJlciddKSA9IDAgLy8gbnVtYmVyXHJcbiAqIHRvU2NoZW1hVHlwZSh0cnVlLCBbJ251bWJlcicsJ3N0cmluZycsJ2Jvb2xlYW4nXSkgPSB0cnVlIC8vIGJvb2xlYW5cclxuICogdG9TY2hlbWFUeXBlKHRydWUsIFsnbnVtYmVyJywnc3RyaW5nJ10pID0gJ3RydWUnIC8vIHN0cmluZ1xyXG4gKiB0b1NjaGVtYVR5cGUodHJ1ZSwgWydudW1iZXInXSkgPSAxIC8vIG51bWJlclxyXG4gKlxyXG4gKiAvLyAgeyBQcmltaXRpdmVWYWx1ZSB9IHZhbHVlIC0gdmFsdWUgdG8gY29udmVydFxyXG4gKiAvLyAgeyBTY2hlbWFQcmltaXRpdmVUeXBlIHwgU2NoZW1hUHJpbWl0aXZlVHlwZVtdIH0gdHlwZXMgLSBhbGxvd2VkIHR5cGVzIHRvIGNvbnZlcnQgdG9cclxuICogLy8geyBQcmltaXRpdmVWYWx1ZSB9XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdG9TY2hlbWFUeXBlKHZhbHVlLCB0eXBlcykge1xyXG4gIGlmICghaXNBcnJheSg8U2NoZW1hUHJpbWl0aXZlVHlwZT50eXBlcykpIHtcclxuICAgIHR5cGVzID0gPFNjaGVtYVByaW1pdGl2ZVR5cGVbXT5bdHlwZXNdO1xyXG4gIH1cclxuICBpZiAoKDxTY2hlbWFQcmltaXRpdmVUeXBlW10+dHlwZXMpLmluY2x1ZGVzKCdudWxsJykgJiYgIWhhc1ZhbHVlKHZhbHVlKSkge1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG4gIGlmICgoPFNjaGVtYVByaW1pdGl2ZVR5cGVbXT50eXBlcykuaW5jbHVkZXMoJ2Jvb2xlYW4nKSAmJiAhaXNCb29sZWFuKHZhbHVlLCAnc3RyaWN0JykpIHtcclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcbiAgaWYgKCg8U2NoZW1hUHJpbWl0aXZlVHlwZVtdPnR5cGVzKS5pbmNsdWRlcygnaW50ZWdlcicpKSB7XHJcbiAgICBjb25zdCB0ZXN0VmFsdWUgPSB0b0phdmFTY3JpcHRUeXBlKHZhbHVlLCAnaW50ZWdlcicpO1xyXG4gICAgaWYgKHRlc3RWYWx1ZSAhPT0gbnVsbCkgeyByZXR1cm4gK3Rlc3RWYWx1ZTsgfVxyXG4gIH1cclxuICBpZiAoKDxTY2hlbWFQcmltaXRpdmVUeXBlW10+dHlwZXMpLmluY2x1ZGVzKCdudW1iZXInKSkge1xyXG4gICAgY29uc3QgdGVzdFZhbHVlID0gdG9KYXZhU2NyaXB0VHlwZSh2YWx1ZSwgJ251bWJlcicpO1xyXG4gICAgaWYgKHRlc3RWYWx1ZSAhPT0gbnVsbCkgeyByZXR1cm4gK3Rlc3RWYWx1ZTsgfVxyXG4gIH1cclxuICBpZiAoXHJcbiAgICAoaXNTdHJpbmcodmFsdWUpIHx8IGlzTnVtYmVyKHZhbHVlLCAnc3RyaWN0JykpICYmXHJcbiAgICAoPFNjaGVtYVByaW1pdGl2ZVR5cGVbXT50eXBlcykuaW5jbHVkZXMoJ3N0cmluZycpXHJcbiAgKSB7IC8vIENvbnZlcnQgbnVtYmVyIHRvIHN0cmluZ1xyXG4gICAgcmV0dXJuIHRvSmF2YVNjcmlwdFR5cGUodmFsdWUsICdzdHJpbmcnKTtcclxuICB9XHJcbiAgaWYgKCg8U2NoZW1hUHJpbWl0aXZlVHlwZVtdPnR5cGVzKS5pbmNsdWRlcygnYm9vbGVhbicpICYmIGlzQm9vbGVhbih2YWx1ZSkpIHtcclxuICAgIHJldHVybiB0b0phdmFTY3JpcHRUeXBlKHZhbHVlLCAnYm9vbGVhbicpO1xyXG4gIH1cclxuICBpZiAoKDxTY2hlbWFQcmltaXRpdmVUeXBlW10+dHlwZXMpLmluY2x1ZGVzKCdzdHJpbmcnKSkgeyAvLyBDb252ZXJ0IG51bGwgJiBib29sZWFuIHRvIHN0cmluZ1xyXG4gICAgaWYgKHZhbHVlID09PSBudWxsKSB7IHJldHVybiAnJzsgfVxyXG4gICAgY29uc3QgdGVzdFZhbHVlID0gdG9KYXZhU2NyaXB0VHlwZSh2YWx1ZSwgJ3N0cmluZycpO1xyXG4gICAgaWYgKHRlc3RWYWx1ZSAhPT0gbnVsbCkgeyByZXR1cm4gdGVzdFZhbHVlOyB9XHJcbiAgfVxyXG4gIGlmICgoXHJcbiAgICAoPFNjaGVtYVByaW1pdGl2ZVR5cGVbXT50eXBlcykuaW5jbHVkZXMoJ251bWJlcicpIHx8XHJcbiAgICAoPFNjaGVtYVByaW1pdGl2ZVR5cGVbXT50eXBlcykuaW5jbHVkZXMoJ2ludGVnZXInKSlcclxuICApIHtcclxuICAgIGlmICh2YWx1ZSA9PT0gdHJ1ZSkgeyByZXR1cm4gMTsgfSAvLyBDb252ZXJ0IGJvb2xlYW4gJiBudWxsIHRvIG51bWJlclxyXG4gICAgaWYgKHZhbHVlID09PSBmYWxzZSB8fCB2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gJycpIHsgcmV0dXJuIDA7IH1cclxuICB9XHJcbiAgaWYgKCg8U2NoZW1hUHJpbWl0aXZlVHlwZVtdPnR5cGVzKS5pbmNsdWRlcygnbnVtYmVyJykpIHsgLy8gQ29udmVydCBtaXhlZCBzdHJpbmcgdG8gbnVtYmVyXHJcbiAgICBjb25zdCB0ZXN0VmFsdWUgPSBwYXJzZUZsb2F0KDxzdHJpbmc+dmFsdWUpO1xyXG4gICAgaWYgKCEhdGVzdFZhbHVlKSB7IHJldHVybiB0ZXN0VmFsdWU7IH1cclxuICB9XHJcbiAgaWYgKCg8U2NoZW1hUHJpbWl0aXZlVHlwZVtdPnR5cGVzKS5pbmNsdWRlcygnaW50ZWdlcicpKSB7IC8vIENvbnZlcnQgc3RyaW5nIG9yIG51bWJlciB0byBpbnRlZ2VyXHJcbiAgICBjb25zdCB0ZXN0VmFsdWUgPSBwYXJzZUludCg8c3RyaW5nPnZhbHVlLCAxMCk7XHJcbiAgICBpZiAoISF0ZXN0VmFsdWUpIHsgcmV0dXJuIHRlc3RWYWx1ZTsgfVxyXG4gIH1cclxuICBpZiAoKDxTY2hlbWFQcmltaXRpdmVUeXBlW10+dHlwZXMpLmluY2x1ZGVzKCdib29sZWFuJykpIHsgLy8gQ29udmVydCBhbnl0aGluZyB0byBib29sZWFuXHJcbiAgICByZXR1cm4gISF2YWx1ZTtcclxuICB9XHJcbiAgaWYgKChcclxuICAgICAgKDxTY2hlbWFQcmltaXRpdmVUeXBlW10+dHlwZXMpLmluY2x1ZGVzKCdudW1iZXInKSB8fFxyXG4gICAgICAoPFNjaGVtYVByaW1pdGl2ZVR5cGVbXT50eXBlcykuaW5jbHVkZXMoJ2ludGVnZXInKVxyXG4gICAgKSAmJiAhKDxTY2hlbWFQcmltaXRpdmVUeXBlW10+dHlwZXMpLmluY2x1ZGVzKCdudWxsJylcclxuICApIHtcclxuICAgIHJldHVybiAwOyAvLyBJZiBudWxsIG5vdCBhbGxvd2VkLCByZXR1cm4gMCBmb3Igbm9uLWNvbnZlcnRhYmxlIHZhbHVlc1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqICdpc1Byb21pc2UnIGZ1bmN0aW9uXHJcbiAqXHJcbiAqIC8vICAgb2JqZWN0XHJcbiAqIC8vIHsgYm9vbGVhbiB9XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNQcm9taXNlKG9iamVjdCk6IG9iamVjdCBpcyBQcm9taXNlPGFueT4ge1xyXG4gIHJldHVybiAhIW9iamVjdCAmJiB0eXBlb2Ygb2JqZWN0LnRoZW4gPT09ICdmdW5jdGlvbic7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnaXNPYnNlcnZhYmxlJyBmdW5jdGlvblxyXG4gKlxyXG4gKiAvLyAgIG9iamVjdFxyXG4gKiAvLyB7IGJvb2xlYW4gfVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JzZXJ2YWJsZShvYmplY3QpOiBvYmplY3QgaXMgT2JzZXJ2YWJsZTxhbnk+IHtcclxuICByZXR1cm4gISFvYmplY3QgJiYgdHlwZW9mIG9iamVjdC5zdWJzY3JpYmUgPT09ICdmdW5jdGlvbic7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnX3RvUHJvbWlzZScgZnVuY3Rpb25cclxuICpcclxuICogLy8gIHsgb2JqZWN0IH0gb2JqZWN0XHJcbiAqIC8vIHsgUHJvbWlzZTxhbnk+IH1cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfdG9Qcm9taXNlKG9iamVjdCk6IFByb21pc2U8YW55PiB7XHJcbiAgcmV0dXJuIGlzUHJvbWlzZShvYmplY3QpID8gb2JqZWN0IDogb2JqZWN0LnRvUHJvbWlzZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogJ3RvT2JzZXJ2YWJsZScgZnVuY3Rpb25cclxuICpcclxuICogLy8gIHsgb2JqZWN0IH0gb2JqZWN0XHJcbiAqIC8vIHsgT2JzZXJ2YWJsZTxhbnk+IH1cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0b09ic2VydmFibGUob2JqZWN0KTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICBjb25zdCBvYnNlcnZhYmxlID0gaXNQcm9taXNlKG9iamVjdCkgPyBmcm9tKG9iamVjdCkgOiBvYmplY3Q7XHJcbiAgaWYgKGlzT2JzZXJ2YWJsZShvYnNlcnZhYmxlKSkgeyByZXR1cm4gb2JzZXJ2YWJsZTsgfVxyXG4gIGNvbnNvbGUuZXJyb3IoJ3RvT2JzZXJ2YWJsZSBlcnJvcjogRXhwZWN0ZWQgdmFsaWRhdG9yIHRvIHJldHVybiBQcm9taXNlIG9yIE9ic2VydmFibGUuJyk7XHJcbiAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiAnaW5BcnJheScgZnVuY3Rpb25cclxuICpcclxuICogU2VhcmNoZXMgYW4gYXJyYXkgZm9yIGFuIGl0ZW0sIG9yIG9uZSBvZiBhIGxpc3Qgb2YgaXRlbXMsIGFuZCByZXR1cm5zIHRydWVcclxuICogYXMgc29vbiBhcyBhIG1hdGNoIGlzIGZvdW5kLCBvciBmYWxzZSBpZiBubyBtYXRjaC5cclxuICpcclxuICogSWYgdGhlIG9wdGlvbmFsIHRoaXJkIHBhcmFtZXRlciBhbGxJbiBpcyBzZXQgdG8gVFJVRSwgYW5kIHRoZSBpdGVtIHRvIGZpbmRcclxuICogaXMgYW4gYXJyYXksIHRoZW4gdGhlIGZ1bmN0aW9uIHJldHVybnMgdHJ1ZSBvbmx5IGlmIGFsbCBlbGVtZW50cyBmcm9tIGl0ZW1cclxuICogYXJlIGZvdW5kIGluIHRoZSBhcnJheSBsaXN0LCBhbmQgZmFsc2UgaWYgYW55IGVsZW1lbnQgaXMgbm90IGZvdW5kLiBJZiB0aGVcclxuICogaXRlbSB0byBmaW5kIGlzIG5vdCBhbiBhcnJheSwgc2V0dGluZyBhbGxJbiB0byBUUlVFIGhhcyBubyBlZmZlY3QuXHJcbiAqXHJcbiAqIC8vICB7IGFueXxhbnlbXSB9IGl0ZW0gLSB0aGUgaXRlbSB0byBzZWFyY2ggZm9yXHJcbiAqIC8vICAgYXJyYXkgLSB0aGUgYXJyYXkgdG8gc2VhcmNoXHJcbiAqIC8vICB7IGJvb2xlYW4gPSBmYWxzZSB9IGFsbEluIC0gaWYgVFJVRSwgYWxsIGl0ZW1zIG11c3QgYmUgaW4gYXJyYXlcclxuICogLy8geyBib29sZWFuIH0gLSB0cnVlIGlmIGl0ZW0ocykgaW4gYXJyYXksIGZhbHNlIG90aGVyd2lzZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGluQXJyYXkoaXRlbSwgYXJyYXksIGFsbEluID0gZmFsc2UpIHtcclxuICBpZiAoIWlzRGVmaW5lZChpdGVtKSB8fCAhaXNBcnJheShhcnJheSkpIHsgcmV0dXJuIGZhbHNlOyB9XHJcbiAgcmV0dXJuIGlzQXJyYXkoaXRlbSkgP1xyXG4gICAgaXRlbVthbGxJbiA/ICdldmVyeScgOiAnc29tZSddKHN1Ykl0ZW0gPT4gYXJyYXkuaW5jbHVkZXMoc3ViSXRlbSkpIDpcclxuICAgIGFycmF5LmluY2x1ZGVzKGl0ZW0pO1xyXG59XHJcblxyXG4vKipcclxuICogJ3hvcicgdXRpbGl0eSBmdW5jdGlvbiAtIGV4Y2x1c2l2ZSBvclxyXG4gKlxyXG4gKiBSZXR1cm5zIHRydWUgaWYgZXhhY3RseSBvbmUgb2YgdHdvIHZhbHVlcyBpcyB0cnV0aHkuXHJcbiAqXHJcbiAqIC8vICAgdmFsdWUxIC0gZmlyc3QgdmFsdWUgdG8gY2hlY2tcclxuICogLy8gICB2YWx1ZTIgLSBzZWNvbmQgdmFsdWUgdG8gY2hlY2tcclxuICogLy8geyBib29sZWFuIH0gLSB0cnVlIGlmIGV4YWN0bHkgb25lIGlucHV0IHZhbHVlIGlzIHRydXRoeSwgZmFsc2UgaWYgbm90XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24geG9yKHZhbHVlMSwgdmFsdWUyKSB7XHJcbiAgcmV0dXJuICghIXZhbHVlMSAmJiAhdmFsdWUyKSB8fCAoIXZhbHVlMSAmJiAhIXZhbHVlMik7XHJcbn1cclxuIl19
|